mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-02 04:50:37 +08:00
Support moving objects using keyboard arrows in the 2d plater view. (#4104)
* * Add nudge_instance to 2D.pm to move the selected instance. * Add menu items ->, -<, ^, v keyboards shortcuts. * Add Set nudge value as a config option in Preferences. * Add Move instance submenu to Plater menu. * Add Move instance icon. * Remove move instance menu item and use EVT_KEY_DOWN instead in 2D.pm. * Fix selecting objects between 3D and 2D platers. * Fix Ubuntu keyboard focus error in 2D plater. * Correct the keycodes in 2D.pm keyboard event. * Fix Windows keyboard focus error. * Remove Todo line. * Adding a minimum value for 2d plater nudege variable and improving keyboard focus in 2D plater.
This commit is contained in:
parent
b6209c4ee3
commit
1190a74f4e
@ -91,6 +91,7 @@ our $Settings = {
|
|||||||
color_toolpaths_by => 'role',
|
color_toolpaths_by => 'role',
|
||||||
tabbed_preset_editors => 1,
|
tabbed_preset_editors => 1,
|
||||||
show_host => 0,
|
show_host => 0,
|
||||||
|
nudge_val => 1
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2728,6 +2728,9 @@ sub selection_changed {
|
|||||||
my ($obj_idx, $object) = $self->selected_object;
|
my ($obj_idx, $object) = $self->selected_object;
|
||||||
my $have_sel = defined $obj_idx;
|
my $have_sel = defined $obj_idx;
|
||||||
|
|
||||||
|
# Remove selection in 2d Plater.
|
||||||
|
$self->{canvas}->{selected_instance} = undef;
|
||||||
|
|
||||||
if (my $menu = $self->GetFrame->{plater_select_menu}) {
|
if (my $menu = $self->GetFrame->{plater_select_menu}) {
|
||||||
$_->Check(0) for $menu->GetMenuItems;
|
$_->Check(0) for $menu->GetMenuItems;
|
||||||
if ($have_sel) {
|
if ($have_sel) {
|
||||||
@ -2798,8 +2801,11 @@ sub select_object {
|
|||||||
my ($self, $obj_idx) = @_;
|
my ($self, $obj_idx) = @_;
|
||||||
|
|
||||||
$_->selected(0) for @{ $self->{objects} };
|
$_->selected(0) for @{ $self->{objects} };
|
||||||
|
$_->selected_instance(-1) for @{ $self->{objects} };
|
||||||
|
|
||||||
if (defined $obj_idx) {
|
if (defined $obj_idx) {
|
||||||
$self->{objects}->[$obj_idx]->selected(1);
|
$self->{objects}->[$obj_idx]->selected(1);
|
||||||
|
$self->{objects}->[$obj_idx]->selected_instance(0);
|
||||||
}
|
}
|
||||||
$self->selection_changed(1);
|
$self->selection_changed(1);
|
||||||
}
|
}
|
||||||
@ -3053,6 +3059,7 @@ has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled m
|
|||||||
has 'transformed_thumbnail' => (is => 'rw');
|
has 'transformed_thumbnail' => (is => 'rw');
|
||||||
has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units
|
has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units
|
||||||
has 'selected' => (is => 'rw', default => sub { 0 });
|
has 'selected' => (is => 'rw', default => sub { 0 });
|
||||||
|
has 'selected_instance' => (is => 'rw', default => sub { -1 });
|
||||||
|
|
||||||
sub make_thumbnail {
|
sub make_thumbnail {
|
||||||
my ($self, $model, $obj_idx) = @_;
|
my ($self, $model, $obj_idx) = @_;
|
||||||
|
@ -10,7 +10,7 @@ use List::Util qw(min max first);
|
|||||||
use Slic3r::Geometry qw(X Y scale unscale convex_hull);
|
use Slic3r::Geometry qw(X Y scale unscale convex_hull);
|
||||||
use Slic3r::Geometry::Clipper qw(offset JT_ROUND intersection_pl);
|
use Slic3r::Geometry::Clipper qw(offset JT_ROUND intersection_pl);
|
||||||
use Wx qw(:misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL);
|
use Wx qw(:misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL);
|
||||||
use Wx::Event qw(EVT_MOUSE_EVENTS EVT_PAINT EVT_ERASE_BACKGROUND EVT_SIZE);
|
use Wx::Event qw(EVT_MOUSE_EVENTS EVT_KEY_DOWN EVT_PAINT EVT_ERASE_BACKGROUND EVT_SIZE);
|
||||||
use base 'Wx::Panel';
|
use base 'Wx::Panel';
|
||||||
|
|
||||||
use constant CANVAS_TEXT => join('-', +(localtime)[3,4]) eq '13-8'
|
use constant CANVAS_TEXT => join('-', +(localtime)[3,4]) eq '13-8'
|
||||||
@ -34,7 +34,8 @@ sub new {
|
|||||||
$self->{on_instances_moved} = sub {};
|
$self->{on_instances_moved} = sub {};
|
||||||
|
|
||||||
$self->{objects_brush} = Wx::Brush->new(Wx::Colour->new(210,210,210), wxSOLID);
|
$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);
|
$self->{instance_brush} = Wx::Brush->new(Wx::Colour->new(255,128,128), wxSOLID);
|
||||||
|
$self->{selected_brush} = Wx::Brush->new(Wx::Colour->new(255,166,128), wxSOLID);
|
||||||
$self->{dragged_brush} = Wx::Brush->new(Wx::Colour->new(128,128,255), wxSOLID);
|
$self->{dragged_brush} = Wx::Brush->new(Wx::Colour->new(128,128,255), wxSOLID);
|
||||||
$self->{transparent_brush} = Wx::Brush->new(Wx::Colour->new(0,0,0), wxTRANSPARENT);
|
$self->{transparent_brush} = Wx::Brush->new(Wx::Colour->new(0,0,0), wxTRANSPARENT);
|
||||||
$self->{grid_pen} = Wx::Pen->new(Wx::Colour->new(230,230,230), 1, wxSOLID);
|
$self->{grid_pen} = Wx::Pen->new(Wx::Colour->new(230,230,230), 1, wxSOLID);
|
||||||
@ -44,6 +45,8 @@ sub new {
|
|||||||
|
|
||||||
$self->{user_drawn_background} = $^O ne 'darwin';
|
$self->{user_drawn_background} = $^O ne 'darwin';
|
||||||
|
|
||||||
|
$self->{selected_instance} = undef;
|
||||||
|
|
||||||
EVT_PAINT($self, \&repaint);
|
EVT_PAINT($self, \&repaint);
|
||||||
EVT_ERASE_BACKGROUND($self, sub {}) if $self->{user_drawn_background};
|
EVT_ERASE_BACKGROUND($self, sub {}) if $self->{user_drawn_background};
|
||||||
EVT_MOUSE_EVENTS($self, \&mouse_event);
|
EVT_MOUSE_EVENTS($self, \&mouse_event);
|
||||||
@ -51,6 +54,22 @@ sub new {
|
|||||||
$self->update_bed_size;
|
$self->update_bed_size;
|
||||||
$self->Refresh;
|
$self->Refresh;
|
||||||
});
|
});
|
||||||
|
EVT_KEY_DOWN($self, sub {
|
||||||
|
my ($s, $event) = @_;
|
||||||
|
|
||||||
|
my $key = $event->GetKeyCode;
|
||||||
|
if ($key == 65 || $key == 314) {
|
||||||
|
$self->nudge_instance('left');
|
||||||
|
} elsif ($key == 87 || $key == 315) {
|
||||||
|
$self->nudge_instance('up');
|
||||||
|
} elsif ($key == 68 || $key == 316) {
|
||||||
|
$self->nudge_instance('right');
|
||||||
|
} elsif ($key == 83 || $key == 317) {
|
||||||
|
$self->nudge_instance('down');
|
||||||
|
} else {
|
||||||
|
$event->Skip;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
@ -78,6 +97,9 @@ sub on_instances_moved {
|
|||||||
sub repaint {
|
sub repaint {
|
||||||
my ($self, $event) = @_;
|
my ($self, $event) = @_;
|
||||||
|
|
||||||
|
# Focus is needed in order to catch keyboard events.
|
||||||
|
$self->SetFocus;
|
||||||
|
|
||||||
my $dc = Wx::AutoBufferedPaintDC->new($self);
|
my $dc = Wx::AutoBufferedPaintDC->new($self);
|
||||||
my $size = $self->GetSize;
|
my $size = $self->GetSize;
|
||||||
my @size = ($size->GetWidth, $size->GetHeight);
|
my @size = ($size->GetWidth, $size->GetHeight);
|
||||||
@ -149,6 +171,8 @@ sub repaint {
|
|||||||
|
|
||||||
if (defined $self->{drag_object} && $self->{drag_object}[0] == $obj_idx && $self->{drag_object}[1] == $instance_idx) {
|
if (defined $self->{drag_object} && $self->{drag_object}[0] == $obj_idx && $self->{drag_object}[1] == $instance_idx) {
|
||||||
$dc->SetBrush($self->{dragged_brush});
|
$dc->SetBrush($self->{dragged_brush});
|
||||||
|
} elsif ($object->selected && $object->selected_instance == $instance_idx) {
|
||||||
|
$dc->SetBrush($self->{instance_brush});
|
||||||
} elsif ($object->selected) {
|
} elsif ($object->selected) {
|
||||||
$dc->SetBrush($self->{selected_brush});
|
$dc->SetBrush($self->{selected_brush});
|
||||||
} else {
|
} else {
|
||||||
@ -201,7 +225,11 @@ sub mouse_event {
|
|||||||
my $pos = $event->GetPosition;
|
my $pos = $event->GetPosition;
|
||||||
my $point = $self->point_to_model_units([ $pos->x, $pos->y ]); #]]
|
my $point = $self->point_to_model_units([ $pos->x, $pos->y ]); #]]
|
||||||
if ($event->ButtonDown) {
|
if ($event->ButtonDown) {
|
||||||
|
# On Linux, Focus is needed in order to move selected instance using keyboard arrows.
|
||||||
|
$self->SetFocus;
|
||||||
|
|
||||||
$self->{on_select_object}->(undef);
|
$self->{on_select_object}->(undef);
|
||||||
|
$self->{selected_instance} = undef;
|
||||||
# traverse objects and instances in reverse order, so that if they're overlapping
|
# traverse objects and instances in reverse order, so that if they're overlapping
|
||||||
# we get the one that gets drawn last, thus on top (as user expects that to move)
|
# we get the one that gets drawn last, thus on top (as user expects that to move)
|
||||||
OBJECTS: for my $obj_idx (reverse 0 .. $#{$self->{objects}}) {
|
OBJECTS: for my $obj_idx (reverse 0 .. $#{$self->{objects}}) {
|
||||||
@ -220,6 +248,8 @@ sub mouse_event {
|
|||||||
$point->y - $instance_origin->[Y], #-
|
$point->y - $instance_origin->[Y], #-
|
||||||
];
|
];
|
||||||
$self->{drag_object} = [ $obj_idx, $instance_idx ];
|
$self->{drag_object} = [ $obj_idx, $instance_idx ];
|
||||||
|
$self->{objects}->[$obj_idx]->selected_instance($instance_idx);
|
||||||
|
$self->{selected_instance} = $self->{drag_object};
|
||||||
} elsif ($event->RightDown) {
|
} elsif ($event->RightDown) {
|
||||||
$self->{on_right_click}->($pos);
|
$self->{on_right_click}->($pos);
|
||||||
}
|
}
|
||||||
@ -236,7 +266,7 @@ sub mouse_event {
|
|||||||
$self->{drag_object} = undef;
|
$self->{drag_object} = undef;
|
||||||
$self->SetCursor(wxSTANDARD_CURSOR);
|
$self->SetCursor(wxSTANDARD_CURSOR);
|
||||||
} elsif ($event->LeftDClick) {
|
} elsif ($event->LeftDClick) {
|
||||||
$self->{on_double_click}->();
|
$self->{on_double_click}->();
|
||||||
} elsif ($event->Dragging) {
|
} elsif ($event->Dragging) {
|
||||||
return if !$self->{drag_start_pos}; # concurrency problems
|
return if !$self->{drag_start_pos}; # concurrency problems
|
||||||
my ($obj_idx, $instance_idx) = @{ $self->{drag_object} };
|
my ($obj_idx, $instance_idx) = @{ $self->{drag_object} };
|
||||||
@ -257,6 +287,55 @@ sub mouse_event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub nudge_instance{
|
||||||
|
my ($self, $direction) = @_;
|
||||||
|
|
||||||
|
# Get the selected instance of an object.
|
||||||
|
if (!defined $self->{selected_instance}) {
|
||||||
|
# Check if an object is selected.
|
||||||
|
for my $obj_idx (0 .. $#{$self->{objects}}) {
|
||||||
|
if ($self->{objects}->[$obj_idx]->selected) {
|
||||||
|
if ($self->{objects}->[$obj_idx]->selected_instance != -1) {
|
||||||
|
$self->{selected_instance} = [$obj_idx, $self->{objects}->[$obj_idx]->selected_instance];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if not defined ($self->{selected_instance});
|
||||||
|
my ($obj_idx, $instance_idx) = @{ $self->{selected_instance} };
|
||||||
|
my $object = $self->{model}->objects->[$obj_idx];
|
||||||
|
my $instance = $object->instances->[$instance_idx];
|
||||||
|
|
||||||
|
# Get the nudge values.
|
||||||
|
my $x_nudge = 0;
|
||||||
|
my $y_nudge = 0;
|
||||||
|
|
||||||
|
$self->{nudge_value} = ($Slic3r::GUI::Settings->{_}{nudge_val} < 0.1 ? 0.1 : $Slic3r::GUI::Settings->{_}{nudge_val}) / &Slic3r::SCALING_FACTOR;
|
||||||
|
|
||||||
|
if ($direction eq 'right'){
|
||||||
|
$x_nudge = $self->{nudge_value};
|
||||||
|
} elsif ($direction eq 'left'){
|
||||||
|
$x_nudge = -1 * $self->{nudge_value};
|
||||||
|
} elsif ($direction eq 'up'){
|
||||||
|
$y_nudge = $self->{nudge_value};
|
||||||
|
} elsif ($direction eq 'down'){
|
||||||
|
$y_nudge = -$self->{nudge_value};
|
||||||
|
}
|
||||||
|
my $point = Slic3r::Pointf->new($x_nudge, $y_nudge);
|
||||||
|
my $instance_origin = [ map scale($_), @{$instance->offset} ];
|
||||||
|
$point = [ map scale($_), @{$point} ];
|
||||||
|
|
||||||
|
$instance->set_offset(
|
||||||
|
Slic3r::Pointf->new(
|
||||||
|
unscale( $instance_origin->[X] + $x_nudge),
|
||||||
|
unscale( $instance_origin->[Y] + $y_nudge),
|
||||||
|
));
|
||||||
|
|
||||||
|
$object->update_bounding_box;
|
||||||
|
$self->Refresh;
|
||||||
|
$self->{on_instances_moved}->();
|
||||||
|
}
|
||||||
|
|
||||||
sub update_bed_size {
|
sub update_bed_size {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
@ -85,6 +85,13 @@ sub new {
|
|||||||
tooltip => 'Shows/Hides the Controller Tab. Requires a restart of Slic3r.',
|
tooltip => 'Shows/Hides the Controller Tab. Requires a restart of Slic3r.',
|
||||||
default => $Slic3r::GUI::Settings->{_}{show_host},
|
default => $Slic3r::GUI::Settings->{_}{show_host},
|
||||||
));
|
));
|
||||||
|
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
|
||||||
|
opt_id => 'nudge_val',
|
||||||
|
type => 's',
|
||||||
|
label => '2D plater nudge value',
|
||||||
|
tooltip => 'In 2D plater, Move objects using keyboard by nudge value of',
|
||||||
|
default => $Slic3r::GUI::Settings->{_}{nudge_val},
|
||||||
|
));
|
||||||
|
|
||||||
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
||||||
$sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
$sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user