diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 98d7b43a1..799d6d632 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3677,7 +3677,40 @@ GLCanvas3D::WarningTexture::WarningTexture() { } -bool GLCanvas3D::WarningTexture::generate(const std::string& msg, const GLCanvas3D& canvas) +void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool state, const GLCanvas3D& canvas) +{ + auto it = std::find(m_warnings.begin(), m_warnings.end(), warning); + + if (state) { + if (it != m_warnings.end()) // this warning is already set to be shown + return; + + m_warnings.push_back(warning); + std::sort(m_warnings.begin(), m_warnings.end()); + } + else { + if (it == m_warnings.end()) // deactivating something that is not active is an easy task + return; + + m_warnings.erase(it); + if (m_warnings.empty()) { // nothing remains to be shown + reset(); + return; + } + } + + // Look at the end of our vector and generate proper texture. + std::string text; + switch (m_warnings.back()) { + case ObjectOutside : text = L("Detected object outside print volume"); break; + case ToolpathOutside : text = L("Detected toolpath outside print volume"); break; + case SomethingNotShown : text = L("Some objects are not visible when editing supports"); break; + } + + _generate(text, canvas); // GUI::GLTexture::reset() is called at the beginning of generate(...) +} + +bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanvas3D& canvas) { reset(); @@ -3750,6 +3783,9 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg, const GLCanvas void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const { + if (m_warnings.empty()) + return; + if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { ::glDisable(GL_DEPTH_TEST); @@ -4074,7 +4110,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_apply_zoom_to_volumes_filter(false) , m_hover_volume_id(-1) , m_toolbar_action_running(false) - , m_warning_texture_enabled(false) , m_legend_texture_enabled(false) , m_picking_enabled(false) , m_moving_enabled(false) @@ -4232,8 +4267,7 @@ void GLCanvas3D::reset_volumes() m_dirty = true; } - enable_warning_texture(false); - _reset_warning_texture(); + _set_warning_texture(WarningTexture::ObjectOutside, false); } int GLCanvas3D::check_volumes_outside_state() const @@ -4262,6 +4296,12 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject } if (visible && !mo) toggle_sla_auxiliaries_visibility(true); + + if (!mo && !visible && !m_model->objects.empty() && (m_model->objects.size() > 1 || m_model->objects.front()->instances.size() > 1)) + _set_warning_texture(WarningTexture::SomethingNotShown, true); + + if (!mo && visible) + _set_warning_texture(WarningTexture::SomethingNotShown, false); } @@ -4375,11 +4415,6 @@ void GLCanvas3D::enable_layers_editing(bool enable) } } -void GLCanvas3D::enable_warning_texture(bool enable) -{ - m_warning_texture_enabled = enable; -} - void GLCanvas3D::enable_legend_texture(bool enable) { m_legend_texture_enabled = enable; @@ -4998,22 +5033,19 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (!contained) { - enable_warning_texture(true); - _generate_warning_texture(L("Detected object outside print volume")); + _set_warning_texture(WarningTexture::ObjectOutside, true); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, state == ModelInstance::PVS_Fully_Outside)); } else { - enable_warning_texture(false); m_volumes.reset_outside_state(); - _reset_warning_texture(); + _set_warning_texture(WarningTexture::ObjectOutside, false); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, !m_model->objects.empty())); } } else { - enable_warning_texture(false); - _reset_warning_texture(); + _set_warning_texture(WarningTexture::ObjectOutside, false); post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false)); } @@ -6667,9 +6699,6 @@ void GLCanvas3D::_render_selection_center() const void GLCanvas3D::_render_warning_texture() const { - if (!m_warning_texture_enabled) - return; - m_warning_texture.render(*this); } @@ -8204,17 +8233,7 @@ void GLCanvas3D::_update_toolpath_volumes_outside_state() void GLCanvas3D::_show_warning_texture_if_needed() { _set_current(); - - if (_is_any_volume_outside()) - { - enable_warning_texture(true); - _generate_warning_texture(L("Detected toolpath outside print volume")); - } - else - { - enable_warning_texture(false); - _reset_warning_texture(); - } + _set_warning_texture(WarningTexture::ToolpathOutside, _is_any_volume_outside()); } std::vector GLCanvas3D::_parse_colors(const std::vector& colors) @@ -8247,14 +8266,9 @@ void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data, m_legend_texture.generate(preview_data, tool_colors, *this, m_dynamic_background_enabled && _is_any_volume_outside()); } -void GLCanvas3D::_generate_warning_texture(const std::string& msg) +void GLCanvas3D::_set_warning_texture(WarningTexture::Warning warning, bool state) { - m_warning_texture.generate(msg, *this); -} - -void GLCanvas3D::_reset_warning_texture() -{ - m_warning_texture.reset(); + m_warning_texture.activate(warning, state, *this); } bool GLCanvas3D::_is_any_volume_outside() const diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 6b3839b4f..3317c6378 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -843,18 +843,32 @@ private: class WarningTexture : public GUI::GLTexture { + public: + WarningTexture(); + + enum Warning { + ObjectOutside, + ToolpathOutside, + SomethingNotShown + }; + + // Sets a warning of the given type to be active/inactive. If several warnings are active simultaneously, + // only the last one is shown (decided by the order in the enum above). + void activate(WarningTexture::Warning warning, bool state, const GLCanvas3D& canvas); + void render(const GLCanvas3D& canvas) const; + + private: static const unsigned char Background_Color[3]; static const unsigned char Opacity; int m_original_width; int m_original_height; - public: - WarningTexture(); + // Information about which warnings are currently active. + std::vector m_warnings; - bool generate(const std::string& msg, const GLCanvas3D& canvas); - - void render(const GLCanvas3D& canvas) const; + // Generates the texture with given text. + bool _generate(const std::string& msg, const GLCanvas3D& canvas); }; class LegendTexture : public GUI::GLTexture @@ -1003,7 +1017,6 @@ public: bool is_reload_delayed() const; void enable_layers_editing(bool enable); - void enable_warning_texture(bool enable); void enable_legend_texture(bool enable); void enable_picking(bool enable); void enable_moving(bool enable); @@ -1189,8 +1202,7 @@ private: void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors); // generates a warning texture containing the given message - void _generate_warning_texture(const std::string& msg); - void _reset_warning_texture(); + void _set_warning_texture(WarningTexture::Warning warning, bool state); bool _is_any_volume_outside() const; diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index e7b31e309..7a7f08518 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1445,8 +1445,8 @@ void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); ::glPushMatrix(); - ::glMultMatrixd(m.data()); ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); + ::glMultMatrixd(m.data()); if (this->is_plane_update_necessary()) const_cast(this)->update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) @@ -1479,8 +1479,8 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); ::glPushMatrix(); - ::glMultMatrixd(m.data()); ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); + ::glMultMatrixd(m.data()); if (this->is_plane_update_necessary()) const_cast(this)->update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) @@ -2064,18 +2064,21 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous if (instance_id == -1) return false; - // Regardless of whether the user clicked the object or not, we will unselect all points: - select_point(NoPoints); + // If there is some selection, don't add new point and deselect everything instead. + if (m_selection_empty) { + 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 + m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), false)); + m_unsaved_changes = true; + } + catch (...) { // not clicked on object + return true; // prevents deselection of the gizmo by GLCanvas3D + } + } + else + select_point(NoPoints); - 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 - m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), true)); - m_unsaved_changes = true; - } - catch (...) { // not clicked on object - return true; // prevents deselection of the gizmo by GLCanvas3D - } return true; } @@ -2106,9 +2109,8 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous direction_to_camera = instance_matrix_no_translation.inverse().cast() * direction_to_camera.eval(); // Iterate over all points, check if they're in the rectangle and if so, check that they are not obscured by the mesh: - 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; + for (unsigned int i=0; i() * m_editing_mode_cache[i].first.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); @@ -2118,14 +2120,14 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous bool is_obscured = false; // Cast a ray in the direction of the camera and look for intersection with the mesh: std::vector hits; - if (m_AABB.intersect_ray(m_V, m_F, support_point.pos, direction_to_camera, hits)) + if (m_AABB.intersect_ray(m_V, m_F, m_editing_mode_cache[i].first.pos, direction_to_camera, hits)) // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction. // Also, the threshold is in mesh coordinates, not in actual dimensions. if (hits.size() > 1 || hits.front().t > 0.001f) is_obscured = true; if (!is_obscured) - point_and_selection.second = true; + select_point(i); } } m_selection_rectangle_active = false; @@ -2170,6 +2172,8 @@ void GLGizmoSlaSupports::delete_selected_points() // wxGetApp().plater()->reslice(); } + select_point(NoPoints); + //m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } @@ -2269,7 +2273,9 @@ RENDER_AGAIN: m_imgui->checkbox(_(L("Lock supports under new islands")), m_lock_unique_islands); force_refresh |= changed != m_lock_unique_islands; + m_imgui->disabled_begin(m_selection_empty); remove_selected = m_imgui->button(_(L("Remove selected points"))); + m_imgui->disabled_end(); m_imgui->text(" "); // vertical gap @@ -2448,10 +2454,13 @@ void GLGizmoSlaSupports::select_point(int i) { if (i == AllPoints || i == NoPoints) { for (auto& point_and_selection : m_editing_mode_cache) - point_and_selection.second = ( i == AllPoints ? true : false); + point_and_selection.second = ( i == AllPoints ); + m_selection_empty = (i == NoPoints); } - else + else { m_editing_mode_cache[i].second = true; + m_selection_empty = false; + } } void GLGizmoSlaSupports::editing_mode_discard_changes() diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index 97e3d0c6f..a24384012 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -502,6 +502,7 @@ private: bool m_ignore_up_event = false; bool m_combo_box_open = false; bool m_unsaved_changes = false; + 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) #if SLAGIZMO_IMGUI_MODAL bool m_show_modal = false;