diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index f7e1d2616..94aea8fa6 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -650,6 +650,19 @@ private: friend class ModelVolume; }; +struct TextInfo +{ + std::string m_font_name; + float m_font_size = 16.f; + int m_curr_font_idx = 0; + bool m_bold = true; + bool m_italic = false; + float m_thickness = 2.f; + std::string m_text; + + template void serialize(Archive &ar) { ar(m_font_name, m_font_size, m_curr_font_idx, m_bold, m_italic, m_thickness, m_text); } +}; + // An object STL, or a modifier volume, over which a different set of parameters shall be applied. // ModelVolume instances are owned by a ModelObject. class ModelVolume final : public ObjectBase @@ -799,6 +812,9 @@ public: void convert_from_imperial_units(); void convert_from_meters(); + void set_text_info(const TextInfo& text_info) { m_text_info = text_info; } + const TextInfo& get_text_info() const { return m_text_info; } + const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } void set_new_unique_id() { @@ -843,6 +859,8 @@ private: mutable Polygon m_cached_2d_polygon; //BBS, used for convex_hell_2d acceleration Geometry::Transformation m_transformation; + TextInfo m_text_info; + //BBS: add convex_hell_2d related logic void calculate_convex_hull_2d(const Geometry::Transformation &transformation) const; @@ -961,7 +979,7 @@ private: // BBS: add backup, check modify bool mesh_changed = false; auto tr = m_transformation; - 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_text_info); mesh_changed |= !(tr == m_transformation); if (mesh_changed) m_transformation.get_matrix(true, true, true, true); // force dirty auto t = supported_facets.timestamp(); @@ -987,7 +1005,7 @@ 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_text_info); cereal::save_by_value(ar, supported_facets); cereal::save_by_value(ar, seam_facets); cereal::save_by_value(ar, mmu_segmentation_facets); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 0d8a6d1d4..5cf7858d5 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2158,7 +2158,7 @@ void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name #endif /* _DEBUG */ } -void ObjectList::load_mesh_part(const TriangleMesh& mesh, const wxString& name, bool center) +void ObjectList::load_mesh_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, bool center) { wxDataViewItem item = GetSelection(); // we can add volumes for Object or Instance @@ -2181,9 +2181,11 @@ void ObjectList::load_mesh_part(const TriangleMesh& mesh, const wxString& name, ModelVolume* mv = mo->add_volume(mesh); Vec3d instance_bbox = mo->mesh().bounding_box().size(); - Vec3d offset = Vec3d(0, 0, instance_bbox[2] / 2); + Vec3d offset = Vec3d(0, 0, instance_bbox[2] / 2 + mv->get_offset(Axis::Z)); mv->set_offset(offset); mv->name = name.ToStdString(); + if (!text_info.m_text.empty()) + mv->set_text_info(text_info); std::vector volumes; volumes.push_back(mv); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 8ce1b81e7..35ff3c919 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -27,6 +27,7 @@ class ModelConfig; class ModelObject; class ModelVolume; class TriangleMesh; +class TextInfo; enum class ModelVolumeType : int; // FIXME: broken build on mac os because of this is missing: @@ -283,7 +284,7 @@ public: void load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center = true); // BBS void switch_to_object_process(); - void load_mesh_part(const TriangleMesh& mesh, const wxString& name, bool center = true); + void load_mesh_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, bool center = true); void del_object(const int obj_idx, bool refresh_immediately = true); void del_subobject_item(wxDataViewItem& item); void del_settings_from_config(const wxDataViewItem& parent_item); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index f5e54ce56..7ec7dda49 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -5,6 +5,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" +#include "slic3r/GUI/Plater.hpp" #include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Model.hpp" @@ -85,6 +86,23 @@ void GLGizmoText::update_font_texture() void GLGizmoText::on_set_state() { + if (m_state == EState::On && m_parent.get_selection().is_single_volume()) { + ModelVolume *model_volume = get_selected_single_volume(m_object_idx, m_volume_idx); + TextInfo text_info = model_volume->get_text_info(); + if (!text_info.m_text.empty()) { + m_font_name = text_info.m_font_name; + m_font_size = text_info.m_font_size; + m_curr_font_idx = text_info.m_curr_font_idx; + m_bold = text_info.m_bold; + m_italic = text_info.m_italic; + m_thickness = text_info.m_thickness; + strcpy(m_text, text_info.m_text.c_str()); + m_is_modify = true; + } + } + else if (m_state == EState::Off) { + reset_text_info(); + } } CommonGizmosDataID GLGizmoText::on_get_requirements() const @@ -101,7 +119,15 @@ bool GLGizmoText::on_is_activable() const { // This is assumed in GLCanvas3D::do_rotate, do not change this // without updating that function too. - return m_parent.get_selection().is_single_full_instance(); + if (m_parent.get_selection().is_single_full_instance()) + return true; + + int obejct_idx, volume_idx; + ModelVolume *model_volume = get_selected_single_volume(obejct_idx, volume_idx); + if (model_volume) + return !model_volume->get_text_info().m_text.empty(); + + return false; } void GLGizmoText::on_render() @@ -197,6 +223,35 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) return; } + const Selection &selection = m_parent.get_selection(); + if (selection.is_single_full_instance() || selection.is_single_full_object()) { + const GLVolume * gl_volume = selection.get_volume(*selection.get_volume_idxs().begin()); + int object_idx = gl_volume->object_idx(); + if (object_idx != m_object_idx || (object_idx == m_object_idx && m_volume_idx != -1)) { + m_object_idx = object_idx; + m_volume_idx = -1; + reset_text_info(); + } + } else if (selection.is_single_volume()) { + int object_idx, volume_idx; + ModelVolume *model_volume = get_selected_single_volume(object_idx, volume_idx); + if ((object_idx != m_object_idx || (object_idx == m_object_idx && volume_idx != m_volume_idx)) + && model_volume) { + TextInfo text_info = model_volume->get_text_info(); + m_font_name = text_info.m_font_name; + m_font_size = text_info.m_font_size; + m_curr_font_idx = text_info.m_curr_font_idx; + m_bold = text_info.m_bold; + m_italic = text_info.m_italic; + m_thickness = text_info.m_thickness; + strcpy(m_text, text_info.m_text.c_str()); + + m_is_modify = true; + m_volume_idx = volume_idx; + m_object_idx = object_idx; + } + } + const float win_h = ImGui::GetWindowHeight(); y = std::min(y, bottom_limit - win_h); GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); @@ -305,17 +360,43 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) float offset = caption_size + input_text_size - m_imgui->calc_text_size(_L("Add")).x - space_size; ImGui::Dummy({0.0, 0.0}); ImGui::SameLine(offset); - bool add_clicked = m_imgui->button(_L("Add")); - if (add_clicked) { + bool btn_clicked = m_imgui->button(m_is_modify ? _L("Modify") : _L("Add")); + if (btn_clicked) { m_imgui->disabled_end(); GizmoImguiEnd(); ImGui::PopStyleVar(); ImGuiWrapper::pop_toolbar_style(); + TextInfo text_info; + text_info.m_font_name = m_font_name; + text_info.m_font_size = m_font_size; + text_info.m_curr_font_idx = m_curr_font_idx; + text_info.m_bold = m_bold; + text_info.m_italic = m_italic; + text_info.m_thickness = m_thickness; + text_info.m_text = m_text; TriangleMesh mesh; load_text_shape(m_text, m_font_name.c_str(), m_font_size, m_thickness, m_bold, m_italic, mesh); - ObjectList* obj_list = wxGetApp().obj_list(); - obj_list->load_mesh_part(mesh, "text_shape"); + + if (m_is_modify) { + Plater *plater = wxGetApp().plater(); + if (!plater) + return; + + plater->take_snapshot("Modify Text"); + const Selection &selection = m_parent.get_selection(); + ModelObject * model_object = selection.get_model()->objects[m_object_idx]; + ModelVolume * model_volume = model_object->volumes[m_volume_idx]; + ModelVolume * new_model_volume = model_object->add_volume(*model_volume, std::move(mesh)); + new_model_volume->set_text_info(text_info); + new_model_volume->set_transformation(model_volume->get_transformation()); + std::swap(model_object->volumes[m_volume_idx], model_object->volumes.back()); + model_object->delete_volume(model_object->volumes.size() - 1); + plater->update(); + } else { + ObjectList *obj_list = wxGetApp().obj_list(); + obj_list->load_mesh_part(mesh, "text_shape", text_info); + } return; } @@ -335,5 +416,31 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGuiWrapper::pop_toolbar_style(); } +ModelVolume *GLGizmoText::get_selected_single_volume(int &out_object_idx, int &out_volume_idx) const +{ + if (m_parent.get_selection().is_single_volume()) { + const Selection &selection = m_parent.get_selection(); + const GLVolume * gl_volume = selection.get_volume(*selection.get_volume_idxs().begin()); + out_object_idx = gl_volume->object_idx(); + ModelObject *model_object = selection.get_model()->objects[out_object_idx]; + out_volume_idx = gl_volume->volume_idx(); + ModelVolume *model_volume = model_object->volumes[out_volume_idx]; + return model_volume; + } + return nullptr; +} + +void GLGizmoText::reset_text_info() +{ + m_font_name = ""; + m_font_size = 16.f; + m_curr_font_idx = 0; + m_bold = true; + m_italic = false; + m_thickness = 2.f; + strcpy(m_text, m_font_name.c_str()); + m_is_modify = false; +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp index 668e6bf0f..1fc3239ac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp @@ -8,6 +8,7 @@ namespace Slic3r { enum class ModelVolumeType : int; +class ModelVolume; namespace GUI { @@ -38,6 +39,10 @@ private: std::vector m_textures; + bool m_is_modify = false; + int m_object_idx; + int m_volume_idx; + public: GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); ~GLGizmoText(); @@ -57,6 +62,10 @@ protected: virtual void on_set_state() override; virtual CommonGizmosDataID on_get_requirements() const override; virtual void on_render_input_window(float x, float y, float bottom_limit); + +private: + ModelVolume *get_selected_single_volume(int& out_object_idx, int& out_volume_idx) const; + void reset_text_info(); }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 855fee055..f7be45b04 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -1501,7 +1501,7 @@ void GLGizmosManager::update_on_off_state(const Vec2d& mouse_pos) if (idx != Undefined && m_gizmos[idx]->is_activable() && m_hover == idx) { activate_gizmo(m_current == idx ? Undefined : (EType)idx); // BBS - wxGetApp().obj_list()->select_object_item((EType)idx <= Scale); + wxGetApp().obj_list()->select_object_item((EType) idx <= Scale || (EType) idx == Text); } }