diff --git a/src/libslic3r/SLA/SLAAutoSupports.cpp b/src/libslic3r/SLA/SLAAutoSupports.cpp index 4389fd71f2..38add28eec 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.cpp +++ b/src/libslic3r/SLA/SLAAutoSupports.cpp @@ -395,7 +395,7 @@ void SLAAutoSupports::uniformly_cover(const ExPolygon& island, Structure& struct assert(! poisson_samples.empty()); for (const Vec2f &pt : poisson_samples) { - m_output.emplace_back(float(pt(0)), float(pt(1)), structure.height, 0.4f, is_new_island); + m_output.emplace_back(float(pt(0)), float(pt(1)), structure.height, 0.2f, is_new_island); structure.supports_force += m_config.support_force; } } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 63dcd950b8..16811087eb 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3430,24 +3430,18 @@ void GLCanvas3D::Gizmos::set_sla_support_data(ModelObject* model_object, const G reinterpret_cast(it->second)->set_sla_support_data(model_object, selection); } -void GLCanvas3D::Gizmos::clicked_on_object(const Vec2d& mouse_position) + +// Returns true if the gizmo used the event to do something, false otherwise. +bool GLCanvas3D::Gizmos::mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down) { if (!m_enabled) - return; + return false; GizmosMap::const_iterator it = m_gizmos.find(SlaSupports); if (it != m_gizmos.end()) - reinterpret_cast(it->second)->clicked_on_object(mouse_position); -} + return reinterpret_cast(it->second)->mouse_event(action, mouse_position, shift_down); -void GLCanvas3D::Gizmos::delete_current_grabber(bool delete_all) -{ - if (!m_enabled) - return; - - GizmosMap::const_iterator it = m_gizmos.find(SlaSupports); - if (it != m_gizmos.end()) - reinterpret_cast(it->second)->delete_current_point(delete_all); + return false; } void GLCanvas3D::Gizmos::render_current_gizmo(const GLCanvas3D::Selection& selection) const @@ -5114,6 +5108,7 @@ void GLCanvas3D::bind_event_handlers() m_canvas->Bind(wxEVT_SIZE, &GLCanvas3D::on_size, this); m_canvas->Bind(wxEVT_IDLE, &GLCanvas3D::on_idle, this); m_canvas->Bind(wxEVT_CHAR, &GLCanvas3D::on_char, this); + m_canvas->Bind(wxEVT_KEY_UP, &GLCanvas3D::on_key_up, this); m_canvas->Bind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this); m_canvas->Bind(wxEVT_TIMER, &GLCanvas3D::on_timer, this); m_canvas->Bind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this); @@ -5139,6 +5134,7 @@ void GLCanvas3D::unbind_event_handlers() m_canvas->Unbind(wxEVT_SIZE, &GLCanvas3D::on_size, this); m_canvas->Unbind(wxEVT_IDLE, &GLCanvas3D::on_idle, this); m_canvas->Unbind(wxEVT_CHAR, &GLCanvas3D::on_char, this); + m_canvas->Unbind(wxEVT_KEY_UP, &GLCanvas3D::on_key_up, this); m_canvas->Unbind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this); m_canvas->Unbind(wxEVT_TIMER, &GLCanvas3D::on_timer, this); m_canvas->Unbind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this); @@ -5182,7 +5178,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) switch (keyCode) { case 'a': case 'A': - case WXK_CONTROL_A: post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); break; + case WXK_CONTROL_A: + if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::SelectAll)) // Sla gizmo selects all support points + m_dirty = true; + else + post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); + break; #ifdef __APPLE__ case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead. #else /* __APPLE__ */ @@ -5203,7 +5204,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) #else /* __APPLE__ */ case WXK_DELETE: #endif /* __APPLE__ */ - post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE)); break; + if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.mouse_event(SLAGizmoEventType::Delete)) + m_dirty = true; + else + post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE)); + break; + case '0': { select_view("iso"); break; } case '1': { select_view("top"); break; } case '2': { select_view("bottom"); break; } @@ -5240,6 +5246,16 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) } } +void GLCanvas3D::on_key_up(wxKeyEvent& evt) +{ + // see include/wx/defs.h enum wxKeyCode + int keyCode = evt.GetKeyCode(); + + // shift has been just released - SLA gizmo might want to close rectangular selection. + if (m_gizmos.get_current_type() == Gizmos::SlaSupports && keyCode == WXK_SHIFT && m_gizmos.mouse_event(SLAGizmoEventType::ShiftUp)) + m_dirty = true; +} + void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) { // Ignore the wheel events if the middle button is pressed. @@ -5380,22 +5396,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } } -#if !ENABLE_IMGUI - else if ((m_gizmos.get_current_type() == Gizmos::SlaSupports) && gizmo_reset_rect_contains(*this, pos(0), pos(1))) - { - if (evt.LeftDown()) - { - m_gizmos.delete_current_grabber(true); - m_dirty = true; - } - } -#endif // not ENABLE_IMGUI else if (!m_selection.is_empty() && gizmos_overlay_contains_mouse) { m_gizmos.update_on_off_state(*this, m_mouse.position, m_selection); _update_gizmos_data(); m_dirty = true; } + else if (evt.LeftDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && evt.ShiftDown() && m_gizmos.mouse_event(SLAGizmoEventType::LeftDown, Vec2d(pos(0), pos(1)), evt.ShiftDown())) + { + // the gizmo got the event and took some action, there is no need to do anything more + } else if (evt.LeftDown() && !m_selection.is_empty() && m_gizmos.grabber_contains_mouse()) { _update_gizmos_data(); @@ -5411,10 +5421,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } - else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse() && evt.RightDown()) { + /*else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse() && evt.RightDown()) { if (m_gizmos.get_current_type() == Gizmos::SlaSupports) m_gizmos.delete_current_grabber(); - } + }*/ else if (view_toolbar_contains_mouse != -1) { if (m_view_toolbar != nullptr) @@ -5519,7 +5529,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } } } - else if (evt.Dragging() && evt.LeftIsDown() && !gizmos_overlay_contains_mouse && (m_layers_editing.state == LayersEditing::Unknown) && (m_mouse.drag.move_volume_idx != -1)) + else if (evt.Dragging() && evt.LeftIsDown() && !gizmos_overlay_contains_mouse && (m_layers_editing.state == LayersEditing::Unknown) + && (m_mouse.drag.move_volume_idx != -1) && m_gizmos.get_current_type() != Gizmos::SlaSupports /* don't allow dragging objects with the Sla gizmo on */) { #if ENABLE_MOVE_MIN_THRESHOLD if (!m_mouse.drag.move_requires_threshold) @@ -5579,6 +5590,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } + else if (evt.Dragging() && m_gizmos.get_current_type() == Gizmos::SlaSupports && evt.ShiftDown() && m_gizmos.mouse_event(SLAGizmoEventType::Dragging, Vec2d(pos(0), pos(1)), evt.ShiftDown())) + { + // the gizmo got the event and took some action, no need to do anything more here + m_dirty = true; + } else if (evt.Dragging() && !gizmos_overlay_contains_mouse) { m_mouse.dragging = true; @@ -5634,6 +5650,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) _stop_timer(); m_layers_editing.accept_changes(*this); } + else if (evt.LeftUp() && m_gizmos.get_current_type() == Gizmos::SlaSupports && !m_gizmos.is_dragging() + && !m_mouse.dragging && m_gizmos.mouse_event(SLAGizmoEventType::LeftUp, Vec2d(pos(0), pos(1)), evt.ShiftDown())) + { + // the gizmo got the event and took some action, no need to do anything more + } else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging) { m_regenerate_volumes = false; @@ -5643,16 +5664,11 @@ 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_gizmos.get_current_type() == Gizmos::SlaSupports && m_hover_volume_id != -1) + else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() + && !is_layers_editing_enabled() && m_gizmos.get_current_type() != Gizmos::SlaSupports) { - int id = m_selection.get_object_idx(); + // SLA gizmo cannot be deselected by clicking in canvas area to avoid inadvertent unselection and losing manual changes - if ((id != -1) && (m_model != nullptr)) { - m_gizmos.clicked_on_object(Vec2d(pos(0), pos(1))); - } - } - else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled()) - { // deselect and propagate event through callback if (!evt.ShiftDown() && m_picking_enabled && !m_toolbar_action_running && !m_mouse.ignore_up_event) { @@ -5685,10 +5701,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) do_rotate(); break; } - case Gizmos::SlaSupports: - // End of mouse dragging, update the SLAPrint/SLAPrintObjects with the new support points. - post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - break; default: break; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 9f341083be..ff69f1ef88 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -132,6 +132,17 @@ wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent); +// this describes events being passed from GLCanvas3D to SlaSupport gizmo +enum class SLAGizmoEventType { + LeftDown = 1, + LeftUp, + Dragging, + Delete, + SelectAll, + ShiftUp +}; + + class GLCanvas3D { struct GCodePreviewVolumeIndex @@ -789,7 +800,7 @@ private: void set_flattening_data(const ModelObject* model_object); void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection); - void clicked_on_object(const Vec2d& mouse_position); + bool mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false); void delete_current_grabber(bool delete_all = false); void render_current_gizmo(const Selection& selection) const; @@ -1050,6 +1061,7 @@ public: void on_size(wxSizeEvent& evt); void on_idle(wxIdleEvent& evt); void on_char(wxKeyEvent& evt); + void on_key_up(wxKeyEvent& evt); void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); void on_mouse(wxMouseEvent& evt); diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index eecf1de2c2..8262587144 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1816,13 +1816,54 @@ void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const ::glEnable(GL_DEPTH_TEST); render_points(selection, false); + render_selection_rectangle(); #if !ENABLE_IMGUI render_tooltip_texture(); #endif // not ENABLE_IMGUI + ::glDisable(GL_BLEND); } +void GLGizmoSlaSupports::render_selection_rectangle() const +{ + if (!m_selection_rectangle_active) + return; + + ::glLineWidth(1.5f); + float render_color[3] = {1.f, 0.f, 0.f}; + ::glColor3fv(render_color); + + ::glPushAttrib(GL_TRANSFORM_BIT); // remember current MatrixMode + + ::glMatrixMode(GL_MODELVIEW); // cache modelview matrix and set to identity + ::glPushMatrix(); + ::glLoadIdentity(); + + ::glMatrixMode(GL_PROJECTION); // cache projection matrix and set to identity + ::glPushMatrix(); + ::glLoadIdentity(); + + ::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): + ::glPushAttrib(GL_ENABLE_BIT); + ::glLineStipple(4, 0xAAAA); + ::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); + ::glEnd(); + ::glPopAttrib(); + + ::glPopMatrix(); // restore former projection matrix + ::glMatrixMode(GL_MODELVIEW); + ::glPopMatrix(); // restore former modelview matrix + ::glPopAttrib(); // restore former MatrixMode +} void GLGizmoSlaSupports::on_render_for_picking(const GLCanvas3D::Selection& selection) const { @@ -1854,7 +1895,8 @@ void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, b float render_color[3]; for (int i = 0; i < (int)m_editing_mode_cache.size(); ++i) { - const Vec3f& point_pos = m_editing_mode_cache[i].pos; + const Vec3f& point_pos = m_editing_mode_cache[i].first.pos; + const bool point_selected = m_editing_mode_cache[i].second; // first precalculate the grabber position in world coordinates, so that the grabber // is not scaled with the object (as it would be if rendered with current gl matrix). Eigen::Matrix glmatrix; @@ -1878,11 +1920,11 @@ void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, b render_color[2] = picking_color_component(i); } else { // normal rendering - bool supports_new_island = m_lock_unique_islands && m_editing_mode_cache[i].is_new_island; + bool supports_new_island = m_lock_unique_islands && m_editing_mode_cache[i].first.is_new_island; if (m_editing_mode) { - render_color[0] = supports_new_island ? 0.f : 1.f; - render_color[1] = 0.f; - render_color[2] = supports_new_island ? 1.f : 0.f; + render_color[0] = point_selected ? 0.f : (supports_new_island ? 0.f : 1.f); + render_color[1] = point_selected ? 1.f : 0.f; + render_color[2] = point_selected ? 0.f : (supports_new_island ? 1.f : 0.f); } else for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f; @@ -1893,7 +1935,7 @@ void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, b ::glPushMatrix(); ::glLoadIdentity(); ::glTranslated(grabber_world_position(0), grabber_world_position(1), grabber_world_position(2) + z_shift); - ::gluSphere(m_quadric, m_editing_mode_cache[i].head_front_radius, 64, 36); + ::gluSphere(m_quadric, m_editing_mode_cache[i].first.head_front_radius, 64, 36); ::glPopMatrix(); } @@ -1941,7 +1983,9 @@ void GLGizmoSlaSupports::update_mesh() m_AABB.init(m_V, m_F); // we'll now reload support points (selection might have changed): - m_editing_mode_cache = m_model_object->sla_support_points; + m_editing_mode_cache.clear(); + for (const sla::SupportPoint& point : m_model_object->sla_support_points) + m_editing_mode_cache.push_back(std::make_pair(point, false)); } Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) @@ -1984,70 +2028,144 @@ Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) return bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2)); } -void GLGizmoSlaSupports::clicked_on_object(const Vec2d& mouse_position) +// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. +// The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is +// aware that the event was reacted to and stops trying to make different sense of it. If the gizmo +// concludes that the event was not intended for it, it should return false. +bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down) +{ + if (!m_editing_mode) + return false; + + // left down - show the selection rectangle: + if (action == SLAGizmoEventType::LeftDown && shift_down) { + if (m_hover_id == -1) { + m_selection_rectangle_active = true; + 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(); + } + else + m_editing_mode_cache[m_hover_id].second = true; + + return true; + } + + // dragging the selection rectangle: + if (action == SLAGizmoEventType::Dragging && m_selection_rectangle_active) { + m_selection_rectangle_end_corner = mouse_position; + return true; + } + + // mouse up without selection rectangle - place point on the mesh: + if (action == SLAGizmoEventType::LeftUp && !m_selection_rectangle_active && !shift_down) { + if (m_ignore_up_event) { + m_ignore_up_event = false; + return false; + } + + int instance_id = m_parent.get_selection().get_instance_idx(); + if (m_old_instance_id != instance_id) + { + bool something_selected = (m_old_instance_id != -1); + m_old_instance_id = instance_id; + if (something_selected) + return false; + } + if (instance_id == -1) + return false; + + // Regardless of whether the user clicked the object or not, we will unselect all points: + for (unsigned int i=0; iinstances[m_active_instance]->get_transformation().get_matrix(); + GLint viewport[4]; + ::glGetIntegerv(GL_VIEWPORT, viewport); + GLdouble modelview_matrix[16]; + ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix); + GLdouble projection_matrix[16]; + ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix); + + const GLCanvas3D::Selection& selection = m_parent.get_selection(); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + double z_offset = volume->get_sla_shift_z(); + + // 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())}); + + for (std::pair& point_and_selection : m_editing_mode_cache) { + const sla::SupportPoint& support_point = point_and_selection.first; + Vec3f pos = instance_matrix.cast() * support_point.pos; + pos(2) += z_offset; + GLdouble out_x, out_y, out_z; + ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z); + out_y = m_canvas_height - out_y; + + if (rectangle.contains(Point(out_x, out_y))) + point_and_selection.second = true; + } + m_selection_rectangle_active = false; + return true; + } + + if (action == SLAGizmoEventType::Delete) { + // delete key pressed + delete_selected_points(); + return true; + } + + if (action == SLAGizmoEventType::SelectAll) { + for (auto& point_and_selection : m_editing_mode_cache) + point_and_selection.second = true; + return true; + } + + return false; +} + +void GLGizmoSlaSupports::delete_selected_points() { if (!m_editing_mode) return; - int instance_id = m_parent.get_selection().get_instance_idx(); - if (m_old_instance_id != instance_id) - { - bool something_selected = (m_old_instance_id != -1); - m_old_instance_id = instance_id; - if (something_selected) - return; + for (unsigned int idx=0; idxreslice(); } - if (instance_id == -1) - return; - Vec3f new_pos; - try { - new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case - } - catch (...) { return; } - - m_editing_mode_cache.emplace_back(new_pos, m_new_point_head_diameter, false); - - // This should trigger the support generation - // wxGetApp().plater()->reslice(); - - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); -} - -void GLGizmoSlaSupports::delete_current_point(bool delete_all) -{ - if (!m_editing_mode && !delete_all) - return; - - if (delete_all) { - m_editing_mode_cache.clear(); - - // This should trigger the support generation - // wxGetApp().plater()->reslice(); - } - else - if (m_hover_id != -1) { - if (!m_editing_mode_cache[m_hover_id].is_new_island || !m_lock_unique_islands) { - m_editing_mode_cache.erase(m_editing_mode_cache.begin() + m_hover_id); - m_hover_id = -1; - - // This should trigger the support generation - // wxGetApp().plater()->reslice(); - } - } //m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } void GLGizmoSlaSupports::on_update(const UpdateData& data, const GLCanvas3D::Selection& selection) { - if (m_editing_mode && m_hover_id != -1 && data.mouse_pos && (!m_editing_mode_cache[m_hover_id].is_new_island || !m_lock_unique_islands)) { + if (m_editing_mode && m_hover_id != -1 && data.mouse_pos && (!m_editing_mode_cache[m_hover_id].first.is_new_island || !m_lock_unique_islands)) { Vec3f new_pos; try { new_pos = unproject_on_mesh(Vec2d((*data.mouse_pos)(0), (*data.mouse_pos)(1))); } catch (...) { return; } - m_editing_mode_cache[m_hover_id].pos = new_pos; - m_editing_mode_cache[m_hover_id].is_new_island = false; + m_editing_mode_cache[m_hover_id].first.pos = new_pos; + m_editing_mode_cache[m_hover_id].first.is_new_island = false; // Do not update immediately, wait until the mouse is released. // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } @@ -2097,29 +2215,13 @@ RENDER_AGAIN: ImGui::PushItemWidth(100.0f); - /*bool force_refresh = m_editing_mode; - if (m_imgui->radio_button(_(L("Automatic")), !m_editing_mode)) - m_editing_mode = false; - ImGui::SameLine(); - if (m_imgui->radio_button(_(L("Manual")), m_editing_mode)) - m_editing_mode = true; - force_refresh = force_refresh != m_editing_mode; - - if (force_refresh) { // mode has just changed! - if (m_editing_mode) - m_editing_mode_cache = m_model_object->sla_support_points; - else - m_model_object->sla_support_points = m_editing_mode_cache; - } - */ - bool force_refresh = false; - bool remove_all_points = false; + bool remove_selected = false; bool old_editing_state = m_editing_mode; if (m_editing_mode) { m_imgui->text(_(L("Left mouse click - add point"))); - m_imgui->text(_(L("Right mouse click - remove point"))); + m_imgui->text(_(L("Shift + Left (+ drag) - select point(s)"))); m_imgui->text(" "); // vertical gap std::vector options = {"0.2", "0.4", "0.6", "0.8", "1.0"}; @@ -2127,28 +2229,38 @@ RENDER_AGAIN: ss << std::setprecision(1) << m_new_point_head_diameter; wxString str = ss.str(); m_imgui->combo(_(L("Head diameter")), options, str); - force_refresh |= std::abs(atof(str) - m_new_point_head_diameter) > 0.001; - m_new_point_head_diameter = atof(str); + float current_number = atof(str); + if (std::abs(current_number - m_new_point_head_diameter) > 0.001) { + force_refresh = true; + m_new_point_head_diameter = current_number; + for (auto& point_and_selection : m_editing_mode_cache) + if (point_and_selection.second) + point_and_selection.first.head_front_radius = current_number / 2.f; + } bool changed = m_lock_unique_islands; m_imgui->checkbox(_(L("Lock supports under new islands")), m_lock_unique_islands); force_refresh |= changed != m_lock_unique_islands; - remove_all_points = m_imgui->button(_(L("Remove all points")) + (m_model_object == nullptr ? "" : " (" + std::to_string(m_editing_mode_cache.size())+")")); + remove_selected = m_imgui->button(_(L("Remove selected points"))); m_imgui->text(" "); // vertical gap bool apply_changes = m_imgui->button(_(L("Apply changes"))); if (apply_changes) { - m_model_object->sla_support_points = m_editing_mode_cache; + m_model_object->sla_support_points.clear(); + for (const std::pair& point_and_selection : m_editing_mode_cache) + m_model_object->sla_support_points.push_back(point_and_selection.first); m_editing_mode = false; force_refresh = true; m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } ImGui::SameLine(); - bool discard_changes = m_imgui->button(_(L("Cancel"))); + bool discard_changes = m_imgui->button(_(L("Discard changes"))); if (discard_changes) { - m_editing_mode_cache = m_model_object->sla_support_points; + m_editing_mode_cache.clear(); + for (const sla::SupportPoint& point : m_model_object->sla_support_points) + m_editing_mode_cache.push_back(std::make_pair(point, false)); m_editing_mode = false; force_refresh = true; } @@ -2161,17 +2273,60 @@ RENDER_AGAIN: m_imgui->text(""); - bool generate =m_imgui->button(_(L("Auto-generate points"))); - force_refresh |= generate; + bool generate = m_imgui->button(_(L("Auto-generate points"))); + if (generate) { - m_model_object->sla_support_points.clear(); - m_editing_mode_cache.clear(); - wxGetApp().plater()->reslice(); +#if SLAGIZMO_IMGUI_MODAL + ImGui::OpenPopup(_(L("Warning"))); + m_show_modal = true; + force_refresh = true; +#else + wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L( + "Autogeneration will erase all currently assigned points.\n\n" + "Are you sure you want to do it?\n" + )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO); + if (dlg.ShowModal() == wxID_YES) { + m_model_object->sla_support_points.clear(); + m_editing_mode_cache.clear(); + wxGetApp().plater()->reslice(); + } +#endif } +#if SLAGIZMO_IMGUI_MODAL + if (m_show_modal) { + if (ImGui::BeginPopupModal(_(L("Warning")), &m_show_modal/*, ImGuiWindowFlags_NoDecoration*/)) + { + m_imgui->text(_(L("Autogeneration will erase all currently assigned points."))); + m_imgui->text(""); + m_imgui->text(_(L("Are you sure you want to do it?"))); + + if (m_imgui->button(_(L("Continue")))) + { + ImGui::CloseCurrentPopup(); + m_show_modal = false; + + m_model_object->sla_support_points.clear(); + m_editing_mode_cache.clear(); + wxGetApp().plater()->reslice(); + } + ImGui::SameLine(); + if (m_imgui->button(_(L("Cancel")))) { + ImGui::CloseCurrentPopup(); + m_show_modal = false; + } + ImGui::EndPopup(); + } + + if (!m_show_modal) + force_refresh = true; + } +#endif ImGui::SameLine(); bool editing_clicked = m_imgui->button("Editing"); if (editing_clicked) { - m_editing_mode_cache = m_model_object->sla_support_points; + m_editing_mode_cache.clear(); + for (const sla::SupportPoint& point : m_model_object->sla_support_points) + m_editing_mode_cache.push_back(std::make_pair(point, false)); m_editing_mode = true; } } @@ -2184,10 +2339,10 @@ RENDER_AGAIN: } - if (remove_all_points) { + if (remove_selected) { force_refresh = false; m_parent.reload_scene(true); - delete_current_point(true); + delete_selected_points(); if (first_run) { first_run = false; goto RENDER_AGAIN; @@ -2228,9 +2383,22 @@ void GLGizmoSlaSupports::on_set_state() if (m_state == Off) { m_parent.toggle_model_objects_visibility(true); m_editing_mode = false; +#if SLAGIZMO_IMGUI_MODAL + if (m_show_modal) { + m_show_modal = false; + on_render_input_window(0,0,m_parent.get_selection()); // this is necessary to allow ImGui to terminate the modal dialog correctly + } +#endif } } +void GLGizmoSlaSupports::on_start_dragging(const GLCanvas3D::Selection& selection) +{ + if (m_hover_id != -1) + for (unsigned int i=0;i m_editing_mode_cache; + std::vector> m_editing_mode_cache; // a support point and whether it is currently selected + + bool m_selection_rectangle_active = false; + Vec2d m_selection_rectangle_start_corner; + Vec2d m_selection_rectangle_end_corner; + bool m_ignore_up_event = false; +#if SLAGIZMO_IMGUI_MODAL + bool m_show_modal = false; +#endif + int m_canvas_width; + int m_canvas_height; protected: void on_set_state() override; + void on_start_dragging(const GLCanvas3D::Selection& selection) override; #if ENABLE_IMGUI virtual void on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection) override;