diff --git a/src/imgui/README.md b/src/imgui/README.md index 00d78ed013..83f4619964 100644 --- a/src/imgui/README.md +++ b/src/imgui/README.md @@ -3,3 +3,8 @@ For more information go to https://github.com/ocornut/imgui THIS DIRECTORY CONTAINS THE imgui-1.75 58b3e02 SOURCE DISTRIBUTION. + +Customized with the following commits: +042880ba2df913916b2cc77f7bb677e07bfd2c58 +67c55c74901f1d337ef08f2090a87cfb4263bb0f +a94c952b40d36b1505fb77b87c0dd739e1034659 \ No newline at end of file diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index cd2c4957da..7b56030c74 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -411,6 +411,11 @@ public: return timestamp == other.get_timestamp(); } + template void serialize(Archive &ar) + { + ar(m_data); + } + private: std::map m_data; @@ -613,7 +618,8 @@ private: } template void load(Archive &ar) { bool has_convex_hull; - ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); + ar(name, source, m_mesh, m_type, m_material_id, m_transformation, + m_is_splittable, has_convex_hull, m_supported_facets); cereal::load_by_value(ar, config); assert(m_mesh); if (has_convex_hull) { @@ -626,7 +632,8 @@ private: } template void save(Archive &ar) const { bool has_convex_hull = m_convex_hull.get() != nullptr; - ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); + ar(name, source, m_mesh, m_type, m_material_id, m_transformation, + m_is_splittable, has_convex_hull, m_supported_facets); cereal::save_by_value(ar, config); if (has_convex_hull) cereal::save_optional(ar, m_convex_hull); diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 291949ce91..0f603c2651 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -84,6 +84,9 @@ void AppConfig::set_defaults() if (get("custom_toolbar_size").empty()) set("custom_toolbar_size", "100"); + if (get("auto_toolbar_size").empty()) + set("auto_toolbar_size", "100"); + if (get("use_perspective_camera").empty()) set("use_perspective_camera", "1"); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 16d3f4123a..59ea01314a 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #ifdef __WXOSX__ @@ -79,6 +80,29 @@ void Field::PostInitialize() m_em_unit = em_unit(m_parent); BUILD(); + + // For the mode, when settings are in non-modal dialog, neither dialog nor tabpanel doesn't receive wxEVT_KEY_UP event, when some field is selected. + // So, like a workaround check wxEVT_KEY_UP event for the Filed and switch between tabs if Ctrl+(1-4) was pressed + if (getWindow()) + getWindow()->Bind(wxEVT_KEY_UP, [](wxKeyEvent& evt) { + if ((evt.GetModifiers() & wxMOD_CONTROL) != 0) { + int tab_id = -1; + switch (evt.GetKeyCode()) { + case '1': { tab_id = 0; break; } + case '2': { tab_id = 1; break; } + case '3': { tab_id = 2; break; } + case '4': { tab_id = 3; break; } + default: break; + } + if (tab_id >= 0) + wxGetApp().mainframe->select_tab(tab_id); + if (tab_id > 0) + // tab panel should be focused for correct navigation between tabs + wxGetApp().tab_panel()->SetFocus(); + } + + evt.Skip(); + }); } // Values of width to alignments of fields @@ -397,7 +421,7 @@ void TextCtrl::BUILD() { bKilledFocus = false; #endif // __WXOSX__ }), temp->GetId()); - +/* // select all text using Ctrl+A temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event) { @@ -405,7 +429,7 @@ void TextCtrl::BUILD() { temp->SetSelection(-1, -1); //select all event.Skip(); })); - +*/ // recast as a wxWindow to fit the calling convention window = dynamic_cast(temp); } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1cbfac4e48..073a9cd35e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1438,7 +1438,7 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas #if ENABLE_SLOPE_RENDERING void GLCanvas3D::Slope::render() const { - if (is_shown()) + if (m_dialog_shown) { const std::array& z_range = m_volumes.get_slope_z_range(); std::array angle_range = { Geometry::rad2deg(::acos(z_range[0])) - 90.0f, Geometry::rad2deg(::acos(z_range[1])) - 90.0f }; @@ -1449,29 +1449,41 @@ void GLCanvas3D::Slope::render() const imgui.set_next_window_pos((float)cnv_size.get_width(), (float)cnv_size.get_height(), ImGuiCond_Always, 1.0f, 1.0f); imgui.begin(_(L("Slope visualization")), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - imgui.text(_(L("Facets' normal angle range (degrees)")) + ":"); + imgui.text(_(L("Facets' slope range (degrees)")) + ":"); - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f)); - if (ImGui::SliderFloat("##yellow", &angle_range[0], 0.0f, 90.0f, "%.1f")) - { - modified = true; - if (angle_range[1] < angle_range[0]) - angle_range[1] = angle_range[0]; - } - ImGui::PopStyleColor(4); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.0f, 0.0f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.0f, 0.0f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.0f, 0.0f, 1.0f)); - if (ImGui::SliderFloat("##red", &angle_range[1], 0.0f, 90.0f, "%.1f")) + + // angle_range is range of normal angle, GUI should + // show facet slope angle + float slope_bound = 90.f - angle_range[1]; + bool mod = ImGui::SliderFloat("##red", &slope_bound, 0.0f, 90.0f, "%.1f"); + angle_range[1] = 90.f - slope_bound; + if (mod) { modified = true; if (angle_range[0] > angle_range[1]) angle_range[0] = angle_range[1]; } + + ImGui::PopStyleColor(4); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f)); + + slope_bound = 90.f - angle_range[0]; + mod = ImGui::SliderFloat("##yellow", &slope_bound, 0.0f, 90.0f, "%.1f"); + angle_range[0] = 90.f - slope_bound; + if (mod) + { + modified = true; + if (angle_range[1] < angle_range[0]) + angle_range[1] = angle_range[0]; + } + ImGui::PopStyleColor(4); ImGui::Separator(); @@ -1486,7 +1498,7 @@ void GLCanvas3D::Slope::render() const imgui.end(); if (modified) - m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - angle_range[0])), -::cos(Geometry::deg2rad(90.0f - angle_range[1])) }); + set_range(angle_range); } } #endif // ENABLE_SLOPE_RENDERING @@ -1868,8 +1880,8 @@ bool GLCanvas3D::is_reload_delayed() const void GLCanvas3D::enable_layers_editing(bool enable) { #if ENABLE_SLOPE_RENDERING - if (enable && m_slope.is_shown()) - m_slope.show(false); + if (enable && m_slope.is_dialog_shown()) + m_slope.show_dialog(false); #endif // ENABLE_SLOPE_RENDERING m_layers_editing.set_enabled(enable); @@ -3098,7 +3110,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'd': { if (!is_layers_editing_enabled()) { - m_slope.show(!m_slope.is_shown()); + m_slope.show_dialog(!m_slope.is_dialog_shown()); m_dirty = true; } break; @@ -3697,7 +3709,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled) { - if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) + if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports + && m_gizmos.get_current_type() != GLGizmosManager::FdmSupports) { m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); m_dirty = true; @@ -4492,7 +4505,7 @@ bool GLCanvas3D::_render_search_list(float pos_x) const bool action_taken = false; ImGuiWrapper* imgui = wxGetApp().imgui(); - const float x = pos_x * (float)wxGetApp().plater()->get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width(); + const float x = /*pos_x * (float)wxGetApp().plater()->get_camera().get_zoom() + */0.5f * (float)get_canvas_size().get_width(); imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f); std::string title = L("Search"); imgui->begin(_(title), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); @@ -5630,6 +5643,44 @@ void GLCanvas3D::_render_selection_center() const } #endif // ENABLE_RENDER_SELECTION_CENTER +void GLCanvas3D::_check_and_update_toolbar_icon_scale() const +{ + float scale = wxGetApp().toolbar_icon_scale(); + Size cnv_size = get_canvas_size(); + + float size = GLToolbar::Default_Icons_Size * scale; + + // Set current size for all top toolbars. It will be used for next calculations +#if ENABLE_RETINA_GL + const float sc = m_retina_helper->get_scale_factor() * scale; + m_main_toolbar.set_scale(sc); + m_undoredo_toolbar.set_scale(sc); + m_collapse_toolbar.set_scale(sc); +#else + m_main_toolbar.set_icons_size(size); + m_undoredo_toolbar.set_icons_size(size); + m_collapse_toolbar.set_icons_size(size); +#endif // ENABLE_RETINA_GL + + float top_tb_width = m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + m_collapse_toolbar.get_width(); + int items_cnt = m_main_toolbar.get_visible_items_cnt() + m_undoredo_toolbar.get_visible_items_cnt() + m_collapse_toolbar.get_visible_items_cnt(); + float noitems_width = top_tb_width - size * items_cnt; // width of separators and borders in top toolbars + + // calculate scale needed for items in all top toolbars + float new_h_scale = (cnv_size.get_width() - noitems_width) / (items_cnt * GLToolbar::Default_Icons_Size); + + items_cnt = m_gizmos.get_selectable_icons_cnt() + 3; // +3 means a place for top and view toolbars and separators in gizmos toolbar + + // calculate scale needed for items in the gizmos toolbar + float new_v_scale = cnv_size.get_height() / (items_cnt * GLGizmosManager::Default_Icons_Size); + + // set minimum scale as a auto scale for the toolbars + float new_scale = std::min(new_h_scale, new_v_scale); + if (fabs(new_scale - scale) > EPSILON) + wxGetApp().set_auto_toolbar_icon_scale(new_scale); +} + + void GLCanvas3D::_render_overlays() const { glsafe(::glDisable(GL_DEPTH_TEST)); @@ -5642,6 +5693,8 @@ void GLCanvas3D::_render_overlays() const double gui_scale = camera.get_gui_scale(); glsafe(::glScaled(gui_scale, gui_scale, 1.0)); + _check_and_update_toolbar_icon_scale(); + _render_gizmos_overlay(); _render_warning_texture(); #if !ENABLE_GCODE_VIEWER @@ -5651,12 +5704,12 @@ void GLCanvas3D::_render_overlays() const // main toolbar and undoredo toolbar need to be both updated before rendering because both their sizes are needed // to correctly place them #if ENABLE_RETINA_GL - const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(true); + const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(/*true*/); m_main_toolbar.set_scale(scale); m_undoredo_toolbar.set_scale(scale); m_collapse_toolbar.set_scale(scale); #else - const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(true)); + const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(/*true*/)); m_main_toolbar.set_icons_size(size); m_undoredo_toolbar.set_icons_size(size); m_collapse_toolbar.set_icons_size(size); @@ -5765,7 +5818,8 @@ void GLCanvas3D::_render_main_toolbar() const float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; - float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width()) * inv_zoom; + float collapse_toolbar_width = m_collapse_toolbar.is_enabled() ? m_collapse_toolbar.get_width() : 0.0f; + float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar_width) * inv_zoom; m_main_toolbar.set_position(top, left); m_main_toolbar.render(*this); @@ -5780,7 +5834,8 @@ void GLCanvas3D::_render_undoredo_toolbar() const float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; - float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width())) * inv_zoom; + float collapse_toolbar_width = m_collapse_toolbar.is_enabled() ? m_collapse_toolbar.get_width() : 0.0f; + float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar_width)) * inv_zoom; m_undoredo_toolbar.set_position(top, left); m_undoredo_toolbar.render(*this); } @@ -7338,9 +7393,14 @@ bool GLCanvas3D::_deactivate_undo_redo_toolbar_items() return false; } +bool GLCanvas3D::is_search_pressed() const +{ + return m_main_toolbar.is_item_pressed("search"); +} + bool GLCanvas3D::_deactivate_search_toolbar_item() { - if (m_main_toolbar.is_item_pressed("search")) + if (is_search_pressed()) { m_main_toolbar.force_left_action(m_main_toolbar.get_item_id("search"), *this); return true; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 685a8b991c..3e7296e139 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -415,6 +415,7 @@ private: class Slope { bool m_enabled{ false }; + bool m_dialog_shown{ false }; GLCanvas3D& m_canvas; GLVolumeCollection& m_volumes; @@ -423,9 +424,14 @@ private: void enable(bool enable) { m_enabled = enable; } bool is_enabled() const { return m_enabled; } - void show(bool show) { m_volumes.set_slope_active(m_enabled ? show : false); } - bool is_shown() const { return m_volumes.is_slope_active(); } + void use(bool use) { m_volumes.set_slope_active(m_enabled ? use : false); } + bool is_used() const { return m_volumes.is_slope_active(); } + void show_dialog(bool show) { if (show && is_used()) return; use(show); m_dialog_shown = show; } + bool is_dialog_shown() const { return m_dialog_shown; } void render() const; + void set_range(const std::array& range) const { + m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - range[0])), -::cos(Geometry::deg2rad(90.0f - range[1])) }); + } }; #endif // ENABLE_SLOPE_RENDERING @@ -586,6 +592,7 @@ public: bool is_layers_editing_enabled() const; bool is_layers_editing_allowed() const; + bool is_search_pressed() const; void reset_layer_height_profile(); void adaptive_layer_height_profile(float quality_factor); @@ -753,8 +760,10 @@ public: void show_labels(bool show) { m_labels.show(show); } #if ENABLE_SLOPE_RENDERING - bool is_slope_shown() const { return m_slope.is_shown(); } - void show_slope(bool show) { m_slope.show(show); } + bool is_slope_shown() const { return m_slope.is_dialog_shown(); } + void use_slope(bool use) { m_slope.use(use); } + void show_slope(bool show) { m_slope.show_dialog(show); } + void set_slope_range(const std::array& range) { m_slope.set_range(range); } #endif // ENABLE_SLOPE_RENDERING private: @@ -788,6 +797,7 @@ private: #if ENABLE_RENDER_SELECTION_CENTER void _render_selection_center() const; #endif // ENABLE_RENDER_SELECTION_CENTER + void _check_and_update_toolbar_icon_scale() const; void _render_overlays() const; void _render_warning_texture() const; #if !ENABLE_GCODE_VIEWER diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index e7f784773a..c69327cfa4 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -532,7 +532,12 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) m_mouse_capture.left = true; m_mouse_capture.parent = &parent; processed = true; +#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI + if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() && + ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left))) +#else if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left))) +#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI { // mouse is inside an icon do_action(GLToolbarItem::Left, item_id, parent, true); @@ -549,7 +554,12 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) m_mouse_capture.right = true; m_mouse_capture.parent = &parent; processed = true; +#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI + if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() && + ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right))) +#else if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right))) +#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI { // mouse is inside an icon do_action(GLToolbarItem::Right, item_id, parent, true); @@ -627,6 +637,16 @@ float GLToolbar::get_main_size() const return size * m_layout.scale; } +int GLToolbar::get_visible_items_cnt() const +{ + int cnt = 0; + for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i) + if (m_items[i]->is_visible() && !m_items[i]->is_separator()) + cnt++; + + return cnt; +} + void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover) { if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id)) @@ -634,7 +654,11 @@ void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas if ((0 <= item_id) && (item_id < (int)m_items.size())) { GLToolbarItem* item = m_items[item_id]; +#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI + if ((item != nullptr) && !item->is_separator() && !item->is_disabled() && (!check_hover || item->is_hovered())) +#else if ((item != nullptr) && !item->is_separator() && (!check_hover || item->is_hovered())) +#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI { if (((type == GLToolbarItem::Right) && item->is_right_toggable()) || ((type == GLToolbarItem::Left) && item->is_left_toggable())) diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 27b43fef63..9911bb34a5 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -319,6 +319,7 @@ public: void get_additional_tooltip(int item_id, std::string& text); void set_additional_tooltip(int item_id, const std::string& text); void set_tooltip(int item_id, const std::string& text); + int get_visible_items_cnt() const; // returns true if any item changed its state bool update_items_state(); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 7f3d86a9c3..9a2a51e9ce 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -580,17 +580,35 @@ float GUI_App::toolbar_icon_scale(const bool is_limited/* = false*/) const const std::string& use_val = app_config->get("use_custom_toolbar_size"); const std::string& val = app_config->get("custom_toolbar_size"); + const std::string& auto_val = app_config->get("auto_toolbar_size"); - if (val.empty() || use_val.empty() || use_val == "0") + if (val.empty() || auto_val.empty() || use_val.empty()) return icon_sc; - int int_val = atoi(val.c_str()); + int int_val = use_val == "0" ? 100 : atoi(val.c_str()); + // correct value in respect to auto_toolbar_size + int_val = std::min(atoi(auto_val.c_str()), int_val); + if (is_limited && int_val < 50) int_val = 50; return 0.01f * int_val * icon_sc; } +void GUI_App::set_auto_toolbar_icon_scale(float scale) const +{ +#ifdef __APPLE__ + const float icon_sc = 1.0f; // for Retina display will be used its own scale +#else + const float icon_sc = m_em_unit * 0.1f; +#endif // __APPLE__ + + int int_val = std::min(int(scale / icon_sc * 100), 100); + std::string val = std::to_string(int_val); + + app_config->set("auto_toolbar_size", val); +} + void GUI_App::recreate_GUI(const wxString& msg_name) { mainframe->shutdown(); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index cd59f1d803..3afadf4e0e 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -135,6 +135,7 @@ public: const wxFont& normal_font() { return m_normal_font; } int em_unit() const { return m_em_unit; } float toolbar_icon_scale(const bool is_limited = false) const; + void set_auto_toolbar_icon_scale(float scale) const; void recreate_GUI(const wxString& message); void system_info(); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1f2ce0221d..b2283ba4a2 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2771,6 +2771,7 @@ void ObjectList::delete_all_objects_from_list() void ObjectList::increase_object_instances(const size_t obj_idx, const size_t num) { select_item(m_objects_model->AddInstanceChild(m_objects_model->GetItemById(obj_idx), num)); + selection_changed(); } void ObjectList::decrease_object_instances(const size_t obj_idx, const size_t num) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 8094d10ad0..a75eed12c0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -58,10 +58,10 @@ void GLGizmoFdmSupports::set_fdm_support_data(ModelObject* model_object, const S return; if (mo && selection.is_from_single_instance() - && (mo != m_old_mo || mo->volumes.size() != m_old_volumes_size)) + && (mo->id() != m_old_mo_id || mo->volumes.size() != m_old_volumes_size)) { - update_mesh(); - m_old_mo = mo; + update_from_model_object(); + m_old_mo_id = mo->id(); m_old_volumes_size = mo->volumes.size(); } } @@ -84,12 +84,29 @@ void GLGizmoFdmSupports::on_render() const void GLGizmoFdmSupports::render_triangles(const Selection& selection) const { + if (m_setting_angle) + return; + const ModelObject* mo = m_c->selection_info()->model_object(); glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } ); glsafe(::glPolygonOffset(-1.0, 1.0)); + // Take care of the clipping plane. The normal of the clipping plane is + // saved with opposite sign than we need to pass to OpenGL (FIXME) + bool clipping_plane_active = m_c->object_clipper()->get_position() != 0.; + if (clipping_plane_active) { + const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane(); + double clp_data[4]; + memcpy(clp_data, clp->get_data(), 4 * sizeof(double)); + for (int i=0; i<3; ++i) + clp_data[i] = -1. * clp_data[i]; + + glsafe(::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)clp_data)); + glsafe(::glEnable(GL_CLIP_PLANE0)); + } + int mesh_id = -1; for (const ModelVolume* mv : mo->volumes) { if (! mv->is_model_part()) @@ -113,6 +130,8 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const } glsafe(::glPopMatrix()); } + if (clipping_plane_active) + glsafe(::glDisable(GL_CLIP_PLANE0)); } @@ -161,14 +180,21 @@ void GLGizmoFdmSupports::render_cursor_circle() const } -void GLGizmoFdmSupports::on_render_for_picking() const +void GLGizmoFdmSupports::update_model_object() const { - + ModelObject* mo = m_c->selection_info()->model_object(); + int idx = -1; + for (ModelVolume* mv : mo->volumes) { + ++idx; + if (! mv->is_model_part()) + continue; + for (int i=0; im_supported_facets.set_facet(i, m_selected_facets[idx][i]); + } } - -void GLGizmoFdmSupports::update_mesh() +void GLGizmoFdmSupports::update_from_model_object() { wxBusyCursor wait; @@ -177,7 +203,6 @@ void GLGizmoFdmSupports::update_mesh() for (const ModelVolume* mv : mo->volumes) if (mv->is_model_part()) ++num_of_volumes; - m_selected_facets.resize(num_of_volumes); m_neighbors.resize(num_of_volumes); m_ivas.clear(); @@ -218,6 +243,21 @@ void GLGizmoFdmSupports::update_mesh() +bool GLGizmoFdmSupports::is_mesh_point_clipped(const Vec3d& point) const +{ + if (m_c->object_clipper()->get_position() == 0.) + return false; + + auto sel_info = m_c->selection_info(); + int active_inst = m_c->selection_info()->get_active_instance(); + const ModelInstance* mi = sel_info->model_object()->instances[active_inst]; + const Transform3d& trafo = mi->get_transformation().get_matrix(); + + Vec3d transformed_point = trafo * point; + transformed_point(2) += sel_info->get_sla_shift(); + return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); +} + bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) { return a.first < b.first; @@ -310,6 +350,12 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous m_clipping_plane.get(), &facet)) { + // In case this hit is clipped, skip it. + if (is_mesh_point_clipped(hit.cast())) { + some_mesh_was_hit = true; + continue; + } + // Is this hit the closest to the camera so far? double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast()).squaredNorm(); if (hit_squared_distance < closest_hit_squared_distance) { @@ -430,19 +476,16 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp) && m_button_down != Button::None) { + // Take snapshot and update ModelVolume data. + wxString action_name = shift_down + ? _L("Remove selection") + : (m_button_down == Button::Left + ? _L("Add supports") + : _L("Block supports")); + Plater::TakeSnapshot(wxGetApp().plater(), action_name); + update_model_object(); + m_button_down = Button::None; - - // Synchronize gizmo with ModelVolume data. - ModelObject* mo = m_c->selection_info()->model_object(); - int idx = -1; - for (ModelVolume* mv : mo->volumes) { - ++idx; - if (! mv->is_model_part()) - continue; - for (int i=0; im_supported_facets.set_facet(i, m_selected_facets[idx][i]); - } - return true; } @@ -481,6 +524,46 @@ void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv, } +void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwrite, bool block) +{ + float threshold = (M_PI/180.)*threshold_deg; + const Selection& selection = m_parent.get_selection(); + const ModelObject* mo = m_c->selection_info()->model_object(); + const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; + + int mesh_id = -1; + for (const ModelVolume* mv : mo->volumes) { + if (! mv->is_model_part()) + continue; + + ++mesh_id; + + const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true); + Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast().normalized(); + Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast().normalized(); + + float dot_limit = limit.dot(down); + + // Now calculate dot product of vert_direction and facets' normals. + int idx = -1; + for (const stl_facet& facet : mv->mesh().stl.facet_start) { + ++idx; + if (facet.normal.dot(down) > dot_limit && (overwrite || m_selected_facets[mesh_id][idx] == FacetSupportType::NONE)) + m_selected_facets[mesh_id][idx] = block + ? FacetSupportType::BLOCKER + : FacetSupportType::ENFORCER; + } + update_vertex_buffers(mv, mesh_id, true, true); + } + + Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle") + : _L("Add supports by angle")); + update_model_object(); + m_parent.set_as_dirty(); + m_setting_angle = false; +} + + void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) { if (! m_c->selection_info()->model_object()) @@ -489,96 +572,131 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l const float approx_height = m_imgui->scaled(18.0f); y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); - // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); - const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); - const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); - const float minimal_slider_width = m_imgui->scaled(4.f); + if (! m_setting_angle) { + m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); - float caption_max = 0.f; - float total_text_max = 0.; - for (const std::string& t : {"enforce", "block", "remove"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x); - total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); - } - caption_max += m_imgui->scaled(1.f); - total_text_max += m_imgui->scaled(1.f); + // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); + const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); + const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); + const float minimal_slider_width = m_imgui->scaled(4.f); - float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left); - window_width = std::max(window_width, total_text_max); - window_width = std::max(window_width, button_width); + float caption_max = 0.f; + float total_text_max = 0.; + for (const std::string& t : {"enforce", "block", "remove"}) { + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x); + total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); + } + caption_max += m_imgui->scaled(1.f); + total_text_max += m_imgui->scaled(1.f); - auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { - static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); - m_imgui->text(caption); - ImGui::PopStyleColor(); - ImGui::SameLine(caption_max); - m_imgui->text(text); - }; + float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left); + window_width = std::max(window_width, total_text_max); + window_width = std::max(window_width, button_width); - for (const std::string& t : {"enforce", "block", "remove"}) - draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); + auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { + static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + m_imgui->text(caption); + ImGui::PopStyleColor(); + ImGui::SameLine(caption_max); + m_imgui->text(text); + }; - m_imgui->text(""); + for (const std::string& t : {"enforce", "block", "remove"}) + draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); - if (m_imgui->button(m_desc.at("remove_all"))) { - ModelObject* mo = m_c->selection_info()->model_object(); - int idx = -1; - for (ModelVolume* mv : mo->volumes) { - ++idx; - if (mv->is_model_part()) { - m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE); - mv->m_supported_facets.clear(); - update_vertex_buffers(mv, idx, true, true); - m_parent.set_as_dirty(); + m_imgui->text(""); + + if (m_imgui->button("Autoset by angle...")) { + m_setting_angle = true; + } + + ImGui::SameLine(); + + if (m_imgui->button(m_desc.at("remove_all"))) { + ModelObject* mo = m_c->selection_info()->model_object(); + int idx = -1; + for (ModelVolume* mv : mo->volumes) { + ++idx; + if (mv->is_model_part()) { + m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE); + mv->m_supported_facets.clear(); + update_vertex_buffers(mv, idx, true, true); + m_parent.set_as_dirty(); + } } } - } - const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; + const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; - m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(clipping_slider_left); - ImGui::PushItemWidth(window_width - clipping_slider_left); - ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(max_tooltip_width); - ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } + m_imgui->text(m_desc.at("cursor_size")); + ImGui::SameLine(clipping_slider_left); + ImGui::PushItemWidth(window_width - clipping_slider_left); + ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } - ImGui::Separator(); - if (m_c->object_clipper()->get_position() == 0.f) - m_imgui->text(m_desc.at("clipping_of_view")); - else { - if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position(-1., false); - }); + ImGui::Separator(); + if (m_c->object_clipper()->get_position() == 0.f) + m_imgui->text(m_desc.at("clipping_of_view")); + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this](){ + m_c->object_clipper()->set_position(-1., false); + }); + } + } + + ImGui::SameLine(clipping_slider_left); + ImGui::PushItemWidth(window_width - clipping_slider_left); + float clp_dist = m_c->object_clipper()->get_position(); + if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + m_c->object_clipper()->set_position(clp_dist, true); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Ctrl + Mouse wheel").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + + m_imgui->end(); + if (m_setting_angle) { + m_parent.show_slope(false); + m_parent.set_slope_range({90.f - m_angle_threshold_deg, 90.f - m_angle_threshold_deg}); + m_parent.use_slope(true); + m_parent.set_as_dirty(); } } - - ImGui::SameLine(clipping_slider_left); - ImGui::PushItemWidth(window_width - clipping_slider_left); - float clp_dist = m_c->object_clipper()->get_position(); - if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) - m_c->object_clipper()->set_position(clp_dist, true); - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(max_tooltip_width); - ImGui::TextUnformatted(_L("Ctrl + Mouse wheel").ToUTF8().data()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); + else { + std::string name = "Autoset custom supports"; + m_imgui->begin(wxString(name), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); + m_imgui->text("Threshold:"); + ImGui::SameLine(); + if (m_imgui->slider_float("", &m_angle_threshold_deg, 0.f, 90.f, "%.f")) + m_parent.set_slope_range({90.f - m_angle_threshold_deg, 90.f - m_angle_threshold_deg}); + m_imgui->checkbox(wxString("Overwrite already selected facets"), m_overwrite_selected); + if (m_imgui->button("Enforce")) + select_facets_by_angle(m_angle_threshold_deg, m_overwrite_selected, false); + ImGui::SameLine(); + if (m_imgui->button("Block")) + select_facets_by_angle(m_angle_threshold_deg, m_overwrite_selected, true); + ImGui::SameLine(); + if (m_imgui->button("Cancel")) + m_setting_angle = false; + m_imgui->end(); + if (! m_setting_angle) { + m_parent.use_slope(false); + m_parent.set_as_dirty(); + } } - - - - m_imgui->end(); } bool GLGizmoFdmSupports::on_is_activable() const @@ -627,12 +745,24 @@ void GLGizmoFdmSupports::on_set_state() return; if (m_state == On && m_old_state != On) { // the gizmo was just turned on - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on"))); + { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on"))); + } + if (! m_parent.get_gizmos_manager().is_serializing()) { + wxGetApp().CallAfter([]() { + wxGetApp().plater()->enter_gizmos_stack(); + }); + } } if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off // we are actually shutting down - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off"))); - m_old_mo = nullptr; + m_setting_angle = false; + m_parent.use_slope(false); + wxGetApp().plater()->leave_gizmos_stack(); + { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off"))); + } + m_old_mo_id = -1; m_ivas.clear(); m_neighbors.clear(); m_selected_facets.clear(); @@ -657,7 +787,7 @@ void GLGizmoFdmSupports::on_stop_dragging() void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive& ar) { - + update_from_model_object(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 994218f698..bed6d00a0c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -19,7 +19,7 @@ enum class SLAGizmoEventType : unsigned char; class GLGizmoFdmSupports : public GLGizmoBase { private: - const ModelObject* m_old_mo = nullptr; + ObjectID m_old_mo_id; size_t m_old_volumes_size = 0; GLUquadricObj* m_quadric; @@ -53,14 +53,23 @@ public: private: bool on_init() override; void on_render() const override; - void on_render_for_picking() const override; + void on_render_for_picking() const override {} void render_triangles(const Selection& selection) const; void render_cursor_circle() const; - void update_mesh(); + + void update_model_object() const; + void update_from_model_object(); + + void select_facets_by_angle(float threshold, bool overwrite, bool block); + bool m_overwrite_selected = false; + float m_angle_threshold_deg = 45.f; + + bool is_mesh_point_clipped(const Vec3d& point) const; float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; + bool m_setting_angle = false; // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index b248db1c64..8d4616da37 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -58,7 +58,10 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) const ModelObject* mo = m_c->selection_info()->model_object(); if (mo) { - reload_cache(); + if (m_old_mo_id != mo->id()) { + reload_cache(); + m_old_mo_id = mo->id(); + } if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh()) m_holes_in_drilled_mesh = mo->sla_drain_holes; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 3ee83c3454..93e577743a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -43,6 +43,8 @@ private: void hollow_mesh(bool postpone_error_messages = false); bool unsaved_changes() const; + ObjectID m_old_mo_id = -1; + // bool m_show_supports = true; float m_new_hole_radius = 2.f; // Size of a new hole. float m_new_hole_height = 6.f; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 496568d51a..261738d444 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -66,11 +66,10 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S ModelObject* mo = m_c->selection_info()->model_object(); - if (mo != m_old_mo) { + if (mo && mo->id() != m_old_mo_id) { disable_editing_mode(); - if (mo) - reload_cache(); - m_old_mo = mo; + reload_cache(); + m_old_mo_id = mo->id(); } // If we triggered autogeneration before, check backend and fetch results if they are there diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 917d22a988..b6cad8f9ae 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -83,7 +83,7 @@ private: float m_density_stash = 0.f; // and again mutable std::vector m_editing_cache; // a support point and whether it is currently selected std::vector m_normal_cache; // to restore after discarding changes or undo/redo - const ModelObject* m_old_mo = nullptr; + ObjectID m_old_mo_id; // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 5f09a3daf0..8ff6c121fc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -369,15 +369,6 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object) || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) return; - /*m_common_gizmos_data->update_from_backend(m_parent, model_object); - - auto* gizmo_supports = dynamic_cast(m_gizmos[SlaSupports].get()); - - - // note: sla support gizmo takes care of updating the common data. - // following lines are thus dependent - //gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection()); - */ auto* gizmo_hollow = dynamic_cast(m_gizmos[Hollow].get()); auto* gizmo_supports = dynamic_cast(m_gizmos[SlaSupports].get()); gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 478774718f..a7fb821262 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -139,6 +139,11 @@ public: EType new_current = m_current; m_current = old_current; + // Update common data. They should be updated when activate_gizmo is + // called, so it can be used in on_set_state which is called from there. + if (new_current != Undefined) + m_common_gizmos_data->update(m_gizmos[new_current]->get_requirements()); + // activate_gizmo call sets m_current and calls set_state for the gizmo // it does nothing in case the gizmo is already activated // it can safely be called for Undefined gizmo @@ -167,6 +172,7 @@ public: void refresh_on_off_state(); void reset_all_states(); + bool is_serializing() const { return m_serializing; } void set_hover_id(int id); void enable_grabber(EType type, unsigned int id, bool enable); @@ -220,6 +226,8 @@ public: void update_after_undo_redo(const UndoRedo::Snapshot& snapshot); + int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); } + private: void render_background(float left, float top, float right, float bottom, float border) const; void do_render_overlay() const; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index d05e4bd773..73b78d3df2 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +//#include #include #include @@ -28,6 +28,7 @@ #include "RemovableDriveManager.hpp" #include "InstanceCheck.hpp" #include "I18N.hpp" +#include "GLCanvas3D.hpp" #include #include "GUI_App.hpp" @@ -1263,6 +1264,9 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) if (tab==0) { if (m_settings_dialog->IsShown()) this->SetFocus(); + // plater should be focused for correct navigation inside search window + if (m_plater->canvas3D()->is_search_pressed()) + m_plater->SetFocus(); return; } // Show/Activate Settings Dialog @@ -1278,6 +1282,10 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) else if (m_layout == slNew) { m_plater->Show(tab == 0); m_tabpanel->Show(tab != 0); + + // plater should be focused for correct navigation inside search window + if (tab == 0 && m_plater->canvas3D()->is_search_pressed()) + m_plater->SetFocus(); Layout(); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0648c9f474..8d505f2b65 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4474,8 +4474,6 @@ void Plater::increase_instances(size_t num) // p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); } - sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num); - if (p->get_config("autocenter") == "1") arrange(); @@ -4483,8 +4481,9 @@ void Plater::increase_instances(size_t num) p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1); - p->selection_changed(); + sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num); + p->selection_changed(); this->p->schedule_background_process(); } @@ -5389,6 +5388,9 @@ void Plater::paste_from_clipboard() void Plater::search(bool plater_is_active) { if (plater_is_active) { + // plater should be focused for correct navigation inside search window + this->SetFocus(); + wxKeyEvent evt; #ifdef __APPLE__ evt.m_keyCode = 'f'; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index ff42da61db..9e462d4bf1 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -190,9 +190,17 @@ void PreferencesDialog::accept() auto app_config = get_app_config(); - m_settings_layout_changed = m_values.find("old_settings_layout_mode") != m_values.end() || - m_values.find("new_settings_layout_mode") != m_values.end() || - m_values.find("dlg_settings_layout_mode") != m_values.end(); + m_settings_layout_changed = false; + for (const std::string& key : {"old_settings_layout_mode", + "new_settings_layout_mode", + "dlg_settings_layout_mode" }) + { + auto it = m_values.find(key); + if (it != m_values.end() && app_config->get(key) != it->second) { + m_settings_layout_changed = true; + break; + } + } if (m_settings_layout_changed) { // the dialog needs to be destroyed before the call to recreate_gui() diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index aef46bf559..b929b37d0a 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -262,13 +262,14 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/) append(matches, matches2); score = score2; } - if (fuzzy_match(wsearch, label_english, score2, matches2) && score2 > score) { + if (view_params.english && fuzzy_match(wsearch, label_english, score2, matches2) && score2 > score) { label = std::move(label_english); matches = std::move(matches2); score = score2; } if (score > std::numeric_limits::min()) { - label = mark_string(label, matches); + label = mark_string(label, matches); + label += L" [" + std::to_wstring(score) + L"]";// add score value std::string label_u8 = into_u8(label); std::string label_plain = label_u8; boost::erase_all(label_plain, std::string(1, char(ImGui::ColorMarkerStart)));