From d5b258c2672de78ce9da5f771a3aca00b13aa8ae Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 28 Jan 2020 13:15:21 +0100 Subject: [PATCH 1/6] 1st installment of object/instance labels in 3D scene --- src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/AppConfig.cpp | 5 + src/slic3r/GUI/GLCanvas3D.cpp | 142 +++++++++++++++++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 26 +++++ src/slic3r/GUI/GUI_Preview.cpp | 3 + src/slic3r/GUI/KBShortcutsDialog.cpp | 3 + src/slic3r/GUI/Preferences.cpp | 9 ++ 7 files changed, 190 insertions(+) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 0728dedc60..bb494343bc 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -62,5 +62,7 @@ // Enhance reload from disk to be able to work with 3mf/amf files saved with PrusaSlicer 2.1.0 and earlier #define ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK (1 && ENABLE_2_2_0_BETA1) +// Enable showing object/instance info with labels into the 3D scene +#define ENABLE_SHOW_SCENE_LABELS (1 && ENABLE_2_2_0_BETA1) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index a410f3ad8d..925346ee7d 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -95,6 +95,11 @@ void AppConfig::set_defaults() set("use_free_camera", "0"); #endif // ENABLE_6DOF_CAMERA +#if ENABLE_SHOW_SCENE_LABELS + if (get("show_labels").empty()) + set("show_labels", "0"); +#endif // ENABLE_SHOW_SCENE_LABELS + // Remove legacy window positions/sizes erase("", "main_frame_maximized"); erase("", "main_frame_pos"); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8805dc92c8..3035097ff1 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -65,6 +65,10 @@ #include #endif // ENABLE_RENDER_STATISTICS +#if ENABLE_SHOW_SCENE_LABELS +#include +#endif // ENABLE_SHOW_SCENE_LABELS + static const float TRACKBALLSIZE = 0.8f; static const float DEFAULT_BG_DARK_COLOR[3] = { 0.478f, 0.478f, 0.478f }; @@ -1230,6 +1234,136 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const } } +#if ENABLE_SHOW_SCENE_LABELS +void GLCanvas3D::Labels::show(bool show) +{ + bool shown = is_shown(); + if (shown != show) + { + wxGetApp().app_config->set("show_labels", show ? "1" : "0"); + wxGetApp().app_config->save(); + } +} + +bool GLCanvas3D::Labels::is_shown() const +{ + return wxGetApp().app_config->get("show_labels") == "1"; +} + +void GLCanvas3D::Labels::render(const GLCanvas3D& canvas) const +{ + if (!m_enabled || !is_shown()) + return; + + const Camera& camera = canvas.get_camera(); + const Model* model = canvas.get_model(); + if (model == nullptr) + return; + + Transform3d world_to_eye = camera.get_view_matrix(); + Transform3d world_to_screen = camera.get_projection_matrix() * world_to_eye; + const std::array& viewport = camera.get_viewport(); + + struct Owner + { + int obj_idx; + int inst_idx; + BoundingBoxf3 world_box; + double eye_center_z; + std::string id_str; + bool selected; + }; + + // collect world bounding boxes from volumes + std::vector owners; + const GLVolumeCollection& volumes = canvas.get_volumes(); + for (const GLVolume* volume : volumes.volumes) + { + int obj_idx = volume->object_idx(); + if ((0 <= obj_idx) && (obj_idx < (int)model->objects.size())) + { + int inst_idx = volume->instance_idx(); + std::vector::iterator it = std::find_if(owners.begin(), owners.end(), [obj_idx, inst_idx](const Owner& owner) { + return (owner.obj_idx == obj_idx) && (owner.inst_idx == inst_idx); + }); + if (it != owners.end()) + { + it->world_box.merge(volume->transformed_bounding_box()); + it->selected &= volume->selected; + } + else + { + Owner owner; + owner.obj_idx = obj_idx; + owner.inst_idx = inst_idx; + owner.world_box = volume->transformed_bounding_box(); + owner.selected = volume->selected; + owner.id_str = "object" + std::to_string(obj_idx) + "_inst##" + std::to_string(inst_idx); + owners.push_back(owner); + } + } + } + + // calculate eye bounding boxes center zs + for (Owner& owner : owners) + { + owner.eye_center_z = (world_to_eye * owner.world_box.center())(2); + } + + // sort owners by center eye zs and selection + std::sort(owners.begin(), owners.end(), [](const Owner& owner1, const Owner& owner2) { + if (!owner1.selected && owner2.selected) + return true; + else if (owner1.selected && !owner2.selected) + return false; + else + return (owner1.eye_center_z < owner2.eye_center_z); + }); + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + + // render info windows + for (const Owner& owner : owners) + { + Vec3d screen_box_center = world_to_screen * owner.world_box.center(); + float x = 0.0f; + float y = 0.0f; + if (camera.get_type() == Camera::Perspective) + { + x = (0.5f + 0.001f * 0.5f * (float)screen_box_center(0)) * viewport[2]; + y = (0.5f - 0.001f * 0.5f * (float)screen_box_center(1)) * viewport[3]; + } + else + { + x = (0.5f + 0.5f * (float)screen_box_center(0)) * viewport[2]; + y = (0.5f - 0.5f * (float)screen_box_center(1)) * viewport[3]; + } + + if ((x < 0.0f) || (viewport[2] < x) || (y < 0.0f) || (viewport[3] < y)) + continue; + + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, owner.selected ? 3.0f : 1.5f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleColor(ImGuiCol_Border, owner.selected ? ImVec4(0.757f, 0.404f, 0.216f, 1.0f) : ImVec4(0.75f, 0.75f, 0.75f, 1.0f)); + imgui.set_next_window_pos(x, y, ImGuiCond_Always, 0.5f, 0.5f); + imgui.begin(owner.id_str, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); + float win_w = ImGui::GetWindowWidth(); + std::string object_str = model->objects[owner.obj_idx]->name; + ImGui::SetCursorPosX(0.5f * (win_w - imgui.calc_text_size(object_str).x)); + ImGui::AlignTextToFramePadding(); + imgui.text(object_str); + std::string instance_str = _(L("Instance ")) + std::to_string(owner.inst_idx + 1); + ImGui::SetCursorPosX(0.5f * (win_w - imgui.calc_text_size(instance_str).x)); + ImGui::AlignTextToFramePadding(); + imgui.text(instance_str); + imgui.end(); + ImGui::PopStyleColor(); + ImGui::PopStyleVar(2); + } +} +#endif // ENABLE_SHOW_SCENE_LABELS + wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); @@ -2646,6 +2780,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } case 'B': case 'b': { zoom_to_bed(); break; } +#if ENABLE_SHOW_SCENE_LABELS + case 'E': + case 'e': { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; } +#endif // ENABLE_SHOW_SCENE_LABELS case 'I': case 'i': { _update_camera_zoom(1.0); break; } case 'K': @@ -4732,6 +4870,10 @@ void GLCanvas3D::_render_overlays() const _render_undoredo_toolbar(); _render_view_toolbar(); +#if ENABLE_SHOW_SCENE_LABELS + m_labels.render(*this); +#endif // ENABLE_SHOW_SCENE_LABELS + if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f)) m_layers_editing.render_overlay(*this); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index a7f272f975..2ad32a6e50 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -373,6 +373,19 @@ private: }; #endif // ENABLE_RENDER_STATISTICS +#if ENABLE_SHOW_SCENE_LABELS + class Labels + { + bool m_enabled{ false }; + + public: + void enable(bool enable) { m_enabled = enable; } + void show(bool show); + bool is_shown() const; + void render(const GLCanvas3D& canvas) const; + }; +#endif // ENABLE_SHOW_SCENE_LABELS + public: enum ECursorType : unsigned char { @@ -450,6 +463,10 @@ private: mutable int m_imgui_undo_redo_hovered_pos{ -1 }; int m_selected_extruder; +#if ENABLE_SHOW_SCENE_LABELS + Labels m_labels; +#endif // ENABLE_SHOW_SCENE_LABELS + public: GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar); ~GLCanvas3D(); @@ -465,6 +482,9 @@ public: void set_as_dirty(); unsigned int get_volumes_count() const; +#if ENABLE_SHOW_SCENE_LABELS + const GLVolumeCollection& get_volumes() const { return m_volumes; } +#endif // ENABLE_SHOW_SCENE_LABELS void reset_volumes(); int check_volumes_outside_state() const; @@ -476,6 +496,9 @@ public: void set_config(const DynamicPrintConfig* config); void set_process(BackgroundSlicingProcess* process); void set_model(Model* model); +#if ENABLE_SHOW_SCENE_LABELS + const Model* get_model() const { return m_model; } +#endif // ENABLE_SHOW_SCENE_LABELS const Selection& get_selection() const { return m_selection; } Selection& get_selection() { return m_selection; } @@ -523,6 +546,9 @@ public: void enable_main_toolbar(bool enable); void enable_undoredo_toolbar(bool enable); void enable_dynamic_background(bool enable); +#if ENABLE_SHOW_SCENE_LABELS + void enable_labels(bool enable) { m_labels.enable(enable); } +#endif // ENABLE_SHOW_SCENE_LABELS void allow_multisample(bool allow); void zoom_to_bed(); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index e42f8ed216..c256413a81 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -65,6 +65,9 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_ m_canvas->enable_selection(true); m_canvas->enable_main_toolbar(true); m_canvas->enable_undoredo_toolbar(true); +#if ENABLE_SHOW_SCENE_LABELS + m_canvas->enable_labels(true); +#endif // ENABLE_SHOW_SCENE_LABELS wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 268682b817..30f1d9ec0b 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -157,6 +157,9 @@ void KBShortcutsDialog::fill_shortcuts() plater_shortcuts.push_back(Shortcut("Z", L("Zoom to selected object"))); plater_shortcuts.push_back(Shortcut("I", L("Zoom in"))); plater_shortcuts.push_back(Shortcut("O", L("Zoom out"))); +#if ENABLE_SHOW_SCENE_LABELS + plater_shortcuts.push_back(Shortcut("E", L("Show/Hide object/instance labels"))); +#endif // ENABLE_SHOW_SCENE_LABELS plater_shortcuts.push_back(Shortcut(ctrl+"M", L("Show/Hide 3Dconnexion devices settings dialog"))); plater_shortcuts.push_back(Shortcut("ESC", L("Unselect gizmo / Clear selection"))); #if ENABLE_RENDER_PICKING_PASS diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 4fd63fe0ed..57748d3a83 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -144,6 +144,15 @@ void PreferencesDialog::build() } }; +#if ENABLE_SHOW_SCENE_LABELS + def.label = L("Show object/instance labels in 3D scene"); + def.type = coBool; + def.tooltip = L("If enabled, shows labels containing info about objects/instances."); + def.set_default_value(new ConfigOptionBool{ app_config->get("show_labels") == "1" }); + option = Option(def, "show_labels"); + m_optgroup_gui->append_single_option_line(option); +#endif // ENABLE_SHOW_SCENE_LABELS + def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); From 9032dadff3d861abe141d05b6b3868c52556d43e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 28 Jan 2020 15:57:02 +0100 Subject: [PATCH 2/6] Added extra frame renders to let labels grow to their final size --- src/slic3r/GUI/GLCanvas3D.cpp | 34 ++++++++++++++++++++++------------ src/slic3r/GUI/GLCanvas3D.hpp | 4 +++- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3035097ff1..b8cd6a75b7 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1250,13 +1250,13 @@ bool GLCanvas3D::Labels::is_shown() const return wxGetApp().app_config->get("show_labels") == "1"; } -void GLCanvas3D::Labels::render(const GLCanvas3D& canvas) const +void GLCanvas3D::Labels::render() const { if (!m_enabled || !is_shown()) return; - const Camera& camera = canvas.get_camera(); - const Model* model = canvas.get_model(); + const Camera& camera = m_canvas.get_camera(); + const Model* model = m_canvas.get_model(); if (model == nullptr) return; @@ -1271,12 +1271,13 @@ void GLCanvas3D::Labels::render(const GLCanvas3D& canvas) const BoundingBoxf3 world_box; double eye_center_z; std::string id_str; + std::string instance_str; bool selected; }; // collect world bounding boxes from volumes std::vector owners; - const GLVolumeCollection& volumes = canvas.get_volumes(); + const GLVolumeCollection& volumes = m_canvas.get_volumes(); for (const GLVolume* volume : volumes.volumes) { int obj_idx = volume->object_idx(); @@ -1299,6 +1300,7 @@ void GLCanvas3D::Labels::render(const GLCanvas3D& canvas) const owner.world_box = volume->transformed_bounding_box(); owner.selected = volume->selected; owner.id_str = "object" + std::to_string(obj_idx) + "_inst##" + std::to_string(inst_idx); + owner.instance_str = _(L("Instance ")) + std::to_string(inst_idx + 1); owners.push_back(owner); } } @@ -1350,13 +1352,20 @@ void GLCanvas3D::Labels::render(const GLCanvas3D& canvas) const ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); float win_w = ImGui::GetWindowWidth(); std::string object_str = model->objects[owner.obj_idx]->name; - ImGui::SetCursorPosX(0.5f * (win_w - imgui.calc_text_size(object_str).x)); + float object_str_len = imgui.calc_text_size(object_str).x; + ImGui::SetCursorPosX(0.5f * (win_w - object_str_len)); ImGui::AlignTextToFramePadding(); imgui.text(object_str); - std::string instance_str = _(L("Instance ")) + std::to_string(owner.inst_idx + 1); - ImGui::SetCursorPosX(0.5f * (win_w - imgui.calc_text_size(instance_str).x)); + float instance_str_len = imgui.calc_text_size(owner.instance_str).x; + ImGui::SetCursorPosX(0.5f * (win_w - instance_str_len)); ImGui::AlignTextToFramePadding(); - imgui.text(instance_str); + imgui.text(owner.instance_str); + + // force re-render while the windows gets to its final size (it takes several frames) + float content_w = 1 + ImGui::GetWindowContentRegionWidth(); + if ((content_w <= object_str_len) || (content_w <= instance_str_len)) + m_canvas.request_extra_frame(); + imgui.end(); ImGui::PopStyleColor(); ImGui::PopStyleVar(2); @@ -1431,6 +1440,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar , m_show_picking_texture(false) #endif // ENABLE_RENDER_PICKING_PASS , m_render_sla_auxiliaries(true) + , m_labels(*this) { if (m_canvas != nullptr) { m_timer.SetOwner(m_canvas); @@ -4870,13 +4880,13 @@ void GLCanvas3D::_render_overlays() const _render_undoredo_toolbar(); _render_view_toolbar(); -#if ENABLE_SHOW_SCENE_LABELS - m_labels.render(*this); -#endif // ENABLE_SHOW_SCENE_LABELS - if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f)) m_layers_editing.render_overlay(*this); +#if ENABLE_SHOW_SCENE_LABELS + m_labels.render(); +#endif // ENABLE_SHOW_SCENE_LABELS + glsafe(::glPopMatrix()); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2ad32a6e50..eb4aca721b 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -377,12 +377,14 @@ private: class Labels { bool m_enabled{ false }; + GLCanvas3D& m_canvas; public: + explicit Labels(GLCanvas3D& canvas) : m_canvas(canvas) {} void enable(bool enable) { m_enabled = enable; } void show(bool show); bool is_shown() const; - void render(const GLCanvas3D& canvas) const; + void render() const; }; #endif // ENABLE_SHOW_SCENE_LABELS From 6fa49f5931def8ed35b5232bc464b822c7f170c7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 3 Feb 2020 11:44:26 +0100 Subject: [PATCH 3/6] Added sequential print order id to 3D scene labels --- src/libslic3r/GCode.cpp | 6 ++- src/libslic3r/GCode.hpp | 4 ++ src/slic3r/GUI/GLCanvas3D.cpp | 95 ++++++++++++++++++++++------------- src/slic3r/GUI/GLCanvas3D.hpp | 5 +- 4 files changed, 72 insertions(+), 38 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index a53b6bd7c2..eafe66a086 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1101,7 +1101,11 @@ static inline std::vector sort_object_instances_by_max_z(c } // Produce a vector of PrintObjects in the order of their respective ModelObjects in print.model(). -static inline std::vector sort_object_instances_by_model_order(const Print &print) +#if ENABLE_SHOW_SCENE_LABELS +std::vector sort_object_instances_by_model_order(const Print& print) +#else +static inline std::vector sort_object_instances_by_model_order(const Print& print) +#endif // ENABLE_SHOW_SCENE_LABELS { // Build up map from ModelInstance* to PrintInstance* std::vector> model_instance_to_print_instance; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 10463277b0..e0f16f9fd0 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -418,6 +418,10 @@ private: friend class WipeTowerIntegration; }; +#if ENABLE_SHOW_SCENE_LABELS +std::vector sort_object_instances_by_model_order(const Print& print); +#endif // ENABLE_SHOW_SCENE_LABELS + } #endif diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 2989b6dde8..2c484d5542 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6,6 +6,9 @@ #include "polypartition.h" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/PrintConfig.hpp" +#if ENABLE_SHOW_SCENE_LABELS +#include "libslic3r/GCode.hpp" +#endif // ENABLE_SHOW_SCENE_LABELS #include "libslic3r/GCode/PreviewData.hpp" #if ENABLE_THUMBNAIL_GENERATOR #include "libslic3r/GCode/ThumbnailData.hpp" @@ -1250,7 +1253,7 @@ bool GLCanvas3D::Labels::is_shown() const return wxGetApp().app_config->get("show_labels") == "1"; } -void GLCanvas3D::Labels::render() const +void GLCanvas3D::Labels::render(const std::vector& sorted_instances) const { if (!m_enabled || !is_shown()) return; @@ -1268,47 +1271,59 @@ void GLCanvas3D::Labels::render() const { int obj_idx; int inst_idx; + size_t model_instance_id; BoundingBoxf3 world_box; double eye_center_z; - std::string id_str; - std::string instance_str; + std::string title; + std::string label; + std::string print_order; bool selected; }; - // collect world bounding boxes from volumes + // collect owners world bounding boxes and data from volumes std::vector owners; const GLVolumeCollection& volumes = m_canvas.get_volumes(); - for (const GLVolume* volume : volumes.volumes) - { + for (const GLVolume* volume : volumes.volumes) { int obj_idx = volume->object_idx(); - if ((0 <= obj_idx) && (obj_idx < (int)model->objects.size())) - { + if (0 <= obj_idx && obj_idx < (int)model->objects.size()) { int inst_idx = volume->instance_idx(); std::vector::iterator it = std::find_if(owners.begin(), owners.end(), [obj_idx, inst_idx](const Owner& owner) { return (owner.obj_idx == obj_idx) && (owner.inst_idx == inst_idx); }); - if (it != owners.end()) - { + if (it != owners.end()) { it->world_box.merge(volume->transformed_bounding_box()); it->selected &= volume->selected; - } - else - { + } else { + const ModelObject* model_object = model->objects[obj_idx]; Owner owner; owner.obj_idx = obj_idx; owner.inst_idx = inst_idx; + owner.model_instance_id = model_object->instances[inst_idx]->id().id; owner.world_box = volume->transformed_bounding_box(); + owner.title = "object" + std::to_string(obj_idx) + "_inst##" + std::to_string(inst_idx); + owner.label = model_object->name; + if (model_object->instances.size() > 1) + owner.label += " (" + std::to_string(inst_idx + 1) + ")"; owner.selected = volume->selected; - owner.id_str = "object" + std::to_string(obj_idx) + "_inst##" + std::to_string(inst_idx); - owner.instance_str = _(L("Instance ")) + std::to_string(inst_idx + 1); owners.push_back(owner); } } } + // updates print order strings + if (sorted_instances.size() > 1) { + for (int i = 0; i < sorted_instances.size(); ++i) { + size_t id = sorted_instances[i]->model_instance->id().id; + std::vector::iterator it = std::find_if(owners.begin(), owners.end(), [id](const Owner& owner) { + return owner.model_instance_id == id; + }); + if (it != owners.end()) + it->print_order = _(L("Seq.")) + "#: " + std::to_string(i + 1); + } + } + // calculate eye bounding boxes center zs - for (Owner& owner : owners) - { + for (Owner& owner : owners) { owner.eye_center_z = (world_to_eye * owner.world_box.center())(2); } @@ -1325,45 +1340,45 @@ void GLCanvas3D::Labels::render() const ImGuiWrapper& imgui = *wxGetApp().imgui(); // render info windows - for (const Owner& owner : owners) - { + for (const Owner& owner : owners) { Vec3d screen_box_center = world_to_screen * owner.world_box.center(); float x = 0.0f; float y = 0.0f; - if (camera.get_type() == Camera::Perspective) - { + if (camera.get_type() == Camera::Perspective) { x = (0.5f + 0.001f * 0.5f * (float)screen_box_center(0)) * viewport[2]; y = (0.5f - 0.001f * 0.5f * (float)screen_box_center(1)) * viewport[3]; - } - else - { + } else { x = (0.5f + 0.5f * (float)screen_box_center(0)) * viewport[2]; y = (0.5f - 0.5f * (float)screen_box_center(1)) * viewport[3]; } - if ((x < 0.0f) || (viewport[2] < x) || (y < 0.0f) || (viewport[3] < y)) + if (x < 0.0f || viewport[2] < x || y < 0.0f || viewport[3] < y) continue; ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, owner.selected ? 3.0f : 1.5f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleColor(ImGuiCol_Border, owner.selected ? ImVec4(0.757f, 0.404f, 0.216f, 1.0f) : ImVec4(0.75f, 0.75f, 0.75f, 1.0f)); imgui.set_next_window_pos(x, y, ImGuiCond_Always, 0.5f, 0.5f); - imgui.begin(owner.id_str, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + imgui.begin(owner.title, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); float win_w = ImGui::GetWindowWidth(); - std::string object_str = model->objects[owner.obj_idx]->name; - float object_str_len = imgui.calc_text_size(object_str).x; - ImGui::SetCursorPosX(0.5f * (win_w - object_str_len)); + float label_len = imgui.calc_text_size(owner.label).x; + ImGui::SetCursorPosX(0.5f * (win_w - label_len)); ImGui::AlignTextToFramePadding(); - imgui.text(object_str); - float instance_str_len = imgui.calc_text_size(owner.instance_str).x; - ImGui::SetCursorPosX(0.5f * (win_w - instance_str_len)); - ImGui::AlignTextToFramePadding(); - imgui.text(owner.instance_str); + imgui.text(owner.label); + + if (!owner.print_order.empty()) + { + ImGui::Separator(); + float po_len = imgui.calc_text_size(owner.print_order).x; + ImGui::SetCursorPosX(0.5f * (win_w - po_len)); + ImGui::AlignTextToFramePadding(); + imgui.text(owner.print_order); + } // force re-render while the windows gets to its final size (it takes several frames) float content_w = 1 + ImGui::GetWindowContentRegionWidth(); - if ((content_w <= object_str_len) || (content_w <= instance_str_len)) + if (content_w <= label_len) m_canvas.request_extra_frame(); imgui.end(); @@ -4904,7 +4919,15 @@ void GLCanvas3D::_render_overlays() const m_layers_editing.render_overlay(*this); #if ENABLE_SHOW_SCENE_LABELS - m_labels.render(); + const ConfigOptionBool* opt = dynamic_cast(m_config->option("complete_objects")); + bool sequential_print = (opt != nullptr) ? m_config->opt_bool("complete_objects") : false; + std::vector sorted_instances; + if (sequential_print) { + const Print* print = fff_print(); + if (print != nullptr) + sorted_instances = sort_object_instances_by_model_order(*print); + } + m_labels.render(sorted_instances); #endif // ENABLE_SHOW_SCENE_LABELS glsafe(::glPopMatrix()); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index df9e5f152a..24675ee30c 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -40,6 +40,9 @@ class GCodePreviewData; struct ThumbnailData; #endif // ENABLE_THUMBNAIL_GENERATOR struct SlicingParameters; +#if ENABLE_SHOW_SCENE_LABELS +struct PrintInstance; +#endif // ENABLE_SHOW_SCENE_LABELS enum LayerHeightEditActionType : unsigned int; namespace GUI { @@ -385,7 +388,7 @@ private: void enable(bool enable) { m_enabled = enable; } void show(bool show); bool is_shown() const; - void render() const; + void render(const std::vector& sorted_instances) const; }; #endif // ENABLE_SHOW_SCENE_LABELS From 1ee2f16a7145093fcf98f5d2051f869e51e052d9 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 3 Feb 2020 13:24:11 +0100 Subject: [PATCH 4/6] 3D scene labels transparent to mouse click --- 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 2c484d5542..0253e430c7 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1359,7 +1359,7 @@ void GLCanvas3D::Labels::render(const std::vector& sorted_ ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleColor(ImGuiCol_Border, owner.selected ? ImVec4(0.757f, 0.404f, 0.216f, 1.0f) : ImVec4(0.75f, 0.75f, 0.75f, 1.0f)); imgui.set_next_window_pos(x, y, ImGuiCond_Always, 0.5f, 0.5f); - imgui.begin(owner.title, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + imgui.begin(owner.title, ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); float win_w = ImGui::GetWindowWidth(); float label_len = imgui.calc_text_size(owner.label).x; From 3ec4b77dcdc210bcef2462a5d7f734abd74012d4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 4 Feb 2020 14:42:26 +0100 Subject: [PATCH 5/6] Added item menu 'Edit/Show labels' and removed labels activation from preferences dialog --- src/slic3r/GUI/AppConfig.cpp | 5 ----- src/slic3r/GUI/GLCanvas3D.cpp | 15 --------------- src/slic3r/GUI/GLCanvas3D.hpp | 10 ++++++++-- src/slic3r/GUI/MainFrame.cpp | 10 ++++++++-- src/slic3r/GUI/Plater.cpp | 10 ++++++++++ src/slic3r/GUI/Plater.hpp | 5 +++++ src/slic3r/GUI/Preferences.cpp | 9 --------- src/slic3r/GUI/wxExtensions.cpp | 10 +++++++++- src/slic3r/GUI/wxExtensions.hpp | 4 +++- 9 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 925346ee7d..a410f3ad8d 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -95,11 +95,6 @@ void AppConfig::set_defaults() set("use_free_camera", "0"); #endif // ENABLE_6DOF_CAMERA -#if ENABLE_SHOW_SCENE_LABELS - if (get("show_labels").empty()) - set("show_labels", "0"); -#endif // ENABLE_SHOW_SCENE_LABELS - // Remove legacy window positions/sizes erase("", "main_frame_maximized"); erase("", "main_frame_pos"); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 26ab4f4359..449b7fbb80 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1238,21 +1238,6 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const } #if ENABLE_SHOW_SCENE_LABELS -void GLCanvas3D::Labels::show(bool show) -{ - bool shown = is_shown(); - if (shown != show) - { - wxGetApp().app_config->set("show_labels", show ? "1" : "0"); - wxGetApp().app_config->save(); - } -} - -bool GLCanvas3D::Labels::is_shown() const -{ - return wxGetApp().app_config->get("show_labels") == "1"; -} - void GLCanvas3D::Labels::render(const std::vector& sorted_instances) const { if (!m_enabled || !is_shown()) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 24675ee30c..ae26d6f52f 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -381,13 +381,14 @@ private: class Labels { bool m_enabled{ false }; + bool m_shown{ false }; GLCanvas3D& m_canvas; public: explicit Labels(GLCanvas3D& canvas) : m_canvas(canvas) {} void enable(bool enable) { m_enabled = enable; } - void show(bool show); - bool is_shown() const; + void show(bool show) { m_shown = m_enabled ? show : false; } + bool is_shown() const { return m_shown; } void render(const std::vector& sorted_instances) const; }; #endif // ENABLE_SHOW_SCENE_LABELS @@ -676,6 +677,11 @@ public: void mouse_up_cleanup(); +#if ENABLE_SHOW_SCENE_LABELS + bool are_labels_shown() const { return m_labels.is_shown(); } + void show_labels(bool show) { m_labels.show(show); } +#endif // ENABLE_SHOW_SCENE_LABELS + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 105c6faa5f..b05155ef2e 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -550,10 +550,10 @@ void MainFrame::init_menubar() wxString hotkey_delete = "Del"; #endif append_menu_item(editMenu, wxID_ANY, _(L("&Select all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "A", - _(L("Selects all objects")), [this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->select_all(); }, + _(L("Selects all objects")), [this](wxCommandEvent&) { m_plater->select_all(); }, "", nullptr, [this](){return can_select(); }, this); append_menu_item(editMenu, wxID_ANY, _(L("D&eselect all")) + sep + "Esc", - _(L("Deselects all objects")), [this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->deselect_all(); }, + _(L("Deselects all objects")), [this](wxCommandEvent&) { m_plater->deselect_all(); }, "", nullptr, [this](){return can_deselect(); }, this); editMenu->AppendSeparator(); append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + sep + hotkey_delete, @@ -659,6 +659,12 @@ void MainFrame::init_menubar() "", nullptr, [this](){return can_change_view(); }, this); append_menu_item(viewMenu, wxID_ANY, _(L("Right")) + sep + "&6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); }, "", nullptr, [this](){return can_change_view(); }, this); +#if ENABLE_SHOW_SCENE_LABELS + viewMenu->AppendSeparator(); + append_menu_check_item(viewMenu, wxID_ANY, _(L("Show &labels")) + sep + "E", _(L("Show object/instance labels in 3D scene")), + [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this, + [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this); +#endif // ENABLE_SHOW_SCENE_LABELS } // Help menu diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index bbb7db74dd..2ff099a98d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1784,6 +1784,11 @@ struct Plater::priv bool is_preview_loaded() const { return preview->is_loaded(); } bool is_view3D_shown() const { return current_panel == view3D; } +#if ENABLE_SHOW_SCENE_LABELS + bool are_view3D_labels_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->are_labels_shown(); } + void show_view3D_labels(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_labels(show); } +#endif // ENABLE_SHOW_SCENE_LABELS + void set_current_canvas_as_dirty(); #if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK GLCanvas3D* get_current_canvas3D(); @@ -4672,6 +4677,11 @@ bool Plater::is_preview_shown() const { return p->is_preview_shown(); } bool Plater::is_preview_loaded() const { return p->is_preview_loaded(); } bool Plater::is_view3D_shown() const { return p->is_view3D_shown(); } +#if ENABLE_SHOW_SCENE_LABELS +bool Plater::are_view3D_labels_shown() const { return p->are_view3D_labels_shown(); } +void Plater::show_view3D_labels(bool show) { p->show_view3D_labels(show); } +#endif // ENABLE_SHOW_SCENE_LABELS + void Plater::select_all() { p->select_all(); } void Plater::deselect_all() { p->deselect_all(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 568727abf3..bd562d17e7 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -170,6 +170,11 @@ public: bool is_preview_loaded() const; bool is_view3D_shown() const; +#if ENABLE_SHOW_SCENE_LABELS + bool are_view3D_labels_shown() const; + void show_view3D_labels(bool show); +#endif // ENABLE_SHOW_SCENE_LABELS + // Called after the Preferences dialog is closed and the program settings are saved. // Update the UI based on the current preferences. void update_ui_from_settings(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 57748d3a83..4fd63fe0ed 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -144,15 +144,6 @@ void PreferencesDialog::build() } }; -#if ENABLE_SHOW_SCENE_LABELS - def.label = L("Show object/instance labels in 3D scene"); - def.type = coBool; - def.tooltip = L("If enabled, shows labels containing info about objects/instances."); - def.set_default_value(new ConfigOptionBool{ app_config->get("show_labels") == "1" }); - option = Option(def, "show_labels"); - m_optgroup_gui->append_single_option_line(option); -#endif // ENABLE_SHOW_SCENE_LABELS - def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 399fcdf036..f814c11dfb 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -146,7 +146,8 @@ wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, } wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description, - std::function cb, wxEvtHandler* event_handler) + std::function cb, wxEvtHandler* event_handler, + std::function const enable_condition, std::function const check_condition, wxWindow* parent) { if (id == wxID_ANY) id = wxNewId(); @@ -160,6 +161,13 @@ wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, #endif // __WXMSW__ menu->Bind(wxEVT_MENU, cb, id); + if (parent) + parent->Bind(wxEVT_UPDATE_UI, [enable_condition, check_condition](wxUpdateUIEvent& evt) + { + evt.Enable(enable_condition()); + evt.Check(check_condition()); + }, id); + return item; } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 55dac54332..d4679f757c 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -34,7 +34,9 @@ wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, std::function cb, wxEvtHandler* event_handler); wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description, - std::function cb, wxEvtHandler* event_handler); + std::function cb, wxEvtHandler* event_handler, + std::function const enable_condition = []() { return true; }, + std::function const check_condition = []() { return true; }, wxWindow* parent = nullptr); void enable_menu_item(wxUpdateUIEvent& evt, std::function const cb_condition, wxMenuItem* item, wxWindow* win); From a04c72b0c9f0e1fc2c14506761a3463b98c34f39 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 5 Feb 2020 15:27:11 +0100 Subject: [PATCH 6/6] Fixed unneded auto-extra frame render --- 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 449b7fbb80..3b38403fdf 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1363,7 +1363,7 @@ void GLCanvas3D::Labels::render(const std::vector& sorted_ // force re-render while the windows gets to its final size (it takes several frames) float content_w = 1 + ImGui::GetWindowContentRegionWidth(); - if (content_w <= label_len) + if (content_w < label_len) m_canvas.request_extra_frame(); imgui.end();