mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-31 11:32:00 +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',
|
||||
tabbed_preset_editors => 1,
|
||||
show_host => 0,
|
||||
nudge_val => 1
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2727,7 +2727,10 @@ sub selection_changed {
|
||||
|
||||
my ($obj_idx, $object) = $self->selected_object;
|
||||
my $have_sel = defined $obj_idx;
|
||||
|
||||
|
||||
# Remove selection in 2d Plater.
|
||||
$self->{canvas}->{selected_instance} = undef;
|
||||
|
||||
if (my $menu = $self->GetFrame->{plater_select_menu}) {
|
||||
$_->Check(0) for $menu->GetMenuItems;
|
||||
if ($have_sel) {
|
||||
@ -2796,10 +2799,13 @@ sub selection_changed {
|
||||
|
||||
sub select_object {
|
||||
my ($self, $obj_idx) = @_;
|
||||
|
||||
|
||||
$_->selected(0) for @{ $self->{objects} };
|
||||
$_->selected_instance(-1) for @{ $self->{objects} };
|
||||
|
||||
if (defined $obj_idx) {
|
||||
$self->{objects}->[$obj_idx]->selected(1);
|
||||
$self->{objects}->[$obj_idx]->selected_instance(0);
|
||||
}
|
||||
$self->selection_changed(1);
|
||||
}
|
||||
@ -3053,6 +3059,7 @@ has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled m
|
||||
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 'selected' => (is => 'rw', default => sub { 0 });
|
||||
has 'selected_instance' => (is => 'rw', default => sub { -1 });
|
||||
|
||||
sub make_thumbnail {
|
||||
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::Clipper qw(offset JT_ROUND intersection_pl);
|
||||
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 constant CANVAS_TEXT => join('-', +(localtime)[3,4]) eq '13-8'
|
||||
@ -34,7 +34,8 @@ sub new {
|
||||
$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);
|
||||
$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->{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);
|
||||
@ -43,7 +44,9 @@ sub new {
|
||||
$self->{skirt_pen} = Wx::Pen->new(Wx::Colour->new(150,150,150), 1, wxSOLID);
|
||||
|
||||
$self->{user_drawn_background} = $^O ne 'darwin';
|
||||
|
||||
|
||||
$self->{selected_instance} = undef;
|
||||
|
||||
EVT_PAINT($self, \&repaint);
|
||||
EVT_ERASE_BACKGROUND($self, sub {}) if $self->{user_drawn_background};
|
||||
EVT_MOUSE_EVENTS($self, \&mouse_event);
|
||||
@ -51,6 +54,22 @@ sub new {
|
||||
$self->update_bed_size;
|
||||
$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;
|
||||
}
|
||||
@ -77,7 +96,10 @@ sub on_instances_moved {
|
||||
|
||||
sub repaint {
|
||||
my ($self, $event) = @_;
|
||||
|
||||
|
||||
# Focus is needed in order to catch keyboard events.
|
||||
$self->SetFocus;
|
||||
|
||||
my $dc = Wx::AutoBufferedPaintDC->new($self);
|
||||
my $size = $self->GetSize;
|
||||
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) {
|
||||
$dc->SetBrush($self->{dragged_brush});
|
||||
} elsif ($object->selected && $object->selected_instance == $instance_idx) {
|
||||
$dc->SetBrush($self->{instance_brush});
|
||||
} elsif ($object->selected) {
|
||||
$dc->SetBrush($self->{selected_brush});
|
||||
} else {
|
||||
@ -201,7 +225,11 @@ sub mouse_event {
|
||||
my $pos = $event->GetPosition;
|
||||
my $point = $self->point_to_model_units([ $pos->x, $pos->y ]); #]]
|
||||
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->{selected_instance} = undef;
|
||||
# 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)
|
||||
OBJECTS: for my $obj_idx (reverse 0 .. $#{$self->{objects}}) {
|
||||
@ -220,6 +248,8 @@ sub mouse_event {
|
||||
$point->y - $instance_origin->[Y], #-
|
||||
];
|
||||
$self->{drag_object} = [ $obj_idx, $instance_idx ];
|
||||
$self->{objects}->[$obj_idx]->selected_instance($instance_idx);
|
||||
$self->{selected_instance} = $self->{drag_object};
|
||||
} elsif ($event->RightDown) {
|
||||
$self->{on_right_click}->($pos);
|
||||
}
|
||||
@ -236,7 +266,7 @@ sub mouse_event {
|
||||
$self->{drag_object} = undef;
|
||||
$self->SetCursor(wxSTANDARD_CURSOR);
|
||||
} elsif ($event->LeftDClick) {
|
||||
$self->{on_double_click}->();
|
||||
$self->{on_double_click}->();
|
||||
} elsif ($event->Dragging) {
|
||||
return if !$self->{drag_start_pos}; # concurrency problems
|
||||
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 {
|
||||
my $self = shift;
|
||||
|
||||
|
@ -85,6 +85,13 @@ sub new {
|
||||
tooltip => 'Shows/Hides the Controller Tab. Requires a restart of Slic3r.',
|
||||
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);
|
||||
$sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
|
Loading…
x
Reference in New Issue
Block a user