diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index c21052a0c2..11d1075106 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -11,19 +11,21 @@ using namespace Slic3r; Emboss::FontItem::FontItem(const std::string &name, const std::string &path) - : name(name) - , path(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 { -public: +public: Privat() = delete; static std::optional load_font_info(const Emboss::Font &font); @@ -394,6 +396,7 @@ std::optional Emboss::load_font(std::vector data) while (font_offset >= 0) { font_offset = stbtt_GetFontOffsetForIndex(res.buffer.data(), index++); } + --index; // last one is bad // at least one font must be inside collection if (index < 1) { std::cerr << "There is no font collection inside file."; @@ -405,10 +408,29 @@ std::optional Emboss::load_font(std::vector data) auto font_info = Privat::load_font_info(res); if (!font_info.has_value()) return {}; - + const stbtt_fontinfo *info = &(*font_info); // load information about line gap - stbtt_GetFontVMetrics(&(*font_info), &res.ascent, &res.descent, - &res.linegap); + stbtt_GetFontVMetrics(info, &res.ascent, &res.descent, &res.linegap); + + // TrueType Reference Manual - The 'name' table https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html + // OpenType™ Specification - The Naming Table http://www.microsoft.com/typography/otspec/name.htm + int length = 0; + //PLATFORM_ID_UNICODE PLATFORM_ID_MAC PLATFORM_ID_ISO PLATFORM_ID_MICROSOFT + int platformId = STBTT_PLATFORM_ID_MICROSOFT; + // UNICODE_EID_UNICODE_1_0 UNICODE_EID_UNICODE_1_1 UNICODE_EID_ISO_10646 UNICODE_EID_UNICODE_2_0_BMP + // UNICODE_EID_UNICODE_2_0_FULL MS_EID_SYMBOL MS_EID_UNICODE_BMP MS_EID_SHIFTJIS MS_EID_UNICODE_FULL + // MAC_EID_ROMAN MAC_EID_JAPANESE MAC_EID_CHINESE_TRAD MAC_EID_KOREAN MAC_EID_ARABIC MAC_EID_HEBREW MAC_EID_GREEK + // MAC_EID_RUSSIAN + int encodingID = STBTT_MS_EID_SYMBOL; + // MS_LANG_ENGLISH MS_LANG_CHINESE MS_LANG_DUTCH MS_LANG_FRENCH MS_LANG_GERMAN MS_LANG_HEBREW MS_LANG_ITALIAN + // MS_LANG_JAPANESE MS_LANG_KOREAN MS_LANG_RUSSIAN MS_LANG_SPANISH MS_LANG_SWEDISH MAC_LANG_ENGLISH + // MAC_LANG_ARABIC MAC_LANG_DUTCH MAC_LANG_FRENCH MAC_LANG_GERMAN MAC_LANG_HEBREW MAC_LANG_ITALIAN + // MAC_LANG_JAPANESE MAC_LANG_KOREAN MAC_LANG_RUSSIAN MAC_LANG_SPANISH MAC_LANG_SWEDISH + // MAC_LANG_CHINESE_SIMPLIFIED MAC_LANG_CHINESE_TRAD + int languageID = STBTT_MS_LANG_ENGLISH; + int nameID = 4; // human readable - http://www.microsoft.com/typography/otspec/name.htm + const char *name_char = stbtt_GetFontNameString(info, &length, platformId, encodingID, languageID, nameID); + res.name = std::string(name_char, length); return res; } @@ -482,14 +504,10 @@ std::optional Emboss::letter2glyph(const Font &font, return Privat::get_glyph(*font_info_opt, (int) letter, flatness); } -Polygons Emboss::text2polygons(const Font & font, +Polygons Emboss::text2polygons(Font & font, const char * text, - const FontProp &font_prop, - Glyphs * cache) + const FontProp &font_prop) { - Glyphs tmp; - if (cache == nullptr) cache = &tmp; - std::optional font_info_opt; Point cursor(0, 0); @@ -504,8 +522,9 @@ Polygons Emboss::text2polygons(const Font & font, } int unicode = static_cast(wc); std::optional glyph_opt; - auto glyph_item = cache->find(unicode); - if (glyph_item != cache->end()) glyph_opt = glyph_item->second; + auto glyph_item = font.cache.find(unicode); + if (glyph_item != font.cache.end()) + glyph_opt = glyph_item->second; else { if (!font_info_opt.has_value()) { font_info_opt = Privat::load_font_info(font); @@ -514,9 +533,10 @@ Polygons Emboss::text2polygons(const Font & font, } glyph_opt = Privat::get_glyph(*font_info_opt, unicode, font_prop.flatness); + // IMPROVE: multiple loadig glyph without data // has definition inside of font? if (!glyph_opt.has_value()) continue; - cache->operator[](unicode) = *glyph_opt; + font.cache[unicode] = *glyph_opt; } // move glyph to cursor position diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 0400345143..9162cd182e 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -23,8 +23,17 @@ public: { 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; @@ -46,21 +55,6 @@ public: /// File path to font when found static std::optional get_font_path(const std::wstring &font_face_name); - /// - /// keep information from file about font - /// - struct Font - { - // loaded data from font file - std::vector buffer; - - unsigned int index=0; // index of actual file info in collection - unsigned int count=0; // count of fonts in file collection - - // vertical position is "scale*(ascent - descent + lineGap)" - int ascent=0, descent=0, linegap=0; - }; - // user defined font property struct FontProp { @@ -83,6 +77,25 @@ public: }; // cache for glyph by unicode using Glyphs = std::map; + + /// + /// keep information from file about font + /// + struct Font + { + // loaded data from font file + std::vector buffer; + + unsigned int index = 0; // index of actual file info in collection + unsigned int count = 0; // count of fonts in file collection + + // vertical position is "scale*(ascent - descent + lineGap)" + int ascent = 0, descent = 0, linegap = 0; + + std::string name; + + Emboss::Glyphs cache; + }; /// /// Load font file into buffer @@ -110,15 +123,13 @@ public: /// /// Convert text into polygons /// - /// Define fonts + /// Define fonts + cache, which could extend /// Characters to convert /// User defined property of the font - /// Cache for letter polygons /// Inner polygon cw(outer ccw) - static Polygons text2polygons(const Font & font, + static Polygons text2polygons(Font & font, const char * text, - const FontProp &font_prop, - Glyphs * cache = nullptr); + const FontProp &font_prop); /// /// Project 2d point into space diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index c0ca663477..d316ee97bd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -11,7 +11,7 @@ #include #include -namespace Slic3r::GUI { +using namespace Slic3r::GUI; GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D & parent, const std::string &icon_filename, @@ -72,46 +72,24 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse; m_imgui->begin(on_get_name(), flag); - auto& current = m_font_list[m_font_selected]; - if (ImGui::BeginCombo("##font_selector", current.name.c_str())) { - for (const Emboss::FontItem &f : m_font_list) { - ImGui::PushID((void*)&f.name); - std::string name = (f.name.size() < m_gui_cfg->max_font_name) ? - f.name : (f.name.substr(0,m_gui_cfg->max_font_name - 3) + " .."); - if (ImGui::Selectable(name.c_str(), &f == ¤t)) { - m_font_selected = &f - &m_font_list.front(); - load_font(); - process(); - } - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text((f.name + " " + f.path).c_str()); - ImGui::EndTooltip(); - } - ImGui::PopID(); - } - ImGui::EndCombo(); - } - ImGui::SameLine(); if (m_font.has_value()) { - if (ImGui::BeginCombo("##font_collection_selector", std::to_string(m_font->index).c_str())) { - for (size_t i = 0; i < m_font->count; ++i) { - ImGui::PushID(1 << 10 + i); - if (ImGui::Selectable(std::to_string(i).c_str(), - i == m_font->index)) { - m_font->index = i; - } - ImGui::PopID(); - } - ImGui::EndCombo(); - } + ImGui::Text("Selected font is %s END.", m_font->name.c_str()); + } else { + ImGui::Text("No selected font yet."); } + draw_font_list(); + - static std::string os_font; + // TODO: fix load string each render wxSystemSettings ss; wxFont ssFont = ss.GetFont(wxSYS_ANSI_VAR_FONT); - ImGui::Text("Desc %s", std::string(ssFont.GetNativeFontInfoDesc().c_str()).c_str()); + std::string fontDesc = std::string(ssFont.GetNativeFontInfoDesc().c_str()); + ImGui::Text("%s", fontDesc.c_str()); + if (ImGui::Button(_L("Load font").c_str())) { + wxFont font = load_wxFont(fontDesc); + set_font(font); + } static std::string fontName; if (ImGui::Button(_L("choose font").c_str())) { @@ -123,12 +101,11 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) wxFont font2 = data.GetChosenFont(); wxString fontDesc2 = font2.GetNativeFontInfoDesc(); fontName = std::string(fontDesc2.c_str()); - fontName = "Arial 10"; + wxString fontDesc(fontName); wxFont font(fontDesc); //font.IsOk() // m_font = Emboss::load_font(font.GetHFONT()); // load font os specific - m_font_glyph_cache.clear(); process(); } } @@ -140,7 +117,7 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) ImGui::InputFloat("Scale", &m_scale); ImGui::InputFloat("Emboss", &m_emboss); if (ImGui::InputFloat("Flatness", &m_font_prop.flatness)) - m_font_glyph_cache.clear(); + if(m_font.has_value()) m_font->cache.clear(); ImGui::InputInt("CharGap", &m_font_prop.char_gap); ImGui::InputInt("LineGap", &m_font_prop.line_gap); @@ -148,8 +125,6 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) //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(); m_imgui->disabled_end(); @@ -286,7 +261,7 @@ bool GLGizmoEmboss::gizmo_event(SLAGizmoEventType action, void GLGizmoEmboss::process() { if (!m_font.has_value()) return; - Polygons polygons = Emboss::text2polygons(*m_font, m_text.get(), m_font_prop, &m_font_glyph_cache); + Polygons polygons = Emboss::text2polygons(*m_font, m_text.get(), m_font_prop); if (polygons.empty()) return; auto project = std::make_unique( @@ -365,14 +340,87 @@ void GLGizmoEmboss::draw_add_button() { } } +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) { + ImGui::PushID((void *) &f.name); + std::string name = + (f.name.size() < m_gui_cfg->max_font_name) ? + f.name : + (f.name.substr(0, m_gui_cfg->max_font_name - 3) + " .."); + if (ImGui::Selectable(name.c_str(), &f == ¤t)) { + m_font_selected = &f - &m_font_list.front(); + load_font(); + process(); + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text((f.name + " " + f.path).c_str()); + ImGui::EndTooltip(); + } + ImGui::PopID(); + } + ImGui::EndCombo(); + } + ImGui::SameLine(); + if (m_font.has_value()) { + if (ImGui::BeginCombo("##font_collection_selector", + std::to_string(m_font->index).c_str())) { + for (size_t i = 0; i < m_font->count; ++i) { + ImGui::PushID(1 << 10 + i); + if (ImGui::Selectable(std::to_string(i).c_str(), + i == m_font->index)) { + m_font->index = i; + } + ImGui::PopID(); + } + ImGui::EndCombo(); + } + } +} + bool GLGizmoEmboss::load_font() { auto font_path = m_font_list[m_font_selected].path.c_str(); m_font = Emboss::load_font(font_path); - m_font_glyph_cache.clear(); return m_font.has_value(); } +void GLGizmoEmboss::set_font(const wxFont &font) { + //std::string m_font_name = std::string(( + // font.GetFamilyString() + " " + + // font.GetStyleString() + " " + + // font.GetWeightString() + // ).c_str()); +#ifdef _WIN32 + m_font = Emboss::load_font(font.GetHFONT()); +#elif __linux__ + // use file path +#elif __APPLE__ + const wxNativeFontInfo *info = font.GetNativeFontInfo(); + CTFontDescriptorRef descriptor = info3->GetCTFontDescriptor(); + CFDictionaryRef attribs = CTFontDescriptorCopyAttributes(descriptor); + CFStringRef url = (CFStringRef)CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute); + std::string str(CFStringGetCStringPtr(CFURLGetString(anUrl),kCFStringEncodingUTF8)); + m_font = Emboss::load_font(str); +#endif +} + +std::string GLGizmoEmboss::store_wxFont(const wxFont &font) +{ + //wxString os = wxPlatformInfo::Get().GetOperatingSystemIdName(); + wxString font_descriptor = font.GetNativeFontInfoDesc(); + return std::string(font_descriptor.c_str()); +} + +wxFont GLGizmoEmboss::load_wxFont(const std::string &font_descriptor) +{ + wxString font_descriptor_wx(font_descriptor); + return wxFont(font_descriptor_wx); +} + void GLGizmoEmboss::sort_fonts() { // initialize original index locations std::vector idx(m_font_list.size()); @@ -398,5 +446,3 @@ void GLGizmoEmboss::add_fonts(const Emboss::FontList &font_list) { m_font_list.insert(m_font_list.end(), font_list.begin(), font_list.end()); sort_fonts(); } - -} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 5c9154539e..7ad608d209 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -37,8 +37,17 @@ protected: private: void process(); void close(); + void draw_font_list(); void draw_add_button(); bool load_font(); + + // os specific set of wxFont + void set_font(const wxFont &font); + + // serialize / deserialize font + static std::string store_wxFont(const wxFont& font); + static wxFont load_wxFont(const std::string &font_descriptor); + void sort_fonts(); void add_fonts(const Emboss::FontList &font_list); @@ -56,7 +65,6 @@ private: size_t m_font_selected;// index to m_font_list std::optional m_font; - Emboss::Glyphs m_font_glyph_cache; size_t m_text_size; std::unique_ptr m_text;