diff --git a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm index 71e301081..33aa6740e 100644 --- a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm +++ b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm @@ -22,9 +22,19 @@ sub new { my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); # C++ type Slic3r::ModelObject - $self->{model_object} = $params{model_object}; - # Not set, not used. - # $self->{print_object} = $params{print_object}; + my $object = $self->{model_object} = $params{model_object}; + + # Save state for sliders. + $self->{move_options} = { + x => 0, + y => 0, + z => 0, + }; + $self->{last_coords} = { + x => 0, + y => 0, + z => 0, + }; # create TreeCtrl my $tree = $self->{tree} = Wx::TreeCtrl->new($self, -1, wxDefaultPosition, [300, 100], @@ -64,12 +74,61 @@ sub new { $self->{settings_panel} = Slic3r::GUI::Plater::OverrideSettingsPanel->new($self, on_change => sub { $self->{part_settings_changed} = 1; }); my $settings_sizer = Wx::StaticBoxSizer->new($self->{staticbox} = Wx::StaticBox->new($self, -1, "Part Settings"), wxVERTICAL); $settings_sizer->Add($self->{settings_panel}, 1, wxEXPAND | wxALL, 0); + + my $optgroup; + $optgroup = $self->{optgroup} = Slic3r::GUI::OptionsGroup->new( + parent => $self, + title => 'Move', + on_change => sub { + my ($opt_id) = @_; + # There seems to be an issue with wxWidgets 3.0.2/3.0.3, where the slider + # genates tens of events for a single value change. + # Only trigger the recalculation if the value changes + # or a live preview was activated and the mesh cut is not valid yet. + if ($self->{move_options}{$opt_id} != $optgroup->get_value($opt_id)) { + $self->{move_options}{$opt_id} = $optgroup->get_value($opt_id); + wxTheApp->CallAfter(sub { + $self->_update; + }); + } + }, + label_width => 20, + ); + $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( + opt_id => 'x', + type => 'slider', + label => 'X', + default => 0, + min => -($self->{model_object}->bounding_box->size->x)*4, + max => $self->{model_object}->bounding_box->size->x*4, + full_width => 1, + )); + $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( + opt_id => 'y', + type => 'slider', + label => 'Y', + default => 0, + min => -($self->{model_object}->bounding_box->size->y)*4, + max => $self->{model_object}->bounding_box->size->y*4, + full_width => 1, + )); + $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( + opt_id => 'z', + type => 'slider', + label => 'Z', + default => 0, + min => -($self->{model_object}->bounding_box->size->z)*4, + max => $self->{model_object}->bounding_box->size->z*4, + full_width => 1, + )); + # left pane with tree my $left_sizer = Wx::BoxSizer->new(wxVERTICAL); $left_sizer->Add($tree, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10); $left_sizer->Add($buttons_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10); $left_sizer->Add($settings_sizer, 1, wxEXPAND | wxALL, 0); + $left_sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); # right pane with preview canvas my $canvas; @@ -181,6 +240,21 @@ sub selection_changed { $self->{btn_delete}->Disable; $self->{settings_panel}->disable; $self->{settings_panel}->set_config(undef); + + # reset move sliders + $self->{optgroup}->set_value("x", 0); + $self->{optgroup}->set_value("y", 0); + $self->{optgroup}->set_value("z", 0); + $self->{move_options} = { + x => 0, + y => 0, + z => 0, + }; + $self->{last_coords} = { + x => 0, + y => 0, + z => 0, + }; if (my $itemData = $self->get_selection) { my ($config, @opt_keys); @@ -256,17 +330,17 @@ sub on_btn_load { sub on_btn_delete { my ($self) = @_; - + my $itemData = $self->get_selection; if ($itemData && $itemData->{type} eq 'volume') { my $volume = $self->{model_object}->volumes->[$itemData->{volume_id}]; - + # if user is deleting the last solid part, throw error if (!$volume->modifier && scalar(grep !$_->modifier, @{$self->{model_object}->volumes}) == 1) { Slic3r::GUI::show_error($self, "You can't delete the last solid part from this object."); return; } - + $self->{model_object}->delete_volume($itemData->{volume_id}); $self->{parts_changed} = 1; } @@ -312,4 +386,26 @@ sub PartSettingsChanged { return $self->{part_settings_changed}; } +sub _update { + my ($self) = @_; + my ($m_x, $m_y, $m_z) = ($self->{move_options}{x}, $self->{move_options}{y}, $self->{move_options}{z}); + my ($l_x, $l_y, $l_z) = ($self->{last_coords}{x}, $self->{last_coords}{y}, $self->{last_coords}{z}); + + my $itemData = $self->get_selection; + if ($itemData && $itemData->{type} eq 'volume') { + my $d = Slic3r::Pointf3->new($m_x - $l_x, $m_y - $l_y, $m_z - $l_z); + my $volume = $self->{model_object}->volumes->[$itemData->{volume_id}]; + $volume->mesh->translate(@{$d}); + $self->{last_coords}{x} = $m_x; + $self->{last_coords}{y} = $m_y; + $self->{last_coords}{z} = $m_z; + } + + my @objects = (); + push @objects, $self->{model_object}; + $self->{canvas}->reset_objects; + $self->{canvas}->load_object($_, undef, [0]) for @objects; + $self->{canvas}->Render; +} + 1;