Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Slic3r.pm20
-rw-r--r--lib/Slic3r/Config.pm65
-rw-r--r--lib/Slic3r/GUI.pm156
-rw-r--r--lib/Slic3r/GUI/Controller.pm2
-rw-r--r--lib/Slic3r/GUI/Controller/PrinterPanel.pm2
-rw-r--r--lib/Slic3r/GUI/MainFrame.pm112
-rw-r--r--lib/Slic3r/GUI/OptionsGroup/Field.pm4
-rw-r--r--lib/Slic3r/GUI/Plater.pm87
-rw-r--r--lib/Slic3r/GUI/Plater/2D.pm7
-rw-r--r--lib/Slic3r/GUI/Preferences.pm20
-rw-r--r--lib/Slic3r/GUI/Tab.pm127
-rwxr-xr-xslic3r.pl13
-rw-r--r--t/threads.t7
-rw-r--r--xs/src/libslic3r/Config.hpp6
-rw-r--r--xs/src/libslic3r/Utils.hpp1
-rw-r--r--xs/src/libslic3r/utils.cpp7
-rw-r--r--xs/src/slic3r/GUI/AppConfig.cpp12
-rw-r--r--xs/src/slic3r/GUI/GUI.cpp81
-rw-r--r--xs/src/slic3r/GUI/GUI.hpp4
-rw-r--r--xs/src/slic3r/GUI/Preset.cpp83
-rw-r--r--xs/src/slic3r/GUI/Preset.hpp1
-rw-r--r--xs/src/slic3r/GUI/PresetBundle.cpp66
-rw-r--r--xs/src/slic3r/GUI/PresetBundle.hpp9
-rw-r--r--xs/xsp/GUI.xsp3
-rw-r--r--xs/xsp/GUI_AppConfig.xsp18
-rw-r--r--xs/xsp/GUI_Preset.xsp68
26 files changed, 469 insertions, 512 deletions
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index dc870edf3..53b2e3663 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -23,25 +23,14 @@ sub debugf {
our $loglevel = 0;
# load threads before Moo as required by it
-our $have_threads;
BEGIN {
# Test, whether the perl was compiled with ithreads support and ithreads actually work.
use Config;
- $have_threads = $Config{useithreads} && eval "use threads; use threads::shared; use Thread::Queue; 1";
- warn "threads.pm >= 1.96 is required, please update\n" if $have_threads && $threads::VERSION < 1.96;
-
- ### temporarily disable threads if using the broken Moo version
use Moo;
- $have_threads = 0 if $Moo::VERSION == 1.003000;
-
- # Disable multi threading completely by an environment value.
- # This is useful for debugging as the Perl debugger does not work
- # in multi-threaded context at all.
- # A good interactive perl debugger is the ActiveState Komodo IDE
- # or the EPIC http://www.epic-ide.org/
- $have_threads = 0 if (defined($ENV{'SLIC3R_SINGLETHREADED'}) && $ENV{'SLIC3R_SINGLETHREADED'} == 1);
- print "Threading disabled\n" if !$have_threads;
-
+ my $have_threads = $Config{useithreads} && eval "use threads; use threads::shared; use Thread::Queue; 1";
+ die "Slic3r Prusa Edition requires working Perl threads.\n" if ! $have_threads;
+ die "threads.pm >= 1.96 is required, please update\n" if $threads::VERSION < 1.96;
+ die "Perl threading is broken with this Moo version: " . $Moo::VERSION . "\n" if $Moo::VERSION == 1.003000;
$debug = 1 if (defined($ENV{'SLIC3R_DEBUGOUT'}) && $ENV{'SLIC3R_DEBUGOUT'} == 1);
print "Debugging output enabled\n" if $debug;
}
@@ -164,6 +153,7 @@ sub thread_cleanup {
*Slic3r::Surface::Collection::DESTROY = sub {};
*Slic3r::Print::SupportMaterial2::DESTROY = sub {};
*Slic3r::TriangleMesh::DESTROY = sub {};
+ *Slic3r::GUI::AppConfig::DESTROY = sub {};
*Slic3r::GUI::PresetBundle::DESTROY = sub {};
return undef; # this prevents a "Scalars leaked" warning
}
diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index c5e49df6b..a9c822b96 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -12,14 +12,14 @@ use List::Util qw(first max);
# The C++ counterpart is a constant singleton.
our $Options = print_config_def();
-# overwrite the hard-coded readonly value (this information is not available in XS)
-$Options->{threads}{readonly} = !$Slic3r::have_threads;
-
-# generate accessors
+# Generate accessors.
{
no strict 'refs';
for my $opt_key (keys %$Options) {
- *{$opt_key} = sub { $_[0]->get($opt_key) };
+ *{$opt_key} = sub {
+ #print "Slic3r::Config::accessor $opt_key\n";
+ $_[0]->get($opt_key)
+ };
}
}
@@ -64,61 +64,6 @@ sub new_from_cli {
return $self;
}
-# CLASS METHODS:
-
-# Write a "Windows" style ini file with categories enclosed in squre brackets.
-# Used by config-bundle-to-config.pl and to save slic3r.ini.
-sub write_ini {
- my $class = shift;
- my ($file, $ini) = @_;
-
- Slic3r::open(\my $fh, '>', $file);
- binmode $fh, ':utf8';
- my $localtime = localtime;
- printf $fh "# generated by Slic3r $Slic3r::VERSION on %s\n", "$localtime";
- # make sure the _ category is the first one written
- foreach my $category (sort { ($a eq '_') ? -1 : ($a cmp $b) } keys %$ini) {
- printf $fh "\n[%s]\n", $category if $category ne '_';
- foreach my $key (sort keys %{$ini->{$category}}) {
- printf $fh "%s = %s\n", $key, $ini->{$category}{$key};
- }
- }
- close $fh;
-}
-
-# Parse a "Windows" style ini file with categories enclosed in squre brackets.
-# Returns a hash of hashes over strings.
-# {category}{name}=value
-# Non-categorized entries are stored under a category '_'.
-# Used by config-bundle-to-config.pl and to read slic3r.ini.
-sub read_ini {
- my $class = shift;
- my ($file) = @_;
-
- local $/ = "\n";
- Slic3r::open(\my $fh, '<', $file)
- or die "Unable to open $file: $!\n";
- binmode $fh, ':utf8';
-
- my $ini = { _ => {} };
- my $category = '_';
- while (<$fh>) {
- s/\R+$//;
- next if /^\s+/;
- next if /^$/;
- next if /^\s*#/;
- if (/^\[(.+?)\]$/) {
- $category = $1;
- next;
- }
- /^(\w+) *= *(.*)/ or die "Unreadable configuration file (invalid data at line $.)\n";
- $ini->{$category}{$1} = $2;
- }
- close $fh;
-
- return $ini;
-}
-
package Slic3r::Config::Static;
use parent 'Slic3r::Config';
diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm
index a75b0d83b..baba3baa7 100644
--- a/lib/Slic3r/GUI.pm
+++ b/lib/Slic3r/GUI.pm
@@ -53,25 +53,9 @@ use constant FILE_WILDCARDS => {
use constant MODEL_WILDCARD => join '|', @{&FILE_WILDCARDS}{qw(known stl obj amf prusa)};
# If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
-our $no_controller;
our $no_plater;
-our $autosave;
our @cb;
-our $Settings = {
- _ => {
- version_check => 1,
- autocenter => 1,
- # Disable background processing by default as it is not stable.
- background_processing => 0,
- # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
- # By default, Prusa has the controller hidden.
- no_controller => 1,
- # If set, the "- default -" selections of print/filament/printer are suppressed, if there is a valid preset available.
- no_defaults => 1,
- },
-};
-
our $small_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
$small_font->SetPointSize(11) if &Wx::wxMAC;
our $small_bold_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
@@ -89,91 +73,47 @@ sub OnInit {
Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION;
$self->{notifier} = Slic3r::GUI::Notifier->new;
+ $self->{app_config} = Slic3r::GUI::AppConfig->new;
$self->{preset_bundle} = Slic3r::GUI::PresetBundle->new;
# just checking for existence of Slic3r::data_dir is not enough: it may be an empty directory
# supplied as argument to --datadir; in that case we should still run the wizard
- my $enc_datadir = Slic3r::encode_path(Slic3r::data_dir);
- Slic3r::debugf "Data directory: %s\n", $enc_datadir;
- my $run_wizard = (-d $enc_datadir && -e "$enc_datadir/slic3r.ini") ? 0 : 1;
- foreach my $dir ($enc_datadir, "$enc_datadir/print", "$enc_datadir/filament", "$enc_datadir/printer") {
- next if -d $dir;
- if (!mkdir $dir) {
- my $error = "Slic3r was unable to create its data directory at $dir ($!).";
- warn "$error\n";
- fatal_error(undef, $error);
- }
+ eval { $self->{preset_bundle}->setup_directories() };
+ if ($@) {
+ warn $@ . "\n";
+ fatal_error(undef, $@);
}
-
+ my $run_wizard = ! $self->{app_config}->exists;
# load settings
- my $last_version;
- if (-f "$enc_datadir/slic3r.ini") {
- my $ini = eval { Slic3r::Config->read_ini(Slic3r::data_dir . "/slic3r.ini") };
- $Settings = $ini if $ini;
- $last_version = $Settings->{_}{version};
- $Settings->{_}{autocenter} //= 1;
- $Settings->{_}{background_processing} //= 1;
- # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
- $Settings->{_}{no_controller} //= 1;
- # If set, the "- default -" selections of print/filament/printer are suppressed, if there is a valid preset available.
- $Settings->{_}{no_defaults} //= 1;
- }
- $Settings->{_}{version} = $Slic3r::VERSION;
- $self->save_settings;
+ $self->{app_config}->load if ! $run_wizard;
+ $self->{app_config}->set('version', $Slic3r::VERSION);
+ $self->{app_config}->save;
# Suppress the '- default -' presets.
- $self->{preset_bundle}->set_default_suppressed($Slic3r::GUI::Settings->{_}{no_defaults} ? 1 : 0);
- eval { $self->{preset_bundle}->load_presets(Slic3r::data_dir) };
+ $self->{preset_bundle}->set_default_suppressed($self->{app_config}->get('no_defaults') ? 1 : 0);
+ eval {
+ $self->{preset_bundle}->load_presets(Slic3r::data_dir);
+ $self->{preset_bundle}->load_selections($self->{app_config});
+ $run_wizard = 1 if $self->{preset_bundle}->has_defauls_only;
+ };
# application frame
Wx::Image::AddHandler(Wx::PNGHandler->new);
$self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new(
# If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
- no_controller => $no_controller // $Settings->{_}{no_controller},
+ no_controller => $self->{app_config}->get('no_controller'),
no_plater => $no_plater,
);
$self->SetTopWindow($frame);
-
- # load init bundle
- #FIXME this is undocumented and the use case is unclear.
-# {
-# my @dirs = ($FindBin::Bin);
-# if (&Wx::wxMAC) {
-# push @dirs, qw();
-# } elsif (&Wx::wxMSW) {
-# push @dirs, qw();
-# }
-# my $init_bundle = first { -e $_ } map "$_/.init_bundle.ini", @dirs;
-# if ($init_bundle) {
-# Slic3r::debugf "Loading config bundle from %s\n", $init_bundle;
-# $self->{mainframe}->load_configbundle($init_bundle, 1);
-# $run_wizard = 0;
-# }
-# }
-
- if (!$run_wizard && (!defined $last_version || $last_version ne $Slic3r::VERSION)) {
- # user was running another Slic3r version on this computer
- if (!defined $last_version || $last_version =~ /^0\./) {
- show_info($self->{mainframe}, "Hello! Support material was improved since the "
- . "last version of Slic3r you used. It is strongly recommended to revert "
- . "your support material settings to the factory defaults and start from "
- . "those. Enjoy and provide feedback!", "Support Material");
- }
- if (!defined $last_version || $last_version =~ /^(?:0|1\.[01])\./) {
- show_info($self->{mainframe}, "Hello! In this version a new Bed Shape option was "
- . "added. If the bed coordinates in the plater preview screen look wrong, go "
- . "to Print Settings and click the \"Set\" button next to \"Bed Shape\".", "Bed Shape");
- }
- }
if ($run_wizard) {
$self->{mainframe}->config_wizard;
- eval { $self->{preset_bundle}->load_presets(Slic3r::data_dir) };
}
EVT_IDLE($frame, sub {
while (my $cb = shift @cb) {
$cb->();
}
+ $self->{app_config}->save if $self->{app_config}->dirty;
});
return 1;
@@ -265,11 +205,6 @@ sub notify {
$self->{notifier}->notify($message);
}
-sub save_settings {
- my ($self) = @_;
- Slic3r::Config->write_ini(Slic3r::data_dir . "/slic3r.ini", $Settings);
-}
-
# 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 {
@@ -277,22 +212,11 @@ sub update_ui_from_settings {
$self->{mainframe}->update_ui_from_settings;
}
-sub output_path {
- my ($self, $dir) = @_;
-
- return ($Settings->{_}{last_output_path} && $Settings->{_}{remember_output_path})
- ? $Settings->{_}{last_output_path}
- : $dir;
-}
-
sub open_model {
my ($self, $window) = @_;
- my $dir = $Slic3r::GUI::Settings->{recent}{skein_directory}
- || $Slic3r::GUI::Settings->{recent}{config_directory}
- || '';
-
- my $dialog = Wx::FileDialog->new($window // $self->GetTopWindow, 'Choose one or more files (STL/OBJ/AMF/PRUSA):', $dir, "",
+ my $dialog = Wx::FileDialog->new($window // $self->GetTopWindow, 'Choose one or more files (STL/OBJ/AMF/PRUSA):',
+ $self->{app_config}->get_last_dir, "",
MODEL_WILDCARD, wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST);
if ($dialog->ShowModal != wxID_OK) {
$dialog->Destroy;
@@ -308,31 +232,6 @@ sub CallAfter {
push @cb, $cb;
}
-sub scan_serial_ports {
- my ($self) = @_;
-
- my @ports = ();
-
- if ($^O eq 'MSWin32') {
- # Windows
- if (eval "use Win32::TieRegistry; 1") {
- my $ts = Win32::TieRegistry->new("HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM",
- { Access => 'KEY_READ' });
- if ($ts) {
- # when no serial ports are available, the registry key doesn't exist and
- # TieRegistry->new returns undef
- $ts->Tie(\my %reg);
- push @ports, sort values %reg;
- }
- }
- } else {
- # UNIX and OS X
- push @ports, glob '/dev/{ttyUSB,ttyACM,tty.,cu.,rfcomm}*';
- }
-
- return grep !/Bluetooth|FireFly/, @ports;
-}
-
sub append_menu_item {
my ($self, $menu, $string, $description, $cb, $id, $icon, $kind) = @_;
@@ -369,25 +268,24 @@ sub set_menu_item_icon {
sub save_window_pos {
my ($self, $window, $name) = @_;
- $Settings->{_}{"${name}_pos"} = join ',', $window->GetScreenPositionXY;
- $Settings->{_}{"${name}_size"} = join ',', $window->GetSizeWH;
- $Settings->{_}{"${name}_maximized"} = $window->IsMaximized;
- $self->save_settings;
+ $self->{app_config}->set("${name}_pos", join ',', $window->GetScreenPositionXY);
+ $self->{app_config}->set("${name}_size", join ',', $window->GetSizeWH);
+ $self->{app_config}->set("${name}_maximized", $window->IsMaximized);
+ $self->{app_config}->save;
}
sub restore_window_pos {
my ($self, $window, $name) = @_;
-
- if (defined $Settings->{_}{"${name}_pos"}) {
- my $size = [ split ',', $Settings->{_}{"${name}_size"}, 2 ];
+ if ($self->{app_config}->has("${name}_pos")) {
+ my $size = [ split ',', $self->{app_config}->get("${name}_size"), 2 ];
$window->SetSize($size);
my $display = Wx::Display->new->GetClientArea();
- my $pos = [ split ',', $Settings->{_}{"${name}_pos"}, 2 ];
+ my $pos = [ split ',', $self->{app_config}->get("${name}_pos"), 2 ];
if (($pos->[0] + $size->[0]/2) < $display->GetRight && ($pos->[1] + $size->[1]/2) < $display->GetBottom) {
$window->Move($pos);
}
- $window->Maximize(1) if $Settings->{_}{"${name}_maximized"};
+ $window->Maximize(1) if $self->{app_config}->get("${name}_maximized");
}
}
diff --git a/lib/Slic3r/GUI/Controller.pm b/lib/Slic3r/GUI/Controller.pm
index c4a22cace..6f2636d20 100644
--- a/lib/Slic3r/GUI/Controller.pm
+++ b/lib/Slic3r/GUI/Controller.pm
@@ -121,7 +121,7 @@ sub OnActivate {
}
if (!%active) {
# enable printers whose port is available
- my %ports = map { $_ => 1 } wxTheApp->scan_serial_ports;
+ my %ports = map { $_ => 1 } Slic3r::GUI::scan_serial_ports;
$active{$_} = 1
for grep exists $ports{$presets{$_}->serial_port}, keys %presets;
}
diff --git a/lib/Slic3r/GUI/Controller/PrinterPanel.pm b/lib/Slic3r/GUI/Controller/PrinterPanel.pm
index 1bf46c456..794ea4e4e 100644
--- a/lib/Slic3r/GUI/Controller/PrinterPanel.pm
+++ b/lib/Slic3r/GUI/Controller/PrinterPanel.pm
@@ -348,7 +348,7 @@ sub update_serial_ports {
my $cb = $self->{serial_port_combobox};
my $current = $cb->GetValue;
$cb->Clear;
- $cb->Append($_) for wxTheApp->scan_serial_ports;
+ $cb->Append($_) for Slic3r::GUI::scan_serial_ports;
$cb->SetValue($current);
}
diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm
index a0a47c547..c7f3f1cf9 100644
--- a/lib/Slic3r/GUI/MainFrame.pm
+++ b/lib/Slic3r/GUI/MainFrame.pm
@@ -76,6 +76,9 @@ sub new {
}
# save window size
wxTheApp->save_window_pos($self, "main_frame");
+ # Save the slic3r.ini. Usually the ini file is saved from "on idle" callback,
+ # but in rare cases it may not have been called yet.
+ wxTheApp->{app_config}->save;
# propagate event
$event->Skip;
});
@@ -140,9 +143,11 @@ sub _init_tabpanel {
my ($group, $name) = @_;
$self->{options_tabs}{$group}->select_preset($name);
});
-
# load initial config
- $self->{plater}->on_config_change(wxTheApp->{preset_bundle}->full_config);
+ my $full_config = wxTheApp->{preset_bundle}->full_config;
+ $self->{plater}->on_config_change($full_config);
+ # Show a correct number of filament fields.
+ $self->{plater}->on_extruders_change(int(@{$full_config->nozzle_diameter}));
}
}
@@ -340,14 +345,15 @@ sub quick_slice {
my $progress_dialog;
eval {
# validate configuration
- my $config = $self->config;
+ my $config = wxTheApp->{preset_bundle}->full_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}) {
- 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);
+ my $dialog = Wx::FileDialog->new($self, 'Choose a file to slice (STL/OBJ/AMF/PRUSA):',
+ wxTheApp->{app_config}->get_last_dir, "",
+ &Slic3r::GUI::MODEL_WILDCARD, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if ($dialog->ShowModal != wxID_OK) {
$dialog->Destroy;
return;
@@ -369,8 +375,7 @@ sub quick_slice {
$input_file = $qs_last_input_file;
}
my $input_file_basename = basename($input_file);
- $Slic3r::GUI::Settings->{recent}{skein_directory} = dirname($input_file);
- wxTheApp->save_settings;
+ wxTheApp->{app_config}->update_skein_dir(dirname($input_file));
my $print_center;
{
@@ -392,11 +397,9 @@ sub quick_slice {
$sprint->apply_config($config);
$sprint->set_model($model);
- {
- my $extra = $self->extra_variables;
- $sprint->placeholder_parser->set($_, $extra->{$_}) for keys %$extra;
- }
-
+ # Copy the names of active presets into the placeholder parser.
+ wxTheApp->{preset_bundle}->export_selections_pp($sprint->placeholder_parser);
+
# select output file
my $output_file;
if ($params{reslice}) {
@@ -405,7 +408,7 @@ sub quick_slice {
$output_file = $sprint->output_filepath;
$output_file =~ s/\.[gG][cC][oO][dD][eE]$/.svg/ if $params{export_svg};
my $dlg = Wx::FileDialog->new($self, 'Save ' . ($params{export_svg} ? 'SVG' : 'G-code') . ' file as:',
- wxTheApp->output_path(dirname($output_file)),
+ wxTheApp->{app_config}->get_last_output_dir(dirname($output_file)),
basename($output_file), $params{export_svg} ? &Slic3r::GUI::FILE_WILDCARDS->{svg} : &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if ($dlg->ShowModal != wxID_OK) {
$dlg->Destroy;
@@ -413,8 +416,7 @@ sub quick_slice {
}
$output_file = $dlg->GetPath;
$qs_last_output_file = $output_file unless $params{export_svg};
- $Slic3r::GUI::Settings->{_}{last_output_path} = dirname($output_file);
- wxTheApp->save_settings;
+ wxTheApp->{app_config}->update_last_output_dir(dirname($output_file));
$dlg->Destroy;
}
@@ -457,8 +459,9 @@ sub repair_stl {
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);
+ my $dialog = Wx::FileDialog->new($self, 'Select the STL file to repair:',
+ wxTheApp->{app_config}->get_last_dir, "",
+ &Slic3r::GUI::FILE_WILDCARDS->{stl}, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if ($dialog->ShowModal != wxID_OK) {
$dialog->Destroy;
return;
@@ -487,15 +490,6 @@ sub repair_stl {
Slic3r::GUI::show_info($self, "Your file was repaired.", "Repair");
}
-# Extra variables for the placeholder parser generating a G-code.
-sub extra_variables {
- my $self = shift;
- my %extra_variables = ();
- $extra_variables{"${_}_preset"} = wxTheApp->{preset_bundle}->{$_}->get_current_preset_name
- for qw(print filament printer);
- return { %extra_variables };
-}
-
sub export_config {
my $self = shift;
# Generate a cummulative configuration for the selected print, filaments and printer.
@@ -504,15 +498,14 @@ sub export_config {
eval { $config->validate; };
Slic3r::GUI::catch_error($self) and return;
# Ask user for the file name for the config file.
- 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,
+ my $dlg = Wx::FileDialog->new($self, 'Save configuration as:',
+ $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
+ $last_config ? basename($last_config) : "config.ini",
&Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
my $file = ($dlg->ShowModal == wxID_OK) ? $dlg->GetPath : undef;
$dlg->Destroy;
if (defined $file) {
- $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file);
- wxTheApp->save_settings;
+ wxTheApp->{app_config}->update_config_dir(dirname($file));
$last_config = $file;
$config->save($file);
}
@@ -523,9 +516,10 @@ sub load_config_file {
my ($self, $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",
- 'INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g', wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+ my $dlg = Wx::FileDialog->new($self, 'Select configuration to load:',
+ $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
+ "config.ini",
+ 'INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g', wxFD_OPEN | wxFD_FILE_MUST_EXIST);
return unless $dlg->ShowModal == wxID_OK;
$file = $dlg->GetPaths;
$dlg->Destroy;
@@ -534,49 +528,51 @@ sub load_config_file {
# Dont proceed further if the config file cannot be loaded.
return if Slic3r::GUI::catch_error($self);
$_->load_current_preset for (values %{$self->{options_tabs}});
- $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file);
- wxTheApp->save_settings;
+ wxTheApp->{app_config}->update_config_dir(dirname($file));
$last_config = $file;
}
sub export_configbundle {
- my $self = shift;
+ my ($self) = @_;
+ return unless $self->check_unsaved_changes;
# validate current configuration in case it's dirty
- eval { $self->config->validate; };
+ eval { wxTheApp->{preset_bundle}->full_config->validate; };
Slic3r::GUI::catch_error($self) and return;
# Ask user for a file name.
- 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,
+ my $dlg = Wx::FileDialog->new($self, 'Save presets bundle as:',
+ $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
+ "Slic3r_config_bundle.ini",
&Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
my $file = ($dlg->ShowModal == wxID_OK) ? $dlg->GetPath : undef;
$dlg->Destroy;
if (defined $file) {
# Export the config bundle.
- $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file);
- wxTheApp->save_settings;
- eval { $self->{presets}->export_configbundle($file); };
+ wxTheApp->{app_config}->update_config_dir(dirname($file));
+ eval { wxTheApp->{preset_bundle}->export_configbundle($file); };
Slic3r::GUI::catch_error($self) and return;
}
}
+# Loading a config bundle with an external file name used to be used
+# to auto-install a config bundle on a fresh user account,
+# but that behavior was not documented and likely buggy.
sub load_configbundle {
- my ($self, $file, $skip_no_id) = @_;
-
+ my ($self, $file) = @_;
+ return unless $self->check_unsaved_changes;
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);
+ my $dlg = Wx::FileDialog->new($self, 'Select configuration to load:',
+ $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
+ "config.ini",
+ &Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
return unless $dlg->ShowModal == wxID_OK;
$file = $dlg->GetPaths;
$dlg->Destroy;
}
- $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file);
- wxTheApp->save_settings;
+ wxTheApp->{app_config}->update_config_dir(dirname($file));
my $presets_imported = 0;
- eval { $presets_imported = $self->{presets}->load_configbundle($file); };
+ eval { $presets_imported = wxTheApp->{preset_bundle}->load_configbundle($file); };
Slic3r::GUI::catch_error($self) and return;
# Load the currently selected preset into the GUI, update the preset selection box.
@@ -597,16 +593,18 @@ sub load_config {
}
sub config_wizard {
- my $self = shift;
-
+ my ($self) = @_;
+ # Exit wizard if there are unsaved changes and the user cancels the action.
return unless $self->check_unsaved_changes;
if (my $config = Slic3r::GUI::ConfigWizard->new($self)->run) {
for my $tab (values %{$self->{options_tabs}}) {
- # Select the first visible preset.
- $tab->select_preset(undef);
+ # Select the first visible preset, force.
+ $tab->select_preset(undef, 1);
}
+ # Load the config over the previously selected defaults.
$self->load_config($config);
for my $tab (values %{$self->{options_tabs}}) {
+ # Save the settings under a new name, select the name.
$tab->save_preset('My Settings');
}
}
@@ -666,7 +664,7 @@ sub _set_menu_item_icon {
# 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->{menu_item_reslice_now}->Enable(! wxTheApp->{app_config}->get("background_processing"));
$self->{plater}->update_ui_from_settings if ($self->{plater});
}
diff --git a/lib/Slic3r/GUI/OptionsGroup/Field.pm b/lib/Slic3r/GUI/OptionsGroup/Field.pm
index 531e13a5d..4ef2ce2ca 100644
--- a/lib/Slic3r/GUI/OptionsGroup/Field.pm
+++ b/lib/Slic3r/GUI/OptionsGroup/Field.pm
@@ -124,6 +124,10 @@ sub BUILD {
});
}
+sub get_value {
+ my ($self) = @_;
+ return $self->wxWindow->GetValue ? 1 : 0;
+}
package Slic3r::GUI::OptionsGroup::Field::SpinCtrl;
use Moo;
diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index 91329e45e..06adbe525 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -63,12 +63,7 @@ sub new {
$self->{print}->set_status_cb(sub {
my ($percent, $message) = @_;
-
- if ($Slic3r::have_threads) {
- Wx::PostEvent($self, Wx::PlThreadEvent->new(-1, $PROGRESS_BAR_EVENT, shared_clone([$percent, $message])));
- } else {
- $self->on_progress_event($percent, $message);
- }
+ Wx::PostEvent($self, Wx::PlThreadEvent->new(-1, $PROGRESS_BAR_EVENT, shared_clone([$percent, $message])));
});
# Initialize preview notebook
@@ -119,7 +114,7 @@ sub new {
$self->GetFrame->{options_tabs}{print}->load_config($cfg);
});
$self->{canvas3D}->set_on_model_update(sub {
- if ($Slic3r::GUI::Settings->{_}{background_processing}) {
+ if (wxTheApp->{app_config}->get("background_processing")) {
$self->schedule_background_process;
} else {
# Hide the print info box, it is no more valid.
@@ -330,7 +325,7 @@ sub new {
$self->on_process_completed($event->GetData);
});
- if ($Slic3r::have_threads) {
+ {
my $timer_id = Wx::NewId();
$self->{apply_config_timer} = Wx::Timer->new($self, $timer_id);
EVT_TIMER($self, $timer_id, sub {
@@ -448,7 +443,6 @@ sub new {
$self->{"print_info_$field"}->SetFont($Slic3r::GUI::small_font);
$grid_sizer->Add($self->{"print_info_$field"}, 0);
}
-
}
my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
@@ -510,13 +504,14 @@ sub _on_select_preset {
wxTheApp->{preset_bundle}->set_filament_preset($idx, $choice->GetStringSelection);
}
if ($group eq 'filament' && @{$self->{preset_choosers}{filament}} > 1) {
- wxTheApp->save_settings;
wxTheApp->{preset_bundle}->update_platter_filament_ui_colors($idx, $choice);
} else {
# call GetSelection() in scalar context as it's context-aware
$self->{on_select_preset}->($group, $choice->GetStringSelection)
if $self->{on_select_preset};
}
+ # Synchronize config.ini with the current selections.
+ wxTheApp->{preset_bundle}->export_selections(wxTheApp->{app_config});
# get new config and generate on_config_change() event for updating plater and other things
$self->on_config_change(wxTheApp->{preset_bundle}->full_config);
}
@@ -548,8 +543,8 @@ sub GetFrame {
sub update_ui_from_settings
{
my ($self) = @_;
- if (defined($self->{btn_reslice}) && $self->{buttons_sizer}->IsShown($self->{btn_reslice}) != (! $Slic3r::GUI::Settings->{_}{background_processing})) {
- $self->{buttons_sizer}->Show($self->{btn_reslice}, ! $Slic3r::GUI::Settings->{_}{background_processing});
+ if (defined($self->{btn_reslice}) && $self->{buttons_sizer}->IsShown($self->{btn_reslice}) != (! wxTheApp->{app_config}->get("background_processing"))) {
+ $self->{buttons_sizer}->Show($self->{btn_reslice}, ! wxTheApp->{app_config}->get("background_processing"));
$self->{buttons_sizer}->Layout;
}
}
@@ -587,6 +582,8 @@ sub update_presets {
$choice_idx += 1;
}
}
+ # Synchronize config.ini with the current selections.
+ wxTheApp->{preset_bundle}->export_selections(wxTheApp->{app_config});
}
sub add {
@@ -655,8 +652,7 @@ sub load_files {
}
# Note the current directory for the file open dialog.
- $Slic3r::GUI::Settings->{recent}{skein_directory} = dirname($input_files->[-1]);
- wxTheApp->save_settings;
+ wxTheApp->{app_config}->update_skein_dir(dirname($input_files->[-1]));
$process_dialog->Destroy;
$self->statusbar->SetStatusText("Loaded " . join(',', @loaded_files));
@@ -704,7 +700,7 @@ sub load_model_objects {
}
# if user turned autocentering off, automatic arranging would disappoint them
- if (!$Slic3r::GUI::Settings->{_}{autocenter}) {
+ if (! wxTheApp->{app_config}->get("autocenter")) {
$need_arrange = 0;
}
@@ -817,7 +813,7 @@ sub increase {
# only autoarrange if user has autocentering enabled
$self->stop_background_process;
- if ($Slic3r::GUI::Settings->{_}{autocenter}) {
+ if (wxTheApp->{app_config}->get("autocenter")) {
$self->arrange;
} else {
$self->update;
@@ -1130,7 +1126,7 @@ sub async_apply_config {
# Hide the slicing results if the current slicing status is no more valid.
$self->{"print_info_box_show"}->(0) if $invalidated;
- if ($Slic3r::GUI::Settings->{_}{background_processing}) {
+ if (wxTheApp->{app_config}->get("background_processing")) {
if ($invalidated) {
# kill current thread if any
$self->stop_background_process;
@@ -1152,7 +1148,6 @@ sub async_apply_config {
sub start_background_process {
my ($self) = @_;
- return if !$Slic3r::have_threads;
return if !@{$self->{objects}};
return if $self->{process_thread};
@@ -1171,11 +1166,8 @@ sub start_background_process {
return;
}
- # apply extra variables
- {
- my $extra = $self->GetFrame->extra_variables;
- $self->{print}->placeholder_parser->set($_, $extra->{$_}) for keys %$extra;
- }
+ # Copy the names of active presets into the placeholder parser.
+ wxTheApp->{preset_bundle}->export_selections_pp($self->{print}->placeholder_parser);
# start thread
@_ = ();
@@ -1246,7 +1238,7 @@ sub reslice {
# explicitly cancel a previous thread and start a new one.
my ($self) = @_;
# Don't reslice if export of G-code or sending to OctoPrint is running.
- if ($Slic3r::have_threads && ! defined($self->{export_gcode_output_file}) && ! defined($self->{send_gcode_file})) {
+ if (! defined($self->{export_gcode_output_file}) && ! defined($self->{send_gcode_file})) {
# Stop the background processing threads, stop the async update timer.
$self->stop_background_process;
# Rather perform one additional unnecessary update of the print object instead of skipping a pending async update.
@@ -1289,52 +1281,41 @@ sub export_gcode {
$self->{print}->apply_config($config);
$self->{print}->validate;
};
- if (!$Slic3r::have_threads) {
- Slic3r::GUI::catch_error($self) and return;
- }
+ Slic3r::GUI::catch_error($self) and return;
# select output file
if ($output_file) {
$self->{export_gcode_output_file} = $self->{print}->output_filepath($output_file);
} else {
my $default_output_file = $self->{print}->output_filepath($main::opt{output} // '');
- my $dlg = Wx::FileDialog->new($self, 'Save G-code file as:', wxTheApp->output_path(dirname($default_output_file)),
+ my $dlg = Wx::FileDialog->new($self, 'Save G-code file as:',
+ wxTheApp->{app_config}->get_last_output_dir(dirname($default_output_file)),
basename($default_output_file), &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if ($dlg->ShowModal != wxID_OK) {
$dlg->Destroy;
return;
}
my $path = $dlg->GetPath;
- $Slic3r::GUI::Settings->{_}{last_output_path} = dirname($path);
- wxTheApp->save_settings;
+ wxTheApp->{app_config}->update_last_output_dir(dirname($path));
$self->{export_gcode_output_file} = $path;
$dlg->Destroy;
}
$self->statusbar->StartBusy;
- if ($Slic3r::have_threads) {
- $self->statusbar->SetCancelCallback(sub {
- $self->stop_background_process;
- $self->statusbar->SetStatusText("Export cancelled");
- $self->{export_gcode_output_file} = undef;
- $self->{send_gcode_file} = undef;
-
- # this updates buttons status
- $self->object_list_changed;
- });
+ $self->statusbar->SetCancelCallback(sub {
+ $self->stop_background_process;
+ $self->statusbar->SetStatusText("Export cancelled");
+ $self->{export_gcode_output_file} = undef;
+ $self->{send_gcode_file} = undef;
- # start background process, whose completion event handler
- # will detect $self->{export_gcode_output_file} and proceed with export
- $self->start_background_process;
- } else {
- eval {
- $self->{print}->process;
- $self->{print}->export_gcode(output_file => $self->{export_gcode_output_file});
- };
- my $result = !Slic3r::GUI::catch_error($self);
- $self->on_export_completed($result);
- }
+ # this updates buttons status
+ $self->object_list_changed;
+ });
+
+ # start background process, whose completion event handler
+ # will detect $self->{export_gcode_output_file} and proceed with export
+ $self->start_background_process;
# this updates buttons status
$self->object_list_changed;
@@ -1577,7 +1558,7 @@ sub reset_thumbnail {
sub update {
my ($self, $force_autocenter) = @_;
- if ($Slic3r::GUI::Settings->{_}{autocenter} || $force_autocenter) {
+ if (wxTheApp->{app_config}->get("autocenter") || $force_autocenter) {
$self->{model}->center_instances_around_point($self->bed_centerf);
}
@@ -1604,9 +1585,7 @@ sub update {
# and some reasonable default has to be selected for the additional extruders.
sub on_extruders_change {
my ($self, $num_extruders) = @_;
-
my $choices = $self->{preset_choosers}{filament};
- wxTheApp->{preset_bundle}->update_multi_material_filament_presets;
while (int(@$choices) < $num_extruders) {
# copy strings from first choice
diff --git a/lib/Slic3r/GUI/Plater/2D.pm b/lib/Slic3r/GUI/Plater/2D.pm
index 089b25947..a1e077591 100644
--- a/lib/Slic3r/GUI/Plater/2D.pm
+++ b/lib/Slic3r/GUI/Plater/2D.pm
@@ -9,7 +9,7 @@ use utf8;
use List::Util qw(min max first);
use Slic3r::Geometry qw(X Y scale unscale convex_hull);
use Slic3r::Geometry::Clipper qw(offset JT_ROUND intersection_pl);
-use Wx qw(:misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL);
+use Wx qw(wxTheApp :misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_MOUSE_EVENTS EVT_PAINT EVT_ERASE_BACKGROUND EVT_SIZE);
use base 'Wx::Panel';
@@ -102,7 +102,7 @@ sub repaint {
}
# draw print center
- if (@{$self->{objects}} && $Slic3r::GUI::Settings->{_}{autocenter}) {
+ if (@{$self->{objects}} && wxTheApp->{app_config}->get("autocenter")) {
my $center = $self->unscaled_point_to_pixel($self->{print_center});
$dc->SetPen($self->{print_center_pen});
$dc->DrawLine($center->[X], 0, $center->[X], $size[Y]);
@@ -197,7 +197,6 @@ sub repaint {
sub mouse_event {
my ($self, $event) = @_;
-
my $pos = $event->GetPosition;
my $point = $self->point_to_model_units([ $pos->x, $pos->y ]); #]]
if ($event->ButtonDown) {
@@ -257,7 +256,7 @@ sub mouse_event {
}
sub update_bed_size {
- my $self = shift;
+ my ($self) = @_;
# when the canvas is not rendered yet, its GetSize() method returns 0,0
my $canvas_size = $self->GetSize;
diff --git a/lib/Slic3r/GUI/Preferences.pm b/lib/Slic3r/GUI/Preferences.pm
index 4b6c665b7..ca953e215 100644
--- a/lib/Slic3r/GUI/Preferences.pm
+++ b/lib/Slic3r/GUI/Preferences.pm
@@ -10,6 +10,7 @@ sub new {
my $self = $class->SUPER::new($parent, -1, "Preferences", wxDefaultPosition, wxDefaultSize);
$self->{values} = {};
+ my $app_config = wxTheApp->{app_config};
my $optgroup;
$optgroup = Slic3r::GUI::OptionsGroup->new(
parent => $self,
@@ -25,7 +26,7 @@ sub new {
# type => 'bool',
# label => 'Check for updates',
# tooltip => 'If this is enabled, Slic3r will check for updates daily and display a reminder if a newer version is available.',
-# default => $Slic3r::GUI::Settings->{_}{version_check} // 1,
+# default => $app_config->get("version_check") // 1,
# readonly => !wxTheApp->have_version_check,
# ));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
@@ -33,36 +34,35 @@ sub new {
type => 'bool',
label => 'Remember output directory',
tooltip => 'If this is enabled, Slic3r will prompt the last output directory instead of the one containing the input files.',
- default => $Slic3r::GUI::Settings->{_}{remember_output_path},
+ default => $app_config->get("remember_output_path"),
));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
opt_id => 'autocenter',
type => 'bool',
label => 'Auto-center parts',
tooltip => 'If this is enabled, Slic3r will auto-center objects around the print bed center.',
- default => $Slic3r::GUI::Settings->{_}{autocenter},
+ default => $app_config->get("autocenter"),
));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
opt_id => 'background_processing',
type => 'bool',
label => 'Background processing',
tooltip => 'If this is enabled, Slic3r will pre-process objects as soon as they\'re loaded in order to save time when exporting G-code.',
- default => $Slic3r::GUI::Settings->{_}{background_processing},
- readonly => !$Slic3r::have_threads,
+ default => $app_config->get("background_processing"),
));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
opt_id => 'no_controller',
type => 'bool',
label => 'Disable USB/serial connection',
tooltip => 'Disable communication with the printer over a serial / USB cable. This simplifies the user interface in case the printer is never attached to the computer.',
- default => $Slic3r::GUI::Settings->{_}{no_controller},
+ default => $app_config->get("no_controller"),
));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
opt_id => 'no_defaults',
type => 'bool',
label => 'Suppress "- default -" presets',
tooltip => 'Suppress "- default -" presets in the Print / Filament / Printer selections once there are any other valid presets available.',
- default => $Slic3r::GUI::Settings->{_}{no_defaults},
+ default => $app_config->get("no_defaults"),
));
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
@@ -79,15 +79,15 @@ sub new {
}
sub _accept {
- my $self = shift;
+ my ($self) = @_;
if (defined($self->{values}{no_controller}) ||
defined($self->{values}{no_defaults})) {
Slic3r::GUI::warning_catcher($self)->("You need to restart Slic3r to make the changes effective.");
}
- $Slic3r::GUI::Settings->{_}{$_} = $self->{values}{$_} for keys %{$self->{values}};
- wxTheApp->save_settings;
+ my $app_config = wxTheApp->{app_config};
+ $app_config->set($_, $self->{values}{$_}) for keys %{$self->{values}};
$self->EndModal(wxID_OK);
$self->Close; # needed on Linux
diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm
index 1375bb92b..2718d4f5e 100644
--- a/lib/Slic3r/GUI/Tab.pm
+++ b/lib/Slic3r/GUI/Tab.pm
@@ -125,15 +125,9 @@ sub save_preset {
$self->{treectrl}->SetFocus;
if (!defined $name) {
- my $preset = $self->{presets}->get_edited_preset;
+ my $preset = $self->{presets}->get_selected_preset;
my $default_name = $preset->default ? 'Untitled' : $preset->name;
$default_name =~ s/\.[iI][nN][iI]$//;
-
- my @prsts = @{$self->{presets}};
- print "Num of presets: ". int(@prsts) . "\n";
- for my $pr (@prsts) {
- print "Name: " . $pr->name . " default " . $pr->default . "\n";
- }
my $dlg = Slic3r::GUI::SavePresetWindow->new($self,
title => lc($self->title),
default => $default_name,
@@ -156,16 +150,16 @@ sub delete_preset {
my ($self) = @_;
my $current_preset = $self->{presets}->get_selected_preset;
# Don't let the user delete the '- default -' configuration.
+ my $msg = 'Are you sure you want to ' . ($current_preset->external ? 'remove' : 'delete') . ' the selected preset?';
+ my $title = ($current_preset->external ? 'Remove' : 'Delete') . ' Preset';
return if $current_preset->default ||
- wxID_YES != Wx::MessageDialog->new($self, "Are you sure you want to delete the selected preset?", 'Delete Preset', wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION)->ShowModal;
+ wxID_YES != Wx::MessageDialog->new($self, $msg, $title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION)->ShowModal;
# Delete the file and select some other reasonable preset.
# The 'external' presets will only be removed from the preset list, their files will not be deleted.
eval { $self->{presets}->delete_current_preset; };
Slic3r::GUI::catch_error($self) and return;
- # Delete the item from the UI component and activate another preset.
- $self->{presets}->update_tab_ui($self->{presets_choice});
- # Update the selection boxes at the patter.
- $self->_on_presets_changed;
+ # Load the newly selected preset into the UI, update selection combo boxes with their dirty flags.
+ $self->load_current_preset;
}
# Register the on_value_change callback.
@@ -203,7 +197,6 @@ sub _update {}
# to uddate number of "filament" selection boxes when the number of extruders change.
sub _on_presets_changed {
my ($self) = @_;
- print "Tab::_on_presets_changed\n";
$self->{on_presets_changed}->($self->{presets}) if $self->{on_presets_changed};
}
@@ -237,38 +230,34 @@ sub may_discard_current_preset_if_dirty
}
# Called by the UI combo box when the user switches profiles.
-# Select a preset by a name. If ! defined(name), then the first visible preset is selected.
+# Select a preset by a name. If ! defined(name), then the default preset is selected.
# If the current profile is modified, user is asked to save the changes.
sub select_preset {
my ($self, $name, $force) = @_;
- print "select_preset 1\n";
- if (! $self->may_discard_current_preset_if_dirty) {
+ $force //= 0;
+ if (! $force && ! $self->may_discard_current_preset_if_dirty) {
$self->{presets}->update_tab_ui($self->{presets_choice});
# Trigger the on_presets_changed event so that we also restore the previous value in the plater selector.
$self->_on_presets_changed;
return;
}
- print "select_preset 2\n";
- $self->{presets}->select_preset_by_name(defined $name ? $name : "");
- print "select_preset 3\n";
+ if (defined $name) {
+ $self->{presets}->select_preset_by_name($name);
+ } else {
+ $self->{presets}->select_preset(0);
+ }
# Initialize the UI from the current preset.
$self->load_current_preset;
- print "select_preset 4\n";
- # Save the current application settings with the newly selected preset name.
- wxTheApp->save_settings;
- print "select_preset 5\n";
}
# Initialize the UI from the current preset.
sub load_current_preset {
my ($self) = @_;
- print "load_current_preset 1\n";
$self->{presets}->update_tab_ui($self->{presets_choice});
- print "load_current_preset 2\n";
my $preset = $self->{presets}->get_current_preset;
eval {
local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self);
- my $method = ($preset->default || $preset->external) ? 'Disable' : 'Enable';
+ my $method = $preset->default ? 'Disable' : 'Enable';
$self->{btn_delete_preset}->$method;
$self->_update;
# For the printer profile, generate the extruder pages.
@@ -281,8 +270,9 @@ sub load_current_preset {
# preset dirty again
# (not sure this is true anymore now that update_dirty is idempotent)
wxTheApp->CallAfter(sub {
- $self->_on_presets_changed;
$self->update_dirty;
+ #the following is called by update_dirty
+ #$self->_on_presets_changed;
});
}
@@ -404,7 +394,7 @@ sub build {
my $self = shift;
$self->{presets} = wxTheApp->{preset_bundle}->print;
- $self->{config} = $self->{presets}->get_edited_preset->config_ref;
+ $self->{config} = $self->{presets}->get_edited_preset->config;
{
my $page = $self->add_options_page('Layers and perimeters', 'layers.png');
@@ -608,7 +598,7 @@ sub build {
$optgroup->append_single_option_line('clip_multipart_objects');
$optgroup->append_single_option_line('elefant_foot_compensation');
$optgroup->append_single_option_line('xy_size_compensation');
-# $optgroup->append_single_option_line('threads') if $Slic3r::have_threads;
+# $optgroup->append_single_option_line('threads');
$optgroup->append_single_option_line('resolution');
}
}
@@ -675,7 +665,7 @@ sub _update {
my ($self) = @_;
$self->Freeze;
- my $config = $self->{presets}->get_edited_preset->config_ref;
+ my $config = $self->{config};
if ($config->spiral_vase && !($config->perimeters == 1 && $config->top_solid_layers == 0 && $config->fill_density == 0)) {
my $dialog = Wx::MessageDialog->new($self,
@@ -882,7 +872,7 @@ sub build {
my $self = shift;
$self->{presets} = wxTheApp->{preset_bundle}->filament;
- $self->{config} = $self->{presets}->get_edited_preset->config_ref;
+ $self->{config} = $self->{presets}->get_edited_preset->config;
{
my $page = $self->add_options_page('Filament', 'spool.png');
@@ -1061,8 +1051,9 @@ sub build {
my ($self, %params) = @_;
$self->{presets} = wxTheApp->{preset_bundle}->printer;
- $self->{config} = $self->{presets}->get_edited_preset->config_ref;
-
+ $self->{config} = $self->{presets}->get_edited_preset->config;
+ $self->{extruders_count} = scalar @{$self->{config}->nozzle_diameter};
+
my $bed_shape_widget = sub {
my ($parent) = @_;
@@ -1086,9 +1077,7 @@ sub build {
return $sizer;
};
-
- $self->{extruders_count} = 1;
-
+
{
my $page = $self->add_options_page('General', 'printer_empty.png');
{
@@ -1117,13 +1106,16 @@ sub build {
$optgroup->append_single_option_line('single_extruder_multi_material');
}
$optgroup->on_change(sub {
- my ($opt_id) = @_;
- if ($opt_id eq 'extruders_count') {
- wxTheApp->CallAfter(sub {
+ my ($opt_key, $value) = @_;
+ wxTheApp->CallAfter(sub {
+ if ($opt_key eq 'extruders_count') {
$self->_extruders_count_changed($optgroup->get_value('extruders_count'));
- });
- $self->update_dirty;
- }
+ $self->update_dirty;
+ } else {
+ $self->update_dirty;
+ $self->_on_value_change($opt_key, $value);
+ }
+ });
});
}
if (!$params{no_controller})
@@ -1326,43 +1318,23 @@ sub build {
sub _update_serial_ports {
my ($self) = @_;
- $self->get_field('serial_port')->set_values([ wxTheApp->scan_serial_ports ]);
+ $self->get_field('serial_port')->set_values([ Slic3r::GUI::scan_serial_ports ]);
}
sub _extruders_count_changed {
my ($self, $extruders_count) = @_;
-
$self->{extruders_count} = $extruders_count;
+ wxTheApp->{preset_bundle}->printer->get_edited_preset->set_num_extruders($extruders_count);
+ wxTheApp->{preset_bundle}->update_multi_material_filament_presets;
$self->_build_extruder_pages;
$self->_on_value_change('extruders_count', $extruders_count);
}
-sub _extruder_options {
- qw(nozzle_diameter min_layer_height max_layer_height extruder_offset
- retract_length retract_lift retract_lift_above retract_lift_below retract_speed deretract_speed
- retract_before_wipe retract_restart_extra retract_before_travel wipe
- retract_layer_change retract_length_toolchange retract_restart_extra_toolchange extruder_colour) }
-
sub _build_extruder_pages {
- my $self = shift;
-
+ my ($self) = @_;
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);
- 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;
- }
- $self->{config}->set($opt_key, $values)
- or die "Unable to extend $opt_key";
- }
-
# build page
my $page = $self->{extruder_pages}[$extruder_idx] = $self->add_options_page("Extruder " . ($extruder_idx + 1), 'funnel.png');
{
@@ -1412,14 +1384,6 @@ sub _build_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";
- }
-
# rebuild page list
my @pages_without_extruders = (grep $_->{title} !~ /^Extruder \d+/, @{$self->{pages}});
my $page_notes = pop @pages_without_extruders;
@@ -1513,15 +1477,12 @@ sub _update {
# this gets executed after preset is loaded and before GUI fields are updated
sub on_preset_loaded {
- my $self = shift;
-
+ my ($self) = @_;
# update the extruders count field
- {
- # update the GUI field according to the number of nozzle diameters supplied
- my $extruders_count = scalar @{ $self->{config}->nozzle_diameter };
- $self->set_value('extruders_count', $extruders_count);
- $self->_extruders_count_changed($extruders_count);
- }
+ my $extruders_count = scalar @{ $self->{config}->nozzle_diameter };
+ $self->set_value('extruders_count', $extruders_count);
+ # update the GUI field according to the number of nozzle diameters supplied
+ $self->_extruders_count_changed($extruders_count);
}
# Single Tab page containing a {vsizer} of {optgroups}
diff --git a/slic3r.pl b/slic3r.pl
index 9864c0714..87c8fe40c 100755
--- a/slic3r.pl
+++ b/slic3r.pl
@@ -241,16 +241,7 @@ if (@ARGV) { # slicing from command line
sub usage {
my ($exit_code) = @_;
-
my $config = Slic3r::Config::new_from_defaults->as_hash;
-
- my $j = '';
- if ($Slic3r::have_threads) {
- $j = <<"EOF";
- -j, --threads <num> Number of threads to use (1+, default: $config->{threads})
-EOF
- }
-
print <<"EOF";
Slic3r $Slic3r::VERSION is a STL-to-GCODE translator for RepRap 3D printers
written by Alessandro Ranellucci <aar\@cpan.org> - http://slic3r.org/
@@ -275,8 +266,8 @@ Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ...
them as <name>_upper.stl and <name>_lower.stl
--split Split the shells contained in given STL file into several STL files
--info Output information about the supplied file(s) and exit
-
-$j
+ -j, --threads <num> Number of threads to use (1+, default: $config->{threads})
+
GUI options:
--gui Forces the GUI launch instead of command line slicing (if you
supply a model file, it will be loaded into the plater)
diff --git a/t/threads.t b/t/threads.t
index 7fcd86f0e..7fede3328 100644
--- a/t/threads.t
+++ b/t/threads.t
@@ -1,4 +1,4 @@
-use Test::More;
+use Test::More tests => 2;
use strict;
use warnings;
@@ -12,11 +12,6 @@ use List::Util qw(first);
use Slic3r;
use Slic3r::Test;
-if (!$Slic3r::have_threads) {
- plan skip_all => "this perl is not compiled with threads";
-}
-plan tests => 2;
-
{
my $print = Slic3r::Test::init_print('20mm_cube');
{
diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp
index 2228b8e7c..30fc00b68 100644
--- a/xs/src/libslic3r/Config.hpp
+++ b/xs/src/libslic3r/Config.hpp
@@ -207,15 +207,15 @@ public:
void resize(size_t n, const ConfigOption *opt_default = nullptr) override
{
assert(opt_default == nullptr || opt_default->is_vector());
- assert(opt_default == nullptr || dynamic_cast<ConfigOptionVector<T>>(opt_default));
+// assert(opt_default == nullptr || dynamic_cast<ConfigOptionVector<T>>(opt_default));
assert(! this->values.empty() || opt_default != nullptr);
if (n == 0)
this->values.clear();
else if (n < this->values.size())
this->values.erase(this->values.begin() + n, this->values.end());
- else if (n > this->values.size())
+ else if (n > this->values.size()) {
if (this->values.empty()) {
- if (opt_default == nullptr) {
+ if (opt_default == nullptr)
throw std::runtime_error("ConfigOptionVector::resize(): No default value provided.");
if (opt_default->type() != this->type())
throw std::runtime_error("ConfigOptionVector::resize(): Extending with an incompatible type.");
diff --git a/xs/src/libslic3r/Utils.hpp b/xs/src/libslic3r/Utils.hpp
index 9e4043818..308a2a118 100644
--- a/xs/src/libslic3r/Utils.hpp
+++ b/xs/src/libslic3r/Utils.hpp
@@ -25,7 +25,6 @@ std::string config_path(const std::string &file_name);
// The suffix ".ini" will be added if it is missing in the name.
std::string config_path(const std::string &section, const std::string &name);
-extern std::locale locale_utf8;
extern std::string encode_path(const char *src);
extern std::string decode_path(const char *src);
extern std::string normalize_utf8_nfc(const char *src);
diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp
index e10e136d1..f4c03ef50 100644
--- a/xs/src/libslic3r/utils.cpp
+++ b/xs/src/libslic3r/utils.cpp
@@ -103,14 +103,14 @@ const std::string& data_dir()
std::string config_path(const std::string &file_name)
{
- auto file = boost::filesystem::canonical(boost::filesystem::path(g_data_dir) / file_name).make_preferred();
+ auto file = (boost::filesystem::path(g_data_dir) / file_name).make_preferred();
return file.string();
}
std::string config_path(const std::string &section, const std::string &name)
{
auto file_name = boost::algorithm::iends_with(name, ".ini") ? name : name + ".ini";
- auto file = boost::filesystem::canonical(boost::filesystem::path(g_data_dir) / file_name).make_preferred();
+ auto file = (boost::filesystem::path(g_data_dir) / section / file_name).make_preferred();
return file.string();
}
@@ -228,10 +228,9 @@ std::string decode_path(const char *src)
#endif /* WIN32 */
}
-std::locale locale_utf8(boost::locale::generator().generate(""));
-
std::string normalize_utf8_nfc(const char *src)
{
+ static std::locale locale_utf8(boost::locale::generator().generate(""));
return boost::locale::normalize(src, boost::locale::norm_nfc, locale_utf8);
}
diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp
index b61ce89d2..f978fcbb4 100644
--- a/xs/src/slic3r/GUI/AppConfig.cpp
+++ b/xs/src/slic3r/GUI/AppConfig.cpp
@@ -27,9 +27,7 @@ void AppConfig::reset()
// Override missing or keys with their defaults.
void AppConfig::set_defaults()
{
- // 2) Reset to defaults.
- if (get("version_check").empty())
- set("version_check", "1");
+ // Reset the empty fields to defaults.
if (get("autocenter").empty())
set("autocenter", "1");
// Disable background processing by default as it is not stable.
@@ -38,10 +36,13 @@ void AppConfig::set_defaults()
// If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
// By default, Prusa has the controller hidden.
if (get("no_controller").empty())
- set("no_controller", "0");
+ set("no_controller", "1");
// If set, the "- default -" selections of print/filament/printer are suppressed, if there is a valid preset available.
if (get("no_defaults").empty())
set("no_defaults", "1");
+ // Version check is enabled by default in the config, but it is not implemented yet.
+ if (get("version_check").empty())
+ set("version_check", "1");
}
void AppConfig::load()
@@ -114,13 +115,11 @@ std::string AppConfig::get_last_dir() const
void AppConfig::update_config_dir(const std::string &dir)
{
this->set("recent", "config_directory", dir);
- this->save();
}
void AppConfig::update_skein_dir(const std::string &dir)
{
this->set("recent", "skein_directory", dir);
- this->save();
}
std::string AppConfig::get_last_output_dir(const std::string &alt) const
@@ -138,7 +137,6 @@ std::string AppConfig::get_last_output_dir(const std::string &alt) const
void AppConfig::update_last_output_dir(const std::string &dir)
{
this->set("", "last_output_path", dir);
- this->save();
}
std::string AppConfig::config_path()
diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 17da135a0..12bf48014 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -1,9 +1,14 @@
#include "GUI.hpp"
+#include <assert.h>
+
+#include <boost/algorithm/string/predicate.hpp>
+
#if __APPLE__
#import <IOKit/pwr_mgt/IOPMLib.h>
#elif _WIN32
#include <Windows.h>
+#include "boost/nowide/convert.hpp"
#pragma comment(lib, "user32.lib")
#endif
@@ -34,6 +39,82 @@ void enable_screensaver()
#endif
}
+std::vector<std::string> scan_serial_ports()
+{
+ std::vector<std::string> out;
+#ifdef _WIN32
+ // 1) Open the registry key SERIALCOM.
+ HKEY hKey;
+ LONG lRes = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &hKey);
+ assert(lRes == ERROR_SUCCESS);
+ if (lRes == ERROR_SUCCESS) {
+ // 2) Get number of values of SERIALCOM key.
+ DWORD cValues; // number of values for key
+ {
+ TCHAR achKey[255]; // buffer for subkey name
+ DWORD cbName; // size of name string
+ TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
+ DWORD cchClassName = MAX_PATH; // size of class string
+ DWORD cSubKeys=0; // number of subkeys
+ DWORD cbMaxSubKey; // longest subkey size
+ DWORD cchMaxClass; // longest class string
+ DWORD cchMaxValue; // longest value name
+ DWORD cbMaxValueData; // longest value data
+ DWORD cbSecurityDescriptor; // size of security descriptor
+ FILETIME ftLastWriteTime; // last write time
+ // Get the class name and the value count.
+ lRes = RegQueryInfoKey(
+ hKey, // key handle
+ achClass, // buffer for class name
+ &cchClassName, // size of class string
+ NULL, // reserved
+ &cSubKeys, // number of subkeys
+ &cbMaxSubKey, // longest subkey size
+ &cchMaxClass, // longest class string
+ &cValues, // number of values for this key
+ &cchMaxValue, // longest value name
+ &cbMaxValueData, // longest value data
+ &cbSecurityDescriptor, // security descriptor
+ &ftLastWriteTime); // last write time
+ assert(lRes == ERROR_SUCCESS);
+ }
+ // 3) Read the SERIALCOM values.
+ {
+ DWORD dwIndex = 0;
+ for (int i = 0; i < cValues; ++ i, ++ dwIndex) {
+ wchar_t valueName[2048];
+ DWORD valNameLen = 2048;
+ DWORD dataType;
+ wchar_t data[2048];
+ DWORD dataSize = 4096;
+ lRes = ::RegEnumValueW(hKey, dwIndex, valueName, &valNameLen, nullptr, &dataType, (BYTE*)&data, &dataSize);
+ if (lRes == ERROR_SUCCESS && dataType == REG_SZ && valueName[0] != 0)
+ out.emplace_back(boost::nowide::narrow(data));
+ }
+ }
+ ::RegCloseKey(hKey);
+ }
+#else
+ // UNIX and OS X
+ boost::filesystem::recursive_directory_iterator end;
+ std::initializer_list<const char*> prefixes { "ttyUSB" , "ttyACM", "tty.", "cu.", "rfcomm" };
+ for (boost::filesystem::recursive_directory_iterator it_path(boost::filesystem::path("/dev"));
+ it_path != end; ++ it_path)
+ for (const char *prefix : prefixes)
+ if (boost::starts_with(it_path->string(), std::string("/dev/") + prefix)) {
+ out.emplace_back(path);
+ break;
+ }
+#endif
+
+ out.erase(std::remove_if(out.begin(), out.end(),
+ [](const std::string &key){
+ return boost::starts_with(key, "Bluetooth") || boost::starts_with(key, "FireFly");
+ }),
+ out.end());
+ return out;
+}
+
bool debugged()
{
#ifdef _WIN32
diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp
index 85656c0a3..955a1cd8d 100644
--- a/xs/src/slic3r/GUI/GUI.hpp
+++ b/xs/src/slic3r/GUI/GUI.hpp
@@ -1,10 +1,14 @@
#ifndef slic3r_GUI_hpp_
#define slic3r_GUI_hpp_
+#include <string>
+#include <vector>
+
namespace Slic3r { namespace GUI {
void disable_screensaver();
void enable_screensaver();
+std::vector<std::string> scan_serial_ports();
bool debugged();
void break_to_debugger();
diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp
index d02653a4a..5b42b27a1 100644
--- a/xs/src/slic3r/GUI/Preset.cpp
+++ b/xs/src/slic3r/GUI/Preset.cpp
@@ -1,3 +1,6 @@
+//#undef NDEBUG
+#include <cassert>
+
#include "Preset.hpp"
#include <fstream>
@@ -16,16 +19,9 @@
#include <wx/bmpcbox.h>
#include <wx/wupdlock.h>
+#include "../../libslic3r/libslic3r.h"
#include "../../libslic3r/Utils.hpp"
-#if 0
-#define DEBUG
-#define _DEBUG
-#undef NDEBUG
-#endif
-
-#include <assert.h>
-
namespace Slic3r {
ConfigFileType guess_config_file_type(const boost::property_tree::ptree &tree)
@@ -94,6 +90,19 @@ void Preset::normalize(DynamicPrintConfig &config)
if (nozzle_diameter != nullptr)
// Loaded the Printer settings. Verify, that all extruder dependent values have enough values.
set_num_extruders(config, (unsigned int)nozzle_diameter->values.size());
+ if (config.option("filament_diameter") != nullptr) {
+ // This config contains single or multiple filament presets.
+ // Ensure that the filament preset vector options contain the correct number of values.
+ size_t n = (nozzle_diameter == nullptr) ? 1 : nozzle_diameter->values.size();
+ const auto &defaults = FullPrintConfig::defaults();
+ for (const std::string &key : Preset::filament_options()) {
+ auto *opt = config.option(key, false);
+ assert(opt != nullptr);
+ assert(opt->is_vector());
+ if (opt != nullptr && opt->is_vector())
+ static_cast<ConfigOptionVectorBase*>(opt)->resize(n, defaults.option(key));
+ }
+ }
}
// Load a config file, return a C++ class Slic3r::DynamicPrintConfig with $keys initialized from the config file.
@@ -247,7 +256,6 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri
}
}
std::sort(m_presets.begin() + 1, m_presets.end());
- m_presets.front().is_visible = ! m_default_suppressed || m_presets.size() > 1;
this->select_preset(first_visible_idx());
}
@@ -255,19 +263,22 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri
// and select it, losing previous modifications.
Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select)
{
+ DynamicPrintConfig cfg(this->default_preset().config);
+ cfg.apply(config, true);
+ return this->load_preset(path, name, std::move(cfg));
+}
+
+Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select)
+{
Preset key(m_type, name);
auto it = std::lower_bound(m_presets.begin(), m_presets.end(), key);
- if (it != m_presets.end() && it->name == name) {
- // The preset with the same name was found.
- it->is_dirty = false;
- } else {
+ if (it == m_presets.end() || it->name != name)
it = m_presets.emplace(it, Preset(m_type, name, false));
- }
Preset &preset = *it;
preset.file = path;
- preset.config = this->default_preset().config;
+ preset.config = std::move(config);
preset.loaded = true;
- this->get_selected_preset().is_dirty = false;
+ preset.is_dirty = false;
if (select)
this->select_preset_by_name(name, true);
return preset;
@@ -275,6 +286,8 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string
void PresetCollection::save_current_preset(const std::string &new_name)
{
+ // 1) Find the preset with a new_name or create a new one,
+ // initialize it with the edited config.
Preset key(m_type, new_name, false);
auto it = std::lower_bound(m_presets.begin(), m_presets.end(), key);
if (it != m_presets.end() && it->name == key.name) {
@@ -285,37 +298,39 @@ void PresetCollection::save_current_preset(const std::string &new_name)
return;
// Overwriting an existing preset.
preset.config = std::move(m_edited_preset.config);
- m_idx_selected = it - m_presets.begin();
} else {
// Creating a new preset.
- m_idx_selected = m_presets.insert(it, m_edited_preset) - m_presets.begin();
- Preset &preset = m_presets[m_idx_selected];
+ Preset &preset = *m_presets.insert(it, m_edited_preset);
std::string file_name = new_name;
if (! boost::iends_with(file_name, ".ini"))
file_name += ".ini";
preset.name = new_name;
preset.file = (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string();
}
- m_edited_preset = m_presets[m_idx_selected];
- m_presets[m_idx_selected].save();
- m_presets.front().is_visible = ! m_default_suppressed || m_idx_selected > 0;
+ // 2) Activate the saved preset.
+ this->select_preset_by_name(new_name, true);
+ // 2) Store the active preset to disk.
+ this->get_selected_preset().save();
}
void PresetCollection::delete_current_preset()
{
const Preset &selected = this->get_selected_preset();
- if (selected.is_default || selected.is_external)
+ if (selected.is_default)
return;
- // Erase the preset file.
- boost::nowide::remove(selected.file.c_str());
+ if (! selected.is_external) {
+ // Erase the preset file.
+ boost::nowide::remove(selected.file.c_str());
+ }
// Remove the preset from the list.
m_presets.erase(m_presets.begin() + m_idx_selected);
// Find the next visible preset.
- m_presets.front().is_visible = ! m_default_suppressed || m_presets.size() > 1;
- for (; m_idx_selected < m_presets.size() && ! m_presets[m_idx_selected].is_visible; ++ m_idx_selected) ;
- if (m_idx_selected == m_presets.size())
- m_idx_selected = this->first_visible_idx();
- m_edited_preset = m_presets[m_idx_selected];
+ size_t new_selected_idx = m_idx_selected;
+ if (new_selected_idx < m_presets.size())
+ for (; new_selected_idx < m_presets.size() && ! m_presets[new_selected_idx].is_visible; ++ new_selected_idx) ;
+ if (new_selected_idx == m_presets.size())
+ for (--new_selected_idx; new_selected_idx > 0 && !m_presets[new_selected_idx].is_visible; --new_selected_idx);
+ this->select_preset(new_selected_idx);
}
bool PresetCollection::load_bitmap_default(const std::string &file_name)
@@ -337,7 +352,7 @@ Preset* PresetCollection::find_preset(const std::string &name, bool first_visibl
// Return index of the first visible preset. Certainly at least the '- default -' preset shall be visible.
size_t PresetCollection::first_visible_idx() const
{
- size_t idx = 0;
+ size_t idx = m_default_suppressed ? 1 : 0;
for (; idx < this->m_presets.size(); ++ idx)
if (m_presets[idx].is_visible)
break;
@@ -438,11 +453,13 @@ bool PresetCollection::update_dirty_ui(wxChoice *ui)
Preset& PresetCollection::select_preset(size_t idx)
{
+ for (Preset &preset : m_presets)
+ preset.is_dirty = false;
if (idx >= m_presets.size())
idx = first_visible_idx();
m_idx_selected = idx;
m_edited_preset = m_presets[idx];
- m_presets.front().is_visible = ! m_default_suppressed || m_idx_selected > 0;
+ m_presets.front().is_visible = ! m_default_suppressed || m_idx_selected == 0;
return m_presets[idx];
}
@@ -458,7 +475,7 @@ bool PresetCollection::select_preset_by_name(const std::string &name_w_suffix, b
idx = it - m_presets.begin();
else {
// Find the first visible preset.
- for (size_t i = 0; i < m_presets.size(); ++ i)
+ for (size_t i = m_default_suppressed ? 1 : 0; i < m_presets.size(); ++ i)
if (m_presets[i].is_visible) {
idx = i;
break;
diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp
index 85280eccf..a9bc8812c 100644
--- a/xs/src/slic3r/GUI/Preset.hpp
+++ b/xs/src/slic3r/GUI/Preset.hpp
@@ -121,6 +121,7 @@ public:
// Load a preset from an already parsed config file, insert it into the sorted sequence of presets
// and select it, losing previous modifications.
Preset& load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select = true);
+ Preset& load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select = true);
// Save the preset under a new name. If the name is different from the old one,
// a new preset is stored into the list of presets.
diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp
index 4abb7a88f..4cfeb5fad 100644
--- a/xs/src/slic3r/GUI/PresetBundle.cpp
+++ b/xs/src/slic3r/GUI/PresetBundle.cpp
@@ -1,3 +1,6 @@
+//#undef NDEBUGc
+#include <cassert>
+
#include "PresetBundle.hpp"
#include <fstream>
@@ -17,10 +20,10 @@
#include <wx/bmpcbox.h>
#include <wx/wupdlock.h>
+#include "../../libslic3r/libslic3r.h"
+#include "../../libslic3r/PlaceholderParser.hpp"
#include "../../libslic3r/Utils.hpp"
-#include <assert.h>
-
namespace Slic3r {
PresetBundle::PresetBundle() :
@@ -117,6 +120,15 @@ void PresetBundle::export_selections(AppConfig &config)
config.set("presets", "printer", printers.get_selected_preset().name);
}
+void PresetBundle::export_selections(PlaceholderParser &pp)
+{
+ assert(filament_presets.size() >= 1);
+ assert(filament_presets.size() > 1 || filaments.get_selected_preset().name == filament_presets.front());
+ pp.set("print_preset", prints.get_selected_preset().name);
+ pp.set("filament_preset", filament_presets);
+ pp.set("printer_preset", printers.get_selected_preset().name);
+}
+
bool PresetBundle::load_compatible_bitmaps(const std::string &path_bitmap_compatible, const std::string &path_bitmap_incompatible)
{
bool loaded_compatible = m_bitmapCompatible ->LoadFile(
@@ -193,6 +205,15 @@ DynamicPrintConfig PresetBundle::full_config() const
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
void PresetBundle::load_config_file(const std::string &path)
{
+ if (boost::iends_with(path, ".gcode") || boost::iends_with(path, ".g")) {
+ DynamicPrintConfig config;
+ config.apply(FullPrintConfig::defaults());
+ config.load_from_gcode(path);
+ Preset::normalize(config);
+ load_config_file_config(path, std::move(config));
+ return;
+ }
+
// 1) Try to load the config file into a boost property tree.
boost::property_tree::ptree tree;
try {
@@ -211,36 +232,37 @@ void PresetBundle::load_config_file(const std::string &path)
throw std::runtime_error(std::string("Unknown configuration file type: ") + path);
case CONFIG_FILE_TYPE_APP_CONFIG:
throw std::runtime_error(std::string("Invalid configuration file: ") + path + ". This is an application config file.");
- case CONFIG_FILE_TYPE_CONFIG:
- load_config_file_config(path, tree);
- break;
+ case CONFIG_FILE_TYPE_CONFIG:
+ {
+ // Initialize a config from full defaults.
+ DynamicPrintConfig config;
+ config.apply(FullPrintConfig::defaults());
+ config.load(tree);
+ Preset::normalize(config);
+ load_config_file_config(path, std::move(config));
+ break;
+ }
case CONFIG_FILE_TYPE_CONFIG_BUNDLE:
- load_config_file_config_bundle(path, tree);
+ load_config_file_config_bundle(path, tree);
break;
}
}
// Load a config file from a boost property_tree. This is a private method called from load_config_file.
-void PresetBundle::load_config_file_config(const std::string &path, const boost::property_tree::ptree &tree)
+void PresetBundle::load_config_file_config(const std::string &path, const DynamicPrintConfig &config)
{
- // 1) Initialize a config from full defaults.
- DynamicPrintConfig config;
- config.apply(FullPrintConfig());
- config.load(tree);
- Preset::normalize(config);
-
- // 2) Create a name from the file name.
+ // 1) Create a name from the file name.
// Keep the suffix (.ini, .gcode, .amf, .3mf etc) to differentiate it from the normal profiles.
std::string name = boost::filesystem::path(path).filename().string();
- // 3) If the loading succeeded, split and load the config into print / filament / printer settings.
+ // 2) If the loading succeeded, split and load the config into print / filament / printer settings.
// First load the print and printer presets.
for (size_t i_group = 0; i_group < 2; ++ i_group) {
PresetCollection &presets = (i_group == 0) ? this->prints : this->printers;
presets.load_preset(path, name, config).is_external = true;
}
- // Now load the filaments. If there are multiple filament presets, split them and load them.
+ // 3) Now load the filaments. If there are multiple filament presets, split them and load them.
auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(config.option("nozzle_diameter"));
auto *filament_diameter = dynamic_cast<const ConfigOptionFloats*>(config.option("filament_diameter"));
size_t num_extruders = std::min(nozzle_diameter->values.size(), filament_diameter->values.size());
@@ -253,7 +275,7 @@ void PresetBundle::load_config_file_config(const std::string &path, const boost:
std::vector<DynamicPrintConfig> configs(num_extruders, this->filaments.default_preset().config);
// loop through options and scatter them into configs.
for (const t_config_option_key &key : this->filaments.default_preset().config.keys()) {
- const ConfigOption *other_opt = config.option(key, false);
+ const ConfigOption *other_opt = config.option(key);
if (other_opt == nullptr)
continue;
if (other_opt->is_scalar()) {
@@ -273,7 +295,7 @@ void PresetBundle::load_config_file_config(const std::string &path, const boost:
else
sprintf(suffix, " (%d)", i);
// Load all filament presets, but only select the first one in the preset dialog.
- this->filaments.load_preset(path, name + suffix, configs[i], i == 0).is_external = true;
+ this->filaments.load_preset(path, name + suffix, std::move(configs[i]), i == 0).is_external = true;
filament_presets.emplace_back(name + suffix);
}
}
@@ -301,7 +323,7 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const
// Generate a new unique name.
}
if (! new_name.empty())
- this->prints.load_preset(path, new_name, tmp_bundle.prints.get_selected_preset().config);
+ this->prints.load_preset(path, new_name, std::move(tmp_bundle.prints.get_selected_preset().config));
}
}
@@ -369,8 +391,9 @@ size_t PresetBundle::load_configbundle(const std::string &path)
DynamicPrintConfig config(presets->default_preset().config);
for (auto &kvp : section.second)
config.set_deserialize(kvp.first, kvp.second.data());
+ Preset::normalize(config);
// Load the preset into the list of presets, save it to disk.
- presets->load_preset(Slic3r::config_path(presets->name(), preset_name), preset_name, config, false).save();
+ presets->load_preset(Slic3r::config_path(presets->name(), preset_name), preset_name, std::move(config), false).save();
++ presets_loaded;
}
}
@@ -386,7 +409,7 @@ size_t PresetBundle::load_configbundle(const std::string &path)
this->update_multi_material_filament_presets();
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
- this->filament_presets[i] = filaments.first_visible().name;
+ this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
return presets_loaded;
}
@@ -396,7 +419,6 @@ void PresetBundle::update_multi_material_filament_presets()
auto *nozzle_diameter = static_cast<const ConfigOptionFloats*>(printers.get_edited_preset().config.option("nozzle_diameter"));
size_t num_extruders = nozzle_diameter->values.size();
// Verify validity of the current filament presets.
- printf("PresetBundle::update_multi_material_filament_presets, old: %d, new: %d\n", int(this->filament_presets.size()), int(num_extruders));
for (size_t i = 0; i < std::min(this->filament_presets.size(), num_extruders); ++ i)
this->filament_presets[i] = this->filaments.find_preset(this->filament_presets[i], true)->name;
// Append the rest of filament presets.
diff --git a/xs/src/slic3r/GUI/PresetBundle.hpp b/xs/src/slic3r/GUI/PresetBundle.hpp
index 7add3055d..b1077c11c 100644
--- a/xs/src/slic3r/GUI/PresetBundle.hpp
+++ b/xs/src/slic3r/GUI/PresetBundle.hpp
@@ -6,6 +6,8 @@
namespace Slic3r {
+class PlaceholderParser;
+
// Bundle of Print + Filament + Printer presets.
class PresetBundle
{
@@ -23,6 +25,8 @@ public:
void load_selections(const AppConfig &config);
// Export selections (current print, current filaments, current printer) into config.ini
void export_selections(AppConfig &config);
+ // Export selections (current print, current filaments, current printer) into a placeholder parser.
+ void export_selections(PlaceholderParser &pp);
PresetCollection prints;
PresetCollection filaments;
@@ -31,6 +35,9 @@ public:
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
std::vector<std::string> filament_presets;
+ bool has_defauls_only() const
+ { return prints.size() <= 1 && filaments.size() <= 1 && printers.size() <= 1; }
+
DynamicPrintConfig full_config() const;
// Load an external config file containing the print, filament and printer presets.
@@ -66,7 +73,7 @@ public:
void update_multi_material_filament_presets();
private:
- void load_config_file_config(const std::string &path, const boost::property_tree::ptree &tree);
+ void load_config_file_config(const std::string &path, const DynamicPrintConfig &config);
void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree);
bool load_compatible_bitmaps(const std::string &path_bitmap_compatible, const std::string &path_bitmap_incompatible);
diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp
index 875c49e26..ce3c178a1 100644
--- a/xs/xsp/GUI.xsp
+++ b/xs/xsp/GUI.xsp
@@ -14,6 +14,9 @@ void disable_screensaver()
void enable_screensaver()
%code{% Slic3r::GUI::enable_screensaver(); %};
+std::vector<std::string> scan_serial_ports()
+ %code{% RETVAL=Slic3r::GUI::scan_serial_ports(); %};
+
bool debugged()
%code{% RETVAL=Slic3r::GUI::debugged(); %};
diff --git a/xs/xsp/GUI_AppConfig.xsp b/xs/xsp/GUI_AppConfig.xsp
index d220c3580..8162b9a5e 100644
--- a/xs/xsp/GUI_AppConfig.xsp
+++ b/xs/xsp/GUI_AppConfig.xsp
@@ -13,8 +13,22 @@
void reset();
void set_defaults();
- void load();
- void save();
+ void load()
+ %code%{
+ try {
+ THIS->load();
+ } catch (std::exception& e) {
+ croak("Loading an application config file failed:\n%s\n", e.what());
+ }
+ %};
+ void save()
+ %code%{
+ try {
+ THIS->save();
+ } catch (std::exception& e) {
+ croak("Saving an application config file failed:\n%s\n", e.what());
+ }
+ %};
bool exists();
bool dirty();
diff --git a/xs/xsp/GUI_Preset.xsp b/xs/xsp/GUI_Preset.xsp
index 34184a588..e76b5c704 100644
--- a/xs/xsp/GUI_Preset.xsp
+++ b/xs/xsp/GUI_Preset.xsp
@@ -52,10 +52,25 @@
bool update_dirty_ui(SV *ui)
%code%{ RETVAL = THIS->update_dirty_ui((wxChoice*)wxPli_sv_2_object(aTHX_ ui, "Wx::Choice")); %};
+ void select_preset(int idx);
bool select_preset_by_name(char *name) %code%{ RETVAL = THIS->select_preset_by_name(name, true); %};
- void save_current_preset(char *new_name);
- void delete_current_preset();
+ void save_current_preset(char *new_name)
+ %code%{
+ try {
+ THIS->save_current_preset(new_name);
+ } catch (std::exception& e) {
+ croak("Error saving a preset %s:\n%s\n", new_name, e.what());
+ }
+ %};
+ void delete_current_preset()
+ %code%{
+ try {
+ THIS->delete_current_preset();
+ } catch (std::exception& e) {
+ croak("Error deleting a preset file %s:\n%s\n", THIS->get_selected_preset().file.c_str(), e.what());
+ }
+ %};
%{
@@ -88,24 +103,61 @@ PresetCollection::presets_hash()
%}
};
-
%name{Slic3r::GUI::PresetBundle} class PresetBundle {
PresetBundle();
~PresetBundle();
- void setup_directories();
- void load_presets(const char *dir_path);
- void load_config_file(const char *path);
- size_t load_configbundle(const char *path);
- void export_configbundle(char *path);
+ void setup_directories()
+ %code%{
+ try {
+ THIS->setup_directories();
+ } catch (std::exception& e) {
+ croak("Cannot create configuration directories:\n%s\n", e.what());
+ }
+ %};
+ void load_presets(const char *dir_path)
+ %code%{
+ try {
+ THIS->load_presets(dir_path);
+ } catch (std::exception& e) {
+ croak("Loading of Slic3r presets from %s failed:\n%s\n", dir_path, e.what());
+ }
+ %};
+ void load_config_file(const char *path)
+ %code%{
+ try {
+ THIS->load_config_file(path);
+ } catch (std::exception& e) {
+ croak("Loading a configuration file %s failed:\n%s\n", path, e.what());
+ }
+ %};
+ size_t load_configbundle(const char *path)
+ %code%{
+ try {
+ RETVAL = THIS->load_configbundle(path);
+ } catch (std::exception& e) {
+ croak("Loading of a config bundle %s failed:\n%s\n", path, e.what());
+ }
+ %};
+ void export_configbundle(char *path)
+ %code%{
+ try {
+ THIS->export_configbundle(path);
+ } catch (std::exception& e) {
+ croak("Export of a config bundle %s failed:\n%s\n", path, e.what());
+ }
+ %};
+
void set_default_suppressed(bool default_suppressed);
void load_selections (AppConfig *config) %code%{ THIS->load_selections(*config); %};
void export_selections(AppConfig *config) %code%{ THIS->export_selections(*config); %};
+ void export_selections_pp(PlaceholderParser *pp) %code%{ THIS->export_selections(*pp); %};
Ref<PresetCollection> print() %code%{ RETVAL = &THIS->prints; %};
Ref<PresetCollection> filament() %code%{ RETVAL = &THIS->filaments; %};
Ref<PresetCollection> printer() %code%{ RETVAL = &THIS->printers; %};
+ bool has_defauls_only();
std::vector<std::string> filament_presets() %code%{ RETVAL = THIS->filament_presets; %};
void set_filament_preset(int idx, const char *name);