diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index c028c123b..1ad9d7610 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -136,6 +136,17 @@ sub mouse_event { if ($self->enable_picking) { $self->deselect_volumes; $self->select_volume($volume_idx); + + if ($volume_idx != -1) { + my $group_id = $self->volumes->[$volume_idx]->select_group_id; + my @volumes; + if ($group_id != -1) { + $self->select_volume($_) + for grep $self->volumes->[$_]->select_group_id == $group_id, + 0..$#{$self->volumes}; + } + } + $self->Refresh; } @@ -215,8 +226,17 @@ sub mouse_event { $self->_drag_start_xy($pos); } } elsif ($e->LeftUp || $e->MiddleUp || $e->RightUp) { - if ($self->on_move && defined $self->_drag_volume_idx) { - $self->on_move->($self->_drag_volume_idx) if $self->_dragged; + if ($self->on_move && defined($self->_drag_volume_idx) && $self->_dragged) { + # get all volumes belonging to the same group, if any + my @volume_idxs; + my $group_id = $self->volumes->[$self->_drag_volume_idx]->drag_group_id; + if ($group_id == -1) { + @volume_idxs = ($self->_drag_volume_idx); + } else { + @volume_idxs = grep $self->volumes->[$_]->drag_group_id == $group_id, + 0..$#{$self->volumes}; + } + $self->on_move->(@volume_idxs); } $self->_drag_volume_idx(undef); $self->_drag_start_pos(undef); @@ -652,7 +672,13 @@ sub Render { $_->hover(0) for @{$self->volumes}; if ($volume_idx <= $#{$self->volumes}) { $self->_hover_volume_idx($volume_idx); + $self->volumes->[$volume_idx]->hover(1); + my $group_id = $self->volumes->[$volume_idx]->select_group_id; + if ($group_id != -1) { + $_->hover(1) for grep { $_->select_group_id == $group_id } @{$self->volumes}; + } + $self->on_hover->($volume_idx) if $self->on_hover; } } @@ -900,8 +926,8 @@ use Moo; has 'mesh' => (is => 'rw', required => 0); # only required for cut contours has 'bounding_box' => (is => 'ro', required => 1); has 'color' => (is => 'ro', required => 1); -has 'hover_group_id' => (is => 'ro', default => sub { -1 }); -has 'drag_group_id' => (is => 'ro', default => sub { -1 }); +has 'select_group_id' => (is => 'rw', default => sub { -1 }); +has 'drag_group_id' => (is => 'rw', default => sub { -1 }); has 'origin' => (is => 'rw', default => sub { Slic3r::Pointf3->new(0,0,0) }); has 'verts' => (is => 'rw'); has 'norms' => (is => 'rw'); @@ -925,6 +951,8 @@ use List::Util qw(first); use constant COLORS => [ [1,1,0], [1,0.5,0.5], [0.5,1,0.5], [0.5,0.5,1] ]; __PACKAGE__->mk_accessors(qw( + select_by + drag_by volumes_by_object _objects_by_volumes )); @@ -933,7 +961,9 @@ sub new { my $class = shift; my $self = $class->SUPER::new(@_); - $self->volumes_by_object({}); # obj_idx => [ volume_idx, volume_idx ... ] + $self->select_by('object'); # object | instance + $self->drag_by('instance'); # object | instance + $self->volumes_by_object({}); # obj_idx => [ volume_idx, volume_idx ... ] $self->_objects_by_volumes({}); # volume_idx => [ obj_idx, instance_idx ] return $self; @@ -960,7 +990,6 @@ sub load_object { my @volumes = sort { ($a->modifier // 0) <=> ($b->modifier // 0) } @{$model_object->volumes}; my @volumes_idx = (); - my $group_id = $#{$self->volumes} + 1; foreach my $volume (@volumes) { foreach my $instance_idx (@$instance_idxs) { my $instance = $model_object->instances->[$instance_idx]; @@ -978,10 +1007,19 @@ sub load_object { push @$color, $volume->modifier ? 0.5 : 1; push @{$self->volumes}, my $v = Slic3r::GUI::3DScene::Volume->new( bounding_box => $mesh->bounding_box, - drag_group_id => $group_id * 1000 + $instance_idx, color => $color, ); $v->mesh($mesh) if $self->enable_cutting; + if ($self->select_by eq 'object') { + $v->select_group_id($obj_idx*1000); + } elsif ($self->select_by eq 'instance') { + $v->select_group_id($obj_idx*1000 + $instance_idx); + } + if ($self->drag_by eq 'object') { + $v->drag_group_id($obj_idx*1000); + } elsif ($self->drag_by eq 'instance') { + $v->drag_group_id($obj_idx*1000 + $instance_idx); + } push @volumes_idx, my $scene_volume_idx = $#{$self->volumes}; $self->_objects_by_volumes->{$scene_volume_idx} = [ $obj_idx, $instance_idx ]; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index f49856b6d..f25b179a6 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -87,8 +87,7 @@ sub new { $canvas->PopupMenu($menu, $click_pos); $menu->Destroy; }; - my $on_instance_moved = sub { - my ($obj_idx, $instance_idx) = @_; + my $on_instances_moved = sub { $self->update; }; @@ -98,7 +97,7 @@ sub new { $self->{canvas}->on_select_object($on_select_object); $self->{canvas}->on_double_click($on_double_click); $self->{canvas}->on_right_click(sub { $on_right_click->($self->{canvas}, @_); }); - $self->{canvas}->on_instance_moved($on_instance_moved); + $self->{canvas}->on_instances_moved($on_instances_moved); # Initialize 3D preview and toolpaths preview if ($Slic3r::GUI::have_OpenGL) { @@ -107,7 +106,7 @@ sub new { $self->{canvas3D}->set_on_select_object($on_select_object); $self->{canvas3D}->set_on_double_click($on_double_click); $self->{canvas3D}->set_on_right_click(sub { $on_right_click->($self->{canvas3D}, @_); }); - $self->{canvas3D}->set_on_instance_moved($on_instance_moved); + $self->{canvas3D}->set_on_instances_moved($on_instances_moved); $self->{toolpaths2D} = Slic3r::GUI::Plater::2DToolpaths->new($self->{preview_notebook}, $self->{print}); $self->{preview_notebook}->AddPage($self->{toolpaths2D}, 'Preview'); diff --git a/lib/Slic3r/GUI/Plater/2D.pm b/lib/Slic3r/GUI/Plater/2D.pm index a43f0a061..bf0dcbfba 100644 --- a/lib/Slic3r/GUI/Plater/2D.pm +++ b/lib/Slic3r/GUI/Plater/2D.pm @@ -27,7 +27,7 @@ sub new { $self->{on_select_object} = sub {}; $self->{on_double_click} = sub {}; $self->{on_right_click} = sub {}; - $self->{on_instance_moved} = sub {}; + $self->{on_instances_moved} = sub {}; $self->{objects_brush} = Wx::Brush->new(Wx::Colour->new(210,210,210), wxSOLID); $self->{selected_brush} = Wx::Brush->new(Wx::Colour->new(255,128,128), wxSOLID); @@ -63,9 +63,9 @@ sub on_right_click { $self->{on_right_click} = $cb; } -sub on_instance_moved { +sub on_instances_moved { my ($self, $cb) = @_; - $self->{on_instance_moved} = $cb; + $self->{on_instances_moved} = $cb; } sub repaint { @@ -211,7 +211,7 @@ sub mouse_event { } $self->Refresh; } elsif ($event->LeftUp) { - $self->{on_instance_moved}->(@{ $self->{drag_object} }) + $self->{on_instances_moved}->() if $self->{drag_object}; $self->{drag_start_pos} = undef; $self->{drag_object} = undef; diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm index 6e4c305cf..5928625ef 100644 --- a/lib/Slic3r/GUI/Plater/3D.pm +++ b/lib/Slic3r/GUI/Plater/3D.pm @@ -17,12 +17,14 @@ sub new { my $self = $class->SUPER::new($parent); $self->enable_picking(1); $self->enable_moving(1); + $self->select_by('object'); + $self->drag_by('instance'); $self->{objects} = $objects; $self->{model} = $model; $self->{config} = $config; $self->{on_select_object} = sub {}; - $self->{on_instance_moved} = sub {}; + $self->{on_instances_moved} = sub {}; $self->on_select(sub { my ($volume_idx) = @_; @@ -30,33 +32,27 @@ sub new { my $obj_idx = undef; if ($volume_idx != -1) { $obj_idx = $self->object_idx($volume_idx); - $self->volumes->[$_]->selected(1) for @{$self->volumes_by_object->{$obj_idx}}; - $self->Refresh; } $self->{on_select_object}->($obj_idx) if $self->{on_select_object}; }); - $self->on_hover(sub { - my ($volume_idx) = @_; - - my $obj_idx = $self->object_idx($volume_idx); - $self->volumes->[$_]->hover(1) for @{$self->volumes_by_object->{$obj_idx}}; - }); $self->on_move(sub { - my ($volume_idx) = @_; + my @volume_idxs = @_; - my $volume = $self->volumes->[$volume_idx]; - my $obj_idx = $self->object_idx($volume_idx); - my $instance_idx = $self->instance_idx($volume_idx); - my $model_object = $self->{model}->get_object($obj_idx); - $model_object - ->instances->[$instance_idx] - ->offset - ->translate($volume->origin->x, $volume->origin->y); #)) - $model_object->invalidate_bounding_box; + foreach my $volume_idx (@volume_idxs) { + my $volume = $self->volumes->[$volume_idx]; + my $obj_idx = $self->object_idx($volume_idx); + my $instance_idx = $self->instance_idx($volume_idx); + my $model_object = $self->{model}->get_object($obj_idx); + $model_object + ->instances->[$instance_idx] + ->offset + ->translate($volume->origin->x, $volume->origin->y); #)) + $model_object->invalidate_bounding_box; + } - $self->{on_instance_moved}->($obj_idx, $instance_idx) - if $self->{on_instance_moved}; + $self->{on_instances_moved}->() + if $self->{on_instances_moved}; }); return $self; @@ -77,9 +73,9 @@ sub set_on_right_click { $self->on_right_click($cb); } -sub set_on_instance_moved { +sub set_on_instances_moved { my ($self, $cb) = @_; - $self->{on_instance_moved} = $cb; + $self->{on_instances_moved} = $cb; } sub update {