2011-10-03 11:55:32 +02:00
package Slic3r::GUI::SkeinPanel ;
use strict ;
use warnings ;
2011-10-03 13:08:43 +02:00
use utf8 ;
2011-10-03 11:55:32 +02:00
2011-12-09 14:07:50 +01:00
use File::Basename qw(basename dirname) ;
2012-04-11 15:58:09 +02:00
use Slic3r::Geometry qw(X Y) ;
2012-02-05 16:43:44 +01:00
use Wx qw(:sizer :progressdialog wxOK wxICON_INFORMATION wxICON_WARNING wxICON_ERROR wxICON_QUESTION
wxOK wxCANCEL wxID_OK wxFD_OPEN wxFD_SAVE wxDEFAULT wxNORMAL) ;
2011-10-03 11:55:32 +02:00
use Wx::Event qw(EVT_BUTTON) ;
use base 'Wx::Panel' ;
2012-04-30 14:56:01 +02:00
our $last_skein_dir ;
our $last_config_dir ;
our $last_input_file ;
our $last_output_file ;
2011-12-26 19:45:01 +01:00
our $last_config ;
2011-12-09 14:07:50 +01:00
2011-10-03 11:55:32 +02:00
sub new {
my $class = shift ;
my ( $parent ) = @_ ;
my $self = $class -> SUPER:: new ( $parent , - 1 );
2012-06-28 14:44:54 +02:00
no warnings 'qw' ;
2011-10-03 11:55:32 +02:00
my %panels = (
2011-11-13 22:22:34 +01:00
printer => {
2011-10-03 11:55:32 +02:00
title => 'Printer' ,
2012-06-28 14:44:54 +02:00
options => [ qw(nozzle_diameter#0 bed_size print_center z_offset gcode_flavor use_relative_e_distances) ],
2011-11-13 22:22:34 +01:00
},
filament => {
2011-10-03 11:55:32 +02:00
title => 'Filament' ,
2012-06-28 16:22:11 +02:00
options => [ qw(filament_diameter#0 extrusion_multiplier#0 temperature#0 first_layer_temperature#0 bed_temperature first_layer_bed_temperature) ],
2011-11-13 22:22:34 +01:00
},
2011-11-28 19:11:26 +01:00
print_speed => {
title => 'Print speed' ,
2012-06-27 19:37:34 +02:00
options => [ qw(perimeter_speed small_perimeter_speed external_perimeter_speed infill_speed solid_infill_speed top_solid_infill_speed bridge_speed) ],
2011-11-28 19:11:26 +01:00
},
2011-11-13 22:22:34 +01:00
speed => {
2011-11-28 19:11:26 +01:00
title => 'Other speed settings' ,
2012-06-06 15:52:21 +02:00
options => [ qw(travel_speed first_layer_speed) ],
2011-11-13 22:22:34 +01:00
},
accuracy => {
2011-10-03 11:55:32 +02:00
title => 'Accuracy' ,
2012-06-06 16:11:38 +02:00
options => [ qw(layer_height first_layer_height infill_every_layers) ],
2011-11-13 22:22:34 +01:00
},
print => {
2011-10-03 11:55:32 +02:00
title => 'Print settings' ,
2012-06-23 22:43:23 +02:00
options => [ qw(perimeters solid_layers fill_density fill_angle fill_pattern solid_fill_pattern randomize_start) ],
2011-11-13 22:22:34 +01:00
},
retract => {
2011-10-03 11:55:32 +02:00
title => 'Retraction' ,
2011-11-07 15:58:47 +01:00
options => [ qw(retract_length retract_lift retract_speed retract_restart_extra retract_before_travel) ],
2011-11-13 22:22:34 +01:00
},
2012-02-25 21:01:00 +01:00
cooling => {
title => 'Cooling' ,
2012-03-03 22:21:30 +01:00
options => [ qw(cooling min_fan_speed max_fan_speed bridge_fan_speed fan_below_layer_time slowdown_below_layer_time min_print_speed disable_fan_first_layers fan_always_on) ],
2012-06-23 22:43:23 +02:00
label_width => 450 ,
2012-02-25 21:01:00 +01:00
},
2011-11-13 22:22:34 +01:00
skirt => {
2011-10-03 11:55:32 +02:00
title => 'Skirt' ,
2012-06-23 22:27:59 +02:00
options => [ qw(skirts skirt_distance skirt_height brim_width) ],
2011-11-13 22:22:34 +01:00
},
2011-11-13 22:48:21 +01:00
gcode => {
2012-04-30 14:56:01 +02:00
title => 'G-code' ,
2012-05-23 11:47:52 +02:00
options => [ qw(start_gcode end_gcode layer_gcode gcode_comments post_process) ],
2012-05-20 20:07:39 +02:00
label_width => 260 ,
2011-11-13 22:48:21 +01:00
},
2012-05-23 11:47:52 +02:00
sequential_printing => {
title => 'Sequential printing' ,
options => [ qw(complete_objects extruder_clearance_radius extruder_clearance_height) ],
},
2011-11-25 10:58:13 +01:00
extrusion => {
title => 'Extrusion' ,
2012-06-30 23:18:15 +01:00
options => [ qw(extrusion_width first_layer_extrusion_width perimeter_extrusion_width infill_extrusion_width support_material_extrusion_width bridge_flow_ratio) ],
2011-11-25 10:58:13 +01:00
},
2011-12-26 04:20:45 -05:00
output => {
title => 'Output' ,
2012-04-30 23:30:06 +02:00
options => [ qw(output_filename_format duplicate_distance) ],
2011-12-26 04:20:45 -05:00
},
2012-05-19 15:08:32 +02:00
other => {
title => 'Other' ,
2012-06-23 22:43:23 +02:00
options => [ ( $ Slic3r:: have_threads ? qw(threads) : ()), qw(extra_perimeters) ],
2012-05-19 15:08:32 +02:00
},
2012-02-05 20:55:17 +01:00
notes => {
title => 'Notes' ,
options => [ qw(notes) ],
},
2012-06-23 22:43:23 +02:00
support_material => {
title => 'Support material' ,
2012-06-28 15:14:27 +02:00
options => [ qw(support_material support_material_threshold support_material_pattern support_material_spacing support_material_angle support_material_extruder) ],
2012-06-23 22:43:23 +02:00
},
2011-10-03 11:55:32 +02:00
);
2011-10-05 18:13:47 +02:00
$self -> { panels } = \ %panels ;
2011-10-03 11:55:32 +02:00
2011-11-13 22:22:34 +01:00
my $tabpanel = Wx::Notebook -> new ( $self , - 1 , Wx:: wxDefaultPosition , Wx:: wxDefaultSize , & Wx:: wxNB_TOP );
my $make_tab = sub {
my @cols = @_ ;
my $tab = Wx::Panel -> new ( $tabpanel , - 1 );
my $sizer = Wx::BoxSizer -> new ( wxHORIZONTAL );
foreach my $col ( @cols ) {
my $vertical_sizer = Wx::BoxSizer -> new ( wxVERTICAL );
for my $optgroup ( @$col ) {
2012-05-19 15:08:32 +02:00
next unless @ { $panels { $optgroup }{ options } };
2011-11-13 22:22:34 +01:00
my $optpanel = Slic3r::GUI::OptionsGroup -> new ( $tab , % { $panels { $optgroup }});
$vertical_sizer -> Add ( $optpanel , 0 , wxEXPAND | wxALL , 10 );
}
$sizer -> Add ( $vertical_sizer );
}
$tab -> SetSizer ( $sizer );
return $tab ;
};
2011-10-03 11:55:32 +02:00
2011-11-25 10:58:13 +01:00
my @tabs = (
2012-06-23 22:43:23 +02:00
$make_tab -> ([ qw(accuracy skirt support_material) ], [ qw(print retract) ]),
$make_tab -> ([ qw(cooling notes) ]),
2012-02-19 12:27:44 +01:00
$make_tab -> ([ qw(printer filament) ], [ qw(print_speed speed) ]),
2011-11-25 10:58:13 +01:00
$make_tab -> ([ qw(gcode) ]),
2012-06-28 16:33:07 +02:00
$make_tab -> ([ qw(extrusion) ], [ qw(output other sequential_printing) ]),
2011-11-25 10:58:13 +01:00
);
2011-10-03 11:55:32 +02:00
2012-05-04 10:15:33 +02:00
$tabpanel -> AddPage ( Slic3r::GUI::Plater -> new ( $tabpanel ), "Plater" );
2012-03-03 22:50:08 +01:00
$tabpanel -> AddPage ( $tabs [ 0 ], "Print Settings" );
2012-02-25 21:01:00 +01:00
$tabpanel -> AddPage ( $tabs [ 1 ], "Cooling" );
2012-03-03 21:25:26 +01:00
$tabpanel -> AddPage ( $tabs [ 2 ], "Printer and Filament" );
2012-04-30 14:56:01 +02:00
$tabpanel -> AddPage ( $tabs [ 3 ], "G-code" );
$tabpanel -> AddPage ( $tabs [ 4 ], "Advanced" );
2011-11-13 22:22:34 +01:00
my $buttons_sizer ;
2011-10-05 18:13:47 +02:00
{
2011-11-13 22:22:34 +01:00
$buttons_sizer = Wx::BoxSizer -> new ( wxHORIZONTAL );
2012-04-30 14:56:01 +02:00
my $slice_button = Wx::Button -> new ( $self , - 1 , "Quick slice…" );
2012-02-28 23:04:19 +00:00
$slice_button -> SetDefault ();
2012-03-03 22:53:12 +01:00
$buttons_sizer -> Add ( $slice_button , 0 , wxRIGHT , 20 );
2012-02-28 23:04:19 +00:00
EVT_BUTTON ( $self , $slice_button , sub { $self -> do_slice });
2012-03-03 22:53:12 +01:00
my $save_button = Wx::Button -> new ( $self , - 1 , "Save config..." );
2012-05-01 13:27:57 +02:00
$buttons_sizer -> Add ( $save_button , 0 , wxRIGHT , 5 );
2012-03-03 22:50:08 +01:00
EVT_BUTTON ( $self , $save_button , sub { $self -> save_config });
2012-03-03 22:53:12 +01:00
my $load_button = Wx::Button -> new ( $self , - 1 , "Load config..." );
2012-05-01 13:27:57 +02:00
$buttons_sizer -> Add ( $load_button , 0 , wxRIGHT , 5 );
2012-03-03 22:50:08 +01:00
EVT_BUTTON ( $self , $load_button , sub { $self -> load_config });
my $text = Wx::StaticText -> new ( $self , - 1 , "Remember to check for updates at http://slic3r.org/\nVersion: $Slic3r::VERSION" , Wx:: wxDefaultPosition , Wx:: wxDefaultSize , wxALIGN_RIGHT );
my $font = Wx::Font -> new ( 10 , wxDEFAULT , wxNORMAL , wxNORMAL );
$text -> SetFont ( $font );
$buttons_sizer -> Add ( $text , 1 , wxEXPAND | wxALIGN_RIGHT );
2011-10-03 11:55:32 +02:00
}
2011-10-05 18:13:47 +02:00
my $sizer = Wx::BoxSizer -> new ( wxVERTICAL );
2012-03-03 22:50:08 +01:00
$sizer -> Add ( $buttons_sizer , 0 , wxEXPAND | wxALL , 10 );
2011-11-13 22:22:34 +01:00
$sizer -> Add ( $tabpanel );
2011-10-05 18:13:47 +02:00
2011-10-03 11:55:32 +02:00
$sizer -> SetSizeHints ( $self );
$self -> SetSizer ( $sizer );
2011-10-03 13:08:43 +02:00
$self -> Layout ;
2011-10-03 11:55:32 +02:00
2012-04-11 17:38:56 +02:00
$_ -> () for @ Slic3r::GUI::OptionsGroup:: reload_callbacks ;
2011-10-03 11:55:32 +02:00
return $self ;
}
2012-05-20 11:40:37 +02:00
our $model_wildcard = "STL files (*.stl)|*.stl;*.STL|OBJ files (*.obj)|*.obj;*.OBJ|AMF files (*.amf)|*.amf;*.AMF;*.xml;*.XML" ;
2012-04-30 14:56:01 +02:00
our $ini_wildcard = "INI files *.ini|*.ini;*.INI" ;
our $gcode_wildcard = "G-code files *.gcode|*.gcode;*.GCODE" ;
2012-05-30 12:06:01 +02:00
our $svg_wildcard = "SVG files *.svg|*.svg;*.SVG" ;
2011-12-22 17:38:37 +01:00
2011-10-03 11:55:32 +02:00
sub do_slice {
my $self = shift ;
2011-12-22 17:38:37 +01:00
my %params = @_ ;
2011-10-03 11:55:32 +02:00
2011-10-03 17:41:45 +02:00
my $process_dialog ;
2011-10-03 11:55:32 +02:00
eval {
# validate configuration
Slic3r::Config -> validate ;
2012-02-05 16:43:44 +01:00
# confirm slicing of more than one copies
2012-04-11 15:58:09 +02:00
my $copies = $ Slic3r:: duplicate_grid -> [ X ] * $ Slic3r:: duplicate_grid -> [ Y ];
$copies = $ Slic3r:: duplicate if $ Slic3r:: duplicate > 1 ;
2012-02-05 16:43:44 +01:00
if ( $copies > 1 ) {
my $confirmation = Wx::MessageDialog -> new ( $self , "Are you sure you want to slice $copies copies?" ,
'Confirm' , wxICON_QUESTION | wxOK | wxCANCEL );
return unless $confirmation -> ShowModal == wxID_OK ;
}
2011-10-03 11:55:32 +02:00
# select input file
2012-02-03 20:22:45 +01:00
my $dir = $last_skein_dir || $last_config_dir || "" ;
2012-03-12 19:52:23 +02:00
my $input_file ;
if ( ! $params { reslice }) {
2012-05-31 09:26:30 +02:00
my $dialog = Wx::FileDialog -> new ( $self , 'Choose a file to slice (STL/OBJ/AMF):' , $dir , "" , $model_wildcard , wxFD_OPEN | & Wx:: wxFD_FILE_MUST_EXIST );
2012-04-18 17:16:01 +03:00
if ( $dialog -> ShowModal != wxID_OK ) {
$dialog -> Destroy ;
return ;
}
2012-03-12 19:52:23 +02:00
$input_file = $dialog -> GetPaths ;
2012-04-18 17:16:01 +03:00
$dialog -> Destroy ;
2012-03-12 19:52:23 +02:00
$last_input_file = $input_file ;
} else {
if ( ! defined $last_input_file ) {
Wx::MessageDialog -> new ( $self , "No previously sliced file" ,
'Confirm' , wxICON_ERROR | wxOK ) -> ShowModal ();
return ;
}
if ( ! - e $last_input_file ) {
Wx::MessageDialog -> new ( $self , "Cannot find previously sliced file!" ,
'Confirm' , wxICON_ERROR | wxOK ) -> ShowModal ();
return ;
}
$input_file = $last_input_file ;
}
2011-10-03 11:55:32 +02:00
my $input_file_basename = basename ( $input_file );
2012-02-03 19:57:49 +01:00
$last_skein_dir = dirname ( $input_file );
2011-10-03 11:55:32 +02:00
2012-04-30 14:56:01 +02:00
my $print = Slic3r::Print -> new ;
$print -> add_object_from_file ( $input_file );
2012-05-23 11:47:52 +02:00
$print -> validate ;
2011-12-26 04:20:45 -05:00
# select output file
2012-04-30 14:56:01 +02:00
my $output_file = $ main:: opt { output };
2012-03-12 19:52:23 +02:00
if ( $params { reslice }) {
2012-04-30 14:56:01 +02:00
$output_file = $last_output_file if defined $last_output_file ;
2012-03-12 19:52:23 +02:00
} elsif ( $params { save_as }) {
2012-04-30 14:56:01 +02:00
$output_file = $print -> expanded_output_filepath ( $output_file );
2012-03-26 17:57:54 +02:00
$output_file =~ s/\.gcode$/.svg/i if $params { export_svg };
my $dlg = Wx::FileDialog -> new ( $self , 'Save ' . ( $params { export_svg } ? 'SVG' : 'G-code' ) . ' file as:' , dirname ( $output_file ),
2012-05-30 12:06:01 +02:00
basename ( $output_file ), $params { export_svg } ? $svg_wildcard : $gcode_wildcard , wxFD_SAVE );
2012-04-18 17:16:01 +03:00
if ( $dlg -> ShowModal != wxID_OK ) {
$dlg -> Destroy ;
return ;
}
2012-04-30 14:56:01 +02:00
$output_file = $last_output_file = $dlg -> GetPath ;
2012-04-18 17:16:01 +03:00
$dlg -> Destroy ;
2011-12-26 04:20:45 -05:00
}
# show processbar dialog
$process_dialog = Wx::ProgressDialog -> new ( 'Slicing...' , "Processing $input_file_basename..." ,
2012-02-05 14:23:15 +01:00
100 , $self , 0 );
2011-12-26 04:20:45 -05:00
$process_dialog -> Pulse ;
2011-11-27 11:40:03 +01:00
{
2011-12-18 13:43:31 +01:00
my @warnings = ();
local $SIG { __WARN__ } = sub { push @warnings , $_ [ 0 ] };
2012-05-30 12:06:01 +02:00
my %export_params = (
2012-04-30 14:56:01 +02:00
output_file => $output_file ,
status_cb => sub {
my ( $percent , $message ) = @_ ;
if ( & Wx:: wxVERSION_STRING =~ / 2\.(8\.|9\.[2-9])/ ) {
$process_dialog -> Update ( $percent , "$message..." );
}
},
);
2012-03-26 17:57:54 +02:00
if ( $params { export_svg }) {
2012-05-30 12:06:01 +02:00
$print -> export_svg ( %export_params );
2012-03-26 17:57:54 +02:00
} else {
2012-05-30 12:06:01 +02:00
$print -> export_gcode ( %export_params );
2012-03-26 17:57:54 +02:00
}
2012-04-30 14:56:01 +02:00
Slic3r::GUI:: warning_catcher ( $self ) -> ( $_ ) for @warnings ;
2011-11-27 11:40:03 +01:00
}
2011-10-03 11:55:32 +02:00
$process_dialog -> Destroy ;
2011-10-03 17:41:45 +02:00
undef $process_dialog ;
2011-10-03 11:55:32 +02:00
2012-03-26 17:57:54 +02:00
my $message = "$input_file_basename was successfully sliced" ;
$message .= sprintf " in %d minutes and %.3f seconds" ,
2012-04-30 14:56:01 +02:00
int ( $print -> processing_time / 60 ),
$print -> processing_time - int ( $print -> processing_time / 60 ) * 60
if $print -> processing_time ;
2012-03-26 17:57:54 +02:00
$message .= "." ;
2012-06-14 13:49:50 +02:00
Slic3r::GUI:: notify ( $message );
2012-02-16 22:52:57 +01:00
Wx::MessageDialog -> new ( $self , $message , 'Done!' ,
wxOK | wxICON_INFORMATION ) -> ShowModal ;
2011-10-03 11:55:32 +02:00
};
2012-04-30 14:56:01 +02:00
Slic3r::GUI:: catch_error ( $self , sub { $process_dialog -> Destroy if $process_dialog });
2011-10-05 18:13:47 +02:00
}
sub save_config {
my $self = shift ;
2011-10-03 11:55:32 +02:00
2012-02-06 16:52:11 +01:00
my $process_dialog ;
eval {
# validate configuration
Slic3r::Config -> validate ;
};
2012-04-30 14:56:01 +02:00
Slic3r::GUI:: catch_error ( $self , sub { $process_dialog -> Destroy if $process_dialog }) and return ;
2012-02-06 16:52:11 +01:00
2012-02-03 20:22:45 +01:00
my $dir = $last_config ? dirname ( $last_config ) : $last_config_dir || $last_skein_dir || "" ;
2011-12-26 19:06:57 +01:00
my $filename = $last_config ? basename ( $last_config ) : "config.ini" ;
my $dlg = Wx::FileDialog -> new ( $self , 'Save configuration as:' , $dir , $filename ,
2012-05-30 11:55:46 +02:00
$ini_wildcard , wxFD_SAVE | & Wx:: wxFD_OVERWRITE_PROMPT );
2011-10-05 18:13:47 +02:00
if ( $dlg -> ShowModal == wxID_OK ) {
2011-12-09 14:07:50 +01:00
my $file = $dlg -> GetPath ;
2012-02-03 19:57:49 +01:00
$last_config_dir = dirname ( $file );
2011-12-26 19:06:57 +01:00
$last_config = $file ;
2011-12-09 14:07:50 +01:00
Slic3r::Config -> save ( $file );
2011-10-05 18:13:47 +02:00
}
2012-04-18 17:16:01 +03:00
$dlg -> Destroy ;
2011-10-05 18:13:47 +02:00
}
sub load_config {
my $self = shift ;
2012-02-03 20:22:45 +01:00
my $dir = $last_config ? dirname ( $last_config ) : $last_config_dir || $last_skein_dir || "" ;
2012-02-03 19:57:49 +01:00
my $dlg = Wx::FileDialog -> new ( $self , 'Select configuration to load:' , $dir , "config.ini" ,
2012-05-31 09:26:30 +02:00
$ini_wildcard , wxFD_OPEN | & Wx:: wxFD_FILE_MUST_EXIST );
2011-10-05 18:13:47 +02:00
if ( $dlg -> ShowModal == wxID_OK ) {
my ( $file ) = $dlg -> GetPaths ;
2012-02-03 19:57:49 +01:00
$last_config_dir = dirname ( $file );
2011-12-26 19:06:57 +01:00
$last_config = $file ;
2011-10-05 18:13:47 +02:00
eval {
2012-04-30 14:56:01 +02:00
local $SIG { __WARN__ } = Slic3r::GUI:: warning_catcher ( $self );
2011-10-05 18:13:47 +02:00
Slic3r::Config -> load ( $file );
};
2012-05-01 11:46:17 +02:00
Slic3r::GUI:: catch_error ( $self );
2011-10-05 18:13:47 +02:00
$_ -> () for @ Slic3r::GUI::OptionsGroup:: reload_callbacks ;
}
2012-04-18 17:16:01 +03:00
$dlg -> Destroy ;
2011-10-05 18:13:47 +02:00
}
2011-10-03 11:55:32 +02:00
1 ;