diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 16875b6b4..a402dc0c3 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -88,6 +88,7 @@ our $Settings = { no_controller => 0, threads => $Slic3r::Config::Options->{threads}{default}, color_toolpaths_by => 'role', + tabbed_preset_editors => 1, }, }; diff --git a/lib/Slic3r/GUI/Controller.pm b/lib/Slic3r/GUI/Controller.pm index 4e8e42578..dfb328149 100644 --- a/lib/Slic3r/GUI/Controller.pm +++ b/lib/Slic3r/GUI/Controller.pm @@ -47,13 +47,13 @@ sub new { delete $presets{$_} for map $_->printer_name, @panels; foreach my $preset_name (sort keys %presets) { - my $config = $presets{$preset_name}->dirty_config; - next if !$config->serial_port; + my $preset = $presets{$preset_name}; + next if !$preset->dirty_config->serial_port; my $id = &Wx::NewId(); $menu->Append($id, $preset_name); EVT_MENU($menu, $id, sub { - $self->add_printer($preset_name, $config); + $self->add_printer($preset); }); } $self->PopupMenu($menu, $btn->GetPosition); @@ -100,10 +100,10 @@ sub OnActivate { # get all available presets my %presets = (); - { - my %all = map { $_->name => $_ } @{wxTheApp->presets->{printer}}; - my %configs = map { my $name = $_; $name => $all{$name}->load_config } keys %all; - %presets = map { $_ => $configs{$_} } grep $configs{$_}->serial_port, keys %all; + foreach my $preset (@{wxTheApp->presets->{printer}}) { + $preset->load_config; + next if !$preset->dirty_config->serial_port; + $presets{$preset->name} = $preset; } # decide which ones we want to keep @@ -124,7 +124,7 @@ sub OnActivate { # enable printers whose port is available my %ports = map { $_ => 1 } wxTheApp->scan_serial_ports; $active{$_} = 1 - for grep exists $ports{$presets{$_}->serial_port}, keys %presets; + for grep exists $ports{$presets{$_}->dirty_config->serial_port}, keys %presets; } if (!%active && $self->_selected_printer_preset) { # enable currently selected printer if it is configured @@ -140,7 +140,7 @@ sub OnActivate { $self->{sizer}->DetachWindow($panel); $panel->Destroy; } - $self->add_printer($_, $presets{$_}) for sort keys %active; + $self->add_printer($presets{$_}) for sort keys %active; # show/hide the warning about no printers $self->{text_no_printers}->Show(!%presets); @@ -156,16 +156,16 @@ sub OnActivate { } sub add_printer { - my ($self, $printer_name, $config) = @_; + my ($self, $preset) = @_; # check that printer doesn't exist already foreach my $panel ($self->print_panels) { - if ($panel->printer_name eq $printer_name) { + if ($panel->printer_name eq $preset->name) { return $panel; } } - my $printer_panel = Slic3r::GUI::Controller::PrinterPanel->new($self, $printer_name, $config); + my $printer_panel = Slic3r::GUI::Controller::PrinterPanel->new($self, $preset->name, $preset); $self->{sizer}->Prepend($printer_panel, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 10); $self->Layout; diff --git a/lib/Slic3r/GUI/Controller/PrinterPanel.pm b/lib/Slic3r/GUI/Controller/PrinterPanel.pm index 9e2dc211d..7d9e8a296 100644 --- a/lib/Slic3r/GUI/Controller/PrinterPanel.pm +++ b/lib/Slic3r/GUI/Controller/PrinterPanel.pm @@ -16,11 +16,11 @@ use constant STATUS_TIMER_INTERVAL => 1000; # milliseconds use constant TEMP_TIMER_INTERVAL => 5000; # milliseconds sub new { - my ($class, $parent, $printer_name, $config) = @_; + my ($class, $parent, $printer_name, $preset) = @_; my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, [500, 250]); $self->printer_name($printer_name || 'Printer'); - $self->config($config); + $self->config($preset->dirty_config); $self->manual_control_config({ xy_travel_speed => 130, z_travel_speed => 10, @@ -103,7 +103,7 @@ sub new { } my $serial_port_sizer = Wx::BoxSizer->new(wxHORIZONTAL); { - $self->{serial_port_combobox} = Wx::ComboBox->new($self, -1, $config->serial_port, wxDefaultPosition, wxDefaultSize, []); + $self->{serial_port_combobox} = Wx::ComboBox->new($self, -1, $self->config->serial_port, wxDefaultPosition, wxDefaultSize, []); $self->{serial_port_combobox}->SetFont($Slic3r::GUI::small_font); $self->update_serial_ports; $serial_port_sizer->Add($self->{serial_port_combobox}, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 1); @@ -125,7 +125,7 @@ sub new { } my $serial_speed_sizer = Wx::BoxSizer->new(wxHORIZONTAL); { - $self->{serial_speed_combobox} = Wx::ComboBox->new($self, -1, $config->serial_speed, wxDefaultPosition, wxDefaultSize, + $self->{serial_speed_combobox} = Wx::ComboBox->new($self, -1, $self->config->serial_speed, wxDefaultPosition, wxDefaultSize, ["57600", "115200", "250000"]); $self->{serial_speed_combobox}->SetFont($Slic3r::GUI::small_font); $serial_speed_sizer->Add($self->{serial_speed_combobox}, 0, wxALIGN_CENTER_VERTICAL, 0); diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index fc7aef322..83f53b916 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -8,9 +8,10 @@ use utf8; use File::Basename qw(basename dirname); use List::Util qw(min); use Slic3r::Geometry qw(X Y Z); -use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog - :font :icon wxTheApp); -use Wx::Event qw(EVT_CLOSE EVT_NOTEBOOK_PAGE_CHANGED); +use Wx qw(:frame :bitmap :id :misc :panel :sizer :menu :dialog :filedialog + :font :icon :aui wxTheApp); +use Wx::AUI; +use Wx::Event qw(EVT_CLOSE EVT_AUINOTEBOOK_PAGE_CHANGED EVT_AUINOTEBOOK_PAGE_CLOSE); use base 'Wx::Frame'; our $qs_last_input_file; @@ -28,6 +29,7 @@ sub new { } $self->{loaded} = 0; + $self->{preset_editor_tabs} = {}; # group => panel # initialize tabpanel and menubar $self->_init_tabpanel; @@ -92,10 +94,24 @@ sub new { sub _init_tabpanel { my ($self) = @_; - $self->{tabpanel} = my $panel = Wx::Notebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL); - EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{tabpanel}, sub { - my $panel = $self->{tabpanel}->GetCurrentPage; + $self->{tabpanel} = my $panel = Wx::AuiNotebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TOP); + EVT_AUINOTEBOOK_PAGE_CHANGED($self, $self->{tabpanel}, sub { + my $panel = $self->{tabpanel}->GetPage($self->{tabpanel}->GetSelection); $panel->OnActivate if $panel->can('OnActivate'); + if ($self->{tabpanel}->GetSelection > 1) { + $self->{tabpanel}->SetWindowStyle($self->{tabpanel}->GetWindowStyleFlag | wxAUI_NB_CLOSE_ON_ACTIVE_TAB); + } else { + $self->{tabpanel}->SetWindowStyle($self->{tabpanel}->GetWindowStyleFlag & ~wxAUI_NB_CLOSE_ON_ACTIVE_TAB); + } + }); + EVT_AUINOTEBOOK_PAGE_CLOSE($self, $self->{tabpanel}, sub { + my $panel = $self->{tabpanel}->GetPage($self->{tabpanel}->GetSelection); + if ($panel->isa('Slic3r::GUI::PresetEditor')) { + delete $self->{preset_editor_tabs}{$panel->name}; + } + wxTheApp->CallAfter(sub { + $self->{tabpanel}->SetSelection(0); + }); }); $panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel), "Plater"); diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 2cd8e52af..aa294ad54 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -49,7 +49,7 @@ sub new { my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); $self->{config} = Slic3r::Config->new_from_defaults(qw( bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width - serial_port serial_speed octoprint_host octoprint_apikey overridable filament_colour + serial_port serial_speed octoprint_host octoprint_apikey shortcuts filament_colour )); $self->{model} = Slic3r::Model->new; $self->{print} = Slic3r::Print->new; @@ -366,9 +366,37 @@ sub new { { my $o = $self->{settings_override_panel} = Slic3r::GUI::Plater::OverrideSettingsPanel->new($self, on_change => sub { + my ($opt_key) = @_; + + my ($preset) = $self->selected_presets('print'); + $preset->load_config; + + # If this option is not in the override panel it means it was manually deleted, + # so let's restore the profile value. + if (!$self->{settings_override_config}->has($opt_key)) { + $preset->_dirty_config->set($opt_key, $preset->_config->get($opt_key)); + } else { + # Apply the overrides to the current Print preset, potentially making it dirty + $preset->_dirty_config->apply($self->{settings_override_config}); + + # If this is a configured shortcut (and not just a dirty option), + # save it now. + if (any { $_ eq $opt_key } @{$preset->dirty_config->shortcuts}) { + $preset->save([$opt_key]); + } + } + + $self->load_presets; $self->config_changed; + + # Reload the open tab if any + if (my $print_tab = $self->GetFrame->{preset_editor_tabs}{print}) { + $print_tab->load_presets; + $print_tab->reload_preset; + } }); - $o->set_editable(1); + $o->can_add(0); + $o->can_delete(1); $o->set_opt_keys([ Slic3r::GUI::PresetEditor::Print->options ]); $self->{settings_override_config} = Slic3r::Config->new; $o->set_default_config($self->{settings_override_config}); @@ -534,6 +562,14 @@ sub _on_change_combobox { return 0 if !$self->prompt_unsaved_changes; } wxTheApp->CallAfter(sub { + # Close the preset editor tab if any + if (exists $self->GetFrame->{preset_editor_tabs}{$group}) { + my $tabpanel = $self->GetFrame->{tabpanel}; + $tabpanel->DeletePage($tabpanel->GetPageIndex($self->GetFrame->{preset_editor_tabs}{$group})); + delete $self->GetFrame->{preset_editor_tabs}{$group}; + $tabpanel->SetSelection(0); # without this, a newly created tab will not be selected by wx + } + $self->_on_select_preset($group); # This will remove the "(modified)" mark from any dirty preset handled here. @@ -562,31 +598,19 @@ sub _on_select_preset { my $o_config = $self->{settings_override_config}; my $o_panel = $self->{settings_override_panel}; - if ($changed) { - # Preserve current options if re-selecting the same preset - $o_config->clear; - } + my $shortcuts = $config->get('shortcuts'); - my $overridable = $config->get('overridable'); - - # Add/remove options (we do it this way for preserving current options) - foreach my $opt_key (@$overridable) { - # Populate option with the default value taken from configuration - # (re-set the override always, because if we here it means user - # switched to this preset or opened/closed the editor, so he expects - # the new values set in the editor to be used). + # Re-populate the override panel with the configured shortcuts + # and the dirty options. + $o_config->clear; + foreach my $opt_key (@$shortcuts, $presets[0]->dirty_options) { + # Don't add shortcut for shortcuts! + next if $opt_key eq 'shortcuts'; $o_config->set($opt_key, $config->get($opt_key)); } - foreach my $opt_key (@{$o_config->get_keys}) { - # Keep options listed among overridable and options added on the fly - if ((none { $_ eq $opt_key } @$overridable) - && (any { $_ eq $opt_key } $o_panel->fixed_options)) { - $o_config->erase($opt_key); - } - } $o_panel->set_default_config($config); - $o_panel->set_fixed_options(\@$overridable); + $o_panel->set_fixed_options(\@$shortcuts); $o_panel->update_optgroup; } elsif ($group eq 'printer') { # reload print and filament settings to honor their compatible_printer options @@ -699,7 +723,7 @@ sub load_presets { } } - $self->{print}->placeholder_parser->set("${group}_preset", [ @preset_names ]); + $self->{print}->placeholder_parser->set_multiple("${group}_preset", [ @preset_names ]); } } @@ -742,19 +766,54 @@ sub selected_presets { sub show_preset_editor { my ($self, $group, $i) = @_; - my $class = "Slic3r::GUI::PresetEditorDialog::" . ucfirst($group); - my $dlg = $class->new($self); + wxTheApp->CallAfter(sub { + my @presets = $self->selected_presets($group); - my @presets = $self->selected_presets($group); - $dlg->preset_editor->select_preset_by_name($presets[$i // 0]->name); - $dlg->ShowModal; + my $preset_editor; + my $dlg; + my $mainframe = $self->GetFrame; + my $tabpanel = $mainframe->{tabpanel}; + if (exists $mainframe->{preset_editor_tabs}{$group}) { + # we already have an open editor + $tabpanel->SetSelection($tabpanel->GetPageIndex($mainframe->{preset_editor_tabs}{$group})); + return; + } elsif ($Slic3r::GUI::Settings->{_}{tabbed_preset_editors}) { + my $class = "Slic3r::GUI::PresetEditor::" . ucfirst($group); + $mainframe->{preset_editor_tabs}{$group} = $preset_editor = $class->new($self->GetFrame); + $tabpanel->AddPage($preset_editor, ucfirst($group) . " Settings", 1); + } else { + my $class = "Slic3r::GUI::PresetEditorDialog::" . ucfirst($group); + $dlg = $class->new($self); + $preset_editor = $dlg->preset_editor; + } - # Re-load the presets as they might have changed. - $self->load_presets; + $preset_editor->select_preset_by_name($presets[$i // 0]->name); + $preset_editor->on_value_change(sub { + # Re-load the presets in order to toggle the (modified) suffix + $self->load_presets; + + # Update shortcuts + $self->_on_select_preset($group); + + # Use the new config wherever we actually use its contents + $self->config_changed; + }); + my $cb = sub { + my ($group, $preset) = @_; + + # Re-load the presets as they might have changed. + $self->load_presets; + + # Select the preset in plater too + $self->select_preset_by_name($preset->name, $group, $i, 1); + }; + $preset_editor->on_select_preset($cb); + $preset_editor->on_save_preset($cb); - # Select the preset that was last selected in the editor. - $self->select_preset_by_name - ($dlg->preset_editor->current_preset->name, $group, $i, 1); + if ($dlg) { + $dlg->ShowModal; + } + }); } # Returns the current config by merging the selected presets and the overrides. @@ -765,7 +824,7 @@ sub config { my $config = Slic3r::Config->new_from_defaults; # get defaults also for the values tracked by the Plater's config - # (for example 'overridable') + # (for example 'shortcuts') $config->apply(Slic3r::Config->new_from_defaults(@{$self->{config}->get_keys})); my %classes = map { $_ => "Slic3r::GUI::PresetEditor::".ucfirst($_) } diff --git a/lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm b/lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm index f803fb8f8..34b9eb6f4 100644 --- a/lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm +++ b/lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm @@ -34,7 +34,8 @@ sub new { $self->{default_config} = Slic3r::Config->new; $self->{config} = Slic3r::Config->new; $self->{on_change} = $params{on_change}; - $self->{editable} = 1; + $self->{can_add} = 1; + $self->{can_delete} = 1; $self->{fixed_options} = {}; $self->{sizer} = Wx::BoxSizer->new(wxVERTICAL); @@ -144,7 +145,7 @@ sub update_optgroup { $self->{options_sizer}->Clear(1); return if !defined $self->{config}; - $self->{btn_add}->Show($self->{editable}); + $self->{btn_add}->Show($self->{can_add}); my %categories = (); foreach my $opt_key (@{$self->{config}->get_keys}) { @@ -173,7 +174,7 @@ sub update_optgroup { my ($opt_key, $opt_index) = @{ $optgroup->_opt_map->{$opt_id} }; # disallow deleting fixed options - return undef if $self->{fixed_options}{$opt_key} || !$self->{editable}; + return undef if $self->{fixed_options}{$opt_key} || !$self->{can_delete}; my $btn = Wx::BitmapButton->new($self, -1, Wx::Bitmap->new($Slic3r::var->("delete.png"), wxBITMAP_TYPE_PNG), wxDefaultPosition, wxDefaultSize, Wx::wxBORDER_NONE); @@ -210,11 +211,27 @@ sub disable { $self->Disable; } -# Shows or hides the Add button. +# Shows or hides the Add/Delete buttons. sub set_editable { my ($self, $editable) = @_; - $self->{editable} = $editable; + $self->{can_add} = $self->{can_delete} = $editable; +} + +# Shows or hides the Add button. +sub can_add { + my ($self, $can) = @_; + + $self->{can_add} = $can if defined $can; + return $can; +} + +# Shows or hides the Delete button. +sub can_delete { + my ($self, $can) = @_; + + $self->{can_delete} = $can if defined $can; + return $can; } 1; diff --git a/lib/Slic3r/GUI/Preferences.pm b/lib/Slic3r/GUI/Preferences.pm index 9c96efa3a..d4495d77b 100644 --- a/lib/Slic3r/GUI/Preferences.pm +++ b/lib/Slic3r/GUI/Preferences.pm @@ -71,6 +71,13 @@ sub new { 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}, )); + $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( + opt_id => 'tabbed_preset_editors', + type => 'bool', + label => 'Display profile editors as tabs', + tooltip => 'When opening a profile editor, it will be shown in a dialog or in a tab according to this option.', + default => $Slic3r::GUI::Settings->{_}{tabbed_preset_editors}, + )); my $sizer = Wx::BoxSizer->new(wxVERTICAL); $sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); diff --git a/lib/Slic3r/GUI/Preset.pm b/lib/Slic3r/GUI/Preset.pm index 5bdd0f20e..0dfc33df8 100644 --- a/lib/Slic3r/GUI/Preset.pm +++ b/lib/Slic3r/GUI/Preset.pm @@ -94,7 +94,7 @@ sub prompt_unsaved_changes { if ($res == wxID_CANCEL) { return 0; } elsif ($res == wxID_YES) { - return $self->save($self->default ? undef : $self->name); + return $self->default ? $self->save_prompt($parent) : $self->save; } elsif ($res == wxID_NO) { $self->dismiss_changes; return 1; @@ -104,20 +104,29 @@ sub prompt_unsaved_changes { return 1; } +sub save_prompt { + my ($self, $parent) = @_; + + my $default_name = $self->default ? 'Untitled' : $self->name; + $default_name =~ s/\.ini$//i; + + my $dlg = Slic3r::GUI::SavePresetWindow->new($parent, + default => $default_name, + values => [ map $_->name, grep !$_->default && !$_->external, @{wxTheApp->presets->{$self->name}} ], + ); + return 0 unless $dlg->ShowModal == wxID_OK; + + $self->save_as($dlg->get_name); +} + sub save { - my ($self, $name, $parent) = @_; + my ($self, $opt_keys) = @_; - if (!$name) { - my $default_name = $self->default ? 'Untitled' : $self->name; - $default_name =~ s/\.ini$//i; - - my $dlg = Slic3r::GUI::SavePresetWindow->new($parent, - default => $default_name, - values => [ map $_->name, grep !$_->default && !$_->external, @{wxTheApp->presets->{$self->name}} ], - ); - return 0 unless $dlg->ShowModal == wxID_OK; - $name = $dlg->get_name; - } + return $self->save_as($self->name, $opt_keys); +} + +sub save_as { + my ($self, $name, $opt_keys) = @_; $self->rename($name); @@ -125,8 +134,15 @@ sub save { die "Calling save() without setting filename"; } - $self->_config->clear; - $self->_config->apply($self->_dirty_config); + if ($opt_keys) { + $self->_config->apply_only($self->_dirty_config, $opt_keys); + } else { + $self->_config->clear; + $self->_config->apply($self->_dirty_config); + } + + # unlink the file first to avoid problems on case-insensitive file systems + unlink Slic3r::encode_path($self->file); $self->_config->save($self->file); wxTheApp->load_presets; @@ -167,6 +183,8 @@ sub dirty_config { sub load_config { my ($self) = @_; + return if $self->_loaded; + my @keys = $self->_group_class->options; my @extra_keys = $self->_group_class->overriding_options; diff --git a/lib/Slic3r/GUI/PresetEditor.pm b/lib/Slic3r/GUI/PresetEditor.pm index aa78bb895..8bd6e0db0 100644 --- a/lib/Slic3r/GUI/PresetEditor.pm +++ b/lib/Slic3r/GUI/PresetEditor.pm @@ -87,7 +87,7 @@ sub new { }); EVT_CHOICE($parent, $self->{presets_choice}, sub { - $self->on_select_preset; + $self->_on_select_preset; }); EVT_BUTTON($self, $self->{btn_save_preset}, sub { $self->save_preset }); @@ -123,13 +123,20 @@ sub save_preset { $self->{treectrl}->SetFocus; my $preset = $self->current_preset; - $preset->save(undef, $self); + $preset->save_prompt($self); $self->load_presets; $self->select_preset_by_name($preset->name); + $self->{on_save_preset}->($self->name, $preset) if $self->{on_save_preset}; + return 1; } +sub on_save_preset { + my ($self, $cb) = @_; + $self->{on_save_preset} = $cb; +} + sub on_value_change { my ($self, $cb) = @_; $self->{on_value_change} = $cb; @@ -141,10 +148,12 @@ sub on_value_change { sub _on_value_change { my ($self, $opt_key) = @_; - $self->current_preset->_dirty_config->apply($self->config); - $self->{on_value_change}->($opt_key) if $self->{on_value_change}; - $self->load_presets; - $self->_update; + wxTheApp->CallAfter(sub { + $self->current_preset->_dirty_config->apply($self->config); + $self->{on_value_change}->($opt_key) if $self->{on_value_change}; + $self->load_presets; + $self->_update; + }); } sub _update {} @@ -155,7 +164,7 @@ sub select_preset { my ($self, $i, $force) = @_; $self->{presets_choice}->SetSelection($i); - $self->on_select_preset($force); + $self->_on_select_preset($force); } sub select_preset_by_name { @@ -163,8 +172,12 @@ sub select_preset_by_name { my $presets = wxTheApp->presets->{$self->name}; my $i = first { $presets->[$_]->name eq $name } 0..$#$presets; + if (!defined $i) { + warn "No preset named $name"; + return 0; + } $self->{presets_choice}->SetSelection($i); - $self->on_select_preset($force); + $self->_on_select_preset($force); } sub prompt_unsaved_changes { @@ -175,6 +188,11 @@ sub prompt_unsaved_changes { } sub on_select_preset { + my ($self, $cb) = @_; + $self->{on_select_preset} = $cb; +} + +sub _on_select_preset { my ($self, $force) = @_; # This method is called: @@ -185,9 +203,6 @@ sub on_select_preset { # Get the selected name. my $preset = wxTheApp->presets->{$self->name}->[$self->{presets_choice}->GetSelection]; - # If selection didn't change, do nothing. - return if defined $self->current_preset && $preset->name eq $self->current_preset->name; - # If we have unsaved changes, prompt user. if (!$force && !$self->prompt_unsaved_changes) { # User decided not to save the current changes, so we restore the previous selection. @@ -199,13 +214,16 @@ sub on_select_preset { $self->current_preset($preset); + # If selection didn't change, do nothing. + # Only after resetting current_preset because it might contain an older object of the + # current preset. + return if defined $self->current_preset && $preset->name eq $self->current_preset->name; + # We reload presets in order to remove the "(modified)" suffix in case user was # prompted and chose to discard changes. $self->load_presets; - $preset->load_config if !$preset->_loaded; - $self->config->clear; - $self->config->apply($preset->dirty_config); + $self->reload_preset; eval { local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self); @@ -215,12 +233,13 @@ sub on_select_preset { $self->_update; $self->on_preset_loaded; - $self->reload_config; }; if ($@) { $@ = "I was unable to load the selected config file: $@"; Slic3r::GUI::catch_error($self); } + + $self->{on_select_preset}->($self->name, $preset) if $self->{on_select_preset}; } sub add_options_page { @@ -240,6 +259,15 @@ sub add_options_page { return $page; } +sub reload_preset { + my ($self) = @_; + + $self->current_preset->load_config if !$self->current_preset->_loaded; + $self->config->clear; + $self->config->apply($self->current_preset->dirty_config); + $self->reload_config; +} + sub reload_config { my $self = shift; @@ -441,7 +469,7 @@ sub options { external_perimeter_extrusion_width infill_extrusion_width solid_infill_extrusion_width top_infill_extrusion_width support_material_extrusion_width infill_overlap bridge_flow_ratio - xy_size_compensation resolution overridable compatible_printers + xy_size_compensation resolution shortcuts compatible_printers print_settings_id ) } @@ -449,7 +477,7 @@ sub options { sub build { my $self = shift; - my $overridable_widget = sub { + my $shortcuts_widget = sub { my ($parent) = @_; my $Options = $Slic3r::Config::Options; @@ -458,15 +486,15 @@ sub build { grep { exists $Options->{$_} && $Options->{$_}{category} } $self->options ); my @opt_keys = sort { $options{$a} cmp $options{$b} } keys %options; - $self->{overridable_opt_keys} = [ @opt_keys ]; + $self->{shortcuts_opt_keys} = [ @opt_keys ]; - my $listbox = $self->{overridable_list} = Wx::CheckListBox->new($parent, -1, + my $listbox = $self->{shortcuts_list} = Wx::CheckListBox->new($parent, -1, wxDefaultPosition, [-1, 320], [ map $options{$_}, @opt_keys ]); EVT_CHECKLISTBOX($self, $listbox, sub { my $value = [ map $opt_keys[$_], grep $listbox->IsChecked($_), 0..$#opt_keys ]; - $self->config->set('overridable', $value); - $self->_on_value_change('overridable'); + $self->config->set('shortcuts', $value); + $self->_on_value_change('shortcuts'); }); my $sizer = Wx::BoxSizer->new(wxVERTICAL); @@ -715,7 +743,7 @@ sub build { } { - my $page = $self->add_options_page('Overrides', 'wrench.png'); + my $page = $self->add_options_page('Shortcuts', 'wrench.png'); { my $optgroup = $page->new_optgroup('Profile preferences'); { @@ -727,10 +755,10 @@ sub build { } } { - my $optgroup = $page->new_optgroup('Overridable settings (they will be displayed in the plater for quick changes)'); + my $optgroup = $page->new_optgroup('Show shortcuts for the following settings'); { my $line = Slic3r::GUI::OptionsGroup::Line->new( - widget => $overridable_widget, + widget => $shortcuts_widget, full_width => 1, ); $optgroup->append_line($line); @@ -745,9 +773,9 @@ sub reload_config { $self->_reload_compatible_printers_widget; { - my %overridable = map { $_ => 1 } @{ $self->config->get('overridable') }; - for my $i (0..$#{$self->{overridable_opt_keys}}) { - $self->{overridable_list}->Check($i, $overridable{ $self->{overridable_opt_keys}[$i] }); + my %shortcuts = map { $_ => 1 } @{ $self->config->get('shortcuts') }; + for my $i (0..$#{$self->{shortcuts_opt_keys}}) { + $self->{shortcuts_list}->Check($i, $shortcuts{ $self->{shortcuts_opt_keys}[$i] }); } } diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index ff206b1f5..ce149a8fc 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -853,8 +853,9 @@ PrintConfigDef::PrintConfigDef() def->cli = "overhangs|detect-bridging-perimeters!"; def->default_value = new ConfigOptionBool(true); - def = this->add("overridable", coStrings); - def->label = "Overridable options"; + def = this->add("shortcuts", coStrings); + def->label = "Shortcuts"; + def->aliases.push_back("overridable"); { ConfigOptionStrings* opt = new ConfigOptionStrings(); opt->values.push_back("support_material"); @@ -1383,7 +1384,7 @@ PrintConfigDef::PrintConfigDef() def = this->add("support_material_interface_speed", coFloatOrPercent); def->label = "↳ interface"; - def->category = "Support material interface speed"; + def->full_label = "Support material interface speed"; def->gui_type = "f_enum_open"; def->category = "Support material"; def->tooltip = "Speed for printing support material interface layers. If expressed as percentage (for example 50%) it will be calculated over support material speed.";