2016-09-14 09:22:41 +00:00
# The main frame, the parent of all.
2014-06-14 17:11:04 +00:00
package Slic3r::GUI::MainFrame ;
use strict ;
use warnings ;
use utf8 ;
2014-06-27 15:21:41 +00:00
use File::Basename qw( basename dirname ) ;
2014-06-14 17:54:18 +00:00
use List::Util qw( min ) ;
2017-07-21 14:29:40 +00:00
use Slic3r::Geometry qw( X Y ) ;
2014-06-14 17:54:18 +00:00
use Wx qw( :frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog
2014-06-14 17:59:59 +00:00
: font : icon wxTheApp ) ;
2015-11-03 20:55:17 +00:00
use Wx::Event qw( EVT_CLOSE EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED ) ;
2014-06-14 17:11:04 +00:00
use base 'Wx::Frame' ;
2015-06-02 20:27:11 +00:00
our $ qs_last_input_file ;
our $ qs_last_output_file ;
2014-06-14 17:54:18 +00:00
our $ last_config ;
2014-06-14 17:11:04 +00:00
sub new {
my ( $ class , % params ) = @ _ ;
2016-10-21 14:53:42 +00:00
my $ self = $ class - > SUPER:: new ( undef , - 1 , $ Slic3r:: FORK_NAME . ' - ' . $ Slic3r:: VERSION , wxDefaultPosition , wxDefaultSize , wxDEFAULT_FRAME_STYLE ) ;
2016-10-24 16:05:26 +00:00
if ( $^O eq 'MSWin32' ) {
2016-11-20 13:22:26 +00:00
# Load the icon either from the exe, or fron the ico file.
my $ iconfile = $ Slic3r:: var - > ( '..\slic3r.exe' ) ;
$ iconfile = $ Slic3r:: var - > ( "Slic3r.ico" ) unless - f $ iconfile ;
$ self - > SetIcon ( Wx::Icon - > new ( $ iconfile , wxBITMAP_TYPE_ICO ) ) ;
2016-10-24 16:05:26 +00:00
} else {
$ self - > SetIcon ( Wx::Icon - > new ( $ Slic3r:: var - > ( "Slic3r_128px.png" ) , wxBITMAP_TYPE_PNG ) ) ;
}
2014-06-14 17:11:04 +00:00
2014-06-14 17:54:18 +00:00
# store input params
2016-05-16 21:40:24 +00:00
# If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
$ self - > { no_controller } = $ params { no_controller } ;
2014-06-14 17:54:18 +00:00
$ self - > { no_plater } = $ params { no_plater } ;
$ self - > { loaded } = 0 ;
# initialize tabpanel and menubar
$ self - > _init_tabpanel ;
$ self - > _init_menubar ;
2016-11-30 10:45:31 +00:00
# set default tooltip timer in msec
# SetAutoPop supposedly accepts long integers but some bug doesn't allow for larger values
# (SetAutoPop is not available on GTK.)
eval { Wx::ToolTip:: SetAutoPop ( 32767 ) } ;
2014-06-14 17:54:18 +00:00
# initialize status bar
2014-06-14 17:11:04 +00:00
$ self - > { statusbar } = Slic3r::GUI::ProgressStatusBar - > new ( $ self , - 1 ) ;
2016-10-21 14:53:42 +00:00
$ self - > { statusbar } - > SetStatusText ( "Version $Slic3r::VERSION - Remember to check for updates at http://github.com/prusa3d/slic3r/releases" ) ;
2014-06-14 17:11:04 +00:00
$ self - > SetStatusBar ( $ self - > { statusbar } ) ;
2014-06-14 17:54:18 +00:00
$ self - > { loaded } = 1 ;
# initialize layout
{
my $ sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ sizer - > Add ( $ self - > { tabpanel } , 1 , wxEXPAND ) ;
$ sizer - > SetSizeHints ( $ self ) ;
$ self - > SetSizer ( $ sizer ) ;
$ self - > Fit ;
2014-07-04 08:32:32 +00:00
$ self - > SetMinSize ( [ 760 , 490 ] ) ;
2017-08-04 13:54:12 +00:00
$ self - > SetSize ( $ self - > GetMinSize ) ;
wxTheApp - > restore_window_pos ( $ self , "main_frame" ) ;
2014-06-14 17:54:18 +00:00
$ self - > Show ;
$ self - > Layout ;
}
2014-12-08 21:05:26 +00:00
# declare events
EVT_CLOSE ( $ self , sub {
my ( undef , $ event ) = @ _ ;
if ( $ event - > CanVeto && ! $ self - > check_unsaved_changes ) {
$ event - > Veto ;
return ;
}
# save window size
2017-08-04 13:54:12 +00:00
wxTheApp - > save_window_pos ( $ self , "main_frame" ) ;
2014-12-08 21:05:26 +00:00
# propagate event
$ event - > Skip ;
} ) ;
2016-10-25 11:24:42 +00:00
$ self - > update_ui_from_settings ;
2014-12-08 21:05:26 +00:00
2014-06-14 17:54:18 +00:00
return $ self ;
}
sub _init_tabpanel {
my ( $ self ) = @ _ ;
$ self - > { tabpanel } = my $ panel = Wx::Notebook - > new ( $ self , - 1 , wxDefaultPosition , wxDefaultSize , wxNB_TOP | wxTAB_TRAVERSAL ) ;
2015-11-03 20:55:17 +00:00
EVT_NOTEBOOK_PAGE_CHANGED ( $ self , $ self - > { tabpanel } , sub {
my $ panel = $ self - > { tabpanel } - > GetCurrentPage ;
$ panel - > OnActivate if $ panel - > can ( 'OnActivate' ) ;
} ) ;
2014-06-14 17:54:18 +00:00
2014-07-01 14:40:56 +00:00
if ( ! $ self - > { no_plater } ) {
$ panel - > AddPage ( $ self - > { plater } = Slic3r::GUI::Plater - > new ( $ panel ) , "Plater" ) ;
2016-05-16 21:40:24 +00:00
if ( ! $ self - > { no_controller } ) {
$ panel - > AddPage ( $ self - > { controller } = Slic3r::GUI::Controller - > new ( $ panel ) , "Controller" ) ;
}
2014-07-01 14:40:56 +00:00
}
2014-06-14 17:54:18 +00:00
$ self - > { options_tabs } = { } ;
for my $ tab_name ( qw( print filament printer ) ) {
my $ tab ;
2017-06-14 09:48:08 +00:00
$ tab = $ self - > { options_tabs } { $ tab_name } = ( "Slic3r::GUI::Tab::" . ucfirst $ tab_name ) - > new (
2016-05-16 21:40:24 +00:00
$ panel ,
no_controller = > $ self - > { no_controller } ) ;
2017-02-07 17:28:53 +00:00
# Callback to be executed after any of the configuration fields (Perl class Slic3r::GUI::OptionsGroup::Field) change their value.
2014-07-01 14:40:56 +00:00
$ tab - > on_value_change ( sub {
2017-05-31 15:05:11 +00:00
my ( $ opt_key , $ value ) = @ _ ;
2014-07-01 14:40:56 +00:00
my $ config = $ tab - > config ;
2014-09-21 13:29:52 +00:00
if ( $ self - > { plater } ) {
$ self - > { plater } - > on_config_change ( $ config ) ; # propagate config change events to the plater
$ self - > { plater } - > on_extruders_change ( $ value ) if $ opt_key eq 'extruders_count' ;
}
2017-06-14 09:48:08 +00:00
# don't save while loading for the first time
$ self - > config - > save ( $ Slic3r:: GUI:: autosave ) if $ Slic3r:: GUI:: autosave && $ self - > { loaded } ;
2014-07-01 14:40:56 +00:00
} ) ;
2016-10-24 14:07:36 +00:00
# Install a callback for the tab to update the platter and print controller presets, when
# a preset changes at Slic3r::GUI::Tab.
2014-07-01 14:40:56 +00:00
$ tab - > on_presets_changed ( sub {
if ( $ self - > { plater } ) {
2017-02-07 17:28:53 +00:00
# Update preset combo boxes (Print settings, Filament, Printer) from their respective tabs.
2014-07-01 14:40:56 +00:00
$ self - > { plater } - > update_presets ( $ tab_name , @ _ ) ;
$ self - > { plater } - > on_config_change ( $ tab - > config ) ;
2016-05-16 21:40:24 +00:00
if ( $ self - > { controller } ) {
$ self - > { controller } - > update_presets ( $ tab_name , @ _ ) ;
}
2014-07-01 14:40:56 +00:00
}
} ) ;
$ tab - > load_presets ;
2014-06-14 17:54:18 +00:00
$ panel - > AddPage ( $ tab , $ tab - > title ) ;
}
2014-07-01 14:40:56 +00:00
if ( $ self - > { plater } ) {
$ self - > { plater } - > on_select_preset ( sub {
2015-05-26 00:01:43 +00:00
my ( $ group , $ i ) = @ _ ;
$ self - > { options_tabs } { $ group } - > select_preset ( $ i ) ;
2014-07-01 14:40:56 +00:00
} ) ;
# load initial config
$ self - > { plater } - > on_config_change ( $ self - > config ) ;
}
2014-06-14 17:54:18 +00:00
}
sub _init_menubar {
my ( $ self ) = @ _ ;
2014-06-14 17:11:04 +00:00
# File menu
my $ fileMenu = Wx::Menu - > new ;
{
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ fileMenu , "&Load Config…\tCtrl+L" , 'Load exported configuration file' , sub {
$ self - > load_config_file ;
2015-05-25 20:37:04 +00:00
} , undef , 'plugin_add.png' ) ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ fileMenu , "&Export Config…\tCtrl+E" , 'Export current configuration to file' , sub {
$ self - > export_config ;
2015-05-25 20:37:04 +00:00
} , undef , 'plugin_go.png' ) ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ fileMenu , "&Load Config Bundle…" , 'Load presets from a bundle' , sub {
$ self - > load_configbundle ;
2015-05-25 20:37:04 +00:00
} , undef , 'lorry_add.png' ) ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ fileMenu , "&Export Config Bundle…" , 'Export all presets to file' , sub {
$ self - > export_configbundle ;
2015-05-25 20:37:04 +00:00
} , undef , 'lorry_go.png' ) ;
2014-06-14 17:11:04 +00:00
$ fileMenu - > AppendSeparator ( ) ;
2014-06-14 18:26:46 +00:00
my $ repeat ;
2017-06-14 10:52:50 +00:00
$ self - > _append_menu_item ( $ fileMenu , "Q&uick Slice…\tCtrl+U" , 'Slice a file into a G-code' , sub {
2015-05-05 22:39:16 +00:00
wxTheApp - > CallAfter ( sub {
$ self - > quick_slice ;
$ repeat - > Enable ( defined $ Slic3r:: GUI:: MainFrame:: last_input_file ) ;
} ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'cog_go.png' ) ;
2017-06-14 10:52:50 +00:00
$ self - > _append_menu_item ( $ fileMenu , "Quick Slice and Save &As…\tCtrl+Alt+U" , 'Slice a file into a G-code, save as' , sub {
2015-05-05 22:39:16 +00:00
wxTheApp - > CallAfter ( sub {
$ self - > quick_slice ( save_as = > 1 ) ;
$ repeat - > Enable ( defined $ Slic3r:: GUI:: MainFrame:: last_input_file ) ;
} ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'cog_go.png' ) ;
2014-06-14 18:26:46 +00:00
$ repeat = $ self - > _append_menu_item ( $ fileMenu , "&Repeat Last Quick Slice\tCtrl+Shift+U" , 'Repeat last quick slice' , sub {
2015-05-05 22:39:16 +00:00
wxTheApp - > CallAfter ( sub {
$ self - > quick_slice ( reslice = > 1 ) ;
} ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'cog_go.png' ) ;
2014-06-14 17:11:04 +00:00
$ repeat - > Enable ( 0 ) ;
$ fileMenu - > AppendSeparator ( ) ;
2017-06-14 10:52:50 +00:00
$ self - > _append_menu_item ( $ fileMenu , "Slice to SV&G…\tCtrl+G" , 'Slice file to a multi-layer SVG' , sub {
2014-06-14 18:26:46 +00:00
$ self - > quick_slice ( save_as = > 1 , export_svg = > 1 ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'shape_handles.png' ) ;
2016-10-25 11:24:42 +00:00
$ self - > { menu_item_reslice_now } = $ self - > _append_menu_item (
$ fileMenu , "(&Re)Slice Now\tCtrl+S" , 'Start new slicing process' ,
sub { $ self - > reslice_now ; } , undef , 'shape_handles.png' ) ;
2014-06-14 17:11:04 +00:00
$ fileMenu - > AppendSeparator ( ) ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ fileMenu , "Repair STL file…" , 'Automatically repair an STL file' , sub {
$ self - > repair_stl ;
2015-05-25 20:37:04 +00:00
} , undef , 'wrench.png' ) ;
2014-06-14 17:11:04 +00:00
$ fileMenu - > AppendSeparator ( ) ;
2015-05-31 20:35:52 +00:00
# Cmd+, is standard on OS X - what about other operating systems?
2015-05-31 20:33:46 +00:00
$ self - > _append_menu_item ( $ fileMenu , "Preferences…\tCtrl+," , 'Application preferences' , sub {
2014-06-14 18:26:46 +00:00
Slic3r::GUI::Preferences - > new ( $ self ) - > ShowModal ;
2014-07-01 14:40:56 +00:00
} , wxID_PREFERENCES ) ;
2014-06-14 17:11:04 +00:00
$ fileMenu - > AppendSeparator ( ) ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ fileMenu , "&Quit" , 'Quit Slic3r' , sub {
$ self - > Close ( 0 ) ;
2014-07-01 14:40:56 +00:00
} , wxID_EXIT ) ;
2014-06-14 17:11:04 +00:00
}
# Plater menu
2014-06-14 17:54:18 +00:00
unless ( $ self - > { no_plater } ) {
my $ plater = $ self - > { plater } ;
2014-06-14 17:11:04 +00:00
$ self - > { plater_menu } = Wx::Menu - > new ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ self - > { plater_menu } , "Export G-code..." , 'Export current plate as G-code' , sub {
$ plater - > export_gcode ;
2015-05-25 20:37:04 +00:00
} , undef , 'cog_go.png' ) ;
2015-01-03 14:48:53 +00:00
$ self - > _append_menu_item ( $ self - > { plater_menu } , "Export plate as STL..." , 'Export current plate as STL' , sub {
2014-06-14 18:26:46 +00:00
$ plater - > export_stl ;
2015-05-25 20:37:04 +00:00
} , undef , 'brick_go.png' ) ;
2015-01-03 14:48:53 +00:00
$ self - > _append_menu_item ( $ self - > { plater_menu } , "Export plate as AMF..." , 'Export current plate as AMF' , sub {
2014-06-14 18:26:46 +00:00
$ plater - > export_amf ;
2015-05-25 20:37:04 +00:00
} , undef , 'brick_go.png' ) ;
2014-06-14 17:11:04 +00:00
2014-06-14 19:36:28 +00:00
$ self - > { object_menu } = $ self - > { plater } - > object_menu ;
2014-06-14 17:11:04 +00:00
$ self - > on_plater_selection_changed ( 0 ) ;
}
# Window menu
my $ windowMenu = Wx::Menu - > new ;
{
2015-01-04 22:18:23 +00:00
my $ tab_offset = 0 ;
if ( ! $ self - > { no_plater } ) {
$ self - > _append_menu_item ( $ windowMenu , "Select &Plater Tab\tCtrl+1" , 'Show the plater' , sub {
$ self - > select_tab ( 0 ) ;
2015-05-28 16:05:36 +00:00
} , undef , 'application_view_tile.png' ) ;
2017-03-23 17:02:35 +00:00
$ tab_offset += 1 ;
}
if ( ! $ self - > { no_controller } ) {
$ self - > _append_menu_item ( $ windowMenu , "Select &Controller Tab\tCtrl+T" , 'Show the printer controller' , sub {
$ self - > select_tab ( 1 ) ;
} , undef , 'printer_empty.png' ) ;
$ tab_offset += 1 ;
}
if ( $ tab_offset > 0 ) {
2015-01-04 22:18:23 +00:00
$ windowMenu - > AppendSeparator ( ) ;
}
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ windowMenu , "Select P&rint Settings Tab\tCtrl+2" , 'Show the print settings' , sub {
2015-01-04 22:18:23 +00:00
$ self - > select_tab ( $ tab_offset + 0 ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'cog.png' ) ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ windowMenu , "Select &Filament Settings Tab\tCtrl+3" , 'Show the filament settings' , sub {
2015-01-04 22:18:23 +00:00
$ self - > select_tab ( $ tab_offset + 1 ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'spool.png' ) ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ windowMenu , "Select Print&er Settings Tab\tCtrl+4" , 'Show the printer settings' , sub {
2015-01-04 22:18:23 +00:00
$ self - > select_tab ( $ tab_offset + 2 ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'printer_empty.png' ) ;
2014-06-14 17:11:04 +00:00
}
2016-10-05 12:13:07 +00:00
# View menu
if ( ! $ self - > { no_plater } ) {
$ self - > { viewMenu } = Wx::Menu - > new ;
2017-07-21 14:29:40 +00:00
# \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators,
# as the simple numeric accelerators spoil all numeric data entry.
# The camera control accelerators are captured by 3DScene Perl module instead.
$ self - > _append_menu_item ( $ self - > { viewMenu } , "Iso\t\xA00" , 'Iso View' , sub { $ self - > select_view ( 'iso' ) ; } ) ;
$ self - > _append_menu_item ( $ self - > { viewMenu } , "Top\t\xA01" , 'Top View' , sub { $ self - > select_view ( 'top' ) ; } ) ;
$ self - > _append_menu_item ( $ self - > { viewMenu } , "Bottom\t\xA02" , 'Bottom View' , sub { $ self - > select_view ( 'bottom' ) ; } ) ;
$ self - > _append_menu_item ( $ self - > { viewMenu } , "Front\t\xA03" , 'Front View' , sub { $ self - > select_view ( 'front' ) ; } ) ;
$ self - > _append_menu_item ( $ self - > { viewMenu } , "Rear\t\xA04" , 'Rear View' , sub { $ self - > select_view ( 'rear' ) ; } ) ;
$ self - > _append_menu_item ( $ self - > { viewMenu } , "Left\t\xA05" , 'Left View' , sub { $ self - > select_view ( 'left' ) ; } ) ;
$ self - > _append_menu_item ( $ self - > { viewMenu } , "Right\t\xA06" , 'Right View' , sub { $ self - > select_view ( 'right' ) ; } ) ;
2016-10-05 12:13:07 +00:00
}
2014-06-14 17:11:04 +00:00
# Help menu
my $ helpMenu = Wx::Menu - > new ;
{
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ helpMenu , "&Configuration $Slic3r::GUI::ConfigWizard::wizard…" , "Run Configuration $Slic3r::GUI::ConfigWizard::wizard" , sub {
$ self - > config_wizard ;
} ) ;
2014-06-14 17:11:04 +00:00
$ helpMenu - > AppendSeparator ( ) ;
2016-10-21 14:53:42 +00:00
$ self - > _append_menu_item ( $ helpMenu , "Prusa 3D Drivers" , 'Open the Prusa3D drivers download page in your browser' , sub {
Wx:: LaunchDefaultBrowser ( 'http://www.prusa3d.com/drivers/' ) ;
} ) ;
$ self - > _append_menu_item ( $ helpMenu , "Prusa Edition Releases" , 'Open the Prusa Edition releases page in your browser' , sub {
Wx:: LaunchDefaultBrowser ( 'http://github.com/prusa3d/slic3r/releases' ) ;
} ) ;
# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub {
# wxTheApp->check_version(1);
# });
# $versioncheck->Enable(wxTheApp->have_version_check);
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ helpMenu , "Slic3r &Website" , 'Open the Slic3r website in your browser' , sub {
Wx:: LaunchDefaultBrowser ( 'http://slic3r.org/' ) ;
} ) ;
$ self - > _append_menu_item ( $ helpMenu , "Slic3r &Manual" , 'Open the Slic3r manual in your browser' , sub {
Wx:: LaunchDefaultBrowser ( 'http://manual.slic3r.org/' ) ;
} ) ;
2014-06-14 17:11:04 +00:00
$ helpMenu - > AppendSeparator ( ) ;
2017-02-19 15:04:57 +00:00
$ self - > _append_menu_item ( $ helpMenu , "System Info" , 'Show system information' , sub {
wxTheApp - > system_info ;
} ) ;
$ self - > _append_menu_item ( $ helpMenu , "Report an Issue" , 'Report an issue on the Slic3r Prusa Edition' , sub {
Wx:: LaunchDefaultBrowser ( 'http://github.com/prusa3d/slic3r/issues/new' ) ;
} ) ;
2014-06-14 18:26:46 +00:00
$ self - > _append_menu_item ( $ helpMenu , "&About Slic3r" , 'Show about dialog' , sub {
wxTheApp - > about ;
} ) ;
2014-06-14 17:11:04 +00:00
}
2016-09-12 11:26:17 +00:00
2014-06-14 17:11:04 +00:00
# menubar
# assign menubar to frame after appending items, otherwise special items
# will not be handled correctly
{
my $ menubar = Wx::MenuBar - > new ;
$ menubar - > Append ( $ fileMenu , "&File" ) ;
$ menubar - > Append ( $ self - > { plater_menu } , "&Plater" ) if $ self - > { plater_menu } ;
$ menubar - > Append ( $ self - > { object_menu } , "&Object" ) if $ self - > { object_menu } ;
$ menubar - > Append ( $ windowMenu , "&Window" ) ;
2016-10-05 12:13:07 +00:00
$ menubar - > Append ( $ self - > { viewMenu } , "&View" ) if $ self - > { viewMenu } ;
2014-06-14 17:11:04 +00:00
$ menubar - > Append ( $ helpMenu , "&Help" ) ;
$ self - > SetMenuBar ( $ menubar ) ;
}
2014-06-14 17:54:18 +00:00
}
sub is_loaded {
my ( $ self ) = @ _ ;
return $ self - > { loaded } ;
2014-06-14 17:11:04 +00:00
}
sub on_plater_selection_changed {
my ( $ self , $ have_selection ) = @ _ ;
return if ! defined $ self - > { object_menu } ;
$ self - > { object_menu } - > Enable ( $ _ - > GetId , $ have_selection )
for $ self - > { object_menu } - > GetMenuItems ;
}
2017-06-14 10:52:50 +00:00
# To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".
2014-06-14 17:54:18 +00:00
sub quick_slice {
my $ self = shift ;
my % params = @ _ ;
my $ progress_dialog ;
eval {
# validate configuration
my $ config = $ self - > config ;
$ config - > validate ;
# select input file
my $ input_file ;
my $ dir = $ Slic3r:: GUI:: Settings - > { recent } { skein_directory } || $ Slic3r:: GUI:: Settings - > { recent } { config_directory } || '' ;
if ( ! $ params { reslice } ) {
2017-04-05 12:45:43 +00:00
my $ dialog = Wx::FileDialog - > new ( $ self , 'Choose a file to slice (STL/OBJ/AMF/PRUSA):' , $ dir , "" , & Slic3r::GUI:: MODEL_WILDCARD , wxFD_OPEN | wxFD_FILE_MUST_EXIST ) ;
2014-06-14 17:54:18 +00:00
if ( $ dialog - > ShowModal != wxID_OK ) {
$ dialog - > Destroy ;
return ;
}
2017-08-03 15:31:31 +00:00
$ input_file = $ dialog - > GetPaths ;
2014-06-14 17:54:18 +00:00
$ dialog - > Destroy ;
2015-06-02 20:27:11 +00:00
$ qs_last_input_file = $ input_file unless $ params { export_svg } ;
2014-06-14 17:54:18 +00:00
} else {
2015-06-02 20:27:11 +00:00
if ( ! defined $ qs_last_input_file ) {
2014-06-14 17:54:18 +00:00
Wx::MessageDialog - > new ( $ self , "No previously sliced file." ,
'Error' , wxICON_ERROR | wxOK ) - > ShowModal ( ) ;
return ;
}
2015-06-02 20:27:11 +00:00
if ( ! - e $ qs_last_input_file ) {
Wx::MessageDialog - > new ( $ self , "Previously sliced file ($qs_last_input_file) not found." ,
2014-06-14 17:54:18 +00:00
'File Not Found' , wxICON_ERROR | wxOK ) - > ShowModal ( ) ;
return ;
}
2015-06-02 20:27:11 +00:00
$ input_file = $ qs_last_input_file ;
2014-06-14 17:54:18 +00:00
}
my $ input_file_basename = basename ( $ input_file ) ;
$ Slic3r:: GUI:: Settings - > { recent } { skein_directory } = dirname ( $ input_file ) ;
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2014-06-14 17:54:18 +00:00
2014-12-21 22:29:31 +00:00
my $ print_center ;
{
my $ bed_shape = Slic3r::Polygon - > new_scale ( @ { $ config - > bed_shape } ) ;
$ print_center = Slic3r::Pointf - > new_unscale ( @ { $ bed_shape - > bounding_box - > center } ) ;
}
2014-06-14 17:54:18 +00:00
my $ sprint = Slic3r::Print::Simple - > new (
2014-12-21 22:29:31 +00:00
print_center = > $ print_center ,
2014-06-14 17:54:18 +00:00
status_cb = > sub {
my ( $ percent , $ message ) = @ _ ;
$ progress_dialog - > Update ( $ percent , "$message…" ) ;
} ,
) ;
2014-06-27 15:21:41 +00:00
# keep model around
my $ model = Slic3r::Model - > read_from_file ( $ input_file ) ;
2014-06-14 17:54:18 +00:00
$ sprint - > apply_config ( $ config ) ;
2014-06-27 15:21:41 +00:00
$ sprint - > set_model ( $ model ) ;
2014-06-14 17:54:18 +00:00
{
my $ extra = $ self - > extra_variables ;
$ sprint - > placeholder_parser - > set ( $ _ , $ extra - > { $ _ } ) for keys %$ extra ;
}
# select output file
my $ output_file ;
if ( $ params { reslice } ) {
2015-06-02 20:27:11 +00:00
$ output_file = $ qs_last_output_file if defined $ qs_last_output_file ;
2014-06-14 17:54:18 +00:00
} elsif ( $ params { save_as } ) {
2016-12-20 18:01:51 +00:00
$ output_file = $ sprint - > output_filepath ;
2017-07-11 15:15:34 +00:00
$ output_file =~ s/\.[gG][cC][oO][dD][eE]$/.svg/ if $ params { export_svg } ;
2014-06-14 17:54:18 +00:00
my $ dlg = Wx::FileDialog - > new ( $ self , 'Save ' . ( $ params { export_svg } ? 'SVG' : 'G-code' ) . ' file as:' ,
2014-06-14 17:59:59 +00:00
wxTheApp - > output_path ( dirname ( $ output_file ) ) ,
2015-06-03 11:19:43 +00:00
basename ( $ output_file ) , $ params { export_svg } ? & Slic3r::GUI::FILE_WILDCARDS - > { svg } : & Slic3r::GUI::FILE_WILDCARDS - > { gcode } , wxFD_SAVE | wxFD_OVERWRITE_PROMPT ) ;
2014-06-14 17:54:18 +00:00
if ( $ dlg - > ShowModal != wxID_OK ) {
$ dlg - > Destroy ;
return ;
}
2017-08-03 15:31:31 +00:00
$ output_file = $ dlg - > GetPath ;
2015-06-02 20:27:11 +00:00
$ qs_last_output_file = $ output_file unless $ params { export_svg } ;
2014-06-14 17:54:18 +00:00
$ Slic3r:: GUI:: Settings - > { _ } { last_output_path } = dirname ( $ output_file ) ;
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2014-06-14 17:54:18 +00:00
$ dlg - > Destroy ;
}
# show processbar dialog
$ progress_dialog = Wx::ProgressDialog - > new ( 'Slicing…' , "Processing $input_file_basename…" ,
100 , $ self , 0 ) ;
$ progress_dialog - > Pulse ;
{
my @ warnings = ( ) ;
local $ SIG { __WARN__ } = sub { push @ warnings , $ _ [ 0 ] } ;
$ sprint - > output_file ( $ output_file ) ;
if ( $ params { export_svg } ) {
$ sprint - > export_svg ;
} else {
$ sprint - > export_gcode ;
}
$ sprint - > status_cb ( undef ) ;
Slic3r::GUI:: warning_catcher ( $ self ) - > ( $ _ ) for @ warnings ;
}
$ progress_dialog - > Destroy ;
undef $ progress_dialog ;
my $ message = "$input_file_basename was successfully sliced." ;
2014-06-14 17:59:59 +00:00
wxTheApp - > notify ( $ message ) ;
2014-06-14 17:54:18 +00:00
Wx::MessageDialog - > new ( $ self , $ message , 'Slicing Done!' ,
wxOK | wxICON_INFORMATION ) - > ShowModal ;
} ;
Slic3r::GUI:: catch_error ( $ self , sub { $ progress_dialog - > Destroy if $ progress_dialog } ) ;
}
2016-10-25 11:24:42 +00:00
sub reslice_now {
my ( $ self ) = @ _ ;
if ( $ self - > { plater } ) {
$ self - > { plater } - > reslice ;
}
}
2014-06-14 17:54:18 +00:00
sub repair_stl {
my $ self = shift ;
my $ input_file ;
{
my $ dir = $ Slic3r:: GUI:: Settings - > { recent } { skein_directory } || $ Slic3r:: GUI:: Settings - > { recent } { config_directory } || '' ;
my $ dialog = Wx::FileDialog - > new ( $ self , 'Select the STL file to repair:' , $ dir , "" , & Slic3r::GUI::FILE_WILDCARDS - > { stl } , wxFD_OPEN | wxFD_FILE_MUST_EXIST ) ;
if ( $ dialog - > ShowModal != wxID_OK ) {
$ dialog - > Destroy ;
return ;
}
2017-08-03 15:31:31 +00:00
$ input_file = $ dialog - > GetPaths ;
2014-06-14 17:54:18 +00:00
$ dialog - > Destroy ;
}
my $ output_file = $ input_file ;
{
2017-07-11 15:15:34 +00:00
$ output_file =~ s/\.[sS][tT][lL]$/_fixed.obj/ ;
2014-06-14 17:54:18 +00:00
my $ dlg = Wx::FileDialog - > new ( $ self , "Save OBJ file (less prone to coordinate errors than STL) as:" , dirname ( $ output_file ) ,
basename ( $ output_file ) , & Slic3r::GUI::FILE_WILDCARDS - > { obj } , wxFD_SAVE | wxFD_OVERWRITE_PROMPT ) ;
if ( $ dlg - > ShowModal != wxID_OK ) {
$ dlg - > Destroy ;
return undef ;
}
2017-08-03 15:31:31 +00:00
$ output_file = $ dlg - > GetPath ;
2014-06-14 17:54:18 +00:00
$ dlg - > Destroy ;
}
my $ tmesh = Slic3r::TriangleMesh - > new ;
2017-08-03 15:31:31 +00:00
$ tmesh - > ReadSTLFile ( $ input_file ) ;
2014-06-14 17:54:18 +00:00
$ tmesh - > repair ;
2017-08-03 15:31:31 +00:00
$ tmesh - > WriteOBJFile ( $ output_file ) ;
2014-06-14 17:54:18 +00:00
Slic3r::GUI:: show_info ( $ self , "Your file was repaired." , "Repair" ) ;
}
sub extra_variables {
my $ self = shift ;
my % extra_variables = ( ) ;
2017-06-14 09:48:08 +00:00
$ extra_variables { "${_}_preset" } = $ self - > { options_tabs } { $ _ } - > get_current_preset - > name
for qw( print filament printer ) ;
2014-06-14 17:54:18 +00:00
return { % extra_variables } ;
}
sub export_config {
my $ self = shift ;
my $ config = $ self - > config ;
eval {
# validate configuration
$ config - > validate ;
} ;
Slic3r::GUI:: catch_error ( $ self ) and return ;
my $ dir = $ last_config ? dirname ( $ last_config ) : $ Slic3r:: GUI:: Settings - > { recent } { config_directory } || $ Slic3r:: GUI:: Settings - > { recent } { skein_directory } || '' ;
my $ filename = $ last_config ? basename ( $ last_config ) : "config.ini" ;
my $ dlg = Wx::FileDialog - > new ( $ self , 'Save configuration as:' , $ dir , $ filename ,
& Slic3r::GUI::FILE_WILDCARDS - > { ini } , wxFD_SAVE | wxFD_OVERWRITE_PROMPT ) ;
if ( $ dlg - > ShowModal == wxID_OK ) {
2017-08-03 15:31:31 +00:00
my $ file = $ dlg - > GetPath ;
2014-06-14 17:54:18 +00:00
$ Slic3r:: GUI:: Settings - > { recent } { config_directory } = dirname ( $ file ) ;
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2014-06-14 17:54:18 +00:00
$ last_config = $ file ;
$ config - > save ( $ file ) ;
}
$ dlg - > Destroy ;
}
sub load_config_file {
my $ self = shift ;
my ( $ file ) = @ _ ;
if ( ! $ file ) {
return unless $ self - > check_unsaved_changes ;
my $ dir = $ last_config ? dirname ( $ last_config ) : $ Slic3r:: GUI:: Settings - > { recent } { config_directory } || $ Slic3r:: GUI:: Settings - > { recent } { skein_directory } || '' ;
my $ dlg = Wx::FileDialog - > new ( $ self , 'Select configuration to load:' , $ dir , "config.ini" ,
2017-06-14 15:51:14 +00:00
'INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g' , wxFD_OPEN | wxFD_FILE_MUST_EXIST ) ;
2014-06-14 17:54:18 +00:00
return unless $ dlg - > ShowModal == wxID_OK ;
2017-08-03 15:31:31 +00:00
$ file = $ dlg - > GetPaths ;
2014-06-14 17:54:18 +00:00
$ dlg - > Destroy ;
}
2017-06-14 18:18:46 +00:00
for my $ tab ( values % { $ self - > { options_tabs } } ) {
# Dont proceed further if the config file cannot be loaded.
return undef if ! $ tab - > load_config_file ( $ file ) ;
}
2014-06-14 17:54:18 +00:00
$ Slic3r:: GUI:: Settings - > { recent } { config_directory } = dirname ( $ file ) ;
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2014-06-14 17:54:18 +00:00
$ last_config = $ file ;
}
sub export_configbundle {
my $ self = shift ;
eval {
# validate current configuration in case it's dirty
$ self - > config - > validate ;
} ;
Slic3r::GUI:: catch_error ( $ self ) and return ;
my $ dir = $ last_config ? dirname ( $ last_config ) : $ Slic3r:: GUI:: Settings - > { recent } { config_directory } || $ Slic3r:: GUI:: Settings - > { recent } { skein_directory } || '' ;
my $ filename = "Slic3r_config_bundle.ini" ;
my $ dlg = Wx::FileDialog - > new ( $ self , 'Save presets bundle as:' , $ dir , $ filename ,
& Slic3r::GUI::FILE_WILDCARDS - > { ini } , wxFD_SAVE | wxFD_OVERWRITE_PROMPT ) ;
if ( $ dlg - > ShowModal == wxID_OK ) {
2017-08-03 15:31:31 +00:00
my $ file = $ dlg - > GetPath ;
2014-06-14 17:54:18 +00:00
$ Slic3r:: GUI:: Settings - > { recent } { config_directory } = dirname ( $ file ) ;
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2014-06-14 17:54:18 +00:00
# leave default category empty to prevent the bundle from being parsed as a normal config file
my $ ini = { _ = > { } } ;
2017-06-14 09:48:08 +00:00
$ ini - > { settings } { $ _ } = $ Slic3r:: GUI:: Settings - > { _ } { $ _ } for qw( autocenter ) ;
2014-06-14 17:54:18 +00:00
$ ini - > { presets } = $ Slic3r:: GUI:: Settings - > { presets } ;
2017-06-14 09:48:08 +00:00
2014-06-14 17:54:18 +00:00
foreach my $ section ( qw( print filament printer ) ) {
2014-06-14 17:59:59 +00:00
my % presets = wxTheApp - > presets ( $ section ) ;
2014-06-14 17:54:18 +00:00
foreach my $ preset_name ( keys % presets ) {
my $ config = Slic3r::Config - > load ( $ presets { $ preset_name } ) ;
$ ini - > { "$section:$preset_name" } = $ config - > as_ini - > { _ } ;
}
}
Slic3r::Config - > write_ini ( $ file , $ ini ) ;
}
$ dlg - > Destroy ;
}
sub load_configbundle {
2015-12-07 11:17:06 +00:00
my ( $ self , $ file , $ skip_no_id ) = @ _ ;
2014-06-14 17:54:18 +00:00
2015-12-07 11:17:06 +00:00
if ( ! $ file ) {
my $ dir = $ last_config ? dirname ( $ last_config ) : $ Slic3r:: GUI:: Settings - > { recent } { config_directory } || $ Slic3r:: GUI:: Settings - > { recent } { skein_directory } || '' ;
my $ dlg = Wx::FileDialog - > new ( $ self , 'Select configuration to load:' , $ dir , "config.ini" ,
& Slic3r::GUI::FILE_WILDCARDS - > { ini } , wxFD_OPEN | wxFD_FILE_MUST_EXIST ) ;
return unless $ dlg - > ShowModal == wxID_OK ;
2017-08-03 15:31:31 +00:00
$ file = $ dlg - > GetPaths ;
2015-12-07 11:17:06 +00:00
$ dlg - > Destroy ;
}
2014-06-14 17:54:18 +00:00
$ Slic3r:: GUI:: Settings - > { recent } { config_directory } = dirname ( $ file ) ;
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2014-06-14 17:54:18 +00:00
# load .ini file
my $ ini = Slic3r::Config - > read_ini ( $ file ) ;
if ( $ ini - > { settings } ) {
$ Slic3r:: GUI:: Settings - > { _ } { $ _ } = $ ini - > { settings } { $ _ } for keys % { $ ini - > { settings } } ;
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2014-06-14 17:54:18 +00:00
}
if ( $ ini - > { presets } ) {
$ Slic3r:: GUI:: Settings - > { presets } = $ ini - > { presets } ;
2014-06-14 17:59:59 +00:00
wxTheApp - > save_settings ;
2014-06-14 17:54:18 +00:00
}
2017-06-14 09:48:08 +00:00
2014-06-14 17:54:18 +00:00
my $ imported = 0 ;
2015-12-07 11:17:06 +00:00
INI_BLOCK: foreach my $ ini_category ( sort keys %$ ini ) {
2014-06-14 17:54:18 +00:00
next unless $ ini_category =~ /^(print|filament|printer):(.+)$/ ;
my ( $ section , $ preset_name ) = ( $ 1 , $ 2 ) ;
my $ config = Slic3r::Config - > load_ini_hash ( $ ini - > { $ ini_category } ) ;
2015-12-07 11:17:06 +00:00
next if $ skip_no_id && ! $ config - > get ( $ section . "_settings_id" ) ;
{
my % current_presets = Slic3r::GUI - > presets ( $ section ) ;
my % current_ids = map { $ _ = > 1 }
grep $ _ ,
map Slic3r::Config - > load ( $ _ ) - > get ( $ section . "_settings_id" ) ,
values % current_presets ;
next INI_BLOCK if exists $ current_ids { $ config - > get ( $ section . "_settings_id" ) } ;
}
2014-06-14 17:54:18 +00:00
$ config - > save ( sprintf "$Slic3r::GUI::datadir/%s/%s.ini" , $ section , $ preset_name ) ;
2015-12-07 11:17:06 +00:00
Slic3r:: debugf "Imported %s preset %s\n" , $ section , $ preset_name ;
2014-06-14 17:54:18 +00:00
$ imported + + ;
}
2017-06-14 09:48:08 +00:00
foreach my $ tab ( values % { $ self - > { options_tabs } } ) {
$ tab - > load_presets ;
2014-06-14 17:54:18 +00:00
}
2015-12-17 17:48:50 +00:00
return if ! $ imported ;
2014-06-14 17:54:18 +00:00
my $ message = sprintf "%d presets successfully imported." , $ imported ;
2017-06-14 09:48:08 +00:00
Slic3r::GUI:: show_info ( $ self , $ message ) ;
2014-06-14 17:54:18 +00:00
}
sub load_config {
my $ self = shift ;
my ( $ config ) = @ _ ;
foreach my $ tab ( values % { $ self - > { options_tabs } } ) {
2014-07-01 14:40:56 +00:00
$ tab - > load_config ( $ config ) ;
2014-06-14 17:54:18 +00:00
}
2015-05-26 22:50:18 +00:00
if ( $ self - > { plater } ) {
$ self - > { plater } - > on_config_change ( $ config ) ;
}
2014-06-14 17:54:18 +00:00
}
sub config_wizard {
my $ self = shift ;
return unless $ self - > check_unsaved_changes ;
if ( my $ config = Slic3r::GUI::ConfigWizard - > new ( $ self ) - > run ) {
2017-06-14 09:48:08 +00:00
for my $ tab ( values % { $ self - > { options_tabs } } ) {
$ tab - > select_default_preset ;
2014-06-14 17:54:18 +00:00
}
$ self - > load_config ( $ config ) ;
2017-06-14 09:48:08 +00:00
for my $ tab ( values % { $ self - > { options_tabs } } ) {
$ tab - > save_preset ( 'My Settings' ) ;
2014-06-14 17:54:18 +00:00
}
}
}
= head2 config
This method collects all config values from the tabs and merges them into a single config object .
= cut
sub config {
my $ self = shift ;
2014-07-01 14:40:56 +00:00
return Slic3r::Config - > new_from_defaults
if ! exists $ self - > { options_tabs } { print }
|| ! exists $ self - > { options_tabs } { filament }
|| ! exists $ self - > { options_tabs } { printer } ;
2014-06-14 17:54:18 +00:00
# retrieve filament presets and build a single config object for them
my $ filament_config ;
2017-06-14 09:48:08 +00:00
if ( ! $ self - > { plater } || $ self - > { plater } - > filament_presets == 1 ) {
2014-06-14 17:54:18 +00:00
$ filament_config = $ self - > { options_tabs } { filament } - > config ;
} else {
my $ i = - 1 ;
foreach my $ preset_idx ( $ self - > { plater } - > filament_presets ) {
$ i + + ;
2015-03-23 20:48:31 +00:00
my $ config ;
if ( $ preset_idx == $ self - > { options_tabs } { filament } - > current_preset ) {
# the selected preset for this extruder is the one in the tab
# use the tab's config instead of the preset in case it is dirty
# perhaps plater shouldn't expose dirty presets at all in multi-extruder environments.
$ config = $ self - > { options_tabs } { filament } - > config ;
} else {
my $ preset = $ self - > { options_tabs } { filament } - > get_preset ( $ preset_idx ) ;
$ config = $ self - > { options_tabs } { filament } - > get_preset_config ( $ preset ) ;
}
2014-06-14 17:54:18 +00:00
if ( ! $ filament_config ) {
$ filament_config = $ config - > clone ;
next ;
}
foreach my $ opt_key ( @ { $ config - > get_keys } ) {
my $ value = $ filament_config - > get ( $ opt_key ) ;
next unless ref $ value eq 'ARRAY' ;
$ value - > [ $ i ] = $ config - > get ( $ opt_key ) - > [ 0 ] ;
$ filament_config - > set ( $ opt_key , $ value ) ;
}
}
}
my $ config = Slic3r::Config - > merge (
Slic3r::Config - > new_from_defaults ,
$ self - > { options_tabs } { print } - > config ,
$ self - > { options_tabs } { printer } - > config ,
$ filament_config ,
) ;
2017-06-14 09:48:08 +00:00
my $ extruders_count = $ self - > { options_tabs } { printer } { extruders_count } ;
$ config - > set ( "${_}_extruder" , min ( $ config - > get ( "${_}_extruder" ) , $ extruders_count ) )
for qw( perimeter infill solid_infill support_material support_material_interface ) ;
2014-06-14 17:54:18 +00:00
return $ config ;
}
2015-01-03 22:25:55 +00:00
sub filament_preset_names {
my ( $ self ) = @ _ ;
return map $ self - > { options_tabs } { filament } - > get_preset ( $ _ ) - > name ,
$ self - > { plater } - > filament_presets ;
}
2014-06-14 17:54:18 +00:00
sub check_unsaved_changes {
my $ self = shift ;
2014-12-28 15:19:55 +00:00
my @ dirty = ( ) ;
foreach my $ tab ( values % { $ self - > { options_tabs } } ) {
push @ dirty , $ tab - > title if $ tab - > is_dirty ;
}
2014-06-14 17:54:18 +00:00
if ( @ dirty ) {
my $ titles = join ', ' , @ dirty ;
my $ confirm = Wx::MessageDialog - > new ( $ self , "You have unsaved changes ($titles). Discard changes and continue anyway?" ,
'Unsaved Presets' , wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT ) ;
return ( $ confirm - > ShowModal == wxID_YES ) ;
}
return 1 ;
}
sub select_tab {
my ( $ self , $ tab ) = @ _ ;
2015-11-08 10:17:55 +00:00
$ self - > { tabpanel } - > SetSelection ( $ tab ) ;
2014-06-14 17:54:18 +00:00
}
2016-10-05 12:13:07 +00:00
# Set a camera direction, zoom to all objects.
sub select_view {
my ( $ self , $ direction ) = @ _ ;
if ( ! $ self - > { no_plater } ) {
$ self - > { plater } - > select_view ( $ direction ) ;
}
}
2014-06-14 18:26:46 +00:00
sub _append_menu_item {
2015-05-25 20:37:04 +00:00
my ( $ self , $ menu , $ string , $ description , $ cb , $ id , $ icon ) = @ _ ;
2014-06-14 18:26:46 +00:00
2014-07-01 14:40:56 +00:00
$ id // = & Wx:: NewId ( ) ;
2014-06-14 18:26:46 +00:00
my $ item = $ menu - > Append ( $ id , $ string , $ description ) ;
2015-05-25 20:37:04 +00:00
$ self - > _set_menu_item_icon ( $ item , $ icon ) ;
2014-06-14 18:26:46 +00:00
EVT_MENU ( $ self , $ id , $ cb ) ;
return $ item ;
}
2015-05-25 20:37:04 +00:00
sub _set_menu_item_icon {
my ( $ self , $ menuItem , $ icon ) = @ _ ;
2015-05-26 09:27:07 +00:00
# SetBitmap was not available on OS X before Wx 0.9927
if ( $ icon && $ menuItem - > can ( 'SetBitmap' ) ) {
2016-04-09 17:10:57 +00:00
$ menuItem - > SetBitmap ( Wx::Bitmap - > new ( $ Slic3r:: var - > ( $ icon ) , wxBITMAP_TYPE_PNG ) ) ;
2015-05-25 20:37:04 +00:00
}
}
2016-10-25 11:24:42 +00:00
# Called after the Preferences dialog is closed and the program settings are saved.
# Update the UI based on the current preferences.
sub update_ui_from_settings {
my ( $ self ) = @ _ ;
$ self - > { menu_item_reslice_now } - > Enable ( ! $ Slic3r:: GUI:: Settings - > { _ } { background_processing } ) ;
$ self - > { plater } - > update_ui_from_settings if ( $ self - > { plater } ) ;
}
2014-06-14 17:11:04 +00:00
1 ;