2018-01-03 10:12:42 +01:00
#include "../../libslic3r/GCodeSender.hpp"
2018-01-25 13:46:04 +01:00
#include "Tab.hpp"
#include "PresetBundle.hpp"
#include "PresetHints.hpp"
#include "../../libslic3r/Utils.hpp"
2018-03-16 14:06:23 +01:00
2018-03-15 18:06:26 +01:00
#include "slic3r/Utils/Http.hpp"
#include "slic3r/Utils/OctoPrint.hpp"
2018-05-21 16:14:20 +02:00
#include "slic3r/Utils/Serial.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"
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>
2018-04-06 13:37:00 +02:00
#include "wxExtensions.hpp"
2018-04-17 10:15:48 +02:00
#include <wx/wupdlock.h>
2018-01-03 10:12:42 +01:00
2018-04-18 13:32:21 +02:00
#include <chrono>
2018-01-03 10:12:42 +01:00
2017-12-05 15:54:01 +01:00
namespace Slic3r {
namespace GUI {
2018-06-07 22:10:23 +02:00
static wxString dots ( "…" , wxConvUTF8 );
2017-12-05 15:54:01 +01:00
// sub new
2018-01-05 15:11:33 +01:00
void Tab :: create_preset_tab ( PresetBundle * preset_bundle )
2017-12-05 15:54:01 +01:00
{
2017-12-26 23:04:54 +01:00
m_preset_bundle = preset_bundle ;
2018-01-05 15:11:33 +01:00
2017-12-05 15:54:01 +01:00
// Vertical sizer to hold the choice menu and the rest of the page.
2018-01-05 15:11:33 +01:00
Tab * panel = this ;
2017-12-05 15:54:01 +01:00
auto * sizer = new wxBoxSizer ( wxVERTICAL );
sizer -> SetSizeHints ( panel );
panel -> SetSizer ( sizer );
// preset chooser
2018-01-16 16:28:01 +01:00
m_presets_choice = new wxBitmapComboBox ( panel , wxID_ANY , "" , wxDefaultPosition , wxSize ( 270 , - 1 ), 0 , 0 , wxCB_READONLY );
2018-04-11 13:56:37 +02:00
/*
m_cc_presets_choice = new wxComboCtrl(panel, wxID_ANY, L(""), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
2018-04-06 13:37:00 +02:00
wxDataViewTreeCtrlComboPopup* popup = new wxDataViewTreeCtrlComboPopup;
if (popup != nullptr)
{
// FIXME If the following line is removed, the combo box popup list will not react to mouse clicks.
// On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10.
2018-04-09 12:41:25 +02:00
// m_cc_presets_choice->UseAltPopupWindow();
2018-03-06 09:44:53 +01:00
2018-04-09 12:41:25 +02:00
// m_cc_presets_choice->EnablePopupAnimation(false);
2018-04-06 13:37:00 +02:00
m_cc_presets_choice->SetPopupControl(popup);
popup->SetStringValue(from_u8("Text1"));
popup->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this, popup](wxCommandEvent& evt)
{
auto selected = popup->GetItemText(popup->GetSelection());
if (selected != _(L("System presets")) && selected != _(L("Default presets")))
2018-04-06 15:42:52 +02:00
{
2018-04-06 13:37:00 +02:00
m_cc_presets_choice->SetText(selected);
2018-04-06 15:42:52 +02:00
std::string selected_string = selected.ToUTF8().data();
2018-04-10 14:52:03 +02:00
#ifdef __APPLE__
#else
select_preset(selected_string);
#endif
2018-04-06 15:42:52 +02:00
}
2018-04-06 13:37:00 +02:00
});
2018-04-06 15:42:52 +02:00
2018-04-09 16:50:17 +02:00
// popup->Bind(wxEVT_KEY_DOWN, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); });
// popup->Bind(wxEVT_KEY_UP, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); });
2018-04-06 13:37:00 +02:00
auto icons = new wxImageList(16, 16, true, 1);
popup->SetImageList(icons);
icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG));
2018-04-06 15:42:52 +02:00
icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG));
2018-04-06 13:37:00 +02:00
}
2018-04-11 13:56:37 +02:00
*/
2018-03-06 09:44:53 +01:00
auto color = wxSystemSettings :: GetColour ( wxSYS_COLOUR_WINDOW );
2017-12-05 15:54:01 +01:00
//buttons
wxBitmap bmpMenu ;
2018-02-22 11:34:41 +01:00
bmpMenu = wxBitmap ( from_u8 ( Slic3r :: var ( "disk.png" )), wxBITMAP_TYPE_PNG );
2017-12-26 23:04:54 +01:00
m_btn_save_preset = new wxBitmapButton ( panel , wxID_ANY , bmpMenu , wxDefaultPosition , wxDefaultSize , wxBORDER_NONE );
2018-03-06 13:34:39 +01:00
if ( wxMSW ) m_btn_save_preset -> SetBackgroundColour ( color );
2018-02-22 11:34:41 +01:00
bmpMenu = wxBitmap ( from_u8 ( Slic3r :: var ( "delete.png" )), wxBITMAP_TYPE_PNG );
2017-12-26 23:04:54 +01:00
m_btn_delete_preset = new wxBitmapButton ( panel , wxID_ANY , bmpMenu , wxDefaultPosition , wxDefaultSize , wxBORDER_NONE );
2018-03-06 13:34:39 +01:00
if ( wxMSW ) m_btn_delete_preset -> SetBackgroundColour ( color );
2017-12-05 15:54:01 +01:00
2018-01-16 16:28:01 +01:00
m_show_incompatible_presets = false ;
2018-04-16 11:03:08 +02:00
m_bmp_show_incompatible_presets . LoadFile ( from_u8 ( Slic3r :: var ( "flag-red-icon.png" )), wxBITMAP_TYPE_PNG );
m_bmp_hide_incompatible_presets . LoadFile ( from_u8 ( Slic3r :: var ( "flag-green-icon.png" )), wxBITMAP_TYPE_PNG );
m_btn_hide_incompatible_presets = new wxBitmapButton ( panel , wxID_ANY , m_bmp_hide_incompatible_presets , wxDefaultPosition , wxDefaultSize , wxBORDER_NONE );
2018-03-06 13:34:39 +01:00
if ( wxMSW ) m_btn_hide_incompatible_presets -> SetBackgroundColour ( color );
2017-12-05 15:54:01 +01:00
2018-02-23 09:16:35 +01:00
m_btn_save_preset -> SetToolTip ( _ ( L ( "Save current " )) + m_title );
m_btn_delete_preset -> SetToolTip ( _ ( L ( "Delete this preset" )));
2017-12-26 23:04:54 +01:00
m_btn_delete_preset -> Disable ();
2017-12-05 15:54:01 +01:00
2018-03-21 22:21:37 +01:00
m_undo_btn = new wxButton ( panel , wxID_ANY , "" , wxDefaultPosition , wxDefaultSize , wxBU_EXACTFIT | wxNO_BORDER );
m_undo_to_sys_btn = new wxButton ( panel , wxID_ANY , "" , wxDefaultPosition , wxDefaultSize , wxBU_EXACTFIT | wxNO_BORDER );
2018-04-19 16:20:30 +02:00
m_question_btn = new wxButton ( panel , wxID_ANY , "" , wxDefaultPosition , wxDefaultSize , wxBU_EXACTFIT | wxNO_BORDER );
2018-03-21 22:21:37 +01:00
if ( wxMSW ) {
m_undo_btn -> SetBackgroundColour ( color );
m_undo_to_sys_btn -> SetBackgroundColour ( color );
2018-04-19 16:20:30 +02:00
m_question_btn -> SetBackgroundColour ( color );
2018-03-21 22:21:37 +01:00
}
2018-04-19 16:20:30 +02:00
2018-04-30 14:20:33 +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
2018-04-23 10:27:42 +02:00
// Determine the theme color of OS (dark or light)
auto luma = get_colour_approx_luma ( wxSystemSettings :: GetColour ( wxSYS_COLOUR_WINDOW ));
2018-04-16 11:03:08 +02:00
// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
m_bmp_value_lock . LoadFile ( from_u8 ( var ( "sys_lock.png" )), wxBITMAP_TYPE_PNG );
2018-04-23 10:27:42 +02:00
m_bmp_value_unlock . LoadFile ( from_u8 ( var ( luma >= 128 ? "sys_unlock.png" : "sys_unlock_grey.png" )), wxBITMAP_TYPE_PNG );
2018-04-16 11:03:08 +02:00
m_bmp_non_system = & m_bmp_white_bullet ;
// Bitmaps to be shown on the "Undo user changes" button next to each input field.
2018-04-23 10:27:42 +02:00
m_bmp_value_revert . LoadFile ( from_u8 ( var ( luma >= 128 ? "action_undo.png" : "action_undo_grey.png" )), wxBITMAP_TYPE_PNG );
m_bmp_white_bullet . LoadFile ( from_u8 ( var ( "bullet_white.png" )), wxBITMAP_TYPE_PNG );
2018-04-19 16:20:30 +02:00
m_bmp_question . LoadFile ( from_u8 ( var ( "question_mark_01.png" )), wxBITMAP_TYPE_PNG );
2018-04-20 12:58:07 +02:00
fill_icon_descriptions ();
2018-04-24 14:11:23 +02:00
set_tooltips_text ();
2018-04-20 12:58:07 +02:00
2018-04-16 11:03:08 +02:00
m_undo_btn -> SetBitmap ( m_bmp_white_bullet );
2018-04-19 16:20:30 +02:00
m_undo_btn -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent ){ on_roll_back_value (); }));
2018-04-16 11:03:08 +02:00
m_undo_to_sys_btn -> SetBitmap ( m_bmp_white_bullet );
2018-04-19 16:20:30 +02:00
m_undo_to_sys_btn -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent ){ on_roll_back_value ( true ); }));
m_question_btn -> SetBitmap ( m_bmp_question );
2018-04-20 12:58:07 +02:00
m_question_btn -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent )
{
2018-04-20 15:02:54 +02:00
auto dlg = new ButtonsDescription ( this , & m_icon_descriptions );
2018-04-30 14:20:33 +02:00
if ( dlg -> ShowModal () == wxID_OK ){
// Colors for ui "decoration"
for ( Tab * tab : get_tabs_list ()){
tab -> m_sys_label_clr = get_label_clr_sys ();
tab -> m_modified_label_clr = get_label_clr_modified ();
tab -> update_labels_colour ();
}
}
2018-04-20 12:58:07 +02:00
}));
2018-03-21 22:21:37 +01:00
2018-04-17 10:15:48 +02:00
// Colors for ui "decoration"
2018-04-30 14:20:33 +02:00
m_sys_label_clr = get_label_clr_sys ();
m_modified_label_clr = get_label_clr_modified ();
m_default_text_clr = get_label_clr_default ();
2018-03-21 22:21:37 +01:00
2017-12-26 23:04:54 +01:00
m_hsizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( m_hsizer , 0 , wxBOTTOM , 3 );
m_hsizer -> Add ( m_presets_choice , 1 , wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL , 3 );
m_hsizer -> AddSpacer ( 4 );
m_hsizer -> Add ( m_btn_save_preset , 0 , wxALIGN_CENTER_VERTICAL );
m_hsizer -> AddSpacer ( 4 );
m_hsizer -> Add ( m_btn_delete_preset , 0 , wxALIGN_CENTER_VERTICAL );
m_hsizer -> AddSpacer ( 16 );
m_hsizer -> Add ( m_btn_hide_incompatible_presets , 0 , wxALIGN_CENTER_VERTICAL );
2018-03-21 22:21:37 +01:00
m_hsizer -> AddSpacer ( 64 );
m_hsizer -> Add ( m_undo_to_sys_btn , 0 , wxALIGN_CENTER_VERTICAL );
m_hsizer -> Add ( m_undo_btn , 0 , wxALIGN_CENTER_VERTICAL );
2018-04-20 12:58:07 +02:00
m_hsizer -> AddSpacer ( 32 );
2018-04-19 16:20:30 +02:00
m_hsizer -> Add ( m_question_btn , 0 , wxALIGN_CENTER_VERTICAL );
2018-04-11 13:56:37 +02:00
// m_hsizer->Add(m_cc_presets_choice, 1, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, 3);
2017-12-05 15:54:01 +01:00
//Horizontal sizer to hold the tree and the selected page.
2017-12-26 23:04:54 +01:00
m_hsizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( m_hsizer , 1 , wxEXPAND , 0 );
2017-12-05 15:54:01 +01:00
2018-04-10 14:00:48 +02:00
2018-04-11 13:56:37 +02:00
/*
2018-04-10 14:00:48 +02:00
//temporary left vertical sizer
m_left_sizer = new wxBoxSizer(wxVERTICAL);
m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3);
// tree
m_presetctrl = new wxDataViewTreeCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), wxDV_NO_HEADER);
m_left_sizer->Add(m_presetctrl, 1, wxEXPAND);
m_preset_icons = new wxImageList(16, 16, true, 1);
m_presetctrl->SetImageList(m_preset_icons);
m_preset_icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG));
m_preset_icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG));
m_presetctrl->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxCommandEvent& evt)
{
auto selected = m_presetctrl->GetItemText(m_presetctrl->GetSelection());
if (selected != _(L("System presets")) && selected != _(L("Default presets")))
{
std::string selected_string = selected.ToUTF8().data();
2018-04-10 14:52:03 +02:00
#ifdef __APPLE__
#else
2018-04-10 14:00:48 +02:00
select_preset(selected_string);
2018-04-10 14:52:03 +02:00
#endif
2018-04-10 14:00:48 +02:00
}
});
2018-04-11 13:56:37 +02:00
*/
2018-04-10 14:00:48 +02:00
2017-12-05 15:54:01 +01:00
//left vertical sizer
2017-12-26 23:04:54 +01:00
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
// tree
2018-01-18 11:45:25 +01:00
m_treectrl = new wxTreeCtrl ( panel , wxID_ANY , wxDefaultPosition , wxSize ( 185 , - 1 ),
wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_SUNKEN | wxWANTS_CHARS );
2017-12-26 23:04:54 +01:00
m_left_sizer -> Add ( m_treectrl , 1 , wxEXPAND );
2018-01-26 01:44:34 +01:00
m_icons = new wxImageList ( 16 , 16 , true , 1 );
2017-12-05 15:54:01 +01:00
// Index of the last icon inserted into $self->{icons}.
2017-12-26 23:04:54 +01:00
m_icon_count = - 1 ;
m_treectrl -> AssignImageList ( m_icons );
m_treectrl -> AddRoot ( "root" );
m_treectrl -> SetIndent ( 0 );
m_disable_tree_sel_changed_event = 0 ;
2017-12-05 15:54:01 +01:00
2018-01-05 15:11:33 +01:00
m_treectrl -> Bind ( wxEVT_TREE_SEL_CHANGED , & Tab :: OnTreeSelChange , this );
m_treectrl -> Bind ( wxEVT_KEY_DOWN , & Tab :: OnKeyDown , this );
2017-12-13 14:45:10 +01:00
2018-01-16 16:28:01 +01:00
m_presets_choice -> Bind ( wxEVT_COMBOBOX , ([ this ]( wxCommandEvent e ){
2018-02-01 12:09:09 +01:00
//! Because of The MSW and GTK version of wxBitmapComboBox derived from wxComboBox,
//! but the OSX version derived from wxOwnerDrawnCombo, instead of:
//! select_preset(m_presets_choice->GetStringSelection().ToStdString());
//! we doing next:
int selected_item = m_presets_choice -> GetSelection ();
2018-04-26 12:40:17 +02:00
if ( m_selected_preset_item == selected_item && ! m_presets -> current_is_dirty ())
2018-04-19 12:08:59 +02:00
return ;
2018-02-01 12:09:09 +01:00
if ( selected_item >= 0 ){
2018-02-05 12:49:23 +01:00
std :: string selected_string = m_presets_choice -> GetString ( selected_item ). ToUTF8 (). data ();
2018-05-02 13:20:36 +02:00
if ( selected_string . find_first_of ( "-------" ) == 0
/*selected_string == "------- System presets -------" ||
selected_string == "------- User presets -------"*/ ){
2018-04-19 12:08:59 +02:00
m_presets_choice -> SetSelection ( m_selected_preset_item );
return ;
}
m_selected_preset_item = selected_item ;
2018-02-05 11:03:13 +01:00
select_preset ( selected_string );
2018-02-01 12:09:09 +01:00
}
2018-01-16 16:28:01 +01:00
}));
2018-01-18 11:45:25 +01: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 ();
2018-01-16 16:28:01 +01:00
}));
2017-12-13 14:45:10 +01:00
2017-12-05 15:54:01 +01:00
// Initialize the DynamicPrintConfig by default keys/values.
2017-12-13 14:45:10 +01:00
build ();
rebuild_page_tree ();
2018-01-09 09:41:07 +01:00
update ();
2017-12-05 15:54:01 +01:00
}
2018-03-16 12:56:03 +01:00
void Tab :: load_initial_data ()
{
m_config = & m_presets -> get_edited_preset (). config ;
2018-04-16 11:03:08 +02:00
m_bmp_non_system = m_presets -> get_selected_preset_parent () ? & m_bmp_value_unlock : & m_bmp_white_bullet ;
2018-04-24 14:11:23 +02:00
m_ttg_non_system = m_presets -> get_selected_preset_parent () ? & m_ttg_value_unlock : & m_ttg_white_bullet_ns ;
m_tt_non_system = m_presets -> get_selected_preset_parent () ? & m_tt_value_unlock : & m_ttg_white_bullet_ns ;
2018-03-16 12:56:03 +01:00
}
2018-04-13 12:35:04 +02:00
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
{
2017-12-13 14:45:10 +01:00
// Index of icon in an icon list $self->{icons}.
auto icon_idx = 0 ;
2017-12-26 23:04:54 +01:00
if ( ! icon . empty ()) {
2018-02-28 15:39:20 +01:00
icon_idx = ( m_icon_index . find ( icon ) == m_icon_index . end ()) ? - 1 : m_icon_index . at ( icon );
2017-12-13 14:45:10 +01:00
if ( icon_idx == - 1 ) {
// Add a new icon to the icon list.
2018-02-22 11:34:41 +01:00
const auto img_icon = new wxIcon ( from_u8 ( Slic3r :: var ( icon )), wxBITMAP_TYPE_PNG );
2017-12-26 23:04:54 +01:00
m_icons -> Add ( * img_icon );
2018-02-08 10:58:13 +01:00
icon_idx = ++ m_icon_count ;
2017-12-26 23:04:54 +01:00
m_icon_index [ icon ] = icon_idx ;
2017-12-13 14:45:10 +01:00
}
}
// Initialize the page.
2018-01-05 15:11:33 +01:00
PageShp page ( new Page ( this , title , icon_idx ));
2017-12-13 14:45:10 +01:00
page -> SetScrollbars ( 1 , 1 , 1 , 1 );
page -> Hide ();
2017-12-26 23:04:54 +01:00
m_hsizer -> Add ( page . get (), 1 , wxEXPAND | wxLEFT , 5 );
2018-01-02 12:50:27 +01:00
if ( ! is_extruder_pages )
m_pages . push_back ( page );
2017-12-14 14:42:47 +01:00
2018-01-12 12:41:13 +01:00
page -> set_config ( m_config );
2017-12-13 14:45:10 +01:00
return page ;
}
2018-04-30 14:20:33 +02:00
void Tab :: update_labels_colour ()
{
Freeze ();
//update options "decoration"
for ( const auto opt : m_options_list )
{
const wxColour * color = & m_sys_label_clr ;
// 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 ;
}
if ( opt . first == "bed_shape" || opt . first == "compatible_printers" ) {
if ( m_colored_Label != nullptr ) {
m_colored_Label -> SetForegroundColour ( * color );
m_colored_Label -> Refresh ( true );
}
continue ;
}
Field * field = get_field ( opt . first );
if ( field == nullptr ) continue ;
field -> set_label_colour_force ( color );
}
Thaw ();
auto cur_item = m_treectrl -> GetFirstVisibleItem ();
while ( cur_item ){
auto title = m_treectrl -> GetItemText ( cur_item );
for ( auto page : m_pages )
{
if ( page -> title () != title )
continue ;
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 );
}
}
2018-03-09 08:34:32 +01:00
// Update UI according to changes
void Tab :: update_changed_ui ()
{
2018-04-16 13:43:01 +02:00
if ( m_postpone_update_ui )
return ;
2018-03-07 15:05:41 +01:00
2018-04-18 13:32:21 +02:00
const bool is_printer_type = ( name () == "printer" );
2018-04-18 14:15:13 +02:00
auto dirty_options = m_presets -> current_dirty_options ( is_printer_type );
auto nonsys_options = m_presets -> current_different_from_parent_options ( is_printer_type );
2018-04-18 13:32:21 +02:00
if ( is_printer_type ){
2018-03-08 11:58:06 +01:00
TabPrinter * tab = static_cast < TabPrinter *> ( this );
2018-03-19 17:21:37 +01:00
if ( tab -> m_initial_extruders_count != tab -> m_extruders_count )
2018-04-18 14:15:13 +02:00
dirty_options . emplace_back ( "extruders_count" );
2018-04-18 13:32:21 +02:00
if ( tab -> m_sys_extruders_count != tab -> m_extruders_count )
2018-04-18 14:15:13 +02:00
nonsys_options . emplace_back ( "extruders_count" );
2018-03-02 09:08:11 +01:00
}
2018-03-06 09:44:53 +01:00
2018-04-18 13:32:21 +02:00
for ( auto & it : m_options_list )
it . second = m_opt_status_value ;
2018-04-18 14:15:13 +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
2018-04-13 18:22:06 +02:00
Freeze ();
2018-03-23 17:27:43 +01:00
//update options "decoration"
2018-04-18 14:15:13 +02:00
for ( const auto opt : m_options_list )
2018-03-21 22:21:37 +01:00
{
2018-03-23 17:27:43 +01:00
bool is_nonsys_value = false ;
bool is_modified_value = true ;
2018-04-24 14:11:23 +02:00
const wxBitmap * sys_icon = & m_bmp_value_lock ;
const wxBitmap * icon = & m_bmp_value_revert ;
2018-04-18 13:32:21 +02:00
2018-04-24 14:11:23 +02:00
const wxColour * color = & 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
2018-04-18 13:32:21 +02:00
if (( opt . second & osSystemValue ) == 0 ){
2018-03-23 17:27:43 +01:00
is_nonsys_value = true ;
2018-04-18 13:32:21 +02:00
sys_icon = m_bmp_non_system ;
2018-04-24 14:11:23 +02:00
sys_tt = m_tt_non_system ;
// value is equal to last saved
2018-04-18 13:32:21 +02:00
if (( opt . second & osInitValue ) != 0 )
color = & m_default_text_clr ;
2018-04-24 14:11:23 +02:00
// value is modified
2018-03-22 09:37:42 +01:00
else
2018-04-18 13:32:21 +02:00
color = & m_modified_label_clr ;
2018-03-21 22:21:37 +01:00
}
2018-04-18 13:32:21 +02:00
if (( opt . second & osInitValue ) != 0 )
2018-03-23 17:27:43 +01:00
{
is_modified_value = false ;
2018-04-18 13:32:21 +02:00
icon = & m_bmp_white_bullet ;
2018-04-24 14:11:23 +02:00
tt = & m_tt_white_bullet ;
2018-03-23 17:27:43 +01:00
}
2018-04-18 13:32:21 +02:00
if ( opt . first == "bed_shape" || opt . first == "compatible_printers" ) {
2018-04-13 18:22:06 +02:00
if ( m_colored_Label != nullptr ) {
2018-04-18 13:32:21 +02:00
m_colored_Label -> SetForegroundColour ( * color );
2018-04-13 18:22:06 +02:00
m_colored_Label -> Refresh ( true );
}
continue ;
}
2018-04-18 13:32:21 +02:00
Field * field = get_field ( opt . first );
2018-03-23 17:27:43 +01:00
if ( field == nullptr ) continue ;
field -> m_is_nonsys_value = is_nonsys_value ;
field -> m_is_modified_value = is_modified_value ;
2018-04-18 13:32:21 +02:00
field -> set_undo_bitmap ( icon );
field -> set_undo_to_sys_bitmap ( sys_icon );
2018-04-24 14:11:23 +02:00
field -> set_undo_tooltip ( tt );
field -> set_undo_to_sys_tooltip ( sys_tt );
2018-04-18 13:32:21 +02:00
field -> set_label_colour ( color );
2018-03-16 12:56:03 +01:00
}
2018-04-13 18:22:06 +02:00
Thaw ();
2018-03-21 22:21:37 +01:00
wxTheApp -> CallAfter ([ this ]() {
update_changed_tree_ui ();
});
}
2018-04-18 13:32:21 +02:00
void Tab :: init_options_list ()
{
if ( ! m_options_list . empty ())
m_options_list . clear ();
for ( const auto opt_key : m_config -> keys ())
m_options_list . emplace ( opt_key , m_opt_status_value );
}
2018-03-21 22:21:37 +01:00
template < class T >
2018-04-18 13:32:21 +02:00
void add_correct_opts_to_options_list ( const std :: string & opt_key , std :: map < std :: string , int >& map , TabPrinter * tab , const int & value )
2018-03-21 22:21:37 +01:00
{
T * opt_cur = static_cast < T *> ( tab -> m_config -> option ( opt_key ));
for ( int i = 0 ; i < opt_cur -> values . size (); i ++ )
2018-04-18 13:32:21 +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
{
2018-04-18 13:32:21 +02:00
if ( ! m_options_list . empty ())
m_options_list . clear ();
2018-03-21 22:21:37 +01:00
for ( const auto opt_key : m_config -> keys ())
{
if ( opt_key == "bed_shape" ){
2018-04-18 13:32:21 +02:00
m_options_list . emplace ( opt_key , m_opt_status_value );
2018-03-21 22:21:37 +01:00
continue ;
}
switch ( m_config -> option ( opt_key ) -> type ())
{
2018-04-18 13:32:21 +02:00
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-03-21 22:21:37 +01:00
}
}
2018-04-18 13:32:21 +02:00
m_options_list . emplace ( "extruders_count" , m_opt_status_value );
2018-03-21 22:21:37 +01:00
}
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 )
{
2018-04-18 13:32:21 +02:00
auto opt = m_options_list . find ( opt_key );
if ( sys_page ) sys_page = ( opt -> second & osSystemValue ) != 0 ;
if ( ! modified_page ) 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 ()
{
auto cur_item = m_treectrl -> GetFirstVisibleItem ();
2018-03-22 09:37:42 +01:00
auto selection = m_treectrl -> GetItemText ( m_treectrl -> GetSelection ());
2018-03-21 22:21:37 +01:00
while ( cur_item ){
auto title = m_treectrl -> GetItemText ( cur_item );
for ( auto page : m_pages )
{
if ( page -> title () != title )
continue ;
bool sys_page = true ;
bool modified_page = false ;
if ( title == _ ( "General" )){
2018-03-23 17:27:43 +01:00
std :: initializer_list < const char *> optional_keys { "extruders_count" , "bed_shape" };
for ( auto & opt_key : optional_keys ) {
2018-04-13 18:22:06 +02:00
get_sys_and_mod_flags ( opt_key , sys_page , modified_page );
2018-03-23 17:27:43 +01:00
}
2018-03-21 22:21:37 +01:00
}
2018-04-18 13:32:21 +02:00
if ( title == _ ( "Dependencies" ) && name () != "printer" ){
2018-04-13 18:22:06 +02:00
get_sys_and_mod_flags ( "compatible_printers" , sys_page , modified_page );
}
2018-03-21 22:21:37 +01:00
for ( auto group : page -> m_optgroups )
{
if ( ! sys_page && modified_page )
break ;
2018-04-13 18:22:06 +02:00
for ( t_opt_map :: iterator it = group -> m_opt_map . begin (); it != group -> m_opt_map . end (); ++ it ) {
const std :: string & opt_key = it -> first ;
get_sys_and_mod_flags ( opt_key , sys_page , modified_page );
}
2018-03-21 22:21:37 +01:00
}
2018-04-18 13:32:21 +02:00
const wxColor * clr = sys_page ? & m_sys_label_clr :
modified_page ? & m_modified_label_clr :
& m_default_text_clr ;
if ( page -> set_item_colour ( clr ))
m_treectrl -> SetItemTextColour ( cur_item , * clr );
2018-03-22 09:37:42 +01:00
page -> m_is_nonsys_values = ! sys_page ;
page -> m_is_modified_values = modified_page ;
if ( selection == title ){
m_is_nonsys_values = page -> m_is_nonsys_values ;
m_is_modified_values = page -> m_is_modified_values ;
}
2018-03-21 22:21:37 +01:00
break ;
}
auto next_item = m_treectrl -> GetNextVisible ( cur_item );
cur_item = next_item ;
}
2018-03-22 09:37:42 +01:00
update_undo_buttons ();
}
void Tab :: update_undo_buttons ()
{
2018-04-16 11:03:08 +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
2018-04-24 14:11:23 +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
{
2018-04-18 13:32:21 +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
2018-04-16 13:43:01 +02:00
m_postpone_update_ui = true ;
2018-03-22 10:56:57 +01:00
auto selection = m_treectrl -> GetItemText ( m_treectrl -> GetSelection ());
for ( auto page : m_pages )
if ( page -> title () == selection ) {
for ( auto group : page -> m_optgroups ){
if ( group -> title == _ ( "Capabilities" )){
2018-04-18 13:32:21 +02:00
if (( m_options_list [ "extruders_count" ] & os ) == 0 )
to_sys ? group -> back_to_sys_value ( "extruders_count" ) : group -> back_to_initial_value ( "extruders_count" );
2018-03-22 10:56:57 +01:00
}
2018-03-23 17:27:43 +01:00
if ( group -> title == _ ( "Size and coordinates" )){
2018-04-18 13:32:21 +02:00
if (( m_options_list [ "bed_shape" ] & os ) == 0 ){
to_sys ? group -> back_to_sys_value ( "bed_shape" ) : group -> back_to_initial_value ( "bed_shape" );
2018-04-16 13:43:01 +02:00
load_key_value ( "bed_shape" , true /*some value*/ , true );
}
2018-04-13 18:22:06 +02:00
2018-03-23 17:27:43 +01:00
}
2018-04-18 13:32:21 +02:00
if ( group -> title == _ ( "Profile dependencies" ) && name () != "printer" ){
if (( m_options_list [ "compatible_printers" ] & os ) == 0 ){
to_sys ? group -> back_to_sys_value ( "compatible_printers" ) : group -> back_to_initial_value ( "compatible_printers" );
2018-04-16 13:43:01 +02:00
load_key_value ( "compatible_printers" , true /*some value*/ , true );
2018-04-13 18:22:06 +02:00
2018-04-16 13:43:01 +02:00
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 ();
}
2018-04-13 18:22:06 +02:00
}
2018-03-22 10:56:57 +01:00
for ( t_opt_map :: iterator it = group -> m_opt_map . begin (); it != group -> m_opt_map . end (); ++ it ) {
const std :: string & opt_key = it -> first ;
2018-04-18 13:32:21 +02:00
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
}
}
break ;
}
2018-04-16 13:43:01 +02:00
m_postpone_update_ui = false ;
2018-03-23 17:27:43 +01:00
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}.
void Tab :: update_dirty (){
m_presets -> update_dirty_ui ( m_presets_choice );
on_presets_changed ();
update_changed_ui ();
2018-04-06 15:42:52 +02:00
// update_dirty_presets(m_cc_presets_choice);
2018-03-09 08:34:32 +01:00
}
2018-01-16 16:28:01 +01:00
void Tab :: update_tab_ui ()
{
2018-04-19 12:08:59 +02:00
m_selected_preset_item = m_presets -> update_tab_ui ( m_presets_choice , m_show_incompatible_presets );
2018-04-11 13:56:37 +02:00
// update_tab_presets(m_cc_presets_choice, m_show_incompatible_presets);
// update_presetsctrl(m_presetctrl, m_show_incompatible_presets);
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
{
bool modified = 0 ;
2018-01-12 12:41:13 +01:00
for ( auto opt_key : m_config -> diff ( config )) {
2018-03-12 16:52:21 +01:00
m_config -> set_key_value ( opt_key , config . option ( opt_key ) -> clone ());
2018-01-05 15:11:33 +01:00
modified = 1 ;
}
if ( modified ) {
2018-01-07 18:41:40 +01:00
update_dirty ();
2018-01-05 15:11:33 +01:00
//# Initialize UI components with the config values.
2018-01-09 09:41:07 +01:00
reload_config ();
2018-01-05 15:11:33 +01:00
update ();
}
}
2018-01-09 09:41:07 +01:00
// Reload current $self->{config} (aka $self->{presets}->edited_preset->config) into the UI fields.
void Tab :: reload_config (){
Freeze ();
for ( auto page : m_pages )
page -> reload_config ();
2018-02-15 17:30:33 +01:00
Thaw ();
2018-01-09 09:41:07 +01:00
}
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
{
Field * field = nullptr ;
for ( auto page : m_pages ){
2018-01-12 17:16:59 +01:00
field = page -> get_field ( opt_key , opt_index );
2018-01-11 10:33:17 +01:00
if ( field != nullptr )
return field ;
}
return field ;
}
2018-01-16 16:28:01 +01:00
// Set a key/value pair on this page. Return true if the value has been modified.
// Currently used for distributing extruders_count over preset pages of Slic3r::GUI::Tab::Printer
// after a preset is loaded.
2018-04-13 12:35:04 +02:00
bool Tab :: set_value ( const t_config_option_key & opt_key , const boost :: any & value ){
2018-01-16 16:28:01 +01:00
bool changed = false ;
for ( auto page : m_pages ) {
if ( page -> set_value ( opt_key , value ))
changed = true ;
}
return changed ;
}
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
{
2018-04-16 13:43:01 +02:00
if ( ! saved_value ) change_opt_value ( * m_config , opt_key , value );
2018-01-12 12:41:13 +01:00
// Mark the print & filament enabled if they are compatible with the currently selected preset.
2017-12-22 11:50:28 +01:00
if ( opt_key . compare ( "compatible_printers" ) == 0 ) {
2018-04-13 14:49:33 +02:00
// Don't select another profile if this profile happens to become incompatible.
m_preset_bundle -> update_compatible_with_printer ( false );
2018-01-12 12:41:13 +01:00
}
m_presets -> update_dirty_ui ( m_presets_choice );
on_presets_changed ();
update ();
}
2018-01-21 23:35:00 +01:00
extern wxFrame * g_wxMainFrame ;
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
{
if ( m_event_value_change > 0 ) {
wxCommandEvent event ( m_event_value_change );
2018-01-25 21:44:22 +01:00
std :: string str_out = opt_key + " " + m_name ;
2018-01-25 13:46:04 +01:00
event . SetString ( str_out );
if ( opt_key == "extruders_count" )
{
int val = boost :: any_cast < size_t > ( value );
event . SetInt ( val );
}
2018-01-21 23:35:00 +01:00
g_wxMainFrame -> ProcessWindowEvent ( event );
}
2018-03-12 16:52:21 +01:00
if ( opt_key == "fill_density" )
{
2018-04-13 12:35:04 +02:00
boost :: any val = get_optgroup () -> get_config_value ( * m_config , opt_key );
get_optgroup () -> set_value ( opt_key , val );
2018-03-12 16:52:21 +01:00
}
2018-03-13 16:14:36 +01:00
if ( opt_key == "support_material" || opt_key == "support_material_buildplate_only" )
2018-03-12 16:52:21 +01:00
{
2018-03-13 16:14:36 +01:00
wxString new_selection = ! m_config -> opt_bool ( "support_material" ) ?
_ ( "None" ) :
m_config -> opt_bool ( "support_material_buildplate_only" ) ?
_ ( "Support on build plate only" ) :
_ ( "Everywhere" );
get_optgroup () -> set_value ( "support" , new_selection );
2018-03-12 16:52:21 +01:00
}
if ( opt_key == "brim_width" )
{
bool val = m_config -> opt_float ( "brim_width" ) > 0.0 ? true : false ;
get_optgroup () -> set_value ( "brim" , val );
}
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 ();
2018-01-21 23:35:00 +01: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 () {
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 ;
bool single_extruder_mm = dynamic_cast < ConfigOptionBool *> ( ( m_preset_bundle -> printers . get_edited_preset (). config ). option ( "single_extruder_multi_material" )) -> value ;
if ( wipe_tower_enabled && multiple_extruders && single_extruder_mm )
get_wiping_dialog_button () -> Show ();
else get_wiping_dialog_button () -> Hide ();
( get_wiping_dialog_button () -> GetParent ()) -> Layout ();
}
2018-01-16 16:28:01 +01:00
// Call a callback to update the selection of presets on the platter:
// 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,
// to uddate 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
{
if ( m_event_presets_changed > 0 ) {
wxCommandEvent event ( m_event_presets_changed );
2018-01-25 21:44:22 +01:00
event . SetString ( m_name );
2018-01-21 23:35:00 +01:00
g_wxMainFrame -> ProcessWindowEvent ( event );
}
2018-04-26 12:40:17 +02:00
update_preset_description_line ();
}
2018-03-23 09:41:04 +01:00
2018-04-26 12:40:17 +02:00
void Tab :: update_preset_description_line ()
{
2018-03-23 09:41:04 +01:00
const Preset * parent = m_presets -> get_selected_preset_parent ();
2018-04-26 12:40:17 +02:00
const Preset & preset = m_presets -> get_edited_preset ();
wxString description_line = preset . is_default ?
_ ( L ( "It's a default preset." )) : preset . is_system ?
_ ( L ( "It's a system preset." )) :
_ ( L ( "Current preset is inherited from " )) + ( parent == nullptr ?
"default preset." :
": \n\t " + parent -> name );
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." ));
if ( parent && parent -> vendor )
{
description_line += " \n\n " + _ ( L ( "Additional information:" )) + " \n " ;
description_line += " \t " + _ ( L ( "vendor" )) + ": " + ( name () == "printer" ? " \n\t\t " : "" ) + parent -> vendor -> name +
", ver: " + parent -> vendor -> config_version . to_string ();
if ( name () == "printer" ){
const std :: string & printer_model = preset . config . opt_string ( "printer_model" );
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 ( ! printer_model . empty ())
description_line += " \n\n\t " + _ ( L ( "printer model" )) + ": \n\t\t " + printer_model ;
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 ;
}
}
}
}
m_parent_preset_description_line -> SetText ( description_line , false );
2018-01-16 16:28:01 +01:00
}
2018-03-13 16:14:36 +01:00
void Tab :: update_frequently_changed_parameters ()
{
boost :: any value = get_optgroup () -> get_config_value ( * m_config , "fill_density" );
get_optgroup () -> set_value ( "fill_density" , value );
wxString new_selection = ! m_config -> opt_bool ( "support_material" ) ?
_ ( "None" ) :
m_config -> opt_bool ( "support_material_buildplate_only" ) ?
_ ( "Support on build plate only" ) :
_ ( "Everywhere" );
get_optgroup () -> set_value ( "support" , new_selection );
bool val = m_config -> opt_float ( "brim_width" ) > 0.0 ? true : false ;
get_optgroup () -> set_value ( "brim" , val );
2018-04-04 11:13:28 +02:00
2018-04-05 10:44:31 +02:00
update_wiping_button_visibility ();
2018-03-13 16:14:36 +01:00
}
2018-01-12 12:41:13 +01:00
void Tab :: reload_compatible_printers_widget ()
{
bool has_any = ! m_config -> option < ConfigOptionStrings > ( "compatible_printers" ) -> values . empty ();
has_any ? m_compatible_printers_btn -> Enable () : m_compatible_printers_btn -> Disable ();
m_compatible_printers_checkbox -> SetValue ( ! has_any );
get_field ( "compatible_printers_condition" ) -> toggle ( ! has_any );
2017-12-22 11:50:28 +01:00
}
2018-01-05 15:11:33 +01:00
void TabPrint :: build ()
2017-12-13 14:45:10 +01:00
{
2018-01-05 15:11:33 +01:00
m_presets = & m_preset_bundle -> prints ;
2018-03-16 12:56:03 +01:00
load_initial_data ();
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
auto page = add_options_page ( _ ( L ( "Layers and perimeters" )), "layers.png" );
auto optgroup = page -> new_optgroup ( _ ( L ( "Layer height" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "layer_height" );
optgroup -> append_single_option_line ( "first_layer_height" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Vertical shells" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "perimeters" );
optgroup -> append_single_option_line ( "spiral_vase" );
2017-12-14 14:42:47 +01:00
2018-01-15 12:13:05 +01:00
Line line { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_recommended_thin_wall_thickness_description_line );
};
optgroup -> append_line ( line );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Horizontal shells" )));
line = { _ ( L ( "Solid layers" )), "" };
2018-01-07 18:41:40 +01:00
line . append_option ( optgroup -> get_option ( "top_solid_layers" ));
line . append_option ( optgroup -> get_option ( "bottom_solid_layers" ));
2017-12-14 14:42:47 +01:00
optgroup -> append_line ( line );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Quality (slower slicing)" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "extra_perimeters" );
optgroup -> append_single_option_line ( "ensure_vertical_shell_thickness" );
optgroup -> append_single_option_line ( "avoid_crossing_perimeters" );
optgroup -> append_single_option_line ( "thin_walls" );
optgroup -> append_single_option_line ( "overhangs" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Advanced" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "seam_position" );
optgroup -> append_single_option_line ( "external_perimeters_first" );
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Infill" )), "infill.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Infill" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "fill_density" );
optgroup -> append_single_option_line ( "fill_pattern" );
optgroup -> append_single_option_line ( "external_fill_pattern" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Reducing printing time" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "infill_every_layers" );
optgroup -> append_single_option_line ( "infill_only_where_needed" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Advanced" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "solid_infill_every_layers" );
optgroup -> append_single_option_line ( "fill_angle" );
optgroup -> append_single_option_line ( "solid_infill_below_area" );
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
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Skirt and brim" )), "box.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Skirt" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "skirts" );
optgroup -> append_single_option_line ( "skirt_distance" );
optgroup -> append_single_option_line ( "skirt_height" );
optgroup -> append_single_option_line ( "min_skirt_length" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Brim" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "brim_width" );
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Support material" )), "building.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Support material" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "support_material" );
optgroup -> append_single_option_line ( "support_material_threshold" );
optgroup -> append_single_option_line ( "support_material_enforce_layers" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Raft" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "raft_layers" );
// # optgroup->append_single_option_line(get_option_("raft_contact_distance");
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Options for support material and raft" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "support_material_contact_distance" );
optgroup -> append_single_option_line ( "support_material_pattern" );
optgroup -> append_single_option_line ( "support_material_with_sheath" );
optgroup -> append_single_option_line ( "support_material_spacing" );
optgroup -> append_single_option_line ( "support_material_angle" );
optgroup -> append_single_option_line ( "support_material_interface_layers" );
optgroup -> append_single_option_line ( "support_material_interface_spacing" );
optgroup -> append_single_option_line ( "support_material_interface_contact_loops" );
optgroup -> append_single_option_line ( "support_material_buildplate_only" );
optgroup -> append_single_option_line ( "support_material_xy_spacing" );
optgroup -> append_single_option_line ( "dont_support_bridges" );
optgroup -> append_single_option_line ( "support_material_synchronize_layers" );
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Speed" )), "time.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Speed for print moves" )));
2018-01-07 18:41:40 +01: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" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Speed for non-print moves" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "travel_speed" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Modifiers" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "first_layer_speed" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Acceleration control (advanced)" )));
2018-01-07 18:41:40 +01: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
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Autospeed (advanced)" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "max_print_speed" );
optgroup -> append_single_option_line ( "max_volumetric_speed" );
optgroup -> append_single_option_line ( "max_volumetric_extrusion_rate_slope_positive" );
optgroup -> append_single_option_line ( "max_volumetric_extrusion_rate_slope_negative" );
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Multiple Extruders" )), "funnel.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Extruders" )));
2018-01-07 18:41:40 +01: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
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Ooze prevention" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "ooze_prevention" );
optgroup -> append_single_option_line ( "standby_temperature_delta" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Wipe tower" )));
2018-01-07 18:41:40 +01: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" );
2018-02-27 08:56:11 +01:00
optgroup -> append_single_option_line ( "wipe_tower_rotation_angle" );
2018-03-12 15:41:25 +01:00
optgroup -> append_single_option_line ( "wipe_tower_bridging" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Advanced" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "interface_shells" );
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Advanced" )), "wrench.png" );
2018-03-22 14:12:29 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Extrusion width" )));
2018-01-07 18:41:40 +01: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
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Overlap" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "infill_overlap" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Flow" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "bridge_flow_ratio" );
2017-12-14 14:42:47 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Other" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "clip_multipart_objects" );
optgroup -> append_single_option_line ( "elefant_foot_compensation" );
optgroup -> append_single_option_line ( "xy_size_compensation" );
// # optgroup->append_single_option_line("threads");
optgroup -> append_single_option_line ( "resolution" );
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Output options" )), "page_white_go.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Sequential printing" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "complete_objects" );
2018-02-23 09:16:35 +01:00
line = { _ ( L ( "Extruder clearance (mm)" )), "" };
2018-01-07 18:41:40 +01:00
Option option = optgroup -> get_option ( "extruder_clearance_radius" );
2017-12-14 14:42:47 +01:00
option . opt . width = 60 ;
line . append_option ( option );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "extruder_clearance_height" );
2017-12-14 14:42:47 +01:00
option . opt . width = 60 ;
line . append_option ( option );
optgroup -> append_line ( line );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Output file" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "gcode_comments" );
option = optgroup -> get_option ( "output_filename_format" );
2017-12-18 13:58:51 +01:00
option . opt . full_width = true ;
2017-12-14 14:42:47 +01:00
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Post-processing scripts" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "post_process" );
2017-12-18 13:58:51 +01:00
option . opt . full_width = true ;
2017-12-14 14:42:47 +01:00
option . opt . height = 50 ;
optgroup -> append_single_option_line ( option );
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Notes" )), "note.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Notes" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "notes" );
2017-12-18 13:58:51 +01:00
option . opt . full_width = true ;
2017-12-14 14:42:47 +01:00
option . opt . height = 250 ;
optgroup -> append_single_option_line ( option );
2017-12-13 14:45:10 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Dependencies" )), "wrench.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Profile dependencies" )));
line = { _ ( L ( "Compatible printers" )), "" };
2017-12-26 23:04:54 +01:00
line . widget = [ this ]( wxWindow * parent ){
2018-01-15 12:13:05 +01:00
return compatible_printers_widget ( parent , & m_compatible_printers_checkbox , & m_compatible_printers_btn );
2017-12-26 23:04:54 +01:00
};
2018-04-13 18:22:06 +02:00
optgroup -> append_line ( line , & m_colored_Label );
2018-01-11 10:33:17 +01: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
line = Line { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_parent_preset_description_line );
};
optgroup -> append_line ( line );
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.
void TabPrint :: reload_config (){
reload_compatible_printers_widget ();
Tab :: reload_config ();
}
2018-01-05 15:11:33 +01:00
void TabPrint :: update ()
{
Freeze ();
2018-03-16 17:25:11 +01:00
double fill_density = m_config -> option < ConfigOptionPercent > ( "fill_density" ) -> value ;
2018-02-23 09:16:35 +01:00
if ( m_config -> opt_bool ( "spiral_vase" ) &&
2018-01-26 01:44:34 +01:00
! ( m_config -> opt_int ( "perimeters" ) == 1 && m_config -> opt_int ( "top_solid_layers" ) == 0 &&
2018-03-16 17:25:11 +01:00
fill_density == 0 )) {
2018-02-23 09:16:35 +01:00
wxString msg_text = _ ( L ( "The Spiral Vase mode requires: \n "
2018-01-05 15:11:33 +01:00
"- one perimeter \n "
2018-02-23 09:16:35 +01:00
"- no top solid layers \n "
"- 0% fill density \n "
"- no support material \n "
"- no ensure_vertical_shell_thickness \n "
" \n Shall I adjust those settings in order to enable Spiral Vase?" ));
auto dialog = new wxMessageDialog ( parent (), msg_text , _ ( L ( "Spiral Vase" )), wxICON_WARNING | wxYES | wxNO );
2018-01-26 01:44:34 +01:00
DynamicPrintConfig new_conf = * m_config ;
2018-02-23 09:16:35 +01:00
if ( dialog -> ShowModal () == wxID_YES ) {
2018-01-05 15:11:33 +01:00
new_conf . set_key_value ( "perimeters" , new ConfigOptionInt ( 1 ));
new_conf . set_key_value ( "top_solid_layers" , new ConfigOptionInt ( 0 ));
new_conf . set_key_value ( "fill_density" , new ConfigOptionPercent ( 0 ));
new_conf . set_key_value ( "support_material" , new ConfigOptionBool ( false ));
2018-02-22 11:34:41 +01:00
new_conf . set_key_value ( "support_material_enforce_layers" , new ConfigOptionInt ( 0 ));
2018-01-05 15:11:33 +01:00
new_conf . set_key_value ( "ensure_vertical_shell_thickness" , new ConfigOptionBool ( false ));
2018-03-16 17:25:11 +01:00
fill_density = 0 ;
2018-01-05 15:11:33 +01:00
}
else {
new_conf . set_key_value ( "spiral_vase" , new ConfigOptionBool ( false ));
}
2018-02-23 09:16:35 +01:00
load_config ( new_conf );
2018-03-16 17:25:11 +01:00
on_value_change ( "fill_density" , fill_density );
2018-01-05 15:11:33 +01:00
}
2018-02-23 09:16:35 +01:00
if ( m_config -> opt_bool ( "wipe_tower" ) && m_config -> opt_bool ( "support_material" ) &&
2018-01-12 12:41:13 +01:00
m_config -> opt_float ( "support_material_contact_distance" ) > 0. &&
( m_config -> opt_int ( "support_material_extruder" ) != 0 || m_config -> opt_int ( "support_material_interface_extruder" ) != 0 )) {
2018-02-23 09:16:35 +01:00
wxString msg_text = _ ( L ( "The Wipe Tower currently supports the non-soluble supports only \n "
2018-01-11 10:33:17 +01:00
"if they are printed with the current extruder without triggering a tool change. \n "
"(both support_material_extruder and support_material_interface_extruder need to be set to 0). \n "
2018-02-23 09:16:35 +01:00
" \n Shall I adjust those settings in order to enable the Wipe Tower?" ));
auto dialog = new wxMessageDialog ( parent (), msg_text , _ ( L ( "Wipe Tower" )), wxICON_WARNING | wxYES | wxNO );
2018-01-12 12:41:13 +01:00
DynamicPrintConfig new_conf = * m_config ;
2018-01-11 10:33:17 +01:00
if ( dialog -> ShowModal () == wxID_YES ) {
new_conf . set_key_value ( "support_material_extruder" , new ConfigOptionInt ( 0 ));
new_conf . set_key_value ( "support_material_interface_extruder" , new ConfigOptionInt ( 0 ));
}
2018-02-23 09:16:35 +01:00
else
2018-01-11 10:33:17 +01:00
new_conf . set_key_value ( "wipe_tower" , new ConfigOptionBool ( false ));
load_config ( new_conf );
}
2018-02-23 09:16:35 +01:00
if ( m_config -> opt_bool ( "wipe_tower" ) && m_config -> opt_bool ( "support_material" ) &&
2018-01-12 12:41:13 +01:00
m_config -> opt_float ( "support_material_contact_distance" ) == 0 &&
! m_config -> opt_bool ( "support_material_synchronize_layers" )) {
2018-02-23 09:16:35 +01:00
wxString msg_text = _ ( L ( "For the Wipe Tower to work with the soluble supports, the support layers \n "
2018-01-11 10:33:17 +01:00
"need to be synchronized with the object layers. \n "
2018-02-23 09:16:35 +01:00
" \n Shall I synchronize support layers in order to enable the Wipe Tower?" ));
auto dialog = new wxMessageDialog ( parent (), msg_text , _ ( L ( "Wipe Tower" )), wxICON_WARNING | wxYES | wxNO );
2018-01-12 12:41:13 +01:00
DynamicPrintConfig new_conf = * m_config ;
2018-01-11 10:33:17 +01:00
if ( dialog -> ShowModal () == wxID_YES ) {
new_conf . set_key_value ( "support_material_synchronize_layers" , new ConfigOptionBool ( true ));
}
else
new_conf . set_key_value ( "wipe_tower" , new ConfigOptionBool ( false ));
load_config ( new_conf );
}
2018-01-12 12:41:13 +01:00
if ( m_config -> opt_bool ( "support_material" )) {
2018-01-11 10:33:17 +01:00
// Ask only once.
if ( ! m_support_material_overhangs_queried ) {
m_support_material_overhangs_queried = true ;
2018-01-12 12:41:13 +01:00
if ( ! m_config -> opt_bool ( "overhangs" ) /* != 1*/ ) {
2018-02-23 09:16:35 +01:00
wxString msg_text = _ ( L ( "Supports work better, if the following feature is enabled: \n "
2018-01-11 10:33:17 +01:00
"- Detect bridging perimeters \n "
2018-02-23 09:16:35 +01:00
" \n Shall I adjust those settings for supports?" ));
auto dialog = new wxMessageDialog ( parent (), msg_text , _ ( L ( "Support Generator" )), wxICON_WARNING | wxYES | wxNO | wxCANCEL );
2018-01-12 12:41:13 +01:00
DynamicPrintConfig new_conf = * m_config ;
2018-01-11 10:33:17 +01:00
auto answer = dialog -> ShowModal ();
if ( answer == wxID_YES ) {
// Enable "detect bridging perimeters".
new_conf . set_key_value ( "overhangs" , new ConfigOptionBool ( true ));
2018-02-23 09:16:35 +01:00
} else if ( answer == wxID_NO ) {
2018-01-11 10:33:17 +01:00
// Do nothing, leave supports on and "detect bridging perimeters" off.
2018-02-23 09:16:35 +01:00
} else if ( answer == wxID_CANCEL ) {
2018-01-11 10:33:17 +01:00
// Disable supports.
new_conf . set_key_value ( "support_material" , new ConfigOptionBool ( false ));
m_support_material_overhangs_queried = false ;
}
load_config ( new_conf );
}
}
}
else {
m_support_material_overhangs_queried = false ;
}
2018-01-12 12:41:13 +01:00
if ( m_config -> option < ConfigOptionPercent > ( "fill_density" ) -> value == 100 ) {
auto fill_pattern = m_config -> option < ConfigOptionEnum < InfillPattern >> ( "fill_pattern" ) -> value ;
2018-01-11 10:33:17 +01:00
std :: string str_fill_pattern = "" ;
2018-01-12 12:41:13 +01:00
t_config_enum_values map_names = m_config -> option < ConfigOptionEnum < InfillPattern >> ( "fill_pattern" ) -> get_enum_values ();
2018-02-23 09:16:35 +01:00
for ( auto it : map_names ) {
2018-01-11 10:33:17 +01:00
if ( fill_pattern == it . second ) {
str_fill_pattern = it . first ;
break ;
}
}
if ( ! str_fill_pattern . empty ()){
2018-01-12 12:41:13 +01:00
auto external_fill_pattern = m_config -> def () -> get ( "external_fill_pattern" ) -> enum_values ;
2018-01-11 10:33:17 +01:00
bool correct_100p_fill = false ;
for ( auto fill : external_fill_pattern )
{
if ( str_fill_pattern . compare ( fill ) == 0 )
correct_100p_fill = true ;
}
// get fill_pattern name from enum_labels for using this one at dialog_msg
2018-01-12 12:41:13 +01:00
str_fill_pattern = m_config -> def () -> get ( "fill_pattern" ) -> enum_labels [ fill_pattern ];
2018-01-11 10:33:17 +01:00
if ( ! correct_100p_fill ){
2018-02-23 09:16:35 +01:00
wxString msg_text = _ ( L ( "The " )) + str_fill_pattern + _ ( L ( " infill pattern is not supposed to work at 100% density. \n "
" \n Shall I switch to rectilinear fill pattern?" ));
auto dialog = new wxMessageDialog ( parent (), msg_text , _ ( L ( "Infill" )), wxICON_WARNING | wxYES | wxNO );
2018-01-12 12:41:13 +01:00
DynamicPrintConfig new_conf = * m_config ;
2018-01-11 10:33:17 +01:00
if ( dialog -> ShowModal () == wxID_YES ) {
new_conf . set_key_value ( "fill_pattern" , new ConfigOptionEnum < InfillPattern > ( ipRectilinear ));
2018-03-14 11:45:31 +01:00
fill_density = 100 ;
2018-01-11 10:33:17 +01:00
}
else
2018-03-14 15:10:16 +01:00
fill_density = m_presets -> get_selected_preset (). config . option < ConfigOptionPercent > ( "fill_density" ) -> value ;
2018-03-14 11:45:31 +01:00
new_conf . set_key_value ( "fill_density" , new ConfigOptionPercent ( fill_density ));
2018-01-11 10:33:17 +01:00
load_config ( new_conf );
2018-03-14 11:45:31 +01:00
on_value_change ( "fill_density" , fill_density );
2018-01-11 10:33:17 +01:00
}
}
}
2018-01-12 12:41:13 +01:00
bool have_perimeters = m_config -> opt_int ( "perimeters" ) > 0 ;
2018-04-04 10:18:26 +02:00
for ( auto el : { "extra_perimeters" , "ensure_vertical_shell_thickness" , "thin_walls" , "overhangs" ,
"seam_position" , "external_perimeters_first" , "external_perimeter_extrusion_width" ,
"perimeter_speed" , "small_perimeter_speed" , "external_perimeter_speed" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_perimeters );
2018-01-12 12:41:13 +01:00
bool have_infill = m_config -> option < ConfigOptionPercent > ( "fill_density" ) -> value > 0 ;
2018-01-11 10:33:17 +01:00
// infill_extruder uses the same logic as in Print::extruders()
2018-04-04 10:18:26 +02:00
for ( auto el : { "fill_pattern" , "infill_every_layers" , "infill_only_where_needed" ,
"solid_infill_every_layers" , "solid_infill_below_area" , "infill_extruder" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_infill );
2018-01-12 12:41:13 +01:00
bool have_solid_infill = m_config -> opt_int ( "top_solid_layers" ) > 0 || m_config -> opt_int ( "bottom_solid_layers" ) > 0 ;
2018-01-11 10:33:17 +01:00
// solid_infill_extruder uses the same logic as in Print::extruders()
2018-04-04 10:18:26 +02:00
for ( auto el : { "external_fill_pattern" , "infill_first" , "solid_infill_extruder" ,
"solid_infill_extrusion_width" , "solid_infill_speed" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_solid_infill );
2018-04-04 10:18:26 +02:00
for ( auto el : { "fill_angle" , "bridge_angle" , "infill_extrusion_width" ,
"infill_speed" , "bridge_speed" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_infill || have_solid_infill );
get_field ( "gap_fill_speed" ) -> toggle ( have_perimeters && have_infill );
2018-01-12 12:41:13 +01:00
bool have_top_solid_infill = m_config -> opt_int ( "top_solid_layers" ) > 0 ;
2018-04-04 10:18:26 +02:00
for ( auto el : { "top_infill_extrusion_width" , "top_solid_infill_speed" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_top_solid_infill );
2018-01-12 12:41:13 +01:00
bool have_default_acceleration = m_config -> opt_float ( "default_acceleration" ) > 0 ;
2018-04-04 10:18:26 +02:00
for ( auto el : { "perimeter_acceleration" , "infill_acceleration" ,
"bridge_acceleration" , "first_layer_acceleration" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_default_acceleration );
2018-01-12 12:41:13 +01:00
bool have_skirt = m_config -> opt_int ( "skirts" ) > 0 || m_config -> opt_float ( "min_skirt_length" ) > 0 ;
2018-04-04 10:18:26 +02:00
for ( auto el : { "skirt_distance" , "skirt_height" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_skirt );
2018-01-12 12:41:13 +01:00
bool have_brim = m_config -> opt_float ( "brim_width" ) > 0 ;
2018-01-11 10:33:17 +01:00
// perimeter_extruder uses the same logic as in Print::extruders()
get_field ( "perimeter_extruder" ) -> toggle ( have_perimeters || have_brim );
2018-01-12 12:41:13 +01:00
bool have_raft = m_config -> opt_int ( "raft_layers" ) > 0 ;
bool have_support_material = m_config -> opt_bool ( "support_material" ) || have_raft ;
bool have_support_interface = m_config -> opt_int ( "support_material_interface_layers" ) > 0 ;
bool have_support_soluble = have_support_material && m_config -> opt_float ( "support_material_contact_distance" ) == 0 ;
2018-04-04 10:18:26 +02:00
for ( auto el : { "support_material_threshold" , "support_material_pattern" , "support_material_with_sheath" ,
2018-02-23 09:16:35 +01:00
"support_material_spacing" , "support_material_angle" , "support_material_interface_layers" ,
"dont_support_bridges" , "support_material_extrusion_width" , "support_material_contact_distance" ,
2018-04-04 10:18:26 +02:00
"support_material_xy_spacing" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_support_material );
2018-04-04 10:18:26 +02:00
for ( auto el : { "support_material_interface_spacing" , "support_material_interface_extruder" ,
"support_material_interface_speed" , "support_material_interface_contact_loops" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_support_material && have_support_interface );
get_field ( "support_material_synchronize_layers" ) -> toggle ( have_support_soluble );
get_field ( "perimeter_extrusion_width" ) -> toggle ( have_perimeters || have_skirt || have_brim );
get_field ( "support_material_extruder" ) -> toggle ( have_support_material || have_skirt );
get_field ( "support_material_speed" ) -> toggle ( have_support_material || have_brim || have_skirt );
2018-01-12 12:41:13 +01:00
bool have_sequential_printing = m_config -> opt_bool ( "complete_objects" );
2018-04-04 10:18:26 +02:00
for ( auto el : { "extruder_clearance_radius" , "extruder_clearance_height" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_sequential_printing );
2018-01-12 12:41:13 +01:00
bool have_ooze_prevention = m_config -> opt_bool ( "ooze_prevention" );
2018-01-11 10:33:17 +01:00
get_field ( "standby_temperature_delta" ) -> toggle ( have_ooze_prevention );
2018-01-12 12:41:13 +01:00
bool have_wipe_tower = m_config -> opt_bool ( "wipe_tower" );
2018-04-04 10:18:26 +02:00
for ( auto el : { "wipe_tower_x" , "wipe_tower_y" , "wipe_tower_width" , "wipe_tower_rotation_angle" , "wipe_tower_bridging" })
2018-01-11 10:33:17 +01:00
get_field ( el ) -> toggle ( have_wipe_tower );
2018-01-05 15:11:33 +01:00
2018-01-15 12:13:05 +01:00
m_recommended_thin_wall_thickness_description_line -> SetText (
2018-02-26 13:57:36 +01:00
from_u8 ( PresetHints :: recommended_thin_wall_thickness ( * m_preset_bundle )));
2018-01-15 12:13:05 +01:00
2018-01-05 15:11:33 +01:00
Thaw ();
}
2018-01-15 12:13:05 +01:00
void TabPrint :: OnActivate ()
{
2018-02-26 13:57:36 +01:00
m_recommended_thin_wall_thickness_description_line -> SetText (
from_u8 ( PresetHints :: recommended_thin_wall_thickness ( * m_preset_bundle )));
2018-01-15 12:13:05 +01:00
}
2018-01-05 15:11:33 +01:00
void TabFilament :: build ()
2017-12-22 11:50:28 +01:00
{
2018-01-12 12:41:13 +01:00
m_presets = & m_preset_bundle -> filaments ;
2018-03-16 12:56:03 +01:00
load_initial_data ();
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
auto page = add_options_page ( _ ( L ( "Filament" )), "spool.png" );
auto optgroup = page -> new_optgroup ( _ ( L ( "Filament" )));
2018-01-07 18:41:40 +01: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" );
2017-12-22 11:50:28 +01:00
2018-06-07 22:54:26 +02:00
optgroup = page -> new_optgroup ( _ ( L ( "Temperature " )) + wxString ( "°C" , wxConvUTF8 ));
2018-02-23 09:16:35 +01:00
Line line = { _ ( L ( "Extruder" )), "" };
2018-01-07 18:41:40 +01:00
line . append_option ( optgroup -> get_option ( "first_layer_temperature" ));
line . append_option ( optgroup -> get_option ( "temperature" ));
2017-12-22 11:50:28 +01:00
optgroup -> append_line ( line );
2018-02-23 09:16:35 +01:00
line = { _ ( L ( "Bed" )), "" };
2018-01-07 18:41:40 +01:00
line . append_option ( optgroup -> get_option ( "first_layer_bed_temperature" ));
line . append_option ( optgroup -> get_option ( "bed_temperature" ));
2017-12-22 11:50:28 +01:00
optgroup -> append_line ( line );
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Cooling" )), "hourglass.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Enable" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "fan_always_on" );
optgroup -> append_single_option_line ( "cooling" );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
line = { "" , "" };
2017-12-22 11:50:28 +01:00
line . full_width = 1 ;
2017-12-26 23:04:54 +01:00
line . widget = [ this ]( wxWindow * parent ) {
2018-01-15 12:13:05 +01:00
return description_line_widget ( parent , & m_cooling_description_line );
2017-12-26 23:04:54 +01:00
};
2017-12-22 11:50:28 +01:00
optgroup -> append_line ( line );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Fan settings" )));
line = { _ ( L ( "Fan speed" )), "" };
2018-01-07 18:41:40 +01:00
line . append_option ( optgroup -> get_option ( "min_fan_speed" ));
line . append_option ( optgroup -> get_option ( "max_fan_speed" ));
2017-12-22 11:50:28 +01:00
optgroup -> append_line ( line );
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "bridge_fan_speed" );
optgroup -> append_single_option_line ( "disable_fan_first_layers" );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Cooling thresholds" )), 250 );
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "fan_below_layer_time" );
optgroup -> append_single_option_line ( "slowdown_below_layer_time" );
optgroup -> append_single_option_line ( "min_print_speed" );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Advanced" )), "wrench.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Filament properties" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "filament_type" );
optgroup -> append_single_option_line ( "filament_soluble" );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Print speed override" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "filament_max_volumetric_speed" );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
line = { "" , "" };
2017-12-22 11:50:28 +01:00
line . full_width = 1 ;
2017-12-26 23:04:54 +01:00
line . widget = [ this ]( wxWindow * parent ) {
2018-01-15 12:13:05 +01:00
return description_line_widget ( parent , & m_volumetric_speed_description_line );
2017-12-26 23:04:54 +01:00
};
2017-12-22 11:50:28 +01:00
optgroup -> append_line ( line );
2018-05-02 10:52:17 +02:00
optgroup = page -> new_optgroup ( _ ( L ( "Toolchange parameters with single extruder MM printers" )));
2018-03-02 15:52:16 +01:00
optgroup -> append_single_option_line ( "filament_loading_speed" );
optgroup -> append_single_option_line ( "filament_unloading_speed" );
optgroup -> append_single_option_line ( "filament_toolchange_delay" );
2018-03-12 15:41:25 +01:00
line = { _ ( L ( "Ramming" )), "" };
line . widget = [ this ]( wxWindow * parent ){
2018-06-07 22:10:23 +02:00
auto ramming_dialog_btn = new wxButton ( parent , wxID_ANY , _ ( L ( "Ramming settings" )) + dots , wxDefaultPosition , wxDefaultSize , wxBU_EXACTFIT );
2018-03-13 15:54:29 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( ramming_dialog_btn );
ramming_dialog_btn -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent & e )
2018-03-12 15:41:25 +01:00
{
2018-03-15 14:04:12 +01:00
RammingDialog dlg ( this ,( m_config -> option < ConfigOptionStrings > ( "filament_ramming_parameters" )) -> get_at ( 0 ));
2018-03-28 15:37:10 +02:00
if ( dlg . ShowModal () == wxID_OK )
( m_config -> option < ConfigOptionStrings > ( "filament_ramming_parameters" )) -> get_at ( 0 ) = dlg . get_parameters ();
2018-03-13 15:54:29 +01:00
}));
2018-03-12 15:41:25 +01:00
return sizer ;
};
optgroup -> append_line ( line );
2018-03-02 15:52:16 +01:00
2018-03-09 15:10:15 +01:00
page = add_options_page ( _ ( L ( "Custom G-code" )), "cog.png" );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Start G-code" )), 0 );
2018-01-07 18:41:40 +01:00
Option option = optgroup -> get_option ( "start_filament_gcode" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 150 ;
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "End G-code" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "end_filament_gcode" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 150 ;
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Notes" )), "note.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Notes" )), 0 );
2017-12-22 11:50:28 +01:00
optgroup -> label_width = 0 ;
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "filament_notes" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 250 ;
2017-12-26 23:04:54 +01:00
optgroup -> append_single_option_line ( option );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Dependencies" )), "wrench.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Profile dependencies" )));
line = { _ ( L ( "Compatible printers" )), "" };
2017-12-26 23:04:54 +01:00
line . widget = [ this ]( wxWindow * parent ){
2018-01-15 12:13:05 +01:00
return compatible_printers_widget ( parent , & m_compatible_printers_checkbox , & m_compatible_printers_btn );
2017-12-26 23:04:54 +01:00
};
2018-04-13 18:22:06 +02:00
optgroup -> append_line ( line , & m_colored_Label );
2018-01-12 12:41:13 +01: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
line = Line { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_parent_preset_description_line );
};
optgroup -> append_line ( line );
2018-01-12 12:41:13 +01:00
}
// Reload current config (aka presets->edited_preset->config) into the UI fields.
void TabFilament :: reload_config (){
reload_compatible_printers_widget ();
Tab :: reload_config ();
}
void TabFilament :: update ()
{
2018-04-23 15:09:01 +02:00
Freeze ();
2018-02-22 11:34:41 +01:00
wxString text = from_u8 ( PresetHints :: cooling_description ( m_presets -> get_edited_preset ()));
2018-01-15 12:13:05 +01:00
m_cooling_description_line -> SetText ( text );
2018-02-22 11:34:41 +01:00
text = from_u8 ( PresetHints :: maximum_volumetric_flow_description ( * m_preset_bundle ));
2018-01-15 12:13:05 +01:00
m_volumetric_speed_description_line -> SetText ( text );
2018-01-12 12:41:13 +01:00
bool cooling = m_config -> opt_bool ( "cooling" , 0 );
bool fan_always_on = cooling || m_config -> opt_bool ( "fan_always_on" , 0 );
2018-04-04 10:18:26 +02:00
for ( auto el : { "max_fan_speed" , "fan_below_layer_time" , "slowdown_below_layer_time" , "min_print_speed" })
2018-01-12 12:41:13 +01:00
get_field ( el ) -> toggle ( cooling );
2018-04-04 10:18:26 +02:00
for ( auto el : { "min_fan_speed" , "disable_fan_first_layers" })
2018-01-12 12:41:13 +01:00
get_field ( el ) -> toggle ( fan_always_on );
2018-04-23 15:09:01 +02:00
Thaw ();
2018-01-12 12:41:13 +01:00
}
void TabFilament :: OnActivate ()
{
2018-02-22 11:34:41 +01:00
m_volumetric_speed_description_line -> SetText ( from_u8 ( PresetHints :: maximum_volumetric_flow_description ( * m_preset_bundle )));
2017-12-22 11:50:28 +01:00
}
2018-01-15 12:13:05 +01:00
wxSizer * Tab :: description_line_widget ( wxWindow * parent , ogStaticText * * StaticText )
2017-12-22 11:50:28 +01:00
{
2018-01-15 12:13:05 +01:00
* StaticText = new ogStaticText ( parent , "" );
2017-12-22 11:50:28 +01:00
auto font = ( new wxSystemSettings ) -> GetFont ( wxSYS_DEFAULT_GUI_FONT );
2018-01-15 12:13:05 +01:00
( * StaticText ) -> SetFont ( font );
2017-12-22 11:50:28 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
2018-04-26 12:40:17 +02:00
sizer -> Add ( * StaticText , 1 , wxEXPAND | wxALL , 0 );
2017-12-22 11:50:28 +01:00
return sizer ;
}
2018-01-25 13:46:04 +01:00
bool Tab :: current_preset_is_dirty ()
{
return m_presets -> current_is_dirty ();
}
2018-01-05 15:11:33 +01:00
void TabPrinter :: build ()
2017-12-22 11:50:28 +01:00
{
2018-01-12 12:41:13 +01:00
m_presets = & m_preset_bundle -> printers ;
2018-03-16 12:56:03 +01:00
load_initial_data ();
2017-12-22 11:50:28 +01:00
2018-04-23 11:52:03 +02:00
// to avoid redundant memory allocation / deallocation during extruders count changing
2018-04-23 15:09:01 +02:00
m_pages . reserve ( 30 );
2018-04-23 11:52:03 +02:00
2018-01-12 12:41:13 +01:00
auto * nozzle_diameter = dynamic_cast < const ConfigOptionFloats *> ( m_config -> option ( "nozzle_diameter" ));
2018-03-07 15:05:41 +01:00
m_initial_extruders_count = m_extruders_count = nozzle_diameter -> values . size ();
2018-03-21 22:21:37 +01:00
const Preset * parent_preset = m_presets -> get_selected_preset_parent ();
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
2018-02-23 09:16:35 +01:00
auto page = add_options_page ( _ ( L ( "General" )), "printer_empty.png" );
auto optgroup = page -> new_optgroup ( _ ( L ( "Size and coordinates" )));
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
Line line { _ ( L ( "Bed shape" )), "" };
2018-01-25 13:46:04 +01:00
line . widget = [ this ]( wxWindow * parent ){
2018-06-07 22:10:23 +02:00
auto btn = new wxButton ( parent , wxID_ANY , _ ( L ( " Set " )) + dots , wxDefaultPosition , wxDefaultSize , wxBU_LEFT | wxBU_EXACTFIT );
2018-02-23 09:16:35 +01:00
// btn->SetFont(Slic3r::GUI::small_font);
2018-02-22 11:34:41 +01:00
btn -> SetBitmap ( wxBitmap ( from_u8 ( Slic3r :: var ( "printer_empty.png" )), wxBITMAP_TYPE_PNG ));
2017-12-26 23:04:54 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( btn );
2018-01-25 13:46:04 +01:00
btn -> Bind ( wxEVT_BUTTON , ([ this ]( wxCommandEvent e )
2017-12-26 23:04:54 +01:00
{
2018-01-25 13:46:04 +01:00
auto dlg = new BedShapeDialog ( this );
dlg -> build_dialog ( m_config -> option < ConfigOptionPoints > ( "bed_shape" ));
2018-03-23 17:27:43 +01:00
if ( dlg -> ShowModal () == wxID_OK ){
2018-01-30 12:10:12 +01:00
load_key_value ( "bed_shape" , dlg -> GetValue ());
2018-03-23 17:27:43 +01:00
update_changed_ui ();
}
2017-12-26 23:04:54 +01:00
}));
return sizer ;
};
2018-04-13 18:22:06 +02:00
optgroup -> append_line ( line , & m_colored_Label );
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
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Capabilities" )));
2017-12-22 11:50:28 +01:00
ConfigOptionDef def ;
def . type = coInt ,
def . default_value = new ConfigOptionInt ( 1 );
2018-02-23 09:16:35 +01:00
def . label = L ( "Extruders" );
def . tooltip = L ( "Number of extruders of the printer." );
2017-12-22 11:50:28 +01:00
def . min = 1 ;
Option option ( def , "extruders_count" );
optgroup -> append_single_option_line ( option );
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "single_extruder_multi_material" );
2017-12-22 11:50:28 +01:00
2018-01-12 17:16:59 +01:00
optgroup -> m_on_change = [ this , optgroup ]( t_config_option_key opt_key , boost :: any value ){
size_t extruders_count = boost :: any_cast < int > ( optgroup -> get_value ( "extruders_count" ));
wxTheApp -> CallAfter ([ this , opt_key , value , extruders_count ](){
2018-03-22 16:13:41 +01:00
if ( opt_key . compare ( "extruders_count" ) == 0 || opt_key . compare ( "single_extruder_multi_material" ) == 0 ) {
2018-01-12 17:16:59 +01:00
extruders_count_changed ( extruders_count );
update_dirty ();
2018-04-05 10:44:31 +02:00
if ( opt_key . compare ( "single_extruder_multi_material" ) == 0 ) // the single_extruder_multimaterial was added to force pages
on_value_change ( opt_key , value ); // rebuild - let's make sure the on_value_change is not skipped
2018-01-12 17:16:59 +01:00
}
else {
update_dirty ();
on_value_change ( opt_key , value );
}
});
};
2017-12-22 11:50:28 +01:00
2018-03-22 16:13:41 +01:00
2018-01-12 17:16:59 +01:00
if ( ! m_no_controller )
2018-01-03 10:12:42 +01:00
{
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "USB/Serial connection" )));
line = { _ ( L ( "Serial port" )), "" };
2018-01-07 18:41:40 +01:00
Option serial_port = optgroup -> get_option ( "serial_port" );
2018-01-12 17:16:59 +01:00
serial_port . side_widget = ([ this ]( wxWindow * parent ){
2018-02-22 11:34:41 +01:00
auto btn = new wxBitmapButton ( parent , wxID_ANY , wxBitmap ( from_u8 ( Slic3r :: var ( "arrow_rotate_clockwise.png" )), wxBITMAP_TYPE_PNG ),
2017-12-22 11:50:28 +01:00
wxDefaultPosition , wxDefaultSize , wxBORDER_NONE );
2018-02-23 09:16:35 +01:00
btn -> SetToolTip ( _ ( L ( "Rescan serial ports" )));
2017-12-22 11:50:28 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( btn );
2018-01-12 17:16:59 +01:00
btn -> Bind ( wxEVT_BUTTON , [ this ]( wxCommandEvent e ) { update_serial_ports (); });
2017-12-22 11:50:28 +01:00
return sizer ;
});
2018-01-12 17:16:59 +01:00
auto serial_test = [ this ]( wxWindow * parent ){
auto btn = m_serial_test_btn = new wxButton ( parent , wxID_ANY ,
2018-02-23 09:16:35 +01:00
_ ( L ( "Test" )), wxDefaultPosition , wxDefaultSize , wxBU_LEFT | wxBU_EXACTFIT );
2017-12-22 11:50:28 +01:00
// btn->SetFont($Slic3r::GUI::small_font);
2018-02-22 11:34:41 +01:00
btn -> SetBitmap ( wxBitmap ( from_u8 ( Slic3r :: var ( "wrench.png" )), wxBITMAP_TYPE_PNG ));
2017-12-22 11:50:28 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( btn );
2018-01-12 17:16:59 +01:00
btn -> Bind ( wxEVT_BUTTON , [ this , parent ]( wxCommandEvent e ){
2018-01-03 10:12:42 +01:00
auto sender = new GCodeSender ();
auto res = sender -> connect (
2018-01-12 17:16:59 +01:00
m_config -> opt_string ( "serial_port" ),
m_config -> opt_int ( "serial_speed" )
2018-01-03 10:12:42 +01:00
);
if ( res && sender -> wait_connected ()) {
2018-02-23 09:16:35 +01:00
show_info ( parent , _ ( L ( "Connection to printer works correctly." )), _ ( L ( "Success!" )));
2018-01-03 10:12:42 +01:00
}
else {
2018-02-23 09:16:35 +01:00
show_error ( parent , _ ( L ( "Connection failed." )));
2018-01-03 10:12:42 +01:00
}
2017-12-26 23:04:54 +01:00
});
2017-12-22 11:50:28 +01:00
return sizer ;
2017-12-26 23:04:54 +01:00
};
2017-12-22 11:50:28 +01:00
line . append_option ( serial_port );
2018-01-26 01:44:34 +01:00
line . append_option ( optgroup -> get_option ( "serial_speed" ));
2017-12-22 11:50:28 +01:00
line . append_widget ( serial_test );
optgroup -> append_line ( line );
2018-01-03 10:12:42 +01:00
}
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "OctoPrint upload" )));
2018-03-15 18:06:26 +01:00
auto octoprint_host_browse = [ this , optgroup ] ( wxWindow * parent ) {
2018-06-07 22:10:23 +02:00
auto btn = new wxButton ( parent , wxID_ANY , _ ( L ( " Browse " )) + dots , wxDefaultPosition , wxDefaultSize , wxBU_LEFT );
2018-02-22 11:34:41 +01:00
btn -> SetBitmap ( wxBitmap ( from_u8 ( Slic3r :: var ( "zoom.png" )), wxBITMAP_TYPE_PNG ));
2017-12-22 11:50:28 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( btn );
2018-03-15 18:06:26 +01:00
btn -> Bind ( wxEVT_BUTTON , [ this , parent , optgroup ]( wxCommandEvent e ) {
BonjourDialog dialog ( parent );
if ( dialog . show_and_lookup ()) {
optgroup -> set_value ( "octoprint_host" , std :: move ( dialog . get_selected ()), true );
2018-01-26 01:44:34 +01:00
}
2018-01-03 10:12:42 +01:00
});
2017-12-22 11:50:28 +01:00
return sizer ;
2017-12-26 23:04:54 +01:00
};
auto octoprint_host_test = [ this ]( wxWindow * parent ) {
2018-02-23 09:16:35 +01:00
auto btn = m_octoprint_host_test_btn = new wxButton ( parent , wxID_ANY , _ ( L ( "Test" )),
2018-01-26 01:44:34 +01:00
wxDefaultPosition , wxDefaultSize , wxBU_LEFT | wxBU_EXACTFIT );
2018-02-22 11:34:41 +01:00
btn -> SetBitmap ( wxBitmap ( from_u8 ( Slic3r :: var ( "wrench.png" )), wxBITMAP_TYPE_PNG ));
2017-12-22 11:50:28 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( btn );
2018-03-15 18:06:26 +01:00
btn -> Bind ( wxEVT_BUTTON , [ this ]( wxCommandEvent e ) {
OctoPrint octoprint ( m_config );
wxString msg ;
if ( octoprint . test ( msg )) {
show_info ( this , _ ( L ( "Connection to OctoPrint works correctly." )), _ ( L ( "Success!" )));
} else {
const auto text = wxString :: Format ( "%s: %s \n\n %s" ,
_ ( L ( "Could not connect to OctoPrint" )), msg , _ ( L ( "Note: OctoPrint version at least 1.1.0 is required." ))
);
show_error ( this , text );
2018-01-26 01:44:34 +01:00
}
2018-03-15 18:06:26 +01:00
});
2017-12-22 11:50:28 +01:00
return sizer ;
2017-12-26 23:04:54 +01:00
};
2017-12-22 11:50:28 +01:00
2018-01-07 18:41:40 +01:00
Line host_line = optgroup -> create_single_option_line ( "octoprint_host" );
2017-12-22 11:50:28 +01:00
host_line . append_widget ( octoprint_host_browse );
host_line . append_widget ( octoprint_host_test );
optgroup -> append_line ( host_line );
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "octoprint_apikey" );
2017-12-22 11:50:28 +01:00
2018-03-15 18:06:26 +01:00
if ( Http :: ca_file_supported ()) {
Line cafile_line = optgroup -> create_single_option_line ( "octoprint_cafile" );
auto octoprint_cafile_browse = [ this , optgroup ] ( wxWindow * parent ) {
2018-06-07 22:10:23 +02:00
auto btn = new wxButton ( parent , wxID_ANY , _ ( L ( " Browse " )) + dots , wxDefaultPosition , wxDefaultSize , wxBU_LEFT );
2018-03-15 18:06:26 +01:00
btn -> SetBitmap ( wxBitmap ( from_u8 ( Slic3r :: var ( "zoom.png" )), wxBITMAP_TYPE_PNG ));
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( btn );
btn -> Bind ( wxEVT_BUTTON , [ this , optgroup ] ( wxCommandEvent e ){
static const auto filemasks = _ ( L ( "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" ));
wxFileDialog openFileDialog ( this , _ ( L ( "Open CA certificate file" )), "" , "" , filemasks , wxFD_OPEN | wxFD_FILE_MUST_EXIST );
if ( openFileDialog . ShowModal () != wxID_CANCEL ) {
optgroup -> set_value ( "octoprint_cafile" , std :: move ( openFileDialog . GetPath ()), true );
}
});
return sizer ;
};
cafile_line . append_widget ( octoprint_cafile_browse );
optgroup -> append_line ( cafile_line );
auto octoprint_cafile_hint = [ this , optgroup ] ( wxWindow * parent ) {
auto txt = new wxStaticText ( parent , wxID_ANY ,
_ ( L ( "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate." )));
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
sizer -> Add ( txt );
return sizer ;
};
Line cafile_hint { "" , "" };
cafile_hint . full_width = 1 ;
cafile_hint . widget = std :: move ( octoprint_cafile_hint );
optgroup -> append_line ( cafile_hint );
}
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Firmware" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "gcode_flavor" );
2018-06-20 14:20:48 +02:00
optgroup -> append_single_option_line ( "silent_mode" );
optgroup -> m_on_change = [ this , optgroup ]( t_config_option_key opt_key , boost :: any value ){
wxTheApp -> CallAfter ([ this , opt_key , value ](){
if ( opt_key . compare ( "gcode_flavor" ) == 0 )
build_extruder_pages ();
update_dirty ();
on_value_change ( opt_key , value );
});
};
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Advanced" )));
2018-01-07 18:41:40 +01: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
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Custom G-code" )), "cog.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Start G-code" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "start_gcode" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 150 ;
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "End G-code" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "end_gcode" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 150 ;
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Before layer change G-code" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "before_layer_gcode" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 150 ;
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "After layer change G-code" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "layer_gcode" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 150 ;
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Tool change G-code" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "toolchange_gcode" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 150 ;
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Between objects G-code (for sequential printing)" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "between_objects_gcode" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 150 ;
optgroup -> append_single_option_line ( option );
2018-02-23 09:16:35 +01:00
page = add_options_page ( _ ( L ( "Notes" )), "note.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Notes" )), 0 );
2018-01-07 18:41:40 +01:00
option = optgroup -> get_option ( "printer_notes" );
2017-12-22 11:50:28 +01:00
option . opt . full_width = true ;
option . opt . height = 250 ;
optgroup -> append_single_option_line ( option );
2018-03-22 11:46:15 +01:00
page = add_options_page ( _ ( L ( "Dependencies" )), "wrench.png" );
optgroup = page -> new_optgroup ( _ ( L ( "Profile dependencies" )));
line = Line { "" , "" };
line . full_width = 1 ;
line . widget = [ this ]( wxWindow * parent ) {
return description_line_widget ( parent , & m_parent_preset_description_line );
};
optgroup -> append_line ( line );
2017-12-26 23:04:54 +01:00
build_extruder_pages ();
2017-12-22 11:50:28 +01:00
2018-01-12 17:16:59 +01:00
if ( ! m_no_controller )
update_serial_ports ();
}
void TabPrinter :: update_serial_ports (){
Field * field = get_field ( "serial_port" );
Choice * choice = static_cast < Choice *> ( field );
2018-05-21 16:14:20 +02:00
choice -> set_values ( Utils :: scan_serial_ports ());
2018-01-12 17:16:59 +01:00
}
void TabPrinter :: extruders_count_changed ( size_t extruders_count ){
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 ();
build_extruder_pages ();
2018-03-07 15:05:41 +01:00
reload_config ();
2018-01-12 17:16:59 +01:00
on_value_change ( "extruders_count" , extruders_count );
2017-12-22 11:50:28 +01:00
}
2018-06-20 14:20:48 +02:00
PageShp TabPrinter :: create_kinematics_page ()
{
auto page = add_options_page ( _ ( L ( "Kinematics" )), "cog.png" , true );
auto optgroup = page -> new_optgroup ( _ ( L ( "Maximum accelerations" )));
// optgroup->append_single_option_line("max_acceleration_x");
// optgroup->append_single_option_line("max_acceleration_y");
// optgroup->append_single_option_line("max_acceleration_z");
optgroup = page -> new_optgroup ( _ ( L ( "Maximum feedrates" )));
// optgroup->append_single_option_line("max_feedrate_x");
// optgroup->append_single_option_line("max_feedrate_y");
// optgroup->append_single_option_line("max_feedrate_z");
optgroup = page -> new_optgroup ( _ ( L ( "Starting Acceleration" )));
// optgroup->append_single_option_line("start_acceleration");
// optgroup->append_single_option_line("start_retract_acceleration");
optgroup = page -> new_optgroup ( _ ( L ( "Advanced" )));
// optgroup->append_single_option_line("min_feedrate_for_print_moves");
// optgroup->append_single_option_line("min_feedrate_for_travel_moves");
// optgroup->append_single_option_line("max_jerk_x");
// optgroup->append_single_option_line("max_jerk_y");
// optgroup->append_single_option_line("max_jerk_z");
return page ;
}
void TabPrinter :: build_extruder_pages ()
{
2018-04-23 15:39:55 +02:00
size_t n_before_extruders = 2 ; // Count of pages before Extruder pages
2018-06-20 14:20:48 +02:00
bool is_marlin_flavor = m_config -> option < ConfigOptionEnum < GCodeFlavor >> ( "gcode_flavor" ) -> value == gcfMarlin ;
// Add/delete Kinematics page according to is_marlin_flavor
size_t existed_page = 0 ;
for ( int i = n_before_extruders ; i < m_pages . size (); ++ i ) // first make sure it's not there already
if ( m_pages [ i ] -> title (). find ( _ ( L ( "Kinematics" ))) != std :: string :: npos ) {
if ( ! is_marlin_flavor )
m_pages . erase ( m_pages . begin () + i );
else
existed_page = i ;
break ;
}
if ( existed_page < n_before_extruders && is_marlin_flavor ){
auto page = create_kinematics_page ();
m_pages . insert ( m_pages . begin () + n_before_extruders , page );
}
if ( is_marlin_flavor )
n_before_extruders ++ ;
2018-04-23 15:39:55 +02:00
size_t n_after_single_extruder_MM = 2 ; // Count of pages after single_extruder_multi_material page
2018-05-21 14:36:09 +02:00
if ( m_extruders_count_old == m_extruders_count ||
( m_has_single_extruder_MM_page && m_extruders_count == 1 ))
2018-04-18 13:32:21 +02:00
{
// if we have a single extruder MM setup, add a page with configuration options:
for ( int i = 0 ; i < m_pages . size (); ++ i ) // first make sure it's not there already
if ( m_pages [ i ] -> title (). find ( _ ( L ( "Single extruder MM setup" ))) != std :: string :: npos ) {
m_pages . erase ( m_pages . begin () + i );
break ;
}
2018-05-21 14:36:09 +02:00
m_has_single_extruder_MM_page = false ;
2018-04-18 13:32:21 +02:00
}
2018-05-21 14:36:09 +02:00
if ( m_extruders_count > 1 && m_config -> opt_bool ( "single_extruder_multi_material" ) && ! m_has_single_extruder_MM_page ) {
// create a page, but pretend it's an extruder page, so we can add it to m_pages ourselves
auto page = add_options_page ( _ ( L ( "Single extruder MM setup" )), "printer_empty.png" , true );
auto optgroup = page -> new_optgroup ( _ ( L ( "Single extruder multimaterial parameters" )));
optgroup -> append_single_option_line ( "cooling_tube_retraction" );
optgroup -> append_single_option_line ( "cooling_tube_length" );
optgroup -> append_single_option_line ( "parking_pos_retraction" );
m_pages . insert ( m_pages . end () - n_after_single_extruder_MM , page );
m_has_single_extruder_MM_page = true ;
}
2018-04-23 15:39:55 +02:00
2018-04-18 13:32:21 +02:00
for ( auto extruder_idx = m_extruders_count_old ; extruder_idx < m_extruders_count ; ++ extruder_idx ){
2017-12-22 11:50:28 +01:00
//# build page
2018-02-28 15:39:20 +01:00
char buf [ MIN_BUF_LENGTH_FOR_L ];
sprintf ( buf , _CHB ( L ( "Extruder %d" )), extruder_idx + 1 );
auto page = add_options_page ( from_u8 ( buf ), "funnel.png" , true );
2018-04-23 15:39:55 +02:00
m_pages . insert ( m_pages . begin () + n_before_extruders + extruder_idx , page );
2018-01-02 12:50:27 +01:00
2018-02-23 09:16:35 +01:00
auto optgroup = page -> new_optgroup ( _ ( L ( "Size" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "nozzle_diameter" , extruder_idx );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Layer height limits" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "min_layer_height" , extruder_idx );
optgroup -> append_single_option_line ( "max_layer_height" , extruder_idx );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Position (for multi-extruder printers)" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "extruder_offset" , extruder_idx );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Retraction" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "retract_length" , extruder_idx );
optgroup -> append_single_option_line ( "retract_lift" , extruder_idx );
2018-02-23 09:16:35 +01:00
Line line = { _ ( L ( "Only lift Z" )), "" };
2018-01-07 18:41:40 +01:00
line . append_option ( optgroup -> get_option ( "retract_lift_above" , extruder_idx ));
line . append_option ( optgroup -> get_option ( "retract_lift_below" , extruder_idx ));
2017-12-22 11:50:28 +01:00
optgroup -> append_line ( line );
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "retract_speed" , extruder_idx );
optgroup -> append_single_option_line ( "deretract_speed" , extruder_idx );
optgroup -> append_single_option_line ( "retract_restart_extra" , extruder_idx );
optgroup -> append_single_option_line ( "retract_before_travel" , extruder_idx );
optgroup -> append_single_option_line ( "retract_layer_change" , extruder_idx );
optgroup -> append_single_option_line ( "wipe" , extruder_idx );
optgroup -> append_single_option_line ( "retract_before_wipe" , extruder_idx );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Retraction when tool is disabled (advanced settings for multi-extruder setups)" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "retract_length_toolchange" , extruder_idx );
optgroup -> append_single_option_line ( "retract_restart_extra_toolchange" , extruder_idx );
2017-12-22 11:50:28 +01:00
2018-02-23 09:16:35 +01:00
optgroup = page -> new_optgroup ( _ ( L ( "Preview" )));
2018-01-07 18:41:40 +01:00
optgroup -> append_single_option_line ( "extruder_colour" , extruder_idx );
2018-01-02 12:50:27 +01:00
}
// # remove extra pages
2018-04-18 13:32:21 +02:00
if ( m_extruders_count < m_extruders_count_old )
2018-04-23 15:39:55 +02:00
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
2018-04-18 13:32:21 +02:00
m_extruders_count_old = m_extruders_count ;
2018-03-22 16:13:41 +01:00
2018-01-02 12:50:27 +01:00
rebuild_page_tree ();
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 ()
{
// update the extruders count field
auto * nozzle_diameter = dynamic_cast < const ConfigOptionFloats *> ( m_config -> option ( "nozzle_diameter" ));
int extruders_count = nozzle_diameter -> values . size ();
set_value ( "extruders_count" , extruders_count );
// update the GUI field according to the number of nozzle diameters supplied
extruders_count_changed ( extruders_count );
}
2018-01-12 17:16:59 +01:00
void TabPrinter :: update (){
Freeze ();
bool en ;
auto serial_speed = get_field ( "serial_speed" );
if ( serial_speed != nullptr ) {
en = ! m_config -> opt_string ( "serial_port" ). empty ();
get_field ( "serial_speed" ) -> toggle ( en );
if ( m_config -> opt_int ( "serial_speed" ) != 0 && en )
m_serial_test_btn -> Enable ();
else
m_serial_test_btn -> Disable ();
}
2018-03-15 18:06:26 +01:00
m_octoprint_host_test_btn -> Enable ( ! m_config -> opt_string ( "octoprint_host" ). empty ());
2018-01-12 17:16:59 +01:00
bool have_multiple_extruders = m_extruders_count > 1 ;
get_field ( "toolchange_gcode" ) -> toggle ( have_multiple_extruders );
get_field ( "single_extruder_multi_material" ) -> toggle ( have_multiple_extruders );
2018-06-20 14:20:48 +02:00
bool is_marlin_flavor = m_config -> option < ConfigOptionEnum < GCodeFlavor >> ( "gcode_flavor" ) -> value == gcfMarlin ;
get_field ( "silent_mode" ) -> toggle ( is_marlin_flavor );
2018-01-12 17:16:59 +01:00
for ( size_t i = 0 ; i < m_extruders_count ; ++ i ) {
bool have_retract_length = m_config -> opt_float ( "retract_length" , i ) > 0 ;
// when using firmware retraction, firmware decides retraction length
bool use_firmware_retraction = m_config -> opt_bool ( "use_firmware_retraction" );
get_field ( "retract_length" , i ) -> toggle ( ! use_firmware_retraction );
// user can customize travel length if we have retraction length or we"re using
// firmware retraction
get_field ( "retract_before_travel" , i ) -> toggle ( have_retract_length || use_firmware_retraction );
// 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 )
get_field ( el , i ) -> toggle ( retraction );
// retract lift above / below only applies if using retract lift
vec . resize ( 0 );
vec = { "retract_lift_above" , "retract_lift_below" };
for ( auto el : vec )
get_field ( el , i ) -> toggle ( retraction && m_config -> opt_float ( "retract_lift" , i ) > 0 );
// 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 )
get_field ( el , i ) -> toggle ( retraction && ! use_firmware_retraction );
bool wipe = m_config -> opt_bool ( "wipe" , i );
get_field ( "retract_before_wipe" , i ) -> toggle ( wipe );
if ( use_firmware_retraction && wipe ) {
auto dialog = new wxMessageDialog ( parent (),
2018-02-23 09:16:35 +01:00
_ ( L ( "The Wipe option is not available when using the Firmware Retraction mode. \n "
" \n Shall I disable it in order to enable Firmware Retraction?" )),
_ ( L ( "Firmware Retraction" )), wxICON_WARNING | wxYES | wxNO );
2018-01-12 17:16:59 +01:00
DynamicPrintConfig new_conf = * m_config ;
if ( dialog -> ShowModal () == wxID_YES ) {
2018-03-09 17:17:51 +01:00
auto wipe = static_cast < ConfigOptionBools *> ( m_config -> option ( "wipe" ) -> clone ());
2018-03-12 16:52:21 +01:00
for ( int w = 0 ; w < wipe -> values . size (); w ++ )
wipe -> values [ w ] = false ;
2018-01-12 17:16:59 +01:00
new_conf . set_key_value ( "wipe" , wipe );
}
else {
new_conf . set_key_value ( "use_firmware_retraction" , new ConfigOptionBool ( false ));
}
load_config ( new_conf );
}
get_field ( "retract_length_toolchange" , i ) -> toggle ( have_multiple_extruders );
bool toolchange_retraction = m_config -> opt_float ( "retract_length_toolchange" , i ) > 0 ;
get_field ( "retract_restart_extra_toolchange" , i ) -> toggle
( have_multiple_extruders && toolchange_retraction );
}
Thaw ();
}
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 ()
{
2018-01-16 16:28:01 +01:00
auto preset = m_presets -> get_edited_preset ();
2018-03-16 17:25:11 +01:00
2018-04-26 12:40:17 +02:00
( preset . is_default || preset . is_system ) ? m_btn_delete_preset -> Disable () : m_btn_delete_preset -> Enable ( true );
2018-03-13 16:14:36 +01:00
update ();
// For the printer profile, generate the extruder pages.
on_preset_loaded ();
// Reload preset pages with the new configuration values.
reload_config ();
2018-04-16 11:03:08 +02:00
m_bmp_non_system = m_presets -> get_selected_preset_parent () ? & m_bmp_value_unlock : & m_bmp_white_bullet ;
2018-04-24 14:11:23 +02:00
m_ttg_non_system = m_presets -> get_selected_preset_parent () ? & m_ttg_value_unlock : & m_ttg_white_bullet_ns ;
m_tt_non_system = m_presets -> get_selected_preset_parent () ? & m_tt_value_unlock : & m_ttg_white_bullet_ns ;
2018-03-13 16:14:36 +01:00
2018-01-16 16:28:01 +01: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)
2018-01-26 03:24:01 +01:00
wxTheApp -> CallAfter ([ this ]{
2018-02-09 11:04:34 +01:00
// checking out if this Tab exists till this moment
if ( ! checked_tab ( this ))
return ;
2018-01-16 16:28:01 +01:00
update_tab_ui ();
on_presets_changed ();
2018-03-13 16:14:36 +01:00
2018-03-14 15:38:54 +01:00
if ( name () == "print" )
2018-03-13 16:14:36 +01:00
update_frequently_changed_parameters ();
2018-03-21 22:21:37 +01:00
if ( m_name == "printer" ){
2018-03-14 15:38:54 +01:00
static_cast < TabPrinter *> ( this ) -> m_initial_extruders_count = static_cast < TabPrinter *> ( this ) -> m_extruders_count ;
2018-03-21 22:21:37 +01: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 ();
}
2018-04-18 13:32:21 +02:00
m_opt_status_value = ( m_presets -> get_selected_preset_parent () ? osSystemValue : 0 ) | osInitValue ;
init_options_list ();
2018-03-14 15:38:54 +01:00
update_changed_ui ();
2018-01-26 03:24:01 +01:00
});
2018-01-05 15:11:33 +01:00
}
2017-12-13 14:45:10 +01:00
//Regerenerate content of the page tree.
2018-01-05 15:11:33 +01:00
void Tab :: rebuild_page_tree ()
2017-12-13 14:45:10 +01:00
{
Freeze ();
// get label of the currently selected item
2017-12-26 23:04:54 +01:00
auto selected = m_treectrl -> GetItemText ( m_treectrl -> GetSelection ());
auto rootItem = m_treectrl -> GetRootItem ();
2018-04-23 15:09:01 +02:00
2017-12-13 14:45:10 +01:00
auto have_selection = 0 ;
2018-04-23 15:39:55 +02:00
m_treectrl -> DeleteChildren ( rootItem );
2017-12-26 23:04:54 +01:00
for ( auto p : m_pages )
2017-12-13 14:45:10 +01:00
{
2017-12-26 23:04:54 +01:00
auto itemId = m_treectrl -> AppendItem ( rootItem , p -> title (), p -> iconID ());
2018-04-23 15:39:55 +02:00
m_treectrl -> SetItemTextColour ( itemId , p -> get_item_colour ());
2017-12-13 14:45:10 +01:00
if ( p -> title () == selected ) {
2017-12-26 23:04:54 +01:00
m_disable_tree_sel_changed_event = 1 ;
m_treectrl -> SelectItem ( itemId );
m_disable_tree_sel_changed_event = 0 ;
2017-12-13 14:45:10 +01:00
have_selection = 1 ;
}
}
2018-04-23 15:39:55 +02:00
2017-12-13 14:45:10 +01:00
if ( ! have_selection ) {
// this is triggered on first load, so we don't disable the sel change event
2017-12-26 23:04:54 +01:00
m_treectrl -> SelectItem ( m_treectrl -> GetFirstVisibleItem ()); //! (treectrl->GetFirstChild(rootItem));
2017-12-13 14:45:10 +01:00
}
Thaw ();
}
2018-01-16 16:28:01 +01:00
// Called by the UI combo box when the user switches profiles.
// 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.
2018-04-13 12:35:04 +02:00
void Tab :: select_preset ( const std :: string & preset_name /*= ""*/ )
2018-01-16 16:28:01 +01:00
{
2018-01-26 01:44:34 +01:00
std :: string name = preset_name ;
2018-01-16 16:28:01 +01:00
auto force = false ;
auto presets = m_presets ;
// If no name is provided, select the "-- default --" preset.
if ( name . empty ())
name = presets -> default_preset (). name ;
auto current_dirty = presets -> current_is_dirty ();
auto canceled = false ;
auto printer_tab = presets -> name (). compare ( "printer" ) == 0 ;
m_reload_dependent_tabs = {};
if ( ! force && current_dirty && ! may_discard_current_dirty_preset ()) {
canceled = true ;
} 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.
auto new_printer_preset = presets -> find_preset ( name , true );
auto print_presets = & m_preset_bundle -> prints ;
bool print_preset_dirty = print_presets -> current_is_dirty ();
bool print_preset_compatible = print_presets -> get_edited_preset (). is_compatible_with_printer ( * new_printer_preset );
canceled = ! force && print_preset_dirty && ! print_preset_compatible &&
! may_discard_current_dirty_preset ( print_presets , name );
auto filament_presets = & m_preset_bundle -> filaments ;
bool filament_preset_dirty = filament_presets -> current_is_dirty ();
bool filament_preset_compatible = filament_presets -> get_edited_preset (). is_compatible_with_printer ( * new_printer_preset );
if ( ! canceled && ! force ) {
canceled = filament_preset_dirty && ! filament_preset_compatible &&
! may_discard_current_dirty_preset ( filament_presets , name );
}
if ( ! canceled ) {
if ( ! print_preset_compatible ) {
// The preset will be switched to a different, compatible preset, or the '-- default --'.
2018-01-25 13:46:04 +01:00
m_reload_dependent_tabs . push_back ( "print" );
2018-01-16 16:28:01 +01:00
if ( print_preset_dirty ) print_presets -> discard_current_changes ();
}
if ( ! filament_preset_compatible ) {
// The preset will be switched to a different, compatible preset, or the '-- default --'.
2018-01-25 13:46:04 +01:00
m_reload_dependent_tabs . push_back ( "filament" );
2018-01-16 16:28:01 +01:00
if ( filament_preset_dirty ) filament_presets -> discard_current_changes ();
}
}
}
if ( canceled ) {
update_tab_ui ();
// Trigger the on_presets_changed event so that we also restore the previous value in the plater selector,
// if this action was initiated from the platter.
on_presets_changed ();
}
else {
if ( current_dirty ) presets -> discard_current_changes () ;
presets -> select_preset_by_name ( name , force );
// 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.
if ( current_dirty || printer_tab )
m_preset_bundle -> update_compatible_with_printer ( true );
// Initialize the UI from the current preset.
2018-01-26 01:44:34 +01:00
load_current_preset ();
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
{
if ( presets == nullptr ) presets = m_presets ;
// Display a dialog showing the dirty options in a human readable form.
auto old_preset = presets -> get_edited_preset ();
auto type_name = presets -> name ();
auto tab = " " ;
auto name = old_preset . is_default ?
2018-02-23 09:16:35 +01:00
_ ( L ( "Default " )) + type_name + _ ( L ( " preset" )) :
( type_name + _ ( L ( " preset \n " )) + tab + old_preset . name );
2018-01-16 16:28:01 +01:00
// Collect descriptions of the dirty options.
std :: vector < std :: string > option_names ;
for ( auto opt_key : presets -> current_dirty_options ()) {
auto opt = m_config -> def () -> options . at ( opt_key );
std :: string name = "" ;
if ( ! opt . category . empty ())
name += opt . category + " > " ;
name += ! opt . full_label . empty () ?
opt . full_label :
opt . label ;
option_names . push_back ( name );
}
// Show a confirmation dialog with the list of dirty options.
std :: string changes = "" ;
for ( auto changed_name : option_names )
changes += tab + changed_name + " \n " ;
auto message = ( ! new_printer_name . empty ()) ?
2018-02-23 09:16:35 +01:00
name + _ ( L ( " \n\n is not compatible with printer \n " )) + tab + new_printer_name + _ ( L ( " \n\n and it has the following unsaved changes:" )) :
name + _ ( L ( " \n\n has the following unsaved changes:" ));
2018-01-16 16:28:01 +01:00
auto confirm = new wxMessageDialog ( parent (),
2018-02-23 09:16:35 +01:00
message + " \n " + changes + _ ( L ( " \n\n Discard changes and continue anyway?" )),
_ ( L ( "Unsaved Changes" )), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION );
2018-01-16 16:28:01 +01:00
return confirm -> ShowModal () == wxID_YES ;
}
2018-01-05 15:11:33 +01:00
void Tab :: OnTreeSelChange ( wxTreeEvent & event )
2017-12-13 14:45:10 +01:00
{
2017-12-26 23:04:54 +01:00
if ( m_disable_tree_sel_changed_event ) return ;
2018-06-11 16:56:35 +02:00
// There is a bug related to Ubuntu overlay scrollbars, see https://github.com/prusa3d/Slic3r/issues/898 and https://github.com/prusa3d/Slic3r/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.
#ifdef __linux__
std :: unique_ptr < wxWindowUpdateLocker > no_updates ( new wxWindowUpdateLocker ( this ));
#else
2018-04-17 10:15:48 +02:00
wxWindowUpdateLocker noUpdates ( this );
2018-06-11 16:56:35 +02:00
#endif
2018-04-17 10:15:48 +02:00
2018-01-05 15:11:33 +01:00
Page * page = nullptr ;
2017-12-26 23:04:54 +01:00
auto selection = m_treectrl -> GetItemText ( m_treectrl -> GetSelection ());
for ( auto p : m_pages )
2017-12-13 14:45:10 +01:00
if ( p -> title () == selection )
2017-12-05 15:54:01 +01:00
{
2017-12-13 14:45:10 +01:00
page = p . get ();
2018-03-22 09:37:42 +01:00
m_is_nonsys_values = page -> m_is_nonsys_values ;
m_is_modified_values = page -> m_is_modified_values ;
2017-12-05 15:54:01 +01:00
break ;
}
if ( page == nullptr ) return ;
2017-12-26 23:04:54 +01:00
for ( auto & el : m_pages )
2017-12-13 14:45:10 +01:00
el . get () -> Hide ();
2018-06-11 16:56:35 +02:00
#ifdef __linux__
no_updates . reset ( nullptr );
#endif
2017-12-05 15:54:01 +01:00
page -> Show ();
2017-12-26 23:04:54 +01:00
m_hsizer -> Layout ();
2017-12-13 14:45:10 +01:00
Refresh ();
2018-03-22 09:37:42 +01:00
update_undo_buttons ();
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
{
2018-01-21 21:56:20 +01:00
if ( event . GetKeyCode () == WXK_TAB )
m_treectrl -> Navigate ( event . ShiftDown () ? wxNavigationKeyEvent :: IsBackward : wxNavigationKeyEvent :: IsForward );
else
2017-12-05 15:54:01 +01:00
event . Skip ();
2018-01-16 16:28:01 +01:00
}
2017-12-05 15:54:01 +01:00
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
// opens a Slic3r::GUI::SavePresetWindow dialog.
void Tab :: save_preset ( std :: string name /*= ""*/ )
{
// 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 ?
//! m_treectrl->OnSetFocus();
2017-12-05 15:54:01 +01:00
2018-01-16 16:28:01 +01:00
if ( name . empty ()) {
auto preset = m_presets -> get_selected_preset ();
auto default_name = preset . is_default ? "Untitled" : preset . name ;
2018-01-18 11:45:25 +01:00
bool have_extention = boost :: iends_with ( default_name , ".ini" );
if ( have_extention )
{
size_t len = default_name . length () - 4 ;
default_name . resize ( len );
}
//[map $_->name, grep !$_->default && !$_->external, @{$self->{presets}}],
std :: vector < std :: string > values ;
for ( size_t i = 0 ; i < m_presets -> size (); ++ i ) {
const Preset & preset = m_presets -> preset ( i );
2018-03-09 16:37:33 +01:00
if ( preset . is_default || preset . is_system || preset . is_external )
2018-01-18 11:45:25 +01:00
continue ;
values . push_back ( preset . name );
}
auto dlg = new SavePresetWindow ( parent ());
dlg -> build ( title (), default_name , values );
if ( dlg -> ShowModal () != wxID_OK )
return ;
name = dlg -> get_name ();
if ( name == "" ){
2018-02-23 09:16:35 +01:00
show_error ( this , _ ( L ( "The supplied name is empty. It can't be saved." )));
2018-01-18 11:45:25 +01:00
return ;
}
2018-03-09 16:37:33 +01:00
const Preset * existing = m_presets -> find_preset ( name , false );
if ( existing && ( existing -> is_default || existing -> is_system )) {
show_error ( this , _ ( L ( "Cannot overwrite a system profile." )));
return ;
}
if ( existing && ( existing -> is_external )) {
2018-05-14 12:59:19 +02:00
show_error ( this , _ ( L ( "Cannot overwrite an external profile." )));
2018-03-09 16:37:33 +01:00
return ;
}
2018-01-16 16:28:01 +01:00
}
2018-02-16 15:41:33 +01:00
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
m_presets -> save_current_preset ( name );
2018-01-16 16:28:01 +01:00
// Mark the print & filament enabled if they are compatible with the currently selected preset.
m_preset_bundle -> update_compatible_with_printer ( false );
// Add the new item into the UI component, remove dirty flags and activate the saved item.
update_tab_ui ();
// Update the selection boxes at the platter.
on_presets_changed ();
2018-03-16 12:56:03 +01:00
2018-03-19 17:21:37 +01:00
if ( m_name == "printer" )
static_cast < TabPrinter *> ( this ) -> m_initial_extruders_count = static_cast < TabPrinter *> ( this ) -> m_extruders_count ;
2018-03-16 12:56:03 +01:00
update_changed_ui ();
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
{
auto current_preset = m_presets -> get_selected_preset ();
// Don't let the user delete the ' - default - ' configuration.
2018-02-23 09:16:35 +01:00
wxString action = current_preset . is_external ? _ ( L ( "remove" )) : _ ( L ( "delete" ));
wxString msg = _ ( L ( "Are you sure you want to " )) + action + _ ( L ( " the selected preset?" ));
action = current_preset . is_external ? _ ( L ( "Remove" )) : _ ( L ( "Delete" ));
wxString title = action + _ ( L ( " Preset" ));
2018-01-16 16:28:01 +01:00
if ( current_preset . is_default ||
2018-02-13 16:05:53 +01:00
wxID_YES != wxMessageDialog ( parent (), msg , title , wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ). ShowModal ())
2018-01-16 16:28:01 +01:00
return ;
// Delete the file and select some other reasonable preset.
// 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 )
{
return ;
}
// Load the newly selected preset into the UI, update selection combo boxes with their dirty flags.
load_current_preset ();
}
2018-01-18 11:45:25 +01:00
void Tab :: toggle_show_hide_incompatible ()
2018-01-16 16:28:01 +01:00
{
m_show_incompatible_presets = ! m_show_incompatible_presets ;
update_show_hide_incompatible_button ();
update_tab_ui ();
}
void Tab :: update_show_hide_incompatible_button ()
{
m_btn_hide_incompatible_presets -> SetBitmap ( m_show_incompatible_presets ?
2018-04-16 11:03:08 +02:00
m_bmp_show_incompatible_presets : m_bmp_hide_incompatible_presets );
2018-01-16 16:28:01 +01:00
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." );
}
void Tab :: update_ui_from_settings ()
{
// Show the 'show / hide presets' button only for the print and filament tabs, and only if enabled
// in application preferences.
2018-02-27 09:51:14 +01:00
m_show_btn_incompatible_presets = get_app_config () -> get ( "show_incompatible_presets" )[ 0 ] == '1' ? true : false ;
2018-01-16 16:28:01 +01:00
bool show = m_show_btn_incompatible_presets && m_presets -> name (). compare ( "printer" ) != 0 ;
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 ();
}
}
}
// Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer.
2018-01-15 12:13:05 +01:00
wxSizer * Tab :: compatible_printers_widget ( wxWindow * parent , wxCheckBox ** checkbox , wxButton ** btn )
2017-12-19 11:59:42 +01:00
{
2018-02-23 09:16:35 +01:00
* checkbox = new wxCheckBox ( parent , wxID_ANY , _ ( L ( "All" )));
2018-06-07 22:10:23 +02:00
* btn = new wxButton ( parent , wxID_ANY , _ ( L ( " Set " )) + dots , wxDefaultPosition , wxDefaultSize , wxBU_LEFT | wxBU_EXACTFIT );
2018-01-15 12:13:05 +01:00
2018-02-22 11:34:41 +01:00
( * btn ) -> SetBitmap ( wxBitmap ( from_u8 ( Slic3r :: var ( "printer_empty.png" )), wxBITMAP_TYPE_PNG ));
2017-12-19 11:59:42 +01:00
auto sizer = new wxBoxSizer ( wxHORIZONTAL );
2018-01-15 12:13:05 +01:00
sizer -> Add (( * checkbox ), 0 , wxALIGN_CENTER_VERTICAL );
sizer -> Add (( * btn ), 0 , wxALIGN_CENTER_VERTICAL );
2017-12-19 11:59:42 +01:00
2018-01-15 12:13:05 +01:00
( * checkbox ) -> Bind ( wxEVT_CHECKBOX , ([ = ]( wxCommandEvent e )
2017-12-19 11:59:42 +01:00
{
2018-01-15 12:13:05 +01:00
( * btn ) -> Enable ( ! ( * checkbox ) -> GetValue ());
2018-01-12 12:41:13 +01:00
// All printers have been made compatible with this preset.
2018-01-15 12:13:05 +01:00
if (( * checkbox ) -> GetValue ())
2018-01-12 12:41:13 +01:00
load_key_value ( "compatible_printers" , std :: vector < std :: string > {});
2018-01-15 12:13:05 +01:00
get_field ( "compatible_printers_condition" ) -> toggle (( * checkbox ) -> GetValue ());
2018-04-13 18:22:06 +02:00
update_changed_ui ();
2017-12-19 11:59:42 +01:00
}) );
2018-01-15 12:13:05 +01:00
( * btn ) -> Bind ( wxEVT_BUTTON , ([ this , parent , checkbox , btn ]( wxCommandEvent e )
2017-12-19 11:59:42 +01:00
{
// # Collect names of non-default non-external printer profiles.
2018-01-12 17:16:59 +01:00
PresetCollection * printers = & m_preset_bundle -> printers ;
2017-12-19 11:59:42 +01:00
wxArrayString presets ;
for ( size_t idx = 0 ; idx < printers -> size (); ++ idx )
{
Preset & preset = printers -> preset ( idx );
2018-03-09 16:37:33 +01:00
if ( ! preset . is_default && ! preset . is_external && ! preset . is_system )
2017-12-19 11:59:42 +01:00
presets . Add ( preset . name );
}
2018-04-11 12:21:15 +02:00
wxMultiChoiceDialog dlg ( parent ,
_ ( L ( "Select the printers this profile is compatible with." )),
_ ( L ( "Compatible printers" )), presets );
2017-12-19 11:59:42 +01:00
// # Collect and set indices of printers marked as compatible.
wxArrayInt selections ;
2018-01-12 12:41:13 +01:00
auto * compatible_printers = dynamic_cast < const ConfigOptionStrings *> ( m_config -> option ( "compatible_printers" ));
2017-12-19 11:59:42 +01:00
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 ]. compare ( preset_name ) == 0 )
{
selections . Add ( idx );
break ;
}
2018-04-11 12:21:15 +02:00
dlg . SetSelections ( selections );
2018-01-12 12:41:13 +01:00
std :: vector < std :: string > value ;
// Show the dialog.
2018-04-11 12:21:15 +02:00
if ( dlg . ShowModal () == wxID_OK ) {
2017-12-19 11:59:42 +01:00
selections . Clear ();
2018-04-11 12:21:15 +02:00
selections = dlg . GetSelections ();
2017-12-19 11:59:42 +01:00
for ( auto idx : selections )
value . push_back ( presets [ idx ]. ToStdString ());
2018-01-12 12:41:13 +01:00
if ( value . empty ()) {
2018-01-15 12:13:05 +01:00
( * checkbox ) -> SetValue ( 1 );
( * btn ) -> Disable ();
2017-12-19 11:59:42 +01:00
}
2018-01-12 12:41:13 +01:00
// All printers have been made compatible with this preset.
load_key_value ( "compatible_printers" , value );
2018-04-13 18:22:06 +02:00
update_changed_ui ();
2017-12-19 11:59:42 +01:00
}
}));
return sizer ;
}
2018-04-10 14:00:48 +02:00
void Tab :: update_presetsctrl ( wxDataViewTreeCtrl * ui , bool show_incompatible )
{
if ( ui == nullptr )
return ;
ui -> Freeze ();
ui -> DeleteAllItems ();
auto presets = m_presets -> get_presets ();
auto idx_selected = m_presets -> get_idx_selected ();
auto suffix_modified = m_presets -> get_suffix_modified ();
int icon_compatible = 0 ;
int icon_incompatible = 1 ;
int cnt_items = 0 ;
auto root_sys = ui -> AppendContainer ( wxDataViewItem ( 0 ), _ ( L ( "System presets" )));
auto root_def = ui -> AppendContainer ( wxDataViewItem ( 0 ), _ ( L ( "Default presets" )));
auto show_def = get_app_config () -> get ( "no_defaults" )[ 0 ] != '1' ;
for ( size_t i = presets . front (). is_visible ? 0 : 1 ; i < presets . size (); ++ i ) {
const Preset & preset = presets [ i ];
if ( ! preset . is_visible || ( ! show_incompatible && ! preset . is_compatible && i != idx_selected ))
continue ;
auto preset_name = wxString :: FromUTF8 (( preset . name + ( preset . is_dirty ? suffix_modified : "" )). c_str ());
wxDataViewItem item ;
if ( preset . is_system )
item = ui -> AppendItem ( root_sys , preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
else if ( show_def && preset . is_default )
item = ui -> AppendItem ( root_def , preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
else
{
auto parent = m_presets -> get_preset_parent ( preset );
if ( parent == nullptr )
item = ui -> AppendItem ( root_def , preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
else
{
auto parent_name = parent -> name ;
wxDataViewTreeStoreContainerNode * node = ui -> GetStore () -> FindContainerNode ( root_sys );
if ( node )
{
wxDataViewTreeStoreNodeList :: iterator iter ;
for ( iter = node -> GetChildren (). begin (); iter != node -> GetChildren (). end (); iter ++ )
{
wxDataViewTreeStoreNode * child = * iter ;
auto child_item = child -> GetItem ();
auto item_text = ui -> GetItemText ( child_item );
if ( item_text == parent_name )
{
auto added_child = ui -> AppendItem ( child -> GetItem (), preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
if ( ! added_child ){
ui -> DeleteItem ( child -> GetItem ());
auto new_parent = ui -> AppendContainer ( root_sys , parent_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
ui -> AppendItem ( new_parent , preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
}
break ;
}
}
}
}
}
cnt_items ++ ;
if ( i == idx_selected ){
ui -> Select ( item );
m_cc_presets_choice -> SetText ( preset_name );
}
}
if ( ui -> GetStore () -> GetChildCount ( root_def ) == 0 )
ui -> DeleteItem ( root_def );
ui -> Thaw ();
}
2018-04-06 15:42:52 +02:00
void Tab :: update_tab_presets ( wxComboCtrl * ui , bool show_incompatible )
{
if ( ui == nullptr )
return ;
ui -> Freeze ();
ui -> Clear ();
auto presets = m_presets -> get_presets ();
auto idx_selected = m_presets -> get_idx_selected ();
auto suffix_modified = m_presets -> get_suffix_modified ();
int icon_compatible = 0 ;
int icon_incompatible = 1 ;
int cnt_items = 0 ;
wxDataViewTreeCtrlComboPopup * popup = wxDynamicCast ( m_cc_presets_choice -> GetPopupControl (), wxDataViewTreeCtrlComboPopup );
if ( popup != nullptr )
{
popup -> DeleteAllItems ();
2018-04-09 16:50:17 +02:00
2018-04-06 15:42:52 +02:00
auto root_sys = popup -> AppendContainer ( wxDataViewItem ( 0 ), _ ( L ( "System presets" )));
2018-04-09 16:50:17 +02:00
auto root_def = popup -> AppendContainer ( wxDataViewItem ( 0 ), _ ( L ( "Default presets" )));
2018-04-09 12:41:25 +02:00
auto show_def = get_app_config () -> get ( "no_defaults" )[ 0 ] != '1' ;
2018-04-06 15:42:52 +02:00
for ( size_t i = presets . front (). is_visible ? 0 : 1 ; i < presets . size (); ++ i ) {
const Preset & preset = presets [ i ];
if ( ! preset . is_visible || ( ! show_incompatible && ! preset . is_compatible && i != idx_selected ))
continue ;
auto preset_name = wxString :: FromUTF8 (( preset . name + ( preset . is_dirty ? suffix_modified : "" )). c_str ());
2018-04-09 09:55:24 +02:00
wxDataViewItem item ;
2018-04-09 12:41:25 +02:00
if ( preset . is_system )
item = popup -> AppendItem ( root_sys , preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
else if ( show_def && preset . is_default )
item = popup -> AppendItem ( root_def , preset_name ,
2018-04-09 09:55:24 +02:00
preset . is_compatible ? icon_compatible : icon_incompatible );
2018-04-09 16:50:17 +02:00
else
{
auto parent = m_presets -> get_preset_parent ( preset );
if ( parent == nullptr )
item = popup -> AppendItem ( root_def , preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
else
{
auto parent_name = parent -> name ;
wxDataViewTreeStoreContainerNode * node = popup -> GetStore () -> FindContainerNode ( root_sys );
if ( node )
{
wxDataViewTreeStoreNodeList :: iterator iter ;
for ( iter = node -> GetChildren (). begin (); iter != node -> GetChildren (). end (); iter ++ )
{
wxDataViewTreeStoreNode * child = * iter ;
auto child_item = child -> GetItem ();
auto item_text = popup -> GetItemText ( child_item );
if ( item_text == parent_name )
{
auto added_child = popup -> AppendItem ( child -> GetItem (), preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
if ( ! added_child ){
popup -> DeleteItem ( child -> GetItem ());
auto new_parent = popup -> AppendContainer ( root_sys , parent_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
popup -> AppendItem ( new_parent , preset_name ,
preset . is_compatible ? icon_compatible : icon_incompatible );
}
break ;
}
}
}
}
2018-04-09 09:55:24 +02:00
}
2018-04-06 15:42:52 +02:00
cnt_items ++ ;
if ( i == idx_selected ){
popup -> Select ( item );
m_cc_presets_choice -> SetText ( preset_name );
}
}
2018-04-09 16:50:17 +02:00
if ( popup -> GetStore () -> GetChildCount ( root_def ) == 0 )
popup -> DeleteItem ( root_def );
2018-04-06 15:42:52 +02:00
}
ui -> Thaw ();
}
2018-04-20 12:58:07 +02:00
void Tab :: fill_icon_descriptions ()
{
m_icon_descriptions . push_back ( t_icon_description ( & m_bmp_value_lock , L ( "LOCKED LOCK;"
2018-04-24 08:49:37 +02:00
"indicates that the settings are the same as the system values for the current option group" )));
2018-04-20 12:58:07 +02:00
m_icon_descriptions . push_back ( t_icon_description ( & m_bmp_value_unlock , L ( "UNLOCKED LOCK;"
2018-04-24 08:49:37 +02:00
"indicates that some settings were changed and are not equal to the system values for "
"the current option group. \n "
"Click the UNLOCKED LOCK icon to reset all settings for current option group to "
"the system values." )));
2018-04-20 12:58:07 +02:00
m_icon_descriptions . push_back ( t_icon_description ( & m_bmp_white_bullet , L ( "WHITE BULLET;"
2018-04-24 08:49:37 +02:00
"for the left button: \t indicates a non-system preset, \n "
"for the right button: \t indicates that the settings hasn't been modified." )));
2018-04-20 12:58:07 +02:00
m_icon_descriptions . push_back ( t_icon_description ( & m_bmp_value_revert , L ( "BACK ARROW;"
2018-04-24 08:49:37 +02:00
"indicates that the settings were changed and are not equal to the last saved preset for "
"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 ()
{
// m_undo_to_sys_btn->SetToolTip(_(L( "LOCKED LOCK icon indicates that the settings are the same as the system values "
// "for the current option group.\n"
// "UNLOCKED LOCK icon indicates that some settings were changed and are not equal "
// "to the system values for the current option group.\n"
// "WHITE BULLET icon indicates a non system preset.\n\n"
// "Click the UNLOCKED LOCK icon to reset all settings for current option group to "
// "the system values.")));
//
// m_undo_btn->SetToolTip(_(L( "WHITE BULLET icon indicates that the settings are the same as in the last saved"
// "preset for the current option group.\n"
// "BACK ARROW icon indicates that the settings were changed and are not equal to "
// "the last saved preset for the current option group.\n\n"
// "Click the BACK ARROW icon to reset all settings for the current option group to "
// "the last saved preset.")));
// --- 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 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 values for the current option group. \n "
"Click to reset all settings for current option group to the system values." ));
m_ttg_white_bullet_ns = _ ( L ( "WHITE BULLET icon indicates a non system 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." ));
// --- 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 value." ));
m_tt_value_unlock = _ ( L ( "UNLOCKED LOCK icon indicates that the value was changed and is not equal "
"to the system value. \n "
"Click to reset current value to the system 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-01-11 10:33:17 +01:00
void Page :: reload_config ()
{
for ( auto group : m_optgroups )
group -> reload_config ();
}
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
{
Field * field = nullptr ;
for ( auto opt : m_optgroups ){
field = opt -> get_fieldc ( opt_key , opt_index );
if ( field != nullptr )
return field ;
}
return field ;
}
2018-04-13 12:35:04 +02:00
bool Page :: set_value ( const t_config_option_key & opt_key , const boost :: any & value ){
2018-01-16 16:28:01 +01:00
bool changed = false ;
for ( auto optgroup : m_optgroups ) {
if ( optgroup -> set_value ( opt_key , value ))
changed = 1 ;
}
return changed ;
}
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
{
//! config_ have to be "right"
2018-03-07 15:05:41 +01:00
ConfigOptionsGroupShp optgroup = std :: make_shared < ConfigOptionsGroup > ( this , title , m_config , true );
2017-12-22 11:50:28 +01:00
if ( noncommon_label_width >= 0 )
optgroup -> label_width = noncommon_label_width ;
2017-12-13 14:45:10 +01:00
2018-01-05 15:11:33 +01:00
optgroup -> m_on_change = [ this ]( t_config_option_key opt_key , boost :: any value ){
2018-01-18 16:36:26 +01:00
//! This function will be called from OptionGroup.
//! Using of CallAfter is redundant.
2018-01-26 01:44:34 +01:00
//! 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]() {
2018-01-05 15:11:33 +01:00
static_cast < Tab *> ( GetParent ()) -> update_dirty ();
static_cast < Tab *> ( GetParent ()) -> on_value_change ( opt_key , value );
2018-01-18 16:36:26 +01:00
//! });
};
2017-12-13 14:45:10 +01:00
2018-03-06 12:34:20 +01:00
optgroup -> m_get_initial_config = [ this ](){
DynamicPrintConfig config = static_cast < Tab *> ( GetParent ()) -> m_presets -> get_selected_preset (). config ;
return config ;
};
2018-03-16 17:25:11 +01:00
optgroup -> m_get_sys_config = [ this ](){
DynamicPrintConfig config = static_cast < Tab *> ( GetParent ()) -> m_presets -> get_selected_preset_parent () -> config ;
return config ;
};
optgroup -> have_sys_config = [ this ](){
return static_cast < Tab *> ( GetParent ()) -> m_presets -> get_selected_preset_parent () != nullptr ;
};
2017-12-13 14:45:10 +01:00
vsizer () -> Add ( optgroup -> sizer , 0 , wxEXPAND | wxALL , 10 );
2017-12-26 23:04:54 +01:00
m_optgroups . push_back ( optgroup );
2017-12-13 14:45:10 +01:00
return optgroup ;
}
2018-04-13 12:35:04 +02:00
void SavePresetWindow :: build ( const wxString & title , const std :: string & default_name , std :: vector < std :: string > & values )
2018-01-18 11:45:25 +01:00
{
2018-02-23 09:16:35 +01:00
auto text = new wxStaticText ( this , wxID_ANY , _ ( L ( "Save " )) + title + _ ( L ( " as:" )),
2018-02-08 10:58:13 +01:00
wxDefaultPosition , wxDefaultSize );
2018-02-22 11:34:41 +01:00
m_combo = new wxComboBox ( this , wxID_ANY , from_u8 ( default_name ),
2018-02-05 11:03:13 +01:00
wxDefaultPosition , wxDefaultSize , 0 , 0 , wxTE_PROCESS_ENTER );
2018-01-18 11:45:25 +01:00
for ( auto value : values )
2018-02-22 11:34:41 +01:00
m_combo -> Append ( from_u8 ( value ));
2018-01-18 11:45:25 +01:00
auto buttons = CreateStdDialogButtonSizer ( wxOK | wxCANCEL );
auto sizer = new wxBoxSizer ( wxVERTICAL );
sizer -> Add ( text , 0 , wxEXPAND | wxALL , 10 );
sizer -> Add ( m_combo , 0 , wxEXPAND | wxLEFT | wxRIGHT , 10 );
sizer -> Add ( buttons , 0 , wxALIGN_CENTER_HORIZONTAL | wxALL , 10 );
wxButton * btn = static_cast < wxButton *> ( FindWindowById ( wxID_OK , this ));
btn -> Bind ( wxEVT_BUTTON , [ this ]( wxCommandEvent & ) { accept (); });
m_combo -> Bind ( wxEVT_TEXT_ENTER , [ this ]( wxCommandEvent & ) { accept (); });
SetSizer ( sizer );
sizer -> SetSizeHints ( this );
}
void SavePresetWindow :: accept ()
{
2018-02-05 11:03:13 +01:00
m_chosen_name = normalize_utf8_nfc ( m_combo -> GetValue (). ToUTF8 ());
2018-01-18 11:45:25 +01:00
if ( ! m_chosen_name . empty ()) {
const char * unusable_symbols = "<>:/ \\ |?* \" " ;
bool is_unusable_symbol = false ;
for ( size_t i = 0 ; i < std :: strlen ( unusable_symbols ); i ++ ){
if ( m_chosen_name . find_first_of ( unusable_symbols [ i ]) != std :: string :: npos ){
is_unusable_symbol = true ;
break ;
}
}
if ( is_unusable_symbol ) {
2018-02-23 09:16:35 +01:00
show_error ( this , _ ( L ( "The supplied name is not valid; the following characters are not allowed:" )) + " <>:/ \\ |?* \" " );
2018-01-18 11:45:25 +01:00
}
else if ( m_chosen_name . compare ( "- default -" ) == 0 ) {
2018-02-23 09:16:35 +01:00
show_error ( this , _ ( L ( "The supplied name is not available." )));
2018-01-18 11:45:25 +01:00
}
else {
EndModal ( wxID_OK );
}
}
}
2017-12-05 15:54:01 +01:00
} // GUI
} // Slic3r