From ae692635dabb82bbb3710b14dd63d7a41951a888 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 18 Apr 2019 09:59:17 +0200 Subject: [PATCH 01/29] Selection rectangle moved into a separate class --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/GLSelectionRectangle.cpp | 116 +++++++++++++++++++ src/slic3r/GUI/GLSelectionRectangle.hpp | 49 ++++++++ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 108 +++++------------ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 14 +-- 5 files changed, 198 insertions(+), 91 deletions(-) create mode 100644 src/slic3r/GUI/GLSelectionRectangle.cpp create mode 100644 src/slic3r/GUI/GLSelectionRectangle.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 1d8a1e26e..f54189762 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -47,6 +47,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoFlatten.hpp GUI/Gizmos/GLGizmoCut.cpp GUI/Gizmos/GLGizmoCut.hpp + GUI/GLSelectionRectangle.cpp + GUI/GLSelectionRectangle.hpp GUI/GLTexture.hpp GUI/GLTexture.cpp GUI/GLToolbar.hpp diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp new file mode 100644 index 000000000..a908d13ec --- /dev/null +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -0,0 +1,116 @@ +#include "GLSelectionRectangle.hpp" +#include "Camera.hpp" +#include "3DScene.hpp" + +#include + +namespace Slic3r { +namespace GUI { + +void GLSelectionRectangle::start_dragging(const Vec2d& mouse_position, float width, float height, EState status) +{ + if (is_active() || status==Off) + return; + + m_width = width; + m_height = height; + m_status = status; + m_start_corner = mouse_position; + m_end_corner = mouse_position; +} + + + +void GLSelectionRectangle::dragging(const Vec2d& mouse_position) +{ + if (is_active()) + m_end_corner = mouse_position; +} + + + +std::vector GLSelectionRectangle::end_dragging(const Camera& camera, const std::vector& points) +{ + if (!is_active()) + return std::vector(); + + m_status = Off; + std::vector out; + + const std::array& viewport = camera.get_viewport(); + const Transform3d& modelview_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); + + // bounding box created from the rectangle corners - will take care of order of the corners + BoundingBox rectangle(Points{Point(m_start_corner.cast()), Point(m_end_corner.cast())}); + + // Iterate over all points and determine whether they're in the rectangle. + for (unsigned int i=0; i end_dragging(const Camera& camera, const std::vector& points); + + void render() const; + + bool is_active() const { return m_status != Off; } + EState get_status() const { return m_status; } + + + +private: + EState m_status = Off; + Vec2d m_start_corner; + Vec2d m_end_corner; + float m_width; + float m_height; +}; + + +} // namespace GUI +} // namespace Slic3r + + +#endif // slic3r_GLGizmoSlaSupports_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index e8fe32688..b31eb272b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -100,7 +100,7 @@ void GLGizmoSlaSupports::on_render(const Selection& selection) const if (m_quadric != nullptr && selection.is_from_single_instance()) render_points(selection, false); - render_selection_rectangle(); + m_selection_rectangle.render(); render_clipping_plane(selection); glsafe(::glDisable(GL_BLEND)); @@ -240,52 +240,6 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const } - -void GLGizmoSlaSupports::render_selection_rectangle() const -{ - if (m_selection_rectangle_status == srOff) - return; - - glsafe(::glLineWidth(1.5f)); - float render_color[3] = {0.f, 1.f, 0.f}; - if (m_selection_rectangle_status == srDeselect) { - render_color[0] = 1.f; - render_color[1] = 0.3f; - render_color[2] = 0.3f; - } - glsafe(::glColor3fv(render_color)); - - glsafe(::glPushAttrib(GL_TRANSFORM_BIT)); // remember current MatrixMode - - glsafe(::glMatrixMode(GL_MODELVIEW)); // cache modelview matrix and set to identity - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - - glsafe(::glMatrixMode(GL_PROJECTION)); // cache projection matrix and set to identity - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - - glsafe(::glOrtho(0.f, m_canvas_width, m_canvas_height, 0.f, -1.f, 1.f)); // set projection matrix so that world coords = window coords - - // render the selection rectangle (window coordinates): - glsafe(::glPushAttrib(GL_ENABLE_BIT)); - glsafe(::glLineStipple(4, 0xAAAA)); - glsafe(::glEnable(GL_LINE_STIPPLE)); - - ::glBegin(GL_LINE_LOOP); - ::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f); - ::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f); - ::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f); - ::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f); - glsafe(::glEnd()); - glsafe(::glPopAttrib()); - - glsafe(::glPopMatrix()); // restore former projection matrix - glsafe(::glMatrixMode(GL_MODELVIEW)); - glsafe(::glPopMatrix()); // restore former modelview matrix - glsafe(::glPopAttrib()); // restore former MatrixMode -} - void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const { glsafe(::glEnable(GL_DEPTH_TEST)); @@ -513,11 +467,9 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) { if (m_hover_id == -1) { if (shift_down || alt_down) { - m_selection_rectangle_status = shift_down ? srSelect : srDeselect; - m_selection_rectangle_start_corner = mouse_position; - m_selection_rectangle_end_corner = mouse_position; - m_canvas_width = m_parent.get_canvas_size().get_width(); - m_canvas_height = m_parent.get_canvas_size().get_height(); + Size size = m_parent.get_canvas_size(); + m_selection_rectangle.start_dragging(mouse_position, size.get_width(), size.get_height(), + shift_down ? GLSelectionRectangle::SlaSelect : GLSelectionRectangle::SlaDeselect); } } else { @@ -533,7 +485,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // left down without selection rectangle - place point on the mesh: - if (action == SLAGizmoEventType::LeftDown && m_selection_rectangle_status == srOff && !shift_down) { + if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle.is_active() && !shift_down) { // If any point is in hover state, this should initiate its move - return control back to GLCanvas: if (m_hover_id != -1) return false; @@ -558,38 +510,36 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // left up with selection rectangle - select points inside the rectangle: - if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle_status != srOff) { - const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); - const Camera& camera = m_parent.get_camera(); - const std::array& viewport = camera.get_viewport(); - const Transform3d& modelview_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); + if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_active()) { + // Is this a selection or deselection rectangle? + GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_status(); + // First collect positions of all the points in world coordinates. + const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); + std::vector points; + for (unsigned int i=0; i()); + points.back()(2) += m_z_shift; + } + // Now ask the rectangle which of the points are inside. + const Camera& camera = m_parent.get_camera(); + std::vector selected_idxs = m_selection_rectangle.end_dragging(camera, points); + + // we'll recover current look direction (in world coords) and transform it to model coords. const Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - - // bounding box created from the rectangle corners - will take care of order of the corners - BoundingBox rectangle(Points{Point(m_selection_rectangle_start_corner.cast()), Point(m_selection_rectangle_end_corner.cast())}); - const Transform3d& instance_matrix_no_translation_no_scaling = volume->get_instance_transformation().get_matrix(true,false,true); - - // we'll recover current look direction from the modelview matrix (in world coords)... Vec3f direction_to_camera = camera.get_dir_forward().cast(); - // ...and transform it to model coords. Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast() * direction_to_camera).normalized().eval(); Vec3f scaling = volume->get_instance_scaling_factor().cast(); direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2)); - // Iterate over all points, check if they're in the rectangle and if so, check that they are not obscured by the mesh: - for (unsigned int i=0; i() * support_point.pos; - pos(2) += m_z_shift; - GLdouble out_x, out_y, out_z; - ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), (GLdouble*)modelview_matrix.data(), (GLdouble*)projection_matrix.data(), (GLint*)viewport.data(), &out_x, &out_y, &out_z); - out_y = m_canvas_height - out_y; - - if (rectangle.contains(Point(out_x, out_y)) && !is_point_clipped(support_point.pos.cast())) { + if (!is_point_clipped(support_point.pos.cast())) { bool is_obscured = false; // Cast a ray in the direction of the camera and look for intersection with the mesh: std::vector hits; @@ -627,14 +577,13 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (!is_obscured) { - if (m_selection_rectangle_status == srDeselect) + if (rectangle_status == GLSelectionRectangle::SlaDeselect) unselect_point(i); else select_point(i); } } } - m_selection_rectangle_status = srOff; return true; } @@ -652,9 +601,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return true; // point has been placed and the button not released yet // this prevents GLCanvas from starting scene rotation - if (m_selection_rectangle_status != srOff) { - m_selection_rectangle_end_corner = mouse_position; - m_selection_rectangle_status = shift_down ? srSelect : srDeselect; + if (m_selection_rectangle.is_active()) { + m_selection_rectangle.dragging(mouse_position); return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index eaf0932c4..92d80b6eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -3,6 +3,7 @@ #include "GLGizmoBase.hpp" #include "GLGizmos.hpp" +#include "slic3r/GUI/GLSelectionRectangle.hpp" // There is an L function in igl that would be overridden by our localization macro - let's undefine it... #undef L @@ -73,7 +74,7 @@ private: virtual void on_render(const Selection& selection) const; virtual void on_render_for_picking(const Selection& selection) const; - void render_selection_rectangle() const; + //void render_selection_rectangle() const; void render_points(const Selection& selection, bool picking = false) const; void render_clipping_plane(const Selection& selection) const; bool is_mesh_update_necessary() const; @@ -91,20 +92,11 @@ private: mutable Vec3d m_old_clipping_plane_normal; mutable Vec3d m_clipping_plane_normal = Vec3d::Zero(); - enum SelectionRectangleStatus { - srOff = 0, - srSelect = 1, - srDeselect = 2 - }m_selection_rectangle_status = srOff; - - Vec2d m_selection_rectangle_start_corner; - Vec2d m_selection_rectangle_end_corner; + GLSelectionRectangle m_selection_rectangle; bool m_wait_for_up_event = false; bool m_unsaved_changes = false; // Are there unsaved changes in manual mode? bool m_selection_empty = true; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) - int m_canvas_width; - int m_canvas_height; mutable std::unique_ptr m_tms; mutable std::unique_ptr m_supports_tms; From fc67f44bea9a235621d1d1e454125506c5049f48 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 24 Apr 2019 13:43:39 +0200 Subject: [PATCH 02/29] Fixed typo --- src/slic3r/GUI/GLSelectionRectangle.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLSelectionRectangle.hpp b/src/slic3r/GUI/GLSelectionRectangle.hpp index ef1f831cc..2422066e0 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.hpp +++ b/src/slic3r/GUI/GLSelectionRectangle.hpp @@ -6,7 +6,7 @@ namespace Slic3r { namespace GUI { -class Camera; +struct Camera; class GLSelectionRectangle { public: From 97101409487c77b06d66fece7063158d2dcf3e90 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 24 Apr 2019 15:07:28 +0200 Subject: [PATCH 03/29] int GLCanvas3D::m_hover_volume_id replaced with std::vector GLCanvas3D::m_hover_volume_idxs --- src/slic3r/GUI/GLCanvas3D.cpp | 50 +++++++++++------------ src/slic3r/GUI/GLCanvas3D.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8aa3205a7..09b4b2e14 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1205,7 +1205,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar , m_initialized(false) , m_use_VBOs(false) , m_apply_zoom_to_volumes_filter(false) - , m_hover_volume_id(-1) , m_legend_texture_enabled(false) , m_picking_enabled(false) , m_moving_enabled(false) @@ -2543,7 +2542,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (top_level_wnd && top_level_wnd->IsActive()) m_canvas->SetFocus(); m_mouse.position = pos.cast(); - // 1) forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while + // 1) forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while // the context menu is shown, ensuring it to disappear if the mouse is outside any volume and to // change the volume hover state if any is under the mouse // 2) when switching between 3d view and preview the size of the canvas changes if the side panels are visible, @@ -2589,20 +2588,21 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // Don't deselect a volume if layer editing is enabled. We want the object to stay selected // during the scene manipulation. - if (m_picking_enabled && ((m_hover_volume_id != -1) || !is_layers_editing_enabled())) + if (m_picking_enabled && (!m_hover_volume_idxs.empty() || !is_layers_editing_enabled())) { - if (evt.LeftDown() && (m_hover_volume_id != -1)) + if (evt.LeftDown() && !m_hover_volume_idxs.empty()) { - bool already_selected = m_selection.contains_volume(m_hover_volume_id); + int volume_idx = get_first_hover_volume_idx(); + bool already_selected = m_selection.contains_volume(volume_idx); bool ctrl_down = evt.CmdDown(); Selection::IndicesList curr_idxs = m_selection.get_volume_idxs(); if (already_selected && ctrl_down) - m_selection.remove(m_hover_volume_id); + m_selection.remove(volume_idx); else { - m_selection.add(m_hover_volume_id, !ctrl_down, true); + m_selection.add(volume_idx, !ctrl_down, true); m_mouse.drag.move_requires_threshold = !already_selected; if (already_selected) m_mouse.set_move_start_threshold_position_2D_as_invalid(); @@ -2610,6 +2610,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.drag.move_start_threshold_position_2D = pos; } + // propagate event through callback if (curr_idxs != m_selection.get_volume_idxs()) { m_gizmos.refresh_on_off_state(m_selection); @@ -2620,18 +2621,18 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } } - // propagate event through callback - if (m_hover_volume_id != -1) + if (!m_hover_volume_idxs.empty()) { if (evt.LeftDown() && m_moving_enabled && (m_mouse.drag.move_volume_idx == -1)) { // Only accept the initial position, if it is inside the volume bounding box. - BoundingBoxf3 volume_bbox = m_volumes.volumes[m_hover_volume_id]->transformed_bounding_box(); + int volume_idx = get_first_hover_volume_idx(); + BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box(); volume_bbox.offset(1.0); if (volume_bbox.contains(m_mouse.scene_position)) { // The dragging operation is initiated. - m_mouse.drag.move_volume_idx = m_hover_volume_id; + m_mouse.drag.move_volume_idx = volume_idx; m_selection.start_dragging(); m_mouse.drag.start_position_3D = m_mouse.scene_position; m_moving = true; @@ -2648,7 +2649,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) Vec3d cur_pos = m_mouse.drag.start_position_3D; // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag - if (m_selection.contains_volume(m_hover_volume_id)) + if (m_selection.contains_volume(get_first_hover_volume_idx())) { if (m_camera.get_theta() == 90.0f) { @@ -2703,7 +2704,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.LeftIsDown()) { // if dragging over blank area with left button, rotate - if ((m_hover_volume_id == -1) && m_mouse.is_start_position_3D_defined()) + if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined()) { const Vec3d& orig = m_mouse.drag.start_position_3D; m_camera.phi += (((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE); @@ -2745,7 +2746,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // of the scene with the background processing data should be performed. post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); } - else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !is_layers_editing_enabled()) + else if (evt.LeftUp() && !m_mouse.dragging && m_hover_volume_idxs.empty() && !is_layers_editing_enabled()) { // deselect and propagate event through callback if (!evt.ShiftDown() && m_picking_enabled) @@ -2761,18 +2762,18 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.RightUp()) { m_mouse.position = pos.cast(); - // forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while + // forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while // the context menu is already shown render(); - if (m_hover_volume_id != -1) + if (!m_hover_volume_idxs.empty()) { // if right clicking on volume, propagate event through callback (shows context menu) - if (m_volumes.volumes[m_hover_volume_id]->hover - && !m_volumes.volumes[m_hover_volume_id]->is_wipe_tower // no context menu for the wipe tower + int volume_idx = get_first_hover_volume_idx(); + if (!m_volumes.volumes[volume_idx]->is_wipe_tower // no context menu for the wipe tower && m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) // disable context menu when the gizmo is open { // forces the selection of the volume - m_selection.add(m_hover_volume_id); + m_selection.add(volume_idx); m_gizmos.refresh_on_off_state(m_selection); post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); m_gizmos.update_data(*this); @@ -3541,6 +3542,8 @@ void GLCanvas3D::_picking_pass() const if (m_picking_enabled && !m_mouse.dragging && (pos != Vec2d(DBL_MAX, DBL_MAX))) { + m_hover_volume_idxs.clear(); + // Render the object for picking. // FIXME This cannot possibly work in a multi - sampled context as the color gets mangled by the anti - aliasing. // Better to use software ray - casting on a bounding - box hierarchy. @@ -3579,14 +3582,11 @@ void GLCanvas3D::_picking_pass() const } if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) { - m_hover_volume_id = volume_id; + m_hover_volume_idxs.push_back(volume_id); m_gizmos.set_hover_id(-1); } else - { - m_hover_volume_id = -1; m_gizmos.set_hover_id(inside && volume_id <= GLGizmoBase::BASE_ID ? (GLGizmoBase::BASE_ID - volume_id) : -1); - } _update_volumes_hover_state(); } @@ -4077,10 +4077,10 @@ void GLCanvas3D::_update_volumes_hover_state() const v->hover = false; } - if (m_hover_volume_id == -1) + if (m_hover_volume_idxs.empty()) return; - GLVolume* volume = m_volumes.volumes[m_hover_volume_id]; + GLVolume* volume = m_volumes.volumes[get_first_hover_volume_idx()]; if (volume->is_modifier) volume->hover = true; else diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e81d46f11..8a5c34a2c 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -426,7 +426,7 @@ private: bool m_initialized; bool m_use_VBOs; bool m_apply_zoom_to_volumes_filter; - mutable int m_hover_volume_id; + mutable std::vector m_hover_volume_idxs; bool m_warning_texture_enabled; bool m_legend_texture_enabled; bool m_picking_enabled; @@ -575,7 +575,7 @@ public: float get_view_toolbar_height() const { return m_view_toolbar.get_height(); } int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; } - int get_hover_volume_id() const { return m_hover_volume_id; } + int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); } // Returns the view ray line, in world coordinate, at the given mouse position. Linef3 mouse_ray(const Point& mouse_pos); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 5e37e42ad..88e374792 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -693,7 +693,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()); processed = true; } - else if (evt.LeftUp() && (m_current == Flatten) && ((canvas.get_hover_volume_id() != -1) || grabber_contains_mouse())) + else if (evt.LeftUp() && (m_current == Flatten) && ((canvas.get_first_hover_volume_idx() != -1) || grabber_contains_mouse())) { // to avoid to loose the selection when user clicks an object while the Flatten gizmo is active processed = true; From d79a2b8d2d0ffd6019330c41e7bb8b1ee59a2f53 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 24 Apr 2019 15:43:52 +0200 Subject: [PATCH 04/29] GLCanvas3D -> added support for cursor change and change cursor when using SLA support gizmo rectangle selection --- src/slic3r/GUI/GLCanvas3D.cpp | 31 ++++++++++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 11 +++++++ src/slic3r/GUI/GLSelectionRectangle.cpp | 6 ++-- src/slic3r/GUI/GLSelectionRectangle.hpp | 4 +-- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 6 ++-- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 3 ++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 31 ++++++++++++++++---- 7 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 09b4b2e14..af0aa9a69 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1213,6 +1213,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar , m_regenerate_volumes(true) , m_moving(false) , m_tab_down(false) + , m_cursor_type(Standard) , m_color_by("volume") , m_reload_delayed(false) , m_render_sla_auxiliaries(true) @@ -2323,9 +2324,25 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) // m_canvas->HandleAsNavigationKey(evt); // XXX: Doesn't work in some cases / on Linux post_event(SimpleEvent(EVT_GLCANVAS_TAB)); } + else if (keyCode == WXK_SHIFT) + { + set_cursor(Standard); + } + else if (keyCode == WXK_ALT) + { + set_cursor(Standard); + } } else if (evt.GetEventType() == wxEVT_KEY_DOWN) { m_tab_down = keyCode == WXK_TAB && !evt.HasAnyModifiers(); + if (keyCode == WXK_SHIFT) + { + set_cursor(Cross); + } + else if (keyCode == WXK_ALT) + { + set_cursor(Cross); + } } } } @@ -3173,6 +3190,20 @@ double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const return factor * m_bed.get_bounding_box().max_size(); } +void GLCanvas3D::set_cursor(ECursorType type) +{ + if ((m_canvas != nullptr) && (m_cursor_type != type)) + { + switch (type) + { + case Standard: { m_canvas->SetCursor(*wxSTANDARD_CURSOR); break; } + case Cross: { m_canvas->SetCursor(*wxCROSS_CURSOR); break; } + } + + m_cursor_type = type; + } +} + bool GLCanvas3D::_is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 8a5c34a2c..fa55dc683 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -392,6 +392,14 @@ private: void render(const GLCanvas3D& canvas) const; }; +public: + enum ECursorType : unsigned char + { + Standard, + Cross + }; + +private: wxGLCanvas* m_canvas; wxGLContext* m_context; #if ENABLE_RETINA_GL @@ -436,6 +444,7 @@ private: bool m_regenerate_volumes; bool m_moving; bool m_tab_down; + ECursorType m_cursor_type; // Following variable is obsolete and it should be safe to remove it. // I just don't want to do it now before a release (Lukas Matena 24.3.2019) @@ -587,6 +596,8 @@ public: double get_size_proportional_to_max_bed_size(double factor) const; + void set_cursor(ECursorType type); + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index a908d13ec..39b92ff8f 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -9,7 +9,7 @@ namespace GUI { void GLSelectionRectangle::start_dragging(const Vec2d& mouse_position, float width, float height, EState status) { - if (is_active() || status==Off) + if (is_dragging() || status == Off) return; m_width = width; @@ -23,7 +23,7 @@ void GLSelectionRectangle::start_dragging(const Vec2d& mouse_position, float wid void GLSelectionRectangle::dragging(const Vec2d& mouse_position) { - if (is_active()) + if (is_dragging()) m_end_corner = mouse_position; } @@ -31,7 +31,7 @@ void GLSelectionRectangle::dragging(const Vec2d& mouse_position) std::vector GLSelectionRectangle::end_dragging(const Camera& camera, const std::vector& points) { - if (!is_active()) + if (!is_dragging()) return std::vector(); m_status = Off; diff --git a/src/slic3r/GUI/GLSelectionRectangle.hpp b/src/slic3r/GUI/GLSelectionRectangle.hpp index 2422066e0..f7d5bbdc7 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.hpp +++ b/src/slic3r/GUI/GLSelectionRectangle.hpp @@ -27,8 +27,8 @@ public: std::vector end_dragging(const Camera& camera, const std::vector& points); void render() const; - - bool is_active() const { return m_status != Off; } + + bool is_dragging() const { return m_status != Off; } EState get_status() const { return m_status; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index b31eb272b..ebb7df138 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -485,7 +485,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // left down without selection rectangle - place point on the mesh: - if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle.is_active() && !shift_down) { + if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle.is_dragging() && !shift_down) { // If any point is in hover state, this should initiate its move - return control back to GLCanvas: if (m_hover_id != -1) return false; @@ -510,7 +510,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // left up with selection rectangle - select points inside the rectangle: - if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_active()) { + if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_dragging()) { // Is this a selection or deselection rectangle? GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_status(); @@ -601,7 +601,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return true; // point has been placed and the button not released yet // this prevents GLCanvas from starting scene rotation - if (m_selection_rectangle.is_active()) { + if (m_selection_rectangle.is_dragging()) { m_selection_rectangle.dragging(mouse_position); return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 92d80b6eb..ab5dc8d67 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -68,6 +68,9 @@ public: void delete_selected_points(bool force = false); ClippingPlane get_sla_clipping_plane() const; + bool is_in_editing_mode() const { return m_editing_mode; } + bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } + private: bool on_init(); void on_update(const UpdateData& data, const Selection& selection); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 88e374792..b7e1b3f07 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -843,13 +843,34 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas) if (evt.GetEventType() == wxEVT_KEY_UP) { - if ((m_current == SlaSupports) && (keyCode == WXK_SHIFT) && gizmo_event(SLAGizmoEventType::ShiftUp)) - // shift has been just released - SLA gizmo might want to close rectangular selection. - processed = true; + if (m_current == SlaSupports) + { + GLGizmoSlaSupports* gizmo = reinterpret_cast(get_current()); - if ((m_current == SlaSupports) && (keyCode == WXK_ALT) && gizmo_event(SLAGizmoEventType::AltUp)) - // alt has been just released - SLA gizmo might want to close rectangular selection. + if (keyCode == WXK_SHIFT) + { + // shift has been just released - SLA gizmo might want to close rectangular selection. + if (gizmo_event(SLAGizmoEventType::ShiftUp) || (gizmo->is_in_editing_mode() && gizmo->is_selection_rectangle_dragging())) + processed = true; + } + else if (keyCode == WXK_ALT) + { + // alt has been just released - SLA gizmo might want to close rectangular selection. + if (gizmo_event(SLAGizmoEventType::AltUp) || (gizmo->is_in_editing_mode() && gizmo->is_selection_rectangle_dragging())) + processed = true; + } + } + + if (processed) + canvas.set_cursor(GLCanvas3D::Standard); + } + else if (evt.GetEventType() == wxEVT_KEY_DOWN) + { + if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) && reinterpret_cast(get_current())->is_in_editing_mode()) + { + canvas.set_cursor(GLCanvas3D::Cross); processed = true; + } } if (processed) From 9d070410c233cff14c84820e8b3b513824b92a6f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 24 Apr 2019 16:01:27 +0200 Subject: [PATCH 05/29] Refactoring of GLSelectionRectangle --- src/slic3r/GUI/GLSelectionRectangle.cpp | 181 ++++++++++--------- src/slic3r/GUI/GLSelectionRectangle.hpp | 28 +-- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 12 +- 3 files changed, 111 insertions(+), 110 deletions(-) diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 39b92ff8f..03ee7e1f6 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -1,116 +1,119 @@ #include "GLSelectionRectangle.hpp" #include "Camera.hpp" #include "3DScene.hpp" +#include "GLCanvas3D.hpp" #include namespace Slic3r { namespace GUI { -void GLSelectionRectangle::start_dragging(const Vec2d& mouse_position, float width, float height, EState status) -{ - if (is_dragging() || status == Off) - return; + void GLSelectionRectangle::start_dragging(const Vec2d& mouse_position, EState state) + { + if (is_dragging() || (state == Off)) + return; - m_width = width; - m_height = height; - m_status = status; - m_start_corner = mouse_position; - m_end_corner = mouse_position; -} - - - -void GLSelectionRectangle::dragging(const Vec2d& mouse_position) -{ - if (is_dragging()) + m_state = state; + m_start_corner = mouse_position; m_end_corner = mouse_position; -} - - - -std::vector GLSelectionRectangle::end_dragging(const Camera& camera, const std::vector& points) -{ - if (!is_dragging()) - return std::vector(); - - m_status = Off; - std::vector out; - - const std::array& viewport = camera.get_viewport(); - const Transform3d& modelview_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); - - // bounding box created from the rectangle corners - will take care of order of the corners - BoundingBox rectangle(Points{Point(m_start_corner.cast()), Point(m_end_corner.cast())}); - - // Iterate over all points and determine whether they're in the rectangle. - for (unsigned int i=0; i GLSelectionRectangle::stop_dragging(const GLCanvas3D& canvas, const std::vector& points) + { + std::vector out; - glsafe(::glPushAttrib(GL_TRANSFORM_BIT)); // remember current MatrixMode + if (!is_dragging()) + return out; - glsafe(::glMatrixMode(GL_MODELVIEW)); // cache modelview matrix and set to identity - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); + m_state = Off; - glsafe(::glMatrixMode(GL_PROJECTION)); // cache projection matrix and set to identity - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); + const Camera& camera = canvas.get_camera(); + const std::array& viewport = camera.get_viewport(); + const Transform3d& modelview_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); - glsafe(::glOrtho(0.f, m_width, m_height, 0.f, -1.f, 1.f)); // set projection matrix so that world coords = window coords + // bounding box created from the rectangle corners - will take care of order of the corners + BoundingBox rectangle(Points{ Point(m_start_corner.cast()), Point(m_end_corner.cast()) }); - // render the selection rectangle (window coordinates): - glsafe(::glPushAttrib(GL_ENABLE_BIT)); - glsafe(::glLineStipple(4, 0xAAAA)); - glsafe(::glEnable(GL_LINE_STIPPLE)); + // Iterate over all points and determine whether they're in the rectangle. + for (unsigned int i = 0; i end_dragging(const Camera& camera, const std::vector& points); + std::vector stop_dragging(const GLCanvas3D& canvas, const std::vector& points); - void render() const; + // Disables the rectangle. + void stop_dragging(); - bool is_dragging() const { return m_status != Off; } - EState get_status() const { return m_status; } + void render(const GLCanvas3D& canvas) const; + + bool is_dragging() const { return m_state != Off; } + EState get_state() const { return m_state; } - - private: - EState m_status = Off; + EState m_state = Off; Vec2d m_start_corner; Vec2d m_end_corner; - float m_width; - float m_height; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index ebb7df138..5be5e9a89 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -100,7 +100,7 @@ void GLGizmoSlaSupports::on_render(const Selection& selection) const if (m_quadric != nullptr && selection.is_from_single_instance()) render_points(selection, false); - m_selection_rectangle.render(); + m_selection_rectangle.render(m_parent); render_clipping_plane(selection); glsafe(::glDisable(GL_BLEND)); @@ -467,9 +467,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) { if (m_hover_id == -1) { if (shift_down || alt_down) { - Size size = m_parent.get_canvas_size(); - m_selection_rectangle.start_dragging(mouse_position, size.get_width(), size.get_height(), - shift_down ? GLSelectionRectangle::SlaSelect : GLSelectionRectangle::SlaDeselect); + m_selection_rectangle.start_dragging(mouse_position, shift_down ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); } } else { @@ -512,7 +510,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // left up with selection rectangle - select points inside the rectangle: if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_dragging()) { // Is this a selection or deselection rectangle? - GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_status(); + GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); // First collect positions of all the points in world coordinates. const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); @@ -524,7 +522,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // Now ask the rectangle which of the points are inside. const Camera& camera = m_parent.get_camera(); - std::vector selected_idxs = m_selection_rectangle.end_dragging(camera, points); + std::vector selected_idxs = m_selection_rectangle.stop_dragging(m_parent, points); // we'll recover current look direction (in world coords) and transform it to model coords. const Selection& selection = m_parent.get_selection(); @@ -577,7 +575,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (!is_obscured) { - if (rectangle_status == GLSelectionRectangle::SlaDeselect) + if (rectangle_status == GLSelectionRectangle::Deselect) unselect_point(i); else select_point(i); From ec2f319a3d7cce7958a750e142d06c3921e7bf84 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 09:10:03 +0200 Subject: [PATCH 06/29] Rectangle selection in 3D scene -> rendering --- src/slic3r/GUI/GLCanvas3D.cpp | 36 ++++++++++++++++++-- src/slic3r/GUI/GLCanvas3D.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 1 + 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5cae80ba8..084a4f3b4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1647,6 +1647,9 @@ void GLCanvas3D::render() _render_camera_target(); #endif // ENABLE_SHOW_CAMERA_TARGET + if (m_picking_enabled && m_rectangle_selection.is_dragging()) + m_rectangle_selection.render(*this); + // draw overlays _render_gizmos_overlay(); _render_warning_texture(); @@ -2342,10 +2345,20 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) } else if (keyCode == WXK_SHIFT) { + if (m_picking_enabled && m_rectangle_selection.is_dragging()) + { + m_rectangle_selection.stop_dragging(); + m_dirty = true; + } set_cursor(Standard); } else if (keyCode == WXK_ALT) { + if (m_picking_enabled && m_rectangle_selection.is_dragging()) + { + m_rectangle_selection.stop_dragging(); + m_dirty = true; + } set_cursor(Standard); } } @@ -2353,11 +2366,13 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) m_tab_down = keyCode == WXK_TAB && !evt.HasAnyModifiers(); if (keyCode == WXK_SHIFT) { - set_cursor(Cross); + if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) + set_cursor(Cross); } else if (keyCode == WXK_ALT) { - set_cursor(Cross); + if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) + set_cursor(Cross); } } } @@ -2615,6 +2630,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } } + else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled) + { + if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) + { + m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); + m_dirty = true; + } + } else { // Select volume in this 3D canvas. @@ -2724,6 +2747,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } } + else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging()) + { + m_rectangle_selection.dragging(pos.cast()); + m_dirty = true; + } else if (evt.Dragging()) { m_mouse.dragging = true; @@ -2779,6 +2807,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // of the scene with the background processing data should be performed. post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); } + else if (evt.LeftUp() && m_picking_enabled && m_rectangle_selection.is_dragging()) + { + m_rectangle_selection.stop_dragging(); + } else if (evt.LeftUp() && !m_mouse.dragging && m_hover_volume_idxs.empty() && !is_layers_editing_enabled()) { // deselect and propagate event through callback diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index cd96b5c70..e8c301967 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -452,6 +452,7 @@ private: bool m_moving; bool m_tab_down; ECursorType m_cursor_type; + GLSelectionRectangle m_rectangle_selection; // Following variable is obsolete and it should be safe to remove it. // I just don't want to do it now before a release (Lukas Matena 24.3.2019) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index ab5dc8d67..7e09b04ac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -96,6 +96,7 @@ private: mutable Vec3d m_clipping_plane_normal = Vec3d::Zero(); GLSelectionRectangle m_selection_rectangle; + bool m_wait_for_up_event = false; bool m_unsaved_changes = false; // Are there unsaved changes in manual mode? bool m_selection_empty = true; From 11490dfb066e56829a6a11d63d29cde7d0956846 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 09:46:26 +0200 Subject: [PATCH 07/29] Rectangle selection in 3D scene -> hovering detection --- src/slic3r/GUI/3DScene.cpp | 14 ++- src/slic3r/GUI/3DScene.hpp | 9 +- src/slic3r/GUI/GLCanvas3D.cpp | 137 +++++++++++++++++++++--- src/slic3r/GUI/GLCanvas3D.hpp | 1 + src/slic3r/GUI/GLSelectionRectangle.cpp | 6 +- src/slic3r/GUI/GLSelectionRectangle.hpp | 7 ++ 6 files changed, 148 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 9038e388c..9d1407b00 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -223,7 +223,8 @@ void GLIndexedVertexArray::render( } const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; -const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f }; +const float GLVolume::HOVER_SELECT_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f }; +const float GLVolume::HOVER_DESELECT_COLOR[4] = { 0.9f, 0.4f, 0.1f, 1.0f }; const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f }; const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f }; const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f }; @@ -251,7 +252,8 @@ GLVolume::GLVolume(float r, float g, float b, float a) , zoom_to_volumes(true) , shader_outside_printer_detection_enabled(false) , is_outside(false) - , hover(false) + , hover_select(false) + , hover_deselect(false) , is_modifier(false) , is_wipe_tower(false) , is_extrusion_path(false) @@ -291,10 +293,12 @@ void GLVolume::set_render_color() if (force_native_color) set_render_color(color, 4); else { - if (selected) + if (hover_select) + set_render_color(HOVER_SELECT_COLOR, 4); + else if (hover_deselect) + set_render_color(HOVER_DESELECT_COLOR, 4); + else if (selected) set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4); - else if (hover) - set_render_color(HOVER_COLOR, 4); else if (disabled) set_render_color(DISABLED_COLOR, 4); else if (is_outside && shader_outside_printer_detection_enabled) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 88547359e..fa7d6f7d1 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -225,7 +225,8 @@ private: class GLVolume { public: static const float SELECTED_COLOR[4]; - static const float HOVER_COLOR[4]; + static const float HOVER_SELECT_COLOR[4]; + static const float HOVER_DESELECT_COLOR[4]; static const float OUTSIDE_COLOR[4]; static const float SELECTED_OUTSIDE_COLOR[4]; static const float DISABLED_COLOR[4]; @@ -296,8 +297,10 @@ public: bool shader_outside_printer_detection_enabled; // Wheter or not this volume is outside print volume. bool is_outside; - // Boolean: Is mouse over this object? - bool hover; + // Boolean: Is mouse over this object to select it ? + bool hover_select; + // Boolean: Is mouse over this object to deselect it ? + bool hover_deselect; // Wheter or not this volume has been generated from a modifier bool is_modifier; // Wheter or not this volume has been generated from the wipe tower diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 084a4f3b4..621a726b9 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1610,8 +1610,12 @@ void GLCanvas3D::render() wxGetApp().imgui()->new_frame(); - // picking pass - _picking_pass(); + if (m_rectangle_selection.is_dragging()) + // picking pass using rectangle selection + _rectangular_selection_picking_pass(); + else + // regular picking pass + _picking_pass(); // draw scene glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); @@ -2361,6 +2365,8 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) } set_cursor(Standard); } + else if (keyCode == WXK_CONTROL) + m_dirty = true; } else if (evt.GetEventType() == wxEVT_KEY_DOWN) { m_tab_down = keyCode == WXK_TAB && !evt.HasAnyModifiers(); @@ -2374,6 +2380,8 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) set_cursor(Cross); } + else if (keyCode == WXK_CONTROL) + m_dirty = true; } } } @@ -3662,7 +3670,7 @@ void GLCanvas3D::_picking_pass() const if (inside) { glsafe(::glReadPixels(pos(0), cnv_size.get_height() - pos(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color)); - volume_id = color[0] + color[1] * 256 + color[2] * 256 * 256; + volume_id = color[0] + (color[1] << 8) + (color[2] << 16); } if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) { @@ -3676,6 +3684,83 @@ void GLCanvas3D::_picking_pass() const } } +void GLCanvas3D::_rectangular_selection_picking_pass() const +{ + m_gizmos.set_hover_id(-1); + + std::set idxs; + + if (m_picking_enabled) + { + if (m_multisample_allowed) + glsafe(::glDisable(GL_MULTISAMPLE)); + + glsafe(::glDisable(GL_BLEND)); + glsafe(::glEnable(GL_DEPTH_TEST)); + + glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + + _render_volumes_for_picking(); + + if (m_multisample_allowed) + glsafe(::glEnable(GL_MULTISAMPLE)); + + int width = (int)m_rectangle_selection.get_width(); + int height = (int)m_rectangle_selection.get_height(); + int px_count = width * height; + + if (px_count > 0) + { + int left = (int)m_rectangle_selection.get_left(); + int top = get_canvas_size().get_height() - (int)m_rectangle_selection.get_top(); + if ((left >= 0) && (top >= 0)) + { +#define USE_PARALLEL 1 +#if USE_PARALLEL + struct Pixel + { + std::array data; + int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); } + }; + + std::vector frame(px_count); + glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data())); + + tbb::spin_mutex mutex; + tbb::parallel_for(tbb::blocked_range(0, frame.size(), (size_t)width), + [this, &frame, &idxs, &mutex](const tbb::blocked_range& range) { + for (size_t i = range.begin(); i < range.end(); ++i) + { + int volume_id = frame[i].id(); + if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) + { + mutex.lock(); + idxs.insert(volume_id); + mutex.unlock(); + } + } + } + ); +#else + std::vector frame(4 * px_count); + glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data())); + + for (int i = 0; i < px_count; ++i) + { + int px_id = 4 * i; + int volume_id = frame[px_id] + (frame[px_id + 1] << 8) + (frame[px_id + 2] << 16); + if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) + idxs.insert(volume_id); + } +#endif // USE_PARALLEL + } + } + } + + m_hover_volume_idxs.assign(idxs.begin(), idxs.end()); + _update_volumes_hover_state(); +} + void GLCanvas3D::_render_background() const { glsafe(::glPushMatrix()); @@ -4161,24 +4246,48 @@ void GLCanvas3D::_update_volumes_hover_state() const { for (GLVolume* v : m_volumes.volumes) { - v->hover = false; + v->hover_select = false; + v->hover_deselect = false; } if (m_hover_volume_idxs.empty()) return; - GLVolume* volume = m_volumes.volumes[get_first_hover_volume_idx()]; - if (volume->is_modifier) - volume->hover = true; - else - { - int object_idx = volume->object_idx(); - int instance_idx = volume->instance_idx(); + bool is_ctrl_pressed = wxGetKeyState(WXK_CONTROL); + bool is_shift_pressed = wxGetKeyState(WXK_SHIFT); + bool is_alt_pressed = wxGetKeyState(WXK_ALT); - for (GLVolume* v : m_volumes.volumes) + for (int i : m_hover_volume_idxs) + { + GLVolume* volume = m_volumes.volumes[i]; + bool deselect = volume->selected && ((is_ctrl_pressed && !is_shift_pressed) || (!is_ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Deselect))); + bool select = !volume->selected || (volume->is_modifier && ((is_ctrl_pressed && !is_alt_pressed) || (!is_ctrl_pressed && (!m_rectangle_selection.is_dragging() || (m_rectangle_selection.get_state() == GLSelectionRectangle::Select))))); + + if (select || deselect) { - if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) - v->hover = true; + if (volume->is_modifier && (!deselect || ((volume->object_idx() == m_selection.get_object_idx()) && (volume->instance_idx() == m_selection.get_instance_idx())))) + { + if (deselect) + volume->hover_deselect = true; + else + volume->hover_select = true; + } + else + { + int object_idx = volume->object_idx(); + int instance_idx = volume->instance_idx(); + + for (GLVolume* v : m_volumes.volumes) + { + if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) + { + if (deselect) + v->hover_deselect = true; + else + v->hover_select = true; + } + } + } } } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e8c301967..bae9f0b5e 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -623,6 +623,7 @@ private: void _refresh_if_shown_on_screen(); void _picking_pass() const; + void _rectangular_selection_picking_pass() const; void _render_background() const; void _render_bed(float theta) const; void _render_axes() const; diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 03ee7e1f6..9684bb5ec 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -59,10 +59,8 @@ namespace GUI { void GLSelectionRectangle::stop_dragging() { - if (!is_dragging()) - return; - - m_state = Off; + if (is_dragging()) + m_state = Off; } void GLSelectionRectangle::render(const GLCanvas3D& canvas) const diff --git a/src/slic3r/GUI/GLSelectionRectangle.hpp b/src/slic3r/GUI/GLSelectionRectangle.hpp index f26d3eb4b..db72d9415 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.hpp +++ b/src/slic3r/GUI/GLSelectionRectangle.hpp @@ -35,6 +35,13 @@ public: bool is_dragging() const { return m_state != Off; } EState get_state() const { return m_state; } + float get_width() const { return std::abs(m_start_corner(0) - m_end_corner(0)); } + float get_height() const { return std::abs(m_start_corner(1) - m_end_corner(1)); } + float get_left() const { return std::min(m_start_corner(0), m_end_corner(0)); } + float get_right() const { return std::max(m_start_corner(0), m_end_corner(0)); } + float get_top() const { return std::max(m_start_corner(1), m_end_corner(1)); } + float get_bottom() const { return std::min(m_start_corner(1), m_end_corner(1)); } + private: EState m_state = Off; Vec2d m_start_corner; From d2d06c9f73b7885acf43ba59d4c508cc498faf4e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 10:21:24 +0200 Subject: [PATCH 08/29] Rectangle selection in 3D scene -> refactored GLVolume member varialbe for hovering --- src/slic3r/GUI/3DScene.cpp | 7 +++---- src/slic3r/GUI/3DScene.hpp | 13 +++++++++---- src/slic3r/GUI/GLCanvas3D.cpp | 11 +++++------ src/slic3r/GUI/GLSelectionRectangle.hpp | 2 +- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 9d1407b00..873c8b9e6 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -252,8 +252,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) , zoom_to_volumes(true) , shader_outside_printer_detection_enabled(false) , is_outside(false) - , hover_select(false) - , hover_deselect(false) + , hover(None) , is_modifier(false) , is_wipe_tower(false) , is_extrusion_path(false) @@ -293,9 +292,9 @@ void GLVolume::set_render_color() if (force_native_color) set_render_color(color, 4); else { - if (hover_select) + if (hover == Select) set_render_color(HOVER_SELECT_COLOR, 4); - else if (hover_deselect) + else if (hover == Deselect) set_render_color(HOVER_DESELECT_COLOR, 4); else if (selected) set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index fa7d6f7d1..8ed8da43f 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -234,6 +234,13 @@ public: static const float SLA_SUPPORT_COLOR[4]; static const float SLA_PAD_COLOR[4]; + enum EHoverState : unsigned char + { + None, + Select, + Deselect + }; + GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f); GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {} ~GLVolume(); @@ -297,10 +304,8 @@ public: bool shader_outside_printer_detection_enabled; // Wheter or not this volume is outside print volume. bool is_outside; - // Boolean: Is mouse over this object to select it ? - bool hover_select; - // Boolean: Is mouse over this object to deselect it ? - bool hover_deselect; + // Is mouse or rectangle selection over this object to select/deselect it ? + EHoverState hover; // Wheter or not this volume has been generated from a modifier bool is_modifier; // Wheter or not this volume has been generated from the wipe tower diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 621a726b9..9798efecb 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4246,8 +4246,7 @@ void GLCanvas3D::_update_volumes_hover_state() const { for (GLVolume* v : m_volumes.volumes) { - v->hover_select = false; - v->hover_deselect = false; + v->hover = GLVolume::None; } if (m_hover_volume_idxs.empty()) @@ -4268,9 +4267,9 @@ void GLCanvas3D::_update_volumes_hover_state() const if (volume->is_modifier && (!deselect || ((volume->object_idx() == m_selection.get_object_idx()) && (volume->instance_idx() == m_selection.get_instance_idx())))) { if (deselect) - volume->hover_deselect = true; + volume->hover = GLVolume::Deselect; else - volume->hover_select = true; + volume->hover = GLVolume::Select; } else { @@ -4282,9 +4281,9 @@ void GLCanvas3D::_update_volumes_hover_state() const if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) { if (deselect) - v->hover_deselect = true; + v->hover = GLVolume::Deselect; else - v->hover_select = true; + v->hover = GLVolume::Select; } } } diff --git a/src/slic3r/GUI/GLSelectionRectangle.hpp b/src/slic3r/GUI/GLSelectionRectangle.hpp index db72d9415..d9869771e 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.hpp +++ b/src/slic3r/GUI/GLSelectionRectangle.hpp @@ -34,7 +34,7 @@ public: bool is_dragging() const { return m_state != Off; } EState get_state() const { return m_state; } - + float get_width() const { return std::abs(m_start_corner(0) - m_end_corner(0)); } float get_height() const { return std::abs(m_start_corner(1) - m_end_corner(1)); } float get_left() const { return std::min(m_start_corner(0), m_end_corner(0)); } From d2597482e0233e33c1e09dae927049b53dc528f4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 11:10:01 +0200 Subject: [PATCH 09/29] Added imgui debug dialog for render statistics --- src/libslic3r/Technologies.hpp | 2 ++ src/slic3r/GUI/GLCanvas3D.cpp | 25 ++++++++++++++++++++++++- src/slic3r/GUI/GLCanvas3D.hpp | 14 +++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index ea3d87888..afd8ee026 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -11,6 +11,8 @@ #define ENABLE_SELECTION_DEBUG_OUTPUT 0 // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER 0 +// Shows an imgui dialog with render related data +#define ENABLE_RENDER_STATISTICS 1 //==================== diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9798efecb..d58b40fdf 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -52,6 +52,9 @@ #include #include #include +#if ENABLE_RENDER_STATISTICS +#include +#endif // ENABLE_RENDER_STATISTICS static const float TRACKBALLSIZE = 0.8f; static const float GROUND_Z = -0.02f; @@ -1581,6 +1584,10 @@ void GLCanvas3D::render() if (!_set_current() || !_3DScene::init(m_canvas)) return; +#if ENABLE_RENDER_STATISTICS + auto start_time = std::chrono::high_resolution_clock::now(); +#endif // ENABLE_RENDER_STATISTICS + if (m_bed.get_shape().empty()) { // this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE @@ -1666,9 +1673,26 @@ void GLCanvas3D::render() if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f)) m_layers_editing.render_overlay(*this); +#if ENABLE_RENDER_STATISTICS + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.set_next_window_bg_alpha(0.5f); + imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + imgui.text("Last frame: "); + ImGui::SameLine(); + imgui.text(std::to_string(m_render_stats.last_frame)); + ImGui::SameLine(); + imgui.text(" ms"); + imgui.end(); +#endif // ENABLE_RENDER_STATISTICS + wxGetApp().imgui()->render(); m_canvas->SwapBuffers(); + +#if ENABLE_RENDER_STATISTICS + auto end_time = std::chrono::high_resolution_clock::now(); + m_render_stats.last_frame = std::chrono::duration_cast(end_time - start_time).count(); +#endif // ENABLE_RENDER_STATISTICS } void GLCanvas3D::select_all() @@ -2751,7 +2775,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_regenerate_volumes = false; m_selection.translate(cur_pos - m_mouse.drag.start_position_3D); wxGetApp().obj_manipul()->update_settings_value(m_selection); - m_dirty = true; } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index bae9f0b5e..9e2d87bdb 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -319,7 +319,6 @@ class GLCanvas3D } }; -private: struct SlaCap { struct Triangles @@ -399,6 +398,15 @@ private: void render(const GLCanvas3D& canvas) const; }; +#if ENABLE_RENDER_STATISTICS + struct RenderStats + { + long long last_frame; + + RenderStats() : last_frame(0) {} + }; +#endif // ENABLE_RENDER_STATISTICS + public: enum ECursorType : unsigned char { @@ -464,6 +472,10 @@ private: GCodePreviewVolumeIndex m_gcode_preview_volume_index; +#if ENABLE_RENDER_STATISTICS + RenderStats m_render_stats; +#endif // ENABLE_RENDER_STATISTICS + public: GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar); ~GLCanvas3D(); From 3fba85079359e3f33f770a29202fdb0c95a3a506 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 11:50:30 +0200 Subject: [PATCH 10/29] Rectangle selection in 3D scene -> tweaks to the hovering detection logic --- src/slic3r/GUI/GLCanvas3D.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d58b40fdf..d1354f2f5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1676,7 +1676,7 @@ void GLCanvas3D::render() #if ENABLE_RENDER_STATISTICS ImGuiWrapper& imgui = *wxGetApp().imgui(); imgui.set_next_window_bg_alpha(0.5f); - imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); imgui.text("Last frame: "); ImGui::SameLine(); imgui.text(std::to_string(m_render_stats.last_frame)); @@ -4283,11 +4283,11 @@ void GLCanvas3D::_update_volumes_hover_state() const { GLVolume* volume = m_volumes.volumes[i]; bool deselect = volume->selected && ((is_ctrl_pressed && !is_shift_pressed) || (!is_ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Deselect))); - bool select = !volume->selected || (volume->is_modifier && ((is_ctrl_pressed && !is_alt_pressed) || (!is_ctrl_pressed && (!m_rectangle_selection.is_dragging() || (m_rectangle_selection.get_state() == GLSelectionRectangle::Select))))); + bool select = (!volume->selected && !is_alt_pressed) || (volume->is_modifier && ((is_ctrl_pressed && !is_alt_pressed) || (!is_ctrl_pressed && (!m_rectangle_selection.is_dragging() || (m_rectangle_selection.get_state() == GLSelectionRectangle::Select))))); if (select || deselect) { - if (volume->is_modifier && (!deselect || ((volume->object_idx() == m_selection.get_object_idx()) && (volume->instance_idx() == m_selection.get_instance_idx())))) + if (volume->is_modifier && ((!deselect && !is_ctrl_pressed) || (deselect && (volume->object_idx() == m_selection.get_object_idx()) && (volume->instance_idx() == m_selection.get_instance_idx())))) { if (deselect) volume->hover = GLVolume::Deselect; From a0640d2d24eeed796f5946e9345083288ac62718 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 12:31:55 +0200 Subject: [PATCH 11/29] Rectangle selection in 3D scene -> selection update --- src/slic3r/GUI/GLCanvas3D.cpp | 32 ++++++++++++++++++++++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 3 +++ 2 files changed, 35 insertions(+) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d1354f2f5..20babc470 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2375,6 +2375,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) { if (m_picking_enabled && m_rectangle_selection.is_dragging()) { + _update_selection_from_hover(); m_rectangle_selection.stop_dragging(); m_dirty = true; } @@ -2384,6 +2385,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) { if (m_picking_enabled && m_rectangle_selection.is_dragging()) { + _update_selection_from_hover(); m_rectangle_selection.stop_dragging(); m_dirty = true; } @@ -2840,6 +2842,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if (evt.LeftUp() && m_picking_enabled && m_rectangle_selection.is_dragging()) { + if (evt.ShiftDown() || evt.AltDown()) + _update_selection_from_hover(); + m_rectangle_selection.stop_dragging(); } else if (evt.LeftUp() && !m_mouse.dragging && m_hover_volume_idxs.empty() && !is_layers_editing_enabled()) @@ -5584,6 +5589,33 @@ void GLCanvas3D::_resize_toolbars() const } #endif // !ENABLE_SVG_ICONS +void GLCanvas3D::_update_selection_from_hover() +{ + if (m_hover_volume_idxs.empty()) + return; + + GLSelectionRectangle::EState state = m_rectangle_selection.get_state(); + bool is_ctrl_pressed = wxGetKeyState(WXK_CONTROL); + + bool is_single_modifier = (m_hover_volume_idxs.size() == 1) && m_volumes.volumes[m_hover_volume_idxs.front()]->is_modifier; + + if ((state == GLSelectionRectangle::Select) && !is_ctrl_pressed) + m_selection.clear(); + + for (int idx : m_hover_volume_idxs) + { + if (state == GLSelectionRectangle::Select) + m_selection.add(idx, is_single_modifier && !is_ctrl_pressed); + else + m_selection.remove(idx); + } + + m_gizmos.refresh_on_off_state(m_selection); + m_gizmos.update_data(*this); + post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); + m_dirty = true; +} + const Print* GLCanvas3D::fff_print() const { return (m_process == nullptr) ? nullptr : m_process->fff_print(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 9e2d87bdb..57083cfa0 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -714,6 +714,9 @@ private: void _resize_toolbars() const; #endif // !ENABLE_SVG_ICONS + // updates the selection from the content of m_hover_volume_idxs + void _update_selection_from_hover(); + static std::vector _parse_colors(const std::vector& colors); public: From f52f0f36349fa0acb501bd9d8433ce8aa265fbf1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 12:33:27 +0200 Subject: [PATCH 12/29] Disabled debug imgui dialog for render statistics --- src/libslic3r/Technologies.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index afd8ee026..45f04b1df 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -12,7 +12,7 @@ // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER 0 // Shows an imgui dialog with render related data -#define ENABLE_RENDER_STATISTICS 1 +#define ENABLE_RENDER_STATISTICS 0 //==================== From 748a4438ba15d94fd34332028b5361b9450aac1b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 13:35:24 +0200 Subject: [PATCH 13/29] Attempt to fix build on Linux --- src/slic3r/GUI/3DScene.cpp | 6 +++--- src/slic3r/GUI/3DScene.hpp | 6 +++--- src/slic3r/GUI/GLCanvas3D.cpp | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 873c8b9e6..c96798c6f 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -252,7 +252,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) , zoom_to_volumes(true) , shader_outside_printer_detection_enabled(false) , is_outside(false) - , hover(None) + , hover(HS_None) , is_modifier(false) , is_wipe_tower(false) , is_extrusion_path(false) @@ -292,9 +292,9 @@ void GLVolume::set_render_color() if (force_native_color) set_render_color(color, 4); else { - if (hover == Select) + if (hover == HS_Select) set_render_color(HOVER_SELECT_COLOR, 4); - else if (hover == Deselect) + else if (hover == HS_Deselect) set_render_color(HOVER_DESELECT_COLOR, 4); else if (selected) set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 8ed8da43f..377d89fe7 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -236,9 +236,9 @@ public: enum EHoverState : unsigned char { - None, - Select, - Deselect + HS_None, + HS_Select, + HS_Deselect }; GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 20babc470..c86ca594c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4274,7 +4274,7 @@ void GLCanvas3D::_update_volumes_hover_state() const { for (GLVolume* v : m_volumes.volumes) { - v->hover = GLVolume::None; + v->hover = GLVolume::HS_None; } if (m_hover_volume_idxs.empty()) @@ -4295,9 +4295,9 @@ void GLCanvas3D::_update_volumes_hover_state() const if (volume->is_modifier && ((!deselect && !is_ctrl_pressed) || (deselect && (volume->object_idx() == m_selection.get_object_idx()) && (volume->instance_idx() == m_selection.get_instance_idx())))) { if (deselect) - volume->hover = GLVolume::Deselect; + volume->hover = GLVolume::HS_Deselect; else - volume->hover = GLVolume::Select; + volume->hover = GLVolume::HS_Select; } else { @@ -4309,9 +4309,9 @@ void GLCanvas3D::_update_volumes_hover_state() const if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) { if (deselect) - v->hover = GLVolume::Deselect; + v->hover = GLVolume::HS_Deselect; else - v->hover = GLVolume::Select; + v->hover = GLVolume::HS_Select; } } } From 905673f344191e53f2e2c08a62a84e4d0480243e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 13:41:00 +0200 Subject: [PATCH 14/29] Small refactoring --- src/slic3r/GUI/GLCanvas3D.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c86ca594c..9a43ca118 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3658,9 +3658,7 @@ void GLCanvas3D::_refresh_if_shown_on_screen() void GLCanvas3D::_picking_pass() const { - const Vec2d& pos = m_mouse.position; - - if (m_picking_enabled && !m_mouse.dragging && (pos != Vec2d(DBL_MAX, DBL_MAX))) + if (m_picking_enabled && !m_mouse.dragging && (m_mouse.position != Vec2d(DBL_MAX, DBL_MAX))) { m_hover_volume_idxs.clear(); @@ -3694,10 +3692,10 @@ void GLCanvas3D::_picking_pass() const GLubyte color[4] = { 0, 0, 0, 0 }; const Size& cnv_size = get_canvas_size(); - bool inside = (0 <= pos(0)) && (pos(0) < cnv_size.get_width()) && (0 <= pos(1)) && (pos(1) < cnv_size.get_height()); + bool inside = (0 <= m_mouse.position(0)) && (m_mouse.position(0) < cnv_size.get_width()) && (0 <= m_mouse.position(1)) && (m_mouse.position(1) < cnv_size.get_height()); if (inside) { - glsafe(::glReadPixels(pos(0), cnv_size.get_height() - pos(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color)); + glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color)); volume_id = color[0] + (color[1] << 8) + (color[2] << 16); } if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) From 36252a42daad35d6334e1601e95b85e5bb1cb483 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 25 Apr 2019 15:08:14 +0200 Subject: [PATCH 15/29] Small optimization --- src/slic3r/GUI/GLCanvas3D.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9a43ca118..e0884e6b0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1617,12 +1617,15 @@ void GLCanvas3D::render() wxGetApp().imgui()->new_frame(); - if (m_rectangle_selection.is_dragging()) - // picking pass using rectangle selection - _rectangular_selection_picking_pass(); - else - // regular picking pass - _picking_pass(); + if (m_picking_enabled) + { + if (m_rectangle_selection.is_dragging()) + // picking pass using rectangle selection + _rectangular_selection_picking_pass(); + else + // regular picking pass + _picking_pass(); + } // draw scene glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); From 8857d556f65808182bf1069bde4e7121b776445d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 26 Apr 2019 13:37:34 +0200 Subject: [PATCH 16/29] Rectangle selection in 3D scene -> tweaks to hovering detection and selection update logic --- src/slic3r/GUI/GLCanvas3D.cpp | 102 ++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e0884e6b0..9a7c8834e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4281,29 +4281,75 @@ void GLCanvas3D::_update_volumes_hover_state() const if (m_hover_volume_idxs.empty()) return; - bool is_ctrl_pressed = wxGetKeyState(WXK_CONTROL); - bool is_shift_pressed = wxGetKeyState(WXK_SHIFT); - bool is_alt_pressed = wxGetKeyState(WXK_ALT); + bool ctrl_pressed = wxGetKeyState(WXK_CONTROL); // additive select/deselect + bool shift_pressed = wxGetKeyState(WXK_SHIFT); // select by rectangle + bool alt_pressed = wxGetKeyState(WXK_ALT); // deselect by rectangle + + if (alt_pressed && (shift_pressed || ctrl_pressed)) + { + // illegal combinations of keys + m_hover_volume_idxs.clear(); + return; + } + + bool selection_modifiers_only = m_selection.is_empty() || m_selection.is_any_modifier(); + + bool hover_modifiers_only = true; + for (int i : m_hover_volume_idxs) + { + if (!m_volumes.volumes[i]->is_modifier) + { + hover_modifiers_only = false; + break; + } + } + + std::set> hover_instances; + for (int i : m_hover_volume_idxs) + { + const GLVolume& v = *m_volumes.volumes[i]; + hover_instances.insert(std::make_pair(v.object_idx(), v.instance_idx())); + } + + bool hover_from_single_instance = hover_instances.size() == 1; + + if (hover_modifiers_only && !hover_from_single_instance) + { + // do not allow to select volumes from different instances + m_hover_volume_idxs.clear(); + return; + } for (int i : m_hover_volume_idxs) { - GLVolume* volume = m_volumes.volumes[i]; - bool deselect = volume->selected && ((is_ctrl_pressed && !is_shift_pressed) || (!is_ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Deselect))); - bool select = (!volume->selected && !is_alt_pressed) || (volume->is_modifier && ((is_ctrl_pressed && !is_alt_pressed) || (!is_ctrl_pressed && (!m_rectangle_selection.is_dragging() || (m_rectangle_selection.get_state() == GLSelectionRectangle::Select))))); + GLVolume& volume = *m_volumes.volumes[i]; + if (volume.hover != GLVolume::HS_None) + continue; + + bool deselect = volume.selected && ((ctrl_pressed && !shift_pressed) || alt_pressed); + // (volume->is_modifier && !selection_modifiers_only && !is_ctrl_pressed) -> allows hovering on selected modifiers belonging to selection of type Instance + bool select = (!volume.selected || (volume.is_modifier && !selection_modifiers_only && !ctrl_pressed)) && !alt_pressed; if (select || deselect) { - if (volume->is_modifier && ((!deselect && !is_ctrl_pressed) || (deselect && (volume->object_idx() == m_selection.get_object_idx()) && (volume->instance_idx() == m_selection.get_instance_idx())))) + bool as_volume = + volume.is_modifier && hover_from_single_instance && !ctrl_pressed && + ( + (!deselect) || + (deselect && !m_selection.is_single_full_instance() && (volume.object_idx() == m_selection.get_object_idx()) && (volume.instance_idx() == m_selection.get_instance_idx())) + ); + + if (as_volume) { if (deselect) - volume->hover = GLVolume::HS_Deselect; + volume.hover = GLVolume::HS_Deselect; else - volume->hover = GLVolume::HS_Select; + volume.hover = GLVolume::HS_Select; } else { - int object_idx = volume->object_idx(); - int instance_idx = volume->instance_idx(); + int object_idx = volume.object_idx(); + int instance_idx = volume.instance_idx(); for (GLVolume* v : m_volumes.volumes) { @@ -5592,23 +5638,45 @@ void GLCanvas3D::_resize_toolbars() const void GLCanvas3D::_update_selection_from_hover() { + bool ctrl_pressed = wxGetKeyState(WXK_CONTROL); + if (m_hover_volume_idxs.empty()) + { + if (!ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Select)) + m_selection.clear(); + return; + } GLSelectionRectangle::EState state = m_rectangle_selection.get_state(); - bool is_ctrl_pressed = wxGetKeyState(WXK_CONTROL); - bool is_single_modifier = (m_hover_volume_idxs.size() == 1) && m_volumes.volumes[m_hover_volume_idxs.front()]->is_modifier; + bool hover_modifiers_only = true; + for (int i : m_hover_volume_idxs) + { + if (!m_volumes.volumes[i]->is_modifier) + { + hover_modifiers_only = false; + break; + } + } - if ((state == GLSelectionRectangle::Select) && !is_ctrl_pressed) + if ((state == GLSelectionRectangle::Select) && !ctrl_pressed) m_selection.clear(); - for (int idx : m_hover_volume_idxs) + for (int i : m_hover_volume_idxs) { if (state == GLSelectionRectangle::Select) - m_selection.add(idx, is_single_modifier && !is_ctrl_pressed); + { + if (hover_modifiers_only) + { + const GLVolume& v = *m_volumes.volumes[i]; + m_selection.add_volume(v.object_idx(), v.volume_idx(), v.instance_idx(), false); + } + else + m_selection.add(i, false); + } else - m_selection.remove(idx); + m_selection.remove(i); } m_gizmos.refresh_on_off_state(m_selection); From 818f7ad647d0a5ed261820ddce8638e6a18ede72 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 26 Apr 2019 14:07:46 +0200 Subject: [PATCH 17/29] Rectangle selection in 3D scene -> Fixed selection cleared when mouse left-up follows shift-up --- src/slic3r/GUI/GLCanvas3D.cpp | 12 +++++++++++- src/slic3r/GUI/GLCanvas3D.hpp | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f4b6a2b99..985f7ded2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -675,6 +675,7 @@ GLCanvas3D::Mouse::Mouse() : dragging(false) , position(DBL_MAX, DBL_MAX) , scene_position(DBL_MAX, DBL_MAX, DBL_MAX) + , ignore_left_up(false) { } @@ -2387,6 +2388,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) { _update_selection_from_hover(); m_rectangle_selection.stop_dragging(); + m_mouse.ignore_left_up = true; m_dirty = true; } set_cursor(Standard); @@ -2397,6 +2399,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) { _update_selection_from_hover(); m_rectangle_selection.stop_dragging(); + m_mouse.ignore_left_up = true; m_dirty = true; } set_cursor(Standard); @@ -2409,12 +2412,18 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) if (keyCode == WXK_SHIFT) { if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) + { + m_mouse.ignore_left_up = false; set_cursor(Cross); + } } else if (keyCode == WXK_ALT) { if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) + { + m_mouse.ignore_left_up = false; set_cursor(Cross); + } } else if (keyCode == WXK_CONTROL) m_dirty = true; @@ -2536,6 +2545,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.set_start_position_3D_as_invalid(); m_mouse.set_start_position_2D_as_invalid(); m_mouse.dragging = false; + m_mouse.ignore_left_up = false; m_dirty = true; if (m_canvas->HasCapture()) @@ -2857,7 +2867,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_rectangle_selection.stop_dragging(); } - else if (evt.LeftUp() && !m_mouse.dragging && m_hover_volume_idxs.empty() && !is_layers_editing_enabled()) + else if (evt.LeftUp() && !m_mouse.ignore_left_up && !m_mouse.dragging && m_hover_volume_idxs.empty() && !is_layers_editing_enabled()) { // deselect and propagate event through callback if (!evt.ShiftDown() && m_picking_enabled) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 4d2c0c2b2..4670b7221 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -303,6 +303,7 @@ class GLCanvas3D Vec2d position; Vec3d scene_position; Drag drag; + bool ignore_left_up; Mouse(); From fdf1b8af81a7d7d52f720b0f639c11ee6113560a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 29 Apr 2019 08:26:08 +0200 Subject: [PATCH 18/29] Rectangle selection -> Removed cursor change --- src/slic3r/GUI/GLCanvas3D.cpp | 8 ++++---- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 985f7ded2..e57eead30 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2391,7 +2391,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) m_mouse.ignore_left_up = true; m_dirty = true; } - set_cursor(Standard); +// set_cursor(Standard); } else if (keyCode == WXK_ALT) { @@ -2402,7 +2402,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) m_mouse.ignore_left_up = true; m_dirty = true; } - set_cursor(Standard); +// set_cursor(Standard); } else if (keyCode == WXK_CONTROL) m_dirty = true; @@ -2414,7 +2414,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) { m_mouse.ignore_left_up = false; - set_cursor(Cross); +// set_cursor(Cross); } } else if (keyCode == WXK_ALT) @@ -2422,7 +2422,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)) { m_mouse.ignore_left_up = false; - set_cursor(Cross); +// set_cursor(Cross); } } else if (keyCode == WXK_CONTROL) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index b7e1b3f07..a00303634 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -861,14 +861,14 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas) } } - if (processed) - canvas.set_cursor(GLCanvas3D::Standard); +// if (processed) +// canvas.set_cursor(GLCanvas3D::Standard); } else if (evt.GetEventType() == wxEVT_KEY_DOWN) { if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) && reinterpret_cast(get_current())->is_in_editing_mode()) { - canvas.set_cursor(GLCanvas3D::Cross); +// canvas.set_cursor(GLCanvas3D::Cross); processed = true; } } From dfe271965679c20cc300ff2f0b386ea10187343a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 29 Apr 2019 08:31:32 +0200 Subject: [PATCH 19/29] Rectangle selection -> Min size of rectangle selection set to 1 pixel --- src/slic3r/GUI/GLCanvas3D.cpp | 75 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e57eead30..74ced68bc 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3751,55 +3751,52 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const if (m_multisample_allowed) glsafe(::glEnable(GL_MULTISAMPLE)); - int width = (int)m_rectangle_selection.get_width(); - int height = (int)m_rectangle_selection.get_height(); + int width = std::max((int)m_rectangle_selection.get_width(), 1); + int height = std::max((int)m_rectangle_selection.get_height(), 1); int px_count = width * height; - if (px_count > 0) + int left = (int)m_rectangle_selection.get_left(); + int top = get_canvas_size().get_height() - (int)m_rectangle_selection.get_top(); + if ((left >= 0) && (top >= 0)) { - int left = (int)m_rectangle_selection.get_left(); - int top = get_canvas_size().get_height() - (int)m_rectangle_selection.get_top(); - if ((left >= 0) && (top >= 0)) - { #define USE_PARALLEL 1 #if USE_PARALLEL - struct Pixel + struct Pixel + { + std::array data; + int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); } + }; + + std::vector frame(px_count); + glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data())); + + tbb::spin_mutex mutex; + tbb::parallel_for(tbb::blocked_range(0, frame.size(), (size_t)width), + [this, &frame, &idxs, &mutex](const tbb::blocked_range& range) { + for (size_t i = range.begin(); i < range.end(); ++i) { - std::array data; - int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); } - }; - - std::vector frame(px_count); - glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data())); - - tbb::spin_mutex mutex; - tbb::parallel_for(tbb::blocked_range(0, frame.size(), (size_t)width), - [this, &frame, &idxs, &mutex](const tbb::blocked_range& range) { - for (size_t i = range.begin(); i < range.end(); ++i) + int volume_id = frame[i].id(); + if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) { - int volume_id = frame[i].id(); - if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) - { - mutex.lock(); - idxs.insert(volume_id); - mutex.unlock(); - } + mutex.lock(); + idxs.insert(volume_id); + mutex.unlock(); } } - ); -#else - std::vector frame(4 * px_count); - glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data())); - - for (int i = 0; i < px_count; ++i) - { - int px_id = 4 * i; - int volume_id = frame[px_id] + (frame[px_id + 1] << 8) + (frame[px_id + 2] << 16); - if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) - idxs.insert(volume_id); - } -#endif // USE_PARALLEL } + ); +#else + std::vector frame(4 * px_count); + glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data())); + + for (int i = 0; i < px_count; ++i) + { + int px_id = 4 * i; + int volume_id = frame[px_id] + (frame[px_id + 1] << 8) + (frame[px_id + 2] << 16); + if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) + idxs.insert(volume_id); + } +#endif // USE_PARALLEL } } From 2a741bf8f88510114539f63eabc470370a45f6a6 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 29 Apr 2019 10:01:28 +0200 Subject: [PATCH 20/29] Rectangle selection -> Lighter color for deselect hover --- src/slic3r/GUI/3DScene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index c96798c6f..037f70962 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -224,7 +224,7 @@ void GLIndexedVertexArray::render( const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; const float GLVolume::HOVER_SELECT_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f }; -const float GLVolume::HOVER_DESELECT_COLOR[4] = { 0.9f, 0.4f, 0.1f, 1.0f }; +const float GLVolume::HOVER_DESELECT_COLOR[4] = { 1.0f, 0.75f, 0.75f, 1.0f }; const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f }; const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f }; const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f }; From 0a1c092d756fed3001a5498a9f104336281aa7ef Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 30 Apr 2019 12:00:23 +0200 Subject: [PATCH 21/29] Use Prusa3D patched wxWidgets 3.1.1 --- deps/deps-macos.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deps/deps-macos.cmake b/deps/deps-macos.cmake index 790a65aeb..a47b22946 100644 --- a/deps/deps-macos.cmake +++ b/deps/deps-macos.cmake @@ -89,8 +89,10 @@ ExternalProject_Add(dep_libcurl ExternalProject_Add(dep_wxwidgets EXCLUDE_FROM_ALL 1 - URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.2/wxWidgets-3.1.2.tar.bz2" - URL_HASH SHA256=4cb8d23d70f9261debf7d6cfeca667fc0a7d2b6565adb8f1c484f9b674f1f27a + GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" + GIT_TAG v3.1.1-patched +# URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.2/wxWidgets-3.1.2.tar.bz2" +# URL_HASH SHA256=4cb8d23d70f9261debf7d6cfeca667fc0a7d2b6565adb8f1c484f9b674f1f27a BUILD_IN_SOURCE 1 PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/wxwidgets-pngprefix.h" src/png/pngprefix.h CONFIGURE_COMMAND env "CXXFLAGS=${DEP_WERRORS_SDK}" "CFLAGS=${DEP_WERRORS_SDK}" ./configure From 52c28578d66050f86599688a7957afb0f3568e43 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 30 Apr 2019 12:19:29 +0200 Subject: [PATCH 22/29] Fixed compilation of dependencies on OSX --- deps/deps-macos.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/deps-macos.cmake b/deps/deps-macos.cmake index a47b22946..c7c6819e3 100644 --- a/deps/deps-macos.cmake +++ b/deps/deps-macos.cmake @@ -94,7 +94,7 @@ ExternalProject_Add(dep_wxwidgets # URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.2/wxWidgets-3.1.2.tar.bz2" # URL_HASH SHA256=4cb8d23d70f9261debf7d6cfeca667fc0a7d2b6565adb8f1c484f9b674f1f27a BUILD_IN_SOURCE 1 - PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/wxwidgets-pngprefix.h" src/png/pngprefix.h +# PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/wxwidgets-pngprefix.h" src/png/pngprefix.h CONFIGURE_COMMAND env "CXXFLAGS=${DEP_WERRORS_SDK}" "CFLAGS=${DEP_WERRORS_SDK}" ./configure "--prefix=${DESTDIR}/usr/local" --disable-shared From 646986348a2534be397f3e496a5227727672694a Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 30 Apr 2019 13:51:36 +0200 Subject: [PATCH 23/29] Fixed menubar item's name in respect to printer_technology --- src/slic3r/GUI/MainFrame.cpp | 19 +++++++++++++++++-- src/slic3r/GUI/MainFrame.hpp | 11 +++++++++++ src/slic3r/GUI/Plater.cpp | 3 +++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 3e3642af5..cbc85ef23 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -332,6 +332,7 @@ void MainFrame::init_menubar() wxMenu* export_menu = new wxMenu(); wxMenuItem* item_export_gcode = append_menu_item(export_menu, wxID_ANY, _(L("Export &G-code")) + dots +"\tCtrl+G", _(L("Export current plate as G-code")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, "export_gcode"); + m_changeable_menu_items.push_back(item_export_gcode); export_menu->AppendSeparator(); wxMenuItem* item_export_stl = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "export_plater"); @@ -444,8 +445,9 @@ void MainFrame::init_menubar() } append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")), [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog"); - append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")), - [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool.png"); + wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")), + [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool"); + m_changeable_menu_items.push_back(item_material_tab); append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")), [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer"); if (m_plater) { @@ -554,6 +556,19 @@ void MainFrame::init_menubar() }, wxID_EXIT); } #endif + + if (plater()->printer_technology() == ptSLA) + update_menubar(); +} + +void MainFrame::update_menubar() +{ + const bool is_fff = plater()->printer_technology() == ptFFF; + + m_changeable_menu_items[miExport] ->SetItemLabel((is_fff ? _(L("Export &G-code")) : _(L("Export")) ) + dots + "\tCtrl+G"); + + m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3"); + m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, is_fff ? "spool": "resin")); } // To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG". diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index a8b2be2bc..13bf07922 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -70,6 +70,16 @@ class MainFrame : public DPIFrame bool can_delete() const; bool can_delete_all() const; + // MenuBar items changeable in respect to printer technology + enum MenuItems + { // FFF SLA + miExport = 0, // Export G-code Export + miMaterialTab, // Filament Settings Material Settings + }; + + // vector of a MenuBar items changeable in respect to printer technology + std::vector m_changeable_menu_items; + protected: virtual void on_dpi_changed(const wxRect &suggested_rect); @@ -83,6 +93,7 @@ public: void create_preset_tabs(); void add_created_tab(Tab* panel); void init_menubar(); + void update_menubar(); void update_ui_from_settings(); bool is_loaded() const { return m_loaded; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 02cdaf208..2195471da 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3747,6 +3747,9 @@ void Plater::set_printer_technology(PrinterTechnology printer_technology) p->label_btn_export = printer_technology == ptFFF ? L("Export G-code") : L("Export"); p->label_btn_send = printer_technology == ptFFF ? L("Send G-code") : L("Send to printer"); + + if (wxGetApp().mainframe) + wxGetApp().mainframe->update_menubar(); } void Plater::changed_object(int obj_idx) From 3a5485a1790b30dcccefa1009a5c7010fdf2fc78 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 30 Apr 2019 15:09:25 +0200 Subject: [PATCH 24/29] Flip X mouse deltas if bed is upside down (when camera up vector has negative Z) --- src/slic3r/GUI/Camera.cpp | 1 + src/slic3r/GUI/Camera.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 7a1023e62..dd6cbefe1 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -25,6 +25,7 @@ Camera::Camera() , phi(45.0f) // , distance(0.0f) , requires_zoom_to_bed(false) + , inverted_phi(false) , m_theta(45.0f) , m_target(Vec3d::Zero()) { diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index d19bc870e..b9c5dfc32 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -22,6 +22,7 @@ struct Camera float phi; // float distance; bool requires_zoom_to_bed; + bool inverted_phi; private: Vec3d m_target; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index dfddc7f45..d02878a1a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2729,7 +2729,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if ((m_hover_volume_id == -1) && m_mouse.is_start_position_3D_defined()) { const Vec3d& orig = m_mouse.drag.start_position_3D; - m_camera.phi += (((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE); + float sign = m_camera.inverted_phi ? -1.0f : 1.0f; + m_camera.phi += sign * ((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE; m_camera.set_theta(m_camera.get_theta() - ((float)pos(1) - (float)orig(1)) * TRACKBALLSIZE, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); m_dirty = true; } @@ -2781,6 +2782,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); } } + else if (evt.LeftUp() && m_mouse.dragging) + // Flips X mouse deltas if bed is upside down + m_camera.inverted_phi = (m_camera.get_dir_up()(2) < 0.0); else if (evt.RightUp()) { m_mouse.position = pos.cast(); From f18ebec8e94dcb1a507a69ddf698220b36e363c9 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 30 Apr 2019 15:13:38 +0200 Subject: [PATCH 25/29] Added menu icons for a dark mode --- resources/icons/layers.svg | 8 +- resources/icons/white/add_copies.svg | 19 ++++ resources/icons/white/add_modifier.svg | 13 +++ resources/icons/white/add_part.svg | 20 ++++ resources/icons/white/advanced+wrench.svg | 43 +++++++++ resources/icons/white/advanced_plus.svg | 24 +++++ resources/icons/white/cog.svg | 17 ++++ resources/icons/white/cooling.svg | 25 +++++ resources/icons/white/copy_menu.svg | 37 ++++++++ resources/icons/white/delete.svg | 22 +++++ resources/icons/white/delete_all_menu.svg | 31 ++++++ resources/icons/white/editor_menu.svg | 20 ++++ resources/icons/white/export_config.svg | 20 ++++ .../icons/white/export_config_bundle.svg | 50 ++++++++++ resources/icons/white/export_gcode.svg | 14 +++ resources/icons/white/export_plate.svg | 15 +++ resources/icons/white/export_plater.svg | 12 +++ resources/icons/white/extruder+funnel.svg | 15 +++ resources/icons/white/flag_green.svg | 10 ++ resources/icons/white/flag_red.svg | 10 ++ resources/icons/white/import_config.svg | 25 +++++ .../icons/white/import_config_bundle.svg | 61 ++++++++++++ resources/icons/white/import_plate.svg | 38 ++++++++ resources/icons/white/import_plater.svg | 17 ++++ resources/icons/white/infill.svg | 35 +++++++ resources/icons/white/layers.svg | 27 ++++++ resources/icons/white/lock2_closed.svg | 10 ++ resources/icons/white/lock_closed.svg | 10 ++ resources/icons/white/machine+cog.svg | 30 ++++++ resources/icons/white/notes.svg | 25 +++++ resources/icons/white/number_of_copies.svg | 29 ++++++ resources/icons/white/open.svg | 11 +++ resources/icons/white/output+page_white.svg | 20 ++++ resources/icons/white/pad.svg | 83 ++++++++++++++++ resources/icons/white/paste_menu.svg | 27 ++++++ resources/icons/white/plater.svg | 12 +++ resources/icons/white/preview_menu.svg | 48 ++++++++++ resources/icons/white/printer.svg | 14 +++ resources/icons/white/re_slice.svg | 19 ++++ resources/icons/white/remove_copies.svg | 15 +++ resources/icons/white/remove_menu.svg | 44 +++++++++ resources/icons/white/resin.svg | 10 ++ resources/icons/white/save.svg | 25 +++++ resources/icons/white/set_separate_obj.svg | 29 ++++++ resources/icons/white/skirt+brim.svg | 15 +++ resources/icons/white/split_object_SMALL.svg | 19 ++++ resources/icons/white/split_parts_SMALL.svg | 18 ++++ resources/icons/white/spool.svg | 21 +++++ resources/icons/white/support.svg | 94 +++++++++++++++++++ resources/icons/white/support_blocker.svg | 48 ++++++++++ resources/icons/white/support_enforcer.svg | 19 ++++ resources/icons/white/test.svg | 37 ++++++++ resources/icons/white/time.svg | 16 ++++ resources/icons/white/upload_queue.svg | 29 ++++++ resources/icons/white/wrench.svg | 20 ++++ resources/icons/wrench_white.svg | 20 ++++ src/slic3r/GUI/MainFrame.cpp | 62 +++++++----- 57 files changed, 1477 insertions(+), 30 deletions(-) create mode 100644 resources/icons/white/add_copies.svg create mode 100644 resources/icons/white/add_modifier.svg create mode 100644 resources/icons/white/add_part.svg create mode 100644 resources/icons/white/advanced+wrench.svg create mode 100644 resources/icons/white/advanced_plus.svg create mode 100644 resources/icons/white/cog.svg create mode 100644 resources/icons/white/cooling.svg create mode 100644 resources/icons/white/copy_menu.svg create mode 100644 resources/icons/white/delete.svg create mode 100644 resources/icons/white/delete_all_menu.svg create mode 100644 resources/icons/white/editor_menu.svg create mode 100644 resources/icons/white/export_config.svg create mode 100644 resources/icons/white/export_config_bundle.svg create mode 100644 resources/icons/white/export_gcode.svg create mode 100644 resources/icons/white/export_plate.svg create mode 100644 resources/icons/white/export_plater.svg create mode 100644 resources/icons/white/extruder+funnel.svg create mode 100644 resources/icons/white/flag_green.svg create mode 100644 resources/icons/white/flag_red.svg create mode 100644 resources/icons/white/import_config.svg create mode 100644 resources/icons/white/import_config_bundle.svg create mode 100644 resources/icons/white/import_plate.svg create mode 100644 resources/icons/white/import_plater.svg create mode 100644 resources/icons/white/infill.svg create mode 100644 resources/icons/white/layers.svg create mode 100644 resources/icons/white/lock2_closed.svg create mode 100644 resources/icons/white/lock_closed.svg create mode 100644 resources/icons/white/machine+cog.svg create mode 100644 resources/icons/white/notes.svg create mode 100644 resources/icons/white/number_of_copies.svg create mode 100644 resources/icons/white/open.svg create mode 100644 resources/icons/white/output+page_white.svg create mode 100644 resources/icons/white/pad.svg create mode 100644 resources/icons/white/paste_menu.svg create mode 100644 resources/icons/white/plater.svg create mode 100644 resources/icons/white/preview_menu.svg create mode 100644 resources/icons/white/printer.svg create mode 100644 resources/icons/white/re_slice.svg create mode 100644 resources/icons/white/remove_copies.svg create mode 100644 resources/icons/white/remove_menu.svg create mode 100644 resources/icons/white/resin.svg create mode 100644 resources/icons/white/save.svg create mode 100644 resources/icons/white/set_separate_obj.svg create mode 100644 resources/icons/white/skirt+brim.svg create mode 100644 resources/icons/white/split_object_SMALL.svg create mode 100644 resources/icons/white/split_parts_SMALL.svg create mode 100644 resources/icons/white/spool.svg create mode 100644 resources/icons/white/support.svg create mode 100644 resources/icons/white/support_blocker.svg create mode 100644 resources/icons/white/support_enforcer.svg create mode 100644 resources/icons/white/test.svg create mode 100644 resources/icons/white/time.svg create mode 100644 resources/icons/white/upload_queue.svg create mode 100644 resources/icons/white/wrench.svg create mode 100644 resources/icons/wrench_white.svg diff --git a/resources/icons/layers.svg b/resources/icons/layers.svg index cd71fab3a..da5dec21d 100644 --- a/resources/icons/layers.svg +++ b/resources/icons/layers.svg @@ -5,13 +5,13 @@ - + - + - + @@ -20,7 +20,7 @@ - + diff --git a/resources/icons/white/add_copies.svg b/resources/icons/white/add_copies.svg new file mode 100644 index 000000000..17eff0179 --- /dev/null +++ b/resources/icons/white/add_copies.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + diff --git a/resources/icons/white/add_modifier.svg b/resources/icons/white/add_modifier.svg new file mode 100644 index 000000000..09c3ce27d --- /dev/null +++ b/resources/icons/white/add_modifier.svg @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/resources/icons/white/add_part.svg b/resources/icons/white/add_part.svg new file mode 100644 index 000000000..b7c800bbb --- /dev/null +++ b/resources/icons/white/add_part.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/resources/icons/white/advanced+wrench.svg b/resources/icons/white/advanced+wrench.svg new file mode 100644 index 000000000..5e878cb3c --- /dev/null +++ b/resources/icons/white/advanced+wrench.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + diff --git a/resources/icons/white/advanced_plus.svg b/resources/icons/white/advanced_plus.svg new file mode 100644 index 000000000..db532ec4b --- /dev/null +++ b/resources/icons/white/advanced_plus.svg @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/resources/icons/white/cog.svg b/resources/icons/white/cog.svg new file mode 100644 index 000000000..773e4d65d --- /dev/null +++ b/resources/icons/white/cog.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/resources/icons/white/cooling.svg b/resources/icons/white/cooling.svg new file mode 100644 index 000000000..29bd04c36 --- /dev/null +++ b/resources/icons/white/cooling.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/copy_menu.svg b/resources/icons/white/copy_menu.svg new file mode 100644 index 000000000..d660aab6a --- /dev/null +++ b/resources/icons/white/copy_menu.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/delete.svg b/resources/icons/white/delete.svg new file mode 100644 index 000000000..91d5ce74c --- /dev/null +++ b/resources/icons/white/delete.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/delete_all_menu.svg b/resources/icons/white/delete_all_menu.svg new file mode 100644 index 000000000..5d825c424 --- /dev/null +++ b/resources/icons/white/delete_all_menu.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/editor_menu.svg b/resources/icons/white/editor_menu.svg new file mode 100644 index 000000000..649d2c40f --- /dev/null +++ b/resources/icons/white/editor_menu.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/export_config.svg b/resources/icons/white/export_config.svg new file mode 100644 index 000000000..22f8ebe1a --- /dev/null +++ b/resources/icons/white/export_config.svg @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/resources/icons/white/export_config_bundle.svg b/resources/icons/white/export_config_bundle.svg new file mode 100644 index 000000000..99bd62b6c --- /dev/null +++ b/resources/icons/white/export_config_bundle.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/export_gcode.svg b/resources/icons/white/export_gcode.svg new file mode 100644 index 000000000..39f5225cb --- /dev/null +++ b/resources/icons/white/export_gcode.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/resources/icons/white/export_plate.svg b/resources/icons/white/export_plate.svg new file mode 100644 index 000000000..18159d2a8 --- /dev/null +++ b/resources/icons/white/export_plate.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/resources/icons/white/export_plater.svg b/resources/icons/white/export_plater.svg new file mode 100644 index 000000000..e71b38a0a --- /dev/null +++ b/resources/icons/white/export_plater.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/resources/icons/white/extruder+funnel.svg b/resources/icons/white/extruder+funnel.svg new file mode 100644 index 000000000..de6b227da --- /dev/null +++ b/resources/icons/white/extruder+funnel.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/resources/icons/white/flag_green.svg b/resources/icons/white/flag_green.svg new file mode 100644 index 000000000..8479d0e9a --- /dev/null +++ b/resources/icons/white/flag_green.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/resources/icons/white/flag_red.svg b/resources/icons/white/flag_red.svg new file mode 100644 index 000000000..a9b1cf8fe --- /dev/null +++ b/resources/icons/white/flag_red.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/resources/icons/white/import_config.svg b/resources/icons/white/import_config.svg new file mode 100644 index 000000000..001277f73 --- /dev/null +++ b/resources/icons/white/import_config.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/resources/icons/white/import_config_bundle.svg b/resources/icons/white/import_config_bundle.svg new file mode 100644 index 000000000..c16cd7b3c --- /dev/null +++ b/resources/icons/white/import_config_bundle.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/import_plate.svg b/resources/icons/white/import_plate.svg new file mode 100644 index 000000000..7f888e3d7 --- /dev/null +++ b/resources/icons/white/import_plate.svg @@ -0,0 +1,38 @@ + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/import_plater.svg b/resources/icons/white/import_plater.svg new file mode 100644 index 000000000..1dc5aae6e --- /dev/null +++ b/resources/icons/white/import_plater.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/resources/icons/white/infill.svg b/resources/icons/white/infill.svg new file mode 100644 index 000000000..086043099 --- /dev/null +++ b/resources/icons/white/infill.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/layers.svg b/resources/icons/white/layers.svg new file mode 100644 index 000000000..cd71fab3a --- /dev/null +++ b/resources/icons/white/layers.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/lock2_closed.svg b/resources/icons/white/lock2_closed.svg new file mode 100644 index 000000000..726c850a1 --- /dev/null +++ b/resources/icons/white/lock2_closed.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/resources/icons/white/lock_closed.svg b/resources/icons/white/lock_closed.svg new file mode 100644 index 000000000..1665dc9a0 --- /dev/null +++ b/resources/icons/white/lock_closed.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/resources/icons/white/machine+cog.svg b/resources/icons/white/machine+cog.svg new file mode 100644 index 000000000..ec49265b8 --- /dev/null +++ b/resources/icons/white/machine+cog.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/resources/icons/white/notes.svg b/resources/icons/white/notes.svg new file mode 100644 index 000000000..25de4191e --- /dev/null +++ b/resources/icons/white/notes.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/number_of_copies.svg b/resources/icons/white/number_of_copies.svg new file mode 100644 index 000000000..7c9d78a80 --- /dev/null +++ b/resources/icons/white/number_of_copies.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/open.svg b/resources/icons/white/open.svg new file mode 100644 index 000000000..0ea9ecdb2 --- /dev/null +++ b/resources/icons/white/open.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/icons/white/output+page_white.svg b/resources/icons/white/output+page_white.svg new file mode 100644 index 000000000..083874003 --- /dev/null +++ b/resources/icons/white/output+page_white.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/resources/icons/white/pad.svg b/resources/icons/white/pad.svg new file mode 100644 index 000000000..cddb2da02 --- /dev/null +++ b/resources/icons/white/pad.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/paste_menu.svg b/resources/icons/white/paste_menu.svg new file mode 100644 index 000000000..465c2faf0 --- /dev/null +++ b/resources/icons/white/paste_menu.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/resources/icons/white/plater.svg b/resources/icons/white/plater.svg new file mode 100644 index 000000000..d637a5e7e --- /dev/null +++ b/resources/icons/white/plater.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/resources/icons/white/preview_menu.svg b/resources/icons/white/preview_menu.svg new file mode 100644 index 000000000..98095359c --- /dev/null +++ b/resources/icons/white/preview_menu.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/printer.svg b/resources/icons/white/printer.svg new file mode 100644 index 000000000..d94f6fd5c --- /dev/null +++ b/resources/icons/white/printer.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/resources/icons/white/re_slice.svg b/resources/icons/white/re_slice.svg new file mode 100644 index 000000000..b8d7dc727 --- /dev/null +++ b/resources/icons/white/re_slice.svg @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/resources/icons/white/remove_copies.svg b/resources/icons/white/remove_copies.svg new file mode 100644 index 000000000..5b277e45e --- /dev/null +++ b/resources/icons/white/remove_copies.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/resources/icons/white/remove_menu.svg b/resources/icons/white/remove_menu.svg new file mode 100644 index 000000000..59360a33f --- /dev/null +++ b/resources/icons/white/remove_menu.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + diff --git a/resources/icons/white/resin.svg b/resources/icons/white/resin.svg new file mode 100644 index 000000000..81abfae0c --- /dev/null +++ b/resources/icons/white/resin.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/resources/icons/white/save.svg b/resources/icons/white/save.svg new file mode 100644 index 000000000..3349a42dd --- /dev/null +++ b/resources/icons/white/save.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/set_separate_obj.svg b/resources/icons/white/set_separate_obj.svg new file mode 100644 index 000000000..de083c1c9 --- /dev/null +++ b/resources/icons/white/set_separate_obj.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/skirt+brim.svg b/resources/icons/white/skirt+brim.svg new file mode 100644 index 000000000..684e177d2 --- /dev/null +++ b/resources/icons/white/skirt+brim.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/resources/icons/white/split_object_SMALL.svg b/resources/icons/white/split_object_SMALL.svg new file mode 100644 index 000000000..4795cab51 --- /dev/null +++ b/resources/icons/white/split_object_SMALL.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/resources/icons/white/split_parts_SMALL.svg b/resources/icons/white/split_parts_SMALL.svg new file mode 100644 index 000000000..eba846c17 --- /dev/null +++ b/resources/icons/white/split_parts_SMALL.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/resources/icons/white/spool.svg b/resources/icons/white/spool.svg new file mode 100644 index 000000000..7c9fbab97 --- /dev/null +++ b/resources/icons/white/spool.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/support.svg b/resources/icons/white/support.svg new file mode 100644 index 000000000..52b7c6b40 --- /dev/null +++ b/resources/icons/white/support.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/support_blocker.svg b/resources/icons/white/support_blocker.svg new file mode 100644 index 000000000..17401e2ab --- /dev/null +++ b/resources/icons/white/support_blocker.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/support_enforcer.svg b/resources/icons/white/support_enforcer.svg new file mode 100644 index 000000000..0de2dc6a7 --- /dev/null +++ b/resources/icons/white/support_enforcer.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/resources/icons/white/test.svg b/resources/icons/white/test.svg new file mode 100644 index 000000000..639bbbde8 --- /dev/null +++ b/resources/icons/white/test.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/time.svg b/resources/icons/white/time.svg new file mode 100644 index 000000000..d014286b5 --- /dev/null +++ b/resources/icons/white/time.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/resources/icons/white/upload_queue.svg b/resources/icons/white/upload_queue.svg new file mode 100644 index 000000000..710e2be89 --- /dev/null +++ b/resources/icons/white/upload_queue.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/wrench.svg b/resources/icons/white/wrench.svg new file mode 100644 index 000000000..714c5a82a --- /dev/null +++ b/resources/icons/white/wrench.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/resources/icons/wrench_white.svg b/resources/icons/wrench_white.svg new file mode 100644 index 000000000..714c5a82a --- /dev/null +++ b/resources/icons/wrench_white.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index cbc85ef23..78d17a4f1 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -298,6 +298,16 @@ void MainFrame::on_dpi_changed(const wxRect &suggested_rect) this->Maximize(is_maximized); } +static std::string menu_icon(const std::string& icon_name) +{ +#ifdef __WXMSW__ + const std::string folder = "white\\"; +#else + const std::string folder = "white/"; +#endif + return wxGetApp().dark_mode_menus() ? folder+icon_name : icon_name; +} + void MainFrame::init_menubar() { #ifdef __APPLE__ @@ -308,41 +318,41 @@ void MainFrame::init_menubar() wxMenu* fileMenu = new wxMenu; { wxMenuItem* item_open = append_menu_item(fileMenu, wxID_ANY, _(L("&Open Project")) + dots + "\tCtrl+O", _(L("Open a project file")), - [this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "open"); + [this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, menu_icon("open")); wxMenuItem* item_save = append_menu_item(fileMenu, wxID_ANY, _(L("&Save Project")) + "\tCtrl+S", _(L("Save current project file")), - [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename())); }, "save"); + [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename())); }, menu_icon("save")); wxMenuItem* item_save_as = append_menu_item(fileMenu, wxID_ANY, _(L("Save Project &as")) + dots + "\tCtrl+Alt+S", _(L("Save current project file as")), - [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "save"); + [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, menu_icon("save")); fileMenu->AppendSeparator(); wxMenu* import_menu = new wxMenu(); wxMenuItem* item_import_model = append_menu_item(import_menu, wxID_ANY, _(L("Import STL/OBJ/AM&F/3MF")) + dots + "\tCtrl+I", _(L("Load a model")), - [this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, "import_plater"); + [this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, menu_icon("import_plater")); import_menu->AppendSeparator(); append_menu_item(import_menu, wxID_ANY, _(L("Import &Config")) + dots + "\tCtrl+L", _(L("Load exported configuration file")), - [this](wxCommandEvent&) { load_config_file(); }, "import_config"); + [this](wxCommandEvent&) { load_config_file(); }, menu_icon("import_config")); append_menu_item(import_menu, wxID_ANY, _(L("Import Config from &project")) + dots +"\tCtrl+Alt+L", _(L("Load configuration from project file")), - [this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, "import_config"); + [this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, menu_icon("import_config")); import_menu->AppendSeparator(); append_menu_item(import_menu, wxID_ANY, _(L("Import Config &Bundle")) + dots, _(L("Load presets from a bundle")), - [this](wxCommandEvent&) { load_configbundle(); }, "import_config_bundle"); + [this](wxCommandEvent&) { load_configbundle(); }, menu_icon("import_config_bundle")); append_submenu(fileMenu, import_menu, wxID_ANY, _(L("&Import")), ""); wxMenu* export_menu = new wxMenu(); wxMenuItem* item_export_gcode = append_menu_item(export_menu, wxID_ANY, _(L("Export &G-code")) + dots +"\tCtrl+G", _(L("Export current plate as G-code")), - [this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, "export_gcode"); + [this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, menu_icon("export_gcode")); m_changeable_menu_items.push_back(item_export_gcode); export_menu->AppendSeparator(); wxMenuItem* item_export_stl = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")), - [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "export_plater"); + [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater")); wxMenuItem* item_export_amf = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &AMF")) + dots, _(L("Export current plate as AMF")), - [this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, "export_plater"); + [this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, menu_icon("export_plater")); export_menu->AppendSeparator(); append_menu_item(export_menu, wxID_ANY, _(L("Export &Config")) +dots +"\tCtrl+E", _(L("Export current configuration to file")), - [this](wxCommandEvent&) { export_config(); }, "export_config"); + [this](wxCommandEvent&) { export_config(); }, menu_icon("export_config")); append_menu_item(export_menu, wxID_ANY, _(L("Export Config &Bundle")) + dots, _(L("Export all presets to file")), - [this](wxCommandEvent&) { export_configbundle(); }, "export_config_bundle"); + [this](wxCommandEvent&) { export_configbundle(); }, menu_icon("export_config_bundle")); append_submenu(fileMenu, export_menu, wxID_ANY, _(L("&Export")), ""); fileMenu->AppendSeparator(); @@ -370,10 +380,10 @@ void MainFrame::init_menubar() fileMenu->AppendSeparator(); #endif m_menu_item_reslice_now = append_menu_item(fileMenu, wxID_ANY, _(L("(Re)Slice &Now")) + "\tCtrl+R", _(L("Start new slicing process")), - [this](wxCommandEvent&) { reslice_now(); }, "re_slice"); + [this](wxCommandEvent&) { reslice_now(); }, menu_icon("re_slice")); fileMenu->AppendSeparator(); append_menu_item(fileMenu, wxID_ANY, _(L("&Repair STL file")) + dots, _(L("Automatically repair an STL file")), - [this](wxCommandEvent&) { repair_stl(); }, "wrench"); + [this](wxCommandEvent&) { repair_stl(); }, menu_icon("wrench")); fileMenu->AppendSeparator(); append_menu_item(fileMenu, wxID_EXIT, _(L("&Quit")), wxString::Format(_(L("Quit %s")), SLIC3R_APP_NAME), [this](wxCommandEvent&) { Close(false); }); @@ -413,16 +423,16 @@ void MainFrame::init_menubar() [this](wxCommandEvent&) { m_plater->select_all(); }, ""); editMenu->AppendSeparator(); wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + sep + hotkey_delete, _(L("Deletes the current selection")), - [this](wxCommandEvent&) { m_plater->remove_selected(); }, "remove_menu"); + [this](wxCommandEvent&) { m_plater->remove_selected(); }, menu_icon("remove_menu")); wxMenuItem* item_delete_all = append_menu_item(editMenu, wxID_ANY, _(L("Delete &all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + hotkey_delete, _(L("Deletes all objects")), - [this](wxCommandEvent&) { m_plater->reset(); }, "delete_all_menu"); + [this](wxCommandEvent&) { m_plater->reset(); }, menu_icon("delete_all_menu")); editMenu->AppendSeparator(); wxMenuItem* item_copy = append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "C", _(L("Copy selection to clipboard")), - [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); }, "copy_menu"); + [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); }, menu_icon("copy_menu")); wxMenuItem* item_paste = append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "V", _(L("Paste clipboard")), - [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, "paste_menu"); + [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, menu_icon("paste_menu")); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId()); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete()); }, item_delete_sel->GetId()); @@ -437,25 +447,25 @@ void MainFrame::init_menubar() size_t tab_offset = 0; if (m_plater) { append_menu_item(windowMenu, wxID_HIGHEST + 1, _(L("&Plater Tab")) + "\tCtrl+1", _(L("Show the plater")), - [this](wxCommandEvent&) { select_tab(0); }, "plater"); + [this](wxCommandEvent&) { select_tab(0); }, menu_icon("plater")); tab_offset += 1; } if (tab_offset > 0) { windowMenu->AppendSeparator(); } append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")), - [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog"); + [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, menu_icon("cog")); wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")), - [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool"); + [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, menu_icon("spool")); m_changeable_menu_items.push_back(item_material_tab); append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")), - [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer"); + [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, menu_icon("printer")); if (m_plater) { windowMenu->AppendSeparator(); wxMenuItem* item_3d = append_menu_item(windowMenu, wxID_HIGHEST + 5, _(L("3&D")) + "\tCtrl+5", _(L("Show the 3D editing view")), - [this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, "editor_menu"); + [this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, menu_icon("editor_menu")); wxMenuItem* item_preview = append_menu_item(windowMenu, wxID_HIGHEST + 6, _(L("Pre&view")) + "\tCtrl+6", _(L("Show the 3D slices preview")), - [this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, "preview_menu"); + [this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, menu_icon("preview_menu")); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_3d->GetId()); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_preview->GetId()); @@ -476,7 +486,7 @@ void MainFrame::init_menubar() windowMenu->AppendSeparator(); append_menu_item(windowMenu, wxID_ANY, _(L("Print &Host Upload Queue")) + "\tCtrl+J", _(L("Display the Print Host Upload Queue window")), - [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue"); + [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, menu_icon("upload_queue")); } // View menu @@ -568,7 +578,7 @@ void MainFrame::update_menubar() m_changeable_menu_items[miExport] ->SetItemLabel((is_fff ? _(L("Export &G-code")) : _(L("Export")) ) + dots + "\tCtrl+G"); m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3"); - m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, is_fff ? "spool": "resin")); + m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, menu_icon(is_fff ? "spool": "resin"))); } // To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG". From 4a5992ba6eca8e1ddb1e576a009660c80b910d1a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 30 Apr 2019 15:43:19 +0200 Subject: [PATCH 26/29] Top toolbar use layers_white.svg icon for layers editing --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d02878a1a..3c7365d15 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3377,7 +3377,7 @@ bool GLCanvas3D::_init_toolbar() item.name = "layersediting"; #if ENABLE_SVG_ICONS - item.icon_filename = "layers.svg"; + item.icon_filename = "layers_white.svg"; #endif // ENABLE_SVG_ICONS item.tooltip = GUI::L_str("Layers editing"); item.sprite_id = 10; From a3385278e5e892e644a02a288c1cf9c8bd296d00 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 2 May 2019 13:46:39 +0200 Subject: [PATCH 27/29] Export to STL of SLA supports and pad --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 44 ++++++++++++++++------ src/slic3r/GUI/MainFrame.hpp | 1 + src/slic3r/GUI/Plater.cpp | 61 ++++++++++++++++++++++++++++++- src/slic3r/GUI/Plater.hpp | 2 +- 5 files changed, 95 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index f9df2649c..833cd712e 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1147,7 +1147,7 @@ void ObjectList::append_menu_item_fix_through_netfabb(wxMenu* menu) void ObjectList::append_menu_item_export_stl(wxMenu* menu) const { append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, "", - [](wxCommandEvent&) { wxGetApp().plater()->export_stl(true); }, "", menu); + [](wxCommandEvent&) { wxGetApp().plater()->export_stl(false, true); }, "", menu); menu->AppendSeparator(); } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 78d17a4f1..72843f815 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -14,6 +14,7 @@ #include "libslic3r/Print.hpp" #include "libslic3r/Polygon.hpp" +#include "libslic3r/SLAPrint.hpp" #include "Tab.hpp" #include "PresetBundle.hpp" @@ -205,12 +206,30 @@ void MainFrame::add_created_tab(Tab* panel) bool MainFrame::can_save() const { - return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; + return (m_plater != nullptr) && !m_plater->model().objects.empty(); } bool MainFrame::can_export_model() const { - return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; + return (m_plater != nullptr) && !m_plater->model().objects.empty(); +} + +bool MainFrame::can_export_supports() const +{ + if ((m_plater == nullptr) || (m_plater->printer_technology() != ptSLA) || m_plater->model().objects.empty()) + return false; + + bool can_export = false; + const PrintObjects& objects = m_plater->sla_print().objects(); + for (const SLAPrintObject* object : objects) + { + if (object->has_mesh(slaposBasePool) || object->has_mesh(slaposSupportTree)) + { + can_export = true; + break; + } + } + return can_export; } bool MainFrame::can_export_gcode() const @@ -243,17 +262,17 @@ bool MainFrame::can_change_view() const bool MainFrame::can_select() const { - return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; + return (m_plater != nullptr) && !m_plater->model().objects.empty(); } bool MainFrame::can_delete() const { - return (m_plater != nullptr) ? !m_plater->is_selection_empty() : false; + return (m_plater != nullptr) && !m_plater->is_selection_empty(); } bool MainFrame::can_delete_all() const { - return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; + return (m_plater != nullptr) && !m_plater->model().objects.empty(); } void MainFrame::on_dpi_changed(const wxRect &suggested_rect) @@ -346,6 +365,8 @@ void MainFrame::init_menubar() export_menu->AppendSeparator(); wxMenuItem* item_export_stl = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater")); + wxMenuItem* item_export_stl_sla = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as STL including supports")) + dots, _(L("Export current plate as STL including supports")), + [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, menu_icon("export_plater")); wxMenuItem* item_export_amf = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &AMF")) + dots, _(L("Export current plate as AMF")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, menu_icon("export_plater")); export_menu->AppendSeparator(); @@ -389,13 +410,14 @@ void MainFrame::init_menubar() [this](wxCommandEvent&) { Close(false); }); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater != nullptr); }, item_open->GetId()); - Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_save()); }, item_save->GetId()); - Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_save()); }, item_save_as->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_save()); }, item_save->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_save()); }, item_save_as->GetId()); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater != nullptr); }, item_import_model->GetId()); - Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_gcode()); }, item_export_gcode->GetId()); - Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_model()); }, item_export_stl->GetId()); - Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_model()); }, item_export_amf->GetId()); - Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_slice()); }, m_menu_item_reslice_now->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_export_gcode()); }, item_export_gcode->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_export_model()); }, item_export_stl->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_export_supports()); }, item_export_stl_sla->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_export_model()); }, item_export_amf->GetId()); + Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_slice()); }, m_menu_item_reslice_now->GetId()); } #ifdef _MSC_VER diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 13bf07922..f3d582681 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -63,6 +63,7 @@ class MainFrame : public DPIFrame bool can_save() const; bool can_export_model() const; + bool can_export_supports() const; bool can_export_gcode() const; bool can_slice() const; bool can_change_view() const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2195471da..4ec560274 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2925,7 +2925,7 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ [this](wxCommandEvent&) { reload_from_disk(); }); append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")), - [this](wxCommandEvent&) { q->export_stl(true); }); + [this](wxCommandEvent&) { q->export_stl(false, true); }); menu->AppendSeparator(); } @@ -3431,7 +3431,7 @@ void Plater::export_gcode() p->export_gcode(std::move(output_path), PrintHostJob()); } -void Plater::export_stl(bool selection_only) +void Plater::export_stl(bool extended, bool selection_only) { if (p->model.objects.empty()) { return; } @@ -3466,8 +3466,65 @@ void Plater::export_stl(bool selection_only) } } else + { mesh = p->model.mesh(); + if (extended && (p->printer_technology == ptSLA)) + { + const PrintObjects& objects = p->sla_print.objects(); + for (const SLAPrintObject* object : objects) + { + const ModelObject* model_object = object->model_object(); + Transform3d mesh_trafo_inv = object->trafo().inverse(); + bool is_left_handed = object->is_left_handed(); + + TriangleMesh pad_mesh; + bool has_pad_mesh = object->has_mesh(slaposBasePool); + if (has_pad_mesh) + { + pad_mesh = object->get_mesh(slaposBasePool); + pad_mesh.transform(mesh_trafo_inv); + } + + TriangleMesh supports_mesh; + bool has_supports_mesh = object->has_mesh(slaposSupportTree); + if (has_supports_mesh) + { + supports_mesh = object->get_mesh(slaposSupportTree); + supports_mesh.transform(mesh_trafo_inv); + } + + const std::vector& obj_instances = object->instances(); + for (const SLAPrintObject::Instance& obj_instance : obj_instances) + { + auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(), + [&obj_instance](const ModelInstance *mi) { return mi->id() == obj_instance.instance_id; }); + assert(it != model_object->instances.end()); + + if (it != model_object->instances.end()) + { + int instance_idx = it - model_object->instances.begin(); + const Transform3d& inst_transform = object->model_object()->instances[instance_idx]->get_transformation().get_matrix(); + + if (has_pad_mesh) + { + TriangleMesh inst_pad_mesh = pad_mesh; + inst_pad_mesh.transform(inst_transform, is_left_handed); + mesh.merge(inst_pad_mesh); + } + + if (has_supports_mesh) + { + TriangleMesh inst_supports_mesh = supports_mesh; + inst_supports_mesh.transform(inst_transform, is_left_handed); + mesh.merge(inst_supports_mesh); + } + } + } + } + } + } + Slic3r::store_stl(path_u8.c_str(), &mesh, true); p->statusbar()->set_status_text(wxString::Format(_(L("STL file exported to %s")), path)); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index bedc31b35..326a4507e 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -163,7 +163,7 @@ public: void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); void export_gcode(); - void export_stl(bool selection_only = false); + void export_stl(bool extended = false, bool selection_only = false); void export_amf(); void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); void reslice(); From 47f27d20f196df979c0891fbae2fed83d0ab4f8b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 2 May 2019 13:52:13 +0200 Subject: [PATCH 28/29] Added confirmation dialog for Delete All command --- src/slic3r/GUI/MainFrame.cpp | 4 ++-- src/slic3r/GUI/Plater.cpp | 7 ++++++- src/slic3r/GUI/Plater.hpp | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 72843f815..12e59c6f5 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -442,12 +442,12 @@ void MainFrame::init_menubar() wxString hotkey_delete = "Del"; #endif wxMenuItem* item_select_all = append_menu_item(editMenu, wxID_ANY, _(L("&Select all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "A", _(L("Selects all objects")), - [this](wxCommandEvent&) { m_plater->select_all(); }, ""); + [this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->select_all(); }, ""); editMenu->AppendSeparator(); wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + sep + hotkey_delete, _(L("Deletes the current selection")), [this](wxCommandEvent&) { m_plater->remove_selected(); }, menu_icon("remove_menu")); wxMenuItem* item_delete_all = append_menu_item(editMenu, wxID_ANY, _(L("Delete &all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + hotkey_delete, _(L("Deletes all objects")), - [this](wxCommandEvent&) { m_plater->reset(); }, menu_icon("delete_all_menu")); + [this](wxCommandEvent&) { m_plater->reset_with_confirm(); }, menu_icon("delete_all_menu")); editMenu->AppendSeparator(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 4ec560274..48ffaedc9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1447,7 +1447,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) // 3DScene/Toolbar: view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this); view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); }); - view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [this](SimpleEvent&) { reset(); }); + view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [q](SimpleEvent&) { q->reset_with_confirm(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_ARRANGE, [this](SimpleEvent&) { arrange(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_COPY, [q](SimpleEvent&) { q->copy_selection_to_clipboard(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_PASTE, [q](SimpleEvent&) { q->paste_from_clipboard(); }); @@ -3282,6 +3282,11 @@ void Plater::select_all() { p->select_all(); } void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } void Plater::reset() { p->reset(); } +void Plater::reset_with_confirm() +{ + if (wxMessageDialog((wxWindow*)this, _(L("All objects will be removed, continue ?")), _(L("Delete all")), wxYES_NO | wxYES_DEFAULT | wxCENTRE).ShowModal() == wxID_YES) + reset(); +} void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_model(obj_idx); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 326a4507e..5118fdd6c 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -153,6 +153,7 @@ public: void select_all(); void remove(size_t obj_idx); void reset(); + void reset_with_confirm(); void delete_object_from_model(size_t obj_idx); void remove_selected(); void increase_instances(size_t num = 1); From bf30ec439f0a92366923e777f8d2d58a12fb2a6d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 3 May 2019 11:43:48 +0200 Subject: [PATCH 29/29] Fixed file extension when using option --export-amf in command line --- src/slic3r.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r.cpp b/src/slic3r.cpp index c3e69a189..e8f92e66d 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -628,7 +628,7 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co { std::string ext; switch (format) { - case IO::AMF: ext = ".amf"; break; + case IO::AMF: ext = ".zip.amf"; break; case IO::OBJ: ext = ".obj"; break; case IO::STL: ext = ".stl"; break; case IO::TMF: ext = ".3mf"; break;