From 3b51f644110978f69edaf95b50a8796e992aab23 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 21 Jul 2017 16:29:40 +0200 Subject: Fixing https://github.com/prusa3d/Slic3r/issues/432 Slic3r GUI not starting, error when using --gui (on linux) Implements https://github.com/prusa3d/Slic3r/issues/407 Shortcuts: Movement in 3D Space Assignment of the camera shortcuts is clear from the menu accelerators. Implements https://github.com/prusa3d/Slic3r/issues/406 Shortcuts: Rotate +/- 45 degrees l/r keys rotate the object Also changed the accelerators for adding / removing duplicates from Ctrl++/- to plain +/-, from Ctrl-Del to plain Del, and added an 's' key accelerator for uniform scaling. --- lib/Slic3r/GUI/3DScene.pm | 30 ++++++++++++++++-- lib/Slic3r/GUI/MainFrame.pm | 19 +++++++----- lib/Slic3r/GUI/Plater.pm | 30 ++++++++++-------- lib/Slic3r/GUI/Plater/3D.pm | 76 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 128 insertions(+), 27 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index a296b01a2..68de5518b 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -16,13 +16,13 @@ use strict; use warnings; use Wx qw(:timer :bitmap :icon :dialog); -use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS EVT_TIMER); +use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS EVT_CHAR EVT_TIMER); # must load OpenGL *before* Wx::GLCanvas use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants); use base qw(Wx::GLCanvas Class::Accessor); use Math::Trig qw(asin tan); use List::Util qw(reduce min max first); -use Slic3r::Geometry qw(X Y Z MIN MAX triangle_normal normalize deg2rad tan scale unscale scaled_epsilon); +use Slic3r::Geometry qw(X Y normalize scale unscale scaled_epsilon); use Slic3r::Geometry::Clipper qw(offset_ex intersection_pl JT_ROUND); use Wx::GLCanvas qw(:all); use Slic3r::Geometry qw(PI); @@ -168,6 +168,32 @@ sub new { }); EVT_MOUSEWHEEL($self, \&mouse_wheel_event); EVT_MOUSE_EVENTS($self, \&mouse_event); +# EVT_KEY_DOWN($self, sub { + EVT_CHAR($self, sub { + my ($s, $event) = @_; + if ($event->HasModifiers) { + $event->Skip; + } else { + my $key = $event->GetKeyCode; + if ($key == ord('0')) { + $self->select_view('iso'); + } elsif ($key == ord('1')) { + $self->select_view('top'); + } elsif ($key == ord('2')) { + $self->select_view('bottom'); + } elsif ($key == ord('3')) { + $self->select_view('front'); + } elsif ($key == ord('4')) { + $self->select_view('rear'); + } elsif ($key == ord('5')) { + $self->select_view('left'); + } elsif ($key == ord('6')) { + $self->select_view('right'); + } else { + $event->Skip; + } + } + }); $self->{layer_height_edit_timer_id} = &Wx::NewId(); $self->{layer_height_edit_timer} = Wx::Timer->new($self, $self->{layer_height_edit_timer_id}); diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 74ae10749..f075b4b28 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -7,7 +7,7 @@ use utf8; use File::Basename qw(basename dirname); use List::Util qw(min); -use Slic3r::Geometry qw(X Y Z); +use Slic3r::Geometry qw(X Y); use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog :font :icon wxTheApp); use Wx::Event qw(EVT_CLOSE EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED); @@ -273,13 +273,16 @@ sub _init_menubar { # View menu if (!$self->{no_plater}) { $self->{viewMenu} = Wx::Menu->new; - $self->_append_menu_item($self->{viewMenu}, "Iso" , 'Iso View' , sub { $self->select_view('iso' ); }); - $self->_append_menu_item($self->{viewMenu}, "Top" , 'Top View' , sub { $self->select_view('top' ); }); - $self->_append_menu_item($self->{viewMenu}, "Bottom" , 'Bottom View' , sub { $self->select_view('bottom' ); }); - $self->_append_menu_item($self->{viewMenu}, "Front" , 'Front View' , sub { $self->select_view('front' ); }); - $self->_append_menu_item($self->{viewMenu}, "Rear" , 'Rear View' , sub { $self->select_view('rear' ); }); - $self->_append_menu_item($self->{viewMenu}, "Left" , 'Left View' , sub { $self->select_view('left' ); }); - $self->_append_menu_item($self->{viewMenu}, "Right" , 'Right View' , sub { $self->select_view('right' ); }); + # \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators, + # as the simple numeric accelerators spoil all numeric data entry. + # The camera control accelerators are captured by 3DScene Perl module instead. + $self->_append_menu_item($self->{viewMenu}, "Iso\t\xA00" , 'Iso View' , sub { $self->select_view('iso' ); }); + $self->_append_menu_item($self->{viewMenu}, "Top\t\xA01" , 'Top View' , sub { $self->select_view('top' ); }); + $self->_append_menu_item($self->{viewMenu}, "Bottom\t\xA02" , 'Bottom View' , sub { $self->select_view('bottom' ); }); + $self->_append_menu_item($self->{viewMenu}, "Front\t\xA03" , 'Front View' , sub { $self->select_view('front' ); }); + $self->_append_menu_item($self->{viewMenu}, "Rear\t\xA04" , 'Rear View' , sub { $self->select_view('rear' ); }); + $self->_append_menu_item($self->{viewMenu}, "Left\t\xA05" , 'Left View' , sub { $self->select_view('left' ); }); + $self->_append_menu_item($self->{viewMenu}, "Right\t\xA06" , 'Right View' , sub { $self->select_view('right' ); }); } # Help menu diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 5d6f8d23a..6e06687d4 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -7,7 +7,7 @@ use utf8; use File::Basename qw(basename dirname); use List::Util qw(sum first max); -use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale deg2rad rad2deg); +use Slic3r::Geometry qw(X Y Z scale unscale deg2rad rad2deg); use LWP::UserAgent; use threads::shared qw(shared_clone); use Wx qw(:button :colour :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc @@ -105,6 +105,12 @@ 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_rotate_object_left(sub { $self->rotate(-45, Z, 'relative') }); + $self->{canvas3D}->set_on_rotate_object_right(sub { $self->rotate( 45, Z, 'relative') }); + $self->{canvas3D}->set_on_scale_object_uniformly(sub { $self->changescale(undef) }); + $self->{canvas3D}->set_on_increase_objects(sub { $self->increase() }); + $self->{canvas3D}->set_on_decrease_objects(sub { $self->decrease() }); + $self->{canvas3D}->set_on_remove_object(sub { $self->remove() }); $self->{canvas3D}->set_on_instances_moved($on_instances_moved); $self->{canvas3D}->set_on_wipe_tower_moved(sub { my ($new_pos_3f) = @_; @@ -862,8 +868,9 @@ sub remove { $self->{preview3D}->enabled(0) if $self->{preview3D}; # if no object index is supplied, remove the selected one - if (!defined $obj_idx) { + if (! defined $obj_idx) { ($obj_idx, undef) = $self->selected_object; + return if ! defined $obj_idx; } splice @{$self->{objects}}, $obj_idx, 1; @@ -1121,12 +1128,12 @@ sub changescale { if ($tosize) { my $cursize = max(@$object_size); my $newsize = $self->_get_number_from_user('Enter the new max size for the selected object:', 'Scale', 'Invalid scaling value entered', $cursize, 1); - return if $newsize eq ''; + return if ! defined($newsize) || $newsize eq ''; $scale = $model_instance->scaling_factor * $newsize / $cursize * 100; } else { # max scale factor should be above 2540 to allow importing files exported in inches $scale = $self->_get_number_from_user('Enter the scale % for the selected object:', 'Scale', 'Invalid scaling value entered', $model_instance->scaling_factor*100, 1); - return if $scale eq ''; + return if ! defined($scale) || $scale eq ''; } $self->{list}->SetItem($obj_idx, 2, "$scale%"); @@ -2060,23 +2067,23 @@ sub object_menu { my $frame = $self->GetFrame; my $menu = Wx::Menu->new; - $frame->_append_menu_item($menu, "Delete\tCtrl+Del", 'Remove the selected object', sub { + $frame->_append_menu_item($menu, "Delete\t\xA0Del", 'Remove the selected object', sub { $self->remove; }, undef, 'brick_delete.png'); - $frame->_append_menu_item($menu, "Increase copies\tCtrl++", 'Place one more copy of the selected object', sub { + $frame->_append_menu_item($menu, "Increase copies\t\xA0+", 'Place one more copy of the selected object', sub { $self->increase; }, undef, 'add.png'); - $frame->_append_menu_item($menu, "Decrease copies\tCtrl+-", 'Remove one copy of the selected object', sub { + $frame->_append_menu_item($menu, "Decrease copies\t\xA0-", 'Remove one copy of the selected object', sub { $self->decrease; }, undef, 'delete.png'); $frame->_append_menu_item($menu, "Set number of copies…", 'Change the number of copies of the selected object', sub { $self->set_number_of_copies; }, undef, 'textfield.png'); $menu->AppendSeparator(); - $frame->_append_menu_item($menu, "Rotate 45° clockwise", 'Rotate the selected object by 45° clockwise', sub { + $frame->_append_menu_item($menu, "Rotate 45° clockwise\t\xA0l", 'Rotate the selected object by 45° clockwise', sub { $self->rotate(-45, Z, 'relative'); }, undef, 'arrow_rotate_clockwise.png'); - $frame->_append_menu_item($menu, "Rotate 45° counter-clockwise", 'Rotate the selected object by 45° counter-clockwise', sub { + $frame->_append_menu_item($menu, "Rotate 45° counter-clockwise\t\xA0r", 'Rotate the selected object by 45° counter-clockwise', sub { $self->rotate(+45, Z, 'relative'); }, undef, 'arrow_rotate_anticlockwise.png'); @@ -2109,7 +2116,7 @@ sub object_menu { my $scaleMenu = Wx::Menu->new; my $scaleMenuItem = $menu->AppendSubMenu($scaleMenu, "Scale", 'Scale the selected object along a single axis'); $frame->_set_menu_item_icon($scaleMenuItem, 'arrow_out.png'); - $frame->_append_menu_item($scaleMenu, "Uniformly…", 'Scale the selected object along the XYZ axes', sub { + $frame->_append_menu_item($scaleMenu, "Uniformly…\t\xA0s", 'Scale the selected object along the XYZ axes', sub { $self->changescale(undef); }); $frame->_append_menu_item($scaleMenu, "Along X axis…", 'Scale the selected object along the X axis', sub { @@ -2203,9 +2210,6 @@ sub OnDropFiles { package Slic3r::GUI::Plater::Object; use Moo; -use List::Util qw(first); -use Slic3r::Geometry qw(X Y Z MIN MAX deg2rad); - has 'name' => (is => 'rw', required => 1); has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled model units with no transforms has 'transformed_thumbnail' => (is => 'rw'); diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm index 6fa46030a..503a3d159 100644 --- a/lib/Slic3r/GUI/Plater/3D.pm +++ b/lib/Slic3r/GUI/Plater/3D.pm @@ -4,12 +4,14 @@ use warnings; use utf8; use List::Util qw(); -use Slic3r::Geometry qw(); -use Slic3r::Geometry::Clipper qw(); -use Wx qw(:misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL); -use Wx::Event qw(); +use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL); +use Wx::Event qw(EVT_KEY_DOWN EVT_CHAR); use base qw(Slic3r::GUI::3DScene Class::Accessor); +__PACKAGE__->mk_accessors(qw( + on_rotate_object_left on_rotate_object_right on_scale_object_uniformly + on_remove_object on_increase_objects on_decrease_objects)); + sub new { my $class = shift; my ($parent, $objects, $model, $print, $config) = @_; @@ -65,6 +67,42 @@ sub new { $self->{on_wipe_tower_moved}->($wipe_tower_moved) if $wipe_tower_moved && $self->{on_wipe_tower_moved}; }); + + EVT_KEY_DOWN($self, sub { + my ($s, $event) = @_; + if ($event->HasModifiers) { + $event->Skip; + } else { + my $key = $event->GetKeyCode; + if ($key == WXK_DELETE) { + $self->on_remove_object->() if $self->on_remove_object; + } else { + $event->Skip; + } + } + }); + + EVT_CHAR($self, sub { + my ($s, $event) = @_; + if ($event->HasModifiers) { + $event->Skip; + } else { + my $key = $event->GetKeyCode; + if ($key == ord('l')) { + $self->on_rotate_object_left->() if $self->on_rotate_object_left; + } elsif ($key == ord('r')) { + $self->on_rotate_object_right->() if $self->on_rotate_object_right; + } elsif ($key == ord('s')) { + $self->on_scale_object_uniformly->() if $self->on_scale_object_uniformly; + } elsif ($key == ord('+')) { + $self->on_increase_objects->() if $self->on_increase_objects; + } elsif ($key == ord('-')) { + $self->on_decrease_objects->() if $self->on_decrease_objects; + } else { + $event->Skip; + } + } + }); return $self; } @@ -84,6 +122,36 @@ sub set_on_right_click { $self->on_right_click($cb); } +sub set_on_rotate_object_left { + my ($self, $cb) = @_; + $self->on_rotate_object_left($cb); +} + +sub set_on_rotate_object_right { + my ($self, $cb) = @_; + $self->on_rotate_object_right($cb); +} + +sub set_on_scale_object_uniformly { + my ($self, $cb) = @_; + $self->on_scale_object_uniformly($cb); +} + +sub set_on_increase_objects { + my ($self, $cb) = @_; + $self->on_increase_objects($cb); +} + +sub set_on_decrease_objects { + my ($self, $cb) = @_; + $self->on_decrease_objects($cb); +} + +sub set_on_remove_object { + my ($self, $cb) = @_; + $self->on_remove_object($cb); +} + sub set_on_instances_moved { my ($self, $cb) = @_; $self->{on_instances_moved} = $cb; -- cgit v1.2.3