2013-08-25 16:01:59 +00:00
package Slic3r::GUI::Plater::ObjectSettingsDialog ;
2013-03-10 11:46:54 +00:00
use strict ;
use warnings ;
use utf8 ;
use Wx qw( :dialog :id :misc :sizer :systemsettings :notebook wxTAB_TRAVERSAL ) ;
2013-03-10 13:58:49 +00:00
use Wx::Event qw( EVT_BUTTON ) ;
2013-03-10 11:33:10 +00:00
use base 'Wx::Dialog' ;
sub new {
my $ class = shift ;
my ( $ parent , % params ) = @ _ ;
2014-02-14 09:02:08 +00:00
my $ self = $ class - > SUPER:: new ( $ parent , - 1 , "Settings for " . $ params { object } - > name , wxDefaultPosition , [ 700 , 500 ] , wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ) ;
2013-12-12 19:19:33 +00:00
$ self - > { $ _ } = $ params { $ _ } for keys % params ;
2013-03-10 11:46:54 +00:00
$ self - > { tabpanel } = Wx::Notebook - > new ( $ self , - 1 , wxDefaultPosition , wxDefaultSize , wxNB_TOP | wxTAB_TRAVERSAL ) ;
2013-12-12 19:19:33 +00:00
$ self - > { tabpanel } - > AddPage ( $ self - > { settings } = Slic3r::GUI::Plater::ObjectDialog::SettingsTab - > new ( $ self - > { tabpanel } ) , "Settings" ) ;
$ self - > { tabpanel } - > AddPage ( $ self - > { layers } = Slic3r::GUI::Plater::ObjectDialog::LayersTab - > new ( $ self - > { tabpanel } ) , "Layers" ) ;
2014-01-08 18:36:41 +00:00
$ self - > { tabpanel } - > AddPage ( $ self - > { parts } = Slic3r::GUI::Plater::ObjectPartsPanel - > new ( $ self - > { tabpanel } , model_object = > $ params { model_object } ) , "Parts" ) ;
2013-12-12 19:19:33 +00:00
$ self - > { tabpanel } - > AddPage ( $ self - > { materials } = Slic3r::GUI::Plater::ObjectDialog::MaterialsTab - > new ( $ self - > { tabpanel } ) , "Materials" ) ;
2013-03-10 11:46:54 +00:00
my $ buttons = $ self - > CreateStdDialogButtonSizer ( wxOK ) ;
2013-03-10 13:58:49 +00:00
EVT_BUTTON ( $ self , wxID_OK , sub {
# validate user input
2013-08-25 12:37:50 +00:00
return if ! $ self - > { settings } - > CanClose ;
2013-03-10 13:58:49 +00:00
return if ! $ self - > { layers } - > CanClose ;
# notify tabs
$ self - > { layers } - > Closing ;
2013-08-25 17:52:32 +00:00
$ self - > { materials } - > Closing ;
2013-03-10 13:58:49 +00:00
$ self - > EndModal ( wxID_OK ) ;
2013-11-12 20:49:34 +00:00
$ self - > Destroy ;
2013-03-10 13:58:49 +00:00
} ) ;
2013-03-10 11:46:54 +00:00
my $ sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ sizer - > Add ( $ self - > { tabpanel } , 1 , wxEXPAND | wxTOP | wxLEFT | wxRIGHT , 10 ) ;
$ sizer - > Add ( $ buttons , 0 , wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT , 10 ) ;
$ self - > SetSizer ( $ sizer ) ;
2013-05-17 12:14:33 +00:00
$ self - > SetMinSize ( $ self - > GetSize ) ;
2013-03-10 11:46:54 +00:00
return $ self ;
}
2013-03-10 11:33:10 +00:00
2013-12-12 19:19:33 +00:00
package Slic3r::GUI::Plater::ObjectDialog::BaseTab ;
use base 'Wx::Panel' ;
sub model_object {
my ( $ self ) = @ _ ;
return $ self - > GetParent - > GetParent - > { model_object } ;
}
2013-08-25 12:37:50 +00:00
package Slic3r::GUI::Plater::ObjectDialog::SettingsTab ;
use Wx qw( :dialog :id :misc :sizer :systemsettings :button :icon ) ;
use Wx::Grid ;
use Wx::Event qw( EVT_BUTTON ) ;
2013-12-12 19:19:33 +00:00
use base 'Slic3r::GUI::Plater::ObjectDialog::BaseTab' ;
2013-08-25 12:37:50 +00:00
sub new {
my $ class = shift ;
my ( $ parent , % params ) = @ _ ;
my $ self = $ class - > SUPER:: new ( $ parent , - 1 , wxDefaultPosition , wxDefaultSize ) ;
$ self - > { sizer } = Wx::BoxSizer - > new ( wxVERTICAL ) ;
# descriptive text
{
my $ label = Wx::StaticText - > new ( $ self , - 1 , "You can use this section to override some settings just for this object." ,
wxDefaultPosition , [ - 1 , 25 ] ) ;
$ label - > SetFont ( Wx::SystemSettings:: GetFont ( wxSYS_DEFAULT_GUI_FONT ) ) ;
$ self - > { sizer } - > Add ( $ label , 0 , wxEXPAND | wxTOP | wxLEFT | wxRIGHT , 10 ) ;
}
# option selector
{
# get all options with object scope and sort them by category+label
my % settings = map { $ _ = > sprintf ( '%s > %s' , $ Slic3r:: Config:: Options - > { $ _ } { category } , $ Slic3r:: Config:: Options - > { $ _ } { full_label } // $ Slic3r:: Config:: Options - > { $ _ } { label } ) }
grep { ( $ Slic3r:: Config:: Options - > { $ _ } { scope } // '' ) eq 'object' }
keys %$ Slic3r:: Config:: Options ;
$ self - > { options } = [ sort { $ settings { $ a } cmp $ settings { $ b } } keys % settings ] ;
my $ choice = Wx::Choice - > new ( $ self , - 1 , wxDefaultPosition , [ 150 , - 1 ] , [ map $ settings { $ _ } , @ { $ self - > { options } } ] ) ;
# create the button
my $ btn = Wx::BitmapButton - > new ( $ self , - 1 , Wx::Bitmap - > new ( "$Slic3r::var/add.png" , wxBITMAP_TYPE_PNG ) ) ;
EVT_BUTTON ( $ self , $ btn , sub {
2013-08-25 16:08:56 +00:00
my $ idx = $ choice - > GetSelection ;
return if $ idx == - 1 ; # lack of selected item, can happen on Windows
my $ opt_key = $ self - > { options } [ $ idx ] ;
2013-12-12 19:19:33 +00:00
$ self - > model_object - > config - > apply ( Slic3r::Config - > new_from_defaults ( $ opt_key ) ) ;
2013-08-25 12:37:50 +00:00
$ self - > update_optgroup ;
} ) ;
my $ h_sizer = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
$ h_sizer - > Add ( $ choice , 1 , wxEXPAND | wxALL , 0 ) ;
$ h_sizer - > Add ( $ btn , 0 , wxEXPAND | wxLEFT , 10 ) ;
$ self - > { sizer } - > Add ( $ h_sizer , 0 , wxEXPAND | wxALL , 10 ) ;
}
$ self - > { options_sizer } = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ self - > { sizer } - > Add ( $ self - > { options_sizer } , 0 , wxEXPAND | wxALL , 10 ) ;
$ self - > update_optgroup ;
$ self - > SetSizer ( $ self - > { sizer } ) ;
$ self - > { sizer } - > SetSizeHints ( $ self ) ;
return $ self ;
}
sub update_optgroup {
my $ self = shift ;
$ self - > { options_sizer } - > Clear ( 1 ) ;
2013-12-12 19:19:33 +00:00
my $ config = $ self - > model_object - > config ;
2013-08-25 12:37:50 +00:00
my % categories = ( ) ;
2014-01-02 21:06:58 +00:00
foreach my $ opt_key ( @ { $ config - > get_keys } ) {
2013-08-25 12:37:50 +00:00
my $ category = $ Slic3r:: Config:: Options - > { $ opt_key } { category } ;
$ categories { $ category } || = [] ;
push @ { $ categories { $ category } } , $ opt_key ;
}
foreach my $ category ( sort keys % categories ) {
my $ optgroup = Slic3r::GUI::ConfigOptionsGroup - > new (
parent = > $ self ,
title = > $ category ,
config = > $ config ,
options = > [ sort @ { $ categories { $ category } } ] ,
full_labels = > 1 ,
extra_column = > sub {
my ( $ line ) = @ _ ;
my ( $ opt_key ) = @ { $ line - > { options } } ; # we assume that we have one option per line
my $ btn = Wx::BitmapButton - > new ( $ self , - 1 , Wx::Bitmap - > new ( "$Slic3r::var/delete.png" , wxBITMAP_TYPE_PNG ) ) ;
EVT_BUTTON ( $ self , $ btn , sub {
2014-01-22 20:14:47 +00:00
$ self - > model_object - > config - > erase ( $ opt_key ) ;
2013-08-25 12:37:50 +00:00
Slic3r::GUI - > CallAfter ( sub { $ self - > update_optgroup } ) ;
} ) ;
return $ btn ;
} ,
) ;
$ self - > { options_sizer } - > Add ( $ optgroup - > sizer , 0 , wxEXPAND | wxBOTTOM , 10 ) ;
}
$ self - > Layout ;
}
sub CanClose {
my $ self = shift ;
# validate options before allowing user to dismiss the dialog
# the validate method only works on full configs so we have
# to merge our settings with the default ones
2013-12-12 19:19:33 +00:00
my $ config = Slic3r::Config - > merge ( $ self - > GetParent - > GetParent - > GetParent - > GetParent - > GetParent - > config , $ self - > model_object - > config ) ;
2013-08-25 12:37:50 +00:00
eval {
$ config - > validate ;
} ;
return 0 if Slic3r::GUI:: catch_error ( $ self ) ;
return 1 ;
}
2013-03-10 13:58:49 +00:00
package Slic3r::GUI::Plater::ObjectDialog::LayersTab ;
use Wx qw( :dialog :id :misc :sizer :systemsettings ) ;
use Wx::Grid ;
use Wx::Event qw( EVT_GRID_CELL_CHANGED ) ;
2013-12-12 19:19:33 +00:00
use base 'Slic3r::GUI::Plater::ObjectDialog::BaseTab' ;
2013-03-10 13:58:49 +00:00
sub new {
my $ class = shift ;
my ( $ parent , % params ) = @ _ ;
my $ self = $ class - > SUPER:: new ( $ parent , - 1 , wxDefaultPosition , wxDefaultSize ) ;
my $ sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
{
2013-03-24 14:26:55 +00:00
my $ label = Wx::StaticText - > new ( $ self , - 1 , "You can use this section to override the default layer height for parts of this object. Set layer height to zero to skip portions of the input file." ,
2013-11-12 13:34:03 +00:00
wxDefaultPosition , [ - 1 , 40 ] ) ;
2013-03-10 13:58:49 +00:00
$ label - > SetFont ( Wx::SystemSettings:: GetFont ( wxSYS_DEFAULT_GUI_FONT ) ) ;
$ sizer - > Add ( $ label , 0 , wxEXPAND | wxALL , 10 ) ;
}
my $ grid = $ self - > { grid } = Wx::Grid - > new ( $ self , - 1 , wxDefaultPosition , wxDefaultSize ) ;
$ sizer - > Add ( $ grid , 1 , wxEXPAND | wxALL , 10 ) ;
$ grid - > CreateGrid ( 0 , 3 ) ;
$ grid - > DisableDragRowSize ;
2013-03-11 19:00:12 +00:00
$ grid - > HideRowLabels if & Wx:: wxVERSION_STRING !~ / 2\.8\./ ;
2013-03-12 09:28:51 +00:00
$ grid - > SetColLabelValue ( 0 , "Min Z (mm)" ) ;
$ grid - > SetColLabelValue ( 1 , "Max Z (mm)" ) ;
$ grid - > SetColLabelValue ( 2 , "Layer height (mm)" ) ;
$ grid - > SetColSize ( $ _ , 135 ) for 0 .. 2 ;
2013-03-10 13:58:49 +00:00
$ grid - > SetDefaultCellAlignment ( wxALIGN_CENTRE , wxALIGN_CENTRE ) ;
# load data
2013-12-12 19:19:33 +00:00
foreach my $ range ( @ { $ self - > model_object - > layer_height_ranges } ) {
2013-03-10 13:58:49 +00:00
$ grid - > AppendRows ( 1 ) ;
my $ i = $ grid - > GetNumberRows - 1 ;
$ grid - > SetCellValue ( $ i , $ _ , $ range - > [ $ _ ] ) for 0 .. 2 ;
}
$ grid - > AppendRows ( 1 ) ; # append one empty row
EVT_GRID_CELL_CHANGED ( $ grid , sub {
my ( $ grid , $ event ) = @ _ ;
# remove any non-numeric character
my $ value = $ grid - > GetCellValue ( $ event - > GetRow , $ event - > GetCol ) ;
$ value =~ s/,/./g ;
$ value =~ s/[^0-9.]//g ;
$ grid - > SetCellValue ( $ event - > GetRow , $ event - > GetCol , $ value ) ;
# if there's no empty row, let's append one
for my $ i ( 0 .. $ grid - > GetNumberRows - 1 ) {
if ( ! grep $ grid - > GetCellValue ( $ i , $ _ ) , 0 .. 2 ) {
return ;
}
}
$ grid - > AppendRows ( 1 ) ;
} ) ;
$ self - > SetSizer ( $ sizer ) ;
$ sizer - > SetSizeHints ( $ self ) ;
return $ self ;
}
sub CanClose {
my $ self = shift ;
# validate ranges before allowing user to dismiss the dialog
foreach my $ range ( $ self - > _get_ranges ) {
my ( $ min , $ max , $ height ) = @$ range ;
if ( $ max <= $ min ) {
Slic3r::GUI:: show_error ( $ self , "Invalid Z range $min-$max." ) ;
return 0 ;
}
if ( $ min < 0 || $ max < 0 ) {
Slic3r::GUI:: show_error ( $ self , "Invalid Z range $min-$max." ) ;
return 0 ;
}
2013-03-24 14:26:55 +00:00
if ( $ height < 0 ) {
2013-03-10 13:58:49 +00:00
Slic3r::GUI:: show_error ( $ self , "Invalid layer height $height." ) ;
return 0 ;
}
# TODO: check for overlapping ranges
}
return 1 ;
}
sub Closing {
my $ self = shift ;
# save ranges into the plater object
2013-12-12 19:19:33 +00:00
$ self - > model_object - > layer_height_ranges ( [ $ self - > _get_ranges ] ) ;
2013-03-10 13:58:49 +00:00
}
sub _get_ranges {
my $ self = shift ;
my @ ranges = ( ) ;
for my $ i ( 0 .. $ self - > { grid } - > GetNumberRows - 1 ) {
my ( $ min , $ max , $ height ) = map $ self - > { grid } - > GetCellValue ( $ i , $ _ ) , 0 .. 2 ;
next if $ min eq '' || $ max eq '' || $ height eq '' ;
push @ ranges , [ $ min , $ max , $ height ] ;
}
return sort { $ a - > [ 0 ] <=> $ b - > [ 0 ] } @ ranges ;
}
2013-08-25 17:52:32 +00:00
package Slic3r::GUI::Plater::ObjectDialog::MaterialsTab ;
use Wx qw( :dialog :id :misc :sizer :systemsettings :button :icon ) ;
use Wx::Grid ;
use Wx::Event qw( EVT_BUTTON ) ;
2013-12-12 19:19:33 +00:00
use base 'Slic3r::GUI::Plater::ObjectDialog::BaseTab' ;
2013-08-25 17:52:32 +00:00
sub new {
my $ class = shift ;
my ( $ parent , % params ) = @ _ ;
my $ self = $ class - > SUPER:: new ( $ parent , - 1 , wxDefaultPosition , wxDefaultSize ) ;
$ self - > { object } = $ params { object } ;
$ self - > { sizer } = Wx::BoxSizer - > new ( wxVERTICAL ) ;
# descriptive text
{
my $ label = Wx::StaticText - > new ( $ self , - 1 , "In this section you can assign object materials to your extruders." ,
wxDefaultPosition , [ - 1 , 25 ] ) ;
$ label - > SetFont ( Wx::SystemSettings:: GetFont ( wxSYS_DEFAULT_GUI_FONT ) ) ;
$ self - > { sizer } - > Add ( $ label , 0 , wxEXPAND | wxTOP | wxLEFT | wxRIGHT , 10 ) ;
}
# get unique materials used in this object
2013-12-12 19:19:33 +00:00
$ self - > { materials } = [ $ self - > model_object - > unique_materials ] ;
2013-08-25 17:52:32 +00:00
2014-01-02 21:06:58 +00:00
# get the current mapping
$ self - > { mapping } = { } ;
foreach my $ material_id ( @ { $ self - > { materials } } ) {
my $ config = $ self - > model_object - > model - > materials - > { $ material_id } - > config ;
$ self - > { mapping } { $ material_id } = ( $ config - > perimeter_extruder // 0 ) + 1 ;
}
if ( @ { $ self - > { materials } } > 0 ) {
# build an OptionsGroup
my $ optgroup = Slic3r::GUI::OptionsGroup - > new (
parent = > $ self ,
title = > 'Extruders' ,
label_width = > 300 ,
options = > [
map {
my $ i = $ _ ;
my $ material_id = $ self - > { materials } [ $ i ] ;
{
opt_key = > "material_extruder_$_" ,
type = > 'i' ,
label = > $ self - > model_object - > model - > get_material_name ( $ material_id ) ,
min = > 1 ,
default = > $ self - > { mapping } { $ material_id } // 1 ,
on_change = > sub { $ self - > { mapping } { $ material_id } = $ _ [ 0 ] } ,
}
} 0 .. $# { $ self - > { materials } }
] ,
) ;
$ self - > { sizer } - > Add ( $ optgroup - > sizer , 0 , wxEXPAND | wxALL , 10 ) ;
} else {
my $ label = Wx::StaticText - > new ( $ self , - 1 , "This object does not contain named materials." ,
wxDefaultPosition , [ - 1 , 25 ] ) ;
$ label - > SetFont ( Wx::SystemSettings:: GetFont ( wxSYS_DEFAULT_GUI_FONT ) ) ;
$ self - > { sizer } - > Add ( $ label , 0 , wxEXPAND | wxTOP | wxLEFT | wxRIGHT , 10 ) ;
}
2013-08-25 17:52:32 +00:00
$ self - > SetSizer ( $ self - > { sizer } ) ;
$ self - > { sizer } - > SetSizeHints ( $ self ) ;
return $ self ;
}
sub Closing {
my $ self = shift ;
# save mappings into the plater object
2014-01-02 21:06:58 +00:00
foreach my $ volume ( @ { $ self - > model_object - > volumes } ) {
2013-12-30 17:28:41 +00:00
if ( defined $ volume - > material_id ) {
my $ config = $ self - > model_object - > model - > materials - > { $ volume - > material_id } - > config ;
2014-01-22 20:09:32 +00:00
# temporary hack for handling volumes added after the window was launched
$ self - > { mapping } { $ volume - > material_id } // = 0 ;
2014-01-02 21:06:58 +00:00
$ config - > set ( 'extruder' , $ self - > { mapping } { $ volume - > material_id } - 1 ) ;
2013-12-30 17:28:41 +00:00
}
}
2013-08-25 17:52:32 +00:00
}
2013-03-10 11:33:10 +00:00
1 ;