2016-09-14 09:22:41 +00:00
# The "Expert" tab at the right of the main tabbed window.
2016-10-24 14:07:36 +00:00
# This file implements following packages:
# Slic3r::GUI::Tab;
# Slic3r::GUI::Tab::Print;
# Slic3r::GUI::Tab::Filament;
# Slic3r::GUI::Tab::Printer;
# Slic3r::GUI::Tab::Page
# - Option page: For example, the Slic3r::GUI::Tab::Print has option pages "Layers and perimeters", "Infill", "Skirt and brim" ...
# Slic3r::GUI::SavePresetWindow
# - Dialog to select a new preset name to store the configuration.
# Slic3r::GUI::Tab::Preset;
# - Single preset item: name, file is default or external.
2012-06-17 20:27:05 +00:00
package Slic3r::GUI::Tab ;
use strict ;
use warnings ;
use utf8 ;
2012-06-19 12:47:02 +00:00
use File::Basename qw( basename ) ;
2012-06-18 20:27:57 +00:00
use List::Util qw( first ) ;
2014-06-14 17:59:59 +00:00
use Wx qw( :bookctrl :dialog :keycode :icon :id :misc :panel :sizer :treectrl :window
2015-12-25 16:52:10 +00:00
: button wxTheApp ) ;
2017-09-19 11:55:48 +00:00
use Wx::Event qw( EVT_BUTTON EVT_CHOICE EVT_KEY_DOWN EVT_CHECKBOX EVT_TREE_SEL_CHANGED ) ;
2014-12-25 16:35:31 +00:00
use base qw( Wx::Panel Class::Accessor ) ;
2012-06-17 20:27:05 +00:00
sub new {
2017-10-25 10:53:31 +00:00
my ( $ class , $ parent , % params ) = @ _ ;
2012-07-24 10:42:58 +00:00
my $ self = $ class - > SUPER:: new ( $ parent , - 1 , wxDefaultPosition , wxDefaultSize , wxBK_LEFT | wxTAB_TRAVERSAL ) ;
2012-06-19 15:23:10 +00:00
2017-07-11 10:02:44 +00:00
# Vertical sizer to hold the choice menu and the rest of the page.
$ self - > { sizer } = Wx::BoxSizer - > new ( wxVERTICAL ) ;
2012-06-18 14:46:43 +00:00
$ self - > { sizer } - > SetSizeHints ( $ self ) ;
$ self - > SetSizer ( $ self - > { sizer } ) ;
2017-07-11 10:02:44 +00:00
2013-03-09 15:27:18 +00:00
# preset chooser
{
2012-06-18 20:27:57 +00:00
2013-03-09 15:27:18 +00:00
# choice menu
2017-07-11 10:02:44 +00:00
$ self - > { presets_choice } = Wx::Choice - > new ( $ self , - 1 , wxDefaultPosition , [ 270 , - 1 ] , [] ) ;
2013-03-09 15:27:18 +00:00
$ self - > { presets_choice } - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
2012-10-22 14:03:08 +00:00
2013-03-09 15:27:18 +00:00
# buttons
2017-10-25 10:53:31 +00:00
$ self - > { btn_save_preset } = Wx::BitmapButton - > new ( $ self , - 1 , Wx::Bitmap - > new ( Slic3r:: var ( "disk.png" ) , wxBITMAP_TYPE_PNG ) ,
2015-02-09 10:04:28 +00:00
wxDefaultPosition , wxDefaultSize , wxBORDER_NONE ) ;
2017-10-25 10:53:31 +00:00
$ self - > { btn_delete_preset } = Wx::BitmapButton - > new ( $ self , - 1 , Wx::Bitmap - > new ( Slic3r:: var ( "delete.png" ) , wxBITMAP_TYPE_PNG ) ,
2015-02-09 10:04:28 +00:00
wxDefaultPosition , wxDefaultSize , wxBORDER_NONE ) ;
2013-03-09 15:27:18 +00:00
$ self - > { btn_save_preset } - > SetToolTipString ( "Save current " . lc ( $ self - > title ) ) ;
$ self - > { btn_delete_preset } - > SetToolTipString ( "Delete this preset" ) ;
$ self - > { btn_delete_preset } - > Disable ;
2012-10-22 14:03:08 +00:00
2017-07-11 10:02:44 +00:00
my $ hsizer = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
$ self - > { sizer } - > Add ( $ hsizer , 0 , wxBOTTOM , 3 ) ;
$ hsizer - > Add ( $ self - > { presets_choice } , 1 , wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL , 3 ) ;
2013-03-09 15:27:18 +00:00
$ hsizer - > Add ( $ self - > { btn_save_preset } , 0 , wxALIGN_CENTER_VERTICAL ) ;
$ hsizer - > Add ( $ self - > { btn_delete_preset } , 0 , wxALIGN_CENTER_VERTICAL ) ;
2013-01-03 14:49:20 +00:00
}
2017-07-11 10:02:44 +00:00
# Horizontal sizer to hold the tree and the selected page.
$ self - > { hsizer } = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
$ self - > { sizer } - > Add ( $ self - > { hsizer } , 1 , wxEXPAND , 0 ) ;
# left vertical sizer
my $ left_sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ self - > { hsizer } - > Add ( $ left_sizer , 0 , wxEXPAND | wxLEFT | wxTOP | wxBOTTOM , 3 ) ;
2012-06-18 20:27:57 +00:00
2013-03-09 15:27:18 +00:00
# tree
2017-07-20 11:09:02 +00:00
$ self - > { treectrl } = Wx::TreeCtrl - > new ( $ self , - 1 , wxDefaultPosition , [ 185 , - 1 ] , wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_SUNKEN | wxWANTS_CHARS ) ;
2013-03-09 15:27:18 +00:00
$ left_sizer - > Add ( $ self - > { treectrl } , 1 , wxEXPAND ) ;
$ self - > { icons } = Wx::ImageList - > new ( 16 , 16 , 1 ) ;
2017-10-26 15:17:39 +00:00
# Map from an icon file name to its index in $self->{icons}.
$ self - > { icon_index } = { } ;
# Index of the last icon inserted into $self->{icons}.
$ self - > { icon_count } = - 1 ;
2013-03-09 15:27:18 +00:00
$ self - > { treectrl } - > AssignImageList ( $ self - > { icons } ) ;
$ self - > { treectrl } - > AddRoot ( "root" ) ;
$ self - > { pages } = [] ;
$ self - > { treectrl } - > SetIndent ( 0 ) ;
2015-06-01 21:11:27 +00:00
$ self - > { disable_tree_sel_changed_event } = 0 ;
2013-03-09 15:27:18 +00:00
EVT_TREE_SEL_CHANGED ( $ parent , $ self - > { treectrl } , sub {
2015-06-01 21:11:27 +00:00
return if $ self - > { disable_tree_sel_changed_event } ;
2013-03-09 15:27:18 +00:00
my $ page = first { $ _ - > { title } eq $ self - > { treectrl } - > GetItemText ( $ self - > { treectrl } - > GetSelection ) } @ { $ self - > { pages } }
or return ;
$ _ - > Hide for @ { $ self - > { pages } } ;
$ page - > Show ;
2017-07-11 10:02:44 +00:00
$ self - > { hsizer } - > Layout ;
2013-03-09 15:27:18 +00:00
$ self - > Refresh ;
} ) ;
EVT_KEY_DOWN ( $ self - > { treectrl } , sub {
my ( $ treectrl , $ event ) = @ _ ;
if ( $ event - > GetKeyCode == WXK_TAB ) {
$ treectrl - > Navigate ( $ event - > ShiftDown ? & Wx:: wxNavigateBackward : & Wx:: wxNavigateForward ) ;
} else {
$ event - > Skip ;
2012-06-19 15:47:48 +00:00
}
2013-03-09 15:27:18 +00:00
} ) ;
EVT_CHOICE ( $ parent , $ self - > { presets_choice } , sub {
2017-10-25 10:53:31 +00:00
$ self - > select_preset ( $ self - > { presets_choice } - > GetStringSelection ) ;
2013-03-09 15:27:18 +00:00
} ) ;
2013-11-11 20:45:58 +00:00
EVT_BUTTON ( $ self , $ self - > { btn_save_preset } , sub { $ self - > save_preset } ) ;
2017-10-25 10:53:31 +00:00
EVT_BUTTON ( $ self , $ self - > { btn_delete_preset } , sub { $ self - > delete_preset } ) ;
2013-03-09 15:27:18 +00:00
2016-11-01 12:41:24 +00:00
# Initialize the DynamicPrintConfig by default keys/values.
# Possible %params keys: no_controller
2016-05-16 21:40:24 +00:00
$ self - > build ( % params ) ;
2017-10-26 15:17:39 +00:00
$ self - > rebuild_page_tree ;
2014-07-01 16:18:23 +00:00
$ self - > _update ;
2012-07-18 18:36:34 +00:00
2012-06-17 20:27:05 +00:00
return $ self ;
}
2017-10-26 15:17:39 +00: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.
2013-11-11 20:45:58 +00:00
sub save_preset {
my ( $ self , $ 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?
$ self - > { treectrl } - > SetFocus ;
if ( ! defined $ name ) {
2017-11-02 15:21:34 +00:00
my $ preset = $ self - > { presets } - > get_selected_preset ;
2014-12-25 16:35:31 +00:00
my $ default_name = $ preset - > default ? 'Untitled' : $ preset - > name ;
2017-07-11 15:15:34 +00:00
$ default_name =~ s/\.[iI][nN][iI]$// ;
2013-11-11 20:45:58 +00:00
my $ dlg = Slic3r::GUI::SavePresetWindow - > new ( $ self ,
title = > lc ( $ self - > title ) ,
default = > $ default_name ,
2014-12-25 16:35:31 +00:00
values = > [ map $ _ - > name , grep ! $ _ - > default && ! $ _ - > external , @ { $ self - > { presets } } ] ,
2013-11-11 20:45:58 +00:00
) ;
return unless $ dlg - > ShowModal == wxID_OK ;
2017-10-26 15:17:39 +00:00
$ name = $ dlg - > get_name ;
2013-11-11 20:45:58 +00:00
}
2017-10-26 15:17:39 +00:00
# Save the preset into Slic3r::data_dir/section_name/preset_name.ini
eval { $ self - > { presets } - > save_current_preset ( $ name ) ; } ;
Slic3r::GUI:: catch_error ( $ self ) and return ;
# Add the new item into the UI component, remove dirty flags and activate the saved item.
$ self - > { presets } - > update_tab_ui ( $ self - > { presets_choice } ) ;
# Update the selection boxes at the platter.
2017-10-25 10:53:31 +00:00
$ self - > _on_presets_changed ;
}
# Called for a currently selected preset.
sub delete_preset {
my ( $ self ) = @ _ ;
my $ current_preset = $ self - > { presets } - > get_selected_preset ;
# Don't let the user delete the '- default -' configuration.
2017-11-02 15:21:34 +00:00
my $ msg = 'Are you sure you want to ' . ( $ current_preset - > external ? 'remove' : 'delete' ) . ' the selected preset?' ;
my $ title = ( $ current_preset - > external ? 'Remove' : 'Delete' ) . ' Preset' ;
2017-10-26 15:17:39 +00:00
return if $ current_preset - > default ||
2017-11-02 15:21:34 +00:00
wxID_YES != Wx::MessageDialog - > new ( $ self , $ msg , $ title , wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ) - > ShowModal ;
2017-10-25 10:53:31 +00:00
# Delete the file and select some other reasonable preset.
2017-10-26 15:17:39 +00:00
# The 'external' presets will only be removed from the preset list, their files will not be deleted.
eval { $ self - > { presets } - > delete_current_preset ; } ;
2017-10-25 10:53:31 +00:00
Slic3r::GUI:: catch_error ( $ self ) and return ;
2017-11-02 15:21:34 +00:00
# Load the newly selected preset into the UI, update selection combo boxes with their dirty flags.
$ self - > load_current_preset ;
2013-11-11 20:45:58 +00:00
}
2017-10-26 15:17:39 +00:00
# Register the on_value_change callback.
2012-07-27 19:13:03 +00:00
sub on_value_change {
2014-07-01 14:40:56 +00:00
my ( $ self , $ cb ) = @ _ ;
$ self - > { on_value_change } = $ cb ;
}
2017-10-26 15:17:39 +00:00
# Register the on_presets_changed callback.
2014-07-01 14:40:56 +00:00
sub on_presets_changed {
my ( $ self , $ cb ) = @ _ ;
$ self - > { on_presets_changed } = $ cb ;
}
2017-02-07 17:41:09 +00:00
# This method is called whenever an option field is changed by the user.
2017-10-26 15:17:39 +00:00
# Propagate event to the parent through the 'on_value_change' callback
2017-02-07 17:41:09 +00:00
# and call _update.
2017-10-26 15:17:39 +00:00
# The on_value_change callback triggers Platter::on_config_change() to configure the 3D preview
# (colors, wipe tower positon etc) and to restart the background slicing process.
2014-07-01 14:40:56 +00:00
sub _on_value_change {
2017-02-07 17:41:09 +00:00
my ( $ self , $ key , $ value ) = @ _ ;
$ self - > { on_value_change } - > ( $ key , $ value ) if $ self - > { on_value_change } ;
2017-10-25 10:53:31 +00:00
$ self - > _update ;
2012-07-27 19:13:03 +00:00
}
2017-02-07 17:41:09 +00:00
# Override this to capture changes of configuration caused either by loading or switching a preset,
# or by a user changing an option field.
2017-10-26 15:17:39 +00:00
# This callback is useful for cross-validating configuration values of a single preset.
2014-07-01 16:18:23 +00:00
sub _update { }
2017-10-26 15:17:39 +00: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.
2014-07-01 14:40:56 +00:00
sub _on_presets_changed {
2017-10-25 10:53:31 +00:00
my ( $ self ) = @ _ ;
2017-10-26 15:17:39 +00:00
$ self - > { on_presets_changed } - > ( $ self - > { presets } ) if $ self - > { on_presets_changed } ;
2013-03-09 15:43:09 +00:00
}
2017-10-26 15:17:39 +00:00
# For the printer profile, generate the extruder pages after a preset is loaded.
2012-07-18 18:36:34 +00:00
sub on_preset_loaded { }
2012-07-28 09:34:12 +00:00
2017-10-26 15:17:39 +00: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.
sub may_discard_current_preset_if_dirty
{
my ( $ self ) = @ _ ;
2017-10-25 10:53:31 +00:00
if ( $ self - > { presets } - > current_is_dirty ) {
2016-10-24 14:07:36 +00:00
# Display a dialog showing the dirty options in a human readable form.
2017-10-25 10:53:31 +00:00
my $ old_preset = $ self - > { presets } - > get_current_preset ;
2014-12-25 16:35:31 +00:00
my $ name = $ old_preset - > default ? 'Default preset' : "Preset \"" . $ old_preset - > name . "\"" ;
2017-10-25 10:53:31 +00:00
# Collect descriptions of the dirty options.
2014-12-27 13:38:06 +00:00
my @ option_names = ( ) ;
2017-10-25 10:53:31 +00:00
foreach my $ opt_key ( @ { $ self - > { presets } - > current_dirty_options } ) {
2014-12-27 13:38:06 +00:00
my $ opt = $ Slic3r:: Config:: Options - > { $ opt_key } ;
my $ name = $ opt - > { full_label } // $ opt - > { label } ;
2017-10-25 10:53:31 +00:00
$ name = $ opt - > { category } . " > $name" if $ opt - > { category } ;
2014-12-27 13:38:06 +00:00
push @ option_names , $ name ;
}
2017-10-25 10:53:31 +00:00
# Show a confirmation dialog with the list of dirty options.
2014-12-27 13:38:06 +00:00
my $ changes = join "\n" , map "- $_" , @ option_names ;
2014-12-25 16:35:31 +00:00
my $ confirm = Wx::MessageDialog - > new ( $ self , "$name has unsaved changes:\n$changes\n\nDiscard changes and continue anyway?" ,
2012-07-27 11:57:58 +00:00
'Unsaved Changes' , wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ) ;
2017-10-26 15:17:39 +00:00
return 0 if $ confirm - > ShowModal == wxID_NO ;
2012-06-19 15:23:10 +00:00
}
2017-10-26 15:17:39 +00:00
return 1 ;
}
2017-10-25 10:53:31 +00:00
2017-10-26 15:17:39 +00:00
# Called by the UI combo box when the user switches profiles.
2017-11-02 15:21:34 +00:00
# Select a preset by a name. If ! defined(name), then the default preset is selected.
2017-10-26 15:17:39 +00:00
# If the current profile is modified, user is asked to save the changes.
sub select_preset {
my ( $ self , $ name , $ force ) = @ _ ;
2017-11-02 15:21:34 +00:00
$ force // = 0 ;
if ( ! $ force && ! $ self - > may_discard_current_preset_if_dirty ) {
2017-10-26 15:17:39 +00:00
$ self - > { presets } - > update_tab_ui ( $ self - > { presets_choice } ) ;
# Trigger the on_presets_changed event so that we also restore the previous value in the plater selector.
$ self - > _on_presets_changed ;
return ;
}
2017-11-02 15:21:34 +00:00
if ( defined $ name ) {
$ self - > { presets } - > select_preset_by_name ( $ name ) ;
} else {
$ self - > { presets } - > select_preset ( 0 ) ;
}
2017-10-26 15:17:39 +00:00
# Initialize the UI from the current preset.
$ self - > load_current_preset ;
}
# Initialize the UI from the current preset.
sub load_current_preset {
my ( $ self ) = @ _ ;
$ self - > { presets } - > update_tab_ui ( $ self - > { presets_choice } ) ;
2017-10-25 10:53:31 +00:00
my $ preset = $ self - > { presets } - > get_current_preset ;
2012-08-07 16:44:47 +00:00
eval {
local $ SIG { __WARN__ } = Slic3r::GUI:: warning_catcher ( $ self ) ;
2017-11-02 15:21:34 +00:00
my $ method = $ preset - > default ? 'Disable' : 'Enable' ;
2017-10-26 15:17:39 +00:00
$ self - > { btn_delete_preset } - > $ method ;
2017-10-25 10:53:31 +00:00
$ self - > _update ;
# For the printer profile, generate the extruder pages.
2013-03-29 23:30:21 +00:00
$ self - > on_preset_loaded ;
2017-10-25 10:53:31 +00:00
# Reload preset pages with the new configuration values.
2017-10-26 15:17:39 +00:00
$ self - > _reload_config ;
2012-08-07 16:44:47 +00:00
} ;
2014-12-25 16:35:31 +00:00
# use CallAfter because some field triggers schedule on_change calls using CallAfter,
# and we don't want them to be called after this update_dirty() as they would mark the
# preset dirty again
# (not sure this is true anymore now that update_dirty is idempotent)
wxTheApp - > CallAfter ( sub {
$ self - > update_dirty ;
2017-11-02 15:21:34 +00:00
#the following is called by update_dirty
#$self->_on_presets_changed;
2014-12-25 16:35:31 +00:00
} ) ;
2012-06-19 15:23:10 +00:00
}
2012-06-18 20:27:57 +00:00
sub add_options_page {
2017-10-26 15:17:39 +00:00
my ( $ self , $ title , $ icon , % params ) = @ _ ;
# Index of $icon in an icon list $self->{icons}.
my $ icon_idx = 0 ;
2013-03-09 15:27:18 +00:00
if ( $ icon ) {
2017-10-26 15:17:39 +00:00
$ icon_idx = $ self - > { icon_index } - > { $ icon } ;
if ( ! defined $ icon_idx ) {
# Add a new icon to the icon list.
my $ bitmap = Wx::Bitmap - > new ( Slic3r:: var ( $ icon ) , wxBITMAP_TYPE_PNG ) ;
$ self - > { icons } - > Add ( $ bitmap ) ;
$ icon_idx = $ self - > { icon_count } + 1 ;
$ self - > { icon_count } = $ icon_idx ;
$ self - > { icon_index } - > { $ icon } = $ icon_idx ;
}
2012-06-17 20:54:08 +00:00
}
2017-10-26 15:17:39 +00:00
# Initialize the page.
my $ page = Slic3r::GUI::Tab::Page - > new ( $ self , $ title , $ icon_idx ) ;
2013-03-09 15:27:18 +00:00
$ page - > Hide ;
2017-07-11 10:02:44 +00:00
$ self - > { hsizer } - > Add ( $ page , 1 , wxEXPAND | wxLEFT , 5 ) ;
2012-07-18 18:36:34 +00:00
push @ { $ self - > { pages } } , $ page ;
return $ page ;
}
2017-10-25 10:53:31 +00:00
# Reload current $self->{config} (aka $self->{presets}->edited_preset->config) into the UI fields.
2017-10-26 15:17:39 +00:00
sub _reload_config {
2017-10-25 10:53:31 +00:00
my ( $ self ) = @ _ ;
2017-10-27 22:18:02 +00:00
$ self - > Freeze ;
2014-07-01 14:40:56 +00:00
$ _ - > reload_config for @ { $ self - > { pages } } ;
2017-10-27 22:18:02 +00:00
$ self - > Thaw ;
2012-07-24 13:30:50 +00:00
}
2017-10-26 15:17:39 +00:00
# Regerenerate content of the page tree.
sub rebuild_page_tree {
2015-01-25 10:43:34 +00:00
my ( $ self ) = @ _ ;
2017-10-27 22:18:02 +00:00
$ self - > Freeze ;
2015-01-25 10:43:34 +00:00
# get label of the currently selected item
2017-10-27 22:18:02 +00:00
my $ selected = $ self - > { treectrl } - > GetItemText ( $ self - > { treectrl } - > GetSelection ) ;
2012-07-18 18:36:34 +00:00
my $ rootItem = $ self - > { treectrl } - > GetRootItem ;
$ self - > { treectrl } - > DeleteChildren ( $ rootItem ) ;
2015-01-25 10:43:34 +00:00
my $ have_selection = 0 ;
2012-07-18 18:36:34 +00:00
foreach my $ page ( @ { $ self - > { pages } } ) {
my $ itemId = $ self - > { treectrl } - > AppendItem ( $ rootItem , $ page - > { title } , $ page - > { iconID } ) ;
2015-01-25 10:43:34 +00:00
if ( $ page - > { title } eq $ selected ) {
2015-06-01 21:11:27 +00:00
$ self - > { disable_tree_sel_changed_event } = 1 ;
2015-01-25 10:43:34 +00:00
$ self - > { treectrl } - > SelectItem ( $ itemId ) ;
2015-06-01 21:11:27 +00:00
$ self - > { disable_tree_sel_changed_event } = 0 ;
2015-01-25 10:43:34 +00:00
$ have_selection = 1 ;
}
}
if ( ! $ have_selection ) {
2015-06-01 21:11:27 +00:00
# this is triggered on first load, so we don't disable the sel change event
2015-01-25 10:43:34 +00:00
$ self - > { treectrl } - > SelectItem ( $ self - > { treectrl } - > GetFirstChild ( $ rootItem ) ) ;
2012-06-18 20:27:57 +00:00
}
2017-10-27 22:18:02 +00:00
$ self - > Thaw ;
2012-06-17 20:27:05 +00:00
}
2017-09-18 08:01:37 +00:00
# Update the combo box label of the selected preset based on its "dirty" state,
# comparing the selected preset config with $self->{config}.
2014-12-25 16:35:31 +00:00
sub update_dirty {
2017-09-18 08:01:37 +00:00
my ( $ self ) = @ _ ;
2017-10-25 10:53:31 +00:00
$ self - > { presets } - > update_dirty_ui ( $ self - > { presets_choice } ) ;
2014-07-01 14:40:56 +00:00
$ self - > _on_presets_changed ;
2012-06-18 20:27:57 +00:00
}
2017-09-18 08:01:37 +00: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.
2014-07-01 14:40:56 +00:00
sub load_config {
2017-09-18 08:01:37 +00:00
my ( $ self , $ config ) = @ _ ;
2014-07-01 14:40:56 +00:00
2017-10-25 10:53:31 +00:00
my $ modified = 0 ;
2014-07-01 14:40:56 +00:00
foreach my $ opt_key ( @ { $ self - > { config } - > diff ( $ config ) } ) {
$ self - > { config } - > set ( $ opt_key , $ config - > get ( $ opt_key ) ) ;
2017-10-25 10:53:31 +00:00
$ modified = 1 ;
2017-05-19 19:48:32 +00:00
}
2017-10-25 10:53:31 +00:00
if ( $ modified ) {
2014-12-25 16:35:31 +00:00
$ self - > update_dirty ;
2017-05-19 19:48:32 +00:00
# Initialize UI components with the config values.
2017-10-26 15:17:39 +00:00
$ self - > _reload_config ;
2017-10-25 10:53:31 +00:00
$ self - > _update ;
2014-07-01 14:40:56 +00:00
}
2012-06-19 12:47:02 +00:00
}
2017-10-25 10:53:31 +00:00
# Find a field with an index over all pages of this tab.
2017-10-26 15:17:39 +00:00
# This method is used often and everywhere, therefore it shall be quick.
2014-07-01 16:18:23 +00:00
sub get_field {
my ( $ self , $ opt_key , $ opt_index ) = @ _ ;
2017-10-26 15:17:39 +00:00
foreach my $ page ( @ { $ self - > { pages } } ) {
2014-07-01 16:18:23 +00:00
my $ field = $ page - > get_field ( $ opt_key , $ opt_index ) ;
return $ field if defined $ field ;
}
return undef ;
}
2017-10-25 10:53:31 +00:00
# Set a key/value pair on this page. Return true if the value has been modified.
2017-10-26 15:17:39 +00:00
# Currently used for distributing extruders_count over preset pages of Slic3r::GUI::Tab::Printer
# after a preset is loaded.
2014-09-21 13:29:52 +00:00
sub set_value {
2017-10-25 10:53:31 +00:00
my ( $ self , $ opt_key , $ value ) = @ _ ;
2014-09-21 13:29:52 +00:00
my $ changed = 0 ;
2017-10-26 15:17:39 +00:00
foreach my $ page ( @ { $ self - > { pages } } ) {
2014-09-21 13:29:52 +00:00
$ changed = 1 if $ page - > set_value ( $ opt_key , $ value ) ;
}
return $ changed ;
}
2012-06-18 20:27:57 +00:00
package Slic3r::GUI::Tab::Print ;
2012-06-17 20:27:05 +00:00
use base 'Slic3r::GUI::Tab' ;
2015-05-28 16:56:35 +00:00
use List::Util qw( first ) ;
2017-09-19 11:55:48 +00:00
use Wx qw( :icon :dialog :id wxTheApp ) ;
2014-11-22 21:52:12 +00:00
2012-07-27 19:13:03 +00:00
sub name { 'print' }
2012-07-18 18:36:34 +00:00
sub title { 'Print Settings' }
sub build {
my $ self = shift ;
2012-06-17 20:27:05 +00:00
2017-10-25 10:53:31 +00:00
$ self - > { presets } = wxTheApp - > { preset_bundle } - > print ;
2017-11-02 15:21:34 +00:00
$ self - > { config } = $ self - > { presets } - > get_edited_preset - > config ;
2014-07-01 14:40:56 +00:00
{
my $ page = $ self - > add_options_page ( 'Layers and perimeters' , 'layers.png' ) ;
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Layer height' ) ;
$ optgroup - > append_single_option_line ( 'layer_height' ) ;
$ optgroup - > append_single_option_line ( 'first_layer_height' ) ;
}
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Vertical shells' ) ;
$ optgroup - > append_single_option_line ( 'perimeters' ) ;
$ optgroup - > append_single_option_line ( 'spiral_vase' ) ;
}
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Horizontal shells' ) ;
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > 'Solid layers' ,
) ;
$ line - > append_option ( $ optgroup - > get_option ( 'top_solid_layers' ) ) ;
$ line - > append_option ( $ optgroup - > get_option ( 'bottom_solid_layers' ) ) ;
$ optgroup - > append_line ( $ line ) ;
}
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Quality (slower slicing)' ) ;
$ optgroup - > append_single_option_line ( 'extra_perimeters' ) ;
2016-10-16 20:11:19 +00:00
$ optgroup - > append_single_option_line ( 'ensure_vertical_shell_thickness' ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'avoid_crossing_perimeters' ) ;
$ optgroup - > append_single_option_line ( 'thin_walls' ) ;
$ optgroup - > append_single_option_line ( 'overhangs' ) ;
}
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Advanced' ) ;
$ optgroup - > append_single_option_line ( 'seam_position' ) ;
$ optgroup - > append_single_option_line ( 'external_perimeters_first' ) ;
}
}
2012-06-17 20:27:05 +00:00
2014-07-01 14:40:56 +00:00
{
2016-02-20 15:18:48 +00:00
my $ page = $ self - > add_options_page ( 'Infill' , 'infill.png' ) ;
2012-08-07 18:14:28 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Infill' ) ;
$ optgroup - > append_single_option_line ( 'fill_density' ) ;
$ optgroup - > append_single_option_line ( 'fill_pattern' ) ;
2014-11-26 23:38:05 +00:00
$ optgroup - > append_single_option_line ( 'external_fill_pattern' ) ;
2014-07-01 14:40:56 +00:00
}
{
my $ optgroup = $ page - > new_optgroup ( 'Reducing printing time' ) ;
$ optgroup - > append_single_option_line ( 'infill_every_layers' ) ;
$ optgroup - > append_single_option_line ( 'infill_only_where_needed' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Advanced' ) ;
$ 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' ) ;
2017-07-31 14:23:52 +00:00
$ optgroup - > append_single_option_line ( 'bridge_angle' ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'only_retract_when_crossing_perimeters' ) ;
$ optgroup - > append_single_option_line ( 'infill_first' ) ;
}
}
{
my $ page = $ self - > add_options_page ( 'Skirt and brim' , 'box.png' ) ;
2014-03-25 00:11:28 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Skirt' ) ;
$ 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' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Brim' ) ;
$ optgroup - > append_single_option_line ( 'brim_width' ) ;
}
}
2012-08-07 18:14:28 +00:00
2014-07-01 14:40:56 +00:00
{
my $ page = $ self - > add_options_page ( 'Support material' , 'building.png' ) ;
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Support material' ) ;
$ optgroup - > append_single_option_line ( 'support_material' ) ;
$ optgroup - > append_single_option_line ( 'support_material_threshold' ) ;
$ optgroup - > append_single_option_line ( 'support_material_enforce_layers' ) ;
}
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Raft' ) ;
$ optgroup - > append_single_option_line ( 'raft_layers' ) ;
2017-04-10 10:00:07 +00:00
# $optgroup->append_single_option_line('raft_contact_distance');
2014-07-01 14:40:56 +00:00
}
{
my $ optgroup = $ page - > new_optgroup ( 'Options for support material and raft' ) ;
2015-01-19 08:52:24 +00:00
$ optgroup - > append_single_option_line ( 'support_material_contact_distance' ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'support_material_pattern' ) ;
2016-10-04 12:38:13 +00:00
$ optgroup - > append_single_option_line ( 'support_material_with_sheath' ) ;
2014-07-01 14:40:56 +00:00
$ 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' ) ;
2016-11-30 16:33:55 +00:00
$ optgroup - > append_single_option_line ( 'support_material_interface_contact_loops' ) ;
2016-10-04 11:54:10 +00:00
$ optgroup - > append_single_option_line ( 'support_material_buildplate_only' ) ;
2016-03-20 03:30:02 +00:00
$ optgroup - > append_single_option_line ( 'support_material_xy_spacing' ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'dont_support_bridges' ) ;
2016-11-30 15:04:15 +00:00
$ optgroup - > append_single_option_line ( 'support_material_synchronize_layers' ) ;
2014-07-01 14:40:56 +00:00
}
}
{
2014-12-23 19:47:11 +00:00
my $ page = $ self - > add_options_page ( 'Speed' , 'time.png' ) ;
2014-07-01 14:40:56 +00:00
{
2014-12-23 19:47:11 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Speed for print moves' ) ;
$ 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' ) ;
2014-07-01 14:40:56 +00:00
}
{
2014-12-23 19:47:11 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Speed for non-print moves' ) ;
$ optgroup - > append_single_option_line ( 'travel_speed' ) ;
2014-07-01 14:40:56 +00:00
}
{
2014-12-23 19:47:11 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Modifiers' ) ;
$ optgroup - > append_single_option_line ( 'first_layer_speed' ) ;
2014-07-01 14:40:56 +00:00
}
{
2014-12-23 19:47:11 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Acceleration control (advanced)' ) ;
$ 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' ) ;
2014-07-01 14:40:56 +00:00
}
2015-05-31 20:04:32 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Autospeed (advanced)' ) ;
$ optgroup - > append_single_option_line ( 'max_print_speed' ) ;
$ optgroup - > append_single_option_line ( 'max_volumetric_speed' ) ;
2016-09-13 13:02:28 +00:00
$ optgroup - > append_single_option_line ( 'max_volumetric_extrusion_rate_slope_positive' ) ;
$ optgroup - > append_single_option_line ( 'max_volumetric_extrusion_rate_slope_negative' ) ;
2015-05-31 20:04:32 +00:00
}
2014-07-01 14:40:56 +00:00
}
{
my $ page = $ self - > add_options_page ( 'Multiple Extruders' , 'funnel.png' ) ;
2013-03-16 18:58:34 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Extruders' ) ;
$ optgroup - > append_single_option_line ( 'perimeter_extruder' ) ;
$ optgroup - > append_single_option_line ( 'infill_extruder' ) ;
2014-12-16 23:34:00 +00:00
$ optgroup - > append_single_option_line ( 'solid_infill_extruder' ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'support_material_extruder' ) ;
$ optgroup - > append_single_option_line ( 'support_material_interface_extruder' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Ooze prevention' ) ;
$ optgroup - > append_single_option_line ( 'ooze_prevention' ) ;
$ optgroup - > append_single_option_line ( 'standby_temperature_delta' ) ;
}
2017-05-16 11:45:28 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Wipe tower' ) ;
$ optgroup - > append_single_option_line ( 'wipe_tower' ) ;
$ optgroup - > append_single_option_line ( 'wipe_tower_x' ) ;
$ optgroup - > append_single_option_line ( 'wipe_tower_y' ) ;
$ optgroup - > append_single_option_line ( 'wipe_tower_width' ) ;
$ optgroup - > append_single_option_line ( 'wipe_tower_per_color_wipe' ) ;
}
2014-07-01 14:40:56 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Advanced' ) ;
$ optgroup - > append_single_option_line ( 'interface_shells' ) ;
}
}
{
my $ page = $ self - > add_options_page ( 'Advanced' , 'wrench.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Extrusion width' ,
label_width = > 180 ,
) ;
$ 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' ) ;
}
2015-02-01 11:08:25 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Overlap' ) ;
$ optgroup - > append_single_option_line ( 'infill_overlap' ) ;
}
2014-07-01 14:40:56 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Flow' ) ;
$ optgroup - > append_single_option_line ( 'bridge_flow_ratio' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Other' ) ;
2017-02-14 11:36:04 +00:00
$ optgroup - > append_single_option_line ( 'clip_multipart_objects' ) ;
2017-06-26 14:28:10 +00:00
$ optgroup - > append_single_option_line ( 'elefant_foot_compensation' ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'xy_size_compensation' ) ;
2017-11-02 15:21:34 +00:00
# $optgroup->append_single_option_line('threads');
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'resolution' ) ;
}
}
2014-12-23 19:47:11 +00:00
{
my $ page = $ self - > add_options_page ( 'Output options' , 'page_white_go.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Sequential printing' ) ;
$ optgroup - > append_single_option_line ( 'complete_objects' ) ;
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > 'Extruder clearance (mm)' ,
) ;
foreach my $ opt_key ( qw( extruder_clearance_radius extruder_clearance_height ) ) {
my $ option = $ optgroup - > get_option ( $ opt_key ) ;
$ option - > width ( 60 ) ;
$ line - > append_option ( $ option ) ;
}
$ optgroup - > append_line ( $ line ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Output file' ) ;
$ optgroup - > append_single_option_line ( 'gcode_comments' ) ;
{
my $ option = $ optgroup - > get_option ( 'output_filename_format' ) ;
$ option - > full_width ( 1 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
}
{
my $ optgroup = $ page - > new_optgroup ( 'Post-processing scripts' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'post_process' ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 50 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
}
{
my $ page = $ self - > add_options_page ( 'Notes' , 'note.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Notes' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'notes' ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 250 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
}
2012-06-17 20:27:05 +00:00
}
2017-10-25 10:53:31 +00:00
# Reload current $self->{config} (aka $self->{presets}->edited_preset->config) into the UI fields.
2017-10-26 15:17:39 +00:00
sub _reload_config {
2017-09-19 11:55:48 +00:00
my ( $ self ) = @ _ ;
# $self->_reload_compatible_printers_widget;
2017-10-26 15:17:39 +00:00
$ self - > SUPER:: _reload_config ;
2017-09-19 11:55:48 +00:00
}
2017-02-07 17:41:09 +00:00
# Slic3r::GUI::Tab::Print::_update is called after a configuration preset is loaded or switched, or when a single option is modifed by the user.
2014-07-01 16:18:23 +00:00
sub _update {
2017-10-25 10:53:31 +00:00
my ( $ self ) = @ _ ;
2017-10-27 22:18:02 +00:00
$ self - > Freeze ;
2017-02-07 17:41:09 +00:00
2017-11-02 15:21:34 +00:00
my $ config = $ self - > { config } ;
2014-07-01 16:18:23 +00:00
2014-11-22 21:52:12 +00:00
if ( $ config - > spiral_vase && ! ( $ config - > perimeters == 1 && $ config - > top_solid_layers == 0 && $ config - > fill_density == 0 ) ) {
2015-01-18 21:21:50 +00:00
my $ dialog = Wx::MessageDialog - > new ( $ self ,
"The Spiral Vase mode requires:\n"
. "- one perimeter\n"
. "- no top solid layers\n"
. "- 0% fill density\n"
. "- no support material\n"
2017-04-03 09:19:32 +00:00
. "- no ensure_vertical_shell_thickness\n"
2015-01-18 21:21:50 +00:00
. "\nShall I adjust those settings in order to enable Spiral Vase?" ,
2014-11-22 21:52:12 +00:00
'Spiral Vase' , wxICON_WARNING | wxYES | wxNO ) ;
2017-06-06 08:36:14 +00:00
my $ new_conf = Slic3r::Config - > new ;
2014-11-22 21:52:12 +00:00
if ( $ dialog - > ShowModal ( ) == wxID_YES ) {
$ new_conf - > set ( "perimeters" , 1 ) ;
$ new_conf - > set ( "top_solid_layers" , 0 ) ;
$ new_conf - > set ( "fill_density" , 0 ) ;
2015-01-18 21:21:50 +00:00
$ new_conf - > set ( "support_material" , 0 ) ;
2017-04-03 09:19:32 +00:00
$ new_conf - > set ( "ensure_vertical_shell_thickness" , 0 ) ;
2014-11-22 21:52:12 +00:00
} else {
$ new_conf - > set ( "spiral_vase" , 0 ) ;
}
2017-06-06 08:36:14 +00:00
$ self - > load_config ( $ new_conf ) ;
}
if ( $ config - > wipe_tower &&
2017-06-08 10:10:34 +00:00
( $ config - > first_layer_height != 0.2 || $ config - > layer_height < 0.15 || $ config - > layer_height > 0.35 ) ) {
2017-06-06 08:36:14 +00:00
my $ dialog = Wx::MessageDialog - > new ( $ self ,
"The Wipe Tower currently supports only:\n"
. "- first layer height 0.2mm\n"
2017-06-08 10:10:34 +00:00
. "- layer height from 0.15mm to 0.35mm\n"
2017-06-06 08:36:14 +00:00
. "\nShall I adjust those settings in order to enable the Wipe Tower?" ,
'Wipe Tower' , wxICON_WARNING | wxYES | wxNO ) ;
my $ new_conf = Slic3r::Config - > new ;
if ( $ dialog - > ShowModal ( ) == wxID_YES ) {
$ new_conf - > set ( "first_layer_height" , 0.2 ) ;
2017-06-08 10:10:34 +00:00
$ new_conf - > set ( "layer_height" , 0.15 ) if $ config - > layer_height < 0.15 ;
$ new_conf - > set ( "layer_height" , 0.35 ) if $ config - > layer_height > 0.35 ;
2017-06-06 08:36:14 +00:00
} else {
$ new_conf - > set ( "wipe_tower" , 0 ) ;
}
$ self - > load_config ( $ new_conf ) ;
}
if ( $ config - > wipe_tower && $ config - > support_material && $ config - > support_material_contact_distance > 0 . &&
( $ config - > support_material_extruder != 0 || $ config - > support_material_interface_extruder != 0 ) ) {
my $ dialog = Wx::MessageDialog - > new ( $ self ,
"The Wipe Tower currently supports the non-soluble supports only\n"
. "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"
. "\nShall I adjust those settings in order to enable the Wipe Tower?" ,
'Wipe Tower' , wxICON_WARNING | wxYES | wxNO ) ;
my $ new_conf = Slic3r::Config - > new ;
if ( $ dialog - > ShowModal ( ) == wxID_YES ) {
$ new_conf - > set ( "support_material_extruder" , 0 ) ;
$ new_conf - > set ( "support_material_interface_extruder" , 0 ) ;
} else {
$ new_conf - > set ( "wipe_tower" , 0 ) ;
}
$ self - > load_config ( $ new_conf ) ;
2014-11-22 21:52:12 +00:00
}
2016-11-11 14:05:39 +00:00
2017-06-06 09:40:35 +00:00
if ( $ config - > wipe_tower && $ config - > support_material && $ config - > support_material_contact_distance == 0 &&
! $ config - > support_material_synchronize_layers ) {
my $ dialog = Wx::MessageDialog - > new ( $ self ,
"For the Wipe Tower to work with the soluble supports, the support layers\n"
. "need to be synchronized with the object layers.\n"
. "\nShall I synchronize support layers in order to enable the Wipe Tower?" ,
'Wipe Tower' , wxICON_WARNING | wxYES | wxNO ) ;
my $ new_conf = Slic3r::Config - > new ;
if ( $ dialog - > ShowModal ( ) == wxID_YES ) {
$ new_conf - > set ( "support_material_synchronize_layers" , 1 ) ;
} else {
$ new_conf - > set ( "wipe_tower" , 0 ) ;
}
$ self - > load_config ( $ new_conf ) ;
}
2016-11-11 14:05:39 +00:00
if ( $ config - > support_material ) {
# Ask only once.
if ( ! $ self - > { support_material_overhangs_queried } ) {
$ self - > { support_material_overhangs_queried } = 1 ;
if ( $ config - > overhangs != 1 ) {
my $ dialog = Wx::MessageDialog - > new ( $ self ,
"Supports work better, if the following feature is enabled:\n"
. "- Detect bridging perimeters\n"
. "\nShall I adjust those settings for supports?" ,
'Support Generator' , wxICON_WARNING | wxYES | wxNO | wxCANCEL ) ;
my $ answer = $ dialog - > ShowModal ( ) ;
my $ new_conf = Slic3r::Config - > new ;
if ( $ answer == wxID_YES ) {
# Enable "detect bridging perimeters".
$ new_conf - > set ( "overhangs" , 1 ) ;
} elsif ( $ answer == wxID_NO ) {
# Do nothing, leave supports on and "detect bridging perimeters" off.
} elsif ( $ answer == wxID_CANCEL ) {
# Disable supports.
$ new_conf - > set ( "support_material" , 0 ) ;
$ self - > { support_material_overhangs_queried } = 0 ;
}
$ self - > load_config ( $ new_conf ) ;
}
}
} else {
$ self - > { support_material_overhangs_queried } = 0 ;
}
2014-08-08 15:18:41 +00:00
2015-05-28 16:56:35 +00:00
if ( $ config - > fill_density == 100
&& ! first { $ _ eq $ config - > fill_pattern } @ { $ Slic3r:: Config:: Options - > { external_fill_pattern } { values } } ) {
my $ dialog = Wx::MessageDialog - > new ( $ self ,
"The " . $ config - > fill_pattern . " infill pattern is not supposed to work at 100% density.\n"
. "\nShall I switch to rectilinear fill pattern?" ,
'Infill' , wxICON_WARNING | wxYES | wxNO ) ;
my $ new_conf = Slic3r::Config - > new ;
if ( $ dialog - > ShowModal ( ) == wxID_YES ) {
2016-09-26 11:58:47 +00:00
$ new_conf - > set ( "fill_pattern" , 'rectilinear' ) ;
$ new_conf - > set ( "fill_density" , 100 ) ;
2015-05-28 16:56:35 +00:00
} else {
$ new_conf - > set ( "fill_density" , 40 ) ;
}
$ self - > load_config ( $ new_conf ) ;
}
2014-07-01 16:18:23 +00:00
my $ have_perimeters = $ config - > perimeters > 0 ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_perimeters )
2016-10-16 20:11:19 +00:00
for qw( extra_perimeters ensure_vertical_shell_thickness thin_walls overhangs seam_position external_perimeters_first
2014-12-23 19:47:11 +00:00
external_perimeter_extrusion_width
perimeter_speed small_perimeter_speed external_perimeter_speed ) ;
2014-07-01 16:18:23 +00:00
my $ have_infill = $ config - > fill_density > 0 ;
2015-03-06 20:35:00 +00:00
# infill_extruder uses the same logic as in Print::extruders()
2014-07-01 16:18:23 +00:00
$ self - > get_field ( $ _ ) - > toggle ( $ have_infill )
2014-12-23 19:47:11 +00:00
for qw( fill_pattern infill_every_layers infill_only_where_needed solid_infill_every_layers
solid_infill_below_area infill_extruder ) ;
my $ have_solid_infill = ( $ config - > top_solid_layers > 0 ) || ( $ config - > bottom_solid_layers > 0 ) ;
2015-03-06 20:35:00 +00:00
# solid_infill_extruder uses the same logic as in Print::extruders()
2014-12-23 19:47:11 +00:00
$ self - > get_field ( $ _ ) - > toggle ( $ have_solid_infill )
for qw( external_fill_pattern infill_first solid_infill_extruder solid_infill_extrusion_width
solid_infill_speed ) ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_infill || $ have_solid_infill )
2017-07-31 14:23:52 +00:00
for qw( fill_angle bridge_angle infill_extrusion_width infill_speed bridge_speed ) ;
2014-12-23 19:47:11 +00:00
$ self - > get_field ( 'gap_fill_speed' ) - > toggle ( $ have_perimeters && $ have_infill ) ;
my $ have_top_solid_infill = $ config - > top_solid_layers > 0 ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_top_solid_infill )
for qw( top_infill_extrusion_width top_solid_infill_speed ) ;
2014-07-01 16:18:23 +00:00
my $ have_default_acceleration = $ config - > default_acceleration > 0 ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_default_acceleration )
for qw( perimeter_acceleration infill_acceleration bridge_acceleration first_layer_acceleration ) ;
my $ have_skirt = $ config - > skirts > 0 || $ config - > min_skirt_length > 0 ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_skirt )
for qw( skirt_distance skirt_height ) ;
2014-12-23 19:47:11 +00:00
my $ have_brim = $ config - > brim_width > 0 ;
2015-03-06 20:35:00 +00:00
# perimeter_extruder uses the same logic as in Print::extruders()
2014-12-23 19:47:11 +00:00
$ self - > get_field ( 'perimeter_extruder' ) - > toggle ( $ have_perimeters || $ have_brim ) ;
2017-04-10 10:00:07 +00:00
my $ have_raft = $ config - > raft_layers > 0 ;
my $ have_support_material = $ config - > support_material || $ have_raft ;
2014-07-01 16:18:23 +00:00
my $ have_support_interface = $ config - > support_material_interface_layers > 0 ;
2017-04-10 10:00:07 +00:00
my $ have_support_soluble = $ have_support_material && $ config - > support_material_contact_distance == 0 ;
2014-07-01 16:18:23 +00:00
$ self - > get_field ( $ _ ) - > toggle ( $ have_support_material )
2016-10-04 12:38:13 +00:00
for qw( support_material_threshold support_material_pattern support_material_with_sheath
2017-04-10 10:00:07 +00:00
support_material_spacing support_material_angle
2014-07-01 16:18:23 +00:00
support_material_interface_layers dont_support_bridges
2016-04-09 17:54:32 +00:00
support_material_extrusion_width support_material_contact_distance support_material_xy_spacing ) ;
2014-07-01 16:18:23 +00:00
$ self - > get_field ( $ _ ) - > toggle ( $ have_support_material && $ have_support_interface )
2014-12-23 19:47:11 +00:00
for qw( support_material_interface_spacing support_material_interface_extruder
2016-11-30 16:33:55 +00:00
support_material_interface_speed support_material_interface_contact_loops ) ;
2017-04-10 10:00:07 +00:00
$ self - > get_field ( 'support_material_synchronize_layers' ) - > toggle ( $ have_support_soluble ) ;
2014-12-23 19:47:11 +00:00
$ self - > get_field ( 'perimeter_extrusion_width' ) - > toggle ( $ have_perimeters || $ have_skirt || $ have_brim ) ;
$ self - > get_field ( 'support_material_extruder' ) - > toggle ( $ have_support_material || $ have_skirt ) ;
$ self - > get_field ( 'support_material_speed' ) - > toggle ( $ have_support_material || $ have_brim || $ have_skirt ) ;
2014-07-01 16:18:23 +00:00
my $ have_sequential_printing = $ config - > complete_objects ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_sequential_printing )
for qw( extruder_clearance_radius extruder_clearance_height ) ;
my $ have_ooze_prevention = $ config - > ooze_prevention ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_ooze_prevention )
for qw( standby_temperature_delta ) ;
2017-05-16 11:45:28 +00:00
my $ have_wipe_tower = $ config - > wipe_tower ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_wipe_tower )
for qw( wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe ) ;
2017-10-27 22:18:02 +00:00
$ self - > Thaw ;
2014-07-01 16:18:23 +00:00
}
2012-06-18 12:29:47 +00:00
package Slic3r::GUI::Tab::Filament ;
use base 'Slic3r::GUI::Tab' ;
2017-09-19 11:55:48 +00:00
use Wx qw( wxTheApp ) ;
2012-06-18 12:29:47 +00:00
2012-07-27 19:13:03 +00:00
sub name { 'filament' }
2012-07-18 18:36:34 +00:00
sub title { 'Filament Settings' }
sub build {
my $ self = shift ;
2012-06-18 12:29:47 +00:00
2017-10-25 10:53:31 +00:00
$ self - > { presets } = wxTheApp - > { preset_bundle } - > filament ;
2017-11-02 15:21:34 +00:00
$ self - > { config } = $ self - > { presets } - > get_edited_preset - > config ;
2014-07-01 14:40:56 +00:00
{
my $ page = $ self - > add_options_page ( 'Filament' , 'spool.png' ) ;
2012-06-18 12:29:47 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Filament' ) ;
2015-05-26 00:01:43 +00:00
$ optgroup - > append_single_option_line ( 'filament_colour' , 0 ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'filament_diameter' , 0 ) ;
$ optgroup - > append_single_option_line ( 'extrusion_multiplier' , 0 ) ;
2017-01-16 05:56:01 +00:00
$ optgroup - > append_single_option_line ( 'filament_density' , 0 ) ;
$ optgroup - > append_single_option_line ( 'filament_cost' , 0 ) ;
2014-07-01 14:40:56 +00:00
}
2012-06-18 12:29:47 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Temperature (°C)' ) ;
{
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > 'Extruder' ,
) ;
$ line - > append_option ( $ optgroup - > get_option ( 'first_layer_temperature' , 0 ) ) ;
$ line - > append_option ( $ optgroup - > get_option ( 'temperature' , 0 ) ) ;
$ optgroup - > append_line ( $ line ) ;
}
{
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > 'Bed' ,
) ;
2017-06-21 14:15:39 +00:00
$ line - > append_option ( $ optgroup - > get_option ( 'first_layer_bed_temperature' , 0 ) ) ;
$ line - > append_option ( $ optgroup - > get_option ( 'bed_temperature' , 0 ) ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_line ( $ line ) ;
}
}
}
{
my $ page = $ self - > add_options_page ( 'Cooling' , 'hourglass.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Enable' ) ;
2017-06-21 14:15:39 +00:00
$ optgroup - > append_single_option_line ( 'fan_always_on' , 0 ) ;
$ optgroup - > append_single_option_line ( 'cooling' , 0 ) ;
2014-07-01 14:40:56 +00:00
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > '' ,
full_width = > 1 ,
widget = > sub {
my ( $ parent ) = @ _ ;
return $ self - > { description_line } = Slic3r::GUI::OptionsGroup::StaticText - > new ( $ parent ) ;
2012-10-25 10:37:02 +00:00
} ,
2014-07-01 14:40:56 +00:00
) ;
$ optgroup - > append_line ( $ line ) ;
}
2012-06-18 12:29:47 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Fan settings' ) ;
{
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > 'Fan speed' ,
) ;
2017-06-21 14:15:39 +00:00
$ line - > append_option ( $ optgroup - > get_option ( 'min_fan_speed' , 0 ) ) ;
$ line - > append_option ( $ optgroup - > get_option ( 'max_fan_speed' , 0 ) ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_line ( $ line ) ;
}
2017-06-21 14:15:39 +00:00
$ optgroup - > append_single_option_line ( 'bridge_fan_speed' , 0 ) ;
$ optgroup - > append_single_option_line ( 'disable_fan_first_layers' , 0 ) ;
2014-07-01 14:40:56 +00:00
}
{
my $ optgroup = $ page - > new_optgroup ( 'Cooling thresholds' ,
label_width = > 250 ,
) ;
2017-06-21 14:15:39 +00:00
$ optgroup - > append_single_option_line ( 'fan_below_layer_time' , 0 ) ;
$ optgroup - > append_single_option_line ( 'slowdown_below_layer_time' , 0 ) ;
$ optgroup - > append_single_option_line ( 'min_print_speed' , 0 ) ;
2014-07-01 14:40:56 +00:00
}
}
2016-11-01 12:41:24 +00:00
{
my $ page = $ self - > add_options_page ( 'Advanced' , 'wrench.png' ) ;
{
2017-05-17 14:53:40 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Filament properties' ) ;
$ optgroup - > append_single_option_line ( 'filament_type' , 0 ) ;
$ optgroup - > append_single_option_line ( 'filament_soluble' , 0 ) ;
$ optgroup = $ page - > new_optgroup ( 'Print speed override' ) ;
2016-11-01 12:41:24 +00:00
$ optgroup - > append_single_option_line ( 'filament_max_volumetric_speed' , 0 ) ;
}
}
2017-06-05 09:30:57 +00:00
{
my $ page = $ self - > add_options_page ( 'Custom G-code' , 'cog.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Start G-code' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'start_filament_gcode' , 0 ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 150 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'End G-code' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'end_filament_gcode' , 0 ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 150 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
}
2016-11-01 12:41:24 +00:00
{
my $ page = $ self - > add_options_page ( 'Notes' , 'note.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Notes' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'filament_notes' , 0 ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 250 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
}
2014-07-01 16:18:23 +00:00
}
2017-02-07 17:41:09 +00:00
# Slic3r::GUI::Tab::Filament::_update is called after a configuration preset is loaded or switched, or when a single option is modifed by the user.
2014-07-01 16:18:23 +00:00
sub _update {
2017-10-25 10:53:31 +00:00
my ( $ self ) = @ _ ;
2014-07-01 14:40:56 +00:00
$ self - > _update_description ;
2014-07-01 16:18:23 +00:00
2017-06-21 14:15:39 +00:00
my $ cooling = $ self - > { config } - > cooling - > [ 0 ] ;
my $ fan_always_on = $ cooling || $ self - > { config } - > fan_always_on - > [ 0 ] ;
$ self - > get_field ( $ _ , 0 ) - > toggle ( $ cooling )
2014-07-01 19:58:57 +00:00
for qw( max_fan_speed fan_below_layer_time slowdown_below_layer_time min_print_speed ) ;
2017-06-21 14:15:39 +00:00
$ self - > get_field ( $ _ , 0 ) - > toggle ( $ fan_always_on )
2014-07-01 19:58:57 +00:00
for qw( min_fan_speed disable_fan_first_layers ) ;
2012-06-18 12:29:47 +00:00
}
2012-10-28 11:43:41 +00:00
sub _update_description {
2017-10-25 10:53:31 +00:00
my ( $ self ) = @ _ ;
my $ config = $ self - > { config } ;
2012-10-28 11:43:41 +00:00
my $ msg = "" ;
2017-06-21 14:15:39 +00:00
my $ fan_other_layers = $ config - > fan_always_on - > [ 0 ]
? sprintf "will always run at %d%%%s." , $ config - > min_fan_speed - > [ 0 ] ,
( $ config - > disable_fan_first_layers - > [ 0 ] > 1
? " except for the first " . $ config - > disable_fan_first_layers - > [ 0 ] . " layers"
: $ config - > disable_fan_first_layers - > [ 0 ] == 1
2013-05-10 13:09:27 +00:00
? " except for the first layer"
: "" )
: "will be turned off." ;
2017-06-21 14:15:39 +00:00
if ( $ config - > cooling - > [ 0 ] ) {
2013-09-16 08:09:39 +00:00
$ msg = sprintf "If estimated layer time is below ~%ds, fan will run at %d%% and print speed will be reduced so that no less than %ds are spent on that layer (however, speed will never be reduced below %dmm/s)." ,
2017-06-21 14:15:39 +00:00
$ config - > slowdown_below_layer_time - > [ 0 ] , $ config - > max_fan_speed - > [ 0 ] , $ config - > slowdown_below_layer_time - > [ 0 ] , $ config - > min_print_speed - > [ 0 ] ;
if ( $ config - > fan_below_layer_time - > [ 0 ] > $ config - > slowdown_below_layer_time - > [ 0 ] ) {
2012-10-28 11:43:41 +00:00
$ msg . = sprintf "\nIf estimated layer time is greater, but still below ~%ds, fan will run at a proportionally decreasing speed between %d%% and %d%%." ,
2017-06-21 14:15:39 +00:00
$ config - > fan_below_layer_time - > [ 0 ] , $ config - > max_fan_speed - > [ 0 ] , $ config - > min_fan_speed - > [ 0 ] ;
2012-10-28 11:43:41 +00:00
}
2013-05-10 13:09:27 +00:00
$ msg . = "\nDuring the other layers, fan $fan_other_layers"
} else {
$ msg = "Fan $fan_other_layers" ;
2012-10-28 11:43:41 +00:00
}
2013-03-09 15:27:18 +00:00
$ self - > { description_line } - > SetText ( $ msg ) ;
2012-10-28 11:43:41 +00:00
}
2012-06-17 20:27:05 +00:00
package Slic3r::GUI::Tab::Printer ;
use base 'Slic3r::GUI::Tab' ;
2015-11-04 18:43:23 +00:00
use Wx qw( wxTheApp :sizer :button :bitmap :misc :id :icon :dialog ) ;
2014-06-15 23:49:49 +00:00
use Wx::Event qw( EVT_BUTTON ) ;
2012-06-17 20:27:05 +00:00
2012-07-27 19:13:03 +00:00
sub name { 'printer' }
2012-07-18 18:36:34 +00:00
sub title { 'Printer Settings' }
sub build {
2017-10-25 10:53:31 +00:00
my ( $ self , % params ) = @ _ ;
2012-06-17 20:27:05 +00:00
2017-10-25 10:53:31 +00:00
$ self - > { presets } = wxTheApp - > { preset_bundle } - > printer ;
2017-11-02 15:21:34 +00:00
$ self - > { config } = $ self - > { presets } - > get_edited_preset - > config ;
$ self - > { extruders_count } = scalar @ { $ self - > { config } - > nozzle_diameter } ;
2014-06-15 23:49:49 +00:00
my $ bed_shape_widget = sub {
my ( $ parent ) = @ _ ;
2015-11-02 00:35:28 +00:00
my $ btn = Wx::Button - > new ( $ parent , - 1 , "Set…" , wxDefaultPosition , wxDefaultSize ,
wxBU_LEFT | wxBU_EXACTFIT ) ;
2014-06-15 23:49:49 +00:00
$ btn - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
2017-10-25 10:53:31 +00:00
$ btn - > SetBitmap ( Wx::Bitmap - > new ( Slic3r:: var ( "cog.png" ) , wxBITMAP_TYPE_PNG ) ) ;
2014-06-15 23:49:49 +00:00
my $ sizer = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
$ sizer - > Add ( $ btn ) ;
EVT_BUTTON ( $ self , $ btn , sub {
my $ dlg = Slic3r::GUI::BedShapeDialog - > new ( $ self , $ self - > { config } - > bed_shape ) ;
if ( $ dlg - > ShowModal == wxID_OK ) {
my $ value = $ dlg - > GetValue ;
$ self - > { config } - > set ( 'bed_shape' , $ value ) ;
2014-12-25 16:35:31 +00:00
$ self - > update_dirty ;
2014-07-01 14:40:56 +00:00
$ self - > _on_value_change ( 'bed_shape' , $ value ) ;
2014-06-15 23:49:49 +00:00
}
} ) ;
return $ sizer ;
} ;
2017-11-02 15:21:34 +00:00
2014-07-01 14:40:56 +00:00
{
my $ page = $ self - > add_options_page ( 'General' , 'printer_empty.png' ) ;
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Size and coordinates' ) ;
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > 'Bed shape' ,
widget = > $ bed_shape_widget ,
) ;
$ optgroup - > append_line ( $ line ) ;
$ optgroup - > append_single_option_line ( 'z_offset' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Capabilities' ) ;
{
my $ option = Slic3r::GUI::OptionsGroup::Option - > new (
opt_id = > 'extruders_count' ,
type = > 'i' ,
default = > 1 ,
label = > 'Extruders' ,
tooltip = > 'Number of extruders of the printer.' ,
min = > 1 ,
) ;
$ optgroup - > append_single_option_line ( $ option ) ;
2017-05-16 11:45:28 +00:00
$ optgroup - > append_single_option_line ( 'single_extruder_multi_material' ) ;
2014-07-01 14:40:56 +00:00
}
$ optgroup - > on_change ( sub {
2017-11-02 15:21:34 +00:00
my ( $ opt_key , $ value ) = @ _ ;
wxTheApp - > CallAfter ( sub {
if ( $ opt_key eq 'extruders_count' ) {
2015-06-01 12:57:07 +00:00
$ self - > _extruders_count_changed ( $ optgroup - > get_value ( 'extruders_count' ) ) ;
2017-11-02 15:21:34 +00:00
$ self - > update_dirty ;
} else {
$ self - > update_dirty ;
$ self - > _on_value_change ( $ opt_key , $ value ) ;
}
} ) ;
2014-07-01 14:40:56 +00:00
} ) ;
}
2016-05-16 21:40:24 +00:00
if ( ! $ params { no_controller } )
2015-01-03 22:25:55 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'USB/Serial connection' ) ;
2015-01-04 18:14:54 +00:00
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > 'Serial port' ,
) ;
my $ serial_port = $ optgroup - > get_option ( 'serial_port' ) ;
$ serial_port - > side_widget ( sub {
my ( $ parent ) = @ _ ;
2017-10-25 10:53:31 +00:00
my $ btn = Wx::BitmapButton - > new ( $ parent , - 1 , Wx::Bitmap - > new ( Slic3r:: var ( "arrow_rotate_clockwise.png" ) , wxBITMAP_TYPE_PNG ) ,
2015-01-04 18:14:54 +00:00
wxDefaultPosition , wxDefaultSize , & Wx:: wxBORDER_NONE ) ;
$ btn - > SetToolTipString ( "Rescan serial ports" )
if $ btn - > can ( 'SetToolTipString' ) ;
EVT_BUTTON ( $ self , $ btn , \ & _update_serial_ports ) ;
return $ btn ;
} ) ;
2015-11-02 00:35:28 +00:00
my $ serial_test = sub {
my ( $ parent ) = @ _ ;
my $ btn = $ self - > { serial_test_btn } = Wx::Button - > new ( $ parent , - 1 ,
"Test" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT | wxBU_EXACTFIT ) ;
$ btn - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
2017-10-25 10:53:31 +00:00
$ btn - > SetBitmap ( Wx::Bitmap - > new ( Slic3r:: var ( "wrench.png" ) , wxBITMAP_TYPE_PNG ) ) ;
2015-11-02 00:35:28 +00:00
EVT_BUTTON ( $ self , $ btn , sub {
my $ sender = Slic3r::GCode::Sender - > new ;
my $ res = $ sender - > connect (
$ self - > { config } - > serial_port ,
$ self - > { config } - > serial_speed ,
) ;
2015-11-02 19:34:36 +00:00
if ( $ res && $ sender - > wait_connected ) {
2015-11-02 00:35:28 +00:00
Slic3r::GUI:: show_info ( $ self , "Connection to printer works correctly." , "Success!" ) ;
} else {
Slic3r::GUI:: show_error ( $ self , "Connection failed." ) ;
}
} ) ;
return $ btn ;
} ;
2015-01-04 18:14:54 +00:00
$ line - > append_option ( $ serial_port ) ;
$ line - > append_option ( $ optgroup - > get_option ( 'serial_speed' ) ) ;
2015-11-02 00:35:28 +00:00
$ line - > append_widget ( $ serial_test ) ;
2015-01-04 18:14:54 +00:00
$ optgroup - > append_line ( $ line ) ;
2015-01-03 22:25:55 +00:00
}
2014-12-28 00:30:05 +00:00
{
2014-12-29 11:49:32 +00:00
my $ optgroup = $ page - > new_optgroup ( 'OctoPrint upload' ) ;
2014-12-28 17:49:13 +00:00
2015-01-08 20:34:51 +00:00
# append two buttons to the Host line
my $ octoprint_host_browse = sub {
2014-12-28 17:49:13 +00:00
my ( $ parent ) = @ _ ;
my $ btn = Wx::Button - > new ( $ parent , - 1 , "Browse…" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT ) ;
$ btn - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
2017-10-25 10:53:31 +00:00
$ btn - > SetBitmap ( Wx::Bitmap - > new ( Slic3r:: var ( "zoom.png" ) , wxBITMAP_TYPE_PNG ) ) ;
2014-12-28 17:49:13 +00:00
if ( ! eval "use Net::Bonjour; 1" ) {
$ btn - > Disable ;
}
2015-01-08 20:34:51 +00:00
2014-12-28 17:49:13 +00:00
EVT_BUTTON ( $ self , $ btn , sub {
2016-06-03 07:36:23 +00:00
# look for devices
my $ entries ;
{
my $ res = Net::Bonjour - > new ( 'http' ) ;
$ res - > discover ;
$ entries = [ $ res - > entries ] ;
}
if ( @ { $ entries } ) {
my $ dlg = Slic3r::GUI::BonjourBrowser - > new ( $ self , $ entries ) ;
if ( $ dlg - > ShowModal == wxID_OK ) {
my $ value = $ dlg - > GetValue . ":" . $ dlg - > GetPort ;
$ self - > { config } - > set ( 'octoprint_host' , $ value ) ;
$ self - > update_dirty ;
$ self - > _on_value_change ( 'octoprint_host' , $ value ) ;
2017-10-26 15:17:39 +00:00
$ self - > _reload_config ;
2016-06-03 07:36:23 +00:00
}
} else {
Wx::MessageDialog - > new ( $ self , 'No Bonjour device found' , 'Device Browser' , wxOK | wxICON_INFORMATION ) - > ShowModal ;
2014-12-28 17:49:13 +00:00
}
} ) ;
2015-01-08 20:34:51 +00:00
return $ btn ;
} ;
my $ octoprint_host_test = sub {
my ( $ parent ) = @ _ ;
2015-11-02 00:35:28 +00:00
my $ btn = $ self - > { octoprint_host_test_btn } = Wx::Button - > new ( $ parent , - 1 ,
"Test" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT | wxBU_EXACTFIT ) ;
2015-01-08 20:34:51 +00:00
$ btn - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
2017-10-25 10:53:31 +00:00
$ btn - > SetBitmap ( Wx::Bitmap - > new ( Slic3r:: var ( "wrench.png" ) , wxBITMAP_TYPE_PNG ) ) ;
2015-01-08 20:34:51 +00:00
EVT_BUTTON ( $ self , $ btn , sub {
my $ ua = LWP::UserAgent - > new ;
$ ua - > timeout ( 10 ) ;
2015-01-12 17:56:54 +00:00
my $ res = $ ua - > get (
2015-01-08 20:34:51 +00:00
"http://" . $ self - > { config } - > octoprint_host . "/api/version" ,
'X-Api-Key' = > $ self - > { config } - > octoprint_apikey ,
) ;
if ( $ res - > is_success ) {
Slic3r::GUI:: show_info ( $ self , "Connection to OctoPrint works correctly." , "Success!" ) ;
} else {
Slic3r::GUI:: show_error ( $ self ,
"I wasn't able to connect to OctoPrint (" . $ res - > status_line . "). "
. "Check hostname and OctoPrint version (at least 1.1.0 is required)." ) ;
}
} ) ;
return $ btn ;
2014-12-28 17:49:13 +00:00
} ;
my $ host_line = $ optgroup - > create_single_option_line ( 'octoprint_host' ) ;
2015-01-08 20:34:51 +00:00
$ host_line - > append_widget ( $ octoprint_host_browse ) ;
$ host_line - > append_widget ( $ octoprint_host_test ) ;
2014-12-28 17:49:13 +00:00
$ optgroup - > append_line ( $ host_line ) ;
2014-12-28 00:30:05 +00:00
$ optgroup - > append_single_option_line ( 'octoprint_apikey' ) ;
}
2015-01-04 18:20:13 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Firmware' ) ;
$ optgroup - > append_single_option_line ( 'gcode_flavor' ) ;
}
2014-07-01 14:40:56 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Advanced' ) ;
2015-01-05 18:39:10 +00:00
$ optgroup - > append_single_option_line ( 'use_relative_e_distances' ) ;
2014-07-01 14:40:56 +00:00
$ optgroup - > append_single_option_line ( 'use_firmware_retraction' ) ;
2015-01-05 18:39:10 +00:00
$ optgroup - > append_single_option_line ( 'use_volumetric_e' ) ;
2016-07-16 14:52:11 +00:00
$ optgroup - > append_single_option_line ( 'variable_layer_height' ) ;
2014-07-01 14:40:56 +00:00
}
}
{
my $ page = $ self - > add_options_page ( 'Custom G-code' , 'cog.png' ) ;
2012-06-17 20:27:05 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Start G-code' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'start_gcode' ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 150 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
2012-06-17 21:24:10 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'End G-code' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'end_gcode' ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 150 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
2012-06-17 21:24:10 +00:00
{
2015-01-30 19:08:00 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Before layer change G-code' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'before_layer_gcode' ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 150 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'After layer change G-code' ,
2014-07-01 14:40:56 +00:00
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'layer_gcode' ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 150 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
2012-12-23 15:29:08 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Tool change G-code' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'toolchange_gcode' ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 150 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
}
2012-06-17 20:27:05 +00:00
2017-05-05 09:59:51 +00:00
{
my $ page = $ self - > add_options_page ( 'Notes' , 'note.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Notes' ,
label_width = > 0 ,
) ;
my $ option = $ optgroup - > get_option ( 'printer_notes' ) ;
$ option - > full_width ( 1 ) ;
$ option - > height ( 250 ) ;
$ optgroup - > append_single_option_line ( $ option ) ;
}
}
2012-07-18 18:36:34 +00:00
$ self - > { extruder_pages } = [] ;
2012-07-27 19:13:03 +00:00
$ self - > _build_extruder_pages ;
2017-05-05 09:59:51 +00:00
2016-05-16 21:40:24 +00:00
$ self - > _update_serial_ports if ( ! $ params { no_controller } ) ;
2015-01-04 18:14:54 +00:00
}
sub _update_serial_ports {
my ( $ self ) = @ _ ;
2017-11-02 15:21:34 +00:00
$ self - > get_field ( 'serial_port' ) - > set_values ( [ Slic3r::GUI:: scan_serial_ports ] ) ;
2012-07-18 18:36:34 +00:00
}
2014-09-21 13:29:52 +00:00
sub _extruders_count_changed {
my ( $ self , $ extruders_count ) = @ _ ;
$ self - > { extruders_count } = $ extruders_count ;
2017-11-02 15:21:34 +00:00
wxTheApp - > { preset_bundle } - > printer - > get_edited_preset - > set_num_extruders ( $ extruders_count ) ;
wxTheApp - > { preset_bundle } - > update_multi_material_filament_presets ;
2014-09-21 13:29:52 +00:00
$ self - > _build_extruder_pages ;
$ self - > _on_value_change ( 'extruders_count' , $ extruders_count ) ;
}
2012-07-27 19:13:03 +00:00
sub _build_extruder_pages {
2017-11-02 15:21:34 +00:00
my ( $ self ) = @ _ ;
2014-04-19 14:38:28 +00:00
my $ default_config = Slic3r::Config::Full - > new ;
2017-11-02 15:21:34 +00:00
2014-04-19 14:38:28 +00:00
foreach my $ extruder_idx ( @ { $ self - > { extruder_pages } } .. $ self - > { extruders_count } - 1 ) {
# build page
2014-07-01 14:40:56 +00:00
my $ page = $ self - > { extruder_pages } [ $ extruder_idx ] = $ self - > add_options_page ( "Extruder " . ( $ extruder_idx + 1 ) , 'funnel.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Size' ) ;
$ optgroup - > append_single_option_line ( 'nozzle_diameter' , $ extruder_idx ) ;
}
2017-02-07 17:46:02 +00:00
{
2017-02-09 15:21:48 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Layer height limits' ) ;
2017-02-07 17:46:02 +00:00
$ optgroup - > append_single_option_line ( $ _ , $ extruder_idx )
for qw( min_layer_height max_layer_height ) ;
}
2014-07-01 14:40:56 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Position (for multi-extruder printers)' ) ;
$ optgroup - > append_single_option_line ( 'extruder_offset' , $ extruder_idx ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Retraction' ) ;
$ optgroup - > append_single_option_line ( $ _ , $ extruder_idx )
2015-12-18 17:36:39 +00:00
for qw( retract_length retract_lift ) ;
{
my $ line = Slic3r::GUI::OptionsGroup::Line - > new (
label = > 'Only lift Z' ,
) ;
$ line - > append_option ( $ optgroup - > get_option ( 'retract_lift_above' , $ extruder_idx ) ) ;
$ line - > append_option ( $ optgroup - > get_option ( 'retract_lift_below' , $ extruder_idx ) ) ;
$ optgroup - > append_line ( $ line ) ;
}
$ optgroup - > append_single_option_line ( $ _ , $ extruder_idx )
2017-05-19 17:24:21 +00:00
for qw( retract_speed deretract_speed retract_restart_extra retract_before_travel retract_layer_change wipe retract_before_wipe ) ;
2014-07-01 14:40:56 +00:00
}
{
my $ optgroup = $ page - > new_optgroup ( 'Retraction when tool is disabled (advanced settings for multi-extruder setups)' ) ;
$ optgroup - > append_single_option_line ( $ _ , $ extruder_idx )
for qw( retract_length_toolchange retract_restart_extra_toolchange ) ;
}
2017-05-24 13:20:20 +00:00
{
my $ optgroup = $ page - > new_optgroup ( 'Preview' ) ;
$ optgroup - > append_single_option_line ( 'extruder_colour' , $ extruder_idx ) ;
}
2012-07-18 18:36:34 +00:00
}
2014-04-19 14:38:28 +00:00
# remove extra pages
if ( $ self - > { extruders_count } <= $# { $ self - > { extruder_pages } } ) {
2015-01-25 10:43:34 +00:00
$ _ - > Destroy for @ { $ self - > { extruder_pages } } [ $ self - > { extruders_count } .. $# { $ self - > { extruder_pages } } ] ;
2014-04-19 14:38:28 +00:00
splice @ { $ self - > { extruder_pages } } , $ self - > { extruders_count } ;
}
2012-07-18 18:36:34 +00:00
# rebuild page list
2017-05-05 09:59:51 +00:00
my @ pages_without_extruders = ( grep $ _ - > { title } !~ /^Extruder \d+/ , @ { $ self - > { pages } } ) ;
my $ page_notes = pop @ pages_without_extruders ;
2012-07-18 18:36:34 +00:00
@ { $ self - > { pages } } = (
2017-05-05 09:59:51 +00:00
@ pages_without_extruders ,
2012-07-24 13:30:50 +00:00
@ { $ self - > { extruder_pages } } [ 0 .. $ self - > { extruders_count } - 1 ] ,
2017-05-05 09:59:51 +00:00
$ page_notes
2012-07-18 18:36:34 +00:00
) ;
2017-10-26 15:17:39 +00:00
$ self - > rebuild_page_tree ;
2012-07-18 18:36:34 +00:00
}
2017-02-07 17:41:09 +00:00
# Slic3r::GUI::Tab::Printer::_update is called after a configuration preset is loaded or switched, or when a single option is modifed by the user.
2014-07-01 16:18:23 +00:00
sub _update {
2017-10-25 10:53:31 +00:00
my ( $ self ) = @ _ ;
2017-10-27 22:18:02 +00:00
$ self - > Freeze ;
2014-07-01 16:18:23 +00:00
my $ config = $ self - > { config } ;
2016-05-16 21:40:24 +00:00
my $ serial_speed = $ self - > get_field ( 'serial_speed' ) ;
if ( $ serial_speed ) {
$ self - > get_field ( 'serial_speed' ) - > toggle ( $ config - > get ( 'serial_port' ) ) ;
if ( $ config - > get ( 'serial_speed' ) && $ config - > get ( 'serial_port' ) ) {
$ self - > { serial_test_btn } - > Enable ;
} else {
$ self - > { serial_test_btn } - > Disable ;
}
2015-11-02 00:35:28 +00:00
}
2015-01-08 20:37:00 +00:00
if ( $ config - > get ( 'octoprint_host' ) && eval "use LWP::UserAgent; 1" ) {
2015-01-08 20:34:51 +00:00
$ self - > { octoprint_host_test_btn } - > Enable ;
} else {
$ self - > { octoprint_host_test_btn } - > Disable ;
}
2014-12-28 00:30:05 +00:00
$ self - > get_field ( 'octoprint_apikey' ) - > toggle ( $ config - > get ( 'octoprint_host' ) ) ;
2014-12-23 19:47:11 +00:00
my $ have_multiple_extruders = $ self - > { extruders_count } > 1 ;
$ self - > get_field ( 'toolchange_gcode' ) - > toggle ( $ have_multiple_extruders ) ;
2017-05-16 11:45:28 +00:00
$ self - > get_field ( 'single_extruder_multi_material' ) - > toggle ( $ have_multiple_extruders ) ;
2014-07-01 16:18:23 +00:00
for my $ i ( 0 .. ( $ self - > { extruders_count } - 1 ) ) {
my $ have_retract_length = $ config - > get_at ( 'retract_length' , $ i ) > 0 ;
# when using firmware retraction, firmware decides retraction length
$ self - > get_field ( 'retract_length' , $ i ) - > toggle ( ! $ config - > use_firmware_retraction ) ;
# user can customize travel length if we have retraction length or we're using
# firmware retraction
$ self - > get_field ( 'retract_before_travel' , $ i ) - > toggle ( $ have_retract_length || $ config - > use_firmware_retraction ) ;
# user can customize other retraction options if retraction is enabled
my $ retraction = ( $ have_retract_length || $ config - > use_firmware_retraction ) ;
$ self - > get_field ( $ _ , $ i ) - > toggle ( $ retraction )
for qw( retract_lift retract_layer_change ) ;
2015-12-18 17:36:39 +00:00
# retract lift above/below only applies if using retract lift
$ self - > get_field ( $ _ , $ i ) - > toggle ( $ retraction && $ config - > get_at ( 'retract_lift' , $ i ) > 0 )
for qw( retract_lift_above retract_lift_below ) ;
2014-07-01 16:18:23 +00:00
# some options only apply when not using firmware retraction
$ self - > get_field ( $ _ , $ i ) - > toggle ( $ retraction && ! $ config - > use_firmware_retraction )
2017-05-19 17:24:21 +00:00
for qw( retract_speed deretract_speed retract_before_wipe retract_restart_extra wipe ) ;
my $ wipe = $ config - > get_at ( 'wipe' , $ i ) ;
$ self - > get_field ( 'retract_before_wipe' , $ i ) - > toggle ( $ wipe ) ;
if ( $ config - > use_firmware_retraction && $ wipe ) {
2015-11-04 18:43:23 +00:00
my $ dialog = Wx::MessageDialog - > new ( $ self ,
"The Wipe option is not available when using the Firmware Retraction mode.\n"
. "\nShall I disable it in order to enable Firmware Retraction?" ,
'Firmware Retraction' , wxICON_WARNING | wxYES | wxNO ) ;
my $ new_conf = Slic3r::Config - > new ;
if ( $ dialog - > ShowModal ( ) == wxID_YES ) {
my $ wipe = $ config - > wipe ;
$ wipe - > [ $ i ] = 0 ;
$ new_conf - > set ( "wipe" , $ wipe ) ;
} else {
$ new_conf - > set ( "use_firmware_retraction" , 0 ) ;
}
$ self - > load_config ( $ new_conf ) ;
}
2014-07-01 16:18:23 +00:00
2014-12-23 19:47:11 +00:00
$ self - > get_field ( 'retract_length_toolchange' , $ i ) - > toggle ( $ have_multiple_extruders ) ;
2014-07-01 16:18:23 +00:00
my $ toolchange_retraction = $ config - > get_at ( 'retract_length_toolchange' , $ i ) > 0 ;
2014-12-23 19:47:11 +00:00
$ self - > get_field ( 'retract_restart_extra_toolchange' , $ i ) - > toggle
( $ have_multiple_extruders && $ toolchange_retraction ) ;
2014-07-01 16:18:23 +00:00
}
2017-10-27 22:18:02 +00:00
$ self - > Thaw ;
2014-07-01 16:18:23 +00:00
}
2012-07-27 19:13:03 +00:00
# this gets executed after preset is loaded and before GUI fields are updated
2012-07-18 18:36:34 +00:00
sub on_preset_loaded {
2017-11-02 15:21:34 +00:00
my ( $ self ) = @ _ ;
2012-07-18 18:36:34 +00:00
# update the extruders count field
2017-11-02 15:21:34 +00:00
my $ extruders_count = scalar @ { $ self - > { config } - > nozzle_diameter } ;
$ self - > set_value ( 'extruders_count' , $ extruders_count ) ;
# update the GUI field according to the number of nozzle diameters supplied
$ self - > _extruders_count_changed ( $ extruders_count ) ;
2012-06-17 20:27:05 +00:00
}
2017-10-25 10:53:31 +00:00
# Single Tab page containing a {vsizer} of {optgroups}
2012-06-17 20:27:05 +00:00
package Slic3r::GUI::Tab::Page ;
2015-05-28 16:56:35 +00:00
use Wx qw( wxTheApp :misc :panel :sizer ) ;
2012-06-18 09:26:21 +00:00
use base 'Wx::ScrolledWindow' ;
2012-06-17 20:27:05 +00:00
sub new {
2017-10-25 10:53:31 +00:00
my ( $ class , $ parent , $ title , $ iconID ) = @ _ ;
2012-07-24 10:42:58 +00:00
my $ self = $ class - > SUPER:: new ( $ parent , - 1 , wxDefaultPosition , wxDefaultSize , wxTAB_TRAVERSAL ) ;
2012-07-24 13:30:50 +00:00
$ self - > { optgroups } = [] ;
2012-07-18 18:36:34 +00:00
$ self - > { title } = $ title ;
$ self - > { iconID } = $ iconID ;
2012-06-17 20:27:05 +00:00
2012-06-18 09:26:21 +00:00
$ self - > SetScrollbars ( 1 , 1 , 1 , 1 ) ;
2013-03-09 13:55:07 +00:00
$ self - > { vsizer } = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ self - > SetSizer ( $ self - > { vsizer } ) ;
2012-06-17 20:27:05 +00:00
return $ self ;
}
2014-07-01 14:40:56 +00:00
sub new_optgroup {
my ( $ self , $ title , % params ) = @ _ ;
my $ optgroup = Slic3r::GUI::ConfigOptionsGroup - > new (
parent = > $ self ,
title = > $ title ,
config = > $ self - > GetParent - > { config } ,
label_width = > $ params { label_width } // 200 ,
2014-09-23 18:00:51 +00:00
on_change = > sub {
2015-05-28 16:56:35 +00:00
my ( $ opt_key , $ value ) = @ _ ;
wxTheApp - > CallAfter ( sub {
$ self - > GetParent - > update_dirty ;
$ self - > GetParent - > _on_value_change ( $ opt_key , $ value ) ;
} ) ;
2014-09-23 18:00:51 +00:00
} ,
2012-07-27 19:13:03 +00:00
) ;
2014-07-01 14:40:56 +00:00
2012-07-24 13:30:50 +00:00
push @ { $ self - > { optgroups } } , $ optgroup ;
2014-07-01 14:40:56 +00:00
$ self - > { vsizer } - > Add ( $ optgroup - > sizer , 0 , wxEXPAND | wxALL , 10 ) ;
return $ optgroup ;
}
sub reload_config {
my ( $ self ) = @ _ ;
$ _ - > reload_config for @ { $ self - > { optgroups } } ;
2012-07-24 13:30:50 +00:00
}
2014-07-01 16:18:23 +00:00
sub get_field {
my ( $ self , $ opt_key , $ opt_index ) = @ _ ;
foreach my $ optgroup ( @ { $ self - > { optgroups } } ) {
my $ field = $ optgroup - > get_fieldc ( $ opt_key , $ opt_index ) ;
return $ field if defined $ field ;
}
return undef ;
}
2012-07-24 13:30:50 +00:00
sub set_value {
2017-10-25 10:53:31 +00:00
my ( $ self , $ opt_key , $ value ) = @ _ ;
2012-07-24 13:30:50 +00:00
my $ changed = 0 ;
foreach my $ optgroup ( @ { $ self - > { optgroups } } ) {
$ changed = 1 if $ optgroup - > set_value ( $ opt_key , $ value ) ;
}
return $ changed ;
2012-06-17 20:27:05 +00:00
}
2017-10-26 15:17:39 +00:00
# Dialog to select a new file name for a modified preset to be saved.
# Called from Tab::save_preset().
2012-06-18 20:27:57 +00:00
package Slic3r::GUI::SavePresetWindow ;
2012-07-02 23:20:30 +00:00
use Wx qw( :combobox :dialog :id :misc :sizer ) ;
2012-06-21 11:01:59 +00:00
use Wx::Event qw( EVT_BUTTON EVT_TEXT_ENTER ) ;
2012-06-18 20:27:57 +00:00
use base 'Wx::Dialog' ;
sub new {
2017-10-25 10:53:31 +00:00
my ( $ class , $ parent , % params ) = @ _ ;
2012-07-02 23:20:30 +00:00
my $ self = $ class - > SUPER:: new ( $ parent , - 1 , "Save preset" , wxDefaultPosition , wxDefaultSize ) ;
2012-06-18 20:27:57 +00:00
2014-12-25 16:35:31 +00:00
my @ values = @ { $ params { values } } ;
2014-03-23 20:40:45 +00:00
2012-07-02 23:20:30 +00:00
my $ text = Wx::StaticText - > new ( $ self , - 1 , "Save " . lc ( $ params { title } ) . " as:" , wxDefaultPosition , wxDefaultSize ) ;
2014-03-23 20:40:45 +00:00
$ self - > { combo } = Wx::ComboBox - > new ( $ self , - 1 , $ params { default } , wxDefaultPosition , wxDefaultSize , \ @ values ,
2012-07-01 17:24:06 +00:00
wxTE_PROCESS_ENTER ) ;
my $ buttons = $ self - > CreateStdDialogButtonSizer ( wxOK | wxCANCEL ) ;
2012-06-18 20:27:57 +00:00
my $ sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ sizer - > Add ( $ text , 0 , wxEXPAND | wxTOP | wxLEFT | wxRIGHT , 10 ) ;
2012-06-21 11:01:59 +00:00
$ sizer - > Add ( $ self - > { combo } , 0 , wxEXPAND | wxLEFT | wxRIGHT , 10 ) ;
2012-06-18 20:27:57 +00:00
$ sizer - > Add ( $ buttons , 0 , wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT , 10 ) ;
2012-07-01 17:24:06 +00:00
EVT_BUTTON ( $ self , wxID_OK , \ & accept ) ;
2012-06-21 11:01:59 +00:00
EVT_TEXT_ENTER ( $ self , $ self - > { combo } , \ & accept ) ;
2012-06-18 20:27:57 +00:00
$ self - > SetSizer ( $ sizer ) ;
$ sizer - > SetSizeHints ( $ self ) ;
return $ self ;
}
2012-06-21 11:01:59 +00:00
sub accept {
my ( $ self , $ event ) = @ _ ;
2017-10-26 15:17:39 +00:00
if ( ( $ self - > { chosen_name } = Slic3r:: normalize_utf8_nfc ( $ self - > { combo } - > GetValue ) ) ) {
2017-07-11 15:15:34 +00:00
if ( $ self - > { chosen_name } !~ /^[^<>:\/\\|?*\"]+$/ ) {
2012-08-06 12:23:00 +00:00
Slic3r::GUI:: show_error ( $ self , "The supplied name is not valid; the following characters are not allowed: <>:/\|?*\"" ) ;
2014-03-23 20:40:45 +00:00
} elsif ( $ self - > { chosen_name } eq '- default -' ) {
Slic3r::GUI:: show_error ( $ self , "The supplied name is not available." ) ;
} else {
$ self - > EndModal ( wxID_OK ) ;
2012-07-15 16:55:01 +00:00
}
2012-06-21 11:01:59 +00:00
}
}
2012-06-18 20:27:57 +00:00
sub get_name {
2017-10-25 10:53:31 +00:00
my ( $ self ) = @ _ ;
2012-06-18 20:27:57 +00:00
return $ self - > { chosen_name } ;
}
2012-06-17 20:27:05 +00:00
1 ;