From 8add695de92713b6e60150fe9013f7131e30ba3a Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 15 Sep 2021 15:14:04 +0200 Subject: [PATCH] Add editing of text volume --- src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/Emboss.cpp | 39 ++- src/libslic3r/Emboss.hpp | 41 +-- src/libslic3r/Model.hpp | 6 + src/libslic3r/TextConfiguration.hpp | 70 +++++ src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 389 ++++++++++++++++++++---- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 25 +- 7 files changed, 440 insertions(+), 131 deletions(-) create mode 100644 src/libslic3r/TextConfiguration.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 605fb8b845..5cbacc3d7b 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -206,6 +206,7 @@ add_library(libslic3r STATIC Technologies.hpp Tesselate.cpp Tesselate.hpp + TextConfiguration.hpp TriangleMesh.cpp TriangleMesh.hpp TriangleMeshSlicer.cpp diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index b9a94eeda0..12ae090959 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -10,18 +10,6 @@ using namespace Slic3r; -Emboss::FontItem::FontItem(const std::string &name, const std::string &path) - : name(name), path(path), type(Type::file_path) -{} -Emboss::FontItem::FontItem(const std::string &name, const std::string &path, Type type) - : name(name), path(path), type(type) -{} -Emboss::FontItem::FontItem(const std::wstring &name, const std::wstring &path) - : name(boost::nowide::narrow(name.c_str())) - , path(boost::nowide::narrow(path.c_str())) - , type(Type::file_path) -{} - // do not expose out of this file stbtt_ data types class Privat { @@ -30,6 +18,9 @@ public: static std::optional load_font_info(const Emboss::Font &font); static std::optional get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness = 2.f); + + + static FontItem create_font_item(std::wstring name, std::wstring path); }; std::optional Privat::load_font_info(const Emboss::Font &font) @@ -103,6 +94,11 @@ std::optional Privat::get_glyph(stbtt_fontinfo &font_info, int un return glyph; } +FontItem Privat::create_font_item(std::wstring name, std::wstring path) { + return FontItem(boost::nowide::narrow(name.c_str()), + boost::nowide::narrow(path.c_str())); +} + #ifdef _WIN32 #include #include @@ -238,15 +234,14 @@ void get_OS_font() } -Emboss::FontList Emboss::get_font_list() +FontList Emboss::get_font_list() { //auto a = get_font_path(L"none"); - get_OS_font(); + //get_OS_font(); //choose_font_dlg(); //FontList list1 = get_font_list_by_enumeration(); //FontList list2 = get_font_list_by_register(); - //FontList list3 = get_font_list_by_folder(); - + //FontList list3 = get_font_list_by_folder(); return get_font_list_by_register(); } @@ -260,7 +255,7 @@ bool exists_file(const std::wstring &name) } } -Emboss::FontList Emboss::get_font_list_by_register() { +FontList Emboss::get_font_list_by_register() { static const LPWSTR fontRegistryPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; HKEY hKey; LONG result; @@ -310,7 +305,7 @@ Emboss::FontList Emboss::get_font_list_by_register() { if (pos >= font_name_w.size()) continue; // remove TrueType text from name font_name_w = std::wstring(font_name_w, 0, pos); - font_list.emplace_back(font_name_w, path_w); + font_list.emplace_back(Privat::create_font_item(font_name_w, path_w)); } while (result != ERROR_NO_MORE_ITEMS); delete[] font_name; delete[] fileTTF_name; @@ -336,7 +331,7 @@ bool CALLBACK EnumFamCallBack(LPLOGFONT lplf, UNREFERENCED_PARAMETER(lpntm); } -Emboss::FontList Emboss::get_font_list_by_enumeration() { +FontList Emboss::get_font_list_by_enumeration() { HDC hDC = GetDC(NULL); std::vector font_names; @@ -345,12 +340,12 @@ Emboss::FontList Emboss::get_font_list_by_enumeration() { FontList font_list; for (const std::wstring &font_name : font_names) { - font_list.emplace_back(font_name, L""); + font_list.emplace_back(Privat::create_font_item(font_name, L"")); } return font_list; } -Emboss::FontList Emboss::get_font_list_by_folder() { +FontList Emboss::get_font_list_by_folder() { FontList result; WCHAR winDir[MAX_PATH]; UINT winDir_size = GetWindowsDirectory(winDir, MAX_PATH); @@ -367,7 +362,7 @@ Emboss::FontList Emboss::get_font_list_by_folder() { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; std::wstring file_name(fd.cFileName); // TODO: find font name instead of filename - result.emplace_back(file_name, search_dir + file_name); + result.emplace_back(Privat::create_font_item(file_name, search_dir + file_name)); } while (::FindNextFile(hFind, &fd)); ::FindClose(hFind); } diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index c740e3d8ef..29c972a7b5 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -7,6 +7,7 @@ #include #include // indexed_triangle_set #include "Polygon.hpp" +#include "TextConfiguration.hpp" namespace Slic3r { @@ -19,28 +20,10 @@ class Emboss public: Emboss() = delete; - struct FontItem - { - std::string name; - std::string path; - enum class Type; - Type type; - FontItem(const std::string &name, const std::string &path); - FontItem(const std::string &name, const std::string &path, Type type); - FontItem(const std::wstring &name, const std::wstring &path); - - // way of load font described in path string - enum class Type { - file_path, // path is file loacation on computer - no move between computers - wx_font_descr // path is font descriptor generated by wxWidgets - limits for os/language move - }; - }; - using FontList = std::vector; - /// /// Collect fonts registred inside OS /// - /// OS resistred TTF font files(full path) with names + /// OS registred TTF font files(full path) with names static FontList get_font_list(); #ifdef _WIN32 static FontList get_font_list_by_register(); @@ -55,24 +38,6 @@ public: /// File path to font when found static std::optional get_font_path(const std::wstring &font_face_name); - // user defined font property - struct FontProp - { - // define extra space between letters, negative mean closer letter - int char_gap = 0; - // define extra space between lines, negative mean closer lines - int line_gap = 0; - // Precision of lettter outline curve in conversion to lines - float flatness = 2.0; - // Height of letter [in mm] - float size_in_mm = 10; - // Z depth of text [in mm] - float emboss = 5; - // TODO: add enum class Align: center/left/right - - FontProp() = default; - }; - // description of one letter struct Glyph { @@ -185,7 +150,7 @@ public: return std::make_pair(res.first * m_scale, res.second * m_scale); } - float m_scale; + float m_scale; }; }; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index ba3156139a..dd875074bc 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -14,12 +14,14 @@ #include "Arrange.hpp" #include "CustomGCode.hpp" #include "enum_bitmask.hpp" +#include "TextConfiguration.hpp" #include #include #include #include #include +#include namespace cereal { class BinaryInputArchive; @@ -636,6 +638,10 @@ public: // List of mesh facets painted for MMU segmentation. FacetsAnnotation mmu_segmentation_facets; + // Is set only when volume is Embossed Text type + // Contain information how to re-create volume + std::optional text_configuration; + // A parent object owning this modifier volume. ModelObject* get_object() const { return this->object; } ModelVolumeType type() const { return m_type; } diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp new file mode 100644 index 0000000000..e4e334877c --- /dev/null +++ b/src/libslic3r/TextConfiguration.hpp @@ -0,0 +1,70 @@ +#ifndef slic3r_TextConfiguration_hpp_ +#define slic3r_TextConfiguration_hpp_ + +#include +#include + +namespace Slic3r { + +// represent selected font +// Name must be human readable is visible in gui +// (Path + Type) must define how to open font for using on different OS +struct FontItem +{ + std::string name; + std::string path; + enum class Type; + Type type; + + FontItem() : type(Type::undefined) {} + FontItem(const std::string &name, const std::string &path, Type type = Type::file_path) + : name(name), path(path), type(type) + {} + + // way of load font described in path string + enum class Type { + undefined = 0, + file_path, // path is file loacation on computer - no move between computers + wx_font_descr, // path is font descriptor generated by wxWidgets - limits for os/language move + }; +}; +using FontList = std::vector; + +// user defined font property +struct FontProp +{ + // define extra space between letters, negative mean closer letter + int char_gap = 0; + // define extra space between lines, negative mean closer lines + int line_gap = 0; + // Precision of lettter outline curve in conversion to lines + float flatness = 2.0; + // Height of letter [in mm] + float size_in_mm = 10; + // Z depth of text [in mm] + float emboss = 5; + // TODO: add enum class Align: center/left/right + + FontProp() = default; +}; + +// define how to create 'Text volume' +struct TextConfiguration +{ + // define font + FontItem font_item; + // user modification of font + FontProp font_prop; + + std::string text; + + TextConfiguration() = default; + TextConfiguration(const FontItem & font_item, + const FontProp & font_prop, + const std::string &text) + : font_item(font_item), font_prop(font_prop), text(text) + {} +}; +} // namespace Slic3r + +#endif // slic3r_TextConfiguration_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 641cb9e781..f6d4c7b4ab 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -8,6 +8,8 @@ #include "libslic3r/Model.hpp" +#include "nanosvg/nanosvg.h" // load SVG file + #include #include @@ -21,13 +23,12 @@ public: // os specific load of wxFont static std::optional load_font(const wxFont &font); // Must be in gui because of wxWidget - static std::optional load_font(const Emboss::FontItem &fi); + static std::optional load_font(const FontItem &fi); - - static Slic3r::Emboss::FontItem get_font_item(const wxFont &font); + static FontItem get_font_item(const wxFont &font); // load font used by Operating system as default GUI - static Slic3r::Emboss::FontItem get_os_font(); + static FontItem get_os_font(); static std::string get_human_readable_name(const wxFont &font); // serialize / deserialize font @@ -52,23 +53,20 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent) { // TODO: suggest to use https://fontawesome.com/ // (copy & paste) unicode symbols from web - bool is_font_loaded = load_font(); - add_fonts(Emboss::get_font_list()); - add_fonts({WxFontUtils::get_os_font()}); - if (!is_font_loaded) { + bool is_font_loaded = load_font(); + FontList fl = Emboss::get_font_list(); + m_font_list.insert(m_font_list.end(), fl.begin(), fl.end()); + m_font_list.emplace_back(WxFontUtils::get_os_font()); + while (!is_font_loaded && !m_font_list.empty()) { // can't load so erase it from list m_font_list.erase(m_font_list.begin() + m_font_selected); - m_font_selected = 0; // select first - do{ - is_font_loaded = load_font(); - if (!is_font_loaded) m_font_list.erase(m_font_list.begin()); - } while (!is_font_loaded && !m_font_list.empty()); + m_font_selected = 0; // select first + is_font_loaded = load_font(); } - int index = 0; - for (char &c : _u8L("Embossed text")) { m_text[index++] = c; } - m_text[index] = '\0'; + sort_fonts(); + set_default_configuration(); } GLGizmoEmboss::~GLGizmoEmboss() {} @@ -88,50 +86,156 @@ std::string GLGizmoEmboss::on_get_name() const void GLGizmoEmboss::on_render() {} void GLGizmoEmboss::on_render_for_picking() {} +// took from nanosvgrast.h function nsvgRasterize->nsvg__flattenShape +void flatten_cubic_bez(Slic3r::Polygon &polygon, + float tessTol, + float x1, + float y1, + float x2, + float y2, + float x3, + float y3, + float x4, + float y4, + int level) +{ + float x12, y12, x23, y23, x34, y34, x123, y123, x234, y234, x1234, + y1234; + float dx, dy, d2, d3; + + if (level == 0) return; + + x12 = (x1 + x2) * 0.5f; + y12 = (y1 + y2) * 0.5f; + x23 = (x2 + x3) * 0.5f; + y23 = (y2 + y3) * 0.5f; + x34 = (x3 + x4) * 0.5f; + y34 = (y3 + y4) * 0.5f; + x123 = (x12 + x23) * 0.5f; + y123 = (y12 + y23) * 0.5f; + + dx = x4 - x1; + dy = y4 - y1; + d2 = std::abs(((x2 - x4) * dy - (y2 - y4) * dx)); + d3 = std::abs(((x3 - x4) * dy - (y3 - y4) * dx)); + + if ((d2 + d3) * (d2 + d3) < tessTol * (dx * dx + dy * dy)) { + polygon.points.emplace_back(x4, y4); + return; + } + + --level; + if (level == 0) return; + x234 = (x23 + x34) * 0.5f; + y234 = (y23 + y34) * 0.5f; + x1234 = (x123 + x234) * 0.5f; + y1234 = (y123 + y234) * 0.5f; + flatten_cubic_bez(polygon, tessTol, x1, y1, x12, y12, x123, y123, x1234, y1234, level); + flatten_cubic_bez(polygon, tessTol, x1234, y1234, x234, y234, x34, y34, x4, y4, level); +} + +Slic3r::ExPolygons to_ExPolygons(NSVGimage *image, + float tessTol = 10., + int max_level = 10) +{ + Polygons polygons; + for (NSVGshape *shape = image->shapes; shape != NULL; + shape = shape->next) { + if (!(shape->flags & NSVG_FLAGS_VISIBLE)) continue; + Slic3r::Polygon polygon; + if (shape->fill.type != NSVG_PAINT_NONE) { + for (NSVGpath *path = shape->paths; path != NULL; + path = path->next) { + // Flatten path + polygon.points.emplace_back(path->pts[0], path->pts[1]); + for (size_t i = 0; i < path->npts - 1; i += 3) { + float *p = &path->pts[i * 2]; + flatten_cubic_bez(polygon, tessTol, p[0], p[1], p[2], + p[3], p[4], p[5], p[6], p[7], + max_level); + } + + if (path->closed) { + polygons.push_back(polygon); + polygon = Slic3r::Polygon(); + } + } + } + polygons.push_back(polygon); + } + return union_ex(polygons); +} +#include "libslic3r/SVG.hpp" + void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) { if (!m_gui_cfg.has_value()) m_gui_cfg.emplace(GuiCfg()); + check_selection(); int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse; m_imgui->begin(on_get_name(), flag); + + if (!m_font.has_value()) { + ImGui::Text("Warning: No font is selected. Select correct one."); + } + draw_font_list(); - static std::string fontName; if (ImGui::Button(_L("choose font").c_str())) { - static wxFontData data; // keep last selected font - wxFontDialog font_dialog((wxWindow*)wxGetApp().mainframe, data); - font_dialog.SetTitle(_L("Select font for Emboss")); - if (font_dialog.ShowModal() == wxID_OK) { - data = font_dialog.GetFontData(); - wxFont font = data.GetChosenFont(); - auto fontOpt = WxFontUtils::load_font(font); - if (fontOpt.has_value()) { - Emboss::FontItem fontItem = WxFontUtils::get_font_item(font); - m_font_selected = m_font_list.size(); - add_fonts({fontItem}); - m_font = fontOpt; - process(); - } - } + choose_font_by_dialog(); + } + + ImGui::SameLine(); + if (ImGui::Button(_L("use system font").c_str())) { + wxSystemSettings ss; + wxFont f = ss.GetFont(wxSYS_DEFAULT_GUI_FONT); + size_t font_index = m_font_list.size(); + FontItem fi = WxFontUtils::get_font_item(f); + m_font_list.emplace_back(fi); + bool loaded = load_font(font_index); } - if (!fontName.empty()) ImGui::Text(fontName.c_str()); ImGui::SameLine(); draw_add_button(); - ImGui::InputFloat("Size[in mm]", &m_font_prop.size_in_mm); - ImGui::InputFloat("Emboss[in mm]", &m_font_prop.emboss); - if (ImGui::InputFloat("Flatness", &m_font_prop.flatness)) - if(m_font.has_value()) m_font->cache.clear(); - ImGui::InputInt("CharGap[in font points]", &m_font_prop.char_gap); - ImGui::InputInt("LineGap[in font points]", &m_font_prop.line_gap); - ImGui::InputFloat3("Origin", m_orientation.origin.data()); + if (ImGui::Button("add svg")) { + std::string filePath = + "C:/Users/filip/Downloads/fontawesome-free-5.15.4-web/" + "fontawesome-free-5.15.4-web/svgs/solid/bicycle.svg"; + NSVGimage *image = nsvgParseFromFile(filePath.c_str(), "mm", 96.0f); + ExPolygons polys = to_ExPolygons(image); + + for (auto &poly : polys) poly.scale(1e5); + SVG svg("converted.svg", BoundingBox(polys.front().contour.points)); + svg.draw(polys); + + nsvgDelete(image); + } + + if (ImGui::InputFloat("Size[in mm]", &m_font_prop.size_in_mm)) { + if (m_font_prop.size_in_mm < 0.1) m_font_prop.size_in_mm = 10; + process(); + } + if (ImGui::InputFloat("Emboss[in mm]", &m_font_prop.emboss)) process(); + if (ImGui::InputFloat("Flatness", &m_font_prop.flatness)) { + if (m_font.has_value()) m_font->cache.clear(); + process(); + } + if (ImGui::InputInt("CharGap[in font points]", &m_font_prop.char_gap)) process(); + if (ImGui::InputInt("LineGap[in font points]", &m_font_prop.line_gap)) process(); + + //ImGui::InputFloat3("Origin", m_orientation.origin.data()); //if (ImGui::InputFloat3("Normal", m_normal.data())) m_normal.normalize(); //if (ImGui::InputFloat3("Up", m_up.data())) m_up.normalize(); m_imgui->disabled_begin(!m_font.has_value()); - if (ImGui::Button("Preview")) process(); + + // create default text + if (m_volume == nullptr) { + if (ImGui::Button("Generate preview")) process(); + } + m_imgui->disabled_end(); ImVec2 input_size(-FLT_MIN, ImGui::GetTextLineHeight() * 6); ImGuiInputTextFlags flags = @@ -149,17 +253,7 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) // change text size int max_text_size = static_cast(m_text_size); if (ImGui::InputInt("max text size", &max_text_size, 8, 64)) { - if (max_text_size < 4) max_text_size = 4; - std::unique_ptr newData(new char[max_text_size]); - size_t index = 0; - while ((index+1) < max_text_size) { - if (m_text.get()[index] == '\0') break; - newData.get()[index] = m_text.get()[index]; - ++index; - } - newData.get()[index] = '\0'; - m_text = std::move(newData); - m_text_size = max_text_size; + set_max_text_size(static_cast(max_text_size)); } // draw 2d triangle in IMGUI @@ -172,7 +266,6 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) m_imgui->end(); } - bool GLGizmoEmboss::on_is_activable() const { return !m_parent.get_selection().is_empty(); @@ -195,8 +288,10 @@ void GLGizmoEmboss::on_set_state() } m_volume = nullptr; } else if (GLGizmoBase::m_state == GLGizmoBase::On) { + if(!set_volume()) set_default_configuration(); + // when open by hyperlink it needs to show up - //request_rerender(); + m_parent.reload_scene(true); } } @@ -263,6 +358,63 @@ bool GLGizmoEmboss::gizmo_event(SLAGizmoEventType action, return false; } +void GLGizmoEmboss::set_default_configuration() { + set_text(_u8L("Embossed text")); + m_font_prop = FontProp(); + // may be set default font? +} + +void GLGizmoEmboss::check_selection() +{ + // is text created? + if (m_volume == nullptr) return; + ModelVolume* vol = get_selected_volume(); + + // is same volume selected? + if (m_volume == vol) return; + + // Do not use actual edited value when switch volume + ImGui::SetKeyboardFocusHere(-1); + + // is selected volume embossed? + if (vol!= nullptr && vol->text_configuration.has_value()) { + m_volume = vol; + load_configuration(*vol->text_configuration); + return; + } + + // behave like adding new text + m_volume == nullptr; +} + +ModelVolume *GLGizmoEmboss::get_selected_volume() +{ + return get_selected_volume(m_parent.get_selection(), + wxGetApp().plater()->model().objects); +} + +ModelVolume *GLGizmoEmboss::get_selected_volume(const Selection &selection, + const ModelObjectPtrs objects) +{ + int object_idx = selection.get_object_idx(); + // is more object selected? + if (object_idx == -1) return nullptr; + + auto volume_idxs = selection.get_volume_idxs(); + // is more volumes selected? + if (volume_idxs.size() != 1) return nullptr; + unsigned int vol_id_gl = *volume_idxs.begin(); + const GLVolume * vol_gl = selection.get_volume(vol_id_gl); + const GLVolume::CompositeID &id = vol_gl->composite_id; + + if (id.object_id >= objects.size()) return nullptr; + ModelObject *object = objects[id.object_id]; + + if (id.volume_id >= object->volumes.size()) return nullptr; + return object->volumes[id.volume_id]; +} + +// create_text_volume() void GLGizmoEmboss::process() { if (!m_font.has_value()) return; @@ -305,6 +457,7 @@ void GLGizmoEmboss::process() { // set a default extruder value, since user can't add it manually m_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); + m_volume->text_configuration = create_configuration(); // select new added volume ModelVolume *new_volume = m_volume; @@ -343,7 +496,7 @@ void GLGizmoEmboss::draw_add_button() { if (dialog.ShowModal() == wxID_OK) dialog.GetPaths(input_files); if (input_files.IsEmpty()) return; - Emboss::FontList font_list; + FontList font_list; font_list.reserve(input_files.size()); for (auto &input_file : input_files) { std::string path = std::string(input_file.c_str()); @@ -368,7 +521,7 @@ void GLGizmoEmboss::draw_font_list() { auto ¤t = m_font_list[m_font_selected]; if (ImGui::BeginCombo("##font_selector", current.name.c_str())) { - for (const Emboss::FontItem &f : m_font_list) { + for (const FontItem &f : m_font_list) { ImGui::PushID((void *) &f.name); std::string name = (f.name.size() < m_gui_cfg->max_font_name) ? @@ -411,6 +564,14 @@ void GLGizmoEmboss::draw_font_list() } } +bool GLGizmoEmboss::load_font(size_t font_index) +{ + std::swap(font_index, m_font_selected); + bool is_loaded = load_font(); + if (!is_loaded) std::swap(font_index, m_font_selected); + return is_loaded; +} + bool GLGizmoEmboss::load_font() { if (m_font_selected >= m_font_list.size()) return false; auto font = WxFontUtils::load_font(m_font_list[m_font_selected]); @@ -419,18 +580,62 @@ bool GLGizmoEmboss::load_font() { return true; } -std::optional WxFontUtils::load_font(const Emboss::FontItem &fi) +void GLGizmoEmboss::set_text(const std::string &text) { + if (text.size() > m_text_size-1) + set_max_text_size(text.size() + 1); + + int index = 0; + for (const char &c : text) m_text[index++] = c; + m_text[index] = '\0'; +} + +void GLGizmoEmboss::set_max_text_size(size_t size) { + if (size < 4) size = 4; + std::unique_ptr newData(new char[size]); + size_t index = 0; + while ((index + 1) < size) { + if (m_text.get()[index] == '\0') break; + newData.get()[index] = m_text.get()[index]; + ++index; + } + newData.get()[index] = '\0'; + m_text = std::move(newData); + m_text_size = size; +} + +bool GLGizmoEmboss::choose_font_by_dialog() { + // keep last selected font did not work + // static wxFontData data; + // wxFontDialog font_dialog((wxWindow *) wxGetApp().mainframe, data); + + wxFontDialog font_dialog(nullptr); + font_dialog.SetTitle(_L("Select font for Emboss")); + if (font_dialog.ShowModal() != wxID_OK) return false; + wxFontData data = font_dialog.GetFontData(); + wxFont font = data.GetChosenFont(); + size_t font_index = m_font_list.size(); + m_font_list.emplace_back(WxFontUtils::get_font_item(font)); + if (!load_font(font_index)) { + m_font_list.pop_back(); + return false; + } + sort_fonts(); + process(); + return true; +} + +std::optional WxFontUtils::load_font(const FontItem &fi) { switch (fi.type) { - case Emboss::FontItem::Type::file_path: + case FontItem::Type::file_path: return Emboss::load_font(fi.path.c_str()); - case Emboss::FontItem::Type::wx_font_descr: + case FontItem::Type::wx_font_descr: return WxFontUtils::load_font(WxFontUtils::load_wxFont(fi.path)); } return {}; } -std::optional WxFontUtils::load_font(const wxFont &font) +std::optional WxFontUtils::load_font(const wxFont &font) { if (!font.IsOk()) return {}; #ifdef _WIN32 @@ -448,18 +653,18 @@ std::optional WxFontUtils::load_font(const wxFont &font) #endif } -Slic3r::Emboss::FontItem WxFontUtils::get_font_item(const wxFont &font) +FontItem WxFontUtils::get_font_item(const wxFont &font) { std::string name = get_human_readable_name(font); std::string fontDesc = store_wxFont(font); - return Emboss::FontItem(name, fontDesc, Emboss::FontItem::Type::wx_font_descr); + return FontItem(name, fontDesc, FontItem::Type::wx_font_descr); } -Slic3r::Emboss::FontItem WxFontUtils::get_os_font() +FontItem WxFontUtils::get_os_font() { wxSystemSettings ss; wxFont ss_font = ss.GetFont(wxSYS_ANSI_VAR_FONT); - Emboss::FontItem fi = get_font_item(ss_font); + FontItem fi = get_font_item(ss_font); fi.name += +" (" + _u8L("OS default") + ")"; return get_font_item(ss_font); } @@ -502,7 +707,7 @@ void GLGizmoEmboss::sort_fonts() { return m_font_list[i1].name < m_font_list[i2].name; }); - Emboss::FontList font_list; + FontList font_list; font_list.reserve(m_font_list.size()); size_t selected = 0; for (const size_t &i : idx) { @@ -513,18 +718,68 @@ void GLGizmoEmboss::sort_fonts() { m_font_selected = selected; } -void GLGizmoEmboss::add_fonts(const Emboss::FontList &font_list) { +void GLGizmoEmboss::add_fonts(const FontList &font_list) { m_font_list.insert(m_font_list.end(), font_list.begin(), font_list.end()); sort_fonts(); } +bool GLGizmoEmboss::set_volume() +{ + ModelVolume *vol = get_selected_volume(); + // Is selected only one volume + if (vol == nullptr) return false; + + // Is volume created by Emboss? + if (!vol->text_configuration.has_value()) return false; + + // set selected volume + m_volume = vol; + load_configuration(*vol->text_configuration); + return true; +} + +TextConfiguration GLGizmoEmboss::create_configuration() { + std::string text((const char *) m_text.get()); + return TextConfiguration(m_font_list[m_font_selected], m_font_prop, text); +} + +bool GLGizmoEmboss::load_configuration(const TextConfiguration &configuration) +{ + size_t index = m_font_list.size(); + for (const auto &font_item : m_font_list) { + if (font_item.type == configuration.font_item.type && + font_item.path == configuration.font_item.path) { + index = &font_item - &m_font_list.front(); + } + } + size_t prev_font_selected = m_font_selected; + // when not in font list add to list + if (index >= m_font_list.size()) { + m_font_selected = m_font_list.size(); + add_fonts({configuration.font_item}); + } else { + m_font_selected = index; + } + // When can't load font + if (!load_font()) { + // remove bad loadabled font, for correct prev index + m_font_list.erase(m_font_list.begin() + m_font_selected); + m_font_selected = prev_font_selected; + return false; + } + + m_font_prop = configuration.font_prop; + set_text(configuration.text); + return true; +} + std::string GLGizmoEmboss::create_volume_name() { size_t max_len = 20; std::string text((const char *)m_text.get()); if (text.size() > max_len) text = text.substr(0, max_len - 3) + " .."; - return _u8L("Text") + ": " + text; + return _u8L("Text") + " - " + text; } // any existing icon filename to not influence GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 9560218ef3..fbdd7197f8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -37,14 +37,31 @@ protected: virtual void on_set_state() override; private: + void set_default_configuration(); + void check_selection(); + // more general function --> move to select + ModelVolume *get_selected_volume(); + static ModelVolume *get_selected_volume(const Selection &selection, const ModelObjectPtrs objects); void process(); void close(); void draw_font_list(); void draw_add_button(); bool load_font(); + // try to set font_index + bool load_font(size_t font_index); + void set_text(const std::string &text); + void set_max_text_size(size_t size); + + bool choose_font_by_dialog(); void sort_fonts(); - void add_fonts(const Emboss::FontList &font_list); + void add_fonts(const FontList &font_list); + + bool set_volume(); + + // Create object described how to make a Volume + TextConfiguration create_configuration(); + bool load_configuration(const TextConfiguration& configuration); std::string create_volume_name(); @@ -58,15 +75,15 @@ private: }; std::optional m_gui_cfg; - Emboss::FontList m_font_list; - size_t m_font_selected;// index to m_font_list + FontList m_font_list; + size_t m_font_selected;// index to m_font_list std::optional m_font; size_t m_text_size; std::unique_ptr m_text; - Emboss::FontProp m_font_prop; + FontProp m_font_prop; // text position struct Orientation