From a06fad9e13d150846b1d565356175eb9fcf7c2e6 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 1 Jul 2014 18:18:23 +0200 Subject: [PATCH] Enable/disable GUI controls according to the others in order to guide the user through option dependency --- lib/Slic3r/GUI/OptionsGroup.pm | 23 +++++ lib/Slic3r/GUI/OptionsGroup/Field.pm | 47 +++++++++ lib/Slic3r/GUI/Plater/ObjectCutDialog.pm | 27 +++-- lib/Slic3r/GUI/Tab.pm | 124 +++++++++++++++++++++-- xs/src/PrintConfig.cpp | 2 +- 5 files changed, 207 insertions(+), 16 deletions(-) diff --git a/lib/Slic3r/GUI/OptionsGroup.pm b/lib/Slic3r/GUI/OptionsGroup.pm index 6febca49c..46d8aa678 100644 --- a/lib/Slic3r/GUI/OptionsGroup.pm +++ b/lib/Slic3r/GUI/OptionsGroup.pm @@ -195,6 +195,18 @@ sub _build_field { : $field->wxSizer; } +sub get_option { + my ($self, $opt_id) = @_; + return undef if !exists $self->_options->{$opt_id}; + return $self->_options->{$opt_id}; +} + +sub get_field { + my ($self, $opt_id) = @_; + return undef if !exists $self->_fields->{$opt_id}; + return $self->_fields->{$opt_id}; +} + sub get_value { my ($self, $opt_id) = @_; @@ -267,6 +279,8 @@ has 'readonly' => (is => 'rw', default => sub { 0 }); package Slic3r::GUI::ConfigOptionsGroup; use Moo; +use List::Util qw(first); + extends 'Slic3r::GUI::OptionsGroup'; has 'config' => (is => 'ro', required => 1); has 'full_labels' => (is => 'ro', default => sub { 0 }); @@ -328,6 +342,15 @@ sub reload_config { } } +sub get_fieldc { + my ($self, $opt_key, $opt_index) = @_; + + $opt_index //= -1; + my $opt_id = first { $self->_opt_map->{$_}[0] eq $opt_key && $self->_opt_map->{$_}[1] == $opt_index } + keys %{$self->_opt_map}; + return defined($opt_id) ? $self->get_field($opt_id) : undef; +} + sub _get_config_value { my ($self, $opt_key, $opt_index, $deserialize) = @_; diff --git a/lib/Slic3r/GUI/OptionsGroup/Field.pm b/lib/Slic3r/GUI/OptionsGroup/Field.pm index ca81d1fd4..0e1028a50 100644 --- a/lib/Slic3r/GUI/OptionsGroup/Field.pm +++ b/lib/Slic3r/GUI/OptionsGroup/Field.pm @@ -28,6 +28,11 @@ sub set_tooltip { if $tooltip && $self->can('SetToolTipString'); } +sub toggle { + my ($self, $enable) = @_; + $enable ? $self->enable : $self->disable; +} + sub _on_change { my ($self, $opt_id) = @_; @@ -80,6 +85,20 @@ sub get_value { return $self->wxWindow->GetValue; } +sub enable { + my ($self) = @_; + + $self->wxWindow->Enable; + $self->wxWindow->Refresh; +} + +sub disable { + my ($self) = @_; + + $self->wxWindow->Disable; + $self->wxWindow->Refresh; +} + package Slic3r::GUI::OptionsGroup::Field::Checkbox; use Moo; @@ -154,6 +173,20 @@ sub BUILD { }); } +sub enable { + my ($self) = @_; + + $self->wxWindow->Enable; + $self->wxWindow->SetEditable(1); +} + +sub disable { + my ($self) = @_; + + $self->wxWindow->Disable; + $self->wxWindow->SetEditable(0); +} + package Slic3r::GUI::OptionsGroup::Field::Choice; use Moo; @@ -343,6 +376,20 @@ sub get_value { ]; } +sub enable { + my ($self) = @_; + + $self->x_textctrl->Enable; + $self->y_textctrl->Enable; +} + +sub disable { + my ($self) = @_; + + $self->x_textctrl->Disable; + $self->y_textctrl->Disable; +} + package Slic3r::GUI::OptionsGroup::Field::Slider; use Moo; diff --git a/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm b/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm index 6ff76b70d..b62776b0b 100644 --- a/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm +++ b/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm @@ -31,13 +31,26 @@ sub new { on_change => sub { my ($opt_id) = @_; - my $value = $optgroup->get_value($opt_id); - $self->{cut_options}{$opt_id} = $value; - if ($opt_id eq 'z') { - if ($self->{canvas}) { - $self->{canvas}->SetCuttingPlane($value); - $self->{canvas}->Render; - } + $self->{cut_options}{$opt_id} = $optgroup->get_value($opt_id); + + # update canvas + if ($self->{canvas}) { + $self->{canvas}->SetCuttingPlane($self->{cut_options}{z}); + $self->{canvas}->Render; + } + + # update controls + my $z = $self->{cut_options}{z}; + $optgroup->get_field('keep_upper')->toggle(my $have_upper = abs($z - $optgroup->get_option('z')->max) > 0.1); + $optgroup->get_field('keep_lower')->toggle(my $have_lower = $z > 0.1); + $optgroup->get_field('rotate_lower')->toggle($z > 0 && $self->{cut_options}{keep_lower}); + + # update cut button + if (($self->{cut_options}{keep_upper} && $have_upper) + || ($self->{cut_options}{keep_lower} && $have_lower)) { + $self->{btn_cut}->Enable; + } else { + $self->{btn_cut}->Disable; } }, label_width => 120, diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 7952f3500..85c4454c6 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -103,6 +103,7 @@ sub new { $self->{config} = Slic3r::Config->new; $self->build; + $self->_update; if ($self->hidden_options) { $self->{config}->apply(Slic3r::Config->new_from_defaults($self->hidden_options)); } @@ -166,8 +167,11 @@ sub _on_value_change { $self->set_dirty(1); $self->{on_value_change}->(@_) if $self->{on_value_change}; + $self->_update; } +sub _update {} + sub _on_presets_changed { my $self = shift; @@ -390,6 +394,16 @@ sub load_config { $self->reload_config; } +sub get_field { + my ($self, $opt_key, $opt_index) = @_; + + foreach my $page (@{ $self->{pages} }) { + my $field = $page->get_field($opt_key, $opt_index); + return $field if defined $field; + } + return undef; +} + package Slic3r::GUI::Tab::Print; use base 'Slic3r::GUI::Tab'; @@ -663,6 +677,47 @@ sub build { } } +sub _update { + my ($self) = @_; + + my $config = $self->{config}; + + my $have_perimeters = $config->perimeters > 0; + $self->get_field('spiral_vase')->toggle($config->perimeters == 1 && $config->top_solid_layers == 0 && $config->fill_density == 0); + $self->get_field($_)->toggle($have_perimeters) + for qw(extra_perimeters thin_walls overhangs seam_position external_perimeters_first); + + my $have_infill = $config->fill_density > 0; + $self->get_field($_)->toggle($have_infill) + for qw(fill_pattern infill_every_layers infill_only_where_needed solid_infill_every_layers); + + my $have_default_acceleration = $config->default_acceleration > 0; + $self->get_field($_)->toggle($have_default_acceleration) + for qw(perimeter_acceleration infill_acceleration bridge_acceleration first_layer_acceleration); + + my $have_skirt = $config->skirts > 0 || $config->min_skirt_length > 0; + $self->get_field($_)->toggle($have_skirt) + for qw(skirt_distance skirt_height); + + my $have_support_material = $config->support_material || $config->raft_layers > 0; + my $have_support_interface = $config->support_material_interface_layers > 0; + $self->get_field($_)->toggle($have_support_material) + for qw(support_material_threshold support_material_enforce_layers + support_material_pattern support_material_spacing support_material_angle + support_material_interface_layers dont_support_bridges + support_material_extruder); + $self->get_field($_)->toggle($have_support_material && $have_support_interface) + for qw(support_material_interface_spacing support_material_interface_extruder); + + my $have_sequential_printing = $config->complete_objects; + $self->get_field($_)->toggle($have_sequential_printing) + for qw(extruder_clearance_radius extruder_clearance_height); + + my $have_ooze_prevention = $config->ooze_prevention; + $self->get_field($_)->toggle($have_ooze_prevention) + for qw(standby_temperature_delta); +} + sub hidden_options { !$Slic3r::have_threads ? qw(threads) : () } package Slic3r::GUI::Tab::Filament; @@ -754,8 +809,23 @@ sub build { $optgroup->append_single_option_line('min_print_speed'); } } +} + +sub _on_value_change { + my $self = shift; + my ($opt_key) = @_; + $self->SUPER::_on_value_change(@_); +} + +sub _update { + my ($self) = @_; $self->_update_description; + + my $cooling = $self->{config}->cooling; + $self->get_field($_)->toggle($cooling) + for qw(min_fan_speed max_fan_speed disable_fan_first_layers + fan_below_layer_time slowdown_below_layer_time min_print_speed); } sub _update_description { @@ -787,14 +857,6 @@ sub _update_description { $self->{description_line}->SetText($msg); } -sub _on_value_change { - my $self = shift; - my ($opt_key) = @_; - $self->SUPER::_on_value_change(@_); - - $self->_update_description; -} - package Slic3r::GUI::Tab::Printer; use base 'Slic3r::GUI::Tab'; use Wx qw(:sizer :button :bitmap :misc :id); @@ -879,6 +941,7 @@ sub build { if ($opt_id eq 'extruders_count') { $self->{extruders_count} = $optgroup->get_value('extruders_count'); $self->_build_extruder_pages; + $self->_update; } }); } @@ -1000,6 +1063,41 @@ sub _build_extruder_pages { $self->update_tree(0); } +sub _update { + my ($self) = @_; + + my $config = $self->{config}; + + $self->get_field('toolchange_gcode')->toggle($self->{extruders_count} > 1); + + for my $i (0 .. ($self->{extruders_count}-1)) { + # disable extruder offset for first extruder + $self->get_field('extruder_offset', $i)->toggle($i != 0); + + my $have_retract_length = $config->get_at('retract_length', $i) > 0; + + # when using firmware retraction, firmware decides retraction length + $self->get_field('retract_length', $i)->toggle(!$config->use_firmware_retraction); + + # user can customize travel length if we have retraction length or we're using + # firmware retraction + $self->get_field('retract_before_travel', $i)->toggle($have_retract_length || $config->use_firmware_retraction); + + # user can customize other retraction options if retraction is enabled + my $retraction = ($have_retract_length || $config->use_firmware_retraction); + $self->get_field($_, $i)->toggle($retraction) + for qw(retract_lift retract_layer_change); + + # some options only apply when not using firmware retraction + $self->get_field($_, $i)->toggle($retraction && !$config->use_firmware_retraction) + for qw(retract_speed retract_restart_extra wipe); + + my $toolchange_retraction = $config->get_at('retract_length_toolchange', $i) > 0; + $self->get_field($_, $i)->toggle($toolchange_retraction) + for qw(retract_restart_extra_toolchange); + } +} + # this gets executed after preset is loaded and before GUI fields are updated sub on_preset_loaded { my $self = shift; @@ -1067,6 +1165,16 @@ sub reload_config { $_->reload_config for @{$self->{optgroups}}; } +sub get_field { + my ($self, $opt_key, $opt_index) = @_; + + foreach my $optgroup (@{ $self->{optgroups} }) { + my $field = $optgroup->get_fieldc($opt_key, $opt_index); + return $field if defined $field; + } + return undef; +} + sub set_value { my $self = shift; my ($opt_key, $value) = @_; diff --git a/xs/src/PrintConfig.cpp b/xs/src/PrintConfig.cpp index 7417a7742..24b169ad8 100644 --- a/xs/src/PrintConfig.cpp +++ b/xs/src/PrintConfig.cpp @@ -724,7 +724,7 @@ PrintConfigDef::build_def() { Options["spiral_vase"].type = coBool; Options["spiral_vase"].label = "Spiral vase"; - Options["spiral_vase"].tooltip = "This experimental feature will raise Z gradually while printing a single-walled object in order to remove any visible seam. By enabling this option other settings will be overridden to enforce a single perimeter, no infill, no top solid layers, no support material. You can still set any number of bottom solid layers as well as skirt/brim loops. It won't work when printing more than an object."; + Options["spiral_vase"].tooltip = "This feature will raise Z gradually while printing a single-walled object in order to remove any visible seam. This option requires a single perimeter, no infill, no top solid layers and no support material. You can still set any number of bottom solid layers as well as skirt/brim loops. It won't work when printing more than an object."; Options["spiral_vase"].cli = "spiral-vase!"; Options["standby_temperature_delta"].type = coInt;