2019-01-16 12:22:17 +01:00
// #include "libslic3r/GCodeSender.hpp"
2019-03-27 12:14:34 +01:00
#include "slic3r/Utils/Serial.hpp"
2018-01-25 13:46:04 +01:00
#include "Tab.hpp"
#include "PresetHints.hpp"
2020-06-16 16:58:41 +02:00
#include "libslic3r/PresetBundle.hpp"
2018-12-04 17:56:49 +01:00
#include "libslic3r/Utils.hpp"
2020-02-28 14:29:53 +01:00
#include "libslic3r/Model.hpp"
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
#include "libslic3r/GCode/GCodeProcessor.hpp"
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2018-03-16 14:06:23 +01:00
2018-03-15 18:06:26 +01:00
#include "slic3r/Utils/Http.hpp"
2018-07-08 14:32:48 +02:00
#include "slic3r/Utils/PrintHost.hpp"
2018-03-15 18:06:26 +01:00
#include "BonjourDialog.hpp"
2018-02-28 16:04:56 +01:00
#include "WipeTowerDialog.hpp"
2018-04-20 12:58:07 +02:00
#include "ButtonsDescription.hpp"
2020-04-30 12:03:49 +02:00
#include "Search.hpp"
2020-10-27 22:19:12 +01:00
#include "OG_CustomCtrl.hpp"
2018-01-25 13:46:04 +01:00
2017-12-05 15:54:01 +01:00
#include <wx/app.h>
#include <wx/button.h>
2017-12-13 14:45:10 +01:00
#include <wx/scrolwin.h>
2017-12-05 15:54:01 +01:00
#include <wx/sizer.h>
#include <wx/bmpcbox.h>
#include <wx/bmpbuttn.h>
#include <wx/treectrl.h>
#include <wx/imaglist.h>
2017-12-22 11:50:28 +01:00
#include <wx/settings.h>
2018-03-15 18:06:26 +01:00
#include <wx/filedlg.h>
2017-12-05 15:54:01 +01:00
2018-01-18 11:45:25 +01:00
#include <boost/algorithm/string/predicate.hpp>
2020-11-28 20:51:57 +01:00
#include <boost/algorithm/string/replace.hpp>
2018-04-06 13:37:00 +02:00
#include "wxExtensions.hpp"
2020-06-16 12:57:49 +02:00
#include "PresetComboBoxes.hpp"
2018-04-17 10:15:48 +02:00
#include <wx/wupdlock.h>
2018-01-03 10:12:42 +01:00
2018-09-21 01:33:41 +02:00
#include "GUI_App.hpp"
2018-11-29 12:33:04 +01:00
#include "GUI_ObjectList.hpp"
2020-05-26 17:42:57 +02:00
#include "Plater.hpp"
#include "MainFrame.hpp"
2020-04-23 12:41:38 +02:00
#include "format.hpp"
2020-07-28 11:31:16 +02:00
#include "PhysicalPrinterDialog.hpp"
2020-07-30 16:16:56 +02:00
#include "UnsavedChangesDialog.hpp"
2020-10-19 14:17:45 +02:00
#include "SavePresetDialog.hpp"
2018-01-03 10:12:42 +01:00
2020-10-01 20:15:40 +02:00
#ifdef WIN32
#include <commctrl.h>
#endif // WIN32
2017-12-05 15:54:01 +01:00
namespace Slic3r {
namespace GUI {
2018-10-03 16:27:02 +02:00
2020-04-16 09:59:12 +02:00
void Tab :: Highlighter :: set_timer_owner ( wxEvtHandler * owner , int timerid /* = wxID_ANY*/ )
2020-04-07 20:34:09 +02:00
{
2020-11-02 15:28:43 +01:00
m_timer . SetOwner ( owner , timerid );
2020-04-16 09:59:12 +02:00
}
2020-10-27 22:19:12 +01:00
void Tab :: Highlighter :: init ( std :: pair < OG_CustomCtrl * , bool *> params )
{
2020-11-02 15:28:43 +01:00
if ( m_timer . IsRunning ())
2020-10-27 22:19:12 +01:00
invalidate ();
if ( ! params . first || ! params . second )
return ;
2020-11-02 15:28:43 +01:00
m_timer . Start ( 300 , false );
2020-10-27 22:19:12 +01:00
2020-11-02 15:28:43 +01:00
m_custom_ctrl = params . first ;
m_show_blink_ptr = params . second ;
2020-10-27 22:19:12 +01:00
2020-11-02 15:28:43 +01:00
* m_show_blink_ptr = true ;
m_custom_ctrl -> Refresh ();
2020-10-27 22:19:12 +01:00
}
2020-04-07 20:34:09 +02:00
void Tab :: Highlighter :: invalidate ()
{
2020-11-02 15:28:43 +01:00
m_timer . Stop ();
2020-04-16 09:59:12 +02:00
2020-11-02 15:28:43 +01:00
if ( m_custom_ctrl && m_show_blink_ptr ) {
* m_show_blink_ptr = false ;
m_custom_ctrl -> Refresh ();
m_show_blink_ptr = nullptr ;
m_custom_ctrl = nullptr ;
2020-09-24 15:41:48 +02:00
}
2020-10-27 22:19:12 +01:00
2020-11-02 15:28:43 +01:00
m_blink_counter = 0 ;
2020-04-07 20:34:09 +02:00
}
2020-04-16 09:59:12 +02:00
void Tab :: Highlighter :: blink ()
2020-04-07 20:34:09 +02:00
{
2020-11-02 15:28:43 +01:00
if ( m_custom_ctrl && m_show_blink_ptr ) {
* m_show_blink_ptr = !* m_show_blink_ptr ;
m_custom_ctrl -> Refresh ();
2020-10-27 22:19:12 +01:00
}
else
2020-04-16 09:59:12 +02:00
return ;
2020-11-02 15:28:43 +01:00
if (( ++ m_blink_counter ) == 11 )
2020-04-07 20:34:09 +02:00
invalidate ();
}
2019-05-10 15:10:17 +02:00
Tab :: Tab ( wxNotebook * parent , const wxString & title , Preset :: Type type ) :
2019-08-06 16:51:32 +02:00
m_parent ( parent ), m_title ( title ), m_type ( type )
2018-12-04 17:56:49 +01:00
{
2019-08-06 16:51:32 +02:00
Create ( parent , wxID_ANY , wxDefaultPosition , wxDefaultSize , wxBK_LEFT | wxTAB_TRAVERSAL /*, name*/ );
this -> SetFont ( Slic3r :: GUI :: wxGetApp (). normal_font ());
2018-12-04 17:56:49 +01:00
2019-08-06 16:51:32 +02:00
m_compatible_printers . type = Preset :: TYPE_PRINTER ;
m_compatible_printers . key_list = "compatible_printers" ;
m_compatible_printers . key_condition = "compatible_printers_condition" ;
2020-12-07 17:29:35 +01:00
m_compatible_printers . dialog_title = _L ( "Compatible printers" );
m_compatible_printers . dialog_label = _L ( "Select the printers this profile is compatible with." );
2018-12-04 17:56:49 +01:00
2019-08-06 16:51:32 +02:00
m_compatible_prints . type = Preset :: TYPE_PRINT ;
m_compatible_prints . key_list = "compatible_prints" ;
m_compatible_prints . key_condition = "compatible_prints_condition" ;
2020-12-07 17:29:35 +01:00
m_compatible_prints . dialog_title = _L ( "Compatible print profiles" );
m_compatible_prints . dialog_label = _L ( "Select the print profiles this profile is compatible with." );
2018-12-04 17:56:49 +01:00
2019-08-06 16:51:32 +02:00
wxGetApp (). tabs_list . push_back ( this );
2019-02-04 12:07:15 +01:00
2020-09-03 15:40:14 +02:00
m_em_unit = em_unit ( m_parent ); //wxGetApp().em_unit();
2019-03-18 12:48:39 +01:00
2019-08-22 13:19:01 +02:00
m_config_manipulation = get_config_manipulation ();
2021-01-29 16:16:23 +01:00
Bind ( wxEVT_SIZE , ([]( wxSizeEvent & evt ) {
2020-09-22 11:17:43 +02:00
//for (auto page : m_pages)
// if (! page.get()->IsShown())
// page->layout_valid = false;
2019-08-06 16:51:32 +02:00
evt . Skip ();
}));
2020-04-07 12:09:58 +02:00
2020-04-16 09:59:12 +02:00
m_highlighter . set_timer_owner ( this , 0 );
2020-04-07 12:09:58 +02:00
this -> Bind ( wxEVT_TIMER , [ this ]( wxTimerEvent & )
{
2020-04-16 09:59:12 +02:00
m_highlighter . blink ();
2020-04-07 12:09:58 +02:00
});
2018-12-04 17:56:49 +01:00
}
2018-10-03 16:27:02 +02:00
2018-10-09 12:41:05 +02:00
void Tab :: set_type ()
{
if ( m_name == "print" ) { m_type = Slic3r :: Preset :: TYPE_PRINT ; }
2018-11-16 17:36:23 +01:00
else if ( m_name == "sla_print" ) { m_type = Slic3r :: Preset :: TYPE_SLA_PRINT ; }
2018-10-09 12:41:05 +02:00
else if ( m_name == "filament" ) { m_type = Slic3r :: Preset :: TYPE_FILAMENT ; }
else if ( m_name == "sla_material" ) { m_type = Slic3r :: Preset :: TYPE_SLA_MATERIAL ; }
else if ( m_name == "printer" ) { m_type = Slic3r :: Preset :: TYPE_PRINTER ; }
2018-12-04 17:56:49 +01:00
else { m_type = Slic3r :: Preset :: TYPE_INVALID ; assert ( false ); }
2018-10-09 12:41:05 +02:00
}
2017-12-05 15:54:01 +01:00
// sub new
2018-10-04 16:43:10 +02:00
void Tab :: create_preset_tab ()
2017-12-05 15:54:01 +01:00
{
2019-03-13 13:13:18 +01:00
#ifdef __WINDOWS__
2019-03-18 12:48:39 +01:00
SetDoubleBuffered ( true );
2019-03-13 13:13:18 +01:00
#endif //__WINDOWS__
2018-10-04 16:43:10 +02:00
m_preset_bundle = wxGetApp (). preset_bundle ;
2018-01-05 15:11:33 +01:00
2019-08-06 16:51:32 +02:00
// Vertical sizer to hold the choice menu and the rest of the page.
2018-06-28 18:30:22 +02:00
#ifdef __WXOSX__
2019-08-06 16:51:32 +02:00
auto * main_sizer = new wxBoxSizer ( wxVERTICAL );
main_sizer -> SetSizeHints ( this );
this -> SetSizer ( main_sizer );
2018-06-28 18:30:22 +02:00
2019-08-06 16:51:32 +02:00
// Create additional panel to Fit() it from OnActivate()
// It's needed for tooltip showing on OSX
m_tmp_panel = new wxPanel ( this , wxID_ANY , wxDefaultPosition , wxDefaultSize , wxBK_LEFT | wxTAB_TRAVERSAL );
auto panel = m_tmp_panel ;
auto sizer = new wxBoxSizer ( wxVERTICAL );
m_tmp_panel -> SetSizer ( sizer );
m_tmp_panel -> Layout ();
2018-06-28 18:30:22 +02:00
2019-08-06 16:51:32 +02:00
main_sizer -> Add ( m_tmp_panel , 1 , wxEXPAND | wxALL , 0 );
2018-06-28 18:30:22 +02:00
#else
2019-08-06 16:51:32 +02:00
Tab * panel = this ;
auto * sizer = new wxBoxSizer ( wxVERTICAL );
sizer -> SetSizeHints ( panel );
panel -> SetSizer ( sizer );
2018-06-28 18:30:22 +02:00
#endif //__WXOSX__
2017-12-05 15:54:01 +01:00
2019-08-06 16:51:32 +02:00
// preset chooser
2020-06-16 12:57:49 +02:00
m_presets_choice = new TabPresetComboBox ( panel , m_type );
2020-06-24 08:50:01 +02:00
m_presets_choice -> set_selection_changed_function ([ this ]( int selection ) {
2020-07-17 14:32:38 +02:00
if ( ! m_presets_choice -> selection_is_changed_according_to_physical_printers ())
{
2020-07-27 20:06:10 +02:00
if ( m_type == Preset :: TYPE_PRINTER && ! m_presets_choice -> is_selected_physical_printer ())
m_preset_bundle -> physical_printers . unselect_printer ();
2020-07-17 14:32:38 +02:00
// select preset
2020-10-02 09:02:16 +02:00
std :: string preset_name = m_presets_choice -> GetString ( selection ). ToUTF8 (). data ();
select_preset ( Preset :: remove_suffix_modified ( preset_name ));
2020-07-17 14:32:38 +02:00
}
2020-06-24 08:50:01 +02:00
});
2020-03-13 22:37:18 +01:00
2019-08-06 16:51:32 +02:00
auto color = wxSystemSettings :: GetColour ( wxSYS_COLOUR_WINDOW );
2017-12-05 15:54:01 +01:00
2019-08-06 16:51:32 +02:00
//buttons
2019-04-13 23:46:52 +02:00
m_scaled_buttons . reserve ( 6 );
m_scaled_buttons . reserve ( 2 );
2021-02-04 09:42:32 +01:00
add_scaled_button ( panel , & m_btn_compare_preset , "compare" );
2019-04-13 23:46:52 +02:00
add_scaled_button ( panel , & m_btn_save_preset , "save" );
add_scaled_button ( panel , & m_btn_delete_preset , "cross" );
2020-07-28 11:31:16 +02:00
if ( m_type == Preset :: Type :: TYPE_PRINTER )
add_scaled_button ( panel , & m_btn_edit_ph_printer , "cog" );
2017-12-05 15:54:01 +01:00
2019-08-06 16:51:32 +02:00
m_show_incompatible_presets = false ;
add_scaled_bitmap ( this , m_bmp_show_incompatible_presets , "flag_red" );
add_scaled_bitmap ( this , m_bmp_hide_incompatible_presets , "flag_green" );
2019-04-25 01:45:00 +02:00
2019-04-13 23:46:52 +02:00
add_scaled_button ( panel , & m_btn_hide_incompatible_presets , m_bmp_hide_incompatible_presets . name ());
2017-12-05 15:54:01 +01:00
2021-02-04 09:42:32 +01:00
m_btn_compare_preset -> SetToolTip ( _L ( "Compare this preset with some another" ));
2019-05-11 23:29:25 +02:00
// TRN "Save current Settings"
2020-03-02 12:46:40 +01:00
m_btn_save_preset -> SetToolTip ( from_u8 (( boost :: format ( _utf8 ( L ( "Save current %s" ))) % m_title ). str ()));
2019-08-06 16:51:32 +02:00
m_btn_delete_preset -> SetToolTip ( _ ( L ( "Delete this preset" )));
2020-10-20 16:38:13 +02:00
m_btn_delete_preset -> Hide ();
2017-12-05 15:54:01 +01:00
2019-04-13 23:46:52 +02:00
add_scaled_button ( panel , & m_question_btn , "question" );
2019-08-06 16:51:32 +02:00
m_question_btn -> SetToolTip ( _ ( L ( "Hover the cursor over buttons to find more information \n "
"or click this button." )));
2018-04-19 16:20:30 +02:00
2020-04-22 15:46:23 +02:00
add_scaled_button ( panel , & m_search_btn , "search" );
2020-11-05 22:17:49 +01:00
m_search_btn -> SetToolTip ( format_wxstr ( _L ( "Search in settings [%1%]" ), "Ctrl+F" ));
2020-04-23 12:41:38 +02:00
2019-08-06 16:51:32 +02:00
// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
2020-05-22 16:59:28 +02:00
add_scaled_bitmap ( this , m_bmp_value_lock , "lock_closed" );
2019-08-06 16:51:32 +02:00
add_scaled_bitmap ( this , m_bmp_value_unlock , "lock_open" );
m_bmp_non_system = & m_bmp_white_bullet ;
// Bitmaps to be shown on the "Undo user changes" button next to each input field.
add_scaled_bitmap ( this , m_bmp_value_revert , "undo" );
2020-05-22 16:59:28 +02:00
add_scaled_bitmap ( this , m_bmp_white_bullet , "dot" );
2018-04-19 16:20:30 +02:00
2019-08-06 16:51:32 +02:00
fill_icon_descriptions ();
set_tooltips_text ();
2018-04-20 12:58:07 +02:00
2019-04-13 23:46:52 +02:00
add_scaled_button ( panel , & m_undo_btn , m_bmp_white_bullet . name ());
add_scaled_button ( panel , & m_undo_to_sys_btn , m_bmp_white_bullet . name ());
2019-08-06 16:51:32 +02:00
m_undo_btn -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent ) { on_roll_back_value (); }));
m_undo_to_sys_btn -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent ) { on_roll_back_value ( true ); }));
2020-12-30 11:55:26 +01:00
m_question_btn -> Bind ( wxEVT_BUTTON , [ this ]( wxCommandEvent ) {
2019-08-15 12:52:56 +02:00
ButtonsDescription dlg ( this , m_icon_descriptions );
2020-12-30 11:55:26 +01:00
if ( dlg . ShowModal () == wxID_OK )
wxGetApp (). update_label_colours ();
});
2021-01-29 16:16:23 +01:00
m_search_btn -> Bind ( wxEVT_BUTTON , []( wxCommandEvent ) { wxGetApp (). plater () -> search ( false ); });
2018-03-21 22:21:37 +01:00
2019-08-06 16:51:32 +02:00
// Colors for ui "decoration"
m_sys_label_clr = wxGetApp (). get_label_clr_sys ();
m_modified_label_clr = wxGetApp (). get_label_clr_modified ();
m_default_text_clr = wxGetApp (). get_label_clr_default ();
2018-03-21 22:21:37 +01:00
2019-01-10 11:05:58 +01:00
// Sizer with buttons for mode changing
2019-04-25 01:45:00 +02:00
m_mode_sizer = new ModeSizer ( panel );
2019-01-10 11:05:58 +01:00
2019-05-15 16:44:33 +02:00
const float scale_factor = /*wxGetApp().*/ em_unit ( this ) * 0.1 ; // GetContentScaleFactor();
2019-08-06 16:51:32 +02:00
m_hsizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( m_hsizer , 0 , wxEXPAND | wxBOTTOM , 3 );
m_hsizer -> Add ( m_presets_choice , 0 , wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL , 3 );
m_hsizer -> AddSpacer ( int ( 4 * scale_factor ));
m_hsizer -> Add ( m_btn_save_preset , 0 , wxALIGN_CENTER_VERTICAL );
2019-02-06 15:29:13 +01:00
m_hsizer -> AddSpacer ( int ( 4 * scale_factor ));
2019-08-06 16:51:32 +02:00
m_hsizer -> Add ( m_btn_delete_preset , 0 , wxALIGN_CENTER_VERTICAL );
2020-07-28 11:31:16 +02:00
if ( m_btn_edit_ph_printer ) {
m_hsizer -> AddSpacer ( int ( 4 * scale_factor ));
m_hsizer -> Add ( m_btn_edit_ph_printer , 0 , wxALIGN_CENTER_VERTICAL );
}
2020-03-13 22:37:18 +01:00
m_hsizer -> AddSpacer ( int ( /*16*/ 8 * scale_factor ));
2019-08-06 16:51:32 +02:00
m_hsizer -> Add ( m_btn_hide_incompatible_presets , 0 , wxALIGN_CENTER_VERTICAL );
2020-03-13 22:37:18 +01:00
m_hsizer -> AddSpacer ( int ( 8 * scale_factor ));
m_hsizer -> Add ( m_question_btn , 0 , wxALIGN_CENTER_VERTICAL );
2020-04-22 20:27:42 +02:00
m_hsizer -> AddSpacer ( int ( 32 * scale_factor ));
2019-08-06 16:51:32 +02:00
m_hsizer -> Add ( m_undo_to_sys_btn , 0 , wxALIGN_CENTER_VERTICAL );
m_hsizer -> Add ( m_undo_btn , 0 , wxALIGN_CENTER_VERTICAL );
2020-04-23 12:41:38 +02:00
m_hsizer -> AddSpacer ( int ( 32 * scale_factor ));
2020-04-16 15:49:40 +02:00
m_hsizer -> Add ( m_search_btn , 0 , wxALIGN_CENTER_VERTICAL );
2021-02-04 09:42:32 +01:00
m_hsizer -> AddSpacer ( int ( 8 * scale_factor ));
m_hsizer -> Add ( m_btn_compare_preset , 0 , wxALIGN_CENTER_VERTICAL );
m_hsizer -> AddSpacer ( int ( 16 * scale_factor ));
2019-01-11 12:47:40 +01:00
// m_hsizer->AddStretchSpacer(32);
2019-08-06 16:51:32 +02:00
// StretchSpacer has a strange behavior under OSX, so
2019-01-11 12:47:40 +01:00
// There is used just additional sizer for m_mode_sizer with right alignment
auto mode_sizer = new wxBoxSizer ( wxVERTICAL );
2020-04-27 11:51:17 +02:00
mode_sizer -> Add ( m_mode_sizer , 1 , wxALIGN_RIGHT );
2019-07-25 16:23:32 +02:00
m_hsizer -> Add ( mode_sizer , 1 , wxALIGN_CENTER_VERTICAL | wxRIGHT , wxOSX ? 15 : 10 );
2017-12-05 15:54:01 +01:00
2019-08-06 16:51:32 +02:00
//Horizontal sizer to hold the tree and the selected page.
m_hsizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( m_hsizer , 1 , wxEXPAND , 0 );
2017-12-05 15:54:01 +01:00
2019-08-06 16:51:32 +02:00
//left vertical sizer
m_left_sizer = new wxBoxSizer ( wxVERTICAL );
m_hsizer -> Add ( m_left_sizer , 0 , wxEXPAND | wxLEFT | wxTOP | wxBOTTOM , 3 );
2017-12-05 15:54:01 +01:00
2019-08-06 16:51:32 +02:00
// tree
2019-02-07 14:44:05 +01:00
m_treectrl = new wxTreeCtrl ( panel , wxID_ANY , wxDefaultPosition , wxSize ( 20 * m_em_unit , - 1 ),
2019-08-06 16:51:32 +02:00
wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_SUNKEN | wxWANTS_CHARS );
m_left_sizer -> Add ( m_treectrl , 1 , wxEXPAND );
2019-05-15 16:44:33 +02:00
const int img_sz = int ( 16 * scale_factor + 0.5f );
m_icons = new wxImageList ( img_sz , img_sz , true , 1 );
2019-08-06 16:51:32 +02:00
// Index of the last icon inserted into $self->{icons}.
m_icon_count = - 1 ;
m_treectrl -> AssignImageList ( m_icons );
m_treectrl -> AddRoot ( "root" );
m_treectrl -> SetIndent ( 0 );
2017-12-05 15:54:01 +01:00
2020-09-29 11:04:25 +02:00
// Delay processing of the following handler until the message queue is flushed.
// This helps to process all the cursor key events on Windows in the tree control,
// so that the cursor jumps to the last item.
m_treectrl -> Bind ( wxEVT_TREE_SEL_CHANGED , [ this ]( wxTreeEvent & ) {
2021-01-11 13:11:35 +01:00
#ifdef __linux__
// Events queue is opposite On Linux. wxEVT_SET_FOCUS invokes after wxEVT_TREE_SEL_CHANGED,
// and a result wxEVT_KILL_FOCUS doesn't invoke for the TextCtrls.
// see https://github.com/prusa3d/PrusaSlicer/issues/5720
// So, call SetFocus explicitly for this control before changing of the selection
m_treectrl -> SetFocus ();
#endif
2020-09-29 13:36:56 +02:00
if ( ! m_disable_tree_sel_changed_event && ! m_pages . empty ()) {
if ( m_page_switch_running )
m_page_switch_planned = true ;
else {
m_page_switch_running = true ;
do {
m_page_switch_planned = false ;
2020-09-29 14:47:03 +02:00
m_treectrl -> Update ();
2020-09-29 13:36:56 +02:00
} while ( this -> tree_sel_change_delayed ());
m_page_switch_running = false ;
}
}
2020-09-29 11:04:25 +02:00
});
2019-08-06 16:51:32 +02:00
m_treectrl -> Bind ( wxEVT_KEY_DOWN , & Tab :: OnKeyDown , this );
2017-12-13 14:45:10 +01:00
2020-09-24 18:54:54 +02:00
// Initialize the page.
#ifdef __WXOSX__
auto page_parent = m_tmp_panel ;
#else
auto page_parent = this ;
#endif
m_page_view = new wxScrolledWindow ( page_parent , wxID_ANY , wxDefaultPosition , wxDefaultSize , wxTAB_TRAVERSAL );
m_page_sizer = new wxBoxSizer ( wxVERTICAL );
m_page_view -> SetSizer ( m_page_sizer );
m_page_view -> SetScrollbars ( 1 , 20 , 1 , 2 );
m_hsizer -> Add ( m_page_view , 1 , wxEXPAND | wxLEFT , 5 );
2021-02-04 09:42:32 +01:00
m_btn_compare_preset -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent e ) { compare_preset (); }));
2019-08-06 16:51:32 +02:00
m_btn_save_preset -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent e ) { save_preset (); }));
m_btn_delete_preset -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent e ) { delete_preset (); }));
m_btn_hide_incompatible_presets -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent e ) {
toggle_show_hide_incompatible ();
}));
2017-12-13 14:45:10 +01:00
2020-07-28 11:31:16 +02:00
if ( m_btn_edit_ph_printer )
2020-10-20 16:38:13 +02:00
m_btn_edit_ph_printer -> Bind ( wxEVT_BUTTON , [ this ]( wxCommandEvent e ) {
if ( m_preset_bundle -> physical_printers . has_selection ())
m_presets_choice -> edit_physical_printer ();
else
m_presets_choice -> add_physical_printer ();
});
2020-07-28 11:31:16 +02:00
2019-08-06 16:51:32 +02:00
// Initialize the DynamicPrintConfig by default keys/values.
build ();
2020-10-07 16:15:07 +02:00
// ys_FIXME: Following should not be needed, the function will be called later
// (update_mode->update_visibility->rebuild_page_tree). This does not work, during the
// second call of rebuild_page_tree m_treectrl->GetFirstVisibleItem(); returns zero
// for some unknown reason (and the page is not refreshed until user does a selection).
rebuild_page_tree ();
2020-02-27 11:44:01 +01:00
m_completed = true ;
2017-12-05 15:54:01 +01:00
}
2019-08-06 16:51:32 +02:00
void Tab :: add_scaled_button ( wxWindow * parent ,
ScalableButton ** btn ,
const std :: string & icon_name ,
const wxString & label /* = wxEmptyString*/ ,
2019-04-13 23:46:52 +02:00
long style /*= wxBU_EXACTFIT | wxNO_BORDER*/ )
{
2020-08-12 17:33:22 +02:00
* btn = new ScalableButton ( parent , wxID_ANY , icon_name , label , wxDefaultSize , wxDefaultPosition , style , true );
2019-04-13 23:46:52 +02:00
m_scaled_buttons . push_back ( * btn );
}
2019-08-06 16:51:32 +02:00
void Tab :: add_scaled_bitmap ( wxWindow * parent ,
ScalableBitmap & bmp ,
2019-04-25 01:45:00 +02:00
const std :: string & icon_name )
2019-04-13 23:46:52 +02:00
{
2019-04-25 01:45:00 +02:00
bmp = ScalableBitmap ( parent , icon_name );
2019-04-13 23:46:52 +02:00
m_scaled_bitmaps . push_back ( & bmp );
}
2018-03-16 12:56:03 +01:00
void Tab :: load_initial_data ()
{
2019-08-06 16:51:32 +02:00
m_config = & m_presets -> get_edited_preset (). config ;
bool has_parent = m_presets -> get_selected_preset_parent () != nullptr ;
m_bmp_non_system = has_parent ? & m_bmp_value_unlock : & m_bmp_white_bullet ;
m_ttg_non_system = has_parent ? & m_ttg_value_unlock : & m_ttg_white_bullet_ns ;
m_tt_non_system = has_parent ? & m_tt_value_unlock : & m_ttg_white_bullet_ns ;
2018-03-16 12:56:03 +01:00
}
2018-08-03 14:34:52 +02:00
Slic3r :: GUI :: PageShp Tab :: add_options_page ( const wxString & title , const std :: string & icon , bool is_extruder_pages /*= false*/ )
2017-12-05 15:54:01 +01:00
{
2019-08-06 16:51:32 +02:00
// Index of icon in an icon list $self->{icons}.
auto icon_idx = 0 ;
if ( ! icon . empty ()) {
icon_idx = ( m_icon_index . find ( icon ) == m_icon_index . end ()) ? - 1 : m_icon_index . at ( icon );
if ( icon_idx == - 1 ) {
// Add a new icon to the icon list.
2019-04-25 01:45:00 +02:00
m_scaled_icons_list . push_back ( ScalableBitmap ( this , icon ));
2019-04-13 23:46:52 +02:00
m_icons -> Add ( m_scaled_icons_list . back (). bmp ());
2018-10-23 11:44:46 +02:00
icon_idx = ++ m_icon_count ;
2019-08-06 16:51:32 +02:00
m_icon_index [ icon ] = icon_idx ;
}
2020-10-07 20:13:12 +02:00
if ( m_category_icon . find ( title ) == m_category_icon . end ()) {
// Add new category to the category_to_icon list.
m_category_icon [ title ] = icon ;
}
2019-08-06 16:51:32 +02:00
}
// Initialize the page.
2020-11-02 15:28:43 +01:00
PageShp page ( new Page ( m_page_view , title , icon_idx ));
2019-03-18 12:48:39 +01:00
// page->SetBackgroundStyle(wxBG_STYLE_SYSTEM);
#ifdef __WINDOWS__
// page->SetDoubleBuffered(true);
#endif //__WINDOWS__
2019-08-06 16:51:32 +02:00
if ( ! is_extruder_pages )
m_pages . push_back ( page );
2017-12-14 14:42:47 +01:00
2019-08-06 16:51:32 +02:00
page -> set_config ( m_config );
return page ;
2017-12-13 14:45:10 +01:00
}
2020-12-01 16:43:34 +01:00
// Names of categories is save in English always. We translate them only for UI.
// But category "Extruder n" can't be translated regularly (using _()), so
// just for this category we should splite the title and translate "Extruder" word separately
wxString Tab :: translate_category ( const wxString & title , Preset :: Type preset_type )
{
if ( preset_type == Preset :: TYPE_PRINTER && title . Contains ( "Extruder " )) {
return _ ( "Extruder" ) + title . SubString ( 8 , title . Last ());
}
return _ ( title );
}
2018-06-27 09:07:04 +02:00
void Tab :: OnActivate ()
{
2019-08-06 16:51:32 +02:00
wxWindowUpdateLocker noUpdates ( this );
2020-09-24 15:41:48 +02:00
#ifdef __WXOSX__
// wxWindowUpdateLocker noUpdates(this);
2019-08-06 16:51:32 +02:00
auto size = GetSizer () -> GetSize ();
m_tmp_panel -> GetSizer () -> SetMinSize ( size . x + m_size_move , size . y );
Fit ();
m_size_move *= - 1 ;
2018-06-28 18:30:22 +02:00
#endif // __WXOSX__
2020-09-24 15:41:48 +02:00
2020-10-01 19:58:23 +02:00
#ifdef __WXMSW__
// Workaround for tooltips over Tree Controls displayed over excessively long
// tree control items, stealing the window focus.
//
// In case the Tab was reparented from the MainFrame to the floating dialog,
// the tooltip created by the Tree Control before reparenting is not reparented,
// but it still points to the MainFrame. If the tooltip pops up, the MainFrame
// is incorrectly focussed, stealing focus from the floating dialog.
//
// The workaround is to delete the tooltip control.
// Vojtech tried to reparent the tooltip control, but it did not work,
// and if the Tab was later reparented back to MainFrame, the tooltip was displayed
// at an incorrect position, therefore it is safer to just discard the tooltip control
// altogether.
HWND hwnd_tt = TreeView_GetToolTips ( m_treectrl -> GetHandle ());
if ( hwnd_tt ) {
HWND hwnd_toplevel = find_toplevel_parent ( m_treectrl ) -> GetHandle ();
HWND hwnd_parent = :: GetParent ( hwnd_tt );
if ( hwnd_parent != hwnd_toplevel ) {
:: DestroyWindow ( hwnd_tt );
TreeView_SetToolTips ( m_treectrl -> GetHandle (), nullptr );
}
}
#endif
2020-10-01 20:12:50 +02:00
2020-09-24 15:41:48 +02:00
// create controls on active page
2020-09-29 14:47:03 +02:00
activate_selected_page ([](){});
2020-09-24 15:41:48 +02:00
m_hsizer -> Layout ();
Refresh ();
2018-06-27 09:07:04 +02:00
}
2020-12-30 11:55:26 +01:00
void Tab :: update_label_colours ()
2018-04-30 14:20:33 +02:00
{
2020-12-30 11:55:26 +01:00
if ( m_sys_label_clr == wxGetApp (). get_label_clr_sys () && m_modified_label_clr == wxGetApp (). get_label_clr_modified ())
return ;
m_sys_label_clr = wxGetApp (). get_label_clr_sys ();
m_modified_label_clr = wxGetApp (). get_label_clr_modified ();
2019-08-06 16:51:32 +02:00
//update options "decoration"
2021-01-29 16:16:23 +01:00
for ( const auto & opt : m_options_list )
2019-08-06 16:51:32 +02:00
{
const wxColour * color = & m_sys_label_clr ;
2018-04-30 14:20:33 +02:00
2019-08-06 16:51:32 +02:00
// value isn't equal to system value
if (( opt . second & osSystemValue ) == 0 ) {
// value is equal to last saved
if (( opt . second & osInitValue ) != 0 )
color = & m_default_text_clr ;
// value is modified
else
color = & m_modified_label_clr ;
}
2020-08-17 15:13:18 +02:00
if ( opt . first == "bed_shape" || opt . first == "filament_ramming_parameters" ||
opt . first == "compatible_prints" || opt . first == "compatible_printers" ) {
2020-10-22 13:02:17 +02:00
if ( m_colored_Label_colors . find ( opt . first ) != m_colored_Label_colors . end ())
2021-01-07 12:26:16 +01:00
m_colored_Label_colors . at ( opt . first ) = * color ;
2019-08-06 16:51:32 +02:00
continue ;
}
2018-04-30 14:20:33 +02:00
2019-08-06 16:51:32 +02:00
Field * field = get_field ( opt . first );
if ( field == nullptr ) continue ;
2020-11-02 15:28:43 +01:00
field -> set_label_colour ( color );
2019-08-06 16:51:32 +02:00
}
2018-04-30 14:20:33 +02:00
2019-08-06 16:51:32 +02:00
auto cur_item = m_treectrl -> GetFirstVisibleItem ();
2019-08-14 17:06:53 +02:00
if ( ! cur_item || ! m_treectrl -> IsVisible ( cur_item ))
return ;
2019-08-06 16:51:32 +02:00
while ( cur_item ) {
auto title = m_treectrl -> GetItemText ( cur_item );
for ( auto page : m_pages )
{
2020-12-01 16:43:34 +01:00
if ( translate_category ( page -> title (), m_type ) != title )
2019-08-06 16:51:32 +02:00
continue ;
2018-04-30 14:20:33 +02:00
2019-08-06 16:51:32 +02:00
const wxColor * clr = ! page -> m_is_nonsys_values ? & m_sys_label_clr :
page -> m_is_modified_values ? & m_modified_label_clr :
& m_default_text_clr ;
m_treectrl -> SetItemTextColour ( cur_item , * clr );
break ;
}
cur_item = m_treectrl -> GetNextVisible ( cur_item );
}
2020-12-30 11:55:26 +01:00
decorate ();
2018-04-30 14:20:33 +02:00
}
2020-09-22 11:17:43 +02:00
void Tab :: decorate ()
{
2021-01-29 16:16:23 +01:00
for ( const auto & opt : m_options_list )
2020-09-22 11:17:43 +02:00
{
2020-11-02 15:28:43 +01:00
Field * field = nullptr ;
wxColour * colored_label_clr = nullptr ;
2020-09-22 11:17:43 +02:00
2020-10-22 13:02:17 +02:00
if ( opt . first == "bed_shape" || opt . first == "filament_ramming_parameters" ||
2020-10-16 02:25:45 +02:00
opt . first == "compatible_prints" || opt . first == "compatible_printers" )
2021-01-07 12:26:16 +01:00
colored_label_clr = ( m_colored_Label_colors . find ( opt . first ) == m_colored_Label_colors . end ()) ? nullptr : & m_colored_Label_colors . at ( opt . first );
2020-10-22 13:02:17 +02:00
2020-11-02 15:28:43 +01:00
if ( ! colored_label_clr ) {
2020-09-22 11:17:43 +02:00
field = get_field ( opt . first );
2020-11-02 15:28:43 +01:00
if ( ! field )
continue ;
}
2020-09-22 11:17:43 +02:00
bool is_nonsys_value = false ;
bool is_modified_value = true ;
const ScalableBitmap * sys_icon = & m_bmp_value_lock ;
const ScalableBitmap * icon = & m_bmp_value_revert ;
const wxColour * color = m_is_default_preset ? & m_default_text_clr : & m_sys_label_clr ;
const wxString * sys_tt = & m_tt_value_lock ;
const wxString * tt = & m_tt_value_revert ;
// value isn't equal to system value
if (( opt . second & osSystemValue ) == 0 ) {
is_nonsys_value = true ;
sys_icon = m_bmp_non_system ;
sys_tt = m_tt_non_system ;
// value is equal to last saved
if (( opt . second & osInitValue ) != 0 )
color = & m_default_text_clr ;
// value is modified
else
color = & m_modified_label_clr ;
}
if (( opt . second & osInitValue ) != 0 )
{
is_modified_value = false ;
icon = & m_bmp_white_bullet ;
tt = & m_tt_white_bullet ;
}
2020-10-22 13:02:17 +02:00
if ( colored_label_clr ) {
* colored_label_clr = * color ;
continue ;
}
2020-09-22 11:17:43 +02:00
field -> m_is_nonsys_value = is_nonsys_value ;
field -> m_is_modified_value = is_modified_value ;
field -> set_undo_bitmap ( icon );
field -> set_undo_to_sys_bitmap ( sys_icon );
field -> set_undo_tooltip ( tt );
field -> set_undo_to_sys_tooltip ( sys_tt );
field -> set_label_colour ( color );
}
2020-10-26 19:38:09 +01:00
if ( m_active_page )
m_active_page -> refresh ();
2020-09-22 11:17:43 +02:00
}
2018-03-09 08:34:32 +01:00
// Update UI according to changes
void Tab :: update_changed_ui ()
{
2019-08-06 16:51:32 +02:00
if ( m_postpone_update_ui )
return ;
2018-03-07 15:05:41 +01:00
2019-08-06 16:51:32 +02:00
const bool deep_compare = ( m_type == Slic3r :: Preset :: TYPE_PRINTER || m_type == Slic3r :: Preset :: TYPE_SLA_MATERIAL );
auto dirty_options = m_presets -> current_dirty_options ( deep_compare );
auto nonsys_options = m_presets -> current_different_from_parent_options ( deep_compare );
2021-02-08 16:15:11 +01:00
if ( m_type == Preset :: TYPE_PRINTER && static_cast < TabPrinter *> ( this ) -> m_printer_technology == ptFFF ) {
2019-08-06 16:51:32 +02:00
TabPrinter * tab = static_cast < TabPrinter *> ( this );
if ( tab -> m_initial_extruders_count != tab -> m_extruders_count )
dirty_options . emplace_back ( "extruders_count" );
if ( tab -> m_sys_extruders_count != tab -> m_extruders_count )
nonsys_options . emplace_back ( "extruders_count" );
}
2018-03-06 09:44:53 +01:00
2019-08-06 16:51:32 +02:00
for ( auto & it : m_options_list )
it . second = m_opt_status_value ;
2018-04-18 13:32:21 +02:00
2019-08-06 16:51:32 +02:00
for ( auto opt_key : dirty_options ) m_options_list [ opt_key ] &= ~ osInitValue ;
for ( auto opt_key : nonsys_options ) m_options_list [ opt_key ] &= ~ osSystemValue ;
2018-04-18 13:32:21 +02:00
2020-09-22 11:17:43 +02:00
decorate ();
2018-03-21 22:21:37 +01:00
2019-08-06 16:51:32 +02:00
wxTheApp -> CallAfter ([ this ]() {
2019-05-10 15:10:17 +02:00
if ( parent ()) //To avoid a crash, parent should be exist for a moment of a tree updating
2019-08-06 16:51:32 +02:00
update_changed_tree_ui ();
});
2018-03-21 22:21:37 +01:00
}
2018-04-18 13:32:21 +02:00
void Tab :: init_options_list ()
{
2019-08-06 16:51:32 +02:00
if ( ! m_options_list . empty ())
m_options_list . clear ();
2018-04-18 13:32:21 +02:00
2021-01-29 16:16:23 +01:00
for ( const std :: string & opt_key : m_config -> keys ())
2019-08-06 16:51:32 +02:00
m_options_list . emplace ( opt_key , m_opt_status_value );
2018-04-18 13:32:21 +02:00
}
2018-03-21 22:21:37 +01:00
template < class T >
2018-08-08 17:47:59 +02:00
void add_correct_opts_to_options_list ( const std :: string & opt_key , std :: map < std :: string , int >& map , Tab * tab , const int & value )
2018-03-21 22:21:37 +01:00
{
2019-08-06 16:51:32 +02:00
T * opt_cur = static_cast < T *> ( tab -> m_config -> option ( opt_key ));
2019-09-06 17:46:55 +02:00
for ( size_t i = 0 ; i < opt_cur -> values . size (); i ++ )
2019-08-06 16:51:32 +02:00
map . emplace ( opt_key + "#" + std :: to_string ( i ), value );
2018-03-21 22:21:37 +01:00
}
2018-04-18 13:32:21 +02:00
void TabPrinter :: init_options_list ()
2018-03-21 22:21:37 +01:00
{
2019-08-06 16:51:32 +02:00
if ( ! m_options_list . empty ())
m_options_list . clear ();
2018-03-21 22:21:37 +01:00
2021-01-29 16:16:23 +01:00
for ( const std :: string & opt_key : m_config -> keys ())
2019-08-06 16:51:32 +02:00
{
2020-12-07 16:14:40 +01:00
if ( opt_key == "bed_shape" || opt_key == "thumbnails" ) {
2019-08-06 16:51:32 +02:00
m_options_list . emplace ( opt_key , m_opt_status_value );
continue ;
}
switch ( m_config -> option ( opt_key ) -> type ())
{
case coInts : add_correct_opts_to_options_list < ConfigOptionInts > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coBools : add_correct_opts_to_options_list < ConfigOptionBools > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coFloats : add_correct_opts_to_options_list < ConfigOptionFloats > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coStrings : add_correct_opts_to_options_list < ConfigOptionStrings > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coPercents : add_correct_opts_to_options_list < ConfigOptionPercents > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coPoints : add_correct_opts_to_options_list < ConfigOptionPoints > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
default : m_options_list . emplace ( opt_key , m_opt_status_value ); break ;
}
}
2021-02-08 16:15:11 +01:00
if ( m_printer_technology == ptFFF )
m_options_list . emplace ( "extruders_count" , m_opt_status_value );
2018-03-21 22:21:37 +01:00
}
2020-02-12 12:08:43 +01:00
void TabPrinter :: msw_rescale ()
{
Tab :: msw_rescale ();
// rescale missed options_groups
const std :: vector < PageShp >& pages = m_printer_technology == ptFFF ? m_pages_sla : m_pages_fff ;
for ( auto page : pages )
page -> msw_rescale ();
2020-10-23 19:17:10 +02:00
if ( m_reset_to_filament_color )
m_reset_to_filament_color -> msw_rescale ();
2020-02-12 12:08:43 +01:00
Layout ();
}
2020-05-21 17:29:00 +02:00
void TabPrinter :: sys_color_changed ()
{
Tab :: sys_color_changed ();
// update missed options_groups
const std :: vector < PageShp >& pages = m_printer_technology == ptFFF ? m_pages_sla : m_pages_fff ;
for ( auto page : pages )
2020-05-22 15:23:05 +02:00
page -> sys_color_changed ();
2020-05-21 17:29:00 +02:00
Layout ();
}
2018-08-08 17:47:59 +02:00
void TabSLAMaterial :: init_options_list ()
{
if ( ! m_options_list . empty ())
m_options_list . clear ();
2021-01-29 16:16:23 +01:00
for ( const std :: string & opt_key : m_config -> keys ())
2018-08-08 17:47:59 +02:00
{
2018-12-04 17:56:49 +01:00
if ( opt_key == "compatible_prints" || opt_key == "compatible_printers" ) {
2018-08-08 17:47:59 +02:00
m_options_list . emplace ( opt_key , m_opt_status_value );
continue ;
}
switch ( m_config -> option ( opt_key ) -> type ())
{
case coInts : add_correct_opts_to_options_list < ConfigOptionInts > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coBools : add_correct_opts_to_options_list < ConfigOptionBools > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coFloats : add_correct_opts_to_options_list < ConfigOptionFloats > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coStrings : add_correct_opts_to_options_list < ConfigOptionStrings > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coPercents : add_correct_opts_to_options_list < ConfigOptionPercents > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
case coPoints : add_correct_opts_to_options_list < ConfigOptionPoints > ( opt_key , m_options_list , this , m_opt_status_value ); break ;
default : m_options_list . emplace ( opt_key , m_opt_status_value ); break ;
}
}
}
2018-04-13 18:22:06 +02:00
void Tab :: get_sys_and_mod_flags ( const std :: string & opt_key , bool & sys_page , bool & modified_page )
{
2019-08-06 16:51:32 +02:00
auto opt = m_options_list . find ( opt_key );
2019-09-04 14:37:09 +02:00
if ( opt == m_options_list . end ())
return ;
2019-08-06 16:51:32 +02:00
if ( sys_page ) sys_page = ( opt -> second & osSystemValue ) != 0 ;
modified_page |= ( opt -> second & osInitValue ) == 0 ;
2018-04-13 18:22:06 +02:00
}
2018-03-21 22:21:37 +01:00
void Tab :: update_changed_tree_ui ()
{
2019-08-06 16:51:32 +02:00
if ( m_options_list . empty ())
2019-02-04 12:57:39 +01:00
return ;
2019-08-06 16:51:32 +02:00
auto cur_item = m_treectrl -> GetFirstVisibleItem ();
2018-10-22 15:18:05 +02:00
if ( ! cur_item || ! m_treectrl -> IsVisible ( cur_item ))
2018-10-15 17:18:38 +02:00
return ;
2019-03-22 20:49:17 +01:00
2019-08-06 16:51:32 +02:00
auto selected_item = m_treectrl -> GetSelection ();
auto selection = selected_item ? m_treectrl -> GetItemText ( selected_item ) : "" ;
2019-03-22 20:49:17 +01:00
2019-08-06 16:51:32 +02:00
while ( cur_item ) {
auto title = m_treectrl -> GetItemText ( cur_item );
for ( auto page : m_pages )
{
2020-12-01 16:43:34 +01:00
if ( translate_category ( page -> title (), m_type ) != title )
2019-08-06 16:51:32 +02:00
continue ;
bool sys_page = true ;
bool modified_page = false ;
2020-04-13 17:55:38 +02:00
if ( page -> title () == "General" ) {
2019-08-06 16:51:32 +02:00
std :: initializer_list < const char *> optional_keys { "extruders_count" , "bed_shape" };
for ( auto & opt_key : optional_keys ) {
get_sys_and_mod_flags ( opt_key , sys_page , modified_page );
}
}
2020-08-17 15:13:18 +02:00
if ( m_type == Preset :: TYPE_FILAMENT && page -> title () == "Advanced" ) {
get_sys_and_mod_flags ( "filament_ramming_parameters" , sys_page , modified_page );
}
2020-04-13 17:55:38 +02:00
if ( page -> title () == "Dependencies" ) {
2019-08-06 16:51:32 +02:00
if ( m_type == Slic3r :: Preset :: TYPE_PRINTER ) {
sys_page = m_presets -> get_selected_preset_parent () != nullptr ;
modified_page = false ;
} else {
if ( m_type == Slic3r :: Preset :: TYPE_FILAMENT || m_type == Slic3r :: Preset :: TYPE_SLA_MATERIAL )
get_sys_and_mod_flags ( "compatible_prints" , sys_page , modified_page );
get_sys_and_mod_flags ( "compatible_printers" , sys_page , modified_page );
}
}
for ( auto group : page -> m_optgroups )
{
if ( ! sys_page && modified_page )
break ;
2020-09-24 15:34:13 +02:00
for ( const auto & kvp : group -> opt_map ()) {
const std :: string & opt_key = kvp . first ;
2019-08-06 16:51:32 +02:00
get_sys_and_mod_flags ( opt_key , sys_page , modified_page );
}
}
2018-04-18 13:32:21 +02:00
2019-08-06 16:51:32 +02:00
const wxColor * clr = sys_page ? ( m_is_default_preset ? & m_default_text_clr : & m_sys_label_clr ) :
modified_page ? & m_modified_label_clr :
& m_default_text_clr ;
2018-04-18 13:32:21 +02:00
2019-08-06 16:51:32 +02:00
if ( page -> set_item_colour ( clr ))
m_treectrl -> SetItemTextColour ( cur_item , * clr );
2018-03-22 09:37:42 +01:00
2019-08-06 16:51:32 +02:00
page -> m_is_nonsys_values = ! sys_page ;
page -> m_is_modified_values = modified_page ;
2018-03-22 09:37:42 +01:00
2019-08-06 16:51:32 +02:00
if ( selection == title ) {
m_is_nonsys_values = page -> m_is_nonsys_values ;
m_is_modified_values = page -> m_is_modified_values ;
}
break ;
}
2018-09-21 01:33:41 +02:00
auto next_item = m_treectrl -> GetNextVisible ( cur_item );
2018-10-08 16:27:38 +02:00
cur_item = next_item ;
2019-08-06 16:51:32 +02:00
}
update_undo_buttons ();
2018-03-22 09:37:42 +01:00
}
void Tab :: update_undo_buttons ()
{
2019-08-06 16:51:32 +02:00
m_undo_btn -> SetBitmap_ ( m_is_modified_values ? m_bmp_value_revert : m_bmp_white_bullet );
m_undo_to_sys_btn -> SetBitmap_ ( m_is_nonsys_values ? * m_bmp_non_system : m_bmp_value_lock );
2018-03-22 09:37:42 +01:00
2019-08-06 16:51:32 +02:00
m_undo_btn -> SetToolTip ( m_is_modified_values ? m_ttg_value_revert : m_ttg_white_bullet );
m_undo_to_sys_btn -> SetToolTip ( m_is_nonsys_values ? * m_ttg_non_system : m_ttg_value_lock );
2018-01-05 15:11:33 +01:00
}
2018-04-18 13:32:21 +02:00
void Tab :: on_roll_back_value ( const bool to_sys /*= true*/ )
2018-03-22 10:56:57 +01:00
{
2020-09-24 15:41:48 +02:00
if ( ! m_active_page ) return ;
2019-08-06 16:51:32 +02:00
int os ;
if ( to_sys ) {
if ( ! m_is_nonsys_values ) return ;
os = osSystemValue ;
}
else {
if ( ! m_is_modified_values ) return ;
os = osInitValue ;
}
2018-03-22 10:56:57 +01:00
2019-08-06 16:51:32 +02:00
m_postpone_update_ui = true ;
2018-03-22 10:56:57 +01:00
2020-10-07 11:52:37 +02:00
for ( auto group : m_active_page -> m_optgroups ) {
if ( group -> title == "Capabilities" ) {
if (( m_options_list [ "extruders_count" ] & os ) == 0 )
to_sys ? group -> back_to_sys_value ( "extruders_count" ) : group -> back_to_initial_value ( "extruders_count" );
}
if ( group -> title == "Size and coordinates" ) {
if (( m_options_list [ "bed_shape" ] & os ) == 0 ) {
to_sys ? group -> back_to_sys_value ( "bed_shape" ) : group -> back_to_initial_value ( "bed_shape" );
load_key_value ( "bed_shape" , true /*some value*/ , true );
2019-08-06 16:51:32 +02:00
}
2020-10-07 11:52:37 +02:00
}
if ( group -> title == "Toolchange parameters with single extruder MM printers" ) {
if (( m_options_list [ "filament_ramming_parameters" ] & os ) == 0 )
to_sys ? group -> back_to_sys_value ( "filament_ramming_parameters" ) : group -> back_to_initial_value ( "filament_ramming_parameters" );
}
if ( group -> title == "Profile dependencies" ) {
// "compatible_printers" option doesn't exists in Printer Settimgs Tab
if ( m_type != Preset :: TYPE_PRINTER && ( m_options_list [ "compatible_printers" ] & os ) == 0 ) {
to_sys ? group -> back_to_sys_value ( "compatible_printers" ) : group -> back_to_initial_value ( "compatible_printers" );
load_key_value ( "compatible_printers" , true /*some value*/ , true );
bool is_empty = m_config -> option < ConfigOptionStrings > ( "compatible_printers" ) -> values . empty ();
m_compatible_printers . checkbox -> SetValue ( is_empty );
is_empty ? m_compatible_printers . btn -> Disable () : m_compatible_printers . btn -> Enable ();
}
// "compatible_prints" option exists only in Filament Settimgs and Materials Tabs
if (( m_type == Preset :: TYPE_FILAMENT || m_type == Preset :: TYPE_SLA_MATERIAL ) && ( m_options_list [ "compatible_prints" ] & os ) == 0 ) {
to_sys ? group -> back_to_sys_value ( "compatible_prints" ) : group -> back_to_initial_value ( "compatible_prints" );
load_key_value ( "compatible_prints" , true /*some value*/ , true );
bool is_empty = m_config -> option < ConfigOptionStrings > ( "compatible_prints" ) -> values . empty ();
m_compatible_prints . checkbox -> SetValue ( is_empty );
is_empty ? m_compatible_prints . btn -> Disable () : m_compatible_prints . btn -> Enable ();
}
}
for ( const auto & kvp : group -> opt_map ()) {
const std :: string & opt_key = kvp . first ;
if (( m_options_list [ opt_key ] & os ) == 0 )
to_sys ? group -> back_to_sys_value ( opt_key ) : group -> back_to_initial_value ( opt_key );
}
}
2018-03-22 10:56:57 +01:00
2019-08-06 16:51:32 +02:00
m_postpone_update_ui = false ;
update_changed_ui ();
2018-03-22 10:56:57 +01:00
}
2018-03-09 08:34:32 +01:00
// Update the combo box label of the selected preset based on its "dirty" state,
// comparing the selected preset config with $self->{config}.
2018-10-31 12:56:08 +01:00
void Tab :: update_dirty ()
{
2020-06-16 12:57:49 +02:00
m_presets_choice -> update_dirty ();
2019-08-06 16:51:32 +02:00
on_presets_changed ();
update_changed_ui ();
2018-03-09 08:34:32 +01:00
}
2018-01-16 16:28:01 +01:00
void Tab :: update_tab_ui ()
{
2020-06-16 12:57:49 +02:00
m_presets_choice -> update ();
2018-01-16 16:28:01 +01:00
}
2018-01-05 15:11:33 +01:00
// Load a provied DynamicConfig into the tab, modifying the active preset.
// This could be used for example by setting a Wipe Tower position by interactive manipulation in the 3D view.
2018-04-13 12:35:04 +02:00
void Tab :: load_config ( const DynamicPrintConfig & config )
2018-01-05 15:11:33 +01:00
{
2019-08-06 16:51:32 +02:00
bool modified = 0 ;
for ( auto opt_key : m_config -> diff ( config )) {
m_config -> set_key_value ( opt_key , config . option ( opt_key ) -> clone ());
modified = 1 ;
}
if ( modified ) {
update_dirty ();
//# Initialize UI components with the config values.
reload_config ();
update ();
}
2018-01-05 15:11:33 +01:00
}
2018-01-09 09:41:07 +01:00
// Reload current $self->{config} (aka $self->{presets}->edited_preset->config) into the UI fields.
2018-10-31 16:22:36 +01:00
void Tab :: reload_config ()
{
2020-09-24 15:41:48 +02:00
if ( m_active_page )
m_active_page -> reload_config ();
2018-01-09 09:41:07 +01:00
}
2019-03-20 16:22:01 +01:00
void Tab :: update_mode ()
2018-10-19 13:55:29 +02:00
{
2019-03-20 16:22:01 +01:00
m_mode = wxGetApp (). get_mode ();
2018-10-21 23:09:24 +02:00
2019-01-11 12:47:40 +01:00
// update mode for ModeSizer
2019-03-20 16:22:01 +01:00
m_mode_sizer -> SetMode ( m_mode );
update_visibility ();
2019-08-13 17:09:42 +02:00
update_changed_tree_ui ();
2019-03-20 16:22:01 +01:00
}
void Tab :: update_visibility ()
{
Freeze (); // There is needed Freeze/Thaw to avoid a flashing after Show/Layout
2019-08-06 16:51:32 +02:00
for ( auto page : m_pages )
2020-09-22 11:17:43 +02:00
page -> update_visibility ( m_mode , page . get () == m_active_page );
rebuild_page_tree ();
2018-10-21 23:09:24 +02:00
2020-09-22 11:17:43 +02:00
if ( this -> m_type == Preset :: TYPE_SLA_PRINT )
update_description_lines ();
2020-03-04 13:47:35 +01:00
2019-01-11 12:47:40 +01:00
Layout ();
2019-08-06 16:51:32 +02:00
Thaw ();
2018-10-19 13:55:29 +02:00
}
2019-04-25 01:45:00 +02:00
void Tab :: msw_rescale ()
2019-04-10 09:56:32 +02:00
{
2020-06-18 11:39:25 +02:00
m_em_unit = em_unit ( m_parent );
2019-04-10 09:56:32 +02:00
2019-04-25 01:45:00 +02:00
m_mode_sizer -> msw_rescale ();
2020-06-16 12:57:49 +02:00
m_presets_choice -> msw_rescale ();
2019-04-13 23:46:52 +02:00
m_treectrl -> SetMinSize ( wxSize ( 20 * m_em_unit , - 1 ));
2019-04-10 09:56:32 +02:00
2019-04-13 23:46:52 +02:00
// rescale buttons and cached bitmaps
for ( const auto btn : m_scaled_buttons )
2019-04-25 01:45:00 +02:00
btn -> msw_rescale ();
2019-04-13 23:46:52 +02:00
for ( const auto bmp : m_scaled_bitmaps )
2019-04-25 01:45:00 +02:00
bmp -> msw_rescale ();
2019-04-13 23:46:52 +02:00
2020-10-23 19:17:10 +02:00
if ( m_detach_preset_btn )
m_detach_preset_btn -> msw_rescale ();
2019-04-13 23:46:52 +02:00
// rescale icons for tree_ctrl
2019-04-25 01:45:00 +02:00
for ( ScalableBitmap & bmp : m_scaled_icons_list )
bmp . msw_rescale ();
2019-04-13 23:46:52 +02:00
// recreate and set new ImageList for tree_ctrl
m_icons -> RemoveAll ();
m_icons = new wxImageList ( m_scaled_icons_list . front (). bmp (). GetWidth (), m_scaled_icons_list . front (). bmp (). GetHeight ());
2019-04-25 01:45:00 +02:00
for ( ScalableBitmap & bmp : m_scaled_icons_list )
2019-04-13 23:46:52 +02:00
m_icons -> Add ( bmp . bmp ());
m_treectrl -> AssignImageList ( m_icons );
// rescale options_groups
2020-09-22 16:16:35 +02:00
if ( m_active_page )
m_active_page -> msw_rescale ();
2019-04-13 23:46:52 +02:00
Layout ();
2019-04-10 09:56:32 +02:00
}
2020-05-21 17:29:00 +02:00
void Tab :: sys_color_changed ()
{
update_tab_ui ();
2020-10-30 12:24:33 +01:00
m_presets_choice -> msw_rescale ();
2020-05-21 17:29:00 +02:00
// update buttons and cached bitmaps
for ( const auto btn : m_scaled_buttons )
btn -> msw_rescale ();
for ( const auto bmp : m_scaled_bitmaps )
bmp -> msw_rescale ();
// update icons for tree_ctrl
for ( ScalableBitmap & bmp : m_scaled_icons_list )
bmp . msw_rescale ();
// recreate and set new ImageList for tree_ctrl
m_icons -> RemoveAll ();
m_icons = new wxImageList ( m_scaled_icons_list . front (). bmp (). GetWidth (), m_scaled_icons_list . front (). bmp (). GetHeight ());
for ( ScalableBitmap & bmp : m_scaled_icons_list )
m_icons -> Add ( bmp . bmp ());
m_treectrl -> AssignImageList ( m_icons );
// Colors for ui "decoration"
2020-12-30 11:55:26 +01:00
update_label_colours ();
2020-05-21 17:29:00 +02:00
// update options_groups
2020-09-24 15:41:48 +02:00
if ( m_active_page )
m_active_page -> msw_rescale ();
2020-05-21 17:29:00 +02:00
Layout ();
}
2018-04-13 12:35:04 +02:00
Field * Tab :: get_field ( const t_config_option_key & opt_key , int opt_index /* = -1*/ ) const
2018-01-11 10:33:17 +01:00
{
2020-09-24 15:41:48 +02:00
return m_active_page ? m_active_page -> get_field ( opt_key , opt_index ) : nullptr ;
2020-10-27 22:19:12 +01:00
}
2020-09-24 15:41:48 +02:00
2020-10-27 22:19:12 +01:00
std :: pair < OG_CustomCtrl * , bool *> Tab :: get_custom_ctrl_with_blinking_ptr ( const t_config_option_key & opt_key , int opt_index /* = -1*/ )
{
if ( ! m_active_page )
return { nullptr , nullptr };
std :: pair < OG_CustomCtrl * , bool *> ret = { nullptr , nullptr };
for ( auto opt_group : m_active_page -> m_optgroups ) {
ret = opt_group -> get_custom_ctrl_with_blinking_ptr ( opt_key , opt_index );
if ( ret . first && ret . second )
break ;
2019-08-06 16:51:32 +02:00
}
2020-10-27 22:19:12 +01:00
return ret ;
2018-01-11 10:33:17 +01:00
}
2020-03-13 22:37:18 +01:00
Field * Tab :: get_field ( const t_config_option_key & opt_key , Page ** selected_page , int opt_index /* = -1*/ )
{
Field * field = nullptr ;
for ( auto page : m_pages ) {
field = page -> get_field ( opt_key , opt_index );
if ( field != nullptr ) {
* selected_page = page . get ();
return field ;
}
}
return field ;
}
2020-09-22 11:17:43 +02:00
void Tab :: toggle_option ( const std :: string & opt_key , bool toggle , int opt_index /* = -1*/ )
{
if ( ! m_active_page )
return ;
Field * field = m_active_page -> get_field ( opt_key , opt_index );
if ( field )
field -> toggle ( toggle );
};
2018-01-12 12:41:13 +01:00
// To be called by custom widgets, load a value into a config,
// update the preset selection boxes (the dirty flags)
2018-04-16 13:43:01 +02:00
// If value is saved before calling this function, put saved_value = true,
// and value can be some random value because in this case it will not been used
void Tab :: load_key_value ( const std :: string & opt_key , const boost :: any & value , bool saved_value /*= false*/ )
2017-12-22 11:50:28 +01:00
{
2019-08-06 16:51:32 +02:00
if ( ! saved_value ) change_opt_value ( * m_config , opt_key , value );
// Mark the print & filament enabled if they are compatible with the currently selected preset.
if ( opt_key == "compatible_printers" || opt_key == "compatible_prints" ) {
// Don't select another profile if this profile happens to become incompatible.
2020-02-27 11:44:01 +01:00
m_preset_bundle -> update_compatible ( PresetSelectCompatibleType :: Never );
2019-08-06 16:51:32 +02:00
}
2020-06-16 12:57:49 +02:00
m_presets_choice -> update_dirty ();
2019-08-06 16:51:32 +02:00
on_presets_changed ();
update ();
2018-01-12 12:41:13 +01:00
}
2019-05-03 18:01:39 +02:00
static wxString support_combo_value_for_config ( const DynamicPrintConfig & config , bool is_fff )
{
const std :: string support = is_fff ? "support_material" : "supports_enable" ;
const std :: string buildplate_only = is_fff ? "support_material_buildplate_only" : "support_buildplate_only" ;
2019-08-06 16:51:32 +02:00
return
! config . opt_bool ( support ) ?
_ ( "None" ) :
( is_fff && ! config . opt_bool ( "support_material_auto" )) ?
_ ( "For support enforcers only" ) :
2019-05-03 18:01:39 +02:00
( config . opt_bool ( buildplate_only ) ? _ ( "Support on build plate only" ) :
2019-08-06 16:51:32 +02:00
_ ( "Everywhere" ));
2019-05-03 18:01:39 +02:00
}
2019-08-08 09:48:56 +02:00
static wxString pad_combo_value_for_config ( const DynamicPrintConfig & config )
{
2019-08-28 11:32:49 +02:00
return config . opt_bool ( "pad_enable" ) ? ( config . opt_bool ( "pad_around_object" ) ? _ ( "Around object" ) : _ ( "Below object" )) : _ ( "None" );
2019-08-08 09:48:56 +02:00
}
2018-04-13 12:35:04 +02:00
void Tab :: on_value_change ( const std :: string & opt_key , const boost :: any & value )
2018-01-21 23:35:00 +01:00
{
2019-08-06 16:51:32 +02:00
if ( wxGetApp (). plater () == nullptr ) {
return ;
}
2019-03-11 13:59:58 +01:00
2019-03-11 16:00:13 +01:00
const bool is_fff = supports_printer_technology ( ptFFF );
2019-08-06 16:51:32 +02:00
ConfigOptionsGroup * og_freq_chng_params = wxGetApp (). sidebar (). og_freq_chng_params ( is_fff );
2019-03-11 16:00:13 +01:00
if ( opt_key == "fill_density" || opt_key == "pad_enable" )
2019-08-06 16:51:32 +02:00
{
2018-10-05 23:29:15 +02:00
boost :: any val = og_freq_chng_params -> get_config_value ( * m_config , opt_key );
og_freq_chng_params -> set_value ( opt_key , val );
2019-08-06 16:51:32 +02:00
}
2019-08-28 11:32:49 +02:00
if ( opt_key == "pad_around_object" ) {
for ( PageShp & pg : m_pages ) {
2020-09-24 15:41:48 +02:00
Field * fld = pg -> get_field ( opt_key ); /// !!! ysFIXME ????
2019-08-28 11:32:49 +02:00
if ( fld ) fld -> set_value ( value , false );
}
}
2019-03-11 16:00:13 +01:00
2019-08-06 16:51:32 +02:00
if ( is_fff ?
( opt_key == "support_material" || opt_key == "support_material_auto" || opt_key == "support_material_buildplate_only" ) :
( opt_key == "supports_enable" || opt_key == "support_buildplate_only" ))
og_freq_chng_params -> set_value ( "support" , support_combo_value_for_config ( * m_config , is_fff ));
2019-03-11 16:00:13 +01:00
2019-08-28 11:32:49 +02:00
if ( ! is_fff && ( opt_key == "pad_enable" || opt_key == "pad_around_object" ))
2019-08-20 17:24:48 +02:00
og_freq_chng_params -> set_value ( "pad" , pad_combo_value_for_config ( * m_config ));
2019-08-08 09:48:56 +02:00
2019-08-06 16:51:32 +02:00
if ( opt_key == "brim_width" )
{
bool val = m_config -> opt_float ( "brim_width" ) > 0.0 ? true : false ;
2018-10-05 23:29:15 +02:00
og_freq_chng_params -> set_value ( "brim" , val );
2019-08-06 16:51:32 +02:00
}
2018-03-12 16:52:21 +01:00
2018-04-05 10:44:31 +02:00
if ( opt_key == "wipe_tower" || opt_key == "single_extruder_multi_material" || opt_key == "extruders_count" )
update_wiping_button_visibility ();
2019-02-22 09:38:56 +01:00
if ( opt_key == "extruders_count" )
wxGetApp (). plater () -> on_extruders_change ( boost :: any_cast < size_t > ( value ));
2019-08-06 16:51:32 +02:00
update ();
2018-01-25 13:46:04 +01:00
}
2018-01-21 23:35:00 +01:00
2018-04-05 10:44:31 +02:00
// Show/hide the 'purging volumes' button
void Tab :: update_wiping_button_visibility () {
2018-10-04 16:43:10 +02:00
if ( m_preset_bundle -> printers . get_selected_preset (). printer_technology () == ptSLA )
2018-08-06 17:01:41 +02:00
return ; // ys_FIXME
2018-04-05 10:44:31 +02:00
bool wipe_tower_enabled = dynamic_cast < ConfigOptionBool *> ( ( m_preset_bundle -> prints . get_edited_preset (). config ). option ( "wipe_tower" )) -> value ;
bool multiple_extruders = dynamic_cast < ConfigOptionFloats *> (( m_preset_bundle -> printers . get_edited_preset (). config ). option ( "nozzle_diameter" )) -> values . size () > 1 ;
2018-10-24 12:57:23 +02:00
auto wiping_dialog_button = wxGetApp (). sidebar (). get_wiping_dialog_button ();
2018-10-03 15:14:52 +02:00
if ( wiping_dialog_button ) {
2019-05-03 00:17:24 -04:00
wiping_dialog_button -> Show ( wipe_tower_enabled && multiple_extruders );
2018-10-03 15:14:52 +02:00
wiping_dialog_button -> GetParent () -> Layout ();
2018-09-21 01:33:41 +02:00
}
2018-04-05 10:44:31 +02:00
}
2020-03-13 22:37:18 +01:00
void Tab :: activate_option ( const std :: string & opt_key , const wxString & category )
{
2020-12-01 16:43:34 +01:00
wxString page_title = translate_category ( category , m_type );
2020-03-13 22:37:18 +01:00
auto cur_item = m_treectrl -> GetFirstVisibleItem ();
if ( ! cur_item || ! m_treectrl -> IsVisible ( cur_item ))
return ;
while ( cur_item ) {
auto title = m_treectrl -> GetItemText ( cur_item );
2020-09-24 15:41:48 +02:00
if ( page_title != title ) {
2020-03-13 22:37:18 +01:00
cur_item = m_treectrl -> GetNextVisible ( cur_item );
continue ;
}
m_treectrl -> SelectItem ( cur_item );
break ;
}
// we should to activate a tab with searched option, if it doesn't.
2020-09-24 15:41:48 +02:00
wxGetApp (). mainframe -> select_tab ( this );
Field * field = get_field ( opt_key );
2020-03-13 22:37:18 +01:00
// focused selected field
2020-11-02 15:28:43 +01:00
if ( field )
2020-03-13 22:37:18 +01:00
field -> getWindow () -> SetFocus ();
2020-11-02 15:28:43 +01:00
else if ( category == "Single extruder MM setup" ) {
2020-04-16 09:59:12 +02:00
// When we show and hide "Single extruder MM setup" page,
// related options are still in the search list
// So, let's hightlighte a "single_extruder_multi_material" option,
// as a "way" to show hidden page again
field = get_field ( "single_extruder_multi_material" );
2020-11-02 15:28:43 +01:00
if ( field )
2020-04-16 09:59:12 +02:00
field -> getWindow () -> SetFocus ();
2020-04-07 12:09:58 +02:00
}
2020-04-13 17:55:38 +02:00
2020-10-27 22:19:12 +01:00
m_highlighter . init ( get_custom_ctrl_with_blinking_ptr ( opt_key ));
2020-04-16 09:59:12 +02:00
}
2020-04-13 17:55:38 +02:00
2020-04-16 09:59:12 +02:00
void Tab :: apply_searcher ()
{
wxGetApp (). sidebar (). get_searcher (). apply ( m_config , m_type , m_mode );
2020-03-13 22:37:18 +01:00
}
2020-09-02 09:06:42 +02:00
void Tab :: cache_config_diff ( const std :: vector < std :: string >& selected_options )
{
m_cache_config . apply_only ( m_presets -> get_edited_preset (). config , selected_options );
}
void Tab :: apply_config_from_cache ()
{
if ( ! m_cache_config . empty ()) {
m_presets -> get_edited_preset (). config . apply ( m_cache_config );
m_cache_config . clear ();
update_dirty ();
}
}
2018-04-05 10:44:31 +02:00
2019-12-02 22:48:01 -05:00
// Call a callback to update the selection of presets on the plater:
2018-01-16 16:28:01 +01:00
// To update the content of the selection boxes,
// to update the filament colors of the selection boxes,
// to update the "dirty" flags of the selection boxes,
2019-03-13 13:13:18 +01:00
// to update number of "filament" selection boxes when the number of extruders change.
2018-02-08 10:58:13 +01:00
void Tab :: on_presets_changed ()
2018-01-21 23:35:00 +01:00
{
2019-08-06 16:51:32 +02:00
if ( wxGetApp (). plater () == nullptr ) {
return ;
}
2019-03-13 17:38:41 +01:00
2019-03-13 13:13:18 +01:00
// Instead of PostEvent (EVT_TAB_PRESETS_CHANGED) just call update_presets
wxGetApp (). plater () -> sidebar (). update_presets ( m_type );
2018-12-04 17:56:49 +01:00
// Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
for ( auto t : m_dependent_tabs )
{
2020-09-02 09:06:42 +02:00
Tab * tab = wxGetApp (). get_tab ( t );
2018-12-04 17:56:49 +01:00
// If the printer tells us that the print or filament/sla_material preset has been switched or invalidated,
// refresh the print or filament/sla_material tab page.
2020-09-02 09:06:42 +02:00
// But if there are options, moved from the previously selected preset, update them to edited preset
tab -> apply_config_from_cache ();
tab -> load_current_preset ();
2018-11-16 11:14:56 +01:00
}
2019-02-22 11:59:40 +01:00
// clear m_dependent_tabs after first update from select_preset()
// to avoid needless preset loading from update() function
m_dependent_tabs . clear ();
2018-04-26 12:40:17 +02:00
}
2018-03-23 09:41:04 +01:00
2020-03-04 13:47:35 +01:00
void Tab :: build_preset_description_line ( ConfigOptionsGroup * optgroup )
{
auto description_line = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_parent_preset_description_line );
};
auto detach_preset_btn = [ this ]( wxWindow * parent ) {
2020-09-22 16:16:35 +02:00
m_detach_preset_btn = new ScalableButton ( parent , wxID_ANY , "lock_open_sys" , _L ( "Detach from system preset" ),
wxDefaultSize , wxDefaultPosition , wxBU_LEFT | wxBU_EXACTFIT , true );
2020-03-04 13:47:35 +01:00
ScalableButton * btn = m_detach_preset_btn ;
btn -> SetFont ( Slic3r :: GUI :: wxGetApp (). normal_font ());
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( btn );
btn -> Bind ( wxEVT_BUTTON , [ this , parent ]( wxCommandEvent & )
{
2020-03-07 10:26:40 +01:00
bool system = m_presets -> get_edited_preset (). is_system ;
bool dirty = m_presets -> get_edited_preset (). is_dirty ;
wxString msg_text = system ?
_ ( L ( "A copy of the current system preset will be created, which will be detached from the system preset." )) :
_ ( L ( "The current custom preset will be detached from the parent system preset." ));
if ( dirty ) {
msg_text += " \n\n " ;
msg_text += _ ( L ( "Modifications to the current profile will be saved." ));
}
msg_text += " \n\n " ;
2021-02-23 18:46:05 +01:00
msg_text += _ ( L ( "This action is not revertible. \n Do you want to proceed?" ));
2020-03-04 13:47:35 +01:00
2020-03-07 10:26:40 +01:00
wxMessageDialog dialog ( parent , msg_text , _ ( L ( "Detach preset" )), wxICON_WARNING | wxYES_NO | wxCANCEL );
2020-03-04 13:47:35 +01:00
if ( dialog . ShowModal () == wxID_YES )
2020-03-06 17:41:00 +01:00
save_preset ( m_presets -> get_edited_preset (). is_system ? std :: string () : m_presets -> get_edited_preset (). name , true );
2020-03-04 13:47:35 +01:00
});
btn -> Hide ();
return sizer ;
};
Line line = Line { "" , "" };
line . full_width = 1 ;
line . append_widget ( description_line );
line . append_widget ( detach_preset_btn );
optgroup -> append_line ( line );
}
2018-04-26 12:40:17 +02:00
void Tab :: update_preset_description_line ()
{
2019-08-06 16:51:32 +02:00
const Preset * parent = m_presets -> get_selected_preset_parent ();
const Preset & preset = m_presets -> get_edited_preset ();
2019-07-26 13:52:51 +02:00
2019-08-06 16:51:32 +02:00
wxString description_line ;
2019-07-26 13:52:51 +02:00
2019-08-06 16:51:32 +02:00
if ( preset . is_default ) {
description_line = _ ( L ( "This is a default preset." ));
} else if ( preset . is_system ) {
description_line = _ ( L ( "This is a system preset." ));
} else if ( parent == nullptr ) {
description_line = _ ( L ( "Current preset is inherited from the default preset." ));
} else {
2020-11-28 11:13:46 +01:00
std :: string name = parent -> name ;
boost :: replace_all ( name , "&" , "&&" );
description_line = _ ( L ( "Current preset is inherited from" )) + ": \n\t " + from_u8 ( name );
2019-08-06 16:51:32 +02:00
}
2019-07-26 13:52:51 +02:00
2019-08-06 16:51:32 +02:00
if ( preset . is_default || preset . is_system )
description_line += " \n\t " + _ ( L ( "It can't be deleted or modified." )) +
" \n\t " + _ ( L ( "Any modifications should be saved as a new preset inherited from this one." )) +
" \n\t " + _ ( L ( "To do that please specify a new name for the preset." ));
2018-11-16 17:36:23 +01:00
2019-08-06 16:51:32 +02:00
if ( parent && parent -> vendor )
{
description_line += " \n\n " + _ ( L ( "Additional information:" )) + " \n " ;
description_line += " \t " + _ ( L ( "vendor" )) + ": " + ( m_type == Slic3r :: Preset :: TYPE_PRINTER ? " \n\t\t " : "" ) + parent -> vendor -> name +
", ver: " + parent -> vendor -> config_version . to_string ();
if ( m_type == Slic3r :: Preset :: TYPE_PRINTER ) {
const std :: string & printer_model = preset . config . opt_string ( "printer_model" );
if ( ! printer_model . empty ())
description_line += " \n\n\t " + _ ( L ( "printer model" )) + ": \n\t\t " + printer_model ;
switch ( preset . printer_technology ()) {
case ptFFF :
{
//FIXME add prefered_sla_material_profile for SLA
const std :: string & default_print_profile = preset . config . opt_string ( "default_print_profile" );
const std :: vector < std :: string > & default_filament_profiles = preset . config . option < ConfigOptionStrings > ( "default_filament_profile" ) -> values ;
if ( ! default_print_profile . empty ())
description_line += " \n\n\t " + _ ( L ( "default print profile" )) + ": \n\t\t " + default_print_profile ;
if ( ! default_filament_profiles . empty ())
{
description_line += " \n\n\t " + _ ( L ( "default filament profile" )) + ": \n\t\t " ;
for ( auto & profile : default_filament_profiles ) {
if ( & profile != &* default_filament_profiles . begin ())
description_line += ", " ;
description_line += profile ;
}
}
break ;
}
case ptSLA :
{
//FIXME add prefered_sla_material_profile for SLA
const std :: string & default_sla_material_profile = preset . config . opt_string ( "default_sla_material_profile" );
if ( ! default_sla_material_profile . empty ())
description_line += " \n\n\t " + _ ( L ( "default SLA material profile" )) + ": \n\t\t " + default_sla_material_profile ;
2018-04-26 12:40:17 +02:00
2019-08-06 16:51:32 +02:00
const std :: string & default_sla_print_profile = preset . config . opt_string ( "default_sla_print_profile" );
if ( ! default_sla_print_profile . empty ())
description_line += " \n\n\t " + _ ( L ( "default SLA print profile" )) + ": \n\t\t " + default_sla_print_profile ;
break ;
}
2019-09-03 10:27:16 +02:00
default : break ;
2019-08-06 16:51:32 +02:00
}
}
2020-03-04 13:47:35 +01:00
else if ( ! preset . alias . empty ())
2019-11-25 15:57:36 +01:00
{
2020-03-04 13:47:35 +01:00
description_line += " \n\n\t " + _ ( L ( "full profile name" )) + ": \n\t\t " + preset . name ;
description_line += " \n\t " + _ ( L ( "symbolic profile name" )) + ": \n\t\t " + preset . alias ;
2019-11-25 15:57:36 +01:00
}
2019-08-06 16:51:32 +02:00
}
m_parent_preset_description_line -> SetText ( description_line , false );
2020-03-04 13:47:35 +01:00
if ( m_detach_preset_btn )
m_detach_preset_btn -> Show ( parent && parent -> is_system && ! preset . is_default );
Layout ();
2018-01-16 16:28:01 +01:00
}
2018-03-13 16:14:36 +01:00
void Tab :: update_frequently_changed_parameters ()
{
2019-08-06 16:51:32 +02:00
const bool is_fff = supports_printer_technology ( ptFFF );
auto og_freq_chng_params = wxGetApp (). sidebar (). og_freq_chng_params ( is_fff );
2018-10-05 23:29:15 +02:00
if ( ! og_freq_chng_params ) return ;
2019-01-15 09:31:53 +01:00
2019-08-06 16:51:32 +02:00
og_freq_chng_params -> set_value ( "support" , support_combo_value_for_config ( * m_config , is_fff ));
2019-08-08 09:48:56 +02:00
if ( ! is_fff )
2019-08-20 17:24:48 +02:00
og_freq_chng_params -> set_value ( "pad" , pad_combo_value_for_config ( * m_config ));
2018-03-13 16:14:36 +01:00
2019-03-27 16:59:34 +01:00
const std :: string updated_value_key = is_fff ? "fill_density" : "pad_enable" ;
2018-04-04 11:13:28 +02:00
2019-03-27 16:59:34 +01:00
const boost :: any val = og_freq_chng_params -> get_config_value ( * m_config , updated_value_key );
og_freq_chng_params -> set_value ( updated_value_key , val );
if ( is_fff )
{
og_freq_chng_params -> set_value ( "brim" , bool ( m_config -> opt_float ( "brim_width" ) > 0.0 ));
update_wiping_button_visibility ();
}
2018-03-13 16:14:36 +01:00
}
2018-01-05 15:11:33 +01:00
void TabPrint :: build ()
2017-12-13 14:45:10 +01:00
{
2019-08-06 16:51:32 +02:00
m_presets = & m_preset_bundle -> prints ;
load_initial_data ();
2017-12-13 14:45:10 +01:00
2020-04-13 17:55:38 +02:00
auto page = add_options_page ( L ( "Layers and perimeters" ), "layers" );
2020-10-29 21:53:33 +01:00
wxString category_path = "layers-and-perimeters_1748#" ;
2020-04-13 17:55:38 +02:00
auto optgroup = page -> new_optgroup ( L ( "Layer height" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "layer_height" , category_path + "layer-height" );
optgroup -> append_single_option_line ( "first_layer_height" , category_path + "first-layer-height" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Vertical shells" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "perimeters" , category_path + "perimeters" );
optgroup -> append_single_option_line ( "spiral_vase" , category_path + "spiral-vase" );
2017-12-14 14:42:47 +01:00
2019-08-06 16:51:32 +02:00
Line line { "" , "" };
line . full_width = 1 ;
2020-10-29 21:53:33 +01:00
line . label_path = category_path + "recommended-thin-wall-thickness" ;
2019-08-06 16:51:32 +02:00
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_recommended_thin_wall_thickness_description_line );
};
optgroup -> append_line ( line );
2018-01-15 12:13:05 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Horizontal shells" ));
line = { L ( "Solid layers" ), "" };
2020-10-29 21:53:33 +01:00
line . label_path = category_path + "solid-layers-top-bottom" ;
2019-08-06 16:51:32 +02:00
line . append_option ( optgroup -> get_option ( "top_solid_layers" ));
line . append_option ( optgroup -> get_option ( "bottom_solid_layers" ));
optgroup -> append_line ( line );
2020-04-13 17:55:38 +02:00
line = { L ( "Minimum shell thickness" ), "" };
2020-02-05 16:53:26 +01:00
line . append_option ( optgroup -> get_option ( "top_solid_min_thickness" ));
line . append_option ( optgroup -> get_option ( "bottom_solid_min_thickness" ));
optgroup -> append_line ( line );
line = { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_top_bottom_shell_thickness_explanation );
};
optgroup -> append_line ( line );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Quality (slower slicing)" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "extra_perimeters" , category_path + "extra-perimeters-if-needed" );
optgroup -> append_single_option_line ( "ensure_vertical_shell_thickness" , category_path + "ensure-vertical-shell-thickness" );
optgroup -> append_single_option_line ( "avoid_crossing_perimeters" , category_path + "avoid-crossing-perimeters" );
2020-10-16 02:25:45 +02:00
optgroup -> append_single_option_line ( "avoid_crossing_perimeters_max_detour" , category_path + "avoid_crossing_perimeters_max_detour" );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "thin_walls" , category_path + "detect-thin-walls" );
2021-03-08 13:44:00 +01:00
optgroup -> append_single_option_line ( "thick_bridges" , category_path + "thick_bridges" );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "overhangs" , category_path + "detect-bridging-perimeters" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Advanced" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "seam_position" , category_path + "seam-position" );
optgroup -> append_single_option_line ( "external_perimeters_first" , category_path + "external-perimeters-first" );
2021-02-10 07:01:40 -08:00
optgroup -> append_single_option_line ( "gap_fill_enabled" );
2017-12-13 14:45:10 +01:00
2021-01-22 17:51:26 +01:00
optgroup = page -> new_optgroup ( L ( "Fuzzy skin (experimental)" ));
2021-02-10 16:02:32 +01:00
Option option = optgroup -> get_option ( "fuzzy_skin" );
2021-03-19 11:11:46 +01:00
// option.opt.width = 30;
2021-01-22 17:51:26 +01:00
optgroup -> append_single_option_line ( option );
optgroup -> append_single_option_line ( optgroup -> get_option ( "fuzzy_skin_thickness" ));
optgroup -> append_single_option_line ( optgroup -> get_option ( "fuzzy_skin_point_dist" ));
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Infill" ), "infill" );
2020-10-29 21:53:33 +01:00
category_path = "infill_42#" ;
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Infill" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "fill_density" , category_path + "fill-density" );
optgroup -> append_single_option_line ( "fill_pattern" , category_path + "fill-pattern" );
2020-11-18 17:00:08 +01:00
optgroup -> append_single_option_line ( "infill_anchor" , category_path + "fill-pattern" );
2020-11-24 16:00:46 +01:00
optgroup -> append_single_option_line ( "infill_anchor_max" , category_path + "fill-pattern" );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "top_fill_pattern" , category_path + "top-fill-pattern" );
optgroup -> append_single_option_line ( "bottom_fill_pattern" , category_path + "bottom-fill-pattern" );
2017-12-14 14:42:47 +01:00
2020-04-29 14:56:31 +02:00
optgroup = page -> new_optgroup ( L ( "Ironing" ));
2020-04-14 11:53:28 +02:00
optgroup -> append_single_option_line ( "ironing" );
optgroup -> append_single_option_line ( "ironing_type" );
optgroup -> append_single_option_line ( "ironing_flowrate" );
optgroup -> append_single_option_line ( "ironing_spacing" );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Reducing printing time" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "infill_every_layers" , category_path + "combine-infill-every-x-layers" );
optgroup -> append_single_option_line ( "infill_only_where_needed" , category_path + "only-infill-where-needed" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Advanced" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "solid_infill_every_layers" , category_path + "solid-infill-every-x-layers" );
optgroup -> append_single_option_line ( "fill_angle" , category_path + "fill-angle" );
optgroup -> append_single_option_line ( "solid_infill_below_area" , category_path + "solid-infill-threshold-area" );
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "bridge_angle" );
optgroup -> append_single_option_line ( "only_retract_when_crossing_perimeters" );
optgroup -> append_single_option_line ( "infill_first" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Skirt and brim" ), "skirt+brim" );
2020-10-29 21:53:33 +01:00
category_path = "skirt-and-brim_133969#" ;
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Skirt" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "skirts" , category_path + "skirt" );
optgroup -> append_single_option_line ( "skirt_distance" , category_path + "skirt" );
optgroup -> append_single_option_line ( "skirt_height" , category_path + "skirt" );
optgroup -> append_single_option_line ( "draft_shield" , category_path + "skirt" );
optgroup -> append_single_option_line ( "min_skirt_length" , category_path + "skirt" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Brim" ));
2021-02-03 15:12:53 +01:00
optgroup -> append_single_option_line ( "brim_type" , category_path + "brim" );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "brim_width" , category_path + "brim" );
2021-02-03 15:12:53 +01:00
optgroup -> append_single_option_line ( "brim_offset" , category_path + "brim" );
2017-12-13 14:45:10 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Support material" ), "support" );
2020-10-29 21:53:33 +01:00
category_path = "support-material_1698#" ;
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Support material" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "support_material" , category_path + "generate-support-material" );
optgroup -> append_single_option_line ( "support_material_auto" , category_path + "auto-generated-supports" );
optgroup -> append_single_option_line ( "support_material_threshold" , category_path + "overhang-threshold" );
optgroup -> append_single_option_line ( "support_material_enforce_layers" , category_path + "enforce-support-for-the-first" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Raft" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "raft_layers" , category_path + "raft-layers" );
2021-02-24 08:48:33 +01:00
optgroup -> append_single_option_line ( "raft_first_layer_density" , category_path + "raft-first-layer-density" );
optgroup -> append_single_option_line ( "raft_first_layer_expansion" , category_path + "raft-first-layer-expansion" );
2021-02-24 09:22:31 +01:00
optgroup -> append_single_option_line ( "raft_contact_distance" );
optgroup -> append_single_option_line ( "raft_expansion" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Options for support material and raft" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "support_material_contact_distance" , category_path + "contact-z-distance" );
2021-03-10 12:14:45 +01:00
optgroup -> append_single_option_line ( "support_material_bottom_contact_distance" , category_path + "contact-z-distance" );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "support_material_pattern" , category_path + "pattern" );
optgroup -> append_single_option_line ( "support_material_with_sheath" , category_path + "with-sheath-around-the-support" );
optgroup -> append_single_option_line ( "support_material_spacing" , category_path + "pattern-spacing-0-inf" );
optgroup -> append_single_option_line ( "support_material_angle" , category_path + "pattern-angle" );
optgroup -> append_single_option_line ( "support_material_interface_layers" , category_path + "interface-layers" );
2021-03-09 15:29:13 +01:00
optgroup -> append_single_option_line ( "support_material_bottom_interface_layers" , category_path + "interface-layers" );
2021-02-24 15:59:09 +01:00
optgroup -> append_single_option_line ( "support_material_interface_pattern" , category_path + "interface-pattern" );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "support_material_interface_spacing" , category_path + "interface-pattern-spacing" );
optgroup -> append_single_option_line ( "support_material_interface_contact_loops" , category_path + "interface-loops" );
optgroup -> append_single_option_line ( "support_material_buildplate_only" , category_path + "support-on-build-plate-only" );
optgroup -> append_single_option_line ( "support_material_xy_spacing" , category_path + "xy-separation-between-an-object-and-its-support" );
optgroup -> append_single_option_line ( "dont_support_bridges" , category_path + "dont-support-bridges" );
optgroup -> append_single_option_line ( "support_material_synchronize_layers" , category_path + "synchronize-with-object-layers" );
2017-12-13 14:45:10 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Speed" ), "time" );
optgroup = page -> new_optgroup ( L ( "Speed for print moves" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "perimeter_speed" );
optgroup -> append_single_option_line ( "small_perimeter_speed" );
optgroup -> append_single_option_line ( "external_perimeter_speed" );
optgroup -> append_single_option_line ( "infill_speed" );
optgroup -> append_single_option_line ( "solid_infill_speed" );
optgroup -> append_single_option_line ( "top_solid_infill_speed" );
optgroup -> append_single_option_line ( "support_material_speed" );
optgroup -> append_single_option_line ( "support_material_interface_speed" );
optgroup -> append_single_option_line ( "bridge_speed" );
optgroup -> append_single_option_line ( "gap_fill_speed" );
2020-04-14 11:53:28 +02:00
optgroup -> append_single_option_line ( "ironing_speed" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Speed for non-print moves" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "travel_speed" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Modifiers" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "first_layer_speed" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Acceleration control (advanced)" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "perimeter_acceleration" );
optgroup -> append_single_option_line ( "infill_acceleration" );
optgroup -> append_single_option_line ( "bridge_acceleration" );
optgroup -> append_single_option_line ( "first_layer_acceleration" );
optgroup -> append_single_option_line ( "default_acceleration" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Autospeed (advanced)" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "max_print_speed" , "max-volumetric-speed_127176" );
optgroup -> append_single_option_line ( "max_volumetric_speed" , "max-volumetric-speed_127176" );
2019-01-29 18:07:45 +01:00
#ifdef HAS_PRESSURE_EQUALIZER
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "max_volumetric_extrusion_rate_slope_positive" );
optgroup -> append_single_option_line ( "max_volumetric_extrusion_rate_slope_negative" );
2019-01-29 18:07:45 +01:00
#endif /* HAS_PRESSURE_EQUALIZER */
2017-12-13 14:45:10 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Multiple Extruders" ), "funnel" );
optgroup = page -> new_optgroup ( L ( "Extruders" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "perimeter_extruder" );
optgroup -> append_single_option_line ( "infill_extruder" );
optgroup -> append_single_option_line ( "solid_infill_extruder" );
optgroup -> append_single_option_line ( "support_material_extruder" );
optgroup -> append_single_option_line ( "support_material_interface_extruder" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Ooze prevention" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "ooze_prevention" );
optgroup -> append_single_option_line ( "standby_temperature_delta" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Wipe tower" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "wipe_tower" );
optgroup -> append_single_option_line ( "wipe_tower_x" );
optgroup -> append_single_option_line ( "wipe_tower_y" );
optgroup -> append_single_option_line ( "wipe_tower_width" );
optgroup -> append_single_option_line ( "wipe_tower_rotation_angle" );
2021-03-04 11:18:50 +01:00
optgroup -> append_single_option_line ( "wipe_tower_brim_width" );
2018-03-12 15:41:25 +01:00
optgroup -> append_single_option_line ( "wipe_tower_bridging" );
2019-09-19 16:30:01 +02:00
optgroup -> append_single_option_line ( "wipe_tower_no_sparse_layers" );
2018-07-27 22:19:46 +02:00
optgroup -> append_single_option_line ( "single_extruder_multi_material_priming" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Advanced" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "interface_shells" );
2017-12-13 14:45:10 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Advanced" ), "wrench" );
optgroup = page -> new_optgroup ( L ( "Extrusion width" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "extrusion_width" );
optgroup -> append_single_option_line ( "first_layer_extrusion_width" );
optgroup -> append_single_option_line ( "perimeter_extrusion_width" );
optgroup -> append_single_option_line ( "external_perimeter_extrusion_width" );
optgroup -> append_single_option_line ( "infill_extrusion_width" );
optgroup -> append_single_option_line ( "solid_infill_extrusion_width" );
optgroup -> append_single_option_line ( "top_infill_extrusion_width" );
optgroup -> append_single_option_line ( "support_material_extrusion_width" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Overlap" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "infill_overlap" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Flow" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "bridge_flow_ratio" );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Slicing" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "slice_closing_radius" );
optgroup -> append_single_option_line ( "resolution" );
optgroup -> append_single_option_line ( "xy_size_compensation" );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "elefant_foot_compensation" , "elephant-foot-compensation_114487" );
2019-03-01 17:53:02 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Other" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "clip_multipart_objects" );
2017-12-13 14:45:10 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Output options" ), "output+page_white" );
optgroup = page -> new_optgroup ( L ( "Sequential printing" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "complete_objects" , "sequential-printing_124589" );
2020-12-04 13:08:20 +01:00
line = { L ( "Extruder clearance" ), "" };
2020-02-12 12:08:43 +01:00
line . append_option ( optgroup -> get_option ( "extruder_clearance_radius" ));
line . append_option ( optgroup -> get_option ( "extruder_clearance_height" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_line ( line );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Output file" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "gcode_comments" );
optgroup -> append_single_option_line ( "gcode_label_objects" );
2021-01-22 17:51:26 +01:00
option = optgroup -> get_option ( "output_filename_format" );
2019-08-06 16:51:32 +02:00
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2017-12-14 14:42:47 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Post-processing scripts" ), 0 );
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "post_process" );
option . opt . full_width = true ;
2019-04-13 23:46:52 +02:00
option . opt . height = 5 ; //50;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-13 14:45:10 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Notes" ), "note.png" );
optgroup = page -> new_optgroup ( L ( "Notes" ), 0 );
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "notes" );
option . opt . full_width = true ;
2019-04-13 23:46:52 +02:00
option . opt . height = 25 ; //250;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-13 14:45:10 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Dependencies" ), "wrench.png" );
optgroup = page -> new_optgroup ( L ( "Profile dependencies" ));
2020-03-04 20:58:14 +01:00
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "compatible_printers" , wxEmptyString , [ this ]( wxWindow * parent ) {
2019-08-06 16:51:32 +02:00
return compatible_widget_create ( parent , m_compatible_printers );
2020-03-04 20:58:14 +01:00
});
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "compatible_printers_condition" );
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2018-03-22 11:46:15 +01:00
2020-03-04 13:47:35 +01:00
build_preset_description_line ( optgroup . get ());
2017-12-13 14:45:10 +01:00
}
2018-01-12 12:41:13 +01:00
// Reload current config (aka presets->edited_preset->config) into the UI fields.
2018-10-31 12:56:08 +01:00
void TabPrint :: reload_config ()
{
2019-08-06 16:51:32 +02:00
this -> compatible_widget_reload ( m_compatible_printers );
Tab :: reload_config ();
2018-01-12 12:41:13 +01:00
}
2020-09-22 11:17:43 +02:00
void TabPrint :: update_description_lines ()
{
Tab :: update_description_lines ();
if ( m_preset_bundle -> printers . get_selected_preset (). printer_technology () == ptSLA )
return ;
if ( m_active_page && m_active_page -> title () == "Layers and perimeters" &&
m_recommended_thin_wall_thickness_description_line && m_top_bottom_shell_thickness_explanation )
{
m_recommended_thin_wall_thickness_description_line -> SetText (
from_u8 ( PresetHints :: recommended_thin_wall_thickness ( * m_preset_bundle )));
m_top_bottom_shell_thickness_explanation -> SetText (
from_u8 ( PresetHints :: top_bottom_shell_thickness_explanation ( * m_preset_bundle )));
}
}
void TabPrint :: toggle_options ()
{
if ( ! m_active_page ) return ;
m_config_manipulation . toggle_print_fff_options ( m_config );
}
2018-01-05 15:11:33 +01:00
void TabPrint :: update ()
{
2018-10-04 16:43:10 +02:00
if ( m_preset_bundle -> printers . get_selected_preset (). printer_technology () == ptSLA )
2018-08-06 17:01:41 +02:00
return ; // ys_FIXME
2019-02-22 09:38:56 +01:00
m_update_cnt ++ ;
2018-01-05 15:11:33 +01:00
2019-08-22 13:19:01 +02:00
m_config_manipulation . update_print_fff_config ( m_config , true );
2018-01-05 15:11:33 +01:00
2020-09-22 11:17:43 +02:00
update_description_lines ();
2019-05-11 23:29:25 +02:00
Layout ();
2018-01-15 12:13:05 +01:00
2019-02-22 09:38:56 +01:00
m_update_cnt -- ;
2019-08-22 13:19:01 +02:00
if ( m_update_cnt == 0 ) {
2020-09-22 11:17:43 +02:00
toggle_options ();
2019-08-22 14:21:50 +02:00
2020-03-20 13:41:36 +01:00
// update() could be called during undo/redo execution
// Update of objectList can cause a crash in this case (because m_objects doesn't match ObjectList)
if ( ! wxGetApp (). plater () -> inside_snapshot_capture ())
wxGetApp (). obj_list () -> update_and_show_object_settings_item ();
2019-08-22 14:21:50 +02:00
2019-02-22 09:38:56 +01:00
wxGetApp (). mainframe -> on_config_changed ( m_config );
2019-08-22 13:19:01 +02:00
}
2018-01-05 15:11:33 +01:00
}
2020-09-22 11:17:43 +02:00
void TabPrint :: clear_pages ()
2018-01-15 12:13:05 +01:00
{
2020-09-22 11:17:43 +02:00
Tab :: clear_pages ();
m_recommended_thin_wall_thickness_description_line = nullptr ;
m_top_bottom_shell_thickness_explanation = nullptr ;
2018-01-15 12:13:05 +01:00
}
2021-02-22 08:39:36 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
2021-02-24 15:50:18 +01:00
bool Tab :: validate_custom_gcode ( const wxString & title , const std :: string & gcode )
2021-02-22 08:39:36 +01:00
{
std :: vector < std :: string > tags ;
bool invalid = GCodeProcessor :: contains_reserved_tags ( gcode , 5 , tags );
2021-02-24 15:50:18 +01:00
if ( invalid ) {
2021-02-22 08:39:36 +01:00
wxString reports = _L_PLURAL ( "The following line" , "The following lines" , tags . size ());
reports += ": \n " ;
for ( const std :: string & keyword : tags ) {
reports += ";" + keyword + " \n " ;
}
reports += _L ( "contain reserved keywords." ) + " \n " ;
reports += _L ( "Please remove them, as they may cause problems in g-code visualization and printing time estimation." );
2021-02-24 15:50:18 +01:00
wxMessageDialog dialog ( wxGetApp (). mainframe , reports , _L ( "Found reserved keywords in" ) + " " + _ ( title ), wxICON_WARNING | wxOK );
2021-02-22 08:39:36 +01:00
dialog . ShowModal ();
}
return ! invalid ;
}
2021-02-24 15:50:18 +01:00
2021-02-26 13:56:51 +01:00
static void validate_custom_gcode_cb ( Tab * tab , ConfigOptionsGroupShp opt_group , const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-24 15:50:18 +01:00
Tab :: validate_custom_gcode ( opt_group -> title , boost :: any_cast < std :: string > ( value ));
tab -> update_dirty ();
2021-02-26 13:56:51 +01:00
tab -> on_value_change ( opt_key , value );
2021-02-24 15:50:18 +01:00
}
2021-02-22 08:39:36 +01:00
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2019-07-28 22:00:39 +02:00
void TabFilament :: add_filament_overrides_page ()
{
2020-04-13 17:55:38 +02:00
PageShp page = add_options_page ( L ( "Filament Overrides" ), "wrench" );
ConfigOptionsGroupShp optgroup = page -> new_optgroup ( L ( "Retraction" ));
2019-07-03 14:52:39 +02:00
2019-07-28 22:00:39 +02:00
auto append_single_option_line = [ optgroup , this ]( const std :: string & opt_key , int opt_index )
2019-07-03 14:52:39 +02:00
{
2019-07-29 14:00:22 +02:00
Line line { "" , "" };
if ( opt_key == "filament_retract_lift_above" || opt_key == "filament_retract_lift_below" ) {
Option opt = optgroup -> get_option ( opt_key );
opt . opt . label = opt . opt . full_label ;
line = optgroup -> create_single_option_line ( opt );
}
else
line = optgroup -> create_single_option_line ( optgroup -> get_option ( opt_key ));
2019-07-03 14:52:39 +02:00
2019-07-28 22:00:39 +02:00
line . near_label_widget = [ this , optgroup , opt_key , opt_index ]( wxWindow * parent ) {
2019-07-03 14:52:39 +02:00
wxCheckBox * check_box = new wxCheckBox ( parent , wxID_ANY , "" );
2021-01-29 16:16:23 +01:00
check_box -> Bind ( wxEVT_CHECKBOX , [ optgroup , opt_key , opt_index ]( wxCommandEvent & evt ) {
2019-07-29 14:00:22 +02:00
const bool is_checked = evt . IsChecked ();
Field * field = optgroup -> get_fieldc ( opt_key , opt_index );
if ( field != nullptr ) {
field -> toggle ( is_checked );
if ( is_checked )
field -> set_last_meaningful_value ();
else
field -> set_na_value ();
}
2019-07-28 22:00:39 +02:00
}, check_box -> GetId ());
m_overrides_options [ opt_key ] = check_box ;
2019-07-03 14:52:39 +02:00
return check_box ;
};
optgroup -> append_line ( line );
};
2019-07-29 14:00:22 +02:00
const int extruder_idx = 0 ; // #ys_FIXME
2019-07-03 14:52:39 +02:00
2019-07-29 14:00:22 +02:00
for ( const std :: string opt_key : { "filament_retract_length" ,
"filament_retract_lift" ,
"filament_retract_lift_above" ,
"filament_retract_lift_below" ,
"filament_retract_speed" ,
"filament_deretract_speed" ,
"filament_retract_restart_extra" ,
"filament_retract_before_travel" ,
"filament_retract_layer_change" ,
"filament_wipe" ,
"filament_retract_before_wipe"
})
append_single_option_line ( opt_key , extruder_idx );
2019-07-28 22:00:39 +02:00
}
2019-07-03 14:52:39 +02:00
2019-07-28 22:00:39 +02:00
void TabFilament :: update_filament_overrides_page ()
{
2020-09-22 11:17:43 +02:00
if ( ! m_active_page || m_active_page -> title () != "Filament Overrides" )
2019-07-28 22:00:39 +02:00
return ;
2020-09-22 11:17:43 +02:00
Page * page = m_active_page ;
2019-07-28 22:00:39 +02:00
2020-04-13 17:55:38 +02:00
const auto og_it = std :: find_if ( page -> m_optgroups . begin (), page -> m_optgroups . end (), []( const ConfigOptionsGroupShp og ) { return og -> title == "Retraction" ; });
2019-07-28 22:00:39 +02:00
if ( og_it == page -> m_optgroups . end ())
return ;
ConfigOptionsGroupShp optgroup = * og_it ;
2019-08-06 16:51:32 +02:00
std :: vector < std :: string > opt_keys = { "filament_retract_length" ,
"filament_retract_lift" ,
"filament_retract_lift_above" ,
2019-07-29 14:00:22 +02:00
"filament_retract_lift_below" ,
2019-07-28 22:00:39 +02:00
"filament_retract_speed" ,
"filament_deretract_speed" ,
"filament_retract_restart_extra" ,
"filament_retract_before_travel" ,
"filament_retract_layer_change" ,
"filament_wipe" ,
"filament_retract_before_wipe"
};
2019-07-29 14:00:22 +02:00
const int extruder_idx = 0 ; // #ys_FIXME
2019-07-30 12:06:51 +02:00
const bool have_retract_length = m_config -> option ( "filament_retract_length" ) -> is_nil () ||
2019-07-29 14:00:22 +02:00
m_config -> opt_float ( "filament_retract_length" , extruder_idx ) > 0 ;
2019-07-28 22:00:39 +02:00
for ( const std :: string & opt_key : opt_keys )
{
2019-07-29 14:00:22 +02:00
bool is_checked = opt_key == "filament_retract_length" ? true : have_retract_length ;
2019-07-29 16:08:36 +02:00
m_overrides_options [ opt_key ] -> Enable ( is_checked );
is_checked &= ! m_config -> option ( opt_key ) -> is_nil ();
m_overrides_options [ opt_key ] -> SetValue ( is_checked );
2019-07-28 22:00:39 +02:00
Field * field = optgroup -> get_fieldc ( opt_key , extruder_idx );
2019-07-29 16:08:36 +02:00
if ( field != nullptr )
2019-07-28 22:00:39 +02:00
field -> toggle ( is_checked );
}
2019-07-03 14:52:39 +02:00
}
2018-01-05 15:11:33 +01:00
void TabFilament :: build ()
2017-12-22 11:50:28 +01:00
{
2019-08-06 16:51:32 +02:00
m_presets = & m_preset_bundle -> filaments ;
load_initial_data ();
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
auto page = add_options_page ( L ( "Filament" ), "spool.png" );
auto optgroup = page -> new_optgroup ( L ( "Filament" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "filament_colour" );
optgroup -> append_single_option_line ( "filament_diameter" );
optgroup -> append_single_option_line ( "extrusion_multiplier" );
optgroup -> append_single_option_line ( "filament_density" );
optgroup -> append_single_option_line ( "filament_cost" );
2020-11-20 14:30:48 +01:00
optgroup -> append_single_option_line ( "filament_spool_weight" );
optgroup -> m_on_change = [ this , optgroup ]( t_config_option_key opt_key , boost :: any value )
{
update_dirty ();
if ( opt_key == "filament_spool_weight" ) {
// Change of this option influences for an update of "Sliced Info"
wxGetApp (). sidebar (). update_sliced_info_sizer ();
wxGetApp (). sidebar (). Layout ();
}
else
on_value_change ( opt_key , value );
};
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Temperature" ));
2020-11-06 11:47:28 +01:00
Line line = { L ( "Nozzle" ), "" };
2019-08-06 16:51:32 +02:00
line . append_option ( optgroup -> get_option ( "first_layer_temperature" ));
line . append_option ( optgroup -> get_option ( "temperature" ));
optgroup -> append_line ( line );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
line = { L ( "Bed" ), "" };
2019-08-06 16:51:32 +02:00
line . append_option ( optgroup -> get_option ( "first_layer_bed_temperature" ));
line . append_option ( optgroup -> get_option ( "bed_temperature" ));
optgroup -> append_line ( line );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Cooling" ), "cooling" );
2020-10-29 21:53:33 +01:00
wxString category_path = "cooling_127569#" ;
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Enable" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "fan_always_on" );
optgroup -> append_single_option_line ( "cooling" );
2017-12-22 11:50:28 +01:00
2019-08-06 16:51:32 +02:00
line = { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_cooling_description_line );
};
optgroup -> append_line ( line );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Fan settings" ));
line = { L ( "Fan speed" ), "" };
2020-10-29 21:53:33 +01:00
line . label_path = category_path + "fan-settings" ;
2019-08-06 16:51:32 +02:00
line . append_option ( optgroup -> get_option ( "min_fan_speed" ));
line . append_option ( optgroup -> get_option ( "max_fan_speed" ));
optgroup -> append_line ( line );
2017-12-22 11:50:28 +01:00
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "bridge_fan_speed" , category_path + "fan-settings" );
optgroup -> append_single_option_line ( "disable_fan_first_layers" , category_path + "fan-settings" );
2020-12-04 11:53:02 +01:00
optgroup -> append_single_option_line ( "full_fan_speed_layer" , category_path + "fan-settings" );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Cooling thresholds" ), 25 );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "fan_below_layer_time" , category_path + "cooling-thresholds" );
optgroup -> append_single_option_line ( "slowdown_below_layer_time" , category_path + "cooling-thresholds" );
optgroup -> append_single_option_line ( "min_print_speed" , category_path + "cooling-thresholds" );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Advanced" ), "wrench" );
optgroup = page -> new_optgroup ( L ( "Filament properties" ));
2020-02-12 12:08:43 +01:00
// Set size as all another fields for a better alignment
Option option = optgroup -> get_option ( "filament_type" );
option . opt . width = Field :: def_width ();
optgroup -> append_single_option_line ( option );
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "filament_soluble" );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Print speed override" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "filament_max_volumetric_speed" , "max-volumetric-speed_127176" );
2017-12-22 11:50:28 +01:00
2019-08-06 16:51:32 +02:00
line = { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_volumetric_speed_description_line );
};
optgroup -> append_line ( line );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Wipe tower parameters" ));
2019-05-03 00:17:24 -04:00
optgroup -> append_single_option_line ( "filament_minimal_purge_on_wipe_tower" );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Toolchange parameters with single extruder MM printers" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "filament_loading_speed_start" );
2018-08-21 14:36:24 +02:00
optgroup -> append_single_option_line ( "filament_loading_speed" );
2018-08-14 16:23:23 +02:00
optgroup -> append_single_option_line ( "filament_unloading_speed_start" );
2018-03-02 15:52:16 +01:00
optgroup -> append_single_option_line ( "filament_unloading_speed" );
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "filament_load_time" );
optgroup -> append_single_option_line ( "filament_unload_time" );
2018-03-02 15:52:16 +01:00
optgroup -> append_single_option_line ( "filament_toolchange_delay" );
2018-04-24 13:02:08 +02:00
optgroup -> append_single_option_line ( "filament_cooling_moves" );
optgroup -> append_single_option_line ( "filament_cooling_initial_speed" );
optgroup -> append_single_option_line ( "filament_cooling_final_speed" );
2018-04-24 13:10:33 +02:00
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "filament_ramming_parameters" , wxEmptyString , [ this ]( wxWindow * parent ) {
2019-08-06 16:51:32 +02:00
auto ramming_dialog_btn = new wxButton ( parent , wxID_ANY , _ ( L ( "Ramming settings" )) + dots , wxDefaultPosition , wxDefaultSize , wxBU_EXACTFIT );
ramming_dialog_btn -> SetFont ( Slic3r :: GUI :: wxGetApp (). normal_font ());
2020-10-29 21:53:33 +01:00
ramming_dialog_btn -> SetSize ( ramming_dialog_btn -> GetBestSize ());
2018-03-13 15:54:29 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
2019-08-06 16:51:32 +02:00
sizer -> Add ( ramming_dialog_btn );
2020-08-17 15:13:18 +02:00
ramming_dialog_btn -> Bind ( wxEVT_BUTTON , [ this ]( wxCommandEvent & e ) {
2018-03-15 14:04:12 +01:00
RammingDialog dlg ( this ,( m_config -> option < ConfigOptionStrings > ( "filament_ramming_parameters" )) -> get_at ( 0 ));
2020-08-17 15:13:18 +02:00
if ( dlg . ShowModal () == wxID_OK ) {
load_key_value ( "filament_ramming_parameters" , dlg . get_parameters ());
update_changed_ui ();
}
});
2019-08-06 16:51:32 +02:00
return sizer ;
2020-08-17 15:13:18 +02:00
});
2018-03-12 15:41:25 +01:00
2019-07-03 14:52:39 +02:00
2019-07-28 22:00:39 +02:00
add_filament_overrides_page ();
2019-07-03 14:52:39 +02:00
2019-04-13 23:46:52 +02:00
const int gcode_field_height = 15 ; // 150
const int notes_field_height = 25 ; // 250
2018-03-02 15:52:16 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Custom G-code" ), "cog" );
optgroup = page -> new_optgroup ( L ( "Start G-code" ), 0 );
2021-02-22 08:39:36 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:39:36 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2020-02-12 12:08:43 +01:00
option = optgroup -> get_option ( "start_filament_gcode" );
2019-08-06 16:51:32 +02:00
option . opt . full_width = true ;
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = gcode_field_height ; // 150;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "End G-code" ), 0 );
2021-02-22 08:39:36 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:39:36 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "end_filament_gcode" );
option . opt . full_width = true ;
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2019-08-06 16:51:32 +02:00
option . opt . height = gcode_field_height ; // 150;
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Notes" ), "note.png" );
optgroup = page -> new_optgroup ( L ( "Notes" ), 0 );
2019-08-06 16:51:32 +02:00
optgroup -> label_width = 0 ;
option = optgroup -> get_option ( "filament_notes" );
option . opt . full_width = true ;
option . opt . height = notes_field_height ; // 250;
optgroup -> append_single_option_line ( option );
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Dependencies" ), "wrench.png" );
optgroup = page -> new_optgroup ( L ( "Profile dependencies" ));
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "compatible_printers" , wxEmptyString , [ this ]( wxWindow * parent ) {
2019-08-06 16:51:32 +02:00
return compatible_widget_create ( parent , m_compatible_printers );
2020-03-04 20:58:14 +01:00
});
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "compatible_printers_condition" );
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2018-03-22 11:46:15 +01:00
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "compatible_prints" , wxEmptyString , [ this ]( wxWindow * parent ) {
2019-08-06 16:51:32 +02:00
return compatible_widget_create ( parent , m_compatible_prints );
2020-03-04 20:58:14 +01:00
});
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "compatible_prints_condition" );
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2018-12-04 17:56:49 +01:00
2020-03-04 13:47:35 +01:00
build_preset_description_line ( optgroup . get ());
2018-01-12 12:41:13 +01:00
}
// Reload current config (aka presets->edited_preset->config) into the UI fields.
2018-10-31 12:56:08 +01:00
void TabFilament :: reload_config ()
{
2019-08-06 16:51:32 +02:00
this -> compatible_widget_reload ( m_compatible_printers );
this -> compatible_widget_reload ( m_compatible_prints );
Tab :: reload_config ();
2018-01-12 12:41:13 +01:00
}
2019-08-06 15:11:46 +02:00
void TabFilament :: update_volumetric_flow_preset_hints ()
{
2019-08-20 17:24:48 +02:00
wxString text ;
try {
text = from_u8 ( PresetHints :: maximum_volumetric_flow_description ( * m_preset_bundle ));
} catch ( std :: exception & ex ) {
2019-08-28 15:12:55 +02:00
text = _ ( L ( "Volumetric flow hints not available" )) + " \n\n " + from_u8 ( ex . what ());
2019-08-20 17:24:48 +02:00
}
m_volumetric_speed_description_line -> SetText ( text );
2019-08-06 15:11:46 +02:00
}
2020-09-22 11:17:43 +02:00
void TabFilament :: update_description_lines ()
{
Tab :: update_description_lines ();
if ( ! m_active_page )
return ;
if ( m_active_page -> title () == "Cooling" && m_cooling_description_line )
m_cooling_description_line -> SetText ( from_u8 ( PresetHints :: cooling_description ( m_presets -> get_edited_preset ())));
if ( m_active_page -> title () == "Advanced" && m_volumetric_speed_description_line )
this -> update_volumetric_flow_preset_hints ();
}
void TabFilament :: toggle_options ()
{
if ( ! m_active_page )
return ;
if ( m_active_page -> title () == "Cooling" )
{
bool cooling = m_config -> opt_bool ( "cooling" , 0 );
bool fan_always_on = cooling || m_config -> opt_bool ( "fan_always_on" , 0 );
for ( auto el : { "max_fan_speed" , "fan_below_layer_time" , "slowdown_below_layer_time" , "min_print_speed" })
toggle_option ( el , cooling );
2020-12-04 11:53:02 +01:00
for ( auto el : { "min_fan_speed" , "disable_fan_first_layers" , "full_fan_speed_layer" })
2020-09-22 11:17:43 +02:00
toggle_option ( el , fan_always_on );
}
if ( m_active_page -> title () == "Filament Overrides" )
update_filament_overrides_page ();
}
2018-01-12 12:41:13 +01:00
void TabFilament :: update ()
{
2018-10-04 16:43:10 +02:00
if ( m_preset_bundle -> printers . get_selected_preset (). printer_technology () == ptSLA )
2018-08-06 17:01:41 +02:00
return ; // ys_FIXME
2019-02-22 09:38:56 +01:00
m_update_cnt ++ ;
2019-07-28 22:00:39 +02:00
2020-09-22 11:17:43 +02:00
update_description_lines ();
2019-05-11 23:29:25 +02:00
Layout ();
2018-01-12 12:41:13 +01:00
2020-09-22 11:17:43 +02:00
toggle_options ();
2019-07-28 22:00:39 +02:00
2019-02-22 09:38:56 +01:00
m_update_cnt -- ;
if ( m_update_cnt == 0 )
wxGetApp (). mainframe -> on_config_changed ( m_config );
2018-01-12 12:41:13 +01:00
}
2020-09-22 11:17:43 +02:00
void TabFilament :: clear_pages ()
2018-01-12 12:41:13 +01:00
{
2020-09-22 11:17:43 +02:00
Tab :: clear_pages ();
m_volumetric_speed_description_line = nullptr ;
m_cooling_description_line = nullptr ;
2017-12-22 11:50:28 +01:00
}
2020-10-16 16:30:46 +02:00
wxSizer * Tab :: description_line_widget ( wxWindow * parent , ogStaticText * * StaticText , wxString text /*= wxEmptyString*/ )
2017-12-22 11:50:28 +01:00
{
2020-10-16 16:30:46 +02:00
* StaticText = new ogStaticText ( parent , text );
2018-01-15 12:13:05 +01:00
2019-04-13 23:46:52 +02:00
// auto font = (new wxSystemSettings)->GetFont(wxSYS_DEFAULT_GUI_FONT);
2019-08-06 16:51:32 +02:00
( * StaticText ) -> SetFont ( wxGetApp (). normal_font ());
2017-12-22 11:50:28 +01:00
2019-08-06 16:51:32 +02:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( * StaticText , 1 , wxEXPAND | wxALL , 0 );
return sizer ;
2017-12-22 11:50:28 +01:00
}
2018-01-25 13:46:04 +01:00
bool Tab :: current_preset_is_dirty ()
{
2019-08-06 16:51:32 +02:00
return m_presets -> current_is_dirty ();
2018-01-25 13:46:04 +01:00
}
2018-12-18 14:34:16 +01:00
2018-01-05 15:11:33 +01:00
void TabPrinter :: build ()
2017-12-22 11:50:28 +01:00
{
2019-08-06 16:51:32 +02:00
m_presets = & m_preset_bundle -> printers ;
2018-08-07 11:58:27 +02:00
m_printer_technology = m_presets -> get_selected_preset (). printer_technology ();
2018-08-06 17:01:41 +02:00
2021-02-04 09:42:32 +01:00
// For DiffPresetDialog we use options list which is saved in Searcher class.
// Options for the Searcher is added in the moment of pages creation.
// So, build first of all printer pages for non-selected printer technology...
std :: string def_preset_name = "- default " + std :: string ( m_printer_technology == ptSLA ? "FFF" : "SLA" ) + " -" ;
m_config = & m_presets -> find_preset ( def_preset_name ) -> config ;
m_printer_technology == ptSLA ? build_fff () : build_sla ();
2021-02-08 16:15:11 +01:00
if ( m_printer_technology == ptSLA )
m_extruders_count_old = 0 ; // revert this value
2021-02-04 09:42:32 +01:00
// ... and than for selected printer technology
load_initial_data ();
m_printer_technology == ptSLA ? build_sla () : build_fff ();
2018-08-07 11:58:27 +02:00
}
2018-08-03 14:34:52 +02:00
2020-10-16 16:30:46 +02:00
void TabPrinter :: build_print_host_upload_group ( Page * page )
{
ConfigOptionsGroupShp optgroup = page -> new_optgroup ( L ( "Print Host upload" ));
wxString description_line_text = _L ( ""
"Note: All parameters from this group are moved to the Physical Printer settings (see changelog). \n\n "
"A new Physical Printer profile is created by clicking on the \" cog \" icon right of the Printer profiles combo box, "
2020-11-05 22:17:49 +01:00
"by selecting the \" Add physical printer \" item in the Printer combo box. The Physical Printer profile editor opens "
2020-10-16 16:30:46 +02:00
"also when clicking on the \" cog \" icon in the Printer settings tab. The Physical Printer profiles are being stored "
"into PrusaSlicer/physical_printer directory." );
Line line = { "" , "" };
line . full_width = 1 ;
line . widget = [ this , description_line_text ]( wxWindow * parent ) {
return description_line_widget ( parent , m_presets -> get_selected_preset (). printer_technology () == ptFFF ?
& m_fff_print_host_upload_description_line : & m_sla_print_host_upload_description_line ,
description_line_text );
};
optgroup -> append_line ( line );
}
2018-08-07 11:58:27 +02:00
void TabPrinter :: build_fff ()
{
if ( ! m_pages . empty ())
m_pages . resize ( 0 );
2019-08-06 16:51:32 +02:00
// to avoid redundant memory allocation / deallocation during extruders count changing
m_pages . reserve ( 30 );
2018-04-23 11:52:03 +02:00
2019-08-06 16:51:32 +02:00
auto * nozzle_diameter = dynamic_cast < const ConfigOptionFloats *> ( m_config -> option ( "nozzle_diameter" ));
m_initial_extruders_count = m_extruders_count = nozzle_diameter -> values . size ();
2019-04-22 01:51:10 +02:00
wxGetApp (). sidebar (). update_objects_list_extruder_column ( m_initial_extruders_count );
2021-02-04 09:42:32 +01:00
const Preset * parent_preset = m_printer_technology == ptSLA ? nullptr // just for first build, if SLA printer preset is selected
: m_presets -> get_selected_preset_parent ();
2019-08-06 16:51:32 +02:00
m_sys_extruders_count = parent_preset == nullptr ? 0 :
static_cast < const ConfigOptionFloats *> ( parent_preset -> config . option ( "nozzle_diameter" )) -> values . size ();
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
auto page = add_options_page ( L ( "General" ), "printer" );
auto optgroup = page -> new_optgroup ( L ( "Size and coordinates" ));
2017-12-22 11:50:28 +01:00
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "bed_shape" , "custom-svg-and-png-bed-textures_124612" , [ this ]( wxWindow * parent ) {
2020-03-04 20:58:14 +01:00
return create_bed_shape_widget ( parent );
});
2017-12-26 23:04:54 +01:00
2018-03-09 10:40:42 +01:00
optgroup -> append_single_option_line ( "max_print_height" );
optgroup -> append_single_option_line ( "z_offset" );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Capabilities" ));
2019-08-06 16:51:32 +02:00
ConfigOptionDef def ;
def . type = coInt ,
def . set_default_value ( new ConfigOptionInt ( 1 ));
def . label = L ( "Extruders" );
def . tooltip = L ( "Number of extruders of the printer." );
def . min = 1 ;
2018-10-19 13:55:29 +02:00
def . mode = comExpert ;
2019-08-06 16:51:32 +02:00
Option option ( def , "extruders_count" );
optgroup -> append_single_option_line ( option );
optgroup -> append_single_option_line ( "single_extruder_multi_material" );
2017-12-22 11:50:28 +01:00
2019-08-06 16:51:32 +02:00
optgroup -> m_on_change = [ this , optgroup ]( t_config_option_key opt_key , boost :: any value ) {
2019-10-01 14:27:29 +02:00
// optgroup->get_value() return int for def.type == coInt,
// Thus, there should be boost::any_cast<int> !
// Otherwise, boost::any_cast<size_t> causes an "unhandled unknown exception"
size_t extruders_count = size_t ( boost :: any_cast < int > ( optgroup -> get_value ( "extruders_count" )));
2019-08-06 16:51:32 +02:00
wxTheApp -> CallAfter ([ this , opt_key , value , extruders_count ]() {
if ( opt_key == "extruders_count" || opt_key == "single_extruder_multi_material" ) {
extruders_count_changed ( extruders_count );
2018-12-21 12:58:03 +01:00
init_options_list (); // m_options_list should be updated before UI updating
2019-08-06 16:51:32 +02:00
update_dirty ();
2019-07-23 16:12:29 +02:00
if ( opt_key == "single_extruder_multi_material" ) { // the single_extruder_multimaterial was added to force pages
2018-04-05 10:44:31 +02:00
on_value_change ( opt_key , value ); // rebuild - let's make sure the on_value_change is not skipped
2019-07-23 16:12:29 +02:00
if ( boost :: any_cast < bool > ( value ) && m_extruders_count > 1 ) {
SuppressBackgroundProcessingUpdate sbpu ;
std :: vector < double > nozzle_diameters = static_cast < const ConfigOptionFloats *> ( m_config -> option ( "nozzle_diameter" )) -> values ;
const double frst_diam = nozzle_diameters [ 0 ];
for ( auto cur_diam : nozzle_diameters ) {
// if value is differs from first nozzle diameter value
if ( fabs ( cur_diam - frst_diam ) > EPSILON ) {
const wxString msg_text = _ ( L ( "Single Extruder Multi Material is selected, \n "
"and all extruders must have the same diameter. \n "
"Do you want to change the diameter for all extruders to first extruder nozzle diameter value?" ));
2019-08-15 12:52:56 +02:00
wxMessageDialog dialog ( parent (), msg_text , _ ( L ( "Nozzle diameter" )), wxICON_WARNING | wxYES_NO );
2019-08-06 16:51:32 +02:00
2019-08-15 10:35:50 +02:00
DynamicPrintConfig new_conf = * m_config ;
2019-08-15 12:52:56 +02:00
if ( dialog . ShowModal () == wxID_YES ) {
2019-07-23 16:12:29 +02:00
for ( size_t i = 1 ; i < nozzle_diameters . size (); i ++ )
nozzle_diameters [ i ] = frst_diam ;
new_conf . set_key_value ( "nozzle_diameter" , new ConfigOptionFloats ( nozzle_diameters ));
}
2019-08-15 10:35:50 +02:00
else
new_conf . set_key_value ( "single_extruder_multi_material" , new ConfigOptionBool ( false ));
load_config ( new_conf );
2019-07-23 16:12:29 +02:00
break ;
}
2019-08-06 16:51:32 +02:00
}
2019-07-23 16:12:29 +02:00
}
}
2019-08-06 16:51:32 +02:00
}
else {
update_dirty ();
on_value_change ( opt_key , value );
}
});
};
2017-12-22 11:50:28 +01:00
2020-10-16 16:30:46 +02:00
build_print_host_upload_group ( page . get ());
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Firmware" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "gcode_flavor" );
2020-12-07 16:14:40 +01:00
option = optgroup -> get_option ( "thumbnails" );
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "silent_mode" );
optgroup -> append_single_option_line ( "remaining_times" );
2018-06-20 14:20:48 +02:00
2019-08-06 16:51:32 +02:00
optgroup -> m_on_change = [ this , optgroup ]( t_config_option_key opt_key , boost :: any value ) {
wxTheApp -> CallAfter ([ this , opt_key , value ]() {
if ( opt_key == "silent_mode" ) {
bool val = boost :: any_cast < bool > ( value );
if ( m_use_silent_mode != val ) {
m_rebuild_kinematics_page = true ;
m_use_silent_mode = val ;
}
}
build_unregular_pages ();
update_dirty ();
on_value_change ( opt_key , value );
});
};
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Advanced" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "use_relative_e_distances" );
optgroup -> append_single_option_line ( "use_firmware_retraction" );
optgroup -> append_single_option_line ( "use_volumetric_e" );
optgroup -> append_single_option_line ( "variable_layer_height" );
2017-12-22 11:50:28 +01:00
2019-04-13 23:46:52 +02:00
const int gcode_field_height = 15 ; // 150
const int notes_field_height = 25 ; // 250
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Custom G-code" ), "cog" );
optgroup = page -> new_optgroup ( L ( "Start G-code" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "start_gcode" );
option . opt . full_width = true ;
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = gcode_field_height ; //150;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "End G-code" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "end_gcode" );
option . opt . full_width = true ;
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = gcode_field_height ; //150;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Before layer change G-code" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "before_layer_gcode" );
option . opt . full_width = true ;
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = gcode_field_height ; //150;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "After layer change G-code" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "layer_gcode" );
option . opt . full_width = true ;
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = gcode_field_height ; //150;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Tool change G-code" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "toolchange_gcode" );
option . opt . full_width = true ;
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = gcode_field_height ; //150;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Between objects G-code (for sequential printing)" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "between_objects_gcode" );
option . opt . full_width = true ;
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = gcode_field_height ; //150;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2020-06-03 10:42:47 +02:00
optgroup = page -> new_optgroup ( L ( "Color Change G-code" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2020-06-03 10:42:47 +02:00
option = optgroup -> get_option ( "color_change_gcode" );
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2020-06-03 10:42:47 +02:00
option . opt . height = gcode_field_height ; //150;
optgroup -> append_single_option_line ( option );
optgroup = page -> new_optgroup ( L ( "Pause Print G-code" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2020-06-03 10:42:47 +02:00
option = optgroup -> get_option ( "pause_print_gcode" );
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2020-06-03 10:42:47 +02:00
option . opt . height = gcode_field_height ; //150;
optgroup -> append_single_option_line ( option );
optgroup = page -> new_optgroup ( L ( "Template Custom G-code" ), 0 );
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
optgroup -> m_on_change = [ this , optgroup ]( const t_config_option_key & opt_key , const boost :: any & value ) {
2021-02-26 13:56:51 +01:00
validate_custom_gcode_cb ( this , optgroup , opt_key , value );
2021-02-22 08:13:48 +01:00
};
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2020-06-03 10:42:47 +02:00
option = optgroup -> get_option ( "template_custom_gcode" );
2020-09-13 02:35:07 +02:00
option . opt . is_code = true ;
2020-06-03 10:42:47 +02:00
option . opt . height = gcode_field_height ; //150;
optgroup -> append_single_option_line ( option );
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Notes" ), "note.png" );
optgroup = page -> new_optgroup ( L ( "Notes" ), 0 );
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "printer_notes" );
option . opt . full_width = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = notes_field_height ; //250;
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Dependencies" ), "wrench.png" );
optgroup = page -> new_optgroup ( L ( "Profile dependencies" ));
2020-03-04 13:47:35 +01:00
build_preset_description_line ( optgroup . get ());
2018-03-22 11:46:15 +01:00
2021-02-04 09:42:32 +01:00
build_unregular_pages ( true );
2018-01-12 17:16:59 +01:00
}
2018-08-03 14:34:52 +02:00
void TabPrinter :: build_sla ()
{
2018-08-07 11:58:27 +02:00
if ( ! m_pages . empty ())
m_pages . resize ( 0 );
2020-04-13 17:55:38 +02:00
auto page = add_options_page ( L ( "General" ), "printer" );
auto optgroup = page -> new_optgroup ( L ( "Size and coordinates" ));
2018-08-03 14:34:52 +02:00
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "bed_shape" , "custom-svg-and-png-bed-textures_124612" , [ this ]( wxWindow * parent ) {
2020-03-04 20:58:14 +01:00
return create_bed_shape_widget ( parent );
});
2018-08-03 14:34:52 +02:00
optgroup -> append_single_option_line ( "max_print_height" );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Display" ));
2018-08-03 14:34:52 +02:00
optgroup -> append_single_option_line ( "display_width" );
optgroup -> append_single_option_line ( "display_height" );
2018-08-08 17:47:59 +02:00
auto option = optgroup -> get_option ( "display_pixels_x" );
2020-04-13 17:55:38 +02:00
Line line = { option . opt . full_label , "" };
2018-08-08 17:47:59 +02:00
line . append_option ( option );
2018-08-03 14:34:52 +02:00
line . append_option ( optgroup -> get_option ( "display_pixels_y" ));
optgroup -> append_line ( line );
2018-12-13 12:42:45 +01:00
optgroup -> append_single_option_line ( "display_orientation" );
2019-08-06 16:51:32 +02:00
2019-05-18 23:21:59 +02:00
// FIXME: This should be on one line in the UI
optgroup -> append_single_option_line ( "display_mirror_x" );
optgroup -> append_single_option_line ( "display_mirror_y" );
2018-08-03 14:34:52 +02:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Tilt" ));
line = { L ( "Tilt time" ), "" };
2019-02-18 16:04:55 +01:00
line . append_option ( optgroup -> get_option ( "fast_tilt_time" ));
line . append_option ( optgroup -> get_option ( "slow_tilt_time" ));
optgroup -> append_line ( line );
optgroup -> append_single_option_line ( "area_fill" );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Corrections" ));
line = Line { m_config -> def () -> get ( "relative_correction" ) -> full_label , "" };
2019-04-09 18:15:25 +02:00
// std::vector<std::string> axes{ "X", "Y", "Z" };
std :: vector < std :: string > axes { "XY" , "Z" };
2018-08-03 16:20:39 +02:00
int id = 0 ;
for ( auto & axis : axes ) {
2019-04-09 13:42:32 +02:00
auto opt = optgroup -> get_option ( "relative_correction" , id );
2018-08-03 16:20:39 +02:00
opt . opt . label = axis ;
line . append_option ( opt );
++ id ;
}
optgroup -> append_line ( line );
2019-04-09 13:42:32 +02:00
optgroup -> append_single_option_line ( "absolute_correction" );
2020-02-06 14:09:48 +01:00
optgroup -> append_single_option_line ( "elefant_foot_compensation" );
2020-02-06 16:28:02 +01:00
optgroup -> append_single_option_line ( "elefant_foot_min_width" );
2019-04-09 13:42:32 +02:00
optgroup -> append_single_option_line ( "gamma_correction" );
2020-02-06 14:09:48 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Exposure" ));
2019-08-20 17:24:48 +02:00
optgroup -> append_single_option_line ( "min_exposure_time" );
optgroup -> append_single_option_line ( "max_exposure_time" );
optgroup -> append_single_option_line ( "min_initial_exposure_time" );
optgroup -> append_single_option_line ( "max_initial_exposure_time" );
2020-10-16 16:30:46 +02:00
build_print_host_upload_group ( page . get ());
2019-04-13 23:46:52 +02:00
const int notes_field_height = 25 ; // 250
2019-02-04 12:07:15 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Notes" ), "note.png" );
optgroup = page -> new_optgroup ( L ( "Notes" ), 0 );
2018-08-08 17:47:59 +02:00
option = optgroup -> get_option ( "printer_notes" );
2018-08-03 14:34:52 +02:00
option . opt . full_width = true ;
2019-02-04 12:07:15 +01:00
option . opt . height = notes_field_height ; //250;
2018-08-03 14:34:52 +02:00
optgroup -> append_single_option_line ( option );
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Dependencies" ), "wrench.png" );
optgroup = page -> new_optgroup ( L ( "Profile dependencies" ));
2020-03-04 13:47:35 +01:00
build_preset_description_line ( optgroup . get ());
2018-01-12 17:16:59 +01:00
}
2020-10-02 17:31:55 +02:00
2018-10-31 12:56:08 +01:00
void TabPrinter :: extruders_count_changed ( size_t extruders_count )
{
2019-04-21 23:12:39 +02:00
bool is_count_changed = false ;
if ( m_extruders_count != extruders_count ) {
2019-08-06 16:51:32 +02:00
m_extruders_count = extruders_count ;
m_preset_bundle -> printers . get_edited_preset (). set_num_extruders ( extruders_count );
m_preset_bundle -> update_multi_material_filament_presets ();
2019-04-21 23:12:39 +02:00
is_count_changed = true ;
}
2019-08-06 16:51:32 +02:00
else if ( m_extruders_count == 1 &&
2019-07-30 15:45:32 +02:00
m_preset_bundle -> project_config . option < ConfigOptionFloats > ( "wiping_volumes_matrix" ) -> values . size () > 1 )
m_preset_bundle -> update_multi_material_filament_presets ();
2019-04-21 23:12:39 +02:00
2019-08-06 16:51:32 +02:00
/* This function should be call in any case because of correct updating/rebuilding
2019-04-21 23:12:39 +02:00
* of unregular pages of a Printer Settings
*/
2019-08-06 16:51:32 +02:00
build_unregular_pages ();
2019-04-21 23:12:39 +02:00
if ( is_count_changed ) {
on_value_change ( "extruders_count" , extruders_count );
wxGetApp (). sidebar (). update_objects_list_extruder_column ( extruders_count );
}
2017-12-22 11:50:28 +01:00
}
2018-06-22 13:01:41 +02:00
void TabPrinter :: append_option_line ( ConfigOptionsGroupShp optgroup , const std :: string opt_key )
2018-06-21 16:15:56 +02:00
{
2019-08-06 16:51:32 +02:00
auto option = optgroup -> get_option ( opt_key , 0 );
2020-04-13 17:55:38 +02:00
auto line = Line { option . opt . full_label , "" };
2019-08-06 16:51:32 +02:00
line . append_option ( option );
2021-02-04 09:42:32 +01:00
if ( m_use_silent_mode
|| m_printer_technology == ptSLA // just for first build, if SLA printer preset is selected
)
2019-08-06 16:51:32 +02:00
line . append_option ( optgroup -> get_option ( opt_key , 1 ));
optgroup -> append_line ( line );
2018-06-21 16:15:56 +02:00
}
2018-06-22 16:13:34 +02:00
PageShp TabPrinter :: build_kinematics_page ()
2018-06-20 14:20:48 +02:00
{
2020-04-13 17:55:38 +02:00
auto page = add_options_page ( L ( "Machine limits" ), "cog" , true );
2018-06-21 16:15:56 +02:00
2020-10-02 17:31:55 +02:00
auto optgroup = page -> new_optgroup ( L ( "General" ));
{
optgroup -> append_single_option_line ( "machine_limits_usage" );
Line line { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_machine_limits_description_line );
};
optgroup -> append_line ( line );
}
if ( m_use_silent_mode ) {
2019-08-06 16:51:32 +02:00
// Legend for OptionsGroups
auto optgroup = page -> new_optgroup ( "" );
auto line = Line { "" , "" };
2018-06-21 16:15:56 +02:00
2019-08-06 16:51:32 +02:00
ConfigOptionDef def ;
def . type = coString ;
2020-11-18 12:08:09 +01:00
def . width = Field :: def_width ();
2021-03-11 15:01:24 +01:00
def . gui_type = ConfigOptionDef :: GUIType :: legend ;
2018-12-21 09:19:00 +01:00
def . mode = comAdvanced ;
2019-08-06 16:51:32 +02:00
def . tooltip = L ( "Values in this column are for Normal mode" );
def . set_default_value ( new ConfigOptionString { _ ( L ( "Normal" )). ToUTF8 (). data () });
2018-06-21 16:15:56 +02:00
2019-08-06 16:51:32 +02:00
auto option = Option ( def , "full_power_legend" );
line . append_option ( option );
2018-06-21 16:15:56 +02:00
2019-08-06 16:51:32 +02:00
def . tooltip = L ( "Values in this column are for Stealth mode" );
def . set_default_value ( new ConfigOptionString { _ ( L ( "Stealth" )). ToUTF8 (). data () });
option = Option ( def , "silent_legend" );
line . append_option ( option );
2018-06-21 16:15:56 +02:00
2019-08-06 16:51:32 +02:00
optgroup -> append_line ( line );
}
2018-06-21 16:15:56 +02:00
2019-08-06 16:51:32 +02:00
std :: vector < std :: string > axes { "x" , "y" , "z" , "e" };
2020-10-02 17:31:55 +02:00
optgroup = page -> new_optgroup ( L ( "Maximum feedrates" ));
2019-08-06 16:51:32 +02:00
for ( const std :: string & axis : axes ) {
append_option_line ( optgroup , "machine_max_feedrate_" + axis );
}
2018-06-20 14:20:48 +02:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Maximum accelerations" ));
2019-08-06 16:51:32 +02:00
for ( const std :: string & axis : axes ) {
append_option_line ( optgroup , "machine_max_acceleration_" + axis );
}
append_option_line ( optgroup , "machine_max_acceleration_extruding" );
append_option_line ( optgroup , "machine_max_acceleration_retracting" );
2018-06-20 14:20:48 +02:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Jerk limits" ));
2019-08-06 16:51:32 +02:00
for ( const std :: string & axis : axes ) {
append_option_line ( optgroup , "machine_max_jerk_" + axis );
}
2018-06-20 14:20:48 +02:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Minimum feedrates" ));
2019-08-06 16:51:32 +02:00
append_option_line ( optgroup , "machine_min_extruding_rate" );
append_option_line ( optgroup , "machine_min_travel_rate" );
2018-07-18 15:08:55 +02:00
2019-08-06 16:51:32 +02:00
return page ;
2018-06-20 14:20:48 +02:00
}
2019-04-21 23:12:39 +02:00
/* Previous name build_extruder_pages().
2019-08-06 16:51:32 +02:00
*
* This function was renamed because of now it implements not just an extruder pages building,
* but "Machine limits" and "Single extruder MM setup" too
2019-04-21 23:12:39 +02:00
* (These pages can changes according to the another values of a current preset)
* */
2021-02-04 09:42:32 +01:00
void TabPrinter :: build_unregular_pages ( bool from_initial_build /* = false*/ )
2018-06-20 14:20:48 +02:00
{
2019-08-06 16:51:32 +02:00
size_t n_before_extruders = 2 ; // Count of pages before Extruder pages
bool is_marlin_flavor = m_config -> option < ConfigOptionEnum < GCodeFlavor >> ( "gcode_flavor" ) -> value == gcfMarlin ;
2018-06-20 14:20:48 +02:00
2019-08-06 16:51:32 +02:00
/* ! Freeze/Thaw in this function is needed to avoid call OnPaint() for erased pages
2019-04-22 00:17:56 +02:00
* and be cause of application crash, when try to change Preset in moment,
* when one of unregular pages is selected.
* */
Freeze ();
2019-08-06 16:51:32 +02:00
// Add/delete Kinematics page according to is_marlin_flavor
size_t existed_page = 0 ;
2019-09-06 17:46:55 +02:00
for ( size_t i = n_before_extruders ; i < m_pages . size (); ++ i ) // first make sure it's not there already
2020-04-13 17:55:38 +02:00
if ( m_pages [ i ] -> title (). find ( L ( "Machine limits" )) != std :: string :: npos ) {
2019-08-06 16:51:32 +02:00
if ( ! is_marlin_flavor || m_rebuild_kinematics_page )
m_pages . erase ( m_pages . begin () + i );
else
existed_page = i ;
break ;
}
2018-06-20 14:20:48 +02:00
2021-02-04 09:42:32 +01:00
if ( existed_page < n_before_extruders && ( is_marlin_flavor || from_initial_build )) {
2019-08-06 16:51:32 +02:00
auto page = build_kinematics_page ();
2021-02-08 16:15:11 +01:00
if ( from_initial_build && ! is_marlin_flavor )
2021-02-04 09:42:32 +01:00
page -> clear ();
else
m_pages . insert ( m_pages . begin () + n_before_extruders , page );
2019-08-06 16:51:32 +02:00
}
2018-06-20 14:20:48 +02:00
2019-08-06 16:51:32 +02:00
if ( is_marlin_flavor )
n_before_extruders ++ ;
size_t n_after_single_extruder_MM = 2 ; // Count of pages after single_extruder_multi_material page
2018-04-23 15:39:55 +02:00
2019-08-06 16:51:32 +02:00
if ( m_extruders_count_old == m_extruders_count ||
( m_has_single_extruder_MM_page && m_extruders_count == 1 ))
{
// if we have a single extruder MM setup, add a page with configuration options:
2019-09-06 17:46:55 +02:00
for ( size_t i = 0 ; i < m_pages . size (); ++ i ) // first make sure it's not there already
2020-04-13 17:55:38 +02:00
if ( m_pages [ i ] -> title (). find ( L ( "Single extruder MM setup" )) != std :: string :: npos ) {
2019-08-06 16:51:32 +02:00
m_pages . erase ( m_pages . begin () + i );
break ;
}
m_has_single_extruder_MM_page = false ;
}
2021-02-04 09:42:32 +01:00
if ( from_initial_build ||
( m_extruders_count > 1 && m_config -> opt_bool ( "single_extruder_multi_material" ) && ! m_has_single_extruder_MM_page )) {
2019-08-06 16:51:32 +02:00
// create a page, but pretend it's an extruder page, so we can add it to m_pages ourselves
2020-04-13 17:55:38 +02:00
auto page = add_options_page ( L ( "Single extruder MM setup" ), "printer" , true );
auto optgroup = page -> new_optgroup ( L ( "Single extruder multimaterial parameters" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "cooling_tube_retraction" );
optgroup -> append_single_option_line ( "cooling_tube_length" );
optgroup -> append_single_option_line ( "parking_pos_retraction" );
2018-05-23 19:34:33 +02:00
optgroup -> append_single_option_line ( "extra_loading_move" );
2018-12-14 20:09:10 +01:00
optgroup -> append_single_option_line ( "high_current_on_filament_swap" );
2021-02-04 09:42:32 +01:00
if ( from_initial_build )
page -> clear ();
else {
m_pages . insert ( m_pages . end () - n_after_single_extruder_MM , page );
m_has_single_extruder_MM_page = true ;
}
2019-08-06 16:51:32 +02:00
}
2019-04-21 23:12:39 +02:00
// Build missed extruder pages
2019-08-06 16:51:32 +02:00
for ( auto extruder_idx = m_extruders_count_old ; extruder_idx < m_extruders_count ; ++ extruder_idx ) {
//# build page
2020-12-01 16:43:34 +01:00
const wxString & page_name = wxString :: Format ( "Extruder %d" , int ( extruder_idx + 1 ));
2019-04-22 00:17:56 +02:00
auto page = add_options_page ( page_name , "funnel" , true );
2019-08-06 16:51:32 +02:00
m_pages . insert ( m_pages . begin () + n_before_extruders + extruder_idx , page );
2020-04-13 17:55:38 +02:00
auto optgroup = page -> new_optgroup ( L ( "Size" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "nozzle_diameter" , wxEmptyString , extruder_idx );
2019-06-26 09:48:52 +02:00
optgroup -> m_on_change = [ this , extruder_idx ]( const t_config_option_key & opt_key , boost :: any value )
{
2019-07-23 16:12:29 +02:00
if ( m_config -> opt_bool ( "single_extruder_multi_material" ) && m_extruders_count > 1 && opt_key . find_first_of ( "nozzle_diameter" ) != std :: string :: npos )
2019-06-26 09:48:52 +02:00
{
SuppressBackgroundProcessingUpdate sbpu ;
const double new_nd = boost :: any_cast < double > ( value );
std :: vector < double > nozzle_diameters = static_cast < const ConfigOptionFloats *> ( m_config -> option ( "nozzle_diameter" )) -> values ;
// if value was changed
2019-08-06 16:51:32 +02:00
if ( fabs ( nozzle_diameters [ extruder_idx == 0 ? 1 : 0 ] - new_nd ) > EPSILON )
2019-06-26 09:48:52 +02:00
{
2019-08-15 10:35:50 +02:00
const wxString msg_text = _ ( L ( "This is a single extruder multimaterial printer, diameters of all extruders "
"will be set to the new value. Do you want to proceed?" ));
2019-08-15 12:52:56 +02:00
wxMessageDialog dialog ( parent (), msg_text , _ ( L ( "Nozzle diameter" )), wxICON_WARNING | wxYES_NO );
2019-06-26 09:48:52 +02:00
DynamicPrintConfig new_conf = * m_config ;
2019-08-15 12:52:56 +02:00
if ( dialog . ShowModal () == wxID_YES ) {
2019-06-26 09:48:52 +02:00
for ( size_t i = 0 ; i < nozzle_diameters . size (); i ++ ) {
if ( i == extruder_idx )
continue ;
nozzle_diameters [ i ] = new_nd ;
}
}
2019-08-06 16:51:32 +02:00
else
2019-06-26 09:48:52 +02:00
nozzle_diameters [ extruder_idx ] = nozzle_diameters [ extruder_idx == 0 ? 1 : 0 ];
new_conf . set_key_value ( "nozzle_diameter" , new ConfigOptionFloats ( nozzle_diameters ));
load_config ( new_conf );
}
}
update_dirty ();
update ();
};
2017-12-22 11:50:28 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Layer height limits" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "min_layer_height" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "max_layer_height" , wxEmptyString , extruder_idx );
2019-08-06 16:51:32 +02:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Position (for multi-extruder printers)" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "extruder_offset" , wxEmptyString , extruder_idx );
2019-08-06 16:51:32 +02:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Retraction" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "retract_length" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "retract_lift" , wxEmptyString , extruder_idx );
2020-04-13 17:55:38 +02:00
Line line = { L ( "Only lift Z" ), "" };
2019-08-06 16:51:32 +02:00
line . append_option ( optgroup -> get_option ( "retract_lift_above" , extruder_idx ));
line . append_option ( optgroup -> get_option ( "retract_lift_below" , extruder_idx ));
optgroup -> append_line ( line );
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "retract_speed" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "deretract_speed" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "retract_restart_extra" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "retract_before_travel" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "retract_layer_change" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "wipe" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "retract_before_wipe" , wxEmptyString , extruder_idx );
2019-08-06 16:51:32 +02:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Retraction when tool is disabled (advanced settings for multi-extruder setups)" ));
2020-10-29 21:53:33 +01:00
optgroup -> append_single_option_line ( "retract_length_toolchange" , wxEmptyString , extruder_idx );
optgroup -> append_single_option_line ( "retract_restart_extra_toolchange" , wxEmptyString , extruder_idx );
2019-08-06 16:51:32 +02:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Preview" ));
2019-08-13 09:37:44 +02:00
auto reset_to_filament_color = [ this , extruder_idx ]( wxWindow * parent ) {
2020-09-22 16:16:35 +02:00
m_reset_to_filament_color = new ScalableButton ( parent , wxID_ANY , "undo" , _L ( "Reset to Filament Color" ),
wxDefaultSize , wxDefaultPosition , wxBU_LEFT | wxBU_EXACTFIT , true );
2019-08-13 09:37:44 +02:00
ScalableButton * btn = m_reset_to_filament_color ;
btn -> SetFont ( Slic3r :: GUI :: wxGetApp (). normal_font ());
2020-10-29 21:53:33 +01:00
btn -> SetSize ( btn -> GetBestSize ());
2019-08-13 09:37:44 +02:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( btn );
btn -> Bind ( wxEVT_BUTTON , [ this , extruder_idx ]( wxCommandEvent & e )
{
std :: vector < std :: string > colors = static_cast < const ConfigOptionStrings *> ( m_config -> option ( "extruder_colour" )) -> values ;
colors [ extruder_idx ] = "" ;
2019-08-20 17:24:48 +02:00
2019-08-13 09:37:44 +02:00
DynamicPrintConfig new_conf = * m_config ;
new_conf . set_key_value ( "extruder_colour" , new ConfigOptionStrings ( colors ));
load_config ( new_conf );
update_dirty ();
update ();
});
return sizer ;
};
2020-10-29 21:53:33 +01:00
line = optgroup -> create_single_option_line ( "extruder_colour" , wxEmptyString , extruder_idx );
2019-08-13 09:37:44 +02:00
line . append_widget ( reset_to_filament_color );
optgroup -> append_line ( line );
2019-08-06 16:51:32 +02:00
}
// # remove extra pages
if ( m_extruders_count < m_extruders_count_old )
m_pages . erase ( m_pages . begin () + n_before_extruders + m_extruders_count ,
m_pages . begin () + n_before_extruders + m_extruders_count_old );
2018-01-02 12:50:27 +01:00
2019-04-22 00:17:56 +02:00
Thaw ();
2019-08-06 16:51:32 +02:00
m_extruders_count_old = m_extruders_count ;
2021-02-04 09:42:32 +01:00
2021-02-08 16:15:11 +01:00
if ( from_initial_build && m_printer_technology == ptSLA )
2021-02-04 09:42:32 +01:00
return ; // next part of code is no needed to execute at this moment
2019-08-06 16:51:32 +02:00
rebuild_page_tree ();
2019-04-21 23:12:39 +02:00
// Reload preset pages with current configuration values
reload_config ();
2020-04-16 09:59:12 +02:00
// apply searcher with current configuration
apply_searcher ();
2017-12-22 11:50:28 +01:00
}
2018-01-16 16:28:01 +01:00
// this gets executed after preset is loaded and before GUI fields are updated
void TabPrinter :: on_preset_loaded ()
{
2019-08-06 16:51:32 +02:00
// update the extruders count field
auto * nozzle_diameter = dynamic_cast < const ConfigOptionFloats *> ( m_config -> option ( "nozzle_diameter" ));
2019-09-06 17:46:55 +02:00
size_t extruders_count = nozzle_diameter -> values . size ();
2019-08-06 16:51:32 +02:00
// update the GUI field according to the number of nozzle diameters supplied
extruders_count_changed ( extruders_count );
2018-01-16 16:28:01 +01:00
}
2018-08-07 11:58:27 +02:00
void TabPrinter :: update_pages ()
{
// update m_pages ONLY if printer technology is changed
2018-10-31 16:22:36 +01:00
const PrinterTechnology new_printer_technology = m_presets -> get_edited_preset (). printer_technology ();
if ( new_printer_technology == m_printer_technology )
2018-08-07 11:58:27 +02:00
return ;
2020-10-07 09:54:13 +02:00
//clear all active pages before switching
clear_pages ();
2018-08-07 11:58:27 +02:00
// set m_pages to m_pages_(technology before changing)
m_printer_technology == ptFFF ? m_pages . swap ( m_pages_fff ) : m_pages . swap ( m_pages_sla );
// build Tab according to the technology, if it's not exist jet OR
// set m_pages_(technology after changing) to m_pages
2018-10-31 16:22:36 +01:00
// m_printer_technology will be set by Tab::load_current_preset()
if ( new_printer_technology == ptFFF )
2019-05-10 11:05:54 +02:00
{
if ( m_pages_fff . empty ())
{
build_fff ();
if ( m_extruders_count > 1 )
{
m_preset_bundle -> update_multi_material_filament_presets ();
on_value_change ( "extruders_count" , m_extruders_count );
}
}
else
m_pages . swap ( m_pages_fff );
2019-05-11 23:50:32 +02:00
wxGetApp (). sidebar (). update_objects_list_extruder_column ( m_extruders_count );
2019-05-10 11:05:54 +02:00
}
2019-08-06 16:51:32 +02:00
else
2018-08-07 11:58:27 +02:00
m_pages_sla . empty () ? build_sla () : m_pages . swap ( m_pages_sla );
2019-03-20 16:22:01 +01:00
rebuild_page_tree ();
2018-08-07 11:58:27 +02:00
}
2020-10-27 22:53:43 +01:00
void TabPrinter :: reload_config ()
{
Tab :: reload_config ();
// "extruders_count" doesn't update from the update_config(),
// so update it implicitly
if ( m_active_page && m_active_page -> title () == "General" )
m_active_page -> set_value ( "extruders_count" , int ( m_extruders_count ));
}
2020-09-29 13:36:56 +02:00
void TabPrinter :: activate_selected_page ( std :: function < void () > throw_if_canceled )
2018-08-07 11:58:27 +02:00
{
2020-09-29 13:36:56 +02:00
Tab :: activate_selected_page ( throw_if_canceled );
2019-02-22 09:38:56 +01:00
2020-09-22 11:17:43 +02:00
// "extruders_count" doesn't update from the update_config(),
// so update it implicitly
2020-10-07 11:52:37 +02:00
if ( m_active_page && m_active_page -> title () == "General" )
2020-09-22 11:17:43 +02:00
m_active_page -> set_value ( "extruders_count" , int ( m_extruders_count ));
2018-08-07 11:58:27 +02:00
}
2020-09-22 16:16:35 +02:00
void TabPrinter :: clear_pages ()
2018-08-07 11:58:27 +02:00
{
2020-09-22 16:16:35 +02:00
Tab :: clear_pages ();
m_reset_to_filament_color = nullptr ;
}
2018-01-12 17:16:59 +01:00
2020-09-22 11:17:43 +02:00
void TabPrinter :: toggle_options ()
2018-08-07 11:58:27 +02:00
{
2020-09-22 11:17:43 +02:00
if ( ! m_active_page || m_presets -> get_edited_preset (). printer_technology () == ptSLA )
return ;
2018-08-21 11:10:32 +02:00
2019-08-06 16:51:32 +02:00
bool have_multiple_extruders = m_extruders_count > 1 ;
2020-09-22 11:17:43 +02:00
if ( m_active_page -> title () == "Custom G-code" )
toggle_option ( "toolchange_gcode" , have_multiple_extruders );
if ( m_active_page -> title () == "General" ) {
toggle_option ( "single_extruder_multi_material" , have_multiple_extruders );
2018-01-12 17:16:59 +01:00
2020-09-22 11:17:43 +02:00
bool is_marlin_flavor = m_config -> option < ConfigOptionEnum < GCodeFlavor >> ( "gcode_flavor" ) -> value == gcfMarlin ;
// Disable silent mode for non-marlin firmwares.
toggle_option ( "silent_mode" , is_marlin_flavor );
}
2018-06-28 12:40:27 +02:00
2020-09-22 11:17:43 +02:00
wxString extruder_number ;
long val ;
if ( m_active_page -> title (). StartsWith ( "Extruder " , & extruder_number ) && extruder_number . ToLong ( & val ) &&
2020-10-06 11:15:24 +02:00
val > 0 && ( size_t ) val <= m_extruders_count )
2019-08-06 16:51:32 +02:00
{
2020-09-22 11:17:43 +02:00
size_t i = size_t ( val - 1 );
2019-08-06 16:51:32 +02:00
bool have_retract_length = m_config -> opt_float ( "retract_length" , i ) > 0 ;
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
// when using firmware retraction, firmware decides retraction length
bool use_firmware_retraction = m_config -> opt_bool ( "use_firmware_retraction" );
2020-09-22 11:17:43 +02:00
toggle_option ( "retract_length" , ! use_firmware_retraction , i );
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
// user can customize travel length if we have retraction length or we"re using
// firmware retraction
2020-09-22 11:17:43 +02:00
toggle_option ( "retract_before_travel" , have_retract_length || use_firmware_retraction , i );
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
// user can customize other retraction options if retraction is enabled
bool retraction = ( have_retract_length || use_firmware_retraction );
std :: vector < std :: string > vec = { "retract_lift" , "retract_layer_change" };
for ( auto el : vec )
2020-09-22 11:17:43 +02:00
toggle_option ( el , retraction , i );
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
// retract lift above / below only applies if using retract lift
vec . resize ( 0 );
vec = { "retract_lift_above" , "retract_lift_below" };
for ( auto el : vec )
2020-09-22 11:17:43 +02:00
toggle_option ( el , retraction && ( m_config -> opt_float ( "retract_lift" , i ) > 0 ), i );
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
// some options only apply when not using firmware retraction
vec . resize ( 0 );
vec = { "retract_speed" , "deretract_speed" , "retract_before_wipe" , "retract_restart_extra" , "wipe" };
for ( auto el : vec )
2020-09-22 11:17:43 +02:00
toggle_option ( el , retraction && ! use_firmware_retraction , i );
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
bool wipe = m_config -> opt_bool ( "wipe" , i );
2020-09-22 11:17:43 +02:00
toggle_option ( "retract_before_wipe" , wipe , i );
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
if ( use_firmware_retraction && wipe ) {
2019-08-15 12:52:56 +02:00
wxMessageDialog dialog ( parent (),
2019-08-06 16:51:32 +02:00
_ ( L ( "The Wipe option is not available when using the Firmware Retraction mode. \n "
2020-09-22 11:17:43 +02:00
" \n Shall I disable it in order to enable Firmware Retraction?" )),
2019-08-06 16:51:32 +02:00
_ ( L ( "Firmware Retraction" )), wxICON_WARNING | wxYES | wxNO );
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
DynamicPrintConfig new_conf = * m_config ;
2019-08-15 12:52:56 +02:00
if ( dialog . ShowModal () == wxID_YES ) {
2019-08-06 16:51:32 +02:00
auto wipe = static_cast < ConfigOptionBools *> ( m_config -> option ( "wipe" ) -> clone ());
2019-09-06 17:46:55 +02:00
for ( size_t w = 0 ; w < wipe -> values . size (); w ++ )
2019-08-06 16:51:32 +02:00
wipe -> values [ w ] = false ;
new_conf . set_key_value ( "wipe" , wipe );
}
else {
new_conf . set_key_value ( "use_firmware_retraction" , new ConfigOptionBool ( false ));
}
load_config ( new_conf );
}
2018-01-12 17:16:59 +01:00
2020-09-22 11:17:43 +02:00
toggle_option ( "retract_length_toolchange" , have_multiple_extruders , i );
2018-01-12 17:16:59 +01:00
2019-08-06 16:51:32 +02:00
bool toolchange_retraction = m_config -> opt_float ( "retract_length_toolchange" , i ) > 0 ;
2020-09-22 11:17:43 +02:00
toggle_option ( "retract_restart_extra_toolchange" , have_multiple_extruders && toolchange_retraction , i );
2019-08-06 16:51:32 +02:00
}
2018-01-12 17:16:59 +01:00
2020-12-22 16:23:53 +01:00
if ( m_active_page -> title () == "Machine limits" && m_machine_limits_description_line ) {
2020-10-02 17:31:55 +02:00
assert ( m_config -> option < ConfigOptionEnum < GCodeFlavor >> ( "gcode_flavor" ) -> value == gcfMarlin );
const auto * machine_limits_usage = m_config -> option < ConfigOptionEnum < MachineLimitsUsage >> ( "machine_limits_usage" );
bool enabled = machine_limits_usage -> value != MachineLimitsUsage :: Ignore ;
bool silent_mode = m_config -> opt_bool ( "silent_mode" );
int max_field = silent_mode ? 2 : 1 ;
for ( const std :: string & opt : Preset :: machine_limits_options ())
for ( int i = 0 ; i < max_field ; ++ i )
toggle_option ( opt , enabled , i );
update_machine_limits_description ( machine_limits_usage -> value );
}
2020-09-22 11:17:43 +02:00
}
void TabPrinter :: update ()
{
m_update_cnt ++ ;
m_presets -> get_edited_preset (). printer_technology () == ptFFF ? update_fff () : update_sla ();
m_update_cnt -- ;
2020-10-16 16:30:46 +02:00
Layout ();
2020-09-22 11:17:43 +02:00
if ( m_update_cnt == 0 )
wxGetApp (). mainframe -> on_config_changed ( m_config );
}
void TabPrinter :: update_fff ()
{
if ( m_use_silent_mode != m_config -> opt_bool ( "silent_mode" )) {
m_rebuild_kinematics_page = true ;
m_use_silent_mode = m_config -> opt_bool ( "silent_mode" );
}
toggle_options ();
2018-01-12 17:16:59 +01:00
}
2018-10-31 12:56:08 +01:00
void TabPrinter :: update_sla ()
{ ; }
2018-08-07 11:58:27 +02:00
2020-03-04 13:47:35 +01:00
void Tab :: update_ui_items_related_on_parent_preset ( const Preset * selected_preset_parent )
{
m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent -> is_default ;
m_bmp_non_system = selected_preset_parent ? & m_bmp_value_unlock : & m_bmp_white_bullet ;
m_ttg_non_system = selected_preset_parent ? & m_ttg_value_unlock : & m_ttg_white_bullet_ns ;
m_tt_non_system = selected_preset_parent ? & m_tt_value_unlock : & m_ttg_white_bullet_ns ;
}
2018-01-16 16:28:01 +01:00
// Initialize the UI from the current preset
2018-01-05 15:11:33 +01:00
void Tab :: load_current_preset ()
{
2019-08-06 16:51:32 +02:00
const Preset & preset = m_presets -> get_edited_preset ();
2018-03-16 17:25:11 +01:00
2020-07-28 11:31:16 +02:00
update_btns_enabling ();
2018-08-06 17:01:41 +02:00
2018-08-07 11:58:27 +02:00
update ();
2019-08-06 16:51:32 +02:00
if ( m_type == Slic3r :: Preset :: TYPE_PRINTER ) {
// For the printer profile, generate the extruder pages.
if ( preset . printer_technology () == ptFFF )
on_preset_loaded ();
else
wxGetApp (). sidebar (). update_objects_list_extruder_column ( 1 );
}
2018-08-07 11:58:27 +02:00
// Reload preset pages with the new configuration values.
reload_config ();
2018-08-06 17:01:41 +02:00
2020-03-04 13:47:35 +01:00
update_ui_items_related_on_parent_preset ( m_presets -> get_selected_preset_parent ());
2019-07-01 14:56:28 +02:00
// m_undo_to_sys_btn->Enable(!preset.is_default);
2018-07-02 13:51:50 +02:00
2019-01-09 10:43:17 +01:00
#if 0
2019-08-06 16:51:32 +02:00
// use CallAfter because some field triggers schedule on_change calls using CallAfter,
// and we don't want them to be called after this update_dirty() as they would mark the
// preset dirty again
// (not sure this is true anymore now that update_dirty is idempotent)
wxTheApp->CallAfter([this]
2019-01-09 10:43:17 +01:00
#endif
2019-08-06 16:51:32 +02:00
{
// checking out if this Tab exists till this moment
if ( ! wxGetApp (). checked_tab ( this ))
return ;
update_tab_ui ();
2018-08-06 17:01:41 +02:00
// update show/hide tabs
2019-08-06 16:51:32 +02:00
if ( m_type == Slic3r :: Preset :: TYPE_PRINTER ) {
2019-01-10 18:08:38 +01:00
const PrinterTechnology printer_technology = m_presets -> get_edited_preset (). printer_technology ();
2018-08-07 11:58:27 +02:00
if ( printer_technology != static_cast < TabPrinter *> ( this ) -> m_printer_technology )
2018-08-06 17:01:41 +02:00
{
2020-10-07 11:52:37 +02:00
// The change of the technology requires to remove some of unrelated Tabs
// During this action, wxNoteBook::RemovePage invoke wxEVT_NOTEBOOK_PAGE_CHANGED
// and as a result a function select_active_page() is called fron Tab::OnActive()
// But we don't need it. So, to avoid activation of the page, set m_active_page to NULL
// till unusable Tabs will be deleted
Page * tmp_page = m_active_page ;
m_active_page = nullptr ;
2018-11-19 13:17:14 +01:00
for ( auto tab : wxGetApp (). tabs_list ) {
if ( tab -> type () == Preset :: TYPE_PRINTER ) // Printer tab is shown every time
continue ;
if ( tab -> supports_printer_technology ( printer_technology ))
2019-01-01 16:08:46 -05:00
{
2018-11-19 13:17:14 +01:00
wxGetApp (). tab_panel () -> InsertPage ( wxGetApp (). tab_panel () -> FindPage ( this ), tab , tab -> title ());
2019-01-01 16:08:46 -05:00
#ifdef __linux__ // the tabs apparently need to be explicitly shown on Linux (pull request #1563)
int page_id = wxGetApp (). tab_panel () -> FindPage ( tab );
wxGetApp (). tab_panel () -> GetPage ( page_id ) -> Show ( true );
#endif // __linux__
}
2018-11-19 13:17:14 +01:00
else {
int page_id = wxGetApp (). tab_panel () -> FindPage ( tab );
2018-09-21 01:33:41 +02:00
wxGetApp (). tab_panel () -> GetPage ( page_id ) -> Show ( false );
wxGetApp (). tab_panel () -> RemovePage ( page_id );
2019-08-06 16:51:32 +02:00
}
2018-08-06 17:01:41 +02:00
}
2018-08-08 16:22:56 +02:00
static_cast < TabPrinter *> ( this ) -> m_printer_technology = printer_technology ;
2020-10-07 11:52:37 +02:00
m_active_page = tmp_page ;
2018-08-06 17:01:41 +02:00
}
2019-08-06 16:51:32 +02:00
on_presets_changed ();
if ( printer_technology == ptFFF ) {
2020-08-18 16:49:06 +02:00
static_cast < TabPrinter *> ( this ) -> m_initial_extruders_count = static_cast < const ConfigOptionFloats *> ( m_presets -> get_selected_preset (). config . option ( "nozzle_diameter" )) -> values . size (); //static_cast<TabPrinter*>(this)->m_extruders_count;
2019-08-06 16:51:32 +02:00
const Preset * parent_preset = m_presets -> get_selected_preset_parent ();
static_cast < TabPrinter *> ( this ) -> m_sys_extruders_count = parent_preset == nullptr ? 0 :
static_cast < const ConfigOptionFloats *> ( parent_preset -> config . option ( "nozzle_diameter" )) -> values . size ();
}
}
else {
on_presets_changed ();
2019-03-22 12:11:23 +01:00
if ( m_type == Preset :: TYPE_SLA_PRINT || m_type == Preset :: TYPE_PRINT )
2019-08-06 16:51:32 +02:00
update_frequently_changed_parameters ();
}
2018-10-31 16:22:36 +01:00
2019-08-06 16:51:32 +02:00
m_opt_status_value = ( m_presets -> get_selected_preset_parent () ? osSystemValue : 0 ) | osInitValue ;
init_options_list ();
2018-12-21 12:58:03 +01:00
update_visibility ();
2019-08-06 16:51:32 +02:00
update_changed_ui ();
}
2019-01-09 10:43:17 +01:00
#if 0
2019-08-06 16:51:32 +02:00
);
2019-01-09 10:43:17 +01:00
#endif
2018-01-05 15:11:33 +01:00
}
2017-12-13 14:45:10 +01:00
//Regerenerate content of the page tree.
2019-03-20 16:22:01 +01:00
void Tab :: rebuild_page_tree ()
2017-12-13 14:45:10 +01:00
{
2019-08-06 16:51:32 +02:00
// get label of the currently selected item
2018-09-21 01:33:41 +02:00
const auto sel_item = m_treectrl -> GetSelection ();
2019-08-06 16:51:32 +02:00
const auto selected = sel_item ? m_treectrl -> GetItemText ( sel_item ) : "" ;
const auto rootItem = m_treectrl -> GetRootItem ();
2018-04-23 15:09:01 +02:00
2020-09-22 11:17:43 +02:00
wxTreeItemId item ;
// Delete/Append events invoke wxEVT_TREE_SEL_CHANGED event.
// To avoid redundant clear/activate functions call
// suppress activate page before page_tree rebuilding
m_disable_tree_sel_changed_event = true ;
2019-08-06 16:51:32 +02:00
m_treectrl -> DeleteChildren ( rootItem );
2018-04-23 15:39:55 +02:00
2018-10-21 23:09:24 +02:00
for ( auto p : m_pages )
{
if ( ! p -> get_show ())
continue ;
2020-12-01 16:43:34 +01:00
auto itemId = m_treectrl -> AppendItem ( rootItem , translate_category ( p -> title (), m_type ), p -> iconID ());
2018-10-21 23:09:24 +02:00
m_treectrl -> SetItemTextColour ( itemId , p -> get_item_colour ());
2020-12-21 14:28:50 +01:00
if ( translate_category ( p -> title (), m_type ) == selected )
2020-09-22 11:17:43 +02:00
item = itemId ;
2018-10-21 23:09:24 +02:00
}
2020-09-22 11:17:43 +02:00
if ( ! item ) {
2018-10-21 23:09:24 +02:00
// this is triggered on first load, so we don't disable the sel change event
2020-09-22 11:17:43 +02:00
item = m_treectrl -> GetFirstVisibleItem ();
2018-10-21 23:09:24 +02:00
}
2020-09-22 11:17:43 +02:00
// allow activate page before selection of a page_tree item
m_disable_tree_sel_changed_event = false ;
if ( item )
m_treectrl -> SelectItem ( item );
2018-10-21 23:09:24 +02:00
}
2020-07-28 11:31:16 +02:00
void Tab :: update_btns_enabling ()
2020-07-20 14:56:09 +02:00
{
2020-10-20 16:38:13 +02:00
// we can delete any preset from the physical printer
// and any user preset
const Preset & preset = m_presets -> get_edited_preset ();
2021-01-14 13:00:03 +01:00
m_btn_delete_preset -> Show (( m_type == Preset :: TYPE_PRINTER && m_preset_bundle -> physical_printers . has_selection ())
|| ( ! preset . is_default && ! preset . is_system ));
2020-07-28 11:31:16 +02:00
if ( m_btn_edit_ph_printer )
2020-10-20 16:38:13 +02:00
m_btn_edit_ph_printer -> SetToolTip ( m_preset_bundle -> physical_printers . has_selection () ?
_L ( "Edit physical printer" ) : _L ( "Add physical printer" ));
2020-07-20 14:56:09 +02:00
}
2020-07-17 14:32:38 +02:00
void Tab :: update_preset_choice ()
{
m_presets_choice -> update ();
2020-07-28 11:31:16 +02:00
update_btns_enabling ();
2020-07-17 14:32:38 +02:00
}
2019-03-22 12:11:23 +01:00
// Called by the UI combo box when the user switches profiles, and also to delete the current profile.
2018-01-16 16:28:01 +01:00
// Select a preset by a name.If !defined(name), then the default preset is selected.
// If the current profile is modified, user is asked to save the changes.
2020-07-17 14:32:38 +02:00
void Tab :: select_preset ( std :: string preset_name , bool delete_current /*=false*/ , const std :: string & last_selected_ph_printer_name /* =""*/ )
2018-01-16 16:28:01 +01:00
{
2019-08-06 16:51:32 +02:00
if ( preset_name . empty ()) {
if ( delete_current ) {
2020-07-28 11:31:16 +02:00
// Find an alternate preset to be selected after the current preset is deleted.
const std :: deque < Preset > & presets = this -> m_presets -> get_presets ();
size_t idx_current = this -> m_presets -> get_idx_selected ();
// Find the next visible preset.
size_t idx_new = idx_current + 1 ;
if ( idx_new < presets . size ())
for (; idx_new < presets . size () && ! presets [ idx_new ]. is_visible ; ++ idx_new ) ;
if ( idx_new == presets . size ())
for ( idx_new = idx_current - 1 ; idx_new > 0 && ! presets [ idx_new ]. is_visible ; -- idx_new );
preset_name = presets [ idx_new ]. name ;
2019-08-06 16:51:32 +02:00
} else {
// If no name is provided, select the "-- default --" preset.
preset_name = m_presets -> default_preset (). name ;
}
}
assert ( ! delete_current || ( m_presets -> get_edited_preset (). name != preset_name && m_presets -> get_edited_preset (). is_user ()));
bool current_dirty = ! delete_current && m_presets -> current_is_dirty ();
bool print_tab = m_presets -> type () == Preset :: TYPE_PRINT || m_presets -> type () == Preset :: TYPE_SLA_PRINT ;
bool printer_tab = m_presets -> type () == Preset :: TYPE_PRINTER ;
bool canceled = false ;
2020-02-27 11:44:01 +01:00
bool technology_changed = false ;
2020-03-06 17:41:00 +01:00
m_dependent_tabs . clear ();
2020-08-10 19:07:45 +02:00
if ( current_dirty && ! may_discard_current_dirty_preset ( nullptr , preset_name )) {
2019-08-06 16:51:32 +02:00
canceled = true ;
} else if ( print_tab ) {
// Before switching the print profile to a new one, verify, whether the currently active filament or SLA material
// are compatible with the new print.
// If it is not compatible and the current filament or SLA material are dirty, let user decide
// whether to discard the changes or keep the current print selection.
2020-02-27 11:44:01 +01:00
PresetWithVendorProfile printer_profile = m_preset_bundle -> printers . get_edited_preset_with_vendor_profile ();
PrinterTechnology printer_technology = printer_profile . preset . printer_technology ();
2019-08-06 16:51:32 +02:00
PresetCollection & dependent = ( printer_technology == ptFFF ) ? m_preset_bundle -> filaments : m_preset_bundle -> sla_materials ;
2018-12-04 17:56:49 +01:00
bool old_preset_dirty = dependent . current_is_dirty ();
2020-02-27 11:44:01 +01:00
bool new_preset_compatible = is_compatible_with_print ( dependent . get_edited_preset_with_vendor_profile (),
m_presets -> get_preset_with_vendor_profile ( * m_presets -> find_preset ( preset_name , true )), printer_profile );
2018-12-04 17:56:49 +01:00
if ( ! canceled )
canceled = old_preset_dirty && ! new_preset_compatible && ! may_discard_current_dirty_preset ( & dependent , preset_name );
if ( ! canceled ) {
// The preset will be switched to a different, compatible preset, or the '-- default --'.
m_dependent_tabs . emplace_back (( printer_technology == ptFFF ) ? Preset :: Type :: TYPE_FILAMENT : Preset :: Type :: TYPE_SLA_MATERIAL );
2020-02-21 11:03:03 +01:00
if ( old_preset_dirty && ! new_preset_compatible )
2018-12-04 17:56:49 +01:00
dependent . discard_current_changes ();
}
2019-08-06 16:51:32 +02:00
} else if ( printer_tab ) {
// Before switching the printer to a new one, verify, whether the currently active print and filament
// are compatible with the new printer.
// If they are not compatible and the current print or filament are dirty, let user decide
// whether to discard the changes or keep the current printer selection.
//
// With the introduction of the SLA printer types, we need to support switching between
// the FFF and SLA printers.
const Preset & new_printer_preset = * m_presets -> find_preset ( preset_name , true );
2019-12-05 14:48:11 +01:00
const PresetWithVendorProfile new_printer_preset_with_vendor_profile = m_presets -> get_preset_with_vendor_profile ( new_printer_preset );
2019-08-06 16:51:32 +02:00
PrinterTechnology old_printer_technology = m_presets -> get_edited_preset (). printer_technology ();
PrinterTechnology new_printer_technology = new_printer_preset . printer_technology ();
2018-11-29 12:33:04 +01:00
if ( new_printer_technology == ptSLA && old_printer_technology == ptFFF && ! may_switch_to_SLA_preset ())
canceled = true ;
else {
struct PresetUpdate {
Preset :: Type tab_type ;
PresetCollection * presets ;
PrinterTechnology technology ;
bool old_preset_dirty ;
bool new_preset_compatible ;
};
std :: vector < PresetUpdate > updates = {
{ Preset :: Type :: TYPE_PRINT , & m_preset_bundle -> prints , ptFFF },
{ Preset :: Type :: TYPE_SLA_PRINT , & m_preset_bundle -> sla_prints , ptSLA },
{ Preset :: Type :: TYPE_FILAMENT , & m_preset_bundle -> filaments , ptFFF },
{ Preset :: Type :: TYPE_SLA_MATERIAL , & m_preset_bundle -> sla_materials , ptSLA }
};
for ( PresetUpdate & pu : updates ) {
pu . old_preset_dirty = ( old_printer_technology == pu . technology ) && pu . presets -> current_is_dirty ();
2019-12-05 14:48:11 +01:00
pu . new_preset_compatible = ( new_printer_technology == pu . technology ) && is_compatible_with_printer ( pu . presets -> get_edited_preset_with_vendor_profile (), new_printer_preset_with_vendor_profile );
2018-11-29 12:33:04 +01:00
if ( ! canceled )
canceled = pu . old_preset_dirty && ! pu . new_preset_compatible && ! may_discard_current_dirty_preset ( pu . presets , preset_name );
}
if ( ! canceled ) {
for ( PresetUpdate & pu : updates ) {
// The preset will be switched to a different, compatible preset, or the '-- default --'.
if ( pu . technology == new_printer_technology )
m_dependent_tabs . emplace_back ( pu . tab_type );
2019-03-04 12:52:30 +01:00
if ( pu . old_preset_dirty && ! pu . new_preset_compatible )
2018-11-29 12:33:04 +01:00
pu . presets -> discard_current_changes ();
}
}
}
2020-02-27 11:44:01 +01:00
if ( ! canceled )
technology_changed = old_printer_technology != new_printer_technology ;
2019-08-06 16:51:32 +02:00
}
2019-03-22 12:11:23 +01:00
2019-08-06 16:51:32 +02:00
if ( ! canceled && delete_current ) {
// Delete the file and select some other reasonable preset.
// It does not matter which preset will be made active as the preset will be re-selected from the preset_name variable.
// The 'external' presets will only be removed from the preset list, their files will not be deleted.
try {
m_presets -> delete_current_preset ();
} catch ( const std :: exception & /* e */ ) {
//FIXME add some error reporting!
canceled = true ;
}
}
2019-03-22 12:11:23 +01:00
2019-08-06 16:51:32 +02:00
if ( canceled ) {
2020-07-20 14:56:09 +02:00
if ( m_type == Preset :: TYPE_PRINTER ) {
if ( ! last_selected_ph_printer_name . empty () &&
m_presets -> get_edited_preset (). name == PhysicalPrinter :: get_preset_name ( last_selected_ph_printer_name )) {
// If preset selection was canceled and previously was selected physical printer, we should select it back
2020-07-23 12:17:18 +02:00
m_preset_bundle -> physical_printers . select_printer ( last_selected_ph_printer_name );
2020-07-17 14:32:38 +02:00
}
2020-12-04 21:23:12 +01:00
if ( m_preset_bundle -> physical_printers . has_selection ()) {
// If preset selection was canceled and physical printer was selected
// we must disable selection marker for the physical printers
m_preset_bundle -> physical_printers . unselect_printer ();
}
2020-07-17 14:32:38 +02:00
}
2020-07-20 14:56:09 +02:00
update_tab_ui ();
2019-08-06 16:51:32 +02:00
// Trigger the on_presets_changed event so that we also restore the previous value in the plater selector,
2019-12-02 22:48:01 -05:00
// if this action was initiated from the plater.
2019-08-06 16:51:32 +02:00
on_presets_changed ();
} else {
if ( current_dirty )
m_presets -> discard_current_changes ();
2019-03-22 12:11:23 +01:00
2019-08-06 16:51:32 +02:00
const bool is_selected = m_presets -> select_preset_by_name ( preset_name , false ) || delete_current ;
assert ( m_presets -> get_edited_preset (). name == preset_name || ! is_selected );
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// The following method should not discard changes of current print or filament presets on change of a printer profile,
// if they are compatible with the current printer.
2020-03-09 12:29:40 +01:00
auto update_compatible_type = [ delete_current ]( bool technology_changed , bool on_page , bool show_incompatible_presets ) {
return ( delete_current || technology_changed ) ? PresetSelectCompatibleType :: Always :
on_page ? PresetSelectCompatibleType :: Never :
show_incompatible_presets ? PresetSelectCompatibleType :: OnlyIfWasCompatible : PresetSelectCompatibleType :: Always ;
2020-02-27 11:44:01 +01:00
};
2019-08-06 16:51:32 +02:00
if ( current_dirty || delete_current || print_tab || printer_tab )
2020-02-27 11:44:01 +01:00
m_preset_bundle -> update_compatible (
update_compatible_type ( technology_changed , print_tab , ( print_tab ? this : wxGetApp (). get_tab ( Preset :: TYPE_PRINT )) -> m_show_incompatible_presets ),
update_compatible_type ( technology_changed , false , wxGetApp (). get_tab ( Preset :: TYPE_FILAMENT ) -> m_show_incompatible_presets ));
2019-08-06 16:51:32 +02:00
// Initialize the UI from the current preset.
2018-08-07 11:58:27 +02:00
if ( printer_tab )
static_cast < TabPrinter *> ( this ) -> update_pages ();
2019-03-15 14:21:32 +01:00
2019-03-22 12:11:23 +01:00
if ( ! is_selected && printer_tab )
2019-03-15 14:21:32 +01:00
{
/* There is a case, when :
2019-08-06 16:51:32 +02:00
* after Config Wizard applying we try to select previously selected preset, but
2019-03-15 14:21:32 +01:00
* in a current configuration this one:
* 1. doesn't exist now,
* 2. have another printer_technology
2019-08-06 16:51:32 +02:00
* So, it is necessary to update list of dependent tabs
2019-03-15 14:21:32 +01:00
* to the corresponding printer_technology
*/
const PrinterTechnology printer_technology = m_presets -> get_edited_preset (). printer_technology ();
2019-03-22 12:11:23 +01:00
if ( printer_technology == ptFFF && m_dependent_tabs . front () != Preset :: Type :: TYPE_PRINT )
2019-08-06 16:51:32 +02:00
m_dependent_tabs = { Preset :: Type :: TYPE_PRINT , Preset :: Type :: TYPE_FILAMENT };
2019-03-22 12:11:23 +01:00
else if ( printer_technology == ptSLA && m_dependent_tabs . front () != Preset :: Type :: TYPE_SLA_PRINT )
m_dependent_tabs = { Preset :: Type :: TYPE_SLA_PRINT , Preset :: Type :: TYPE_SLA_MATERIAL };
2019-03-15 14:21:32 +01:00
}
2020-07-17 14:32:38 +02:00
2020-08-18 16:49:06 +02:00
// check and apply extruders count for printer preset
if ( m_type == Preset :: TYPE_PRINTER )
static_cast < TabPrinter *> ( this ) -> apply_extruder_cnt_from_cache ();
2020-08-13 15:45:16 +02:00
// check if there is something in the cache to move to the new selected preset
2020-09-02 09:06:42 +02:00
apply_config_from_cache ();
2020-08-13 15:45:16 +02:00
2019-08-06 16:51:32 +02:00
load_current_preset ();
}
2021-02-04 09:42:32 +01:00
if ( technology_changed )
wxGetApp (). mainframe -> diff_dialog . update_presets ();
2018-01-16 16:28:01 +01:00
}
// If the current preset is dirty, the user is asked whether the changes may be discarded.
// if the current preset was not dirty, or the user agreed to discard the changes, 1 is returned.
2018-04-13 12:35:04 +02:00
bool Tab :: may_discard_current_dirty_preset ( PresetCollection * presets /*= nullptr*/ , const std :: string & new_printer_name /*= ""*/ )
2018-01-16 16:28:01 +01:00
{
2020-08-12 17:33:22 +02:00
if ( presets == nullptr ) presets = m_presets ;
2020-08-13 15:45:16 +02:00
UnsavedChangesDialog dlg ( m_type , presets , new_printer_name );
2020-10-15 16:48:48 +02:00
if ( wxGetApp (). app_config -> get ( "default_action_on_select_preset" ) == "none" && dlg . ShowModal () == wxID_CANCEL )
2020-08-05 19:25:04 +02:00
return false ;
2020-08-13 15:45:16 +02:00
2020-08-12 17:33:22 +02:00
if ( dlg . save_preset ()) // save selected changes
{
2020-10-03 03:15:54 +02:00
const std :: vector < std :: string >& unselected_options = dlg . get_unselected_options ( presets -> type ());
const std :: string & name = dlg . get_preset_name ();
2020-08-12 17:33:22 +02:00
2020-08-14 18:17:16 +02:00
if ( m_type == presets -> type ()) // save changes for the current preset from this tab
2020-08-12 17:33:22 +02:00
{
2020-08-13 15:45:16 +02:00
// revert unselected options to the old values
2020-08-14 18:17:16 +02:00
presets -> get_edited_preset (). config . apply_only ( presets -> get_selected_preset (). config , unselected_options );
2020-08-13 15:45:16 +02:00
save_preset ( name );
2020-08-14 18:17:16 +02:00
}
else
2020-08-13 15:45:16 +02:00
{
2020-08-14 18:17:16 +02:00
m_preset_bundle -> save_changes_for_preset ( name , presets -> type (), unselected_options );
2019-01-21 12:34:28 +01:00
2020-10-03 03:15:54 +02:00
// If filament preset is saved for multi-material printer preset,
// there are cases when filament comboboxs are updated for old (non-modified) colors,
// but in full_config a filament_colors option aren't.
2020-08-13 15:45:16 +02:00
if ( presets -> type () == Preset :: TYPE_FILAMENT && wxGetApp (). extruders_edited_cnt () > 1 )
wxGetApp (). plater () -> force_filament_colors_update ();
}
2019-08-06 16:51:32 +02:00
}
2020-10-15 16:48:48 +02:00
else if ( dlg . transfer_changes ()) // move selected changes
2020-08-13 15:45:16 +02:00
{
2020-08-18 16:49:06 +02:00
std :: vector < std :: string > selected_options = dlg . get_selected_options ();
2020-09-02 09:06:42 +02:00
if ( m_type == presets -> type ()) // move changes for the current preset from this tab
{
if ( m_type == Preset :: TYPE_PRINTER ) {
auto it = std :: find ( selected_options . begin (), selected_options . end (), "extruders_count" );
if ( it != selected_options . end ()) {
// erase "extruders_count" option from the list
selected_options . erase ( it );
// cache the extruders count
static_cast < TabPrinter *> ( this ) -> cache_extruder_cnt ();
}
}
2020-08-18 16:49:06 +02:00
2020-09-02 09:06:42 +02:00
// copy selected options to the cache from edited preset
cache_config_diff ( selected_options );
}
else
wxGetApp (). get_tab ( presets -> type ()) -> cache_config_diff ( selected_options );
2019-08-06 16:51:32 +02:00
}
2020-08-13 15:45:16 +02:00
return true ;
2018-01-16 16:28:01 +01:00
}
2018-11-29 12:33:04 +01:00
// If we are switching from the FFF-preset to the SLA, we should to control the printed objects if they have a part(s).
// Because of we can't to print the multi-part objects with SLA technology.
bool Tab :: may_switch_to_SLA_preset ()
{
2019-07-18 17:41:47 +02:00
if ( model_has_multi_part_objects ( wxGetApp (). model ()))
2018-11-29 12:33:04 +01:00
{
2019-08-06 16:51:32 +02:00
show_info ( parent (),
2019-01-21 12:34:28 +01:00
_ ( L ( "It's impossible to print multi-part object(s) with SLA technology." )) + " \n\n " +
_ ( L ( "Please check your object list before preset changing." )),
2018-11-29 12:33:04 +01:00
_ ( L ( "Attention!" )) );
return false ;
}
return true ;
}
2020-09-22 11:17:43 +02:00
void Tab :: clear_pages ()
2017-12-13 14:45:10 +01:00
{
2020-09-24 15:41:48 +02:00
// invalidated highlighter, if any exists
m_highlighter . invalidate ();
2020-09-24 18:54:54 +02:00
m_page_sizer -> Clear ( true );
2020-09-22 11:17:43 +02:00
// clear pages from the controlls
for ( auto p : m_pages )
2020-10-06 11:15:24 +02:00
p -> clear ();
2020-09-22 11:17:43 +02:00
2020-09-22 16:16:35 +02:00
// nulling pointers
2020-09-22 11:17:43 +02:00
m_parent_preset_description_line = nullptr ;
m_detach_preset_btn = nullptr ;
2020-09-22 16:16:35 +02:00
m_compatible_printers . checkbox = nullptr ;
m_compatible_printers . btn = nullptr ;
m_compatible_prints . checkbox = nullptr ;
m_compatible_prints . btn = nullptr ;
2020-09-22 11:17:43 +02:00
}
void Tab :: update_description_lines ()
{
2020-12-22 16:23:53 +01:00
if ( m_active_page && m_active_page -> title () == "Dependencies" && m_parent_preset_description_line )
2020-09-22 11:17:43 +02:00
update_preset_description_line ();
}
2020-09-29 13:36:56 +02:00
void Tab :: activate_selected_page ( std :: function < void () > throw_if_canceled )
2020-09-22 11:17:43 +02:00
{
if ( ! m_active_page )
2019-04-22 00:17:56 +02:00
return ;
2018-06-11 16:56:35 +02:00
2020-09-29 13:36:56 +02:00
m_active_page -> activate ( m_mode , throw_if_canceled );
2020-09-22 11:17:43 +02:00
update_changed_ui ();
update_description_lines ();
toggle_options ();
}
2020-09-29 13:36:56 +02:00
bool Tab :: tree_sel_change_delayed ()
2017-12-13 14:45:10 +01:00
{
2020-10-01 19:16:23 +02:00
// There is a bug related to Ubuntu overlay scrollbars, see https://github.com/prusa3d/PrusaSlicer/issues/898 and https://github.com/prusa3d/PrusaSlicer/issues/952.
// The issue apparently manifests when Show()ing a window with overlay scrollbars while the UI is frozen. For this reason,
// we will Thaw the UI prematurely on Linux. This means destroing the no_updates object prematurely.
2019-08-06 16:51:32 +02:00
#ifdef __linux__
std :: unique_ptr < wxWindowUpdateLocker > no_updates ( new wxWindowUpdateLocker ( this ));
2018-06-11 16:56:35 +02:00
#else
2019-12-05 13:55:49 +01:00
/* On Windows we use DoubleBuffering during rendering,
* so on Window is no needed to call a Freeze/Thaw functions.
* But under OSX (builds compiled with MacOSX10.14.sdk) wxStaticBitmap rendering is broken without Freeze/Thaw call.
*/
2020-09-24 18:54:54 +02:00
//#ifdef __WXOSX__ // Use Freeze/Thaw to avoid flickering during clear/activate new page
2020-10-01 19:16:23 +02:00
wxWindowUpdateLocker noUpdates ( this );
2020-09-22 11:17:43 +02:00
//#endif
2019-12-05 13:55:49 +01:00
#endif
2018-10-23 09:48:01 +02:00
2019-08-06 16:51:32 +02:00
Page * page = nullptr ;
2018-09-21 01:33:41 +02:00
const auto sel_item = m_treectrl -> GetSelection ();
const auto selection = sel_item ? m_treectrl -> GetItemText ( sel_item ) : "" ;
2018-10-23 09:48:01 +02:00
for ( auto p : m_pages )
2020-12-01 16:43:34 +01:00
if ( translate_category ( p -> title (), m_type ) == selection )
2019-08-06 16:51:32 +02:00
{
page = p . get ();
m_is_nonsys_values = page -> m_is_nonsys_values ;
m_is_modified_values = page -> m_is_modified_values ;
break ;
}
2020-09-29 13:36:56 +02:00
if ( page == nullptr || m_active_page == page )
return false ;
2017-12-05 15:54:01 +01:00
2020-09-22 11:17:43 +02:00
// clear pages from the controls
m_active_page = page ;
2020-09-29 13:36:56 +02:00
auto throw_if_canceled = std :: function < void () > ([ this ](){
#ifdef WIN32
wxCheckForInterrupt ( m_treectrl );
if ( m_page_switch_planned )
throw UIBuildCanceled ();
2021-01-29 16:16:23 +01:00
#else // WIN32
( void ) this ; // silence warning
#endif
2020-09-29 13:36:56 +02:00
});
2018-06-11 16:56:35 +02:00
2020-09-29 13:36:56 +02:00
try {
clear_pages ();
throw_if_canceled ();
2018-03-22 09:37:42 +01:00
2020-10-02 12:11:10 +02:00
if ( wxGetApp (). mainframe != nullptr && wxGetApp (). mainframe -> is_active_and_shown_tab ( this ))
2020-09-29 13:36:56 +02:00
activate_selected_page ( throw_if_canceled );
#ifdef __linux__
no_updates . reset ( nullptr );
#endif
update_undo_buttons ();
throw_if_canceled ();
2019-08-06 16:51:32 +02:00
m_hsizer -> Layout ();
2020-09-29 13:36:56 +02:00
throw_if_canceled ();
2019-08-06 16:51:32 +02:00
Refresh ();
2020-09-29 13:36:56 +02:00
} catch ( const UIBuildCanceled & ) {
if ( m_active_page )
m_active_page -> clear ();
return true ;
2020-09-24 15:41:48 +02:00
}
2018-06-11 16:56:35 +02:00
2020-09-29 13:36:56 +02:00
return false ;
2017-12-13 14:45:10 +01:00
}
2017-12-05 15:54:01 +01:00
2018-01-05 15:11:33 +01:00
void Tab :: OnKeyDown ( wxKeyEvent & event )
2017-12-05 15:54:01 +01:00
{
2019-08-06 16:51:32 +02:00
if ( event . GetKeyCode () == WXK_TAB )
m_treectrl -> Navigate ( event . ShiftDown () ? wxNavigationKeyEvent :: IsBackward : wxNavigationKeyEvent :: IsForward );
else
event . Skip ();
2018-01-16 16:28:01 +01:00
}
2017-12-05 15:54:01 +01:00
2021-02-04 09:42:32 +01:00
void Tab :: compare_preset ()
{
wxGetApp (). mainframe -> diff_dialog . show ( m_type );
}
2018-01-16 16:28:01 +01:00
// Save the current preset into file.
// This removes the "dirty" flag of the preset, possibly creates a new preset under a new name,
// and activates the new preset.
// Wizard calls save_preset with a name "My Settings", otherwise no name is provided and this method
2020-09-22 11:17:43 +02:00
// opens a Slic3r::GUI::SavePresetDialog dialog.
2020-03-06 17:41:00 +01:00
void Tab :: save_preset ( std :: string name /*= ""*/ , bool detach )
2018-01-16 16:28:01 +01:00
{
2019-08-06 16:51:32 +02:00
// since buttons(and choices too) don't get focus on Mac, we set focus manually
// to the treectrl so that the EVT_* events are fired for the input field having
// focus currently.is there anything better than this ?
2018-01-16 16:28:01 +01:00
//! m_treectrl->OnSetFocus();
2017-12-05 15:54:01 +01:00
2019-08-06 16:51:32 +02:00
if ( name . empty ()) {
2020-11-05 20:50:49 +01:00
SavePresetDialog dlg ( m_parent , m_type , detach ? _u8L ( "Detached" ) : "" );
2019-08-15 12:52:56 +02:00
if ( dlg . ShowModal () != wxID_OK )
2019-08-06 16:51:32 +02:00
return ;
2019-08-15 12:52:56 +02:00
name = dlg . get_name ();
2019-08-06 16:51:32 +02:00
}
2018-01-16 16:28:01 +01:00
2019-08-06 16:51:32 +02:00
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
2020-03-06 17:41:00 +01:00
m_presets -> save_current_preset ( name , detach );
2019-08-06 16:51:32 +02:00
// Mark the print & filament enabled if they are compatible with the currently selected preset.
2020-03-06 17:41:00 +01:00
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
2020-02-27 11:44:01 +01:00
m_preset_bundle -> update_compatible ( PresetSelectCompatibleType :: Never );
2019-08-06 16:51:32 +02:00
// Add the new item into the UI component, remove dirty flags and activate the saved item.
update_tab_ui ();
2019-12-02 22:48:01 -05:00
// Update the selection boxes at the plater.
2019-08-06 16:51:32 +02:00
on_presets_changed ();
// If current profile is saved, "delete preset" button have to be enabled
2020-10-20 16:38:13 +02:00
m_btn_delete_preset -> Show ();
2018-03-16 12:56:03 +01:00
2019-08-06 16:51:32 +02:00
if ( m_type == Preset :: TYPE_PRINTER )
static_cast < TabPrinter *> ( this ) -> m_initial_extruders_count = static_cast < TabPrinter *> ( this ) -> m_extruders_count ;
2020-03-06 19:15:37 +01:00
// Parent preset is "default" after detaching, so we should to update UI values, related on parent preset
if ( detach )
update_ui_items_related_on_parent_preset ( m_presets -> get_selected_preset_parent ());
2019-08-06 16:51:32 +02:00
update_changed_ui ();
2019-09-30 13:59:26 +02:00
/* If filament preset is saved for multi-material printer preset,
* there are cases when filament comboboxs are updated for old (non-modified) colors,
* but in full_config a filament_colors option aren't.*/
if ( m_type == Preset :: TYPE_FILAMENT && wxGetApp (). extruders_edited_cnt () > 1 )
wxGetApp (). plater () -> force_filament_colors_update ();
2020-03-06 17:41:00 +01:00
{
2020-04-22 12:49:52 +02:00
// Profile compatiblity is updated first when the profile is saved.
// Update profile selection combo boxes at the depending tabs to reflect modifications in profile compatibility.
std :: vector < Preset :: Type > dependent ;
switch ( m_type ) {
case Preset :: TYPE_PRINT :
dependent = { Preset :: TYPE_FILAMENT };
break ;
case Preset :: TYPE_SLA_PRINT :
dependent = { Preset :: TYPE_SLA_MATERIAL };
break ;
case Preset :: TYPE_PRINTER :
2020-03-06 17:41:00 +01:00
if ( static_cast < const TabPrinter *> ( this ) -> m_printer_technology == ptFFF )
dependent = { Preset :: TYPE_PRINT , Preset :: TYPE_FILAMENT };
else
dependent = { Preset :: TYPE_SLA_PRINT , Preset :: TYPE_SLA_MATERIAL };
2020-04-22 12:49:52 +02:00
break ;
2020-03-06 17:41:00 +01:00
default :
2020-04-22 12:49:52 +02:00
break ;
}
for ( Preset :: Type preset_type : dependent )
wxGetApp (). get_tab ( preset_type ) -> update_tab_ui ();
}
2021-02-04 09:42:32 +01:00
// update preset comboboxes in DiffPresetDlg
wxGetApp (). mainframe -> diff_dialog . update_presets ( m_type );
2018-01-16 16:28:01 +01:00
}
// Called for a currently selected preset.
2018-01-18 11:45:25 +01:00
void Tab :: delete_preset ()
2018-01-16 16:28:01 +01:00
{
2019-08-06 16:51:32 +02:00
auto current_preset = m_presets -> get_selected_preset ();
// Don't let the user delete the ' - default - ' configuration.
2019-05-11 23:29:25 +02:00
std :: string action = current_preset . is_external ? _utf8 ( L ( "remove" )) : _utf8 ( L ( "delete" ));
// TRN remove/delete
2020-07-28 11:31:16 +02:00
PhysicalPrinterCollection & physical_printers = m_preset_bundle -> physical_printers ;
wxString msg ;
if ( m_presets_choice -> is_selected_physical_printer ())
2020-10-20 16:38:13 +02:00
{
PhysicalPrinter & printer = physical_printers . get_selected_printer ();
if ( printer . preset_names . size () == 1 ) {
if ( m_presets_choice -> del_physical_printer ( _L ( "It's a last preset for this physical printer." )))
Layout ();
return ;
}
msg = format_wxstr ( _L ( "Are you sure you want to delete \" %1% \" preset from the physical printer \" %2% \" ?" ), current_preset . name , printer . name );
}
2020-07-28 11:31:16 +02:00
else
{
if ( m_type == Preset :: TYPE_PRINTER && ! physical_printers . empty ())
{
// Check preset for delete in physical printers
// Ask a customer about next action, if there is a printer with just one preset and this preset is equal to delete
std :: vector < std :: string > ph_printers = physical_printers . get_printers_with_preset ( current_preset . name );
std :: vector < std :: string > ph_printers_only = physical_printers . get_printers_with_only_preset ( current_preset . name );
if ( ! ph_printers . empty ()) {
2021-02-03 21:30:38 +01:00
msg += _L_PLURAL ( "The physical printer below is based on the preset, you are going to delete." ,
"The physical printers below are based on the preset, you are going to delete." , ph_printers . size ());
2020-07-28 11:31:16 +02:00
for ( const std :: string & printer : ph_printers )
msg += " \n \" " + from_u8 ( printer ) + " \" ," ;
msg . RemoveLast ();
2021-02-03 21:30:38 +01:00
msg += " \n " + _L_PLURAL ( "Note, that selected preset will be deleted from this printer too." ,
"Note, that selected preset will be deleted from these printers too." , ph_printers . size ()) + " \n\n " ;
2020-07-28 11:31:16 +02:00
}
if ( ! ph_printers_only . empty ()) {
2021-02-03 21:30:38 +01:00
msg += _L_PLURAL ( "The physical printer below is based only on the preset, you are going to delete." ,
"The physical printers below are based only on the preset, you are going to delete." , ph_printers_only . size ());
2020-07-28 11:31:16 +02:00
for ( const std :: string & printer : ph_printers_only )
msg += " \n \" " + from_u8 ( printer ) + " \" ," ;
msg . RemoveLast ();
2021-02-03 21:30:38 +01:00
msg += " \n " + _L_PLURAL ( "Note, that this printer will be deleted after deleting of the selected preset." ,
"Note, that these printers will be deleted after deleting of the selected preset." , ph_printers_only . size ()) + " \n\n " ;
2020-07-28 11:31:16 +02:00
}
}
msg += from_u8 (( boost :: format ( _u8L ( "Are you sure you want to %1% the selected preset?" )) % action ). str ());
}
2019-08-06 16:51:32 +02:00
action = current_preset . is_external ? _utf8 ( L ( "Remove" )) : _utf8 ( L ( "Delete" ));
// TRN Remove/Delete
2019-05-11 23:29:25 +02:00
wxString title = from_u8 (( boost :: format ( _utf8 ( L ( "%1% Preset" ))) % action ). str ()); //action + _(L(" Preset"));
2019-08-06 16:51:32 +02:00
if ( current_preset . is_default ||
wxID_YES != wxMessageDialog ( parent (), msg , title , wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ). ShowModal ())
return ;
2020-07-28 11:31:16 +02:00
// if we just delete preset from the physical printer
if ( m_presets_choice -> is_selected_physical_printer ()) {
PhysicalPrinter & printer = physical_printers . get_selected_printer ();
// just delete this preset from the current physical printer
printer . delete_preset ( m_presets -> get_edited_preset (). name );
// select first from the possible presets for this printer
physical_printers . select_printer ( printer );
this -> select_preset ( physical_printers . get_selected_printer_preset_name ());
return ;
}
// delete selected preset from printers and printer, if it's needed
if ( m_type == Preset :: TYPE_PRINTER && ! physical_printers . empty ())
physical_printers . delete_preset_from_printers ( current_preset . name );
2019-08-06 16:51:32 +02:00
// Select will handle of the preset dependencies, of saving & closing the depending profiles, and
// finally of deleting the preset.
this -> select_preset ( "" , true );
2018-01-16 16:28:01 +01:00
}
2018-01-18 11:45:25 +01:00
void Tab :: toggle_show_hide_incompatible ()
2018-01-16 16:28:01 +01:00
{
2019-08-06 16:51:32 +02:00
m_show_incompatible_presets = ! m_show_incompatible_presets ;
2020-06-16 12:57:49 +02:00
m_presets_choice -> set_show_incompatible_presets ( m_show_incompatible_presets );
2019-08-06 16:51:32 +02:00
update_show_hide_incompatible_button ();
update_tab_ui ();
2018-01-16 16:28:01 +01:00
}
void Tab :: update_show_hide_incompatible_button ()
{
2019-08-06 16:51:32 +02:00
m_btn_hide_incompatible_presets -> SetBitmap_ ( m_show_incompatible_presets ?
m_bmp_show_incompatible_presets : m_bmp_hide_incompatible_presets );
m_btn_hide_incompatible_presets -> SetToolTip ( m_show_incompatible_presets ?
"Both compatible an incompatible presets are shown. Click to hide presets not compatible with the current printer." :
"Only compatible presets are shown. Click to show both the presets compatible and not compatible with the current printer." );
2018-01-16 16:28:01 +01:00
}
void Tab :: update_ui_from_settings ()
{
2019-08-06 16:51:32 +02:00
// Show the 'show / hide presets' button only for the print and filament tabs, and only if enabled
// in application preferences.
m_show_btn_incompatible_presets = wxGetApp (). app_config -> get ( "show_incompatible_presets" )[ 0 ] == '1' ? true : false ;
bool show = m_show_btn_incompatible_presets && m_type != Slic3r :: Preset :: TYPE_PRINTER ;
Layout ();
show ? m_btn_hide_incompatible_presets -> Show () : m_btn_hide_incompatible_presets -> Hide ();
// If the 'show / hide presets' button is hidden, hide the incompatible presets.
if ( show ) {
update_show_hide_incompatible_button ();
}
else {
if ( m_show_incompatible_presets ) {
m_show_incompatible_presets = false ;
update_tab_ui ();
}
}
2018-01-16 16:28:01 +01:00
}
2020-10-29 21:53:33 +01:00
void Tab :: create_line_with_widget ( ConfigOptionsGroup * optgroup , const std :: string & opt_key , const wxString & path , widget_t widget )
2020-03-04 20:58:14 +01:00
{
Line line = optgroup -> create_single_option_line ( opt_key );
line . widget = widget ;
2020-10-29 21:53:33 +01:00
line . label_path = path ;
2020-03-04 20:58:14 +01:00
2021-01-07 12:26:16 +01:00
m_colored_Label_colors [ opt_key ] = m_default_text_clr ;
line . full_Label_color = & m_colored_Label_colors [ opt_key ];
2020-10-22 13:02:17 +02:00
2020-09-22 11:17:43 +02:00
optgroup -> append_line ( line );
2020-03-04 20:58:14 +01:00
}
2018-01-16 16:28:01 +01:00
// Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer.
2018-12-04 17:56:49 +01:00
wxSizer * Tab :: compatible_widget_create ( wxWindow * parent , PresetDependencies & deps )
2017-12-19 11:59:42 +01:00
{
2019-08-06 16:51:32 +02:00
deps . checkbox = new wxCheckBox ( parent , wxID_ANY , _ ( L ( "All" )));
deps . checkbox -> SetFont ( Slic3r :: GUI :: wxGetApp (). normal_font ());
2020-10-29 21:53:33 +01:00
deps . btn = new ScalableButton ( parent , wxID_ANY , "printer" , from_u8 (( boost :: format ( " %s %s" ) % _utf8 ( L ( "Set" )) % std :: string ( dots . ToUTF8 ())). str ()),
2020-09-22 16:16:35 +02:00
wxDefaultSize , wxDefaultPosition , wxBU_LEFT | wxBU_EXACTFIT , true );
2019-04-13 23:46:52 +02:00
deps . btn -> SetFont ( Slic3r :: GUI :: wxGetApp (). normal_font ());
2020-10-29 21:53:33 +01:00
deps . btn -> SetSize ( deps . btn -> GetBestSize ());
2018-01-15 12:13:05 +01:00
2019-08-06 16:51:32 +02:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add (( deps . checkbox ), 0 , wxALIGN_CENTER_VERTICAL );
sizer -> Add (( deps . btn ), 0 , wxALIGN_CENTER_VERTICAL );
2017-12-19 11:59:42 +01:00
2019-08-06 16:51:32 +02:00
deps . checkbox -> Bind ( wxEVT_CHECKBOX , ([ this , & deps ]( wxCommandEvent e )
{
deps . btn -> Enable ( ! deps . checkbox -> GetValue ());
// All printers have been made compatible with this preset.
if ( deps . checkbox -> GetValue ())
this -> load_key_value ( deps . key_list , std :: vector < std :: string > {});
this -> get_field ( deps . key_condition ) -> toggle ( deps . checkbox -> GetValue ());
this -> update_changed_ui ();
}) );
2017-12-19 11:59:42 +01:00
2019-08-06 16:51:32 +02:00
deps . btn -> Bind ( wxEVT_BUTTON , ([ this , parent , & deps ]( wxCommandEvent e )
{
// Collect names of non-default non-external profiles.
PrinterTechnology printer_technology = m_preset_bundle -> printers . get_edited_preset (). printer_technology ();
PresetCollection & depending_presets = ( deps . type == Preset :: TYPE_PRINTER ) ? m_preset_bundle -> printers :
( printer_technology == ptFFF ) ? m_preset_bundle -> prints : m_preset_bundle -> sla_prints ;
wxArrayString presets ;
for ( size_t idx = 0 ; idx < depending_presets . size (); ++ idx )
{
Preset & preset = depending_presets . preset ( idx );
bool add = ! preset . is_default && ! preset . is_external ;
if ( add && deps . type == Preset :: TYPE_PRINTER )
// Only add printers with the same technology as the active printer.
add &= preset . printer_technology () == printer_technology ;
if ( add )
presets . Add ( from_u8 ( preset . name ));
}
2017-12-19 11:59:42 +01:00
2019-08-06 16:51:32 +02:00
wxMultiChoiceDialog dlg ( parent , deps . dialog_title , deps . dialog_label , presets );
// Collect and set indices of depending_presets marked as compatible.
wxArrayInt selections ;
auto * compatible_printers = dynamic_cast < const ConfigOptionStrings *> ( m_config -> option ( deps . key_list ));
if ( compatible_printers != nullptr || ! compatible_printers -> values . empty ())
for ( auto preset_name : compatible_printers -> values )
for ( size_t idx = 0 ; idx < presets . GetCount (); ++ idx )
if ( presets [ idx ] == preset_name ) {
selections . Add ( idx );
break ;
}
dlg . SetSelections ( selections );
std :: vector < std :: string > value ;
// Show the dialog.
if ( dlg . ShowModal () == wxID_OK ) {
selections . Clear ();
selections = dlg . GetSelections ();
for ( auto idx : selections )
value . push_back ( presets [ idx ]. ToUTF8 (). data ());
if ( value . empty ()) {
deps . checkbox -> SetValue ( 1 );
deps . btn -> Disable ();
}
// All depending_presets have been made compatible with this preset.
this -> load_key_value ( deps . key_list , value );
this -> update_changed_ui ();
}
}));
2020-04-16 09:59:12 +02:00
2019-08-06 16:51:32 +02:00
return sizer ;
2018-12-04 17:56:49 +01:00
}
2020-03-04 20:58:14 +01:00
// Return a callback to create a TabPrinter widget to edit bed shape
wxSizer * TabPrinter :: create_bed_shape_widget ( wxWindow * parent )
{
2020-10-29 21:53:33 +01:00
ScalableButton * btn = new ScalableButton ( parent , wxID_ANY , "printer" , " " + _ ( L ( "Set" )) + " " + dots ,
2020-09-22 16:16:35 +02:00
wxDefaultSize , wxDefaultPosition , wxBU_LEFT | wxBU_EXACTFIT , true );
2020-03-04 20:58:14 +01:00
btn -> SetFont ( wxGetApp (). normal_font ());
2020-10-29 21:53:33 +01:00
btn -> SetSize ( btn -> GetBestSize ());
2020-03-04 20:58:14 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
2020-04-16 09:59:12 +02:00
sizer -> Add ( btn , 0 , wxALIGN_CENTER_VERTICAL );
2020-03-04 20:58:14 +01:00
btn -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent e )
{
BedShapeDialog dlg ( this );
dlg . build_dialog ( * m_config -> option < ConfigOptionPoints > ( "bed_shape" ),
* m_config -> option < ConfigOptionString > ( "bed_custom_texture" ),
* m_config -> option < ConfigOptionString > ( "bed_custom_model" ));
if ( dlg . ShowModal () == wxID_OK ) {
const std :: vector < Vec2d >& shape = dlg . get_shape ();
const std :: string & custom_texture = dlg . get_custom_texture ();
const std :: string & custom_model = dlg . get_custom_model ();
if ( ! shape . empty ())
{
load_key_value ( "bed_shape" , shape );
load_key_value ( "bed_custom_texture" , custom_texture );
load_key_value ( "bed_custom_model" , custom_model );
update_changed_ui ();
}
}
}));
2020-04-16 09:59:12 +02:00
// may be it is not a best place, but
// add information about Category/Grope for "bed_custom_texture" and "bed_custom_model" as a copy from "bed_shape" option
{
Search :: OptionsSearcher & searcher = wxGetApp (). sidebar (). get_searcher ();
const Search :: GroupAndCategory & gc = searcher . get_group_and_category ( "bed_shape" );
searcher . add_key ( "bed_custom_texture" , gc . group , gc . category );
searcher . add_key ( "bed_custom_model" , gc . group , gc . category );
}
2020-03-04 20:58:14 +01:00
return sizer ;
}
2020-08-18 16:49:06 +02:00
void TabPrinter :: cache_extruder_cnt ()
{
if ( m_presets -> get_edited_preset (). printer_technology () == ptSLA )
return ;
m_cache_extruder_count = m_extruders_count ;
}
void TabPrinter :: apply_extruder_cnt_from_cache ()
{
if ( m_presets -> get_edited_preset (). printer_technology () == ptSLA )
return ;
if ( m_cache_extruder_count > 0 ) {
m_presets -> get_edited_preset (). set_num_extruders ( m_cache_extruder_count );
m_cache_extruder_count = 0 ;
}
}
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
2021-02-24 15:50:18 +01:00
bool Tab :: validate_custom_gcodes ()
2021-02-22 08:13:48 +01:00
{
2021-03-01 13:03:43 +01:00
if ( m_type != Preset :: TYPE_FILAMENT &&
( m_type != Preset :: TYPE_PRINTER || static_cast < TabPrinter *> ( this ) -> m_printer_technology != ptFFF ))
return true ;
if ( m_active_page -> title () != L ( "Custom G-code" ))
return true ;
2021-02-22 08:13:48 +01:00
bool valid = true ;
2021-03-01 13:03:43 +01:00
for ( auto opt_group : m_active_page -> m_optgroups ) {
assert ( opt_group -> opt_map (). size () == 1 );
std :: string key = opt_group -> opt_map (). begin () -> first ;
std :: string value = boost :: any_cast < std :: string > ( opt_group -> get_value ( key ));
2021-03-19 11:35:09 +01:00
std :: string config_value = m_type == Preset :: TYPE_FILAMENT ? m_config -> opt_string ( key , 0u ) : m_config -> opt_string ( key );
2021-03-01 13:03:43 +01:00
valid &= validate_custom_gcode ( opt_group -> title , value );
Field * field = opt_group -> get_field ( key );
TextCtrl * text_ctrl = dynamic_cast < TextCtrl *> ( field );
if ( text_ctrl != nullptr && text_ctrl -> m_on_change != nullptr && ! text_ctrl -> m_disable_change_event ) {
Slic3r :: GUI :: t_change callback = opt_group -> m_on_change ;
// temporary disable the opt_group->m_on_change callback to avoid multiple validations
opt_group -> m_on_change = nullptr ;
text_ctrl -> m_on_change ( key , value );
// restore the opt_group->m_on_change callback
opt_group -> m_on_change = callback ;
update_dirty ();
on_value_change ( key , value );
}
if ( ! valid )
break ;
2021-02-22 08:13:48 +01:00
}
return valid ;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2020-10-02 17:31:55 +02:00
void TabPrinter :: update_machine_limits_description ( const MachineLimitsUsage usage )
{
wxString text ;
switch ( usage ) {
case MachineLimitsUsage :: EmitToGCode :
text = _L ( "Machine limits will be emitted to G-code and used to estimate print time." );
break ;
case MachineLimitsUsage :: TimeEstimateOnly :
2020-10-03 03:15:54 +02:00
text = _L ( "Machine limits will NOT be emitted to G-code, however they will be used to estimate print time, "
2020-10-06 11:08:08 +02:00
"which may therefore not be accurate as the printer may apply a different set of machine limits." );
2020-10-02 17:31:55 +02:00
break ;
case MachineLimitsUsage :: Ignore :
text = _L ( "Machine limits are not set, therefore the print time estimate may not be accurate." );
break ;
default : assert ( false );
}
m_machine_limits_description_line -> SetText ( text );
}
2018-12-04 17:56:49 +01:00
void Tab :: compatible_widget_reload ( PresetDependencies & deps )
{
2020-09-22 11:17:43 +02:00
Field * field = this -> get_field ( deps . key_condition );
if ( ! field )
return ;
2019-08-06 16:51:32 +02:00
bool has_any = ! m_config -> option < ConfigOptionStrings > ( deps . key_list ) -> values . empty ();
has_any ? deps . btn -> Enable () : deps . btn -> Disable ();
deps . checkbox -> SetValue ( ! has_any );
2020-09-22 11:17:43 +02:00
field -> toggle ( ! has_any );
2017-12-19 11:59:42 +01:00
}
2018-04-20 12:58:07 +02:00
void Tab :: fill_icon_descriptions ()
{
2019-08-06 16:51:32 +02:00
m_icon_descriptions . emplace_back ( & m_bmp_value_lock , L ( "LOCKED LOCK" ),
2019-05-09 16:14:45 +02:00
// TRN Description for "LOCKED LOCK"
2019-08-06 16:51:32 +02:00
L ( "indicates that the settings are the same as the system (or default) values for the current option group" ));
2018-04-20 12:58:07 +02:00
2019-05-09 19:24:21 +02:00
m_icon_descriptions . emplace_back ( & m_bmp_value_unlock , L ( "UNLOCKED LOCK" ),
2019-05-09 16:14:45 +02:00
// TRN Description for "UNLOCKED LOCK"
2019-08-06 16:51:32 +02:00
L ( "indicates that some settings were changed and are not equal to the system (or default) values for "
"the current option group. \n "
"Click the UNLOCKED LOCK icon to reset all settings for current option group to "
"the system (or default) values." ));
2018-04-20 12:58:07 +02:00
2019-05-09 19:24:21 +02:00
m_icon_descriptions . emplace_back ( & m_bmp_white_bullet , L ( "WHITE BULLET" ),
2019-05-09 16:14:45 +02:00
// TRN Description for "WHITE BULLET"
2020-03-05 07:49:05 +01:00
L ( "for the left button: indicates a non-system (or non-default) preset, \n "
"for the right button: indicates that the settings hasn't been modified." ));
2018-04-20 12:58:07 +02:00
2019-05-09 19:24:21 +02:00
m_icon_descriptions . emplace_back ( & m_bmp_value_revert , L ( "BACK ARROW" ),
2019-05-09 16:14:45 +02:00
// TRN Description for "BACK ARROW"
L ( "indicates that the settings were changed and are not equal to the last saved preset for "
2019-08-06 16:51:32 +02:00
"the current option group. \n "
"Click the BACK ARROW icon to reset all settings for the current option group to "
"the last saved preset." ));
2018-04-20 12:58:07 +02:00
}
2018-04-24 14:11:23 +02:00
void Tab :: set_tooltips_text ()
{
2019-08-06 16:51:32 +02:00
// --- Tooltip text for reset buttons (for whole options group)
// Text to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
m_ttg_value_lock = _ ( L ( "LOCKED LOCK icon indicates that the settings are the same as the system (or default) values "
"for the current option group" ));
m_ttg_value_unlock = _ ( L ( "UNLOCKED LOCK icon indicates that some settings were changed and are not equal "
"to the system (or default) values for the current option group. \n "
"Click to reset all settings for current option group to the system (or default) values." ));
m_ttg_white_bullet_ns = _ ( L ( "WHITE BULLET icon indicates a non system (or non default) preset." ));
m_ttg_non_system = & m_ttg_white_bullet_ns ;
// Text to be shown on the "Undo user changes" button next to each input field.
m_ttg_white_bullet = _ ( L ( "WHITE BULLET icon indicates that the settings are the same as in the last saved "
"preset for the current option group." ));
m_ttg_value_revert = _ ( L ( "BACK ARROW icon indicates that the settings were changed and are not equal to "
"the last saved preset for the current option group. \n "
"Click to reset all settings for the current option group to the last saved preset." ));
2018-04-24 14:11:23 +02:00
2019-08-06 16:51:32 +02:00
// --- Tooltip text for reset buttons (for each option in group)
// Text to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
m_tt_value_lock = _ ( L ( "LOCKED LOCK icon indicates that the value is the same as the system (or default) value." ));
m_tt_value_unlock = _ ( L ( "UNLOCKED LOCK icon indicates that the value was changed and is not equal "
"to the system (or default) value. \n "
"Click to reset current value to the system (or default) value." ));
// m_tt_white_bullet_ns= _(L("WHITE BULLET icon indicates a non system preset."));
m_tt_non_system = & m_ttg_white_bullet_ns ;
// Text to be shown on the "Undo user changes" button next to each input field.
m_tt_white_bullet = _ ( L ( "WHITE BULLET icon indicates that the value is the same as in the last saved preset." ));
m_tt_value_revert = _ ( L ( "BACK ARROW icon indicates that the value was changed and is not equal to the last saved preset. \n "
"Click to reset current value to the last saved preset." ));
2018-04-24 14:11:23 +02:00
}
2020-11-02 15:28:43 +01:00
Page :: Page ( wxWindow * parent , const wxString & title , int iconID ) :
2020-05-27 13:19:26 +02:00
m_parent ( parent ),
m_title ( title ),
2020-11-02 15:28:43 +01:00
m_iconID ( iconID )
2020-05-27 13:19:26 +02:00
{
2020-09-24 18:54:54 +02:00
m_vsizer = ( wxBoxSizer * ) parent -> GetSizer ();
2020-05-27 13:19:26 +02:00
m_item_color = & wxGetApp (). get_label_clr_default ();
}
2018-01-11 10:33:17 +01:00
void Page :: reload_config ()
{
2019-08-06 16:51:32 +02:00
for ( auto group : m_optgroups )
group -> reload_config ();
2018-01-11 10:33:17 +01:00
}
2020-09-22 11:17:43 +02:00
void Page :: update_visibility ( ConfigOptionMode mode , bool update_contolls_visibility )
2018-10-19 13:55:29 +02:00
{
2018-10-21 23:09:24 +02:00
bool ret_val = false ;
2020-09-22 11:17:43 +02:00
for ( auto group : m_optgroups ) {
ret_val = ( update_contolls_visibility ?
group -> update_visibility ( mode ) : // update visibility for all controlls in group
group -> is_visible ( mode ) // just detect visibility for the group
) || ret_val ;
}
2018-10-21 23:09:24 +02:00
m_show = ret_val ;
2018-10-19 13:55:29 +02:00
}
2020-09-29 13:36:56 +02:00
void Page :: activate ( ConfigOptionMode mode , std :: function < void () > throw_if_canceled )
2020-09-22 11:17:43 +02:00
{
for ( auto group : m_optgroups ) {
2020-09-29 13:36:56 +02:00
if ( ! group -> activate ( throw_if_canceled ))
2020-09-24 18:54:54 +02:00
continue ;
2020-11-18 12:08:09 +01:00
m_vsizer -> Add ( group -> sizer , 0 , wxEXPAND | ( group -> is_legend_line () ? ( wxLEFT | wxTOP ) : wxALL ), 10 );
2020-09-22 11:17:43 +02:00
group -> update_visibility ( mode );
group -> reload_config ();
2020-09-29 13:36:56 +02:00
throw_if_canceled ();
2020-09-22 11:17:43 +02:00
}
}
void Page :: clear ()
{
for ( auto group : m_optgroups )
group -> clear ();
}
2019-04-25 01:45:00 +02:00
void Page :: msw_rescale ()
2019-04-13 23:46:52 +02:00
{
for ( auto group : m_optgroups )
2019-04-25 01:45:00 +02:00
group -> msw_rescale ();
2019-04-13 23:46:52 +02:00
}
2020-05-22 15:23:05 +02:00
void Page :: sys_color_changed ()
{
for ( auto group : m_optgroups )
group -> sys_color_changed ();
}
2020-10-26 19:38:09 +01:00
void Page :: refresh ()
{
for ( auto group : m_optgroups )
group -> refresh ();
}
2018-04-13 12:35:04 +02:00
Field * Page :: get_field ( const t_config_option_key & opt_key , int opt_index /*= -1*/ ) const
2018-01-11 10:33:17 +01:00
{
2019-08-06 16:51:32 +02:00
Field * field = nullptr ;
for ( auto opt : m_optgroups ) {
field = opt -> get_fieldc ( opt_key , opt_index );
if ( field != nullptr )
return field ;
}
return field ;
2018-01-11 10:33:17 +01:00
}
2018-10-31 12:56:08 +01:00
bool Page :: set_value ( const t_config_option_key & opt_key , const boost :: any & value ) {
2019-08-06 16:51:32 +02:00
bool changed = false ;
for ( auto optgroup : m_optgroups ) {
if ( optgroup -> set_value ( opt_key , value ))
2020-09-24 18:54:54 +02:00
changed = true ;
2019-08-06 16:51:32 +02:00
}
return changed ;
2018-01-16 16:28:01 +01:00
}
2017-12-13 14:45:10 +01:00
// package Slic3r::GUI::Tab::Page;
2018-04-13 12:35:04 +02:00
ConfigOptionsGroupShp Page :: new_optgroup ( const wxString & title , int noncommon_label_width /*= -1*/ )
2017-12-13 14:45:10 +01:00
{
2019-08-06 16:51:32 +02:00
//! config_ have to be "right"
2020-11-02 15:28:43 +01:00
ConfigOptionsGroupShp optgroup = std :: make_shared < ConfigOptionsGroup > ( m_parent , title , m_config , true );
2020-09-24 15:34:13 +02:00
optgroup -> set_config_category ( m_title . ToStdString ());
2019-08-06 16:51:32 +02:00
if ( noncommon_label_width >= 0 )
optgroup -> label_width = noncommon_label_width ;
2017-12-13 14:45:10 +01:00
2018-07-02 13:51:50 +02:00
#ifdef __WXOSX__
2020-09-24 18:54:54 +02:00
auto tab = parent () -> GetParent () -> GetParent (); // GetParent()->GetParent();
2018-07-02 13:51:50 +02:00
#else
2020-09-24 18:54:54 +02:00
auto tab = parent () -> GetParent (); // GetParent();
2018-07-02 13:51:50 +02:00
#endif
2021-01-29 16:16:23 +01:00
optgroup -> m_on_change = [ tab ]( t_config_option_key opt_key , boost :: any value ) {
2019-08-06 16:51:32 +02:00
//! This function will be called from OptionGroup.
//! Using of CallAfter is redundant.
//! And in some cases it causes update() function to be recalled again
2018-01-18 16:36:26 +01:00
//! wxTheApp->CallAfter([this, opt_key, value]() {
2019-08-06 16:51:32 +02:00
static_cast < Tab *> ( tab ) -> update_dirty ();
static_cast < Tab *> ( tab ) -> on_value_change ( opt_key , value );
2018-01-18 16:36:26 +01:00
//! });
2019-08-06 16:51:32 +02:00
};
2017-12-13 14:45:10 +01:00
2021-01-29 16:16:23 +01:00
optgroup -> m_get_initial_config = [ tab ]() {
2019-08-06 16:51:32 +02:00
DynamicPrintConfig config = static_cast < Tab *> ( tab ) -> m_presets -> get_selected_preset (). config ;
return config ;
};
2018-03-06 12:34:20 +01:00
2021-01-29 16:16:23 +01:00
optgroup -> m_get_sys_config = [ tab ]() {
2019-08-06 16:51:32 +02:00
DynamicPrintConfig config = static_cast < Tab *> ( tab ) -> m_presets -> get_selected_preset_parent () -> config ;
return config ;
};
2018-03-16 17:25:11 +01:00
2021-01-29 16:16:23 +01:00
optgroup -> have_sys_config = [ tab ]() {
2019-08-06 16:51:32 +02:00
return static_cast < Tab *> ( tab ) -> m_presets -> get_selected_preset_parent () != nullptr ;
};
2018-03-16 17:25:11 +01:00
2021-01-29 16:16:23 +01:00
optgroup -> rescale_extra_column_item = []( wxWindow * win ) {
2019-04-13 23:46:52 +02:00
auto * ctrl = dynamic_cast < wxStaticBitmap *> ( win );
if ( ctrl == nullptr )
return ;
2019-04-25 01:45:00 +02:00
ctrl -> SetBitmap ( reinterpret_cast < ScalableBitmap *> ( ctrl -> GetClientData ()) -> bmp ());
2019-04-13 23:46:52 +02:00
};
2019-08-06 16:51:32 +02:00
m_optgroups . push_back ( optgroup );
2017-12-13 14:45:10 +01:00
2019-08-06 16:51:32 +02:00
return optgroup ;
2017-12-13 14:45:10 +01:00
}
2021-02-22 08:13:48 +01:00
#if ENABLE_VALIDATE_CUSTOM_GCODE
const ConfigOptionsGroupShp Page :: get_optgroup ( const wxString & title ) const
{
for ( ConfigOptionsGroupShp optgroup : m_optgroups ) {
if ( optgroup -> title == title )
return optgroup ;
}
return nullptr ;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
2018-08-03 13:04:41 +02:00
void TabSLAMaterial :: build ()
{
m_presets = & m_preset_bundle -> sla_materials ;
load_initial_data ();
2020-04-13 17:55:38 +02:00
auto page = add_options_page ( L ( "Material" ), "resin" );
2018-08-03 13:04:41 +02:00
2020-04-13 17:55:38 +02:00
auto optgroup = page -> new_optgroup ( L ( "Material" ));
2019-09-26 16:33:55 +02:00
optgroup -> append_single_option_line ( "bottle_cost" );
optgroup -> append_single_option_line ( "bottle_volume" );
optgroup -> append_single_option_line ( "bottle_weight" );
optgroup -> append_single_option_line ( "material_density" );
optgroup -> m_on_change = [ this , optgroup ]( t_config_option_key opt_key , boost :: any value )
{
DynamicPrintConfig new_conf = * m_config ;
if ( opt_key == "bottle_volume" ) {
2020-01-07 08:46:11 +01:00
double new_bottle_weight = boost :: any_cast < double > ( value ) * ( new_conf . option ( "material_density" ) -> getFloat () / 1000 );
2019-09-26 16:33:55 +02:00
new_conf . set_key_value ( "bottle_weight" , new ConfigOptionFloat ( new_bottle_weight ));
}
if ( opt_key == "bottle_weight" ) {
2020-01-08 15:23:46 +01:00
double new_bottle_volume = boost :: any_cast < double > ( value ) / new_conf . option ( "material_density" ) -> getFloat () * 1000 ;
2019-09-26 16:33:55 +02:00
new_conf . set_key_value ( "bottle_volume" , new ConfigOptionFloat ( new_bottle_volume ));
}
if ( opt_key == "material_density" ) {
2020-01-07 08:46:11 +01:00
double new_bottle_volume = new_conf . option ( "bottle_weight" ) -> getFloat () / boost :: any_cast < double > ( value ) * 1000 ;
2019-09-27 12:08:08 +02:00
new_conf . set_key_value ( "bottle_volume" , new ConfigOptionFloat ( new_bottle_volume ));
2019-09-26 16:33:55 +02:00
}
load_config ( new_conf );
update_dirty ();
2020-01-08 15:23:46 +01:00
// Change of any from those options influences for an update of "Sliced Info"
wxGetApp (). sidebar (). update_sliced_info_sizer ();
wxGetApp (). sidebar (). Layout ();
2019-09-26 16:33:55 +02:00
};
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Layers" ));
2018-08-03 13:04:41 +02:00
optgroup -> append_single_option_line ( "initial_layer_height" );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Exposure" ));
2018-08-03 13:04:41 +02:00
optgroup -> append_single_option_line ( "exposure_time" );
optgroup -> append_single_option_line ( "initial_exposure_time" );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Corrections" ));
2019-04-03 17:34:46 +02:00
std :: vector < std :: string > corrections = { "material_correction" };
2019-04-11 17:07:41 +02:00
// std::vector<std::string> axes{ "X", "Y", "Z" };
std :: vector < std :: string > axes { "XY" , "Z" };
2018-10-31 12:56:08 +01:00
for ( auto & opt_key : corrections ) {
2020-04-13 17:55:38 +02:00
auto line = Line { m_config -> def () -> get ( opt_key ) -> full_label , "" };
2018-08-03 16:20:39 +02:00
int id = 0 ;
for ( auto & axis : axes ) {
auto opt = optgroup -> get_option ( opt_key , id );
opt . opt . label = axis ;
line . append_option ( opt );
++ id ;
}
optgroup -> append_line ( line );
}
2018-08-03 13:04:41 +02:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Notes" ), "note.png" );
optgroup = page -> new_optgroup ( L ( "Notes" ), 0 );
2018-08-03 13:04:41 +02:00
optgroup -> label_width = 0 ;
Option option = optgroup -> get_option ( "material_notes" );
option . opt . full_width = true ;
2019-04-13 23:46:52 +02:00
option . opt . height = 25 ; //250;
2018-08-03 13:04:41 +02:00
optgroup -> append_single_option_line ( option );
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Dependencies" ), "wrench.png" );
optgroup = page -> new_optgroup ( L ( "Profile dependencies" ));
2020-03-04 20:58:14 +01:00
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "compatible_printers" , wxEmptyString , [ this ]( wxWindow * parent ) {
2018-12-04 17:56:49 +01:00
return compatible_widget_create ( parent , m_compatible_printers );
2020-03-04 20:58:14 +01:00
});
2018-08-03 13:04:41 +02:00
option = optgroup -> get_option ( "compatible_printers_condition" );
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "compatible_prints" , wxEmptyString , [ this ]( wxWindow * parent ) {
2019-08-06 16:51:32 +02:00
return compatible_widget_create ( parent , m_compatible_prints );
2020-03-04 20:58:14 +01:00
});
2019-08-06 16:51:32 +02:00
option = optgroup -> get_option ( "compatible_prints_condition" );
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2018-12-04 17:56:49 +01:00
2020-03-04 13:47:35 +01:00
build_preset_description_line ( optgroup . get ());
2018-08-03 13:04:41 +02:00
}
2018-12-04 17:56:49 +01:00
// Reload current config (aka presets->edited_preset->config) into the UI fields.
void TabSLAMaterial :: reload_config ()
{
2019-08-06 16:51:32 +02:00
this -> compatible_widget_reload ( m_compatible_printers );
this -> compatible_widget_reload ( m_compatible_prints );
Tab :: reload_config ();
2018-12-04 17:56:49 +01:00
}
2018-08-03 13:04:41 +02:00
void TabSLAMaterial :: update ()
{
2018-10-04 16:43:10 +02:00
if ( m_preset_bundle -> printers . get_selected_preset (). printer_technology () == ptFFF )
2019-06-06 14:14:29 +02:00
return ;
2019-08-06 16:51:32 +02:00
2019-06-06 14:14:29 +02:00
// #ys_FIXME. Just a template for this function
2019-02-22 09:38:56 +01:00
// m_update_cnt++;
// ! something to update
// m_update_cnt--;
2019-08-06 16:51:32 +02:00
//
2019-02-22 09:38:56 +01:00
// if (m_update_cnt == 0)
wxGetApp (). mainframe -> on_config_changed ( m_config );
2018-11-16 17:36:23 +01:00
}
void TabSLAPrint :: build ()
{
m_presets = & m_preset_bundle -> sla_prints ;
load_initial_data ();
2020-04-13 17:55:38 +02:00
auto page = add_options_page ( L ( "Layers and perimeters" ), "layers" );
2018-11-16 17:36:23 +01:00
2020-04-13 17:55:38 +02:00
auto optgroup = page -> new_optgroup ( L ( "Layers" ));
2018-11-16 17:36:23 +01:00
optgroup -> append_single_option_line ( "layer_height" );
2019-02-18 16:04:55 +01:00
optgroup -> append_single_option_line ( "faded_layers" );
2018-11-16 17:36:23 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Supports" ), "support" /*"sla_supports"*/ );
optgroup = page -> new_optgroup ( L ( "Supports" ));
2018-11-22 18:02:05 +01:00
optgroup -> append_single_option_line ( "supports_enable" );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Support head" ));
2018-11-23 13:03:07 +01:00
optgroup -> append_single_option_line ( "support_head_front_diameter" );
2018-11-19 09:15:53 +01:00
optgroup -> append_single_option_line ( "support_head_penetration" );
optgroup -> append_single_option_line ( "support_head_width" );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Support pillar" ));
2018-11-23 13:03:07 +01:00
optgroup -> append_single_option_line ( "support_pillar_diameter" );
2020-07-08 11:31:01 +02:00
optgroup -> append_single_option_line ( "support_small_pillar_diameter_percent" );
2020-03-02 12:43:00 +01:00
optgroup -> append_single_option_line ( "support_max_bridges_on_pillar" );
2019-01-09 12:21:43 +01:00
optgroup -> append_single_option_line ( "support_pillar_connection_mode" );
2019-02-05 11:16:03 +01:00
optgroup -> append_single_option_line ( "support_buildplate_only" );
2019-03-11 14:55:28 +01:00
// TODO: This parameter is not used at the moment.
// optgroup->append_single_option_line("support_pillar_widening_factor");
2018-11-23 13:03:07 +01:00
optgroup -> append_single_option_line ( "support_base_diameter" );
2018-11-19 09:15:53 +01:00
optgroup -> append_single_option_line ( "support_base_height" );
2019-06-11 17:57:39 +02:00
optgroup -> append_single_option_line ( "support_base_safety_distance" );
2019-08-28 11:32:49 +02:00
// Mirrored parameter from Pad page for toggling elevation on the same page
2018-11-19 17:58:08 +01:00
optgroup -> append_single_option_line ( "support_object_elevation" );
2018-11-19 09:15:53 +01:00
2020-08-13 11:14:44 +02:00
Line line { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_support_object_elevation_description_line );
};
optgroup -> append_line ( line );
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Connection of the support sticks and junctions" ));
2018-11-19 09:15:53 +01:00
optgroup -> append_single_option_line ( "support_critical_angle" );
optgroup -> append_single_option_line ( "support_max_bridge_length" );
2019-03-08 11:39:34 +01:00
optgroup -> append_single_option_line ( "support_max_pillar_link_distance" );
2018-11-19 09:15:53 +01:00
2020-04-13 17:55:38 +02:00
optgroup = page -> new_optgroup ( L ( "Automatic generation" ));
2019-02-19 16:34:52 +01:00
optgroup -> append_single_option_line ( "support_points_density_relative" );
optgroup -> append_single_option_line ( "support_points_minimal_distance" );
2018-12-07 14:10:16 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Pad" ), "pad" );
optgroup = page -> new_optgroup ( L ( "Pad" ));
2018-11-20 16:12:04 +01:00
optgroup -> append_single_option_line ( "pad_enable" );
2018-11-19 09:15:53 +01:00
optgroup -> append_single_option_line ( "pad_wall_thickness" );
optgroup -> append_single_option_line ( "pad_wall_height" );
2019-09-24 15:15:49 +02:00
optgroup -> append_single_option_line ( "pad_brim_size" );
2018-11-19 09:15:53 +01:00
optgroup -> append_single_option_line ( "pad_max_merge_distance" );
2019-02-25 12:06:38 +01:00
// TODO: Disabling this parameter for the beta release
// optgroup->append_single_option_line("pad_edge_radius");
2019-02-25 16:04:46 +01:00
optgroup -> append_single_option_line ( "pad_wall_slope" );
2019-08-06 16:51:32 +02:00
2019-08-28 11:32:49 +02:00
optgroup -> append_single_option_line ( "pad_around_object" );
2019-09-24 15:15:49 +02:00
optgroup -> append_single_option_line ( "pad_around_object_everywhere" );
2019-06-12 13:15:42 +02:00
optgroup -> append_single_option_line ( "pad_object_gap" );
2019-06-11 17:57:39 +02:00
optgroup -> append_single_option_line ( "pad_object_connector_stride" );
optgroup -> append_single_option_line ( "pad_object_connector_width" );
optgroup -> append_single_option_line ( "pad_object_connector_penetration" );
2019-11-06 13:38:43 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Hollowing" ), "hollowing" );
optgroup = page -> new_optgroup ( L ( "Hollowing" ));
2019-11-06 13:38:43 +01:00
optgroup -> append_single_option_line ( "hollowing_enable" );
optgroup -> append_single_option_line ( "hollowing_min_thickness" );
2019-11-08 09:21:30 +01:00
optgroup -> append_single_option_line ( "hollowing_quality" );
2019-11-08 16:51:43 +01:00
optgroup -> append_single_option_line ( "hollowing_closing_distance" );
2019-03-01 17:53:02 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Advanced" ), "wrench" );
optgroup = page -> new_optgroup ( L ( "Slicing" ));
2019-08-06 16:51:32 +02:00
optgroup -> append_single_option_line ( "slice_closing_radius" );
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Output options" ), "output+page_white" );
optgroup = page -> new_optgroup ( L ( "Output file" ));
2019-08-06 16:51:32 +02:00
Option option = optgroup -> get_option ( "output_filename_format" );
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2018-12-03 13:14:28 +01:00
2020-04-13 17:55:38 +02:00
page = add_options_page ( L ( "Dependencies" ), "wrench" );
optgroup = page -> new_optgroup ( L ( "Profile dependencies" ));
2020-03-04 20:58:14 +01:00
2020-10-29 21:53:33 +01:00
create_line_with_widget ( optgroup . get (), "compatible_printers" , wxEmptyString , [ this ]( wxWindow * parent ) {
2018-12-04 17:56:49 +01:00
return compatible_widget_create ( parent , m_compatible_printers );
2020-03-04 20:58:14 +01:00
});
2018-11-16 17:36:23 +01:00
2018-12-03 13:14:28 +01:00
option = optgroup -> get_option ( "compatible_printers_condition" );
2018-11-16 17:36:23 +01:00
option . opt . full_width = true ;
optgroup -> append_single_option_line ( option );
2020-03-04 13:47:35 +01:00
build_preset_description_line ( optgroup . get ());
2018-11-16 17:36:23 +01:00
}
2018-12-04 17:56:49 +01:00
// Reload current config (aka presets->edited_preset->config) into the UI fields.
void TabSLAPrint :: reload_config ()
{
2019-08-06 16:51:32 +02:00
this -> compatible_widget_reload ( m_compatible_printers );
Tab :: reload_config ();
2018-12-04 17:56:49 +01:00
}
2020-09-22 11:17:43 +02:00
void TabSLAPrint :: update_description_lines ()
{
Tab :: update_description_lines ();
if ( m_active_page && m_active_page -> title () == "Supports" )
{
bool is_visible = m_config -> def () -> get ( "support_object_elevation" ) -> mode <= m_mode ;
if ( m_support_object_elevation_description_line )
{
m_support_object_elevation_description_line -> Show ( is_visible );
if ( is_visible )
{
bool elev = ! m_config -> opt_bool ( "pad_enable" ) || ! m_config -> opt_bool ( "pad_around_object" );
m_support_object_elevation_description_line -> SetText ( elev ? "" :
from_u8 (( boost :: format ( _u8L ( " \" %1% \" is disabled because \" %2% \" is on in \" %3% \" category. \n "
"To enable \" %1% \" , please switch off \" %2% \" " ))
% _L ( "Object elevation" ) % _L ( "Pad around object" ) % _L ( "Pad" )). str ()));
}
}
}
}
void TabSLAPrint :: toggle_options ()
{
if ( m_active_page )
m_config_manipulation . toggle_print_sla_options ( m_config );
}
2018-11-16 17:36:23 +01:00
void TabSLAPrint :: update ()
{
if ( m_preset_bundle -> printers . get_selected_preset (). printer_technology () == ptFFF )
2019-06-06 14:14:29 +02:00
return ;
2019-02-22 09:38:56 +01:00
2019-08-06 16:51:32 +02:00
m_update_cnt ++ ;
2019-08-22 13:19:01 +02:00
m_config_manipulation . update_print_sla_config ( m_config , true );
2020-08-13 11:14:44 +02:00
2020-09-22 11:17:43 +02:00
update_description_lines ();
2020-08-13 11:14:44 +02:00
Layout ();
2019-06-11 17:57:39 +02:00
m_update_cnt -- ;
2019-08-22 13:19:01 +02:00
if ( m_update_cnt == 0 ) {
2020-09-22 11:17:43 +02:00
toggle_options ();
2019-08-22 14:21:50 +02:00
2020-03-20 13:41:36 +01:00
// update() could be called during undo/redo execution
// Update of objectList can cause a crash in this case (because m_objects doesn't match ObjectList)
if ( ! wxGetApp (). plater () -> inside_snapshot_capture ())
wxGetApp (). obj_list () -> update_and_show_object_settings_item ();
2019-08-22 14:21:50 +02:00
2019-08-22 13:19:01 +02:00
wxGetApp (). mainframe -> on_config_changed ( m_config );
2019-08-16 16:47:29 +02:00
}
}
2020-09-22 11:17:43 +02:00
void TabSLAPrint :: clear_pages ()
{
Tab :: clear_pages ();
m_support_object_elevation_description_line = nullptr ;
}
2019-08-22 13:19:01 +02:00
ConfigManipulation Tab :: get_config_manipulation ()
2019-08-22 10:25:19 +02:00
{
2019-08-22 13:19:01 +02:00
auto load_config = [ this ]()
2019-08-16 16:47:29 +02:00
{
2019-08-22 13:19:01 +02:00
update_dirty ();
// Initialize UI components with the config values.
reload_config ();
update ();
};
2019-08-16 16:47:29 +02:00
2020-09-22 11:17:43 +02:00
auto cb_toggle_field = [ this ]( const t_config_option_key & opt_key , bool toggle , int opt_index ) {
return toggle_option ( opt_key , toggle , opt_index );
2019-08-22 13:19:01 +02:00
};
2019-08-16 16:47:29 +02:00
2019-08-22 13:19:01 +02:00
auto cb_value_change = [ this ]( const std :: string & opt_key , const boost :: any & value ) {
return on_value_change ( opt_key , value );
};
2019-08-16 16:47:29 +02:00
2020-09-22 11:17:43 +02:00
return ConfigManipulation ( load_config , cb_toggle_field , cb_value_change );
2019-08-22 10:25:19 +02:00
}
2019-08-16 16:47:29 +02:00
2017-12-05 15:54:01 +01:00
} // GUI
} // Slic3r