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-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-02-03 19:57:49 +01:00
my $last_skein_dir ;
my $last_config_dir ;
2012-03-12 19:52:23 +02:00
my $last_input_file ;
my $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 );
my %panels = (
2011-11-13 22:22:34 +01:00
printer => {
2011-10-03 11:55:32 +02:00
title => 'Printer' ,
2012-03-03 21:37:10 +01:00
options => [ qw(nozzle_diameter 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-03-03 23:14:40 +01:00
options => [ qw(filament_diameter extrusion_multiplier temperature first_layer_temperature 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' ,
2011-12-04 20:50:03 +01:00
options => [ qw(perimeter_speed small_perimeter_speed infill_speed 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' ,
2011-12-01 22:03:13 +01:00
options => [ qw(travel_speed bottom_layer_speed_ratio) ],
2011-11-13 22:22:34 +01:00
},
accuracy => {
2011-10-03 11:55:32 +02:00
title => 'Accuracy' ,
2011-12-04 19:17:42 +01:00
options => [ qw(layer_height first_layer_height_ratio infill_every_layers) ],
2011-11-13 22:22:34 +01:00
},
print => {
2011-10-03 11:55:32 +02:00
title => 'Print settings' ,
2012-02-19 17:02:49 +01:00
options => [ qw(perimeters solid_layers fill_density fill_angle fill_pattern solid_fill_pattern support_material support_material_tool) ],
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-02-25 21:01:00 +01:00
label_width => 300 ,
},
2011-11-13 22:22:34 +01:00
skirt => {
2011-10-03 11:55:32 +02:00
title => 'Skirt' ,
2011-11-13 18:41:12 +01:00
options => [ qw(skirts skirt_distance skirt_height) ],
2011-11-13 22:22:34 +01:00
},
transform => {
2011-10-03 11:55:32 +02:00
title => 'Transform' ,
2012-03-06 14:55:21 +11:00
options => [ qw(scale rotate duplicate duplicate_x duplicate_y duplicate_distance) ],
2011-11-13 22:22:34 +01:00
},
2011-11-13 22:48:21 +01:00
gcode => {
2012-03-26 22:33:43 +02:00
title => 'Custom G-code' ,
2012-03-26 12:14:15 +02:00
options => [ qw(start_gcode end_gcode layer_gcode gcode_comments post_process) ],
2011-11-13 22:48:21 +01:00
},
2011-11-25 10:58:13 +01:00
extrusion => {
title => 'Extrusion' ,
2012-01-30 14:51:05 +01:00
options => [ qw(extrusion_width_ratio bridge_flow_ratio) ],
2011-11-25 10:58:13 +01:00
},
2011-12-26 04:20:45 -05:00
output => {
title => 'Output' ,
options => [ qw(output_filename_format) ],
},
2012-02-05 20:55:17 +01:00
notes => {
title => 'Notes' ,
options => [ qw(notes) ],
},
2011-10-03 11:55:32 +02:00
);
2011-10-05 18:13:47 +02:00
$self -> { panels } = \ %panels ;
2012-02-03 00:30:35 +01:00
if ( eval "use Growl::GNTP; 1" ) {
# register growl notifications
2012-02-26 19:29:25 +01:00
eval {
2012-04-07 20:45:02 +02:00
$self -> { growler } = Growl::GNTP -> new ( AppName => 'Slic3r' , AppIcon => "$FindBin::Bin/var/icon.png" );
2012-02-26 19:29:25 +01:00
$self -> { growler } -> register ([{ Name => 'SKEIN_DONE' , DisplayName => 'Slicing Done' }]);
};
2012-02-03 00:30:35 +01:00
}
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 ) {
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 = (
$make_tab -> ([ qw(transform accuracy skirt) ], [ qw(print retract) ]),
2012-02-25 21:01:00 +01:00
$make_tab -> ([ qw(cooling) ]),
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-03-03 22:50:08 +01:00
$make_tab -> ([ qw(notes) ]),
$make_tab -> ([ qw(extrusion) ], [ qw(output) ]),
2011-11-25 10:58:13 +01:00
);
2011-10-03 11:55:32 +02:00
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-03-26 22:33:43 +02:00
$tabpanel -> AddPage ( $tabs [ 3 ], "Custom G-code" );
2012-03-03 22:50:08 +01:00
$tabpanel -> AddPage ( $tabs [ 4 ], "Notes" );
$tabpanel -> AddPage ( $tabs [ 5 ], "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-03-03 22:50:08 +01:00
my $slice_button = Wx::Button -> new ( $self , - 1 , "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-03-03 22:50:08 +01:00
$buttons_sizer -> Add ( $save_button , 0 );
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-03-03 22:50:08 +01:00
$buttons_sizer -> Add ( $load_button , 0 );
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
return $self ;
}
2012-02-19 15:14:54 +01:00
my $model_wildcard = "STL files (*.stl)|*.stl;*.STL|AMF files (*.amf)|*.amf;*.AMF;*.xml;*.XML" ;
2011-12-22 17:38:37 +01:00
my $ini_wildcard = "INI files *.ini|*.ini;*.INI" ;
2012-03-26 22:33:43 +02:00
my $gcode_wildcard = "G-code files *.gcode|*.gcode;*.GCODE" ;
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
my $copies = Slic3r::Config -> get ( 'duplicate_x' ) * Slic3r::Config -> get ( 'duplicate_y' );
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 }) {
my $dialog = Wx::FileDialog -> new ( $self , 'Choose a STL or AMF file to slice:' , $dir , "" , $model_wildcard , wxFD_OPEN );
return unless $dialog -> ShowModal == wxID_OK ;
$input_file = $dialog -> GetPaths ;
$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
my $skein = Slic3r::Skein -> new (
input_file => $input_file ,
2011-12-26 17:20:26 +01:00
output_file => $ main:: opt { output },
2011-11-26 16:19:30 +01:00
status_cb => sub {
my ( $percent , $message ) = @_ ;
2011-11-26 16:52:10 +01:00
if ( & Wx:: wxVERSION_STRING =~ / 2\.(8\.|9\.[2-9])/ ) {
2012-02-20 12:50:05 +01:00
$process_dialog -> Update ( $percent , "$message..." );
2011-11-26 16:52:10 +01:00
}
2011-11-26 16:19:30 +01:00
},
2011-10-03 11:55:32 +02:00
);
2011-12-26 04:20:45 -05:00
# select output file
2012-03-12 19:52:23 +02:00
if ( $params { reslice }) {
if ( defined $last_output_file ) {
$skein -> output_file ( $last_output_file );
}
} elsif ( $params { save_as }) {
2011-12-26 17:20:26 +01:00
my $output_file = $skein -> expanded_output_filepath ;
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 ),
2011-12-26 04:20:45 -05:00
basename ( $output_file ), $gcode_wildcard , wxFD_SAVE );
return if $dlg -> ShowModal != wxID_OK ;
$skein -> output_file ( $dlg -> GetPath );
2012-03-12 19:52:23 +02:00
$last_output_file = $dlg -> GetPath ;
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-03-26 17:57:54 +02:00
if ( $params { export_svg }) {
$skein -> export_svg ;
} else {
$skein -> go ;
}
2011-12-18 13:43:31 +01:00
$self -> catch_warning -> ( $_ ) 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" ,
int ( $skein -> processing_time / 60 ),
$skein -> processing_time - int ( $skein -> processing_time / 60 ) * 60
if $skein -> processing_time ;
$message .= "." ;
2012-02-26 19:44:07 +01:00
eval {
$self -> { growler } -> notify ( Event => 'SKEIN_DONE' , Title => 'Slicing Done!' , Message => $message )
if ( $self -> { growler });
};
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
};
2011-10-05 18:13:47 +02:00
$self -> catch_error ( sub { $process_dialog -> Destroy if $process_dialog });
}
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 ;
};
$self -> catch_error ( sub { $process_dialog -> Destroy if $process_dialog }) and return ;
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 ,
2011-10-05 18:13:47 +02:00
$ini_wildcard , wxFD_SAVE );
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
}
}
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" ,
2011-10-05 18:13:47 +02:00
$ini_wildcard , wxFD_OPEN );
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 {
2011-12-10 10:39:07 +01:00
local $SIG { __WARN__ } = $self -> catch_warning ;
2011-10-05 18:13:47 +02:00
Slic3r::Config -> load ( $file );
};
$self -> catch_error ();
$_ -> () for @ Slic3r::GUI::OptionsGroup:: reload_callbacks ;
}
}
sub catch_error {
my ( $self , $cb ) = @_ ;
2011-10-03 11:55:32 +02:00
if ( my $err = $@ ) {
2011-10-05 18:13:47 +02:00
$cb -> () if $cb ;
2011-10-03 11:55:32 +02:00
Wx::MessageDialog -> new ( $self , $err , 'Error' , wxOK | wxICON_ERROR ) -> ShowModal ;
2012-02-06 16:52:11 +01:00
return 1 ;
2011-10-03 11:55:32 +02:00
}
2012-02-06 16:52:11 +01:00
return 0 ;
2011-10-03 11:55:32 +02:00
}
2011-12-10 10:39:07 +01:00
sub catch_warning {
my ( $self ) = @_ ;
return sub {
my $message = shift ;
Wx::MessageDialog -> new ( $self , $message , 'Warning' , wxOK | wxICON_WARNING ) -> ShowModal ;
};
};
2011-10-03 11:55:32 +02:00
1 ;