2015-12-04 21:25:45 +01:00
#include "GUI.hpp"
2018-03-27 13:44:18 +02:00
#include "WipeTowerDialog.hpp"
2015-12-04 21:25:45 +01:00
2017-11-02 16:21:34 +01:00
#include <assert.h>
2018-04-09 14:41:55 +02:00
#include <cmath>
2017-11-02 16:21:34 +01:00
2018-01-07 18:41:40 +01:00
#include <boost/lexical_cast.hpp>
2018-05-21 22:10:38 +02:00
#include <boost/algorithm/string.hpp>
2018-02-07 11:37:15 +01:00
#include <boost/format.hpp>
2018-02-02 12:38:35 +01:00
2015-12-04 21:25:45 +01:00
#if __APPLE__
#import <IOKit/pwr_mgt/IOPMLib.h>
#elif _WIN32
#include <Windows.h>
2017-12-13 14:45:10 +01:00
// Undefine min/max macros incompatible with the standard library
// For example, std::numeric_limits<std::streamsize>::max()
// produces some weird errors
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
2017-11-02 16:21:34 +01:00
#include "boost/nowide/convert.hpp"
2015-12-04 21:25:45 +01:00
#endif
2017-12-04 10:48:40 +01:00
#include <wx/app.h>
#include <wx/button.h>
2018-02-15 18:13:37 +01:00
#include <wx/dir.h>
#include <wx/filename.h>
2017-12-04 10:48:40 +01:00
#include <wx/frame.h>
#include <wx/menu.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
2018-02-02 12:38:35 +01:00
#include <wx/combo.h>
2017-12-13 14:45:10 +01:00
#include <wx/window.h>
2018-04-16 16:52:11 +02:00
#include <wx/msgdlg.h>
2018-04-09 14:41:55 +02:00
#include <wx/settings.h>
2018-06-11 18:24:13 +02:00
#include <wx/display.h>
2018-02-02 12:38:35 +01:00
2018-02-02 13:56:25 +01:00
#include "wxExtensions.hpp"
2017-12-04 10:48:40 +01:00
2018-01-23 11:42:04 +01:00
#include "Tab.hpp"
2018-01-23 11:37:19 +01:00
#include "TabIface.hpp"
2018-04-09 17:03:37 +02:00
#include "AboutDialog.hpp"
2018-01-05 15:11:33 +01:00
#include "AppConfig.hpp"
2018-04-10 16:27:42 +02:00
#include "ConfigSnapshotDialog.hpp"
2018-02-08 10:58:13 +01:00
#include "Utils.hpp"
2018-04-30 14:31:57 +02:00
#include "MsgDialog.hpp"
2018-03-13 12:39:57 +01:00
#include "ConfigWizard.hpp"
2018-02-22 11:12:29 +01:00
#include "Preferences.hpp"
2018-03-09 17:17:51 +01:00
#include "PresetBundle.hpp"
2018-04-27 12:29:18 +02:00
#include "UpdateDialogs.hpp"
2018-05-04 16:04:43 +02:00
#include "FirmwareDialog.hpp"
2017-12-05 15:54:01 +01:00
2018-04-16 16:52:11 +02:00
#include "../Utils/PresetUpdater.hpp"
2018-04-10 16:27:42 +02:00
#include "../Config/Snapshot.hpp"
2018-07-17 08:54:17 +02:00
2018-06-22 12:27:56 +02:00
#include "3DScene.hpp"
2018-06-20 18:33:46 +02:00
#include "libslic3r/I18N.hpp"
2018-04-19 10:35:47 +02:00
2015-12-04 21:25:45 +01:00
namespace Slic3r { namespace GUI {
2015-12-05 11:48:24 +01:00
#if __APPLE__
2015-12-04 21:25:45 +01:00
IOPMAssertionID assertionID ;
2015-12-05 11:48:24 +01:00
#endif
2015-12-04 21:25:45 +01:00
2017-10-25 12:53:31 +02:00
void disable_screensaver ()
2015-12-04 21:25:45 +01:00
{
#if __APPLE__
CFStringRef reasonForActivity = CFSTR ( "Slic3r" );
IOReturn success = IOPMAssertionCreateWithName ( kIOPMAssertionTypeNoDisplaySleep ,
kIOPMAssertionLevelOn , reasonForActivity , & assertionID );
// ignore result: success == kIOReturnSuccess
#elif _WIN32
2015-12-06 11:17:50 +01:00
SetThreadExecutionState ( ES_DISPLAY_REQUIRED | ES_CONTINUOUS );
2015-12-04 21:25:45 +01:00
#endif
}
2017-10-25 12:53:31 +02:00
void enable_screensaver ()
2015-12-04 21:25:45 +01:00
{
#if __APPLE__
IOReturn success = IOPMAssertionRelease ( assertionID );
#elif _WIN32
2015-12-06 11:17:50 +01:00
SetThreadExecutionState ( ES_CONTINUOUS );
2015-12-04 21:25:45 +01:00
#endif
}
2017-10-25 12:53:31 +02:00
bool debugged ()
2016-04-13 20:45:44 +02:00
{
2016-04-13 20:51:03 +02:00
#ifdef _WIN32
2016-04-13 20:45:44 +02:00
return IsDebuggerPresent ();
2016-04-13 20:51:03 +02:00
#else
return false ;
#endif /* _WIN32 */
2016-04-13 20:45:44 +02:00
}
2017-10-25 12:53:31 +02:00
void break_to_debugger ()
2016-04-13 20:45:44 +02:00
{
#ifdef _WIN32
if ( IsDebuggerPresent ())
DebugBreak ();
#endif /* _WIN32 */
}
2017-12-04 10:48:40 +01:00
// Passing the wxWidgets GUI classes instantiated by the Perl part to C++.
wxApp * g_wxApp = nullptr ;
wxFrame * g_wxMainFrame = nullptr ;
wxNotebook * g_wxTabPanel = nullptr ;
2018-02-20 08:58:46 +01:00
AppConfig * g_AppConfig = nullptr ;
2018-03-09 17:17:51 +01:00
PresetBundle * g_PresetBundle = nullptr ;
2018-04-16 16:52:11 +02:00
PresetUpdater * g_PresetUpdater = nullptr ;
2018-06-22 12:27:56 +02:00
_3DScene * g_3DScene = nullptr ;
2018-04-09 14:41:55 +02:00
wxColour g_color_label_modified ;
wxColour g_color_label_sys ;
2018-04-18 13:32:21 +02:00
wxColour g_color_label_default ;
2017-12-04 10:48:40 +01:00
2018-02-09 11:04:34 +01:00
std :: vector < Tab *> g_tabs_list ;
2018-02-12 08:57:32 +01:00
wxLocale * g_wxLocale ;
2018-02-08 10:58:13 +01:00
2018-06-20 14:20:48 +02:00
wxFont g_small_font ;
wxFont g_bold_font ;
2018-03-09 17:17:51 +01:00
std :: shared_ptr < ConfigOptionsGroup > m_optgroup ;
2018-03-13 16:14:36 +01:00
double m_brim_width = 0.0 ;
2018-04-03 22:07:59 +02:00
wxButton * g_wiping_dialog_button = nullptr ;
2018-03-09 17:17:51 +01:00
2018-08-06 17:01:41 +02:00
// Windows, associated with Print, Filament & Material Tabs accordingly
wxWindow * g_PrintTab = nullptr ;
wxWindow * g_FilamentTab = nullptr ;
wxWindow * g_MaterialTab = nullptr ;
2018-04-09 14:41:55 +02:00
static void init_label_colours ()
{
auto luma = get_colour_approx_luma ( wxSystemSettings :: GetColour ( wxSYS_COLOUR_WINDOW ));
if ( luma >= 128 ) {
2018-05-02 13:20:36 +02:00
g_color_label_modified = wxColour ( 252 , 77 , 1 );
2018-04-30 14:20:33 +02:00
g_color_label_sys = wxColour ( 26 , 132 , 57 );
2018-04-09 14:41:55 +02:00
} else {
g_color_label_modified = wxColour ( 253 , 111 , 40 );
g_color_label_sys = wxColour ( 115 , 220 , 103 );
}
2018-04-18 13:32:21 +02:00
g_color_label_default = wxSystemSettings :: GetColour ( wxSYS_COLOUR_WINDOWTEXT );
2018-04-09 14:41:55 +02:00
}
2018-03-09 17:17:51 +01:00
2018-04-30 14:20:33 +02:00
void update_label_colours_from_appconfig ()
{
if ( g_AppConfig -> has ( "label_clr_sys" )){
auto str = g_AppConfig -> get ( "label_clr_sys" );
if ( str != "" )
g_color_label_sys = wxColour ( str );
}
if ( g_AppConfig -> has ( "label_clr_modified" )){
auto str = g_AppConfig -> get ( "label_clr_modified" );
if ( str != "" )
g_color_label_modified = wxColour ( str );
}
}
2018-06-20 14:20:48 +02:00
static void init_fonts ()
{
g_small_font = wxSystemSettings :: GetFont ( wxSYS_DEFAULT_GUI_FONT );
g_bold_font = wxSystemSettings :: GetFont ( wxSYS_DEFAULT_GUI_FONT ). Bold ();
#ifdef __WXMAC__
g_small_font . SetPointSize ( 11 );
g_bold_font . SetPointSize ( 13 );
#endif /*__WXMAC__*/
}
2018-06-20 19:26:19 +02:00
static std :: string libslic3r_translate_callback ( const char * s ) { return wxGetTranslation ( wxString ( s , wxConvUTF8 )). utf8_str (). data (); }
2018-06-20 18:33:46 +02:00
2017-12-04 10:48:40 +01:00
void set_wxapp ( wxApp * app )
{
g_wxApp = app ;
2018-06-20 18:33:46 +02:00
// Let the libslic3r know the callback, which will translate messages on demand.
Slic3r :: I18N :: set_translate_callback ( libslic3r_translate_callback );
2018-04-09 14:41:55 +02:00
init_label_colours ();
2018-06-20 14:20:48 +02:00
init_fonts ();
2017-12-04 10:48:40 +01:00
}
void set_main_frame ( wxFrame * main_frame )
{
g_wxMainFrame = main_frame ;
}
void set_tab_panel ( wxNotebook * tab_panel )
{
g_wxTabPanel = tab_panel ;
}
2018-02-20 08:58:46 +01:00
void set_app_config ( AppConfig * app_config )
{
g_AppConfig = app_config ;
}
2018-03-09 17:17:51 +01:00
void set_preset_bundle ( PresetBundle * preset_bundle )
{
g_PresetBundle = preset_bundle ;
}
2018-04-16 16:52:11 +02:00
void set_preset_updater ( PresetUpdater * updater )
{
g_PresetUpdater = updater ;
}
2018-06-22 12:27:56 +02:00
void set_3DScene ( _3DScene * scene )
{
g_3DScene = scene ;
}
2018-02-09 11:04:34 +01:00
std :: vector < Tab *>& get_tabs_list ()
2017-12-04 10:48:40 +01:00
{
2018-02-09 11:04:34 +01:00
return g_tabs_list ;
2017-12-04 10:48:40 +01:00
}
2018-02-09 11:04:34 +01:00
bool checked_tab ( Tab * tab )
2017-12-04 10:48:40 +01:00
{
2018-02-09 11:04:34 +01:00
bool ret = true ;
if ( find ( g_tabs_list . begin (), g_tabs_list . end (), tab ) == g_tabs_list . end ())
ret = false ;
return ret ;
}
void delete_tab_from_list ( Tab * tab )
{
std :: vector < Tab *>:: iterator itr = find ( g_tabs_list . begin (), g_tabs_list . end (), tab );
if ( itr != g_tabs_list . end ())
g_tabs_list . erase ( itr );
}
2018-02-08 10:58:13 +01:00
bool select_language ( wxArrayString & names ,
wxArrayLong & identifiers )
{
wxCHECK_MSG ( names . Count () == identifiers . Count (), false ,
2018-02-23 09:16:35 +01:00
_ ( L ( "Array of language names and identifiers should have the same size." )));
2018-02-12 08:57:32 +01:00
int init_selection = 0 ;
long current_language = g_wxLocale ? g_wxLocale -> GetLanguage () : wxLANGUAGE_UNKNOWN ;
for ( auto lang : identifiers ){
if ( lang == current_language )
break ;
else
++ init_selection ;
}
if ( init_selection == identifiers . size ())
init_selection = 0 ;
2018-02-23 09:16:35 +01:00
long index = wxGetSingleChoiceIndex ( _ ( L ( "Select the language" )), _ ( L ( "Language" )),
2018-02-12 08:57:32 +01:00
names , init_selection );
2018-02-08 10:58:13 +01:00
if ( index != - 1 )
{
2018-02-12 08:57:32 +01:00
g_wxLocale = new wxLocale ;
g_wxLocale -> Init ( identifiers [ index ]);
g_wxLocale -> AddCatalogLookupPathPrefix ( wxPathOnly ( localization_dir ()));
g_wxLocale -> AddCatalog ( g_wxApp -> GetAppName ());
2018-03-06 09:44:53 +01:00
wxSetlocale ( LC_NUMERIC , "C" );
2018-07-23 15:44:01 +02:00
Preset :: update_suffix_modified ();
2018-02-08 10:58:13 +01:00
return true ;
}
return false ;
}
bool load_language ()
{
2018-05-03 09:21:01 +02:00
wxString language = wxEmptyString ;
if ( g_AppConfig -> has ( "translation_language" ))
language = g_AppConfig -> get ( "translation_language" );
2018-02-20 08:58:46 +01:00
2018-05-03 09:21:01 +02:00
if ( language . IsEmpty ())
2018-02-12 08:57:32 +01:00
return false ;
wxArrayString names ;
wxArrayLong identifiers ;
2018-02-08 10:58:13 +01:00
get_installed_languages ( names , identifiers );
for ( size_t i = 0 ; i < identifiers . Count (); i ++ )
{
2018-05-03 09:21:01 +02:00
if ( wxLocale :: GetLanguageCanonicalName ( identifiers [ i ]) == language )
2018-02-08 10:58:13 +01:00
{
2018-02-12 08:57:32 +01:00
g_wxLocale = new wxLocale ;
g_wxLocale -> Init ( identifiers [ i ]);
g_wxLocale -> AddCatalogLookupPathPrefix ( wxPathOnly ( localization_dir ()));
g_wxLocale -> AddCatalog ( g_wxApp -> GetAppName ());
2018-03-06 09:44:53 +01:00
wxSetlocale ( LC_NUMERIC , "C" );
2018-07-23 15:44:01 +02:00
Preset :: update_suffix_modified ();
2018-02-08 10:58:13 +01:00
return true ;
}
}
return false ;
}
2018-02-12 08:57:32 +01:00
void save_language ()
2018-02-08 10:58:13 +01:00
{
2018-05-03 09:21:01 +02:00
wxString language = wxEmptyString ;
if ( g_wxLocale )
language = g_wxLocale -> GetCanonicalName ();
g_AppConfig -> set ( "translation_language" , language . ToStdString ());
2018-02-20 08:58:46 +01:00
g_AppConfig -> save ();
2018-02-08 10:58:13 +01:00
}
void get_installed_languages ( wxArrayString & names ,
wxArrayLong & identifiers )
{
names . Clear ();
identifiers . Clear ();
2018-02-12 08:57:32 +01:00
wxDir dir ( wxPathOnly ( localization_dir ()));
2018-02-08 10:58:13 +01:00
wxString filename ;
const wxLanguageInfo * langinfo ;
wxString name = wxLocale :: GetLanguageName ( wxLANGUAGE_DEFAULT );
if ( ! name . IsEmpty ())
{
2018-02-23 09:16:35 +01:00
names . Add ( _ ( L ( "Default" )));
2018-02-08 10:58:13 +01:00
identifiers . Add ( wxLANGUAGE_DEFAULT );
}
for ( bool cont = dir . GetFirst ( & filename , wxEmptyString , wxDIR_DIRS );
cont ; cont = dir . GetNext ( & filename ))
{
langinfo = wxLocale :: FindLanguageInfo ( filename );
if ( langinfo != NULL )
{
auto full_file_name = dir . GetName () + wxFileName :: GetPathSeparator () +
filename + wxFileName :: GetPathSeparator () +
g_wxApp -> GetAppName () + wxT ( ".mo" );
if ( wxFileExists ( full_file_name ))
{
names . Add ( langinfo -> Description );
identifiers . Add ( langinfo -> Language );
}
}
}
}
2018-04-09 17:03:37 +02:00
enum ConfigMenuIDs {
ConfigMenuWizard ,
ConfigMenuSnapshots ,
ConfigMenuTakeSnapshot ,
ConfigMenuUpdate ,
ConfigMenuPreferences ,
ConfigMenuLanguage ,
2018-05-21 21:04:03 +02:00
ConfigMenuFlashFirmware ,
2018-04-09 17:03:37 +02:00
ConfigMenuCnt ,
};
2018-06-07 22:10:23 +02:00
static wxString dots ( "…" , wxConvUTF8 );
2018-04-09 17:03:37 +02:00
void add_config_menu ( wxMenuBar * menu , int event_preferences_changed , int event_language_change )
2017-12-04 10:48:40 +01:00
{
2018-02-08 10:58:13 +01:00
auto local_menu = new wxMenu ();
2018-04-09 17:03:37 +02:00
wxWindowID config_id_base = wxWindow :: NewControlId (( int ) ConfigMenuCnt );
2018-04-11 12:21:15 +02:00
2018-06-28 16:01:06 +02:00
const auto config_wizard_name = _ ( ConfigWizard :: name (). wx_str ());
2018-06-27 09:07:04 +02:00
const auto config_wizard_tooltip = wxString :: Format ( _ ( L ( "Run %s" )), config_wizard_name );
2018-04-09 17:03:37 +02:00
// Cmd+, is standard on OS X - what about other operating systems?
2018-06-27 09:07:04 +02:00
local_menu -> Append ( config_id_base + ConfigMenuWizard , config_wizard_name + dots , config_wizard_tooltip );
local_menu -> Append ( config_id_base + ConfigMenuSnapshots , _ ( L ( "Configuration Snapshots" )) + dots , _ ( L ( "Inspect / activate configuration snapshots" )));
2018-05-02 13:20:36 +02:00
local_menu -> Append ( config_id_base + ConfigMenuTakeSnapshot , _ ( L ( "Take Configuration Snapshot" )), _ ( L ( "Capture a configuration snapshot" )));
2018-05-21 21:04:03 +02:00
// local_menu->Append(config_id_base + ConfigMenuUpdate, _(L("Check for updates")), _(L("Check for configuration updates")));
2018-04-09 17:03:37 +02:00
local_menu -> AppendSeparator ();
2018-06-07 22:10:23 +02:00
local_menu -> Append ( config_id_base + ConfigMenuPreferences , _ ( L ( "Preferences" )) + dots + " \t Ctrl+," , _ ( L ( "Application preferences" )));
2018-04-09 17:03:37 +02:00
local_menu -> Append ( config_id_base + ConfigMenuLanguage , _ ( L ( "Change Application Language" )));
2018-05-21 21:04:03 +02:00
local_menu -> AppendSeparator ();
local_menu -> Append ( config_id_base + ConfigMenuFlashFirmware , _ ( L ( "Flash printer firmware" )), _ ( L ( "Upload a firmware image into an Arduino based printer" )));
// TODO: for when we're able to flash dictionaries
// local_menu->Append(config_id_base + FirmwareMenuDict, _(L("Flash language file")), _(L("Upload a language dictionary file into a Prusa printer")));
2018-04-09 17:03:37 +02:00
local_menu -> Bind ( wxEVT_MENU , [ config_id_base , event_language_change , event_preferences_changed ]( wxEvent & event ){
switch ( event . GetId () - config_id_base ) {
2018-04-11 12:21:15 +02:00
case ConfigMenuWizard :
2018-04-24 18:06:42 +02:00
config_wizard ( ConfigWizard :: RR_USER );
2018-04-11 12:21:15 +02:00
break ;
2018-04-10 16:27:42 +02:00
case ConfigMenuTakeSnapshot :
// Take a configuration snapshot.
2018-04-11 12:21:15 +02:00
if ( check_unsaved_changes ()) {
wxTextEntryDialog dlg ( nullptr , _ ( L ( "Taking configuration snapshot" )), _ ( L ( "Snapshot name" )));
if ( dlg . ShowModal () == wxID_OK )
2018-04-20 10:26:23 +02:00
g_AppConfig -> set ( "on_snapshot" ,
Slic3r :: GUI :: Config :: SnapshotDB :: singleton (). take_snapshot (
* g_AppConfig , Slic3r :: GUI :: Config :: Snapshot :: SNAPSHOT_USER , dlg . GetValue (). ToUTF8 (). data ()). id );
2018-04-11 12:21:15 +02:00
}
2018-04-10 16:27:42 +02:00
break ;
case ConfigMenuSnapshots :
2018-04-11 12:21:15 +02:00
if ( check_unsaved_changes ()) {
2018-04-20 10:26:23 +02:00
std :: string on_snapshot ;
if ( Config :: SnapshotDB :: singleton (). is_on_snapshot ( * g_AppConfig ))
on_snapshot = g_AppConfig -> get ( "on_snapshot" );
ConfigSnapshotDialog dlg ( Slic3r :: GUI :: Config :: SnapshotDB :: singleton (), on_snapshot );
2018-04-11 12:21:15 +02:00
dlg . ShowModal ();
if ( ! dlg . snapshot_to_activate (). empty ()) {
2018-04-20 10:26:23 +02:00
if ( ! Config :: SnapshotDB :: singleton (). is_on_snapshot ( * g_AppConfig ))
Config :: SnapshotDB :: singleton (). take_snapshot ( * g_AppConfig , Config :: Snapshot :: SNAPSHOT_BEFORE_ROLLBACK );
g_AppConfig -> set ( "on_snapshot" ,
Config :: SnapshotDB :: singleton (). restore_snapshot ( dlg . snapshot_to_activate (), * g_AppConfig ). id );
2018-04-11 12:21:15 +02:00
g_PresetBundle -> load_presets ( * g_AppConfig );
// Load the currently selected preset into the GUI, update the preset selection box.
2018-06-06 10:52:19 +02:00
load_current_presets ();
2018-04-11 12:21:15 +02:00
}
}
2018-04-10 16:27:42 +02:00
break ;
2018-04-09 17:03:37 +02:00
case ConfigMenuPreferences :
{
2018-04-11 12:21:15 +02:00
PreferencesDialog dlg ( g_wxMainFrame , event_preferences_changed );
dlg . ShowModal ();
2018-04-09 17:03:37 +02:00
break ;
}
case ConfigMenuLanguage :
{
wxArrayString names ;
wxArrayLong identifiers ;
get_installed_languages ( names , identifiers );
if ( select_language ( names , identifiers )) {
save_language ();
show_info ( g_wxTabPanel , _ ( L ( "Application will be restarted" )), _ ( L ( "Attention!" )));
if ( event_language_change > 0 ) {
2018-06-25 12:27:42 +02:00
_3DScene :: remove_all_canvases (); // remove all canvas before recreate GUI
2018-04-09 17:03:37 +02:00
wxCommandEvent event ( event_language_change );
g_wxApp -> ProcessEvent ( event );
}
2018-02-09 11:04:34 +01:00
}
2018-04-09 17:03:37 +02:00
break ;
2018-02-09 11:04:34 +01:00
}
2018-05-21 21:04:03 +02:00
case ConfigMenuFlashFirmware :
2018-05-04 16:04:43 +02:00
FirmwareDialog :: run ( g_wxMainFrame );
break ;
default :
break ;
}
});
2018-05-21 21:04:03 +02:00
menu -> Append ( local_menu , _ ( L ( "&Configuration" )));
2018-05-04 16:04:43 +02:00
}
void add_menus ( wxMenuBar * menu , int event_preferences_changed , int event_language_change )
{
2018-06-04 09:24:48 +02:00
add_config_menu ( menu , event_preferences_changed , event_language_change );
2018-05-04 16:04:43 +02:00
}
2018-04-11 12:21:15 +02:00
// This is called when closing the application, when loading a config file or when starting the config wizard
// to notify the user whether he is aware that some preset changes will be lost.
bool check_unsaved_changes ()
2018-03-13 12:39:57 +01:00
{
2018-04-11 12:21:15 +02:00
std :: string dirty ;
for ( Tab * tab : g_tabs_list )
if ( tab -> current_preset_is_dirty ())
if ( dirty . empty ())
dirty = tab -> name ();
else
dirty += std :: string ( ", " ) + tab -> name ();
if ( dirty . empty ())
// No changes, the application may close or reload presets.
return true ;
// Ask the user.
auto dialog = new wxMessageDialog ( g_wxMainFrame ,
_ ( L ( "You have unsaved changes " )) + dirty + _ ( L ( ". Discard changes and continue anyway?" )),
_ ( L ( "Unsaved Presets" )),
wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT );
return dialog -> ShowModal () == wxID_YES ;
}
2018-03-13 12:39:57 +01:00
2018-04-24 18:06:42 +02:00
bool config_wizard_startup ( bool app_config_exists )
2018-04-16 16:52:11 +02:00
{
2018-06-19 18:26:38 +02:00
if ( ! app_config_exists || g_PresetBundle -> printers . size () <= 1 ) {
2018-04-24 18:06:42 +02:00
config_wizard ( ConfigWizard :: RR_DATA_EMPTY );
return true ;
2018-04-16 16:52:11 +02:00
} else if ( g_AppConfig -> legacy_datadir ()) {
// Looks like user has legacy pre-vendorbundle data directory,
// explain what this is and run the wizard
2018-04-27 12:29:18 +02:00
MsgDataLegacy dlg ;
dlg . ShowModal ();
2018-04-16 16:52:11 +02:00
2018-04-24 18:06:42 +02:00
config_wizard ( ConfigWizard :: RR_DATA_LEGACY );
return true ;
2018-04-16 16:52:11 +02:00
}
2018-04-24 18:06:42 +02:00
return false ;
2018-04-16 16:52:11 +02:00
}
2018-04-24 18:06:42 +02:00
void config_wizard ( int reason )
2018-04-11 12:21:15 +02:00
{
// Exit wizard if there are unsaved changes and the user cancels the action.
if ( ! check_unsaved_changes ())
2018-04-16 16:52:11 +02:00
return ;
2018-04-11 12:21:15 +02:00
2018-06-04 09:07:29 +02:00
try {
ConfigWizard wizard ( nullptr , static_cast < ConfigWizard :: RunReason > ( reason ));
wizard . run ( g_PresetBundle , g_PresetUpdater );
}
catch ( const std :: exception & e ) {
show_error ( nullptr , e . what ());
}
2018-04-11 12:21:15 +02:00
2018-06-06 10:52:19 +02:00
// Load the currently selected preset into the GUI, update the preset selection box.
load_current_presets ();
2018-03-13 12:39:57 +01:00
}
2018-02-22 11:12:29 +01:00
void open_preferences_dialog ( int event_preferences )
{
auto dlg = new PreferencesDialog ( g_wxMainFrame , event_preferences );
dlg -> ShowModal ();
}
2018-03-15 18:06:26 +01:00
void create_preset_tabs ( bool no_controller , int event_value_change , int event_presets_changed )
2018-01-05 15:11:33 +01:00
{
2018-04-30 14:20:33 +02:00
update_label_colours_from_appconfig ();
2018-08-03 13:04:41 +02:00
add_created_tab ( new TabPrint ( g_wxTabPanel , no_controller ));
add_created_tab ( new TabFilament ( g_wxTabPanel , no_controller ));
add_created_tab ( new TabSLAMaterial ( g_wxTabPanel , no_controller ));
add_created_tab ( new TabPrinter ( g_wxTabPanel , no_controller ));
2018-01-21 23:35:00 +01:00
for ( size_t i = 0 ; i < g_wxTabPanel -> GetPageCount (); ++ i ) {
Tab * tab = dynamic_cast < Tab *> ( g_wxTabPanel -> GetPage ( i ));
2018-08-06 17:01:41 +02:00
if ( ! tab ||
tab -> GetName () == "sla_material" ) // ys_FIXME don't set event till doesn't exist material_preset combobox on plater
2018-01-21 23:35:00 +01:00
continue ;
tab -> set_event_value_change ( wxEventType ( event_value_change ));
tab -> set_event_presets_changed ( wxEventType ( event_presets_changed ));
}
2017-12-22 11:50:28 +01:00
}
2018-01-23 11:37:19 +01:00
TabIface * get_preset_tab_iface ( char * name )
{
2018-08-06 17:01:41 +02:00
if ( std :: strcmp ( name , "print" ) == 0 ) return new TabIface ( dynamic_cast < Tab *> ( g_PrintTab ));
if ( std :: strcmp ( name , "filament" ) == 0 ) return new TabIface ( dynamic_cast < Tab *> ( g_FilamentTab ));
if ( std :: strcmp ( name , "material" ) == 0 ) return new TabIface ( dynamic_cast < Tab *> ( g_MaterialTab ));
2018-01-23 11:37:19 +01:00
for ( size_t i = 0 ; i < g_wxTabPanel -> GetPageCount (); ++ i ) {
Tab * tab = dynamic_cast < Tab *> ( g_wxTabPanel -> GetPage ( i ));
if ( ! tab )
continue ;
2018-01-25 21:44:22 +01:00
if ( tab -> name () == name ) {
2018-01-23 11:37:19 +01:00
return new TabIface ( tab );
}
}
return new TabIface ( nullptr );
}
2018-02-15 17:30:33 +01:00
// opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element)
2018-04-13 12:35:04 +02:00
void change_opt_value ( DynamicPrintConfig & config , const t_config_option_key & opt_key , const boost :: any & value , int opt_index /*= 0*/ )
2018-01-07 18:41:40 +01:00
{
try {
switch ( config . def () -> get ( opt_key ) -> type ){
2018-01-09 13:52:01 +01:00
case coFloatOrPercent :{
2018-02-20 12:30:13 +01:00
std :: string str = boost :: any_cast < std :: string > ( value );
bool percent = false ;
if ( str . back () == '%' ){
str . pop_back ();
percent = true ;
}
double val = stod ( str );
config . set_key_value ( opt_key , new ConfigOptionFloatOrPercent ( val , percent ));
2018-01-09 13:52:01 +01:00
break ;}
2018-01-07 18:41:40 +01:00
case coPercent :
2018-01-11 10:33:17 +01:00
config . set_key_value ( opt_key , new ConfigOptionPercent ( boost :: any_cast < double > ( value )));
2018-01-09 13:52:01 +01:00
break ;
case coFloat :{
2018-01-07 18:41:40 +01:00
double & val = config . opt_float ( opt_key );
2018-01-09 09:41:07 +01:00
val = boost :: any_cast < double > ( value );
2018-01-07 18:41:40 +01:00
break ;
}
2018-02-26 09:57:08 +01:00
case coPercents :{
ConfigOptionPercents * vec_new = new ConfigOptionPercents { boost :: any_cast < double > ( value ) };
config . option < ConfigOptionPercents > ( opt_key ) -> set_at ( vec_new , opt_index , opt_index );
2018-01-09 13:52:01 +01:00
break ;
2018-02-26 09:57:08 +01:00
}
case coFloats :{
ConfigOptionFloats * vec_new = new ConfigOptionFloats { boost :: any_cast < double > ( value ) };
config . option < ConfigOptionFloats > ( opt_key ) -> set_at ( vec_new , opt_index , opt_index );
break ;
2018-01-09 13:52:01 +01:00
}
2018-01-07 18:41:40 +01:00
case coString :
2018-01-09 13:52:01 +01:00
config . set_key_value ( opt_key , new ConfigOptionString ( boost :: any_cast < std :: string > ( value )));
2018-01-07 18:41:40 +01:00
break ;
2018-01-12 12:41:13 +01:00
case coStrings :{
2018-04-13 12:35:04 +02:00
if ( opt_key . compare ( "compatible_printers" ) == 0 ) {
config . option < ConfigOptionStrings > ( opt_key ) -> values =
boost :: any_cast < std :: vector < std :: string >> ( value );
}
else if ( config . def () -> get ( opt_key ) -> gui_flags . compare ( "serialized" ) == 0 ){
std :: string str = boost :: any_cast < std :: string > ( value );
if ( str . back () == ';' ) str . pop_back ();
// Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values.
// Currently used for the post_process config value only.
std :: vector < std :: string > values ;
boost :: split ( values , str , boost :: is_any_of ( ";" ));
if ( values . size () == 1 && values [ 0 ] == "" )
2018-03-07 15:05:41 +01:00
break ;
2018-03-23 17:27:43 +01:00
config . option < ConfigOptionStrings > ( opt_key ) -> values = values ;
2018-01-12 12:41:13 +01:00
}
else {
2018-01-25 13:46:04 +01:00
ConfigOptionStrings * vec_new = new ConfigOptionStrings { boost :: any_cast < std :: string > ( value ) };
2018-03-02 13:41:37 +01:00
config . option < ConfigOptionStrings > ( opt_key ) -> set_at ( vec_new , opt_index , 0 );
2018-01-12 12:41:13 +01:00
}
}
2018-01-07 18:41:40 +01:00
break ;
case coBool :
config . set_key_value ( opt_key , new ConfigOptionBool ( boost :: any_cast < bool > ( value )));
break ;
2018-01-09 13:52:01 +01:00
case coBools :{
2018-03-09 17:17:51 +01:00
ConfigOptionBools * vec_new = new ConfigOptionBools { ( bool ) boost :: any_cast < unsigned char > ( value ) };
2018-03-02 13:41:37 +01:00
config . option < ConfigOptionBools > ( opt_key ) -> set_at ( vec_new , opt_index , 0 );
2018-01-09 13:52:01 +01:00
break ;}
2018-01-07 18:41:40 +01:00
case coInt :
config . set_key_value ( opt_key , new ConfigOptionInt ( boost :: any_cast < int > ( value )));
break ;
2018-01-12 12:41:13 +01:00
case coInts :{
ConfigOptionInts * vec_new = new ConfigOptionInts { boost :: any_cast < int > ( value ) };
2018-03-02 13:41:37 +01:00
config . option < ConfigOptionInts > ( opt_key ) -> set_at ( vec_new , opt_index , 0 );
2018-01-12 12:41:13 +01:00
}
2018-01-07 18:41:40 +01:00
break ;
2018-01-11 10:33:17 +01:00
case coEnum :{
if ( opt_key . compare ( "external_fill_pattern" ) == 0 ||
opt_key . compare ( "fill_pattern" ) == 0 )
config . set_key_value ( opt_key , new ConfigOptionEnum < InfillPattern > ( boost :: any_cast < InfillPattern > ( value )));
else if ( opt_key . compare ( "gcode_flavor" ) == 0 )
config . set_key_value ( opt_key , new ConfigOptionEnum < GCodeFlavor > ( boost :: any_cast < GCodeFlavor > ( value )));
else if ( opt_key . compare ( "support_material_pattern" ) == 0 )
config . set_key_value ( opt_key , new ConfigOptionEnum < SupportMaterialPattern > ( boost :: any_cast < SupportMaterialPattern > ( value )));
else if ( opt_key . compare ( "seam_position" ) == 0 )
config . set_key_value ( opt_key , new ConfigOptionEnum < SeamPosition > ( boost :: any_cast < SeamPosition > ( value )));
}
2018-01-07 18:41:40 +01:00
break ;
2018-01-30 12:10:12 +01:00
case coPoints :{
2018-03-23 17:27:43 +01:00
if ( opt_key . compare ( "bed_shape" ) == 0 ){
config . option < ConfigOptionPoints > ( opt_key ) -> values = boost :: any_cast < std :: vector < Pointf >> ( value );
break ;
}
2018-03-08 11:58:06 +01:00
ConfigOptionPoints * vec_new = new ConfigOptionPoints { boost :: any_cast < Pointf > ( value ) };
config . option < ConfigOptionPoints > ( opt_key ) -> set_at ( vec_new , opt_index , 0 );
2018-01-30 12:10:12 +01:00
}
2018-01-07 18:41:40 +01:00
break ;
case coNone :
break ;
default :
break ;
}
}
catch ( const std :: exception & e )
{
2018-01-09 13:52:01 +01:00
int i = 0 ; //no reason, just experiment
2018-01-07 18:41:40 +01:00
}
}
2018-03-09 17:17:51 +01:00
void add_created_tab ( Tab * panel )
2017-12-22 11:50:28 +01:00
{
2018-03-09 17:17:51 +01:00
panel -> create_preset_tab ( g_PresetBundle );
2018-01-05 15:11:33 +01:00
2018-01-16 16:28:01 +01:00
// Load the currently selected preset into the GUI, update the preset selection box.
panel -> load_current_preset ();
2018-08-06 17:01:41 +02:00
const wxString & tab_name = panel -> GetName ();
bool add_panel = true ;
if ( tab_name == "print" ) {
g_PrintTab = panel ;
add_panel = g_PresetBundle -> printers . get_edited_preset (). printer_technology () == ptFFF ;
}
else if ( tab_name == "filament" ) {
g_FilamentTab = panel ;
add_panel = g_PresetBundle -> printers . get_edited_preset (). printer_technology () == ptFFF ;
}
else if ( tab_name == "sla_material" ) {
g_MaterialTab = panel ;
add_panel = g_PresetBundle -> printers . get_edited_preset (). printer_technology () == ptSLA ;
}
if ( add_panel )
g_wxTabPanel -> AddPage ( panel , panel -> title ());
2017-12-22 11:50:28 +01:00
}
2018-06-06 10:52:19 +02:00
void load_current_presets ()
{
for ( Tab * tab : g_tabs_list ) {
tab -> load_current_preset ();
}
}
2018-04-30 14:31:57 +02:00
void show_error ( wxWindow * parent , const wxString & message ) {
ErrorDialog msg ( parent , message );
msg . ShowModal ();
}
void show_error_id ( int id , const std :: string & message ) {
auto * parent = id != 0 ? wxWindow :: FindWindowById ( id ) : nullptr ;
2018-05-22 14:33:11 +02:00
show_error ( parent , wxString :: FromUTF8 ( message . data ()));
2017-12-22 11:50:28 +01:00
}
2018-04-13 12:35:04 +02:00
void show_info ( wxWindow * parent , const wxString & message , const wxString & title ){
2018-04-30 14:31:57 +02:00
wxMessageDialog msg_wingow ( parent , message , title . empty () ? _ ( L ( "Notice" )) : title , wxOK | wxICON_INFORMATION );
msg_wingow . ShowModal ();
2017-12-04 10:48:40 +01:00
}
2018-04-13 12:35:04 +02:00
void warning_catcher ( wxWindow * parent , const wxString & message ){
2018-05-02 13:20:36 +02:00
if ( message == "GLUquadricObjPtr | " + _ ( L ( "Attempt to free unreferenced scalar" )) )
2018-02-22 11:12:29 +01:00
return ;
2018-04-30 14:31:57 +02:00
wxMessageDialog msg ( parent , message , _ ( L ( "Warning" )), wxOK | wxICON_WARNING );
msg . ShowModal ();
2018-02-22 11:12:29 +01:00
}
2018-02-05 16:12:16 +01:00
wxApp * get_app (){
return g_wxApp ;
2017-12-04 10:48:40 +01:00
}
2018-04-24 18:06:42 +02:00
PresetBundle * get_preset_bundle ()
{
return g_PresetBundle ;
}
2018-08-06 17:01:41 +02:00
wxNotebook * get_tab_panel () {
return g_wxTabPanel ;
}
wxWindow * get_print_tab () {
return g_PrintTab ;
}
wxWindow * get_filament_tab (){
return g_FilamentTab ;
}
wxWindow * get_material_tab (){
return g_MaterialTab ;
}
2018-04-30 14:20:33 +02:00
const wxColour & get_label_clr_modified () {
2018-04-09 14:41:55 +02:00
return g_color_label_modified ;
2018-03-02 09:08:11 +01:00
}
2018-04-30 14:20:33 +02:00
const wxColour & get_label_clr_sys () {
2018-04-09 14:41:55 +02:00
return g_color_label_sys ;
}
2018-04-30 14:20:33 +02:00
void set_label_clr_modified ( const wxColour & clr ) {
g_color_label_modified = clr ;
auto clr_str = wxString :: Format ( wxT ( "#%02X%02X%02X" ), clr . Red (), clr . Green (), clr . Blue ());
std :: string str = clr_str . ToStdString ();
g_AppConfig -> set ( "label_clr_modified" , str );
g_AppConfig -> save ();
}
void set_label_clr_sys ( const wxColour & clr ) {
g_color_label_sys = clr ;
auto clr_str = wxString :: Format ( wxT ( "#%02X%02X%02X" ), clr . Red (), clr . Green (), clr . Blue ());
std :: string str = clr_str . ToStdString ();
g_AppConfig -> set ( "label_clr_sys" , str );
g_AppConfig -> save ();
}
2018-06-20 14:20:48 +02:00
const wxFont & small_font (){
return g_small_font ;
}
const wxFont & bold_font (){
return g_bold_font ;
}
2018-04-30 14:20:33 +02:00
const wxColour & get_label_clr_default () {
2018-04-18 13:32:21 +02:00
return g_color_label_default ;
}
2018-04-09 14:41:55 +02:00
unsigned get_colour_approx_luma ( const wxColour & colour )
{
double r = colour . Red ();
double g = colour . Green ();
double b = colour . Blue ();
2018-04-10 11:43:04 +02:00
return std :: round ( std :: sqrt (
2018-04-09 14:41:55 +02:00
r * r * .241 +
g * g * .691 +
b * b * .068
));
2018-03-16 12:56:03 +01:00
}
2018-02-02 12:38:35 +01:00
void create_combochecklist ( wxComboCtrl * comboCtrl , std :: string text , std :: string items , bool initial_value )
{
2018-02-06 12:43:25 +01:00
if ( comboCtrl == nullptr )
return ;
wxCheckListBoxComboPopup * popup = new wxCheckListBoxComboPopup ;
2018-02-02 12:38:35 +01:00
if ( popup != nullptr )
{
2018-02-20 15:22:30 +01:00
// FIXME If the following line is removed, the combo box popup list will not react to mouse clicks.
// On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10.
comboCtrl -> UseAltPopupWindow ();
comboCtrl -> EnablePopupAnimation ( false );
2018-02-02 12:38:35 +01:00
comboCtrl -> SetPopupControl ( popup );
2018-02-28 15:39:20 +01:00
popup -> SetStringValue ( from_u8 ( text ));
2018-02-20 11:40:15 +01:00
popup -> Bind ( wxEVT_CHECKLISTBOX , [ popup ]( wxCommandEvent & evt ) { popup -> OnCheckListBox ( evt ); });
popup -> Bind ( wxEVT_LISTBOX , [ popup ]( wxCommandEvent & evt ) { popup -> OnListBoxSelection ( evt ); });
2018-02-20 14:25:40 +01:00
popup -> Bind ( wxEVT_KEY_DOWN , [ popup ]( wxKeyEvent & evt ) { popup -> OnKeyEvent ( evt ); });
popup -> Bind ( wxEVT_KEY_UP , [ popup ]( wxKeyEvent & evt ) { popup -> OnKeyEvent ( evt ); });
2018-02-02 12:38:35 +01:00
std :: vector < std :: string > items_str ;
boost :: split ( items_str , items , boost :: is_any_of ( "|" ), boost :: token_compress_off );
for ( const std :: string & item : items_str )
{
2018-02-26 16:23:44 +01:00
popup -> Append ( from_u8 ( item ));
2018-02-02 12:38:35 +01:00
}
for ( unsigned int i = 0 ; i < popup -> GetCount (); ++ i )
{
popup -> Check ( i , initial_value );
}
}
}
int combochecklist_get_flags ( wxComboCtrl * comboCtrl )
{
int flags = 0 ;
wxCheckListBoxComboPopup * popup = wxDynamicCast ( comboCtrl -> GetPopupControl (), wxCheckListBoxComboPopup );
if ( popup != nullptr )
{
for ( unsigned int i = 0 ; i < popup -> GetCount (); ++ i )
{
if ( popup -> IsChecked ( i ))
2018-02-13 17:46:23 +01:00
flags |= 1 << i ;
2018-02-02 12:38:35 +01:00
}
}
return flags ;
}
2018-02-22 11:12:29 +01:00
AppConfig * get_app_config ()
{
return g_AppConfig ;
}
2018-03-06 09:44:53 +01:00
wxString L_str ( const std :: string & str )
2018-02-22 11:34:41 +01:00
{
2018-02-23 09:16:35 +01:00
//! Explicitly specify that the source string is already in UTF-8 encoding
2018-02-22 11:34:41 +01:00
return wxGetTranslation ( wxString ( str . c_str (), wxConvUTF8 ));
}
2018-03-06 09:44:53 +01:00
wxString from_u8 ( const std :: string & str )
2018-02-22 11:34:41 +01:00
{
return wxString :: FromUTF8 ( str . c_str ());
}
2018-02-07 11:37:15 +01:00
2018-03-09 18:34:30 +01:00
void add_frequently_changed_parameters ( wxWindow * parent , wxBoxSizer * sizer , wxFlexGridSizer * preset_sizer )
{
DynamicPrintConfig * config = & g_PresetBundle -> prints . get_edited_preset (). config ;
m_optgroup = std :: make_shared < ConfigOptionsGroup > ( parent , "" , config );
2018-05-20 23:39:52 +02:00
const wxArrayInt & ar = preset_sizer -> GetColWidths ();
m_optgroup -> label_width = ar . IsEmpty () ? 100 : ar . front () - 4 ; // doesn't work
2018-03-12 16:52:21 +01:00
m_optgroup -> m_on_change = [ config ]( t_config_option_key opt_key , boost :: any value ){
TabPrint * tab_print = nullptr ;
for ( size_t i = 0 ; i < g_wxTabPanel -> GetPageCount (); ++ i ) {
Tab * tab = dynamic_cast < Tab *> ( g_wxTabPanel -> GetPage ( i ));
if ( ! tab )
continue ;
if ( tab -> name () == "print" ){
tab_print = static_cast < TabPrint *> ( tab );
break ;
}
}
if ( tab_print == nullptr )
return ;
if ( opt_key == "fill_density" ){
value = m_optgroup -> get_config_value ( * config , opt_key );
tab_print -> set_value ( opt_key , value );
2018-03-14 10:14:48 +01:00
tab_print -> update ();
2018-03-12 16:52:21 +01:00
}
2018-03-13 16:14:36 +01:00
else {
DynamicPrintConfig new_conf = * config ;
if ( opt_key == "brim" ){
double new_val ;
double brim_width = config -> opt_float ( "brim_width" );
if ( boost :: any_cast < bool > ( value ) == true )
{
new_val = m_brim_width == 0.0 ? 10 :
m_brim_width < 0.0 ? m_brim_width * ( - 1 ) :
m_brim_width ;
}
else {
m_brim_width = brim_width * ( - 1 );
new_val = 0 ;
}
new_conf . set_key_value ( "brim_width" , new ConfigOptionFloat ( new_val ));
2018-03-12 16:52:21 +01:00
}
2018-03-13 16:14:36 +01:00
else { //(opt_key == "support")
const wxString & selection = boost :: any_cast < wxString > ( value );
auto support_material = selection == _ ( "None" ) ? false : true ;
new_conf . set_key_value ( "support_material" , new ConfigOptionBool ( support_material ));
if ( selection == _ ( "Everywhere" ))
new_conf . set_key_value ( "support_material_buildplate_only" , new ConfigOptionBool ( false ));
else if ( selection == _ ( "Support on build plate only" ))
new_conf . set_key_value ( "support_material_buildplate_only" , new ConfigOptionBool ( true ));
}
tab_print -> load_config ( new_conf );
2018-03-12 16:52:21 +01:00
}
tab_print -> update_dirty ();
2018-03-09 18:34:30 +01:00
};
2018-03-12 16:52:21 +01:00
Option option = m_optgroup -> get_option ( "fill_density" );
option . opt . sidetext = "" ;
2018-04-25 11:10:34 +02:00
option . opt . full_width = true ;
2018-03-12 16:52:21 +01:00
m_optgroup -> append_single_option_line ( option );
2018-03-09 18:34:30 +01:00
ConfigOptionDef def ;
def . label = L ( "Support" );
2018-03-13 16:14:36 +01:00
def . type = coStrings ;
2018-03-09 18:34:30 +01:00
def . gui_type = "select_open" ;
def . tooltip = L ( "Select what kind of support do you need" );
def . enum_labels . push_back ( L ( "None" ));
def . enum_labels . push_back ( L ( "Support on build plate only" ));
def . enum_labels . push_back ( L ( "Everywhere" ));
2018-03-13 16:14:36 +01:00
std :: string selection = ! config -> opt_bool ( "support_material" ) ?
"None" :
config -> opt_bool ( "support_material_buildplate_only" ) ?
"Support on build plate only" :
"Everywhere" ;
def . default_value = new ConfigOptionStrings { selection };
2018-03-12 16:52:21 +01:00
option = Option ( def , "support" );
2018-04-25 11:10:34 +02:00
option . opt . full_width = true ;
2018-03-09 18:34:30 +01:00
m_optgroup -> append_single_option_line ( option );
2018-03-13 16:14:36 +01:00
m_brim_width = config -> opt_float ( "brim_width" );
2018-03-09 18:34:30 +01:00
def . label = L ( "Brim" );
def . type = coBool ;
def . tooltip = L ( "This flag enables the brim that will be printed around each object on the first layer." );
def . gui_type = "" ;
2018-03-13 16:14:36 +01:00
def . default_value = new ConfigOptionBool { m_brim_width > 0.0 ? true : false };
2018-03-09 18:34:30 +01:00
option = Option ( def , "brim" );
m_optgroup -> append_single_option_line ( option );
2018-03-27 13:44:18 +02:00
2018-05-02 13:20:36 +02:00
Line line = { "" , "" };
2018-03-27 13:44:18 +02:00
line . widget = [ config ]( wxWindow * parent ){
2018-06-07 22:10:23 +02:00
g_wiping_dialog_button = new wxButton ( parent , wxID_ANY , _ ( L ( "Purging volumes" )) + dots , wxDefaultPosition , wxDefaultSize , wxBU_EXACTFIT );
2018-03-27 13:44:18 +02:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
2018-04-03 22:07:59 +02:00
sizer -> Add ( g_wiping_dialog_button );
2018-04-04 10:18:26 +02:00
g_wiping_dialog_button -> Bind ( wxEVT_BUTTON , ([ parent ]( wxCommandEvent & e )
2018-03-27 13:44:18 +02:00
{
2018-04-04 10:18:26 +02:00
auto & config = g_PresetBundle -> project_config ;
std :: vector < double > init_matrix = ( config . option < ConfigOptionFloats > ( "wiping_volumes_matrix" )) -> values ;
std :: vector < double > init_extruders = ( config . option < ConfigOptionFloats > ( "wiping_volumes_extruders" )) -> values ;
2018-03-27 13:44:18 +02:00
WipingDialog dlg ( parent , std :: vector < float > ( init_matrix . begin (), init_matrix . end ()), std :: vector < float > ( init_extruders . begin (), init_extruders . end ()));
if ( dlg . ShowModal () == wxID_OK ) {
std :: vector < float > matrix = dlg . get_matrix ();
std :: vector < float > extruders = dlg . get_extruders ();
2018-04-04 10:18:26 +02:00
( config . option < ConfigOptionFloats > ( "wiping_volumes_matrix" )) -> values = std :: vector < double > ( matrix . begin (), matrix . end ());
( config . option < ConfigOptionFloats > ( "wiping_volumes_extruders" )) -> values = std :: vector < double > ( extruders . begin (), extruders . end ());
2018-03-27 13:44:18 +02:00
}
}));
return sizer ;
};
m_optgroup -> append_line ( line );
2018-04-25 11:10:34 +02:00
sizer -> Add ( m_optgroup -> sizer , 1 , wxEXPAND | wxBOTTOM , 2 );
2018-03-09 18:34:30 +01:00
}
2018-03-12 16:52:21 +01:00
ConfigOptionsGroup * get_optgroup ()
{
return m_optgroup . get ();
}
2018-04-04 13:06:46 +02:00
2018-04-04 14:41:23 +02:00
wxButton * get_wiping_dialog_button ()
{
2018-04-03 22:07:59 +02:00
return g_wiping_dialog_button ;
2018-04-04 14:41:23 +02:00
}
2018-04-04 13:06:46 +02:00
2018-03-22 13:49:48 +01:00
wxWindow * export_option_creator ( wxWindow * parent )
{
wxPanel * panel = new wxPanel ( parent , - 1 );
wxSizer * sizer = new wxBoxSizer ( wxHORIZONTAL );
wxCheckBox * cbox = new wxCheckBox ( panel , wxID_HIGHEST + 1 , L ( "Export print config" ));
2018-04-25 15:31:37 +02:00
cbox -> SetValue ( true );
2018-03-22 13:49:48 +01:00
sizer -> AddSpacer ( 5 );
sizer -> Add ( cbox , 0 , wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL , 5 );
panel -> SetSizer ( sizer );
sizer -> SetSizeHints ( panel );
return panel ;
}
void add_export_option ( wxFileDialog * dlg , const std :: string & format )
{
if (( dlg != nullptr ) && ( format == "AMF" ) || ( format == "3MF" ))
{
if ( dlg -> SupportsExtraControl ())
dlg -> SetExtraControlCreator ( export_option_creator );
}
}
int get_export_option ( wxFileDialog * dlg )
{
if ( dlg != nullptr )
{
wxWindow * wnd = dlg -> GetExtraControl ();
if ( wnd != nullptr )
{
wxPanel * panel = dynamic_cast < wxPanel *> ( wnd );
if ( panel != nullptr )
{
wxWindow * child = panel -> FindWindow ( wxID_HIGHEST + 1 );
if ( child != nullptr )
{
wxCheckBox * cbox = dynamic_cast < wxCheckBox *> ( child );
if ( cbox != nullptr )
return cbox -> IsChecked () ? 1 : 0 ;
}
}
}
}
return 0 ;
2018-04-04 14:41:23 +02:00
2018-03-22 13:49:48 +01:00
}
2018-06-11 18:24:13 +02:00
void get_current_screen_size ( unsigned & width , unsigned & height )
{
wxDisplay display ( wxDisplay :: GetFromWindow ( g_wxMainFrame ));
const auto disp_size = display . GetClientArea ();
width = disp_size . GetWidth ();
height = disp_size . GetHeight ();
}
2018-04-09 17:03:37 +02:00
void about ()
{
AboutDialog dlg ;
dlg . ShowModal ();
dlg . Destroy ();
}
2018-05-21 21:04:03 +02:00
void desktop_open_datadir_folder ()
2018-06-04 09:07:29 +02:00
{
2018-05-21 22:10:38 +02:00
// Execute command to open a file explorer, platform dependent.
2018-06-04 09:07:29 +02:00
// FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade.
const auto path = data_dir ();
2018-05-21 21:04:03 +02:00
#ifdef _WIN32
2018-06-04 09:07:29 +02:00
const auto widepath = wxString :: FromUTF8 ( path . data ());
const wchar_t * argv [] = { L "explorer" , widepath . GetData (), nullptr };
:: wxExecute ( const_cast < wchar_t **> ( argv ), wxEXEC_ASYNC , nullptr );
2018-05-21 21:04:03 +02:00
#elif __APPLE__
2018-06-04 09:07:29 +02:00
const char * argv [] = { "open" , path . data (), nullptr };
:: wxExecute ( const_cast < char **> ( argv ), wxEXEC_ASYNC , nullptr );
2018-05-21 21:04:03 +02:00
#else
2018-06-04 09:07:29 +02:00
const char * argv [] = { "xdg-open" , path . data (), nullptr };
// Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars,
// because they may mess up the environment expected by the file manager.
// Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure.
if ( wxGetEnv ( "APPIMAGE" , nullptr )) {
// We're running from AppImage
wxEnvVariableHashMap env_vars ;
wxGetEnvMap ( & env_vars );
env_vars . erase ( "APPIMAGE" );
env_vars . erase ( "APPDIR" );
env_vars . erase ( "LD_LIBRARY_PATH" );
env_vars . erase ( "LD_PRELOAD" );
env_vars . erase ( "UNION_PRELOAD" );
wxExecuteEnv exec_env ;
exec_env . env = std :: move ( env_vars );
wxString owd ;
if ( wxGetEnv ( "OWD" , & owd )) {
// This is the original work directory from which the AppImage image was run,
// set it as CWD for the child process:
exec_env . cwd = std :: move ( owd );
}
:: wxExecute ( const_cast < char **> ( argv ), wxEXEC_ASYNC , nullptr , & exec_env );
} else {
// Looks like we're NOT running from AppImage, we'll make no changes to the environment.
:: wxExecute ( const_cast < char **> ( argv ), wxEXEC_ASYNC , nullptr , nullptr );
}
2018-05-21 21:04:03 +02:00
#endif
}
2015-12-04 21:25:45 +01:00
} }