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
wxTheApp ) ;
2012-07-24 12:17:10 +00:00
use Wx::Event qw( EVT_BUTTON EVT_CHOICE EVT_KEY_DOWN EVT_TREE_SEL_CHANGED ) ;
2012-06-18 14:46:43 +00:00
use base 'Wx::Panel' ;
2012-06-17 20:27:05 +00:00
sub new {
my $ class = shift ;
2012-07-18 18:36:34 +00:00
my ( $ 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
2012-06-18 20:27:57 +00:00
# horizontal sizer
2012-07-01 17:24:06 +00:00
$ self - > { sizer } = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
2012-06-18 14:46:43 +00:00
$ self - > { sizer } - > SetSizeHints ( $ self ) ;
$ self - > SetSizer ( $ self - > { sizer } ) ;
2013-03-09 15:27:18 +00:00
# left vertical sizer
my $ left_sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ self - > { sizer } - > Add ( $ left_sizer , 0 , wxEXPAND | wxLEFT | wxTOP | wxBOTTOM , 3 ) ;
my $ left_col_width = 150 ;
# preset chooser
{
2012-06-18 20:27:57 +00:00
2013-03-09 15:27:18 +00:00
# choice menu
$ self - > { presets_choice } = Wx::Choice - > new ( $ self , - 1 , wxDefaultPosition , [ $ left_col_width , - 1 ] , [] ) ;
$ 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
$ self - > { btn_save_preset } = Wx::BitmapButton - > new ( $ self , - 1 , Wx::Bitmap - > new ( "$Slic3r::var/disk.png" , wxBITMAP_TYPE_PNG ) ) ;
$ self - > { btn_delete_preset } = Wx::BitmapButton - > new ( $ self , - 1 , Wx::Bitmap - > new ( "$Slic3r::var/delete.png" , wxBITMAP_TYPE_PNG ) ) ;
$ 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
2013-03-09 15:27:18 +00:00
### These cause GTK warnings:
###my $box = Wx::StaticBox->new($self, -1, "Presets:", wxDefaultPosition, [$left_col_width, 50]);
###my $hsizer = Wx::StaticBoxSizer->new($box, wxHORIZONTAL);
2012-06-18 20:27:57 +00:00
2013-03-09 15:27:18 +00:00
my $ hsizer = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
2012-06-18 20:27:57 +00:00
2013-03-09 15:27:18 +00:00
$ left_sizer - > Add ( $ hsizer , 0 , wxEXPAND | wxBOTTOM , 5 ) ;
$ hsizer - > Add ( $ self - > { presets_choice } , 1 , wxRIGHT | wxALIGN_CENTER_VERTICAL , 3 ) ;
$ 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
}
2012-06-18 20:27:57 +00:00
2013-03-09 15:27:18 +00:00
# tree
$ self - > { treectrl } = Wx::TreeCtrl - > new ( $ self , - 1 , wxDefaultPosition , [ $ left_col_width , - 1 ] , wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_SINGLE | wxTR_NO_LINES | wxBORDER_SUNKEN | wxWANTS_CHARS ) ;
$ left_sizer - > Add ( $ self - > { treectrl } , 1 , wxEXPAND ) ;
$ self - > { icons } = Wx::ImageList - > new ( 16 , 16 , 1 ) ;
$ self - > { treectrl } - > AssignImageList ( $ self - > { icons } ) ;
$ self - > { iconcount } = - 1 ;
$ self - > { treectrl } - > AddRoot ( "root" ) ;
$ self - > { pages } = [] ;
$ self - > { treectrl } - > SetIndent ( 0 ) ;
EVT_TREE_SEL_CHANGED ( $ parent , $ self - > { treectrl } , sub {
my $ page = first { $ _ - > { title } eq $ self - > { treectrl } - > GetItemText ( $ self - > { treectrl } - > GetSelection ) } @ { $ self - > { pages } }
or return ;
$ _ - > Hide for @ { $ self - > { pages } } ;
$ page - > Show ;
$ self - > { sizer } - > Layout ;
$ 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 {
$ self - > on_select_preset ;
2014-07-01 14:40:56 +00:00
$ self - > _on_presets_changed ;
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 } ) ;
2013-03-09 15:27:18 +00:00
EVT_BUTTON ( $ self , $ self - > { btn_delete_preset } , sub {
my $ i = $ self - > { presets_choice } - > GetSelection ;
return if $ i == 0 ; # this shouldn't happen but let's trap it anyway
my $ res = Wx::MessageDialog - > new ( $ self , "Are you sure you want to delete the selected preset?" , 'Delete Preset' , wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ) - > ShowModal ;
return unless $ res == wxID_YES ;
if ( - e $ self - > { presets } [ $ i ] { file } ) {
unlink $ self - > { presets } [ $ i ] { file } ;
}
splice @ { $ self - > { presets } } , $ i , 1 ;
$ self - > set_dirty ( 0 ) ;
$ self - > { presets_choice } - > Delete ( $ i ) ;
$ self - > { presets_choice } - > SetSelection ( 0 ) ;
$ self - > on_select_preset ;
2014-07-01 14:40:56 +00:00
$ self - > _on_presets_changed ;
2013-03-09 15:27:18 +00:00
} ) ;
$ self - > { config } = Slic3r::Config - > new ;
$ self - > build ;
2014-07-01 16:18:23 +00:00
$ self - > _update ;
2013-03-09 15:27:18 +00:00
if ( $ self - > hidden_options ) {
$ self - > { config } - > apply ( Slic3r::Config - > new_from_defaults ( $ self - > hidden_options ) ) ;
2012-07-27 19:13:03 +00:00
}
2012-07-18 18:36:34 +00:00
2012-06-17 20:27:05 +00:00
return $ self ;
}
2012-07-15 15:54:57 +00:00
sub current_preset {
my $ self = shift ;
return $ self - > { presets } [ $ self - > { presets_choice } - > GetSelection ] ;
}
2012-08-07 16:44:47 +00:00
sub get_preset {
my $ self = shift ;
return $ self - > { presets } [ $ _ [ 0 ] ] ;
}
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 ) {
my $ preset = $ self - > current_preset ;
my $ default_name = $ preset - > { default } ? 'Untitled' : basename ( $ preset - > { name } ) ;
$ default_name =~ s/\.ini$//i ;
my $ dlg = Slic3r::GUI::SavePresetWindow - > new ( $ self ,
title = > lc ( $ self - > title ) ,
default = > $ default_name ,
values = > [ map { my $ name = $ _ - > { name } ; $ name =~ s/\.ini$//i ; $ name } @ { $ self - > { presets } } ] ,
) ;
return unless $ dlg - > ShowModal == wxID_OK ;
$ name = $ dlg - > get_name ;
}
$ self - > config - > save ( sprintf "$Slic3r::GUI::datadir/%s/%s.ini" , $ self - > name , $ name ) ;
$ self - > set_dirty ( 0 ) ;
$ self - > load_presets ;
$ self - > { presets_choice } - > SetSelection ( first { basename ( $ self - > { presets } [ $ _ ] { file } ) eq $ name . ".ini" } 1 .. $# { $ self - > { presets } } ) ;
$ self - > on_select_preset ;
2014-07-01 14:40:56 +00:00
$ self - > _on_presets_changed ;
2013-11-11 20:45:58 +00:00
}
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 ;
}
sub on_presets_changed {
my ( $ self , $ cb ) = @ _ ;
$ self - > { on_presets_changed } = $ cb ;
}
# propagate event to the parent
sub _on_value_change {
2012-07-27 19:13:03 +00:00
my $ self = shift ;
2014-07-01 14:40:56 +00:00
$ self - > set_dirty ( 1 ) ;
2012-07-27 19:13:03 +00:00
$ self - > { on_value_change } - > ( @ _ ) if $ self - > { on_value_change } ;
2014-07-01 16:18:23 +00:00
$ self - > _update ;
2012-07-27 19:13:03 +00:00
}
2014-07-01 16:18:23 +00:00
sub _update { }
2014-07-01 14:40:56 +00:00
sub _on_presets_changed {
2013-03-09 15:43:09 +00:00
my $ self = shift ;
2014-07-01 14:40:56 +00:00
2013-03-09 15:43:09 +00:00
$ self - > { on_presets_changed } - > ( [ $ self - > { presets_choice } - > GetStrings ] , $ self - > { presets_choice } - > GetSelection )
if $ self - > { on_presets_changed } ;
}
2012-07-18 18:36:34 +00:00
sub on_preset_loaded { }
2012-07-27 19:13:03 +00:00
sub hidden_options { }
sub config { $ _ [ 0 ] - > { config } - > clone }
2012-07-18 18:36:34 +00:00
2012-07-28 09:34:12 +00:00
sub select_default_preset {
my $ self = shift ;
$ self - > { presets_choice } - > SetSelection ( 0 ) ;
}
2012-08-07 16:44:47 +00:00
sub select_preset {
my $ self = shift ;
$ self - > { presets_choice } - > SetSelection ( $ _ [ 0 ] ) ;
$ self - > on_select_preset ;
}
2012-06-19 15:23:10 +00:00
sub on_select_preset {
my $ self = shift ;
2014-07-01 14:40:56 +00:00
if ( $ self - > { dirty } ) {
2012-07-27 12:11:04 +00:00
my $ name = $ self - > { dirty } == 0 ? 'Default preset' : "Preset \"$self->{presets}[$self->{dirty}]{name}\"" ;
my $ confirm = Wx::MessageDialog - > new ( $ self , "$name has unsaved changes. Discard changes and continue anyway?" ,
2012-07-27 11:57:58 +00:00
'Unsaved Changes' , wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ) ;
if ( $ confirm - > ShowModal == wxID_NO ) {
$ self - > { presets_choice } - > SetSelection ( $ self - > { dirty } ) ;
return ;
}
2012-06-19 15:23:10 +00:00
$ self - > set_dirty ( 0 ) ;
}
2012-07-15 15:54:57 +00:00
my $ preset = $ self - > current_preset ;
2012-08-07 16:44:47 +00:00
my $ preset_config = $ self - > get_preset_config ( $ preset ) ;
eval {
local $ SIG { __WARN__ } = Slic3r::GUI:: warning_catcher ( $ self ) ;
2014-07-01 14:40:56 +00:00
foreach my $ opt_key ( @ { $ self - > { config } - > get_keys } ) {
2012-08-08 22:41:03 +00:00
$ self - > { config } - > set ( $ opt_key , $ preset_config - > get ( $ opt_key ) )
if $ preset_config - > has ( $ opt_key ) ;
2012-06-19 15:23:10 +00:00
}
2013-03-29 23:30:21 +00:00
( $ preset - > { default } || $ preset - > { external } )
? $ self - > { btn_delete_preset } - > Disable
: $ self - > { btn_delete_preset } - > Enable ;
2014-08-07 23:40:34 +00:00
$ self - > _update ;
2013-03-29 23:30:21 +00:00
$ self - > on_preset_loaded ;
2014-07-01 14:40:56 +00:00
$ self - > reload_config ;
2014-06-25 09:45:39 +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 set_dirty(0) as they would mark the
# preset dirty again
wxTheApp - > CallAfter ( sub {
$ self - > set_dirty ( 0 ) ;
} ) ;
2013-03-29 23:30:21 +00:00
$ Slic3r:: GUI:: Settings - > { presets } { $ self - > name } = $ preset - > { file } ? basename ( $ preset - > { file } ) : '' ;
2012-08-07 16:44:47 +00:00
} ;
2013-03-29 23:30:21 +00:00
if ( $@ ) {
$@ = "I was unable to load the selected config file: $@" ;
Slic3r::GUI:: catch_error ( $ self ) ;
$ self - > select_default_preset ;
}
2012-08-07 16:44:47 +00:00
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2012-06-19 15:23:10 +00:00
}
2012-08-07 16:44:47 +00:00
sub get_preset_config {
my $ self = shift ;
my ( $ preset ) = @ _ ;
2012-08-08 22:59:41 +00:00
if ( $ preset - > { default } ) {
2014-07-01 14:40:56 +00:00
return Slic3r::Config - > new_from_defaults ( @ { $ self - > { config } - > get_keys } ) ;
2012-08-08 22:59:41 +00:00
} else {
2012-08-07 16:44:47 +00:00
if ( ! - e $ preset - > { file } ) {
Slic3r::GUI:: show_error ( $ self , "The selected preset does not exist anymore ($preset->{file})." ) ;
return ;
}
2013-03-09 15:27:18 +00:00
# apply preset values on top of defaults
2012-08-08 17:36:34 +00:00
my $ external_config = Slic3r::Config - > load ( $ preset - > { file } ) ;
2012-08-08 22:59:41 +00:00
my $ config = Slic3r::Config - > new ;
2012-08-08 22:41:03 +00:00
$ config - > set ( $ _ , $ external_config - > get ( $ _ ) )
2014-07-01 14:40:56 +00:00
for grep $ external_config - > has ( $ _ ) , @ { $ self - > { config } - > get_keys } ;
2012-08-08 22:59:41 +00:00
return $ config ;
2012-08-07 16:44:47 +00:00
}
}
2014-07-01 14:40:56 +00:00
sub init_config_options {
my ( $ self , @ opt_keys ) = @ _ ;
$ self - > { config } - > apply ( Slic3r::Config - > new_from_defaults ( @ opt_keys ) ) ;
}
2012-06-18 20:27:57 +00:00
sub add_options_page {
2012-06-17 20:27:05 +00:00
my $ self = shift ;
2012-07-18 18:36:34 +00:00
my ( $ title , $ icon , % params ) = @ _ ;
2012-06-17 20:54:08 +00:00
2013-03-09 15:27:18 +00:00
if ( $ icon ) {
2012-07-18 18:36:34 +00:00
my $ bitmap = Wx::Bitmap - > new ( "$Slic3r::var/$icon" , wxBITMAP_TYPE_PNG ) ;
2012-06-18 14:46:43 +00:00
$ self - > { icons } - > Add ( $ bitmap ) ;
$ self - > { iconcount } + + ;
2012-06-17 20:54:08 +00:00
}
2012-07-18 18:36:34 +00:00
2014-07-01 14:40:56 +00:00
my $ page = Slic3r::GUI::Tab::Page - > new ( $ self , $ title , $ self - > { iconcount } ) ;
2013-03-09 15:27:18 +00:00
$ page - > Hide ;
2012-07-24 10:41:51 +00:00
$ self - > { sizer } - > Add ( $ page , 1 , wxEXPAND | wxLEFT , 5 ) ;
2012-07-18 18:36:34 +00:00
push @ { $ self - > { pages } } , $ page ;
$ self - > update_tree ;
return $ page ;
}
2014-07-01 14:40:56 +00:00
sub reload_config {
2012-07-24 13:30:50 +00:00
my $ self = shift ;
2014-07-01 14:40:56 +00:00
$ _ - > reload_config for @ { $ self - > { pages } } ;
2012-07-24 13:30:50 +00:00
}
2012-07-18 18:36:34 +00:00
sub update_tree {
my $ self = shift ;
my ( $ select ) = @ _ ;
$ select // = 0 ; #/
my $ rootItem = $ self - > { treectrl } - > GetRootItem ;
$ self - > { treectrl } - > DeleteChildren ( $ rootItem ) ;
foreach my $ page ( @ { $ self - > { pages } } ) {
my $ itemId = $ self - > { treectrl } - > AppendItem ( $ rootItem , $ page - > { title } , $ page - > { iconID } ) ;
$ self - > { treectrl } - > SelectItem ( $ itemId ) if $ self - > { treectrl } - > GetChildrenCount ( $ rootItem ) == $ select + 1 ;
2012-06-18 20:27:57 +00:00
}
2012-06-17 20:27:05 +00:00
}
2012-06-18 20:27:57 +00:00
sub set_dirty {
my $ self = shift ;
my ( $ dirty ) = @ _ ;
2014-03-29 21:23:35 +00:00
return if $ dirty and $ self - > is_dirty ;
return if ( not $ dirty ) and ( not $ self - > is_dirty ) ;
2012-06-18 20:27:57 +00:00
2012-07-27 11:54:45 +00:00
my $ selection = $ self - > { presets_choice } - > GetSelection ;
my $ i = $ self - > { dirty } // $ selection ; #/
2012-06-18 20:27:57 +00:00
my $ text = $ self - > { presets_choice } - > GetString ( $ i ) ;
2012-07-15 15:54:57 +00:00
2012-06-18 20:27:57 +00:00
if ( $ dirty ) {
$ self - > { dirty } = $ i ;
if ( $ text !~ / \(modified\)$/ ) {
$ self - > { presets_choice } - > SetString ( $ i , "$text (modified)" ) ;
2012-07-27 11:54:45 +00:00
$ self - > { presets_choice } - > SetSelection ( $ selection ) ; # http://trac.wxwidgets.org/ticket/13769
2012-06-18 20:27:57 +00:00
}
} else {
$ self - > { dirty } = undef ;
$ text =~ s/ \(modified\)$// ;
$ self - > { presets_choice } - > SetString ( $ i , $ text ) ;
2012-07-27 11:54:45 +00:00
$ self - > { presets_choice } - > SetSelection ( $ selection ) ; # http://trac.wxwidgets.org/ticket/13769
2012-06-18 20:27:57 +00:00
}
2014-07-01 14:40:56 +00:00
$ self - > _on_presets_changed ;
2012-06-18 20:27:57 +00:00
}
2012-06-23 15:38:19 +00:00
sub is_dirty {
my $ self = shift ;
2012-06-30 20:34:13 +00:00
return ( defined $ self - > { dirty } ) ;
2012-06-23 15:38:19 +00:00
}
2012-06-18 20:27:57 +00:00
sub load_presets {
my $ self = shift ;
2012-07-15 15:54:57 +00:00
$ self - > { presets } = [ {
default = > 1 ,
name = > '- default -' ,
} ] ;
2012-06-18 20:27:57 +00:00
2014-06-14 17:59:59 +00:00
my % presets = wxTheApp - > presets ( $ self - > name ) ;
2014-04-06 20:45:40 +00:00
foreach my $ preset_name ( sort keys % presets ) {
2012-07-15 15:54:57 +00:00
push @ { $ self - > { presets } } , {
2014-03-25 13:04:01 +00:00
name = > $ preset_name ,
file = > $ presets { $ preset_name } ,
2012-07-15 15:54:57 +00:00
} ;
}
2012-06-18 20:27:57 +00:00
$ self - > { presets_choice } - > Clear ;
2012-07-15 15:54:57 +00:00
$ self - > { presets_choice } - > Append ( $ _ - > { name } ) for @ { $ self - > { presets } } ;
2012-06-19 16:11:51 +00:00
{
2012-07-15 15:54:57 +00:00
# load last used preset
2012-07-27 19:13:03 +00:00
my $ i = first { basename ( $ self - > { presets } [ $ _ ] { file } ) eq ( $ Slic3r:: GUI:: Settings - > { presets } { $ self - > name } || '' ) } 1 .. $# { $ self - > { presets } } ;
2012-07-15 15:54:57 +00:00
$ self - > { presets_choice } - > SetSelection ( $ i || 0 ) ;
2012-06-20 15:17:07 +00:00
$ self - > on_select_preset ;
2012-06-19 16:11:51 +00:00
}
2014-07-01 14:40:56 +00:00
$ self - > _on_presets_changed ;
2012-06-18 20:27:57 +00:00
}
2012-06-17 20:27:05 +00:00
2013-03-09 15:27:18 +00:00
sub load_config_file {
2012-06-19 12:47:02 +00:00
my $ self = shift ;
my ( $ file ) = @ _ ;
2013-03-09 15:27:18 +00:00
# look for the loaded config among the existing menu items
my $ i = first { $ self - > { presets } [ $ _ ] { file } eq $ file && $ self - > { presets } [ $ _ ] { external } } 1 .. $# { $ self - > { presets } } ;
if ( ! $ i ) {
my $ preset_name = basename ( $ file ) ; # keep the .ini suffix
push @ { $ self - > { presets } } , {
file = > $ file ,
name = > $ preset_name ,
external = > 1 ,
} ;
$ self - > { presets_choice } - > Append ( $ preset_name ) ;
$ i = $# { $ self - > { presets } } ;
2012-06-19 12:47:02 +00:00
}
2013-03-09 15:27:18 +00:00
$ self - > { presets_choice } - > SetSelection ( $ i ) ;
$ self - > on_select_preset ;
2014-07-01 14:40:56 +00:00
$ self - > _on_presets_changed ;
}
sub load_config {
my $ self = shift ;
my ( $ config ) = @ _ ;
foreach my $ opt_key ( @ { $ self - > { config } - > diff ( $ config ) } ) {
$ self - > { config } - > set ( $ opt_key , $ config - > get ( $ opt_key ) ) ;
$ self - > set_dirty ( 1 ) ;
}
$ self - > reload_config ;
2012-06-19 12:47:02 +00:00
}
2014-07-01 16:18:23 +00:00
sub get_field {
my ( $ self , $ opt_key , $ opt_index ) = @ _ ;
foreach my $ page ( @ { $ self - > { pages } } ) {
my $ field = $ page - > get_field ( $ opt_key , $ opt_index ) ;
return $ field if defined $ field ;
}
return undef ;
}
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' ;
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
2014-07-01 14:40:56 +00:00
$ self - > init_config_options ( qw(
layer_height first_layer_height
perimeters spiral_vase
top_solid_layers bottom_solid_layers
extra_perimeters avoid_crossing_perimeters thin_walls overhangs
seam_position external_perimeters_first
fill_density fill_pattern solid_fill_pattern
infill_every_layers infill_only_where_needed
solid_infill_every_layers fill_angle solid_infill_below_area
only_retract_when_crossing_perimeters infill_first
perimeter_speed small_perimeter_speed external_perimeter_speed infill_speed
solid_infill_speed top_solid_infill_speed support_material_speed
support_material_interface_speed bridge_speed gap_fill_speed
travel_speed
first_layer_speed
perimeter_acceleration infill_acceleration bridge_acceleration
first_layer_acceleration default_acceleration
skirts skirt_distance skirt_height min_skirt_length
brim_width
support_material support_material_threshold support_material_enforce_layers
raft_layers
support_material_pattern support_material_spacing support_material_angle
support_material_interface_layers support_material_interface_spacing
dont_support_bridges
notes
complete_objects extruder_clearance_radius extruder_clearance_height
gcode_comments output_filename_format
post_process
perimeter_extruder infill_extruder support_material_extruder support_material_interface_extruder
ooze_prevention standby_temperature_delta
interface_shells
extrusion_width first_layer_extrusion_width perimeter_extrusion_width
external_perimeter_extrusion_width infill_extrusion_width solid_infill_extrusion_width
top_infill_extrusion_width support_material_extrusion_width
bridge_flow_ratio
xy_size_compensation threads resolution
) ) ;
{
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' ) ;
$ 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
{
my $ page = $ self - > add_options_page ( 'Infill' , 'shading.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' ) ;
$ optgroup - > append_single_option_line ( 'solid_fill_pattern' ) ;
}
{
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' ) ;
$ optgroup - > append_single_option_line ( 'only_retract_when_crossing_perimeters' ) ;
$ optgroup - > append_single_option_line ( 'infill_first' ) ;
}
}
{
my $ page = $ self - > add_options_page ( 'Speed' , 'time.png' ) ;
{
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' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Speed for non-print moves' ) ;
$ optgroup - > append_single_option_line ( 'travel_speed' ) ;
}
2013-09-18 15:45:02 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Modifiers' ) ;
$ optgroup - > append_single_option_line ( 'first_layer_speed' ) ;
}
{
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' ) ;
}
}
{
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' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Options for support material and raft' ) ;
$ optgroup - > append_single_option_line ( 'support_material_pattern' ) ;
$ 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 ( 'dont_support_bridges' ) ;
}
}
{
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 ) ;
}
}
{
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 ( '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' ) ;
$ 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' ) ;
}
{
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' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Flow' ) ;
$ optgroup - > append_single_option_line ( 'bridge_flow_ratio' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Other' ) ;
$ optgroup - > append_single_option_line ( 'xy_size_compensation' ) ;
$ optgroup - > append_single_option_line ( 'threads' ) if $ Slic3r:: have_threads ;
$ optgroup - > append_single_option_line ( 'resolution' ) ;
}
}
2012-06-17 20:27:05 +00:00
}
2014-07-01 16:18:23 +00:00
sub _update {
my ( $ self ) = @ _ ;
my $ config = $ self - > { config } ;
2014-08-08 15:18:41 +00:00
# we enable spiral vase if other settings are compatible with it
# or if it is enabled (this prevents the checkbox from being disabled
# when an incompatible setting is set)
$ self - > get_field ( 'spiral_vase' ) - > toggle (
( $ config - > perimeters == 1 && $ config - > top_solid_layers == 0 && $ config - > fill_density == 0 )
|| $ config - > spiral_vase
) ;
2014-07-01 16:18:23 +00:00
my $ have_perimeters = $ config - > perimeters > 0 ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_perimeters )
for qw( extra_perimeters thin_walls overhangs seam_position external_perimeters_first ) ;
my $ have_infill = $ config - > fill_density > 0 ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_infill )
for qw( fill_pattern infill_every_layers infill_only_where_needed solid_infill_every_layers ) ;
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 ) ;
my $ have_support_material = $ config - > support_material || $ config - > raft_layers > 0 ;
my $ have_support_interface = $ config - > support_material_interface_layers > 0 ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_support_material )
for qw( support_material_threshold support_material_enforce_layers
support_material_pattern support_material_spacing support_material_angle
support_material_interface_layers dont_support_bridges
support_material_extruder ) ;
$ self - > get_field ( $ _ ) - > toggle ( $ have_support_material && $ have_support_interface )
for qw( support_material_interface_spacing support_material_interface_extruder ) ;
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 ) ;
}
2012-07-27 19:13:03 +00:00
sub hidden_options { ! $ Slic3r:: have_threads ? qw( threads ) : ( ) }
2012-06-18 12:29:47 +00:00
package Slic3r::GUI::Tab::Filament ;
use base 'Slic3r::GUI::Tab' ;
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
2014-07-01 14:40:56 +00:00
$ self - > init_config_options ( qw(
filament_diameter extrusion_multiplier
temperature first_layer_temperature bed_temperature first_layer_bed_temperature
fan_always_on cooling
min_fan_speed max_fan_speed bridge_fan_speed disable_fan_first_layers
fan_below_layer_time slowdown_below_layer_time min_print_speed
) ) ;
{
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' ) ;
$ optgroup - > append_single_option_line ( 'filament_diameter' , 0 ) ;
$ optgroup - > append_single_option_line ( 'extrusion_multiplier' , 0 ) ;
}
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' ,
) ;
$ line - > append_option ( $ optgroup - > get_option ( 'first_layer_bed_temperature' ) ) ;
$ line - > append_option ( $ optgroup - > get_option ( 'bed_temperature' ) ) ;
$ optgroup - > append_line ( $ line ) ;
}
}
}
{
my $ page = $ self - > add_options_page ( 'Cooling' , 'hourglass.png' ) ;
{
my $ optgroup = $ page - > new_optgroup ( 'Enable' ) ;
$ optgroup - > append_single_option_line ( 'fan_always_on' ) ;
$ optgroup - > append_single_option_line ( 'cooling' ) ;
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' ,
) ;
$ line - > append_option ( $ optgroup - > get_option ( 'min_fan_speed' ) ) ;
$ line - > append_option ( $ optgroup - > get_option ( 'max_fan_speed' ) ) ;
$ optgroup - > append_line ( $ line ) ;
}
$ optgroup - > append_single_option_line ( 'bridge_fan_speed' ) ;
$ optgroup - > append_single_option_line ( 'disable_fan_first_layers' ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Cooling thresholds' ,
label_width = > 250 ,
) ;
$ 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' ) ;
}
}
2014-07-01 16:18:23 +00:00
}
sub _on_value_change {
my $ self = shift ;
my ( $ opt_key ) = @ _ ;
$ self - > SUPER:: _on_value_change ( @ _ ) ;
}
sub _update {
my ( $ self ) = @ _ ;
2014-07-01 14:40:56 +00:00
$ self - > _update_description ;
2014-07-01 16:18:23 +00:00
my $ cooling = $ self - > { config } - > cooling ;
$ self - > get_field ( $ _ ) - > 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 ) ;
$ self - > get_field ( $ _ ) - > toggle ( $ cooling || $ self - > { config } - > fan_always_on )
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 {
my $ self = shift ;
my $ config = $ self - > config ;
my $ msg = "" ;
2013-05-10 13:09:27 +00:00
my $ fan_other_layers = $ config - > fan_always_on
? sprintf "will always run at %d%%%s." , $ config - > min_fan_speed ,
( $ config - > disable_fan_first_layers > 1
? " except for the first " . $ config - > disable_fan_first_layers . " layers"
: $ config - > disable_fan_first_layers == 1
? " except for the first layer"
: "" )
: "will be turned off." ;
2012-10-28 11:43:41 +00:00
if ( $ config - > cooling ) {
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)." ,
$ config - > slowdown_below_layer_time , $ config - > max_fan_speed , $ config - > slowdown_below_layer_time , $ config - > min_print_speed ;
2012-10-28 11:43:41 +00:00
if ( $ config - > fan_below_layer_time > $ config - > slowdown_below_layer_time ) {
$ msg . = sprintf "\nIf estimated layer time is greater, but still below ~%ds, fan will run at a proportionally decreasing speed between %d%% and %d%%." ,
$ config - > fan_below_layer_time , $ config - > max_fan_speed , $ config - > min_fan_speed ;
}
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' ;
2014-06-15 23:49:49 +00:00
use Wx qw( :sizer :button :bitmap :misc :id ) ;
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 {
my $ self = shift ;
2012-06-17 20:27:05 +00:00
2014-07-01 14:40:56 +00:00
$ self - > init_config_options ( qw(
bed_shape z_offset
gcode_flavor use_relative_e_distances
use_firmware_retraction vibration_limit
start_gcode end_gcode layer_gcode toolchange_gcode
nozzle_diameter extruder_offset
retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe
retract_length_toolchange retract_restart_extra_toolchange
) ) ;
2012-07-24 13:30:50 +00:00
2014-06-15 23:49:49 +00:00
my $ bed_shape_widget = sub {
my ( $ parent ) = @ _ ;
my $ btn = Wx::Button - > new ( $ parent , - 1 , "Set…" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT ) ;
$ btn - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
if ( $ Slic3r:: GUI:: have_button_icons ) {
$ btn - > SetBitmap ( Wx::Bitmap - > new ( "$Slic3r::var/cog.png" , wxBITMAP_TYPE_PNG ) ) ;
}
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-06-16 22:30:44 +00:00
$ self - > set_dirty ( 1 ) ;
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 ;
} ;
2014-07-01 14:40:56 +00:00
$ self - > { extruders_count } = 1 ;
{
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' ) ;
}
2012-12-05 14:08:17 +00:00
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Firmware' ) ;
$ optgroup - > append_single_option_line ( 'gcode_flavor' ) ;
$ optgroup - > append_single_option_line ( 'use_relative_e_distances' ) ;
}
{
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 ) ;
}
$ optgroup - > on_change ( sub {
my ( $ opt_id ) = @ _ ;
if ( $ opt_id eq 'extruders_count' ) {
$ self - > { extruders_count } = $ optgroup - > get_value ( 'extruders_count' ) ;
$ self - > _build_extruder_pages ;
2014-07-01 16:18:23 +00:00
$ self - > _update ;
2014-07-01 14:40:56 +00:00
}
} ) ;
}
{
my $ optgroup = $ page - > new_optgroup ( 'Advanced' ) ;
$ optgroup - > append_single_option_line ( 'use_firmware_retraction' ) ;
$ optgroup - > append_single_option_line ( 'vibration_limit' ) ;
}
}
{
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
{
2014-07-01 14:40:56 +00:00
my $ optgroup = $ page - > new_optgroup ( 'Layer change G-code' ,
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
2012-07-18 18:36:34 +00:00
$ self - > { extruder_pages } = [] ;
2012-07-27 19:13:03 +00:00
$ self - > _build_extruder_pages ;
2012-07-18 18:36:34 +00:00
}
2013-03-18 20:20:32 +00:00
sub _extruder_options { qw( nozzle_diameter extruder_offset retract_length retract_lift retract_speed retract_restart_extra retract_before_travel wipe
2013-03-09 19:05:43 +00:00
retract_layer_change retract_length_toolchange retract_restart_extra_toolchange ) }
2012-07-18 18:36:34 +00:00
2012-07-27 19:13:03 +00:00
sub _build_extruder_pages {
2012-07-18 18:36:34 +00:00
my $ self = shift ;
2012-06-18 20:27:57 +00:00
2014-04-19 14:38:28 +00:00
my $ default_config = Slic3r::Config::Full - > new ;
foreach my $ extruder_idx ( @ { $ self - > { extruder_pages } } .. $ self - > { extruders_count } - 1 ) {
# extend options
foreach my $ opt_key ( $ self - > _extruder_options ) {
my $ values = $ self - > { config } - > get ( $ opt_key ) ;
2014-05-20 21:37:17 +00:00
if ( ! defined $ values ) {
$ values = [ $ default_config - > get_at ( $ opt_key , 0 ) ] ;
} else {
# use last extruder's settings for the new one
my $ last_value = $ values - > [ - 1 ] ;
$ values - > [ $ extruder_idx ] // = $ last_value ;
}
2014-04-19 14:38:28 +00:00
$ self - > { config } - > set ( $ opt_key , $ values )
or die "Unable to extend $opt_key" ;
}
# 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 ) ;
}
{
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 )
for qw( retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe ) ;
}
{
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 ) ;
}
2012-07-18 18:36:34 +00:00
$ self - > { extruder_pages } [ $ extruder_idx ] { disabled } = 0 ;
}
2014-04-19 14:38:28 +00:00
# remove extra pages
if ( $ self - > { extruders_count } <= $# { $ self - > { extruder_pages } } ) {
splice @ { $ self - > { extruder_pages } } , $ self - > { extruders_count } ;
}
# remove extra config values
foreach my $ opt_key ( $ self - > _extruder_options ) {
my $ values = $ self - > { config } - > get ( $ opt_key ) ;
splice @$ values , $ self - > { extruders_count } if $ self - > { extruders_count } <= $#$ values ;
$ self - > { config } - > set ( $ opt_key , $ values )
or die "Unable to truncate $opt_key" ;
}
2012-07-18 18:36:34 +00:00
# rebuild page list
@ { $ self - > { pages } } = (
( grep $ _ - > { title } !~ /^Extruder \d+/ , @ { $ self - > { pages } } ) ,
2012-07-24 13:30:50 +00:00
@ { $ self - > { extruder_pages } } [ 0 .. $ self - > { extruders_count } - 1 ] ,
2012-07-18 18:36:34 +00:00
) ;
2014-07-01 14:40:56 +00:00
$ self - > update_tree ( 0 ) ;
2012-07-18 18:36:34 +00:00
}
2014-07-01 16:18:23 +00:00
sub _update {
my ( $ self ) = @ _ ;
my $ config = $ self - > { config } ;
$ self - > get_field ( 'toolchange_gcode' ) - > toggle ( $ self - > { extruders_count } > 1 ) ;
for my $ i ( 0 .. ( $ self - > { extruders_count } - 1 ) ) {
# disable extruder offset for first extruder
$ self - > get_field ( 'extruder_offset' , $ i ) - > toggle ( $ i != 0 ) ;
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 ) ;
# some options only apply when not using firmware retraction
$ self - > get_field ( $ _ , $ i ) - > toggle ( $ retraction && ! $ config - > use_firmware_retraction )
for qw( retract_speed retract_restart_extra wipe ) ;
my $ toolchange_retraction = $ config - > get_at ( 'retract_length_toolchange' , $ i ) > 0 ;
$ self - > get_field ( $ _ , $ i ) - > toggle ( $ toolchange_retraction )
for qw( retract_restart_extra_toolchange ) ;
}
}
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 {
my $ self = shift ;
2014-07-01 14:40:56 +00:00
return ;
2012-07-18 18:36:34 +00:00
# update the extruders count field
2012-07-20 12:41:27 +00:00
{
2012-07-24 13:30:50 +00:00
# update the GUI field according to the number of nozzle diameters supplied
2012-07-27 19:13:03 +00:00
$ self - > set_value ( 'extruders_count' , scalar @ { $ self - > { config } - > nozzle_diameter } ) ;
2012-07-18 18:36:34 +00:00
# update extruder page list
2014-07-01 14:40:56 +00:00
$ self - > _on_value_change ( 'extruders_count' ) ;
2012-07-18 18:36:34 +00:00
}
2012-06-17 20:27:05 +00:00
}
2013-03-09 15:27:18 +00:00
sub load_config_file {
2012-08-07 18:14:28 +00:00
my $ self = shift ;
2013-03-09 15:27:18 +00:00
$ self - > SUPER:: load_config_file ( @ _ ) ;
2012-08-07 18:14:28 +00:00
Slic3r::GUI:: warning_catcher ( $ self ) - > (
"Your configuration was imported. However, Slic3r is currently only able to import settings "
. "for the first defined filament. We recommend you don't use exported configuration files "
. "for multi-extruder setups and rely on the built-in preset management system instead." )
if @ { $ self - > { config } - > nozzle_diameter } > 1 ;
}
2012-06-17 20:27:05 +00:00
package Slic3r::GUI::Tab::Page ;
2013-03-09 15:27:18 +00:00
use Wx qw( :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 {
my $ class = shift ;
2014-07-01 14:40:56 +00:00
my ( $ 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 ,
on_change = > sub { $ self - > GetParent - > _on_value_change ( @ _ ) } ,
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 {
my $ self = shift ;
my ( $ opt_key , $ value ) = @ _ ;
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
}
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 {
my $ class = shift ;
my ( $ 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-03-23 20:40:45 +00:00
my @ values = grep $ _ ne '- default -' , @ { $ params { values } } ;
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 ) = @ _ ;
2012-07-15 16:55:01 +00:00
if ( ( $ self - > { chosen_name } = $ self - > { combo } - > GetValue ) ) {
2014-03-23 20:40:45 +00:00
if ( $ self - > { chosen_name } !~ /^[^<>:\/\\|?*\"]+$/i ) {
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 {
my $ self = shift ;
return $ self - > { chosen_name } ;
}
2012-06-17 20:27:05 +00:00
1 ;