ENH: support text modify
Change-Id: Ide5a3c7df5f3ea4395821a65807d79b459f3e46e (cherry picked from commit 55de44d4c80c545de14466aa039a7b0ac144f395)
This commit is contained in:
parent
e70253cf25
commit
1c5c9bd3d2
|
@ -650,6 +650,19 @@ private:
|
||||||
friend class ModelVolume;
|
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<typename Archive> 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.
|
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
||||||
// ModelVolume instances are owned by a ModelObject.
|
// ModelVolume instances are owned by a ModelObject.
|
||||||
class ModelVolume final : public ObjectBase
|
class ModelVolume final : public ObjectBase
|
||||||
|
@ -799,6 +812,9 @@ public:
|
||||||
void convert_from_imperial_units();
|
void convert_from_imperial_units();
|
||||||
void convert_from_meters();
|
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); }
|
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() {
|
void set_new_unique_id() {
|
||||||
|
@ -843,6 +859,8 @@ private:
|
||||||
mutable Polygon m_cached_2d_polygon; //BBS, used for convex_hell_2d acceleration
|
mutable Polygon m_cached_2d_polygon; //BBS, used for convex_hell_2d acceleration
|
||||||
Geometry::Transformation m_transformation;
|
Geometry::Transformation m_transformation;
|
||||||
|
|
||||||
|
TextInfo m_text_info;
|
||||||
|
|
||||||
//BBS: add convex_hell_2d related logic
|
//BBS: add convex_hell_2d related logic
|
||||||
void calculate_convex_hull_2d(const Geometry::Transformation &transformation) const;
|
void calculate_convex_hull_2d(const Geometry::Transformation &transformation) const;
|
||||||
|
|
||||||
|
@ -961,7 +979,7 @@ private:
|
||||||
// BBS: add backup, check modify
|
// BBS: add backup, check modify
|
||||||
bool mesh_changed = false;
|
bool mesh_changed = false;
|
||||||
auto tr = m_transformation;
|
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);
|
mesh_changed |= !(tr == m_transformation);
|
||||||
if (mesh_changed) m_transformation.get_matrix(true, true, true, true); // force dirty
|
if (mesh_changed) m_transformation.get_matrix(true, true, true, true); // force dirty
|
||||||
auto t = supported_facets.timestamp();
|
auto t = supported_facets.timestamp();
|
||||||
|
@ -987,7 +1005,7 @@ private:
|
||||||
}
|
}
|
||||||
template<class Archive> void save(Archive &ar) const {
|
template<class Archive> void save(Archive &ar) const {
|
||||||
bool has_convex_hull = m_convex_hull.get() != nullptr;
|
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, supported_facets);
|
||||||
cereal::save_by_value(ar, seam_facets);
|
cereal::save_by_value(ar, seam_facets);
|
||||||
cereal::save_by_value(ar, mmu_segmentation_facets);
|
cereal::save_by_value(ar, mmu_segmentation_facets);
|
||||||
|
|
|
@ -2158,7 +2158,7 @@ void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name
|
||||||
#endif /* _DEBUG */
|
#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();
|
wxDataViewItem item = GetSelection();
|
||||||
// we can add volumes for Object or Instance
|
// 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);
|
ModelVolume* mv = mo->add_volume(mesh);
|
||||||
Vec3d instance_bbox = mo->mesh().bounding_box().size();
|
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->set_offset(offset);
|
||||||
mv->name = name.ToStdString();
|
mv->name = name.ToStdString();
|
||||||
|
if (!text_info.m_text.empty())
|
||||||
|
mv->set_text_info(text_info);
|
||||||
|
|
||||||
std::vector<ModelVolume*> volumes;
|
std::vector<ModelVolume*> volumes;
|
||||||
volumes.push_back(mv);
|
volumes.push_back(mv);
|
||||||
|
|
|
@ -27,6 +27,7 @@ class ModelConfig;
|
||||||
class ModelObject;
|
class ModelObject;
|
||||||
class ModelVolume;
|
class ModelVolume;
|
||||||
class TriangleMesh;
|
class TriangleMesh;
|
||||||
|
class TextInfo;
|
||||||
enum class ModelVolumeType : int;
|
enum class ModelVolumeType : int;
|
||||||
|
|
||||||
// FIXME: broken build on mac os because of this is missing:
|
// 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);
|
void load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center = true);
|
||||||
// BBS
|
// BBS
|
||||||
void switch_to_object_process();
|
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_object(const int obj_idx, bool refresh_immediately = true);
|
||||||
void del_subobject_item(wxDataViewItem& item);
|
void del_subobject_item(wxDataViewItem& item);
|
||||||
void del_settings_from_config(const wxDataViewItem& parent_item);
|
void del_settings_from_config(const wxDataViewItem& parent_item);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "slic3r/GUI/GUI_App.hpp"
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||||
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
|
@ -85,6 +86,23 @@ void GLGizmoText::update_font_texture()
|
||||||
|
|
||||||
void GLGizmoText::on_set_state()
|
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
|
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
|
// This is assumed in GLCanvas3D::do_rotate, do not change this
|
||||||
// without updating that function too.
|
// 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()
|
void GLGizmoText::on_render()
|
||||||
|
@ -197,6 +223,35 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit)
|
||||||
return;
|
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();
|
const float win_h = ImGui::GetWindowHeight();
|
||||||
y = std::min(y, bottom_limit - win_h);
|
y = std::min(y, bottom_limit - win_h);
|
||||||
GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f);
|
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;
|
float offset = caption_size + input_text_size - m_imgui->calc_text_size(_L("Add")).x - space_size;
|
||||||
ImGui::Dummy({0.0, 0.0});
|
ImGui::Dummy({0.0, 0.0});
|
||||||
ImGui::SameLine(offset);
|
ImGui::SameLine(offset);
|
||||||
bool add_clicked = m_imgui->button(_L("Add"));
|
bool btn_clicked = m_imgui->button(m_is_modify ? _L("Modify") : _L("Add"));
|
||||||
if (add_clicked) {
|
if (btn_clicked) {
|
||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
GizmoImguiEnd();
|
GizmoImguiEnd();
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
ImGuiWrapper::pop_toolbar_style();
|
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;
|
TriangleMesh mesh;
|
||||||
load_text_shape(m_text, m_font_name.c_str(), m_font_size, m_thickness, m_bold, m_italic, 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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -335,5 +416,31 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit)
|
||||||
ImGuiWrapper::pop_toolbar_style();
|
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 GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
enum class ModelVolumeType : int;
|
enum class ModelVolumeType : int;
|
||||||
|
class ModelVolume;
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
@ -38,6 +39,10 @@ private:
|
||||||
|
|
||||||
std::vector<TextureInfo> m_textures;
|
std::vector<TextureInfo> m_textures;
|
||||||
|
|
||||||
|
bool m_is_modify = false;
|
||||||
|
int m_object_idx;
|
||||||
|
int m_volume_idx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||||
~GLGizmoText();
|
~GLGizmoText();
|
||||||
|
@ -57,6 +62,10 @@ protected:
|
||||||
virtual void on_set_state() override;
|
virtual void on_set_state() override;
|
||||||
virtual CommonGizmosDataID on_get_requirements() const override;
|
virtual CommonGizmosDataID on_get_requirements() const override;
|
||||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
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
|
} // namespace GUI
|
||||||
|
|
|
@ -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) {
|
if (idx != Undefined && m_gizmos[idx]->is_activable() && m_hover == idx) {
|
||||||
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
||||||
// BBS
|
// BBS
|
||||||
wxGetApp().obj_list()->select_object_item((EType)idx <= Scale);
|
wxGetApp().obj_list()->select_object_item((EType) idx <= Scale || (EType) idx == Text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue