From 276533e236fed185744b9fc71331bd576c951b31 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 31 May 2018 13:51:50 +0200 Subject: [PATCH] 3DScene mouse event handler partially moved to c++ --- lib/Slic3r/GUI/3DScene.pm | 421 ++++++++++-------------- lib/Slic3r/GUI/Plater.pm | 20 +- lib/Slic3r/GUI/Plater/2D.pm | 5 +- lib/Slic3r/GUI/Plater/3D.pm | 26 +- xs/src/slic3r/GUI/3DScene.cpp | 25 ++ xs/src/slic3r/GUI/3DScene.hpp | 5 + xs/src/slic3r/GUI/GLCanvas3D.cpp | 329 +++++++++++++++++- xs/src/slic3r/GUI/GLCanvas3D.hpp | 38 +++ xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 46 +++ xs/src/slic3r/GUI/GLCanvas3DManager.hpp | 5 + xs/xsp/GUI_3DScene.xsp | 39 ++- 11 files changed, 693 insertions(+), 266 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 83cf5b45d..4715b6ecf 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -35,11 +35,8 @@ use Slic3r::Geometry qw(PI); # _camera_type: 'perspective' or 'ortho' #============================================================================================================================== __PACKAGE__->mk_accessors( qw(_quat init - enable_moving on_viewport_changed on_select - on_double_click - on_right_click on_move on_model_update volumes @@ -220,9 +217,7 @@ sub new { # $self->Refresh; # }); # EVT_MOUSEWHEEL($self, \&mouse_wheel_event); -#============================================================================================================================== - EVT_MOUSE_EVENTS($self, \&mouse_event); -#============================================================================================================================== +# EVT_MOUSE_EVENTS($self, \&mouse_event); ## EVT_KEY_DOWN($self, sub { # EVT_CHAR($self, sub { # my ($s, $event) = @_; @@ -433,139 +428,97 @@ sub Destroy { # # Automatic action on mouse down with the same coordinate. # $self->{layer_height_edit_timer}->Start(100, wxTIMER_CONTINUOUS); #} -#============================================================================================================================== - -sub mouse_event { - my ($self, $e) = @_; - - my $pos = Slic3r::Pointf->new($e->GetPositionXY); -#============================================================================================================================== - my $object_idx_selected = (Slic3r::GUI::_3DScene::is_layers_editing_enabled($self) && $self->{print}) ? Slic3r::GUI::_3DScene::get_layers_editing_first_selected_object_id($self, $self->{print}->object_count) : -1; - Slic3r::GUI::_3DScene::set_layers_editing_last_object_id($self, $object_idx_selected); +# +#sub mouse_event { +# my ($self, $e) = @_; +# +# my $pos = Slic3r::Pointf->new($e->GetPositionXY); # my $object_idx_selected = $self->{layer_height_edit_last_object_id} = ($self->layer_editing_enabled && $self->{print}) ? $self->_first_selected_object_id_for_variable_layer_height_editing : -1; -#============================================================================================================================== - -#============================================================================================================================== - Slic3r::GUI::_3DScene::set_mouse_dragging($self, $e->Dragging); +# # $self->_mouse_dragging($e->Dragging); -#============================================================================================================================== - - if ($e->Entering && (&Wx::wxMSW || $^O eq 'linux')) { - # wxMSW needs focus in order to catch mouse wheel events - $self->SetFocus; - $self->_drag_start_xy(undef); - } elsif ($e->LeftDClick) { -#============================================================================================================================== - if ($object_idx_selected != -1 && Slic3r::GUI::_3DScene::bar_rect_contains($self, $e->GetX, $e->GetY)) { +# +# if ($e->Entering && (&Wx::wxMSW || $^O eq 'linux')) { +# # wxMSW needs focus in order to catch mouse wheel events +# $self->SetFocus; +# $self->_drag_start_xy(undef); +# } elsif ($e->LeftDClick) { # if ($object_idx_selected != -1 && $self->_variable_layer_thickness_bar_rect_mouse_inside($e)) { -#============================================================================================================================== - } elsif ($self->on_double_click) { - $self->on_double_click->(); - } - } elsif ($e->LeftDown || $e->RightDown) { - # If user pressed left or right button we first check whether this happened - # on a volume or not. -#============================================================================================================================== - my $volume_idx = Slic3r::GUI::_3DScene::get_hover_volume_id($self); - Slic3r::GUI::_3DScene::set_layers_editing_state($self, 0); +# } elsif ($self->on_double_click) { +# $self->on_double_click->(); +# } +# } elsif ($e->LeftDown || $e->RightDown) { +# # If user pressed left or right button we first check whether this happened +# # on a volume or not. # my $volume_idx = $self->_hover_volume_idx // -1; # $self->_layer_height_edited(0); -#============================================================================================================================== -#============================================================================================================================== - if ($object_idx_selected != -1 && Slic3r::GUI::_3DScene::bar_rect_contains($self, $e->GetX, $e->GetY)) { # if ($object_idx_selected != -1 && $self->_variable_layer_thickness_bar_rect_mouse_inside($e)) { -#============================================================================================================================== - # A volume is selected and the mouse is hovering over a layer thickness bar. - # Start editing the layer height. -#============================================================================================================================== - Slic3r::GUI::_3DScene::set_layers_editing_state($self, 1); - Slic3r::GUI::_3DScene::perform_layer_editing_action($self, $e->GetY, $e->ShiftDown, $e->RightIsDown); +# # A volume is selected and the mouse is hovering over a layer thickness bar. +# # Start editing the layer height. # $self->_layer_height_edited(1); # $self->_variable_layer_thickness_action($e); -#============================================================================================================================== -#============================================================================================================================== - } elsif ($object_idx_selected != -1 && Slic3r::GUI::_3DScene::reset_rect_contains($self, $e->GetX, $e->GetY)) { # } elsif ($object_idx_selected != -1 && $self->_variable_layer_thickness_reset_rect_mouse_inside($e)) { -#============================================================================================================================== - $self->{print}->get_object($object_idx_selected)->reset_layer_height_profile; - # Index 2 means no editing, just wait for mouse up event. -#============================================================================================================================== - Slic3r::GUI::_3DScene::set_layers_editing_state($self, 2); +# $self->{print}->get_object($object_idx_selected)->reset_layer_height_profile; +# # Index 2 means no editing, just wait for mouse up event. # $self->_layer_height_edited(2); -#============================================================================================================================== - $self->Refresh; - $self->Update; - } else { - # The mouse_to_3d gets the Z coordinate from the Z buffer at the screen coordinate $pos->x,y, - # an converts the screen space coordinate to unscaled object space. - my $pos3d = ($volume_idx == -1) ? undef : $self->mouse_to_3d(@$pos); - - # Select volume in this 3D canvas. - # Don't deselect a volume if layer editing is enabled. We want the object to stay selected - # during the scene manipulation. -#============================================================================================================================== - -#============================================================================================================================== - if (Slic3r::GUI::_3DScene::is_picking_enabled($self) && ($volume_idx != -1 || ! Slic3r::GUI::_3DScene::is_layers_editing_enabled($self))) { - Slic3r::GUI::_3DScene::deselect_volumes($self); - Slic3r::GUI::_3DScene::select_volume($self, $volume_idx); +# $self->Refresh; +# $self->Update; +# } else { +# # The mouse_to_3d gets the Z coordinate from the Z buffer at the screen coordinate $pos->x,y, +# # an converts the screen space coordinate to unscaled object space. +# my $pos3d = ($volume_idx == -1) ? undef : $self->mouse_to_3d(@$pos); +# +# # Select volume in this 3D canvas. +# # Don't deselect a volume if layer editing is enabled. We want the object to stay selected +# # during the scene manipulation. +# # if ($self->enable_picking && ($volume_idx != -1 || ! $self->layer_editing_enabled)) { # $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) { -#============================================================================================================================== - Slic3r::GUI::_3DScene::select_volume($self, $_) +# +# 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; - $self->Update; - } - - # propagate event through callback - $self->on_select->($volume_idx) - if $self->on_select; - - if ($volume_idx != -1) { - if ($e->LeftDown && $self->enable_moving) { - # Only accept the initial position, if it is inside the volume bounding box. - my $volume_bbox = $self->volumes->[$volume_idx]->transformed_bounding_box; - $volume_bbox->offset(1.); - if ($volume_bbox->contains_point($pos3d)) { - # The dragging operation is initiated. - $self->_drag_volume_idx($volume_idx); - $self->_drag_start_pos($pos3d); - # Remember the shift to to the object center. The object center will later be used - # to limit the object placement close to the bed. - $self->_drag_volume_center_offset($pos3d->vector_to($volume_bbox->center)); - } - } elsif ($e->RightDown) { - # if right clicking on volume, propagate event through callback - $self->on_right_click->($e->GetPosition) - if $self->on_right_click; - } - } - } -#============================================================================================================================== - } elsif ($e->Dragging && $e->LeftIsDown && (Slic3r::GUI::_3DScene::get_layers_editing_state($self) == 0) && defined($self->_drag_volume_idx)) { +# for grep $self->volumes->[$_]->select_group_id == $group_id, +# 0..$#{$self->volumes}; +# } +# } +# +# $self->Refresh; +# $self->Update; +# } +# +# # propagate event through callback +# $self->on_select->($volume_idx) +# if $self->on_select; +# +# if ($volume_idx != -1) { +# if ($e->LeftDown && $self->enable_moving) { +# # Only accept the initial position, if it is inside the volume bounding box. +# my $volume_bbox = $self->volumes->[$volume_idx]->transformed_bounding_box; +# $volume_bbox->offset(1.); +# if ($volume_bbox->contains_point($pos3d)) { +# # The dragging operation is initiated. +# $self->_drag_volume_idx($volume_idx); +# $self->_drag_start_pos($pos3d); +# # Remember the shift to to the object center. The object center will later be used +# # to limit the object placement close to the bed. +# $self->_drag_volume_center_offset($pos3d->vector_to($volume_bbox->center)); +# } +# } elsif ($e->RightDown) { +# # if right clicking on volume, propagate event through callback +# $self->on_right_click->($e->GetPosition) +# if $self->on_right_click; +# } +# } +# } # } elsif ($e->Dragging && $e->LeftIsDown && ! $self->_layer_height_edited && defined($self->_drag_volume_idx)) { -#============================================================================================================================== - # Get new position at the same Z of the initial click point. - my $cur_pos = Slic3r::Linef3->new( - $self->mouse_to_3d($e->GetX, $e->GetY, 0), - $self->mouse_to_3d($e->GetX, $e->GetY, 1)) - ->intersect_plane($self->_drag_start_pos->z); -#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ -# >>>>>>>>>>>>>>>>>>>>>>>>>> TEMPORARY DISABLED DUE TO bed_polygon REMOVAL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +# # Get new position at the same Z of the initial click point. +# my $cur_pos = Slic3r::Linef3->new( +# $self->mouse_to_3d($e->GetX, $e->GetY, 0), +# $self->mouse_to_3d($e->GetX, $e->GetY, 1)) +# ->intersect_plane($self->_drag_start_pos->z); # # # Clip the new position, so the object center remains close to the bed. # { @@ -578,124 +531,96 @@ sub mouse_event { # } # $cur_pos->translate(@{$self->_drag_volume_center_offset->negative}); # } -#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ - # Calculate the translation vector. - my $vector = $self->_drag_start_pos->vector_to($cur_pos); - # Get the volume being dragged. - my $volume = $self->volumes->[$self->_drag_volume_idx]; - # Get all volumes belonging to the same group, if any. - my @volumes = ($volume->drag_group_id == -1) ? - ($volume) : - grep $_->drag_group_id == $volume->drag_group_id, @{$self->volumes}; - # Apply new temporary volume origin and ignore Z. - $_->translate($vector->x, $vector->y, 0) for @volumes; - $self->_drag_start_pos($cur_pos); - $self->_dragged(1); - $self->Refresh; - $self->Update; - } elsif ($e->Dragging) { -#============================================================================================================================== - if ((Slic3r::GUI::_3DScene::get_layers_editing_state($self) > 0) && ($object_idx_selected != -1)) { - Slic3r::GUI::_3DScene::perform_layer_editing_action($self, $e->GetY, $e->ShiftDown, $e->RightIsDown) if (Slic3r::GUI::_3DScene::get_layers_editing_state($self) == 1); - +# # Calculate the translation vector. +# my $vector = $self->_drag_start_pos->vector_to($cur_pos); +# # Get the volume being dragged. +# my $volume = $self->volumes->[$self->_drag_volume_idx]; +# # Get all volumes belonging to the same group, if any. +# my @volumes = ($volume->drag_group_id == -1) ? +# ($volume) : +# grep $_->drag_group_id == $volume->drag_group_id, @{$self->volumes}; +# # Apply new temporary volume origin and ignore Z. +# $_->translate($vector->x, $vector->y, 0) for @volumes; +# $self->_drag_start_pos($cur_pos); +# $self->_dragged(1); +# $self->Refresh; +# $self->Update; +# } elsif ($e->Dragging) { # if ($self->_layer_height_edited && $object_idx_selected != -1) { # $self->_variable_layer_thickness_action($e) if ($self->_layer_height_edited == 1); -#============================================================================================================================== - } elsif ($e->LeftIsDown) { - # if dragging over blank area with left button, rotate - if (defined $self->_drag_start_pos) { - my $orig = $self->_drag_start_pos; - if (TURNTABLE_MODE) { - # Turntable mode is enabled by default. -#============================================================================================================================== - Slic3r::GUI::_3DScene::set_camera_phi($self, Slic3r::GUI::_3DScene::get_camera_phi($self) + ($pos->x - $orig->x) * TRACKBALLSIZE); - Slic3r::GUI::_3DScene::set_camera_theta($self, Slic3r::GUI::_3DScene::get_camera_theta($self) - ($pos->y - $orig->y) * TRACKBALLSIZE); - +# } elsif ($e->LeftIsDown) { +# # if dragging over blank area with left button, rotate +# if (defined $self->_drag_start_pos) { +# my $orig = $self->_drag_start_pos; +# if (TURNTABLE_MODE) { +# # Turntable mode is enabled by default. # $self->_sphi($self->_sphi + ($pos->x - $orig->x) * TRACKBALLSIZE); # $self->_stheta($self->_stheta - ($pos->y - $orig->y) * TRACKBALLSIZE); #- # $self->_stheta(GIMBALL_LOCK_THETA_MAX) if $self->_stheta > GIMBALL_LOCK_THETA_MAX; # $self->_stheta(0) if $self->_stheta < 0; -#============================================================================================================================== - } else { - my $size = $self->GetClientSize; - my @quat = trackball( - $orig->x / ($size->width / 2) - 1, - 1 - $orig->y / ($size->height / 2), #/ - $pos->x / ($size->width / 2) - 1, - 1 - $pos->y / ($size->height / 2), #/ - ); - $self->_quat(mulquats($self->_quat, \@quat)); - } - $self->on_viewport_changed->() if $self->on_viewport_changed; - $self->Refresh; - $self->Update; - } - $self->_drag_start_pos($pos); - } elsif ($e->MiddleIsDown || $e->RightIsDown) { - # If dragging over blank area with right button, pan. - if (defined $self->_drag_start_xy) { - # get point in model space at Z = 0 - my $cur_pos = $self->mouse_to_3d($e->GetX, $e->GetY, 0); - my $orig = $self->mouse_to_3d($self->_drag_start_xy->x, $self->_drag_start_xy->y, 0); -#============================================================================================================================== - my $camera_target = Slic3r::GUI::_3DScene::get_camera_target($self); - $camera_target->translate(@{$orig->vector_to($cur_pos)->negative}); - Slic3r::GUI::_3DScene::set_camera_target($self, $camera_target); +# } else { +# my $size = $self->GetClientSize; +# my @quat = trackball( +# $orig->x / ($size->width / 2) - 1, +# 1 - $orig->y / ($size->height / 2), #/ +# $pos->x / ($size->width / 2) - 1, +# 1 - $pos->y / ($size->height / 2), #/ +# ); +# $self->_quat(mulquats($self->_quat, \@quat)); +# } +# $self->on_viewport_changed->() if $self->on_viewport_changed; +# $self->Refresh; +# $self->Update; +# } +# $self->_drag_start_pos($pos); +# } elsif ($e->MiddleIsDown || $e->RightIsDown) { +# # If dragging over blank area with right button, pan. +# if (defined $self->_drag_start_xy) { +# # get point in model space at Z = 0 +# my $cur_pos = $self->mouse_to_3d($e->GetX, $e->GetY, 0); +# my $orig = $self->mouse_to_3d($self->_drag_start_xy->x, $self->_drag_start_xy->y, 0); # $self->_camera_target->translate(@{$orig->vector_to($cur_pos)->negative}); -#============================================================================================================================== - $self->on_viewport_changed->() if $self->on_viewport_changed; - $self->Refresh; - $self->Update; - } - $self->_drag_start_xy($pos); - } - } elsif ($e->LeftUp || $e->MiddleUp || $e->RightUp) { -#============================================================================================================================== - if (Slic3r::GUI::_3DScene::get_layers_editing_state($self) > 0) { - Slic3r::GUI::_3DScene::set_layers_editing_state($self, 0); - Slic3r::GUI::_3DScene::stop_timer($self); +# $self->on_viewport_changed->() if $self->on_viewport_changed; +# $self->Refresh; +# $self->Update; +# } +# $self->_drag_start_xy($pos); +# } +# } elsif ($e->LeftUp || $e->MiddleUp || $e->RightUp) { # if ($self->_layer_height_edited) { # $self->_layer_height_edited(undef); # $self->{layer_height_edit_timer}->Stop; -#============================================================================================================================== - $self->on_model_update->() - if ($object_idx_selected != -1 && $self->on_model_update); - } elsif ($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); - $self->_drag_start_xy(undef); - $self->_dragged(undef); - } elsif ($e->Moving) { -#============================================================================================================================== - Slic3r::GUI::_3DScene::set_mouse_position($self, $pos); +# $self->on_model_update->() +# if ($object_idx_selected != -1 && $self->on_model_update); +# } elsif ($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); +# $self->_drag_start_xy(undef); +# $self->_dragged(undef); +# } elsif ($e->Moving) { # $self->_mouse_pos($pos); -#============================================================================================================================== - # Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor - # hovers over. -#============================================================================================================================== - if (Slic3r::GUI::_3DScene::is_picking_enabled($self)) { +# # Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor +# # hovers over. # if ($self->enable_picking) { -#============================================================================================================================== - $self->Update; - $self->Refresh; - } - } else { - $e->Skip(); - } -} - -#============================================================================================================================== +# $self->Update; +# $self->Refresh; +# } +# } else { +# $e->Skip(); +# } +#} +# #sub mouse_wheel_event { # my ($self, $e) = @_; # @@ -1165,23 +1090,25 @@ sub mulquats { @$q1[3] * @$rq[3] - @$q1[0] * @$rq[0] - @$q1[1] * @$rq[1] - @$q1[2] * @$rq[2]) } -# Convert the screen space coordinate to an object space coordinate. -# If the Z screen space coordinate is not provided, a depth buffer value is substituted. -sub mouse_to_3d { - my ($self, $x, $y, $z) = @_; - - return unless $self->GetContext; - $self->SetCurrent($self->GetContext); - - my @viewport = glGetIntegerv_p(GL_VIEWPORT); # 4 items - my @mview = glGetDoublev_p(GL_MODELVIEW_MATRIX); # 16 items - my @proj = glGetDoublev_p(GL_PROJECTION_MATRIX); # 16 items - - $y = $viewport[3] - $y; - $z //= glReadPixels_p($x, $y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); - my @projected = gluUnProject_p($x, $y, $z, @mview, @proj, @viewport); - return Slic3r::Pointf3->new(@projected); -} +#============================================================================================================================== +## Convert the screen space coordinate to an object space coordinate. +## If the Z screen space coordinate is not provided, a depth buffer value is substituted. +#sub mouse_to_3d { +# my ($self, $x, $y, $z) = @_; +# +# return unless $self->GetContext; +# $self->SetCurrent($self->GetContext); +# +# my @viewport = glGetIntegerv_p(GL_VIEWPORT); # 4 items +# my @mview = glGetDoublev_p(GL_MODELVIEW_MATRIX); # 16 items +# my @proj = glGetDoublev_p(GL_PROJECTION_MATRIX); # 16 items +# +# $y = $viewport[3] - $y; +# $z //= glReadPixels_p($x, $y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); +# my @projected = gluUnProject_p($x, $y, $z, @mview, @proj, @viewport); +# return Slic3r::Pointf3->new(@projected); +#} +#============================================================================================================================== sub GetContext { my ($self) = @_; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 3d1f75221..35468aad5 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -84,13 +84,19 @@ sub new { $self->object_settings_dialog if $self->selected_object; }; my $on_right_click = sub { - my ($canvas, $click_pos) = @_; - +#============================================================================================================================== + my ($canvas, $click_pos_x, $click_pos_y) = @_; +# my ($canvas, $click_pos) = @_; +#============================================================================================================================== + my ($obj_idx, $object) = $self->selected_object; return if !defined $obj_idx; my $menu = $self->object_menu; - $canvas->PopupMenu($menu, $click_pos); +#============================================================================================================================== + $canvas->PopupMenu($menu, $click_pos_x, $click_pos_y); +# $canvas->PopupMenu($menu, $click_pos); +#============================================================================================================================== $menu->Destroy; }; my $on_instances_moved = sub { @@ -111,8 +117,12 @@ sub new { $self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config}); $self->{preview_notebook}->AddPage($self->{canvas3D}, L('3D')); $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}, @_); }); +#============================================================================================================================== + Slic3r::GUI::_3DScene::register_on_double_click_callback($self->{canvas3D}, $on_double_click); + Slic3r::GUI::_3DScene::register_on_right_click_callback($self->{canvas3D}, sub { $on_right_click->($self->{canvas3D}, @_); }); +# $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_arrange(sub { $self->arrange }); $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') }); diff --git a/lib/Slic3r/GUI/Plater/2D.pm b/lib/Slic3r/GUI/Plater/2D.pm index 7beba9299..120fec830 100644 --- a/lib/Slic3r/GUI/Plater/2D.pm +++ b/lib/Slic3r/GUI/Plater/2D.pm @@ -222,7 +222,10 @@ sub mouse_event { ]; $self->{drag_object} = [ $obj_idx, $instance_idx ]; } elsif ($event->RightDown) { - $self->{on_right_click}->($pos); +#======================================================================================================================================= + $self->{on_right_click}->($pos->x, $pos->y); +# $self->{on_right_click}->($pos); +#======================================================================================================================================= } last OBJECTS; diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm index a8db8ccbf..04aca9aaf 100644 --- a/lib/Slic3r/GUI/Plater/3D.pm +++ b/lib/Slic3r/GUI/Plater/3D.pm @@ -21,9 +21,10 @@ sub new { my $self = $class->SUPER::new($parent); #============================================================================================================================== Slic3r::GUI::_3DScene::enable_picking($self, 1); + Slic3r::GUI::_3DScene::enable_moving($self, 1); # $self->enable_picking(1); +# $self->enable_moving(1); #============================================================================================================================== - $self->enable_moving(1); $self->select_by('object'); $self->drag_by('instance'); @@ -46,6 +47,9 @@ sub new { $self->{on_select_object}->(($volume_idx == -1) ? undef : $self->volumes->[$volume_idx]->object_idx) if ($self->{on_select_object}); }); +#============================================================================================================================== + Slic3r::GUI::_3DScene::register_on_select_callback($self, $self->on_select); +#============================================================================================================================== $self->on_move(sub { my @volume_idxs = @_; @@ -125,15 +129,17 @@ sub set_on_select_object { $self->{on_select_object} = $cb; } -sub set_on_double_click { - my ($self, $cb) = @_; - $self->on_double_click($cb); -} - -sub set_on_right_click { - my ($self, $cb) = @_; - $self->on_right_click($cb); -} +#============================================================================================================================== +#sub set_on_double_click { +# my ($self, $cb) = @_; +# $self->on_double_click($cb); +#} +# +#sub set_on_right_click { +# my ($self, $cb) = @_; +# $self->on_right_click($cb); +#} +#============================================================================================================================== sub set_on_arrange { my ($self, $cb) = @_; diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index cb87a43d2..12c1fc180 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1939,6 +1939,11 @@ bool _3DScene::is_picking_enabled(wxGLCanvas* canvas) return s_canvas_mgr.is_picking_enabled(canvas); } +bool _3DScene::is_moving_enabled(wxGLCanvas* canvas) +{ + return s_canvas_mgr.is_moving_enabled(canvas); +} + bool _3DScene::is_layers_editing_allowed(wxGLCanvas* canvas) { return s_canvas_mgr.is_layers_editing_allowed(canvas); @@ -1969,6 +1974,11 @@ void _3DScene::enable_picking(wxGLCanvas* canvas, bool enable) s_canvas_mgr.enable_picking(canvas, enable); } +void _3DScene::enable_moving(wxGLCanvas* canvas, bool enable) +{ + s_canvas_mgr.enable_moving(canvas, enable); +} + void _3DScene::enable_shader(wxGLCanvas* canvas, bool enable) { s_canvas_mgr.enable_shader(canvas, enable); @@ -2170,6 +2180,21 @@ void _3DScene::register_on_viewport_changed_callback(wxGLCanvas* canvas, void* c s_canvas_mgr.register_on_viewport_changed_callback(canvas, callback); } +void _3DScene::register_on_double_click_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_on_double_click_callback(canvas, callback); +} + +void _3DScene::register_on_right_click_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_on_right_click_callback(canvas, callback); +} + +void _3DScene::register_on_select_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_on_select_callback(canvas, callback); +} + //void _3DScene::_glew_init() //{ // glewInit(); diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 22a5e8d61..11969df6c 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -598,6 +598,7 @@ public: static bool is_layers_editing_enabled(wxGLCanvas* canvas); static bool is_picking_enabled(wxGLCanvas* canvas); + static bool is_moving_enabled(wxGLCanvas* canvas); static bool is_layers_editing_allowed(wxGLCanvas* canvas); static bool is_multisample_allowed(wxGLCanvas* canvas); @@ -605,6 +606,7 @@ public: static void enable_warning_texture(wxGLCanvas* canvas, bool enable); static void enable_legend_texture(wxGLCanvas* canvas, bool enable); static void enable_picking(wxGLCanvas* canvas, bool enable); + static void enable_moving(wxGLCanvas* canvas, bool enable); static void enable_shader(wxGLCanvas* canvas, bool enable); static void allow_multisample(wxGLCanvas* canvas, bool allow); @@ -663,6 +665,9 @@ public: static void perform_layer_editing_action(wxGLCanvas* canvas, int y, bool shift_down, bool right_down); static void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback); + static void register_on_double_click_callback(wxGLCanvas* canvas, void* callback); + static void register_on_right_click_callback(wxGLCanvas* canvas, void* callback); + static void register_on_select_callback(wxGLCanvas* canvas, void* callback); // static void _glew_init(); //################################################################################################################## diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 4e2355c89..31c7b81b2 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1048,6 +1048,52 @@ void GLCanvas3D::Mouse::set_position(const Pointf& position) m_position = position; } +GLCanvas3D::Drag::Drag() + : m_start_mouse_position(DBL_MAX, DBL_MAX) + , m_volume_idx(-1) +{ +} + +const Point& GLCanvas3D::Drag::get_start_mouse_position() const +{ + return m_start_mouse_position; +} + +void GLCanvas3D::Drag::set_start_mouse_position(const Point& position) +{ + m_start_mouse_position = position; +} + +const Pointf3& GLCanvas3D::Drag::get_start_position_3D() const +{ + return m_start_position_3D; +} + +void GLCanvas3D::Drag::set_start_position_3D(const Pointf3& position) +{ + m_start_position_3D = position; +} + +const Vectorf3& GLCanvas3D::Drag::get_volume_center_offset() const +{ + return m_volume_center_offset; +} + +void GLCanvas3D::Drag::set_volume_center_offset(const Vectorf3& offset) +{ + m_volume_center_offset = offset; +} + +int GLCanvas3D::Drag::get_volume_idx() const +{ + return m_volume_idx; +} + +void GLCanvas3D::Drag::set_volume_idx(int idx) +{ + m_volume_idx = idx; +} + GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, wxGLContext* context) : m_canvas(canvas) , m_context(context) @@ -1061,6 +1107,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, wxGLContext* context) , m_warning_texture_enabled(false) , m_legend_texture_enabled(false) , m_picking_enabled(false) + , m_moving_enabled(false) , m_shader_enabled(false) , m_multisample_allowed(false) { @@ -1439,6 +1486,11 @@ bool GLCanvas3D::is_picking_enabled() const return m_picking_enabled; } +bool GLCanvas3D::is_moving_enabled() const +{ + return m_moving_enabled; +} + bool GLCanvas3D::is_layers_editing_allowed() const { return m_layers_editing.is_allowed(); @@ -1469,6 +1521,11 @@ void GLCanvas3D::enable_picking(bool enable) m_picking_enabled = enable; } +void GLCanvas3D::enable_moving(bool enable) +{ + m_moving_enabled = enable; +} + void GLCanvas3D::enable_shader(bool enable) { m_shader_enabled = enable; @@ -1768,6 +1825,24 @@ void GLCanvas3D::register_on_viewport_changed_callback(void* callback) m_on_viewport_changed_callback.register_callback(callback); } +void GLCanvas3D::register_on_double_click_callback(void* callback) +{ + if (callback != nullptr) + m_on_double_click_callback.register_callback(callback); +} + +void GLCanvas3D::register_on_right_click_callback(void* callback) +{ + if (callback != nullptr) + m_on_right_click_callback.register_callback(callback); +} + +void GLCanvas3D::register_on_select_callback(void* callback) +{ + if (callback != nullptr) + m_on_select_callback.register_callback(callback); +} + void GLCanvas3D::on_size(wxSizeEvent& evt) { set_dirty(true); @@ -1805,7 +1880,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) { // key B/b case 66: - case 98: { zoom_to_bed(); break; } + case 98: { zoom_to_bed(); break; } // key Z/z case 90: case 122: { zoom_to_volumes(); break; } @@ -1869,6 +1944,231 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt) _perform_layer_editing_action(); } +void GLCanvas3D::on_mouse(wxMouseEvent& evt) +{ + if ((m_canvas == nullptr) || (m_volumes == nullptr)) + return; + + Point pos(evt.GetX(), evt.GetY()); + + int selected_object_idx = (is_layers_editing_enabled() && (m_print != nullptr)) ? get_layers_editing_first_selected_object_id(m_print->objects.size()) : -1; + set_layers_editing_last_object_id(selected_object_idx); + + set_mouse_dragging(evt.Dragging()); + + if (evt.Entering()) + { +#if defined(__WXMSW__) || defined(__WXGTK__) + // On Windows and Linux needs focus in order to catch key events + m_canvas->SetFocus(); + m_drag.set_start_mouse_position(Point(INT_MAX, INT_MAX)); +#endif + } + else if (evt.LeftDClick()) + { + m_on_double_click_callback.call(); + } + else if (evt.LeftDown() || evt.RightDown()) + { + // If user pressed left or right button we first check whether this happened + // on a volume or not. + int volume_idx = get_hover_volume_id(); + set_layers_editing_state(0); + if ((selected_object_idx != -1) && bar_rect_contains(pos.x, pos.y)) + { + // A volume is selected and the mouse is inside the layer thickness bar. + // Start editing the layer height. + set_layers_editing_state(1); + perform_layer_editing_action(evt.GetY(), evt.ShiftDown(), evt.RightDown()); + } + else if ((selected_object_idx != -1) && reset_rect_contains(pos.x, pos.y)) + { + if (evt.LeftDown()) + { + // A volume is selected and the mouse is inside the reset button. + m_print->get_object(selected_object_idx)->reset_layer_height_profile(); + // Index 2 means no editing, just wait for mouse up event. + set_layers_editing_state(2); + m_canvas->Refresh(); + m_canvas->Update(); + } + } + else + { + // Select volume in this 3D canvas. + // Don't deselect a volume if layer editing is enabled. We want the object to stay selected + // during the scene manipulation. + + if (is_picking_enabled() && ((volume_idx != -1) || !is_layers_editing_enabled())) + { + deselect_volumes(); + select_volume(volume_idx); + + if (volume_idx != -1) + { + int group_id = m_volumes->volumes[volume_idx]->select_group_id; + if (group_id != -1) + { + for (GLVolume* vol : m_volumes->volumes) + { + if ((vol != nullptr) && (vol->select_group_id == group_id)) + vol->selected = true; + } + } + } + + m_canvas->Refresh(); + m_canvas->Update(); + } + + // propagate event through callback + m_on_select_callback.call(volume_idx); + + // The mouse_to_3d gets the Z coordinate from the Z buffer at the screen coordinate pos x, y, + // an converts the screen space coordinate to unscaled object space. + Pointf3 pos3d = (volume_idx == -1) ? Pointf3(DBL_MAX, DBL_MAX) : _mouse_to_3d(pos); + + if (volume_idx != -1) + { + if (evt.LeftDown() && is_moving_enabled()) + { + // Only accept the initial position, if it is inside the volume bounding box. + BoundingBoxf3 volume_bbox = m_volumes->volumes[volume_idx]->transformed_bounding_box(); + volume_bbox.offset(1.0); + if (volume_bbox.contains(pos3d)) + { + // The dragging operation is initiated. + m_drag.set_volume_idx(volume_idx); + m_drag.set_start_position_3D(pos3d); + // Remember the shift to to the object center.The object center will later be used + // to limit the object placement close to the bed. + m_drag.set_volume_center_offset(pos3d.vector_to(volume_bbox.center())); + } + } + else if (evt.RightDown()) + { + // if right clicking on volume, propagate event through callback + if (m_volumes->volumes[volume_idx]->hover) + { + m_on_right_click_callback.call(pos.x, pos.y); + } + } + } + } + } +// } elsif($e->Dragging && $e->LeftIsDown && (Slic3r::GUI::_3DScene::get_layers_editing_state($self) == 0) && defined($self->_drag_volume_idx)) { +// # Get new position at the same Z of the initial click point. +// my $cur_pos = Slic3r::Linef3->new( +// $self->mouse_to_3d($e->GetX, $e->GetY, 0), +// $self->mouse_to_3d($e->GetX, $e->GetY, 1)) +// ->intersect_plane($self->_drag_start_pos->z); +// +// # Clip the new position, so the object center remains close to the bed. +// { +// $cur_pos->translate(@{$self->_drag_volume_center_offset}); +// my $cur_pos2 = Slic3r::Point->new(scale($cur_pos->x), scale($cur_pos->y)); +// if (!$self->bed_polygon->contains_point($cur_pos2)) { +// my $ip = $self->bed_polygon->point_projection($cur_pos2); +// $cur_pos->set_x(unscale($ip->x)); +// $cur_pos->set_y(unscale($ip->y)); +// } +// $cur_pos->translate(@{$self->_drag_volume_center_offset->negative}); +// } +// +// # Calculate the translation vector. +// my $vector = $self->_drag_start_pos->vector_to($cur_pos); +// # Get the volume being dragged. +// my $volume = $self->volumes->[$self->_drag_volume_idx]; +// # Get all volumes belonging to the same group, if any. +// my @volumes = ($volume->drag_group_id == -1) ? +// ($volume) : +// grep $_->drag_group_id == $volume->drag_group_id, @{$self->volumes}; +// # Apply new temporary volume origin and ignore Z. +// $_->translate($vector->x, $vector->y, 0) for @volumes; +// $self->_drag_start_pos($cur_pos); +// $self->_dragged(1); +// $self->Refresh; +// $self->Update; +// } elsif($e->Dragging) { +// if ((Slic3r::GUI::_3DScene::get_layers_editing_state($self) > 0) && ($object_idx_selected != -1)) { +// Slic3r::GUI::_3DScene::perform_layer_editing_action($self, $e->GetY, $e->ShiftDown, $e->RightIsDown) if (Slic3r::GUI::_3DScene::get_layers_editing_state($self) == 1); +// } elsif($e->LeftIsDown) { +//# if dragging over blank area with left button, rotate +// if (defined $self->_drag_start_pos) { +// my $orig = $self->_drag_start_pos; +// if (TURNTABLE_MODE) { +// # Turntable mode is enabled by default. +// Slic3r::GUI::_3DScene::set_camera_phi($self, Slic3r::GUI::_3DScene::get_camera_phi($self) + ($pos->x - $orig->x) * TRACKBALLSIZE); +// Slic3r::GUI::_3DScene::set_camera_theta($self, Slic3r::GUI::_3DScene::get_camera_theta($self) - ($pos->y - $orig->y) * TRACKBALLSIZE); +// } +// else { +// my $size = $self->GetClientSize; +// my @quat = trackball( +// $orig->x / ($size->width / 2) - 1, +// 1 - $orig->y / ($size->height / 2), # / +// $pos->x / ($size->width / 2) - 1, +// 1 - $pos->y / ($size->height / 2), # / +// ); +// $self->_quat(mulquats($self->_quat, \@quat)); +// } +// $self->on_viewport_changed->() if $self->on_viewport_changed; +// $self->Refresh; +// $self->Update; +// } +// $self->_drag_start_pos($pos); +// } elsif($e->MiddleIsDown || $e->RightIsDown) { +// # If dragging over blank area with right button, pan. +// if (defined $self->_drag_start_xy) { +// # get point in model space at Z = 0 +// my $cur_pos = $self->mouse_to_3d($e->GetX, $e->GetY, 0); +// my $orig = $self->mouse_to_3d($self->_drag_start_xy->x, $self->_drag_start_xy->y, 0); +// my $camera_target = Slic3r::GUI::_3DScene::get_camera_target($self); +// $camera_target->translate(@{$orig->vector_to($cur_pos)->negative}); +// Slic3r::GUI::_3DScene::set_camera_target($self, $camera_target); +// $self->on_viewport_changed->() if $self->on_viewport_changed; +// $self->Refresh; +// $self->Update; +// } +// $self->_drag_start_xy($pos); +// } +// } elsif($e->LeftUp || $e->MiddleUp || $e->RightUp) { +// if (Slic3r::GUI::_3DScene::get_layers_editing_state($self) > 0) { +// Slic3r::GUI::_3DScene::set_layers_editing_state($self, 0); +// Slic3r::GUI::_3DScene::stop_timer($self); +// $self->on_model_update->() +// if ($object_idx_selected != -1 && $self->on_model_update); +// } elsif($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); +// $self->_drag_start_xy(undef); +// $self->_dragged(undef); +// } + else if (evt.Moving()) + { + set_mouse_position(Pointf((coordf_t)pos.x, (coordf_t)pos.y)); + // Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor hovers over. + if (is_picking_enabled()) + { + m_canvas->Refresh(); + m_canvas->Update(); + } + } + else + evt.Skip(); +} + Size GLCanvas3D::get_canvas_size() const { int w = 0; @@ -1997,6 +2297,9 @@ float GLCanvas3D::_get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) co void GLCanvas3D::_deregister_callbacks() { m_on_viewport_changed_callback.deregister_callback(); + m_on_double_click_callback.deregister_callback(); + m_on_right_click_callback.deregister_callback(); + m_on_select_callback.deregister_callback(); } void GLCanvas3D::_mark_volumes_for_layer_height() const @@ -2337,5 +2640,29 @@ void GLCanvas3D::_perform_layer_editing_action(wxMouseEvent* evt) start_timer(); } +Pointf3 GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z) +{ + if (!set_current()) + return Pointf3(DBL_MAX, DBL_MAX, DBL_MAX); + + GLint viewport[4]; + ::glGetIntegerv(GL_VIEWPORT, viewport); + GLdouble modelview_matrix[16]; + ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix); + GLdouble projection_matrix[16]; + ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix); + + GLint y = viewport[3] - (GLint)mouse_pos.y; + GLfloat mouse_z; + if (z == nullptr) + ::glReadPixels((GLint)mouse_pos.x, (GLint)mouse_pos.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)&mouse_z); + else + mouse_z = *z; + + GLdouble out_x, out_y, out_z; + ::gluUnProject((GLdouble)mouse_pos.x, (GLdouble)mouse_pos.y, mouse_z, modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z); + return Pointf3((coordf_t)out_x, (coordf_t)out_y, (coordf_t)out_z); +} + } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index 22f561cbd..7d490984f 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -306,6 +306,29 @@ public: void set_position(const Pointf& position); }; + class Drag + { + Point m_start_mouse_position; + Pointf3 m_start_position_3D; + Vectorf3 m_volume_center_offset; + int m_volume_idx; + + public: + Drag(); + + const Point& get_start_mouse_position() const; + void set_start_mouse_position(const Point& mouse_position); + + const Pointf3& get_start_position_3D() const; + void set_start_position_3D(const Pointf3& position); + + const Vectorf3& get_volume_center_offset() const; + void set_volume_center_offset(const Vectorf3& offset); + + int get_volume_idx() const; + void set_volume_idx(int idx); + }; + private: wxGLCanvas* m_canvas; wxGLContext* m_context; @@ -317,6 +340,7 @@ private: LayersEditing m_layers_editing; Shader m_shader; Mouse m_mouse; + Drag m_drag; GLVolumeCollection* m_volumes; DynamicPrintConfig* m_config; @@ -328,10 +352,14 @@ private: bool m_warning_texture_enabled; bool m_legend_texture_enabled; bool m_picking_enabled; + bool m_moving_enabled; bool m_shader_enabled; bool m_multisample_allowed; PerlCallback m_on_viewport_changed_callback; + PerlCallback m_on_double_click_callback; + PerlCallback m_on_right_click_callback; + PerlCallback m_on_select_callback; public: GLCanvas3D(wxGLCanvas* canvas, wxGLContext* context); @@ -398,6 +426,7 @@ public: bool is_layers_editing_enabled() const; bool is_picking_enabled() const; + bool is_moving_enabled() const; bool is_layers_editing_allowed() const; bool is_multisample_allowed() const; @@ -405,6 +434,7 @@ public: void enable_warning_texture(bool enable); void enable_legend_texture(bool enable); void enable_picking(bool enable); + void enable_moving(bool enable); void enable_shader(bool enable); void allow_multisample(bool allow); @@ -459,12 +489,16 @@ public: void render_texture(unsigned int tex_id, float left, float right, float bottom, float top) const; void register_on_viewport_changed_callback(void* callback); + void register_on_double_click_callback(void* callback); + void register_on_right_click_callback(void* callback); + void register_on_select_callback(void* callback); void on_size(wxSizeEvent& evt); void on_idle(wxIdleEvent& evt); void on_char(wxKeyEvent& evt); void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); + void on_mouse(wxMouseEvent& evt); Size get_canvas_size() const; Point get_local_mouse_position() const; @@ -494,6 +528,10 @@ private: void _render_layer_editing_overlay() const; void _perform_layer_editing_action(wxMouseEvent* evt = nullptr); + + // Convert the screen space coordinate to an object space coordinate. + // If the Z screen space coordinate is not provided, a depth buffer value is substituted. + Pointf3 _mouse_to_3d(const Point& mouse_pos, float* z = nullptr); }; } // namespace GUI diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 2d692cc27..c1eb7f37a 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -78,6 +78,18 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, wxGLContext* context) canvas->Bind(wxEVT_CHAR, [canvas3D](wxKeyEvent& evt) { canvas3D->on_char(evt); }); canvas->Bind(wxEVT_MOUSEWHEEL, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse_wheel(evt); }); canvas->Bind(wxEVT_TIMER, [canvas3D](wxTimerEvent& evt) { canvas3D->on_timer(evt); }); + canvas->Bind(wxEVT_LEFT_DOWN, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_LEFT_UP, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_MIDDLE_DOWN, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_MIDDLE_UP, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_RIGHT_DOWN, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_RIGHT_UP, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_MOTION, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_ENTER_WINDOW, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_LEAVE_WINDOW, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_LEFT_DCLICK, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_MIDDLE_DCLICK, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); + canvas->Bind(wxEVT_RIGHT_DCLICK, [canvas3D](wxMouseEvent& evt) { canvas3D->on_mouse(evt); }); m_canvases.insert(CanvasesMap::value_type(canvas, canvas3D)); @@ -384,6 +396,12 @@ bool GLCanvas3DManager::is_picking_enabled(wxGLCanvas* canvas) const return (it != m_canvases.end()) ? it->second->is_picking_enabled() : false; } +bool GLCanvas3DManager::is_moving_enabled(wxGLCanvas* canvas) const +{ + CanvasesMap::const_iterator it = _get_canvas(canvas); + return (it != m_canvases.end()) ? it->second->is_moving_enabled() : false; +} + bool GLCanvas3DManager::is_layers_editing_allowed(wxGLCanvas* canvas) const { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -424,6 +442,13 @@ void GLCanvas3DManager::enable_picking(wxGLCanvas* canvas, bool enable) it->second->enable_picking(enable); } +void GLCanvas3DManager::enable_moving(wxGLCanvas* canvas, bool enable) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->enable_moving(enable); +} + void GLCanvas3DManager::enable_shader(wxGLCanvas* canvas, bool enable) { CanvasesMap::iterator it = _get_canvas(canvas); @@ -692,6 +717,27 @@ void GLCanvas3DManager::register_on_viewport_changed_callback(wxGLCanvas* canvas it->second->register_on_viewport_changed_callback(callback); } +void GLCanvas3DManager::register_on_double_click_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_on_double_click_callback(callback); +} + +void GLCanvas3DManager::register_on_right_click_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_on_right_click_callback(callback); +} + +void GLCanvas3DManager::register_on_select_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_on_select_callback(callback); +} + GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) { return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index 1cb4c316e..da6e00e7b 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -98,6 +98,7 @@ public: bool is_layers_editing_enabled(wxGLCanvas* canvas) const; bool is_picking_enabled(wxGLCanvas* canvas) const; + bool is_moving_enabled(wxGLCanvas* canvas) const; bool is_layers_editing_allowed(wxGLCanvas* canvas) const; bool is_multisample_allowed(wxGLCanvas* canvas) const; @@ -105,6 +106,7 @@ public: void enable_warning_texture(wxGLCanvas* canvas, bool enable); void enable_legend_texture(wxGLCanvas* canvas, bool enable); void enable_picking(wxGLCanvas* canvas, bool enable); + void enable_moving(wxGLCanvas* canvas, bool enable); void enable_shader(wxGLCanvas* canvas, bool enable); void allow_multisample(wxGLCanvas* canvas, bool allow); @@ -163,6 +165,9 @@ public: void perform_layer_editing_action(wxGLCanvas* canvas, int y, bool shift_down, bool right_down); void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback); + void register_on_double_click_callback(wxGLCanvas* canvas, void* callback); + void register_on_right_click_callback(wxGLCanvas* canvas, void* callback); + void register_on_select_callback(wxGLCanvas* canvas, void* callback); private: CanvasesMap::iterator _get_canvas(wxGLCanvas* canvas); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 0ffe3677b..8023efab2 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -467,6 +467,14 @@ is_picking_enabled(canvas) OUTPUT: RETVAL +bool +is_moving_enabled(canvas) + SV *canvas; + CODE: + RETVAL = _3DScene::is_moving_enabled((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas")); + OUTPUT: + RETVAL + bool is_layers_editing_allowed(canvas) SV *canvas; @@ -503,7 +511,7 @@ enable_legend_texture(canvas, enable) bool enable; CODE: _3DScene::enable_legend_texture((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable); - + void enable_picking(canvas, enable) SV *canvas; @@ -511,6 +519,13 @@ enable_picking(canvas, enable) CODE: _3DScene::enable_picking((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable); +void +enable_moving(canvas, enable) + SV *canvas; + bool enable; + CODE: + _3DScene::enable_moving((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable); + void enable_shader(canvas, enable) SV *canvas; @@ -810,7 +825,27 @@ register_on_viewport_changed_callback(canvas, callback) SV *callback; CODE: _3DScene::register_on_viewport_changed_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); - + +void +register_on_double_click_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_on_double_click_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_on_right_click_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_on_right_click_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_on_select_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_on_select_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); unsigned int