Fixed handling of print and filament presets incompatible

with the newly selected print profile,
fixed loading of print and filament tab pages after the print or filament
preset has been changed to be compatible with a newly selected printer.
This commit is contained in:
bubnikv 2017-12-13 14:00:14 +01:00
parent 91e847cb76
commit 21b4e62e6e
5 changed files with 81 additions and 64 deletions

View file

@ -7,7 +7,7 @@ use utf8;
use File::Basename qw(basename dirname); use File::Basename qw(basename dirname);
use FindBin; use FindBin;
use List::Util qw(min); use List::Util qw(min first);
use Slic3r::Geometry qw(X Y); use Slic3r::Geometry qw(X Y);
use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog
:font :icon wxTheApp); :font :icon wxTheApp);
@ -132,12 +132,14 @@ sub _init_tabpanel {
$self->{plater}->update_presets($tab_name, @_); $self->{plater}->update_presets($tab_name, @_);
if ($tab_name eq 'printer') { if ($tab_name eq 'printer') {
# Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors. # Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
wxTheApp->{preset_bundle}->print->update_tab_ui( my ($presets, $reload_dependent_tabs) = @_;
$self->{options_tabs}{'print'}->{presets_choice}, for my $tab_name_other (qw(print filament)) {
$self->{options_tabs}{'print'}->{show_incompatible_presets}); # If the printer tells us that the print or filament preset has been switched or invalidated,
wxTheApp->{preset_bundle}->filament->update_tab_ui( # refresh the print or filament tab page. Otherwise just refresh the combo box.
$self->{options_tabs}{'filament'}->{presets_choice}, my $update_action = ($reload_dependent_tabs && (first { $_ eq $tab_name_other } (@{$reload_dependent_tabs})))
$self->{options_tabs}{'filament'}->{show_incompatible_presets}); ? 'load_current_preset' : 'update_tab_ui';
$self->{options_tabs}{$tab_name_other}->$update_action;
}
# Update the controller printers. # Update the controller printers.
$self->{controller}->update_presets(@_) if $self->{controller}; $self->{controller}->update_presets(@_) if $self->{controller};
} }

View file

@ -506,6 +506,7 @@ sub _on_select_preset {
wxTheApp->{preset_bundle}->set_filament_preset($idx, $choice->GetStringSelection); wxTheApp->{preset_bundle}->set_filament_preset($idx, $choice->GetStringSelection);
} }
if ($group eq 'filament' && @{$self->{preset_choosers}{filament}} > 1) { if ($group eq 'filament' && @{$self->{preset_choosers}{filament}} > 1) {
# Only update the platter UI for the 2nd and other filaments.
wxTheApp->{preset_bundle}->update_platter_filament_ui($idx, $choice); wxTheApp->{preset_bundle}->update_platter_filament_ui($idx, $choice);
} else { } else {
# call GetSelection() in scalar context as it's context-aware # call GetSelection() in scalar context as it's context-aware

View file

@ -151,7 +151,7 @@ sub save_preset {
eval { $self->{presets}->save_current_preset($name); }; eval { $self->{presets}->save_current_preset($name); };
Slic3r::GUI::catch_error($self) and return; Slic3r::GUI::catch_error($self) and return;
# Add the new item into the UI component, remove dirty flags and activate the saved item. # Add the new item into the UI component, remove dirty flags and activate the saved item.
$self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); $self->update_tab_ui;
# Update the selection boxes at the platter. # Update the selection boxes at the platter.
$self->_on_presets_changed; $self->_on_presets_changed;
} }
@ -177,7 +177,7 @@ sub _toggle_show_hide_incompatible {
my ($self) = @_; my ($self) = @_;
$self->{show_incompatible_presets} = ! $self->{show_incompatible_presets}; $self->{show_incompatible_presets} = ! $self->{show_incompatible_presets};
$self->_update_show_hide_incompatible_button; $self->_update_show_hide_incompatible_button;
$self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); $self->update_tab_ui;
} }
sub _update_show_hide_incompatible_button { sub _update_show_hide_incompatible_button {
@ -223,8 +223,9 @@ sub _update {}
# to update the "dirty" flags of the selection boxes, # to update the "dirty" flags of the selection boxes,
# to uddate number of "filament" selection boxes when the number of extruders change. # to uddate number of "filament" selection boxes when the number of extruders change.
sub _on_presets_changed { sub _on_presets_changed {
my ($self) = @_; my ($self, $reload_dependent_tabs) = @_;
$self->{on_presets_changed}->($self->{presets}) if $self->{on_presets_changed}; $self->{on_presets_changed}->($self->{presets}, $reload_dependent_tabs)
if $self->{on_presets_changed};
} }
# For the printer profile, generate the extruder pages after a preset is loaded. # For the printer profile, generate the extruder pages after a preset is loaded.
@ -237,11 +238,12 @@ sub may_discard_current_dirty_preset
my ($self, $presets, $new_printer_name) = @_; my ($self, $presets, $new_printer_name) = @_;
$presets //= $self->{presets}; $presets //= $self->{presets};
# Display a dialog showing the dirty options in a human readable form. # Display a dialog showing the dirty options in a human readable form.
my $old_preset = $presets->get_current_preset; my $old_preset = $presets->get_current_preset;
my $type_name = $presets->name; my $type_name = $presets->name;
my $name = $old_preset->default ? my $tab = ' ';
my $name = $old_preset->default ?
('Default ' . $type_name . ' preset') : ('Default ' . $type_name . ' preset') :
($type_name . " preset \"" . $old_preset->name . "\""); ($type_name . " preset\n$tab" . $old_preset->name);
# Collect descriptions of the dirty options. # Collect descriptions of the dirty options.
my @option_names = (); my @option_names = ();
foreach my $opt_key (@{$presets->current_dirty_options}) { foreach my $opt_key (@{$presets->current_dirty_options}) {
@ -251,10 +253,10 @@ sub may_discard_current_dirty_preset
push @option_names, $name; push @option_names, $name;
} }
# Show a confirmation dialog with the list of dirty options. # Show a confirmation dialog with the list of dirty options.
my $changes = join "\n", map "- $_", @option_names; my $changes = join "\n", map "$tab$_", @option_names;
my $message = (defined $new_printer_name) ? my $message = (defined $new_printer_name) ?
"$name is not compatible with printer \"$new_printer_name\"\n and it has unsaved changes:" : "$name\n\nis not compatible with printer\n$tab$new_printer_name\n\nand it has the following unsaved changes:" :
"$name has unsaved changes:"; "$name\n\nhas the following unsaved changes:";
my $confirm = Wx::MessageDialog->new($self, my $confirm = Wx::MessageDialog->new($self,
$message . "\n$changes\n\nDiscard changes and continue anyway?", $message . "\n$changes\n\nDiscard changes and continue anyway?",
'Unsaved Changes', wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); 'Unsaved Changes', wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
@ -267,9 +269,11 @@ sub may_discard_current_dirty_preset
sub select_preset { sub select_preset {
my ($self, $name, $force) = @_; my ($self, $name, $force) = @_;
$force //= 0; $force //= 0;
my $current_dirty = $self->{presets}->current_is_dirty; my $presets = $self->{presets};
my $canceled = 0; my $current_dirty = $presets->current_is_dirty;
my $printer_tab = $self->{presets}->name eq 'printer'; my $canceled = 0;
my $printer_tab = $presets->name eq 'printer';
my @reload_dependent_tabs = ();
if (! $force && $current_dirty && ! $self->may_discard_current_dirty_preset) { if (! $force && $current_dirty && ! $self->may_discard_current_dirty_preset) {
$canceled = 1; $canceled = 1;
} elsif ($printer_tab) { } elsif ($printer_tab) {
@ -278,49 +282,57 @@ sub select_preset {
# If they are not compatible and the the current print or filament are dirty, let user decide # If they are not compatible and the the current print or filament are dirty, let user decide
# whether to discard the changes or keep the current printer selection. # whether to discard the changes or keep the current printer selection.
my $new_printer_name = $name // ''; my $new_printer_name = $name // '';
my $new_printer_preset = $self->{presets}->find_preset($new_printer_name, 1); my $new_printer_preset = $presets->find_preset($new_printer_name, 1);
# my $new_nozzle_dmrs = $new_printer_preset->config->get('nozzle_diameter'); my $print_presets = wxTheApp->{preset_bundle}->print;
my $print_presets = wxTheApp->{preset_bundle}->print; my $print_preset_dirty = $print_presets->current_is_dirty;
if ($print_presets->current_is_dirty && my $print_preset_compatible = $print_presets->get_edited_preset->is_compatible_with_printer($new_printer_name);
! $print_presets->get_edited_preset->is_compatible_with_printer($new_printer_name)) { $canceled = $print_preset_dirty && ! $print_preset_compatible &&
if ($self->may_discard_current_dirty_preset($print_presets, $new_printer_name)) { ! $self->may_discard_current_dirty_preset($print_presets, $new_printer_name);
$canceled = 1; my $filament_presets = wxTheApp->{preset_bundle}->filament;
} else { my $filament_preset_dirty = $filament_presets->current_is_dirty;
$print_presets->discard_current_changes; my $filament_preset_compatible = $filament_presets->get_edited_preset->is_compatible_with_printer($new_printer_name);
} if (! $canceled) {
$canceled = $filament_preset_dirty && ! $filament_preset_compatible &&
! $self->may_discard_current_dirty_preset($filament_presets, $new_printer_name);
} }
my $filament_presets = wxTheApp->{preset_bundle}->filament; if (! $canceled) {
# if ((@$new_nozzle_dmrs <= 1) && if (! $print_preset_compatible) {
if (! $canceled && $filament_presets->current_is_dirty && # The preset will be switched to a different, compatible preset, or the '-- default --'.
! $filament_presets->get_edited_preset->is_compatible_with_printer($new_printer_name)) { push @reload_dependent_tabs, 'print';
if ($self->may_discard_current_dirty_preset($filament_presets, $new_printer_name)) { $print_presets->discard_current_changes if $print_preset_dirty;
$canceled = 1; }
} else { if (! $filament_preset_compatible) {
$filament_presets->discard_current_changes; # The preset will be switched to a different, compatible preset, or the '-- default --'.
push @reload_dependent_tabs, 'filament';
$filament_presets->discard_current_changes if $filament_preset_dirty;
} }
} }
} }
if ($canceled) { if ($canceled) {
$self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); $self->update_tab_ui;
# Trigger the on_presets_changed event so that we also restore the previous value in the plater selector. # Trigger the on_presets_changed event so that we also restore the previous value in the plater selector,
# if this action was initiated from the platter.
$self->_on_presets_changed; $self->_on_presets_changed;
} else { } else {
$presets->discard_current_changes if $current_dirty;
if (defined $name) { if (defined $name) {
$self->{presets}->select_preset_by_name($name); $presets->select_preset_by_name($name);
} else { } else {
$self->{presets}->select_preset(0); $presets->select_preset(0);
} }
# Mark the print & filament enabled if they are compatible with the currently selected preset. # Mark the print & filament enabled if they are compatible with the currently selected preset.
# The following method should not discard changes of current print or filament presets on change of a printer profile,
# if they are compatible with the current printer.
wxTheApp->{preset_bundle}->update_compatible_with_printer(1) wxTheApp->{preset_bundle}->update_compatible_with_printer(1)
if $current_dirty || $printer_tab; if $current_dirty || $printer_tab;
# Initialize the UI from the current preset. # Initialize the UI from the current preset.
$self->load_current_preset; $self->load_current_preset(\@reload_dependent_tabs);
} }
} }
# Initialize the UI from the current preset. # Initialize the UI from the current preset.
sub load_current_preset { sub load_current_preset {
my ($self) = @_; my ($self, $dependent_tab_names) = @_;
my $preset = $self->{presets}->get_current_preset; my $preset = $self->{presets}->get_current_preset;
eval { eval {
local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self); local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self);
@ -337,8 +349,8 @@ sub load_current_preset {
# preset dirty again # preset dirty again
# (not sure this is true anymore now that update_dirty is idempotent) # (not sure this is true anymore now that update_dirty is idempotent)
wxTheApp->CallAfter(sub { wxTheApp->CallAfter(sub {
$self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); $self->update_tab_ui;
$self->_on_presets_changed; $self->_on_presets_changed($dependent_tab_names);
}); });
} }
@ -430,8 +442,13 @@ sub _load_key_value {
$self->{config}->set($opt_key, $value); $self->{config}->set($opt_key, $value);
# Mark the print & filament enabled if they are compatible with the currently selected preset. # Mark the print & filament enabled if they are compatible with the currently selected preset.
if ($opt_key eq 'compatible_printers') { if ($opt_key eq 'compatible_printers') {
my $was_compatible = $self->{presets}->get_edited_preset->compatible;
wxTheApp->{preset_bundle}->update_compatible_with_printer(0); wxTheApp->{preset_bundle}->update_compatible_with_printer(0);
$self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); if ($was_compatible != $self->{presets}->get_edited_preset->compatible) {
# This is certainly not a tab page.
# Trigger the on_presets_changed event so that we also update the "compatible" flag at the plater selector.
$self->_on_presets_changed;
}
} else { } else {
$self->{presets}->update_dirty_ui($self->{presets_choice}); $self->{presets}->update_dirty_ui($self->{presets_choice});
} }
@ -538,10 +555,14 @@ sub update_ui_from_settings {
} else { } else {
if ($self->{show_incompatible_presets}) { if ($self->{show_incompatible_presets}) {
$self->{show_incompatible_presets} = 0; $self->{show_incompatible_presets} = 0;
$self->{presets}->update_tab_ui($self->{presets_choice}, 0); $self->update_tab_ui;
} }
} }
} }
sub update_tab_ui {
my ($self) = @_;
$self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets})
}
package Slic3r::GUI::Tab::Print; package Slic3r::GUI::Tab::Print;
use base 'Slic3r::GUI::Tab'; use base 'Slic3r::GUI::Tab';

View file

@ -397,29 +397,19 @@ void PresetCollection::set_default_suppressed(bool default_suppressed)
void PresetCollection::update_compatible_with_printer(const std::string &active_printer, bool select_other_if_incompatible) void PresetCollection::update_compatible_with_printer(const std::string &active_printer, bool select_other_if_incompatible)
{ {
size_t num_visible = 0;
for (size_t idx_preset = 1; idx_preset < m_presets.size(); ++ idx_preset) { for (size_t idx_preset = 1; idx_preset < m_presets.size(); ++ idx_preset) {
bool selected = idx_preset == m_idx_selected; bool selected = idx_preset == m_idx_selected;
Preset &preset_selected = m_presets[idx_preset]; Preset &preset_selected = m_presets[idx_preset];
Preset &preset_edited = selected ? m_edited_preset : preset_selected; Preset &preset_edited = selected ? m_edited_preset : preset_selected;
if (preset_edited.update_compatible_with_printer(active_printer)) if (! preset_edited.update_compatible_with_printer(active_printer) &&
// Mark compatible presets as visible. selected && select_other_if_incompatible)
preset_selected.is_visible = true;
else if (selected && select_other_if_incompatible) {
preset_selected.is_visible = false;
m_idx_selected = (size_t)-1; m_idx_selected = (size_t)-1;
}
if (selected) if (selected)
preset_selected.is_compatible = preset_edited.is_compatible; preset_selected.is_compatible = preset_edited.is_compatible;
if (preset_selected.is_visible)
++ num_visible;
} }
if (m_idx_selected == (size_t)-1) if (m_idx_selected == (size_t)-1)
// Find some other visible preset. // Find some other compatible preset, or the "-- default --" preset.
this->select_preset(first_visible_idx()); this->select_preset(first_compatible_idx());
else if (num_visible == 0)
// Show the "-- default --" preset.
m_presets.front().is_visible = true;
} }
// Save the preset under a new name. If the name is different from the old one, // Save the preset under a new name. If the name is different from the old one,
@ -460,7 +450,7 @@ void PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompatibl
ui->Clear(); ui->Clear();
for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++ i) { for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++ i) {
const Preset &preset = this->m_presets[i]; const Preset &preset = this->m_presets[i];
if (! show_incompatible && ! preset.is_compatible && i != m_idx_selected) if (! preset.is_visible || (! show_incompatible && ! preset.is_compatible && i != m_idx_selected))
continue; continue;
const wxBitmap *bmp = preset.is_compatible ? m_bitmap_compatible : m_bitmap_incompatible; const wxBitmap *bmp = preset.is_compatible ? m_bitmap_compatible : m_bitmap_incompatible;
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
@ -494,6 +484,8 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui)
return was_dirty != is_dirty; return was_dirty != is_dirty;
} }
// Select a new preset. This resets all the edits done to the currently selected preset.
// If the preset with index idx does not exist, a first visible preset is selected.
Preset& PresetCollection::select_preset(size_t idx) Preset& PresetCollection::select_preset(size_t idx)
{ {
for (Preset &preset : m_presets) for (Preset &preset : m_presets)

View file

@ -14,6 +14,7 @@
bool external() %code%{ RETVAL = THIS->is_external; %}; bool external() %code%{ RETVAL = THIS->is_external; %};
bool visible() %code%{ RETVAL = THIS->is_visible; %}; bool visible() %code%{ RETVAL = THIS->is_visible; %};
bool dirty() %code%{ RETVAL = THIS->is_dirty; %}; bool dirty() %code%{ RETVAL = THIS->is_dirty; %};
bool compatible() %code%{ RETVAL = THIS->is_compatible; %};
bool is_compatible_with_printer(char *active_printer) const; bool is_compatible_with_printer(char *active_printer) const;
const char* name() %code%{ RETVAL = THIS->name.c_str(); %}; const char* name() %code%{ RETVAL = THIS->name.c_str(); %};