2018-09-20 08:40:22 +02:00
#include "MainFrame.hpp"
#include <wx/panel.h>
#include <wx/notebook.h>
#include <wx/icon.h>
#include <wx/sizer.h>
#include <wx/menu.h>
#include <wx/progdlg.h>
2018-09-21 15:42:31 +02:00
#include <wx/tooltip.h>
2018-10-18 15:13:38 +02:00
#include <wx/glcanvas.h>
2018-10-03 16:27:02 +02:00
#include <wx/debug.h>
2018-09-20 08:40:22 +02:00
2019-01-09 10:43:17 +01:00
#include <boost/algorithm/string/predicate.hpp>
2018-11-26 14:41:58 +01:00
#include "libslic3r/Print.hpp"
#include "libslic3r/Polygon.hpp"
2018-09-20 08:40:22 +02:00
#include "Tab.hpp"
#include "PresetBundle.hpp"
#include "ProgressStatusBar.hpp"
#include "3DScene.hpp"
#include "AppConfig.hpp"
2018-12-14 15:27:34 +01:00
#include "PrintHostDialogs.hpp"
2018-10-17 12:17:25 +02:00
#include "wxExtensions.hpp"
2019-01-30 10:05:54 +01:00
#include "GUI_ObjectList.hpp"
2018-11-26 14:41:58 +01:00
#include "I18N.hpp"
2018-09-20 08:40:22 +02:00
#include <fstream>
2018-09-21 01:33:41 +02:00
#include "GUI_App.hpp"
2018-09-20 08:40:22 +02:00
namespace Slic3r {
2018-09-21 01:33:41 +02:00
namespace GUI {
2018-12-19 17:38:41 +01:00
MainFrame :: MainFrame () :
2019-01-11 18:09:21 +01:00
wxFrame ( NULL , wxID_ANY , SLIC3R_BUILD , wxDefaultPosition , wxDefaultSize , wxDEFAULT_FRAME_STYLE , "mainframe" ),
2018-12-14 15:27:34 +01:00
m_printhost_queue_dlg ( new PrintHostQueueDialog ( this ))
2018-09-20 08:40:22 +02:00
{
2018-09-24 14:27:03 +02:00
// Load the icon either from the exe, or from the ico file.
#if _WIN32
{
TCHAR szExeFileName [ MAX_PATH ];
GetModuleFileName ( nullptr , szExeFileName , MAX_PATH );
SetIcon ( wxIcon ( szExeFileName , wxBITMAP_TYPE_ICO ));
}
#else
2018-09-21 01:33:41 +02:00
SetIcon ( wxIcon ( Slic3r :: var ( "Slic3r_128px.png" ), wxBITMAP_TYPE_PNG ));
2018-09-24 14:27:03 +02:00
#endif // _WIN32
2018-09-20 08:40:22 +02:00
2018-12-04 11:14:39 +01:00
// initialize status bar
m_statusbar = new ProgressStatusBar ( this );
m_statusbar -> embed ( this );
2019-01-21 12:34:28 +01:00
m_statusbar -> set_status_text ( _ ( L ( "Version" )) + " " +
2018-12-04 11:14:39 +01:00
SLIC3R_VERSION +
_ ( L ( " - Remember to check for updates at http://github.com/prusa3d/slic3r/releases" )));
2019-01-31 15:55:09 +01:00
// initialize default width_unit according to the width of the one symbol ("x") of the current system font
2019-02-04 10:35:16 +01:00
const wxSize size = GetTextExtent ( "m" );
2019-02-06 15:29:13 +01:00
wxGetApp (). set_em_unit ( size . x - 1 );
2019-01-31 15:55:09 +01:00
2018-09-20 08:40:22 +02:00
// initialize tabpanel and menubar
2018-09-21 01:33:41 +02:00
init_tabpanel ();
init_menubar ();
2018-09-20 08:40:22 +02:00
// set default tooltip timer in msec
// SetAutoPop supposedly accepts long integers but some bug doesn't allow for larger values
// (SetAutoPop is not available on GTK.)
2018-09-21 01:33:41 +02:00
wxToolTip :: SetAutoPop ( 32767 );
2018-09-20 08:40:22 +02:00
2018-09-21 01:33:41 +02:00
m_loaded = true ;
// initialize layout
auto sizer = new wxBoxSizer ( wxVERTICAL );
if ( m_tabpanel )
sizer -> Add ( m_tabpanel , 1 , wxEXPAND );
sizer -> SetSizeHints ( this );
SetSizer ( sizer );
Fit ();
2019-01-21 17:36:25 +01:00
#ifdef __APPLE__
// Using SetMinSize() on Mac messes up the window position in some cases
// cf. https://groups.google.com/forum/#!topic/wx-users/yUKPBBfXWO0
SetSize ( wxSize ( 760 , 490 ));
#else
2018-09-21 01:33:41 +02:00
SetMinSize ( wxSize ( 760 , 490 ));
SetSize ( GetMinSize ());
2019-01-21 17:36:25 +01:00
#endif
2018-09-21 01:33:41 +02:00
Layout ();
2018-09-20 08:40:22 +02:00
// declare events
2018-10-31 12:56:08 +01:00
Bind ( wxEVT_CLOSE_WINDOW , [ this ]( wxCloseEvent & event ) {
2018-09-21 01:33:41 +02:00
if ( event . CanVeto () && ! wxGetApp (). check_unsaved_changes ()) {
event . Veto ();
return ;
}
2019-01-11 18:09:21 +01:00
2018-09-21 01:33:41 +02:00
// Save the slic3r.ini.Usually the ini file is saved from "on idle" callback,
// but in rare cases it may not have been called yet.
wxGetApp (). app_config -> save ();
2018-09-20 08:40:22 +02:00
// if (m_plater)
// m_plater->print = undef;
2018-09-21 01:33:41 +02:00
_3DScene :: remove_all_canvases ();
2018-09-20 08:40:22 +02:00
// Slic3r::GUI::deregister_on_request_update_callback();
2019-01-25 13:16:32 +01:00
2019-01-28 12:12:14 +01:00
// set to null tabs and a platter
2019-01-25 13:16:32 +01:00
// to avoid any manipulations with them from App->wxEVT_IDLE after of the mainframe closing
2019-01-28 12:12:14 +01:00
wxGetApp (). tabs_list . clear ();
wxGetApp (). plater_ = nullptr ;
2019-01-25 13:16:32 +01:00
2018-09-21 01:33:41 +02:00
// propagate event
event . Skip ();
});
2018-09-20 08:40:22 +02:00
2019-02-19 14:57:59 +01:00
Bind ( wxEVT_ACTIVATE , [ this ]( wxActivateEvent & event ) {
if ( m_plater != nullptr && event . GetActive ())
m_plater -> on_activate ();
2019-02-20 12:21:22 +01:00
event . Skip ();
2019-02-19 14:57:59 +01:00
});
2019-01-11 18:09:21 +01:00
wxGetApp (). persist_window_geometry ( this );
2018-10-17 14:01:10 +02:00
2019-01-11 18:09:21 +01:00
update_ui_from_settings (); // FIXME (?)
2018-09-20 08:40:22 +02:00
}
2019-01-28 12:12:14 +01:00
2018-09-20 08:40:22 +02:00
void MainFrame :: init_tabpanel ()
{
m_tabpanel = new wxNotebook ( this , wxID_ANY , wxDefaultPosition , wxDefaultSize , wxNB_TOP | wxTAB_TRAVERSAL );
2018-10-31 12:56:08 +01:00
m_tabpanel -> Bind ( wxEVT_NOTEBOOK_PAGE_CHANGED , [ this ]( wxEvent & ) {
2018-09-21 01:33:41 +02:00
auto panel = m_tabpanel -> GetCurrentPage ();
2018-10-02 13:23:38 +02:00
if ( panel == nullptr )
2018-09-17 12:15:11 +02:00
return ;
2018-11-19 13:17:14 +01:00
auto & tabs_list = wxGetApp (). tabs_list ;
if ( find ( tabs_list . begin (), tabs_list . end (), panel ) != tabs_list . end ()) {
// On GTK, the wxEVT_NOTEBOOK_PAGE_CHANGED event is triggered
// before the MainFrame is fully set up.
static_cast < Tab *> ( panel ) -> OnActivate ();
2018-09-21 01:33:41 +02:00
}
});
2018-09-20 08:40:22 +02:00
2018-12-19 17:38:41 +01:00
m_plater = new Slic3r :: GUI :: Plater ( m_tabpanel , this );
wxGetApp (). plater_ = m_plater ;
m_tabpanel -> AddPage ( m_plater , _ ( L ( "Plater" )));
2018-09-20 08:40:22 +02:00
2019-01-30 10:05:54 +01:00
wxGetApp (). obj_list () -> create_popup_menus ();
2018-10-09 12:41:05 +02:00
// The following event is emited by Tab implementation on config value change.
2019-02-22 09:38:56 +01:00
Bind ( EVT_TAB_VALUE_CHANGED , & MainFrame :: on_value_changed , this ); // #ys_FIXME_to_delete
2018-09-20 08:40:22 +02:00
2018-10-03 16:27:02 +02:00
// The following event is emited by Tab on preset selection,
2018-09-20 08:40:22 +02:00
// or when the preset's "modified" status changes.
2019-02-22 09:38:56 +01:00
Bind ( EVT_TAB_PRESETS_CHANGED , & MainFrame :: on_presets_changed , this ); // #ys_FIXME_to_delete
2018-10-03 16:27:02 +02:00
2018-09-21 01:33:41 +02:00
create_preset_tabs ();
2018-09-20 08:40:22 +02:00
if ( m_plater ) {
// load initial config
2018-09-21 01:33:41 +02:00
auto full_config = wxGetApp (). preset_bundle -> full_config ();
2018-10-17 11:12:38 +02:00
m_plater -> on_config_change ( full_config );
2018-09-20 08:40:22 +02:00
// Show a correct number of filament fields.
2018-10-10 13:53:45 +02:00
// nozzle_diameter is undefined when SLA printer is selected
2018-10-31 12:56:08 +01:00
if ( full_config . has ( "nozzle_diameter" )) {
2018-10-10 13:53:45 +02:00
m_plater -> on_extruders_change ( full_config . option < ConfigOptionFloats > ( "nozzle_diameter" ) -> values . size ());
}
2018-09-20 08:40:22 +02:00
}
}
2018-09-21 01:33:41 +02:00
void MainFrame :: create_preset_tabs ()
{
2018-10-01 15:09:31 +02:00
wxGetApp (). update_label_colours_from_appconfig ();
2018-09-21 01:33:41 +02:00
add_created_tab ( new TabPrint ( m_tabpanel ));
add_created_tab ( new TabFilament ( m_tabpanel ));
2018-11-19 13:17:14 +01:00
add_created_tab ( new TabSLAPrint ( m_tabpanel ));
2018-09-21 01:33:41 +02:00
add_created_tab ( new TabSLAMaterial ( m_tabpanel ));
add_created_tab ( new TabPrinter ( m_tabpanel ));
}
void MainFrame :: add_created_tab ( Tab * panel )
{
2018-10-04 16:43:10 +02:00
panel -> create_preset_tab ();
2018-11-19 09:15:53 +01:00
2018-11-19 13:17:14 +01:00
const auto printer_tech = wxGetApp (). preset_bundle -> printers . get_edited_preset (). printer_technology ();
2018-09-21 01:33:41 +02:00
2018-11-19 13:17:14 +01:00
if ( panel -> supports_printer_technology ( printer_tech ))
2018-09-21 01:33:41 +02:00
m_tabpanel -> AddPage ( panel , panel -> title ());
}
2018-11-15 15:27:39 +01:00
bool MainFrame :: can_save () const
{
return ( m_plater != nullptr ) ? ! m_plater -> model (). objects . empty () : false ;
}
bool MainFrame :: can_export_model () const
{
return ( m_plater != nullptr ) ? ! m_plater -> model (). objects . empty () : false ;
}
bool MainFrame :: can_export_gcode () const
{
if ( m_plater == nullptr )
return false ;
if ( m_plater -> model (). objects . empty ())
return false ;
if ( m_plater -> is_export_gcode_scheduled ())
return false ;
// TODO:: add other filters
return true ;
}
2018-11-16 12:31:06 +01:00
2019-01-21 12:34:28 +01:00
bool MainFrame :: can_slice () const
{
bool bg_proc = wxGetApp (). app_config -> get ( "background_processing" ) == "1" ;
return ( m_plater != nullptr ) ? ! m_plater -> model (). objects . empty () && ! bg_proc : false ;
}
2018-11-16 12:31:06 +01:00
bool MainFrame :: can_change_view () const
{
int page_id = m_tabpanel -> GetSelection ();
2019-01-10 14:45:09 +01:00
return page_id != wxNOT_FOUND && dynamic_cast < const Slic3r :: GUI :: Plater *> ( m_tabpanel -> GetPage (( size_t ) page_id )) != nullptr ;
2018-11-16 12:31:06 +01:00
}
2018-11-21 15:28:35 +01:00
bool MainFrame :: can_select () const
{
return ( m_plater != nullptr ) ? ! m_plater -> model (). objects . empty () : false ;
}
2018-11-21 15:47:41 +01:00
bool MainFrame :: can_delete () const
{
return ( m_plater != nullptr ) ? ! m_plater -> is_selection_empty () : false ;
}
2018-11-22 11:31:53 +01:00
bool MainFrame :: can_delete_all () const
{
return ( m_plater != nullptr ) ? ! m_plater -> model (). objects . empty () : false ;
}
2018-11-15 15:27:39 +01:00
2018-09-20 08:40:22 +02:00
void MainFrame :: init_menubar ()
{
2019-01-11 17:06:46 +01:00
#ifdef __APPLE__
wxMenuBar :: SetAutoWindowMenu ( false );
#endif
2018-09-20 08:40:22 +02:00
// File menu
2018-09-21 01:33:41 +02:00
wxMenu * fileMenu = new wxMenu ;
2018-09-20 08:40:22 +02:00
{
2019-01-29 14:44:10 +01:00
wxMenuItem * item_open = append_menu_item ( fileMenu , wxID_ANY , _ ( L ( "&Open Project" )) + dots + " \t Ctrl+O" , _ ( L ( "Open a project file" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { if ( m_plater ) m_plater -> load_project (); }, "brick_add.png" );
2019-01-29 14:44:10 +01:00
wxMenuItem * item_save = append_menu_item ( fileMenu , wxID_ANY , _ ( L ( "&Save Project" )) + " \t Ctrl+S" , _ ( L ( "Save current project file" )),
2019-01-02 15:11:05 +01:00
[ this ]( wxCommandEvent & ) { if ( m_plater ) m_plater -> export_3mf ( into_path ( m_plater -> get_project_filename ())); }, "disk.png" );
2019-01-29 14:44:10 +01:00
wxMenuItem * item_save_as = append_menu_item ( fileMenu , wxID_ANY , _ ( L ( "Save Project &as" )) + dots + " \t Ctrl+Alt+S" , _ ( L ( "Save current project file as" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { if ( m_plater ) m_plater -> export_3mf (); }, "disk.png" );
fileMenu -> AppendSeparator ();
wxMenu * import_menu = new wxMenu ();
2019-01-21 12:34:28 +01:00
wxMenuItem * item_import_model = append_menu_item ( import_menu , wxID_ANY , _ ( L ( "Import STL/OBJ/AM&F/3MF" )) + dots + " \t Ctrl+I" , _ ( L ( "Load a model" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { if ( m_plater ) m_plater -> add_model (); }, "brick_add.png" );
import_menu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
append_menu_item ( import_menu , wxID_ANY , _ ( L ( "Import &Config" )) + dots + " \t Ctrl+L" , _ ( L ( "Load exported configuration file" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { load_config_file (); }, "plugin_add.png" );
2019-01-21 12:34:28 +01:00
append_menu_item ( import_menu , wxID_ANY , _ ( L ( "Import Config from &project" )) + dots + " \t Ctrl+Alt+L" , _ ( L ( "Load configuration from project file" )),
2018-11-16 09:26:41 +01:00
[ this ]( wxCommandEvent & ) { if ( m_plater ) m_plater -> extract_config_from_project (); }, "plugin_add.png" );
import_menu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
append_menu_item ( import_menu , wxID_ANY , _ ( L ( "Import Config &Bundle" )) + dots , _ ( L ( "Load presets from a bundle" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { load_configbundle (); }, "lorry_add.png" );
2019-01-21 12:34:28 +01:00
append_submenu ( fileMenu , import_menu , wxID_ANY , _ ( L ( "&Import" )), "" );
2018-11-15 15:27:39 +01:00
wxMenu * export_menu = new wxMenu ();
2019-01-21 12:34:28 +01:00
wxMenuItem * item_export_gcode = append_menu_item ( export_menu , wxID_ANY , _ ( L ( "Export &G-code" )) + dots + " \t Ctrl+G" , _ ( L ( "Export current plate as G-code" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { if ( m_plater ) m_plater -> export_gcode (); }, "cog_go.png" );
export_menu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
wxMenuItem * item_export_stl = append_menu_item ( export_menu , wxID_ANY , _ ( L ( "Export plate as &STL" )) + dots , _ ( L ( "Export current plate as STL" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { if ( m_plater ) m_plater -> export_stl (); }, "brick_go.png" );
2019-01-21 12:34:28 +01:00
wxMenuItem * item_export_amf = append_menu_item ( export_menu , wxID_ANY , _ ( L ( "Export plate as &AMF" )) + dots , _ ( L ( "Export current plate as AMF" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { if ( m_plater ) m_plater -> export_amf (); }, "brick_go.png" );
export_menu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
append_menu_item ( export_menu , wxID_ANY , _ ( L ( "Export &Config" )) + dots + " \t Ctrl+E" , _ ( L ( "Export current configuration to file" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { export_config (); }, "plugin_go.png" );
2019-01-21 12:34:28 +01:00
append_menu_item ( export_menu , wxID_ANY , _ ( L ( "Export Config &Bundle" )) + dots , _ ( L ( "Export all presets to file" )),
2018-11-15 15:27:39 +01:00
[ this ]( wxCommandEvent & ) { export_configbundle (); }, "lorry_go.png" );
2019-01-21 12:34:28 +01:00
append_submenu ( fileMenu , export_menu , wxID_ANY , _ ( L ( "&Export" )), "" );
2018-11-15 15:27:39 +01:00
fileMenu -> AppendSeparator ();
2018-12-06 14:47:53 +01:00
#if 0
2018-11-15 12:21:09 +01:00
m_menu_item_repeat = nullptr;
2019-01-21 12:34:28 +01:00
append_menu_item(fileMenu, wxID_ANY, _(L("Quick Slice")) +dots+ "\tCtrl+U", _(L("Slice a file into a G-code")),
2018-11-15 12:21:09 +01:00
[this](wxCommandEvent&) {
wxTheApp->CallAfter([this]() {
2018-09-20 08:40:22 +02:00
quick_slice();
2018-11-15 12:21:09 +01:00
m_menu_item_repeat->Enable(is_last_input_file());
}); }, "cog_go.png");
2019-01-21 12:34:28 +01:00
append_menu_item(fileMenu, wxID_ANY, _(L("Quick Slice and Save As")) +dots +"\tCtrl+Alt+U", _(L("Slice a file into a G-code, save as")),
2018-11-15 12:21:09 +01:00
[this](wxCommandEvent&) {
wxTheApp->CallAfter([this]() {
2018-09-21 01:33:41 +02:00
quick_slice(qsSaveAs);
2018-11-15 12:21:09 +01:00
m_menu_item_repeat->Enable(is_last_input_file());
}); }, "cog_go.png");
2019-01-21 12:34:28 +01:00
m_menu_item_repeat = append_menu_item(fileMenu, wxID_ANY, _(L("Repeat Last Quick Slice")) +"\tCtrl+Shift+U", _(L("Repeat last quick slice")),
2018-10-31 12:56:08 +01:00
[this](wxCommandEvent&) {
wxTheApp->CallAfter([this]() {
2018-09-21 01:33:41 +02:00
quick_slice(qsReslice);
2018-09-20 08:40:22 +02:00
}); }, "cog_go.png");
2018-11-15 12:21:09 +01:00
m_menu_item_repeat->Enable(false);
2018-09-20 08:40:22 +02:00
fileMenu->AppendSeparator();
2018-12-06 14:47:53 +01:00
#endif
2019-01-21 12:34:28 +01:00
m_menu_item_reslice_now = append_menu_item ( fileMenu , wxID_ANY , _ ( L ( "(Re)Slice &Now" )) + " \t Ctrl+R" , _ ( L ( "Start new slicing process" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { reslice_now (); }, "shape_handles.png" );
2018-09-20 08:40:22 +02:00
fileMenu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
append_menu_item ( fileMenu , wxID_ANY , _ ( L ( "&Repair STL file" )) + dots , _ ( L ( "Automatically repair an STL file" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { repair_stl (); }, "wrench.png" );
2018-09-20 08:40:22 +02:00
fileMenu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
append_menu_item ( fileMenu , wxID_EXIT , _ ( L ( "&Quit" )), _ ( L ( "Quit Slic3r" )),
2018-11-21 10:21:12 +01:00
[ this ]( wxCommandEvent & ) { Close ( false ); });
2018-11-15 15:27:39 +01:00
2018-11-16 09:26:41 +01:00
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( m_plater != nullptr ); }, item_open -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable (( m_plater != nullptr ) && can_save ()); }, item_save -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable (( m_plater != nullptr ) && can_save ()); }, item_save_as -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( m_plater != nullptr ); }, item_import_model -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable (( m_plater != nullptr ) && can_export_gcode ()); }, item_export_gcode -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable (( m_plater != nullptr ) && can_export_model ()); }, item_export_stl -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable (( m_plater != nullptr ) && can_export_model ()); }, item_export_amf -> GetId ());
2019-01-21 12:34:28 +01:00
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable (( m_plater != nullptr ) && can_slice ()); }, m_menu_item_reslice_now -> GetId ());
2018-09-20 08:40:22 +02:00
}
2019-02-04 12:04:42 +01:00
#ifdef _MSC_VER
// \xA0 is a non-breaking space. It is entered here to spoil the automatic accelerators,
// as the simple numeric accelerators spoil all numeric data entry.
wxString sep = " \t\xA0 " ;
wxString sep_space = " \xA0 " ;
#else
wxString sep = " - " ;
2019-02-04 12:08:48 +01:00
wxString sep_space = "" ;
2019-02-04 12:04:42 +01:00
#endif
2018-11-21 15:28:35 +01:00
// Edit menu
wxMenu * editMenu = nullptr ;
if ( m_plater != nullptr )
{
editMenu = new wxMenu ();
2019-02-04 15:46:12 +01:00
#ifdef __APPLE__
// Backspace sign
wxString hotkey_delete = " \u232b " ;
#else
wxString hotkey_delete = "Del" ;
#endif
wxMenuItem * item_select_all = append_menu_item ( editMenu , wxID_ANY , _ ( L ( "&Select all" )) + sep + GUI :: shortkey_ctrl_prefix () + sep_space + "A" , _ ( L ( "Selects all objects" )),
2018-11-21 15:28:35 +01:00
[ this ]( wxCommandEvent & ) { m_plater -> select_all (); }, "" );
2018-11-22 11:31:53 +01:00
editMenu -> AppendSeparator ();
2019-02-04 15:46:12 +01:00
wxMenuItem * item_delete_sel = append_menu_item ( editMenu , wxID_ANY , _ ( L ( "&Delete selected" )) + sep + hotkey_delete , _ ( L ( "Deletes the current selection" )),
2018-11-21 15:47:41 +01:00
[ this ]( wxCommandEvent & ) { m_plater -> remove_selected (); }, "" );
2019-02-04 15:46:12 +01:00
wxMenuItem * item_delete_all = append_menu_item ( editMenu , wxID_ANY , _ ( L ( "Delete &all" )) + sep + GUI :: shortkey_ctrl_prefix () + sep_space + hotkey_delete , _ ( L ( "Deletes all objects" )),
2018-11-22 11:31:53 +01:00
[ this ]( wxCommandEvent & ) { m_plater -> reset (); }, "" );
2018-11-21 15:28:35 +01:00
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_select ()); }, item_select_all -> GetId ());
2018-11-21 15:47:41 +01:00
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_delete ()); }, item_delete_sel -> GetId ());
2018-11-22 11:31:53 +01:00
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_delete_all ()); }, item_delete_all -> GetId ());
2018-11-21 15:28:35 +01:00
}
2018-09-20 08:40:22 +02:00
// Window menu
auto windowMenu = new wxMenu ();
{
size_t tab_offset = 0 ;
if ( m_plater ) {
2019-01-21 12:34:28 +01:00
append_menu_item ( windowMenu , wxID_HIGHEST + 1 , _ ( L ( "&Plater Tab" )) + " \t Ctrl+1" , _ ( L ( "Show the plater" )),
2018-12-04 13:55:25 +01:00
[ this ]( wxCommandEvent & ) { select_tab ( 0 ); }, "application_view_tile.png" );
2018-09-20 08:40:22 +02:00
tab_offset += 1 ;
}
if ( tab_offset > 0 ) {
windowMenu -> AppendSeparator ();
}
2019-01-21 12:34:28 +01:00
append_menu_item ( windowMenu , wxID_HIGHEST + 2 , _ ( L ( "P&rint Settings Tab" )) + " \t Ctrl+2" , _ ( L ( "Show the print settings" )),
2018-12-04 13:55:25 +01:00
[ this , tab_offset ]( wxCommandEvent & ) { select_tab ( tab_offset + 0 ); }, "cog.png" );
2019-01-21 12:34:28 +01:00
append_menu_item ( windowMenu , wxID_HIGHEST + 3 , _ ( L ( "&Filament Settings Tab" )) + " \t Ctrl+3" , _ ( L ( "Show the filament settings" )),
2018-12-04 13:55:25 +01:00
[ this , tab_offset ]( wxCommandEvent & ) { select_tab ( tab_offset + 1 ); }, "spool.png" );
2019-01-21 12:34:28 +01:00
append_menu_item ( windowMenu , wxID_HIGHEST + 4 , _ ( L ( "Print&er Settings Tab" )) + " \t Ctrl+4" , _ ( L ( "Show the printer settings" )),
2018-12-04 13:55:25 +01:00
[ this , tab_offset ]( wxCommandEvent & ) { select_tab ( tab_offset + 2 ); }, "printer_empty.png" );
if ( m_plater ) {
windowMenu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
wxMenuItem * item_3d = append_menu_item ( windowMenu , wxID_HIGHEST + 5 , _ ( L ( "3&D" )) + " \t Ctrl+5" , _ ( L ( "Show the 3D editing view" )),
2018-12-17 14:40:54 +01:00
[ this ]( wxCommandEvent & ) { m_plater -> select_view_3D ( "3D" ); }, "" );
2019-01-21 12:34:28 +01:00
wxMenuItem * item_preview = append_menu_item ( windowMenu , wxID_HIGHEST + 6 , _ ( L ( "Pre&view" )) + " \t Ctrl+6" , _ ( L ( "Show the 3D slices preview" )),
2018-12-17 14:40:54 +01:00
[ this ]( wxCommandEvent & ) { m_plater -> select_view_3D ( "Preview" ); }, "" );
2018-12-04 13:55:25 +01:00
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_3d -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_preview -> GetId ());
}
2018-12-17 14:40:54 +01:00
#if _WIN32
// This is needed on Windows to fake the CTRL+# of the window menu when using the numpad
wxAcceleratorEntry entries [ 6 ];
entries [ 0 ]. Set ( wxACCEL_CTRL , WXK_NUMPAD1 , wxID_HIGHEST + 1 );
entries [ 1 ]. Set ( wxACCEL_CTRL , WXK_NUMPAD2 , wxID_HIGHEST + 2 );
entries [ 2 ]. Set ( wxACCEL_CTRL , WXK_NUMPAD3 , wxID_HIGHEST + 3 );
entries [ 3 ]. Set ( wxACCEL_CTRL , WXK_NUMPAD4 , wxID_HIGHEST + 4 );
entries [ 4 ]. Set ( wxACCEL_CTRL , WXK_NUMPAD5 , wxID_HIGHEST + 5 );
entries [ 5 ]. Set ( wxACCEL_CTRL , WXK_NUMPAD6 , wxID_HIGHEST + 6 );
wxAcceleratorTable accel ( 6 , entries );
SetAcceleratorTable ( accel );
#endif // _WIN32
2018-12-14 15:27:34 +01:00
windowMenu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
append_menu_item ( windowMenu , wxID_ANY , _ ( L ( "Print &Host Upload Queue" )) + " \t Ctrl+J" , _ ( L ( "Display the Print Host Upload Queue window" )),
2018-12-20 16:42:46 +01:00
[ this ]( wxCommandEvent & ) { m_printhost_queue_dlg -> Show (); }, "arrow_up.png" );
2018-09-20 08:40:22 +02:00
}
// View menu
2018-11-15 15:27:39 +01:00
wxMenu * viewMenu = nullptr ;
if ( m_plater ) {
viewMenu = new wxMenu ();
// The camera control accelerators are captured by GLCanvas3D::on_char().
2019-02-03 19:10:20 +01:00
wxMenuItem * item_iso = append_menu_item ( viewMenu , wxID_ANY , _ ( L ( "Iso" )) + sep + "&0" , _ ( L ( "Iso View" )), [ this ]( wxCommandEvent & ) { select_view ( "iso" ); });
2018-11-15 15:27:39 +01:00
viewMenu -> AppendSeparator ();
2019-02-03 19:10:20 +01:00
wxMenuItem * item_top = append_menu_item ( viewMenu , wxID_ANY , _ ( L ( "Top" )) + sep + "&1" , _ ( L ( "Top View" )), [ this ]( wxCommandEvent & ) { select_view ( "top" ); });
wxMenuItem * item_bottom = append_menu_item ( viewMenu , wxID_ANY , _ ( L ( "Bottom" )) + sep + "&2" , _ ( L ( "Bottom View" )), [ this ]( wxCommandEvent & ) { select_view ( "bottom" ); });
wxMenuItem * item_front = append_menu_item ( viewMenu , wxID_ANY , _ ( L ( "Front" )) + sep + "&3" , _ ( L ( "Front View" )), [ this ]( wxCommandEvent & ) { select_view ( "front" ); });
wxMenuItem * item_rear = append_menu_item ( viewMenu , wxID_ANY , _ ( L ( "Rear" )) + sep + "&4" , _ ( L ( "Rear View" )), [ this ]( wxCommandEvent & ) { select_view ( "rear" ); });
wxMenuItem * item_left = append_menu_item ( viewMenu , wxID_ANY , _ ( L ( "Left" )) + sep + "&5" , _ ( L ( "Left View" )), [ this ]( wxCommandEvent & ) { select_view ( "left" ); });
wxMenuItem * item_right = append_menu_item ( viewMenu , wxID_ANY , _ ( L ( "Right" )) + sep + "&6" , _ ( L ( "Right View" )), [ this ]( wxCommandEvent & ) { select_view ( "right" ); });
2018-11-16 12:31:06 +01:00
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_iso -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_top -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_bottom -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_front -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_rear -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_left -> GetId ());
Bind ( wxEVT_UPDATE_UI , [ this ]( wxUpdateUIEvent & evt ) { evt . Enable ( can_change_view ()); }, item_right -> GetId ());
2018-11-15 15:27:39 +01:00
}
2018-09-20 08:40:22 +02:00
// Help menu
auto helpMenu = new wxMenu ();
{
2019-01-21 12:34:28 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "Prusa 3D &Drivers" )), _ ( L ( "Open the Prusa3D drivers download page in your browser" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { wxLaunchDefaultBrowser ( "http://www.prusa3d.com/drivers/" ); });
2019-01-21 12:34:28 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "Prusa Edition &Releases" )), _ ( L ( "Open the Prusa Edition releases page in your browser" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { wxLaunchDefaultBrowser ( "http://github.com/prusa3d/slic3r/releases" ); });
2018-09-20 08:40:22 +02:00
//# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", "Check for new Slic3r versions", sub{
//# wxTheApp->check_version(1);
//# });
//# $versioncheck->Enable(wxTheApp->have_version_check);
2019-01-21 12:34:28 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "Slic3r &Website" )), _ ( L ( "Open the Slic3r website in your browser" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { wxLaunchDefaultBrowser ( "http://slic3r.org/" ); });
2019-01-21 12:34:28 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "Slic3r &Manual" )), _ ( L ( "Open the Slic3r manual in your browser" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { wxLaunchDefaultBrowser ( "http://manual.slic3r.org/" ); });
2018-09-20 08:40:22 +02:00
helpMenu -> AppendSeparator ();
2019-01-21 12:34:28 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "System &Info" )), _ ( L ( "Show system information" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { wxGetApp (). system_info (); });
2019-01-21 12:34:28 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "Show &Configuration Folder" )), _ ( L ( "Show user configuration folder (datadir)" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { Slic3r :: GUI :: desktop_open_datadir_folder (); });
2019-01-21 12:34:28 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "Report an I&ssue" )), _ ( L ( "Report an issue on the Slic3r Prusa Edition" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { wxLaunchDefaultBrowser ( "http://github.com/prusa3d/slic3r/issues/new" ); });
2019-01-21 12:34:28 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "&About Slic3r" )), _ ( L ( "Show about dialog" )),
2018-10-31 12:56:08 +01:00
[ this ]( wxCommandEvent & ) { Slic3r :: GUI :: about (); });
2018-12-19 13:06:24 +01:00
helpMenu -> AppendSeparator ();
2019-02-03 19:10:20 +01:00
append_menu_item ( helpMenu , wxID_ANY , _ ( L ( "Keyboard Shortcuts" )) + sep + "&?" , _ ( L ( "Show the list of the keyboard shortcuts" )),
2018-12-19 13:06:24 +01:00
[ this ]( wxCommandEvent & ) { wxGetApp (). keyboard_shortcuts (); });
2018-09-20 08:40:22 +02:00
}
// menubar
// assign menubar to frame after appending items, otherwise special items
// will not be handled correctly
2019-01-14 16:48:23 +01:00
auto menubar = new wxMenuBar ();
2019-01-21 12:34:28 +01:00
menubar -> Append ( fileMenu , _ ( L ( "&File" )));
if ( editMenu ) menubar -> Append ( editMenu , _ ( L ( "&Edit" )));
menubar -> Append ( windowMenu , _ ( L ( "&Window" )));
if ( viewMenu ) menubar -> Append ( viewMenu , _ ( L ( "&View" )));
2019-01-14 16:48:23 +01:00
// Add additional menus from C++
wxGetApp (). add_config_menu ( menubar );
2019-01-21 12:34:28 +01:00
menubar -> Append ( helpMenu , _ ( L ( "&Help" )));
2019-01-14 16:48:23 +01:00
SetMenuBar ( menubar );
#ifdef __APPLE__
2019-01-11 18:09:21 +01:00
// This fixes a bug on Mac OS where the quit command doesn't emit window close events
// wx bug: https://trac.wxwidgets.org/ticket/18328
2019-01-14 16:48:23 +01:00
wxMenu * apple_menu = menubar -> OSXGetAppleMenu ();
if ( apple_menu != nullptr ) {
apple_menu -> Bind ( wxEVT_MENU , [ this ]( wxCommandEvent & ) {
Close ();
}, wxID_EXIT );
2018-09-20 08:40:22 +02:00
}
2019-01-14 16:48:23 +01:00
#endif
2018-09-20 08:40:22 +02:00
}
// To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".
2018-10-31 12:56:08 +01:00
void MainFrame :: quick_slice ( const int qs )
{
2018-09-20 08:40:22 +02:00
// my $progress_dialog;
wxString input_file ;
// eval
// {
// validate configuration
2018-09-21 01:33:41 +02:00
auto config = wxGetApp (). preset_bundle -> full_config ();
2018-09-20 08:40:22 +02:00
config . validate ();
// select input file
2018-09-21 01:33:41 +02:00
if ( ! ( qs & qsReslice )) {
2018-09-20 08:40:22 +02:00
auto dlg = new wxFileDialog ( this , _ ( L ( "Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):" )),
2018-09-21 01:33:41 +02:00
wxGetApp (). app_config -> get_last_dir (), "" ,
2018-12-06 17:32:49 +01:00
file_wildcards ( FT_MODEL ), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
2018-09-20 08:40:22 +02:00
if ( dlg -> ShowModal () != wxID_OK ) {
dlg -> Destroy ();
return ;
}
input_file = dlg -> GetPath ();
dlg -> Destroy ();
2018-09-21 01:33:41 +02:00
if ( ! ( qs & qsExportSVG ))
2018-09-20 08:40:22 +02:00
m_qs_last_input_file = input_file ;
}
else {
if ( m_qs_last_input_file . IsEmpty ()) {
auto dlg = new wxMessageDialog ( this , _ ( L ( "No previously sliced file." )),
_ ( L ( "Error" )), wxICON_ERROR | wxOK );
dlg -> ShowModal ();
return ;
}
if ( std :: ifstream ( m_qs_last_input_file . char_str ())) {
auto dlg = new wxMessageDialog ( this , _ ( L ( "Previously sliced file (" )) + m_qs_last_input_file + _ ( L ( ") not found." )),
_ ( L ( "File Not Found" )), wxICON_ERROR | wxOK );
dlg -> ShowModal ();
return ;
}
input_file = m_qs_last_input_file ;
}
auto input_file_basename = get_base_name ( input_file );
2018-09-21 01:33:41 +02:00
wxGetApp (). app_config -> update_skein_dir ( get_dir_name ( input_file ));
2018-09-20 08:40:22 +02:00
auto bed_shape = Slic3r :: Polygon :: new_scale ( config . option < ConfigOptionPoints > ( "bed_shape" ) -> values );
// auto print_center = Slic3r::Pointf->new_unscale(bed_shape.bounding_box().center());
//
// auto sprint = new Slic3r::Print::Simple(
// print_center = > print_center,
2018-10-31 12:56:08 +01:00
// status_cb = > [](int percent, const wxString& msg) {
2018-09-21 01:33:41 +02:00
// m_progress_dialog->Update(percent, msg+"…");
2018-09-20 08:40:22 +02:00
// });
// keep model around
2019-01-03 14:34:53 +01:00
auto model = Slic3r :: Model :: read_from_file ( input_file . ToUTF8 (). data ());
2018-09-20 08:40:22 +02:00
// sprint->apply_config(config);
// sprint->set_model(model);
// Copy the names of active presets into the placeholder parser.
2018-09-21 01:33:41 +02:00
// wxGetApp().preset_bundle->export_selections(sprint->placeholder_parser);
2018-09-20 08:40:22 +02:00
// select output file
wxString output_file ;
2018-09-21 01:33:41 +02:00
if ( qs & qsReslice ) {
2018-09-20 08:40:22 +02:00
if ( ! m_qs_last_output_file . IsEmpty ())
output_file = m_qs_last_output_file ;
}
2018-09-21 01:33:41 +02:00
else if ( qs & qsSaveAs ) {
2018-09-20 08:40:22 +02:00
// The following line may die if the output_filename_format template substitution fails.
// output_file = sprint->output_filepath;
// if (export_svg)
// output_file = ~s / \.[gG][cC][oO][dD][eE]$ / .svg /;
2018-09-21 01:33:41 +02:00
auto dlg = new wxFileDialog ( this , _ ( L ( "Save " )) + ( qs & qsExportSVG ? _ ( L ( "SVG" )) : _ ( L ( "G-code" ))) + _ ( L ( " file as:" )),
wxGetApp (). app_config -> get_last_output_dir ( get_dir_name ( output_file )), get_base_name ( input_file ),
2018-12-06 17:32:49 +01:00
qs & qsExportSVG ? file_wildcards ( FT_SVG ) : file_wildcards ( FT_GCODE ),
2018-09-20 08:40:22 +02:00
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
if ( dlg -> ShowModal () != wxID_OK ) {
dlg -> Destroy ();
return ;
}
output_file = dlg -> GetPath ();
dlg -> Destroy ();
2018-09-21 01:33:41 +02:00
if ( ! ( qs & qsExportSVG ))
2018-09-20 08:40:22 +02:00
m_qs_last_output_file = output_file ;
2018-09-21 01:33:41 +02:00
wxGetApp (). app_config -> update_last_output_dir ( get_dir_name ( output_file ));
2018-09-20 08:40:22 +02:00
}
2018-09-21 01:33:41 +02:00
else if ( qs & qsExportPNG ) {
2018-09-20 08:40:22 +02:00
// output_file = sprint->output_filepath;
// output_file = ~s / \.[gG][cC][oO][dD][eE]$ / .zip / ;
auto dlg = new wxFileDialog ( this , _ ( L ( "Save zip file as:" )),
2018-09-21 01:33:41 +02:00
wxGetApp (). app_config -> get_last_output_dir ( get_dir_name ( output_file )),
2018-09-20 08:40:22 +02:00
get_base_name ( output_file ), "*.zip" , wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
if ( dlg -> ShowModal () != wxID_OK ) {
dlg -> Destroy ();
return ;
}
output_file = dlg -> GetPath ();
dlg -> Destroy ();
}
// show processbar dialog
2019-01-21 12:34:28 +01:00
m_progress_dialog = new wxProgressDialog ( _ ( L ( "Slicing" )) + dots , _ ( L ( "Processing " )) + input_file_basename + "…" ,
2018-09-20 08:40:22 +02:00
100 , this , 4 );
m_progress_dialog -> Pulse ();
{
// my @warnings = ();
// local $SIG{ __WARN__ } = sub{ push @warnings, $_[0] };
// sprint->output_file(output_file);
// if (export_svg) {
// sprint->export_svg();
// }
// else if(export_png) {
// sprint->export_png();
// }
// else {
// sprint->export_gcode();
// }
// sprint->status_cb(undef);
// Slic3r::GUI::warning_catcher($self)->($_) for @warnings;
}
m_progress_dialog -> Destroy ();
m_progress_dialog = nullptr ;
auto message = input_file_basename + _ ( L ( " was successfully sliced." ));
// wxTheApp->notify(message);
wxMessageDialog ( this , message , _ ( L ( "Slicing Done!" )), wxOK | wxICON_INFORMATION ). ShowModal ();
// };
2018-10-31 12:56:08 +01:00
// Slic3r::GUI::catch_error(this, []() { if (m_progress_dialog) m_progress_dialog->Destroy(); });
2018-09-20 08:40:22 +02:00
}
2018-10-17 11:12:38 +02:00
void MainFrame :: reslice_now ()
{
if ( m_plater )
m_plater -> reslice ();
2018-09-20 08:40:22 +02:00
}
void MainFrame :: repair_stl ()
{
wxString input_file ;
{
auto dlg = new wxFileDialog ( this , _ ( L ( "Select the STL file to repair:" )),
2018-09-21 01:33:41 +02:00
wxGetApp (). app_config -> get_last_dir (), "" ,
2018-12-06 17:32:49 +01:00
file_wildcards ( FT_STL ), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
2018-09-20 08:40:22 +02:00
if ( dlg -> ShowModal () != wxID_OK ) {
dlg -> Destroy ();
return ;
}
input_file = dlg -> GetPath ();
dlg -> Destroy ();
}
auto output_file = input_file ;
{
// output_file = ~s / \.[sS][tT][lL]$ / _fixed.obj / ;
auto dlg = new wxFileDialog ( this , L ( "Save OBJ file (less prone to coordinate errors than STL) as:" ),
get_dir_name ( output_file ), get_base_name ( output_file ),
2018-12-06 17:32:49 +01:00
file_wildcards ( FT_OBJ ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
2018-09-20 08:40:22 +02:00
if ( dlg -> ShowModal () != wxID_OK ) {
dlg -> Destroy ();
return /*undef*/ ;
}
output_file = dlg -> GetPath ();
dlg -> Destroy ();
}
auto tmesh = new Slic3r :: TriangleMesh ();
tmesh -> ReadSTLFile ( input_file . char_str ());
tmesh -> repair ();
tmesh -> WriteOBJFile ( output_file . char_str ());
Slic3r :: GUI :: show_info ( this , L ( "Your file was repaired." ), L ( "Repair" ));
}
void MainFrame :: export_config ()
{
// Generate a cummulative configuration for the selected print, filaments and printer.
2018-09-21 01:33:41 +02:00
auto config = wxGetApp (). preset_bundle -> full_config ();
2018-09-20 08:40:22 +02:00
// Validate the cummulative configuration.
auto valid = config . validate ();
if ( ! valid . empty ()) {
// Slic3r::GUI::catch_error(this);
return ;
}
// Ask user for the file name for the config file.
auto dlg = new wxFileDialog ( this , _ ( L ( "Save configuration as:" )),
2018-09-21 01:33:41 +02:00
! m_last_config . IsEmpty () ? get_dir_name ( m_last_config ) : wxGetApp (). app_config -> get_last_dir (),
2018-09-20 08:40:22 +02:00
! m_last_config . IsEmpty () ? get_base_name ( m_last_config ) : "config.ini" ,
2018-12-06 17:32:49 +01:00
file_wildcards ( FT_INI ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
2018-09-21 15:42:31 +02:00
wxString file ;
if ( dlg -> ShowModal () == wxID_OK )
file = dlg -> GetPath ();
2018-09-20 08:40:22 +02:00
dlg -> Destroy ();
if ( ! file . IsEmpty ()) {
2018-09-21 01:33:41 +02:00
wxGetApp (). app_config -> update_config_dir ( get_dir_name ( file ));
2018-09-20 08:40:22 +02:00
m_last_config = file ;
2019-01-03 14:34:53 +01:00
config . save ( file . ToUTF8 (). data ());
2018-09-20 08:40:22 +02:00
}
}
// Load a config file containing a Print, Filament & Printer preset.
2019-01-09 10:43:17 +01:00
void MainFrame :: load_config_file ()
2018-09-20 08:40:22 +02:00
{
2019-01-09 10:43:17 +01:00
if ( ! wxGetApp (). check_unsaved_changes ())
return ;
auto dlg = new wxFileDialog ( this , _ ( L ( "Select configuration to load:" )),
! m_last_config . IsEmpty () ? get_dir_name ( m_last_config ) : wxGetApp (). app_config -> get_last_dir (),
"config.ini" , "INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g" , wxFD_OPEN | wxFD_FILE_MUST_EXIST );
wxString file ;
if ( dlg -> ShowModal () == wxID_OK )
file = dlg -> GetPath ();
dlg -> Destroy ();
if ( ! file . IsEmpty () && this -> load_config_file ( file . ToUTF8 (). data ())) {
wxGetApp (). app_config -> update_config_dir ( get_dir_name ( file ));
m_last_config = file ;
2018-09-20 08:40:22 +02:00
}
2019-01-09 10:43:17 +01:00
}
// Load a config file containing a Print, Filament & Printer preset from command line.
bool MainFrame :: load_config_file ( const std :: string & path )
{
2018-10-17 11:12:38 +02:00
try {
2019-01-09 10:43:17 +01:00
wxGetApp (). preset_bundle -> load_config_file ( path );
2018-12-03 13:14:28 +01:00
} catch ( const std :: exception & ex ) {
show_error ( this , ex . what ());
2019-01-09 10:43:17 +01:00
return false ;
2018-10-17 11:12:38 +02:00
}
2019-01-09 10:43:17 +01:00
wxGetApp (). load_current_presets ();
return true ;
2018-09-20 08:40:22 +02:00
}
void MainFrame :: export_configbundle ()
{
2018-09-21 01:33:41 +02:00
if ( ! wxGetApp (). check_unsaved_changes ())
2018-09-20 08:40:22 +02:00
return ;
// validate current configuration in case it's dirty
2018-12-03 13:14:28 +01:00
auto err = wxGetApp (). preset_bundle -> full_config (). validate ();
if ( ! err . empty ()) {
show_error ( this , err );
2018-09-20 08:40:22 +02:00
return ;
}
// Ask user for a file name.
auto dlg = new wxFileDialog ( this , _ ( L ( "Save presets bundle as:" )),
2018-09-21 01:33:41 +02:00
! m_last_config . IsEmpty () ? get_dir_name ( m_last_config ) : wxGetApp (). app_config -> get_last_dir (),
2018-09-20 08:40:22 +02:00
"Slic3r_config_bundle.ini" ,
2018-12-06 17:32:49 +01:00
file_wildcards ( FT_INI ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
2018-09-21 15:42:31 +02:00
wxString file ;
if ( dlg -> ShowModal () == wxID_OK )
file = dlg -> GetPath ();
2018-09-20 08:40:22 +02:00
dlg -> Destroy ();
if ( ! file . IsEmpty ()) {
// Export the config bundle.
2018-10-17 11:12:38 +02:00
wxGetApp (). app_config -> update_config_dir ( get_dir_name ( file ));
try {
2019-01-03 14:34:53 +01:00
wxGetApp (). preset_bundle -> export_configbundle ( file . ToUTF8 (). data ());
2018-12-03 13:14:28 +01:00
} catch ( const std :: exception & ex ) {
show_error ( this , ex . what ());
2018-10-17 11:12:38 +02:00
}
2018-09-20 08:40:22 +02:00
}
}
// Loading a config bundle with an external file name used to be used
// to auto - install a config bundle on a fresh user account,
// but that behavior was not documented and likely buggy.
2018-10-17 11:12:38 +02:00
void MainFrame :: load_configbundle ( wxString file /* = wxEmptyString, const bool reset_user_profile*/ )
{
2018-09-21 01:33:41 +02:00
if ( ! wxGetApp (). check_unsaved_changes ())
2018-09-20 08:40:22 +02:00
return ;
if ( file . IsEmpty ()) {
auto dlg = new wxFileDialog ( this , _ ( L ( "Select configuration to load:" )),
2018-09-21 01:33:41 +02:00
! m_last_config . IsEmpty () ? get_dir_name ( m_last_config ) : wxGetApp (). app_config -> get_last_dir (),
2018-12-06 17:32:49 +01:00
"config.ini" , file_wildcards ( FT_INI ), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
2019-01-09 10:43:17 +01:00
if ( dlg -> ShowModal () != wxID_OK ) {
dlg -> Destroy ();
return ;
}
2018-09-20 08:40:22 +02:00
file = dlg -> GetPath ();
2019-01-09 10:43:17 +01:00
dlg -> Destroy ();
}
2018-09-20 08:40:22 +02:00
2018-09-21 01:33:41 +02:00
wxGetApp (). app_config -> update_config_dir ( get_dir_name ( file ));
2018-09-20 08:40:22 +02:00
auto presets_imported = 0 ;
2018-10-17 11:12:38 +02:00
try {
2019-01-03 14:34:53 +01:00
presets_imported = wxGetApp (). preset_bundle -> load_configbundle ( file . ToUTF8 (). data ());
2018-12-03 13:14:28 +01:00
} catch ( const std :: exception & ex ) {
show_error ( this , ex . what ());
return ;
2018-10-17 11:12:38 +02:00
}
2018-09-20 08:40:22 +02:00
// Load the currently selected preset into the GUI, update the preset selection box.
2018-11-07 14:57:50 +01:00
wxGetApp (). load_current_presets ();
2018-09-20 08:40:22 +02:00
const auto message = wxString :: Format ( _ ( L ( "%d presets successfully imported." )), presets_imported );
Slic3r :: GUI :: show_info ( this , message , "Info" );
}
// Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset.
// Also update the platter with the new presets.
2018-10-17 11:12:38 +02:00
void MainFrame :: load_config ( const DynamicPrintConfig & config )
{
2019-01-09 10:43:17 +01:00
PrinterTechnology printer_technology = wxGetApp (). preset_bundle -> printers . get_edited_preset (). printer_technology ();
const auto * opt_printer_technology = config . option < ConfigOptionEnum < PrinterTechnology >> ( "printer_technology" );
if ( opt_printer_technology != nullptr && opt_printer_technology -> value != printer_technology ) {
printer_technology = opt_printer_technology -> value ;
this -> plater () -> set_printer_technology ( printer_technology );
}
#if 0
for (auto tab : wxGetApp().tabs_list)
if (tab->supports_printer_technology(printer_technology)) {
if (tab->name() == "printer")
static_cast<TabPrinter*>(tab)->update_pages();
tab->load_config(config);
}
if (m_plater)
2018-10-17 11:12:38 +02:00
m_plater->on_config_change(config);
2019-01-09 10:43:17 +01:00
#else
// Load the currently selected preset into the GUI, update the preset selection box.
//FIXME this is not quite safe for multi-extruder printers,
// as the number of extruders is not adjusted for the vector values.
// (see PresetBundle::update_multi_material_filament_presets())
// Better to call PresetBundle::load_config() instead?
for ( auto tab : wxGetApp (). tabs_list )
if ( tab -> supports_printer_technology ( printer_technology )) {
// Only apply keys, which are present in the tab's config. Ignore the other keys.
for ( const std :: string & opt_key : tab -> get_config () -> diff ( config ))
// Ignore print_settings_id, printer_settings_id, filament_settings_id etc.
if ( ! boost :: algorithm :: ends_with ( opt_key , "_settings_id" ))
tab -> get_config () -> option ( opt_key ) -> set ( config . option ( opt_key ));
}
wxGetApp (). load_current_presets ();
#endif
2018-09-20 08:40:22 +02:00
}
2018-10-17 11:12:38 +02:00
void MainFrame :: select_tab ( size_t tab ) const
{
2018-09-20 08:40:22 +02:00
m_tabpanel -> SetSelection ( tab );
}
// Set a camera direction, zoom to all objects.
2018-10-17 11:12:38 +02:00
void MainFrame :: select_view ( const std :: string & direction )
{
2018-10-17 12:59:58 +02:00
if ( m_plater )
m_plater -> select_view ( direction );
2018-09-20 08:40:22 +02:00
}
2019-02-22 09:38:56 +01:00
// #ys_FIXME_to_delete
2018-10-03 16:27:02 +02:00
void MainFrame :: on_presets_changed ( SimpleEvent & event )
{
auto * tab = dynamic_cast < Tab *> ( event . GetEventObject ());
wxASSERT ( tab != nullptr );
if ( tab == nullptr ) {
return ;
}
// Update preset combo boxes(Print settings, Filament, Material, Printer) from their respective tabs.
auto presets = tab -> get_presets ();
2018-10-04 11:12:55 +02:00
if ( m_plater != nullptr && presets != nullptr ) {
2018-10-03 16:27:02 +02:00
// FIXME: The preset type really should be a property of Tab instead
2018-10-09 12:41:05 +02:00
Slic3r :: Preset :: Type preset_type = tab -> type ();
2018-10-31 12:56:08 +01:00
if ( preset_type == Slic3r :: Preset :: TYPE_INVALID ) {
2018-10-03 16:27:02 +02:00
wxASSERT ( false );
return ;
}
2018-10-17 11:12:38 +02:00
m_plater -> on_config_change ( * tab -> get_config ());
2018-11-16 11:14:56 +01:00
m_plater -> sidebar (). update_presets ( preset_type );
2018-10-03 16:27:02 +02:00
}
}
2019-02-22 09:38:56 +01:00
// #ys_FIXME_to_delete
2018-10-10 13:53:45 +02:00
void MainFrame :: on_value_changed ( wxCommandEvent & event )
2018-10-09 12:41:05 +02:00
{
2018-10-10 13:53:45 +02:00
auto * tab = dynamic_cast < Tab *> ( event . GetEventObject ());
wxASSERT ( tab != nullptr );
if ( tab == nullptr )
return ;
auto opt_key = event . GetString ();
if ( m_plater ) {
2018-10-17 11:12:38 +02:00
m_plater -> on_config_change ( * tab -> get_config ()); // propagate config change events to the plater
2018-10-31 12:56:08 +01:00
if ( opt_key == "extruders_count" ) {
2018-10-17 11:12:38 +02:00
auto value = event . GetInt ();
m_plater -> on_extruders_change ( value );
}
}
// Don't save while loading for the first time.
2019-02-22 09:38:56 +01:00
if ( m_loaded ) {
AppConfig & cfg = * wxGetApp (). app_config ;
if ( cfg . get ( "autosave" ) == "1" )
cfg . save ();
}
}
void MainFrame :: on_config_changed ( DynamicPrintConfig * config ) const
{
if ( m_plater ) {
m_plater -> on_config_change ( * config ); // propagate config change events to the plater
}
// Don't save while loading for the first time.
2018-10-17 11:12:38 +02:00
if ( m_loaded ) {
AppConfig & cfg = * wxGetApp (). app_config ;
if ( cfg . get ( "autosave" ) == "1" )
cfg . save ();
2018-10-10 13:53:45 +02:00
}
2018-10-09 12:41:05 +02:00
}
2018-09-20 08:40:22 +02:00
// Called after the Preferences dialog is closed and the program settings are saved.
// Update the UI based on the current preferences.
void MainFrame :: update_ui_from_settings ()
{
2018-12-04 12:30:47 +01:00
bool bp_on = wxGetApp (). app_config -> get ( "background_processing" ) == "1" ;
2019-01-21 12:34:28 +01:00
// m_menu_item_reslice_now->Enable(!bp_on);
2018-12-11 10:33:11 +01:00
m_plater -> sidebar (). show_reslice ( ! bp_on );
2018-12-10 10:38:32 +01:00
m_plater -> sidebar (). Layout ();
2018-12-04 11:14:39 +01:00
if ( m_plater )
m_plater -> update_ui_from_settings ();
2018-11-16 11:14:56 +01:00
for ( auto tab : wxGetApp (). tabs_list )
tab -> update_ui_from_settings ();
2018-09-20 08:40:22 +02:00
}
2019-01-09 10:43:17 +01:00
std :: string MainFrame :: get_base_name ( const wxString & full_name ) const
2018-09-20 08:40:22 +02:00
{
2019-01-09 10:43:17 +01:00
return boost :: filesystem :: path ( full_name . wx_str ()). filename (). string ();
2018-09-20 08:40:22 +02:00
}
2019-01-09 10:43:17 +01:00
std :: string MainFrame :: get_dir_name ( const wxString & full_name ) const
2018-09-20 08:40:22 +02:00
{
2019-01-09 10:43:17 +01:00
return boost :: filesystem :: path ( full_name . wx_str ()). parent_path (). string ();
2018-09-20 08:40:22 +02:00
}
} // GUI
2018-09-21 01:33:41 +02:00
} // Slic3r