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/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index fc7aef322..631d2a141 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,21 @@ 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}; + } }); $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 efbbeb973..1c495c720 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -556,6 +556,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. @@ -752,22 +760,43 @@ sub selected_presets { sub show_preset_editor { my ($self, $group, $i) = @_; - my $class = "Slic3r::GUI::PresetEditorDialog::" . ucfirst($group); - my $dlg = $class->new($self); - my @presets = $self->selected_presets($group); - $dlg->preset_editor->select_preset_by_name($presets[$i // 0]->name); - $dlg->preset_editor->on_value_change(sub { + + 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; + } + + $preset_editor->select_preset_by_name($presets[$i // 0]->name); + $preset_editor->on_value_change(sub { $self->config_changed; }); - $dlg->ShowModal; + $preset_editor->on_select_preset(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); + }); - # Re-load the presets as they might have changed. - $self->load_presets; - - # 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. 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/PresetEditor.pm b/lib/Slic3r/GUI/PresetEditor.pm index e84a000b7..b566671f9 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 }); @@ -155,7 +155,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 { @@ -164,7 +164,7 @@ sub select_preset_by_name { my $presets = wxTheApp->presets->{$self->name}; my $i = first { $presets->[$_]->name eq $name } 0..$#$presets; $self->{presets_choice}->SetSelection($i); - $self->on_select_preset($force); + $self->_on_select_preset($force); } sub prompt_unsaved_changes { @@ -175,6 +175,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: @@ -221,6 +226,8 @@ sub on_select_preset { $@ = "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 {