diff --git a/src/imgui/imgui.h b/src/imgui/imgui.h index 8b3ba1773..c233ca6c9 100644 --- a/src/imgui/imgui.h +++ b/src/imgui/imgui.h @@ -2648,6 +2648,8 @@ struct ImFontAtlas // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin + IMGUI_API const ImWchar* GetGlyphRangesBasic(); // Basic + IMGUI_API const ImWchar* GetGlyphRangesEnglish(); // Basic Latin + Latin Supplement IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs @@ -2655,6 +2657,7 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters + IMGUI_API const ImWchar* GetGlyphRangesOthers(); //------------------------------------------- // [BETA] Custom Rectangles/Glyphs API diff --git a/src/imgui/imgui_draw.cpp b/src/imgui/imgui_draw.cpp index 70f6b0418..36e7100fd 100644 --- a/src/imgui/imgui_draw.cpp +++ b/src/imgui/imgui_draw.cpp @@ -2806,12 +2806,49 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) } } +const ImWchar* ImFontAtlas::GetGlyphRangesBasic() +{ + static const ImWchar ranges[] = + { + 0x0041, 0x005A, // A-Z + 0x0061, 0x007A, // a-z + 0x0020, 0x0021, + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesEnglish() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0, + }; + return &ranges[0]; +} + +// Retrieve list of range (2 int per range, values are inclusive) +const ImWchar* ImFontAtlas::GetGlyphRangesOthers() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0100, 0x017F, // Latin Extended-A + 0x0180, 0x024F, // Latin Extended-B + 0x2000, 0x206F, // General Punctuation + 0xFF00, 0xFFEF, // Half-width characters + 0, + }; + return &ranges[0]; +} + // Retrieve list of range (2 int per range, values are inclusive) const ImWchar* ImFontAtlas::GetGlyphRangesDefault() { static const ImWchar ranges[] = { - 0x0020, 0x01FF, // Basic Latin + Latin Supplement + 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x2000, 0x206F, // General Punctuation 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions @@ -2862,8 +2899,7 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* //------------------------------------------------------------------------- // [SECTION] ImFontAtlas glyph ranges helpers //------------------------------------------------------------------------- - -const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() +const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() // used in bold_font only { // Store 2500 regularly used characters for Simplified Chinese. // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 @@ -2919,14 +2955,14 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() 0x2000, 0x206F, // General Punctuation 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0x4e00, 0x9FAF, // CJK Ideograms - 0xFF00, 0xFFEF // Half-width characters + 0xFF00, 0xFFEF, // Half-width characters + 0X5C4F, 0X5C50 }; static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; if (!full_ranges[0]) { memcpy(full_ranges, base_ranges, sizeof(base_ranges)); - //UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); } return &full_ranges[0]; } diff --git a/src/libslic3r/Shape/TextShape.cpp b/src/libslic3r/Shape/TextShape.cpp index 9185c1b01..e8399d994 100644 --- a/src/libslic3r/Shape/TextShape.cpp +++ b/src/libslic3r/Shape/TextShape.cpp @@ -30,6 +30,17 @@ namespace Slic3r { +static std::map g_occt_fonts_maps; //map + +static const std::vector fonts_suffix{ "Bold", "Medium", "Heavy", "Italic", "Oblique", "Inclined", "Light", "Thin", +"Semibold", "ExtraBold", "ExtraBold", "Semilight", "SemiLight", "ExtraLight", "Extralight", "Ultralight", +"Condensed", "Ultra", "Extra", "Expanded", "Extended", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Noto Sans"}; + +std::map get_occt_fonts_maps() +{ + return g_occt_fonts_maps; +} + std::vector init_occt_fonts() { std::vector stdFontNames; @@ -41,9 +52,37 @@ std::vector init_occt_fonts() aFontMgr->GetAvailableFontsNames(availFontNames); stdFontNames.reserve(availFontNames.Size()); - for (auto afn : availFontNames) - stdFontNames.push_back(afn->ToCString()); + g_occt_fonts_maps.clear(); + BOOST_LOG_TRIVIAL(info) << "init_occt_fonts start"; +#ifdef __APPLE__ + //from resource + stdFontNames.push_back("HarmonyOS Sans SC"); + g_occt_fonts_maps.insert(std::make_pair("HarmoneyOS Sans SC", Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Regular.ttf")); +#endif + for (auto afn : availFontNames) { +#ifdef __APPLE__ + if(afn->String().StartsWith(".")) + continue; +#endif + bool repeat = false; + for (size_t i = 0; i < fonts_suffix.size(); i++) { + if (afn->SearchFromEnd(fonts_suffix[i]) != -1) { + repeat = true; + break; + } + } + if (repeat) + continue; + + Handle(Font_SystemFont) sys_font = aFontMgr->GetFont(afn->ToCString()); + TCollection_AsciiString font_path = sys_font->FontPath(Font_FontAspect::Font_FontAspect_Regular); + if (!font_path.IsEmpty()) { + g_occt_fonts_maps.insert(std::make_pair(afn->ToCString(), font_path.ToCString())); + stdFontNames.push_back(afn->ToCString()); + } + } + BOOST_LOG_TRIVIAL(info) << "init_occt_fonts end"; return stdFontNames; } diff --git a/src/libslic3r/Shape/TextShape.hpp b/src/libslic3r/Shape/TextShape.hpp index 0da84bb95..b0817d7fc 100644 --- a/src/libslic3r/Shape/TextShape.hpp +++ b/src/libslic3r/Shape/TextShape.hpp @@ -7,6 +7,8 @@ class TriangleMesh; extern std::vector init_occt_fonts(); extern void load_text_shape(const char* text, const char* font, const float text_height, const float thickness, bool is_bold, bool is_italic, TriangleMesh& text_mesh); +std::map get_occt_fonts_maps(); + }; // namespace Slic3r #endif // slic3r_Text_Shape_hpp_ \ No newline at end of file diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 61763b197..018fff3a5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -32,7 +32,7 @@ GLGizmoText::GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, u bool GLGizmoText::on_init() { - m_avail_font_names = init_occt_fonts(); + init_occt_fonts(); m_shortcut_key = WXK_CONTROL_T; return true; } @@ -90,6 +90,8 @@ void GLGizmoText::pop_combo_style() // BBS void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) { + static std::vector m_avail_font_names = wxGetApp().imgui()->get_fonts_names(); + const float win_h = ImGui::GetWindowHeight(); y = std::min(y, bottom_limit - win_h); GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); @@ -141,22 +143,27 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::SameLine(caption_size); ImGui::PushItemWidth(input_text_size + ImGui::GetFrameHeight() * 2); push_combo_style(currt_scale); + int font_index = m_curr_font_idx; + m_imgui->push_font_by_name(cstr_font_names[font_index]); if (ImGui::BBLBeginCombo("##Font", cstr_font_names[m_curr_font_idx], 0)) { ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(4.0f, 0.0f) * currt_scale); for (int i = 0; i < m_avail_font_names.size(); i++) { + m_imgui->push_font_by_name(m_avail_font_names[i]); const bool is_selected = (m_curr_font_idx == i); - if (ImGui::BBLSelectable(cstr_font_names[i], is_selected)) { + if (ImGui::BBLSelectable((cstr_font_names[i] + std::string("##") + std::to_string(i)).c_str(), is_selected, 0, {input_text_size + ImGui::GetFrameHeight() * 2 , 0.0f})) { m_curr_font_idx = i; m_font_name = cstr_font_names[m_curr_font_idx]; } if (is_selected) { ImGui::SetItemDefaultFocus(); } + m_imgui->pop_font_by_name(m_avail_font_names[i]); } ImGui::PopStyleVar(2); ImGui::EndCombo(); } + m_imgui->pop_font_by_name(cstr_font_names[font_index]); pop_combo_style(); ImGui::AlignTextToFramePadding(); @@ -185,6 +192,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) m_imgui->text(_L("Input text")); ImGui::SameLine(caption_size); ImGui::PushItemWidth(input_text_size); + ImGui::InputText("", m_text, sizeof(m_text)); ImGui::Separator(); @@ -201,6 +209,15 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) } m_imgui->disabled_end(); +#if 0 + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; + ImVec4 tint_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); + ImVec4 border_col = ImVec4(0.0f, 0.0f, 0.0f, 0.8f); + m_imgui->text(wxString("") << atlas->TexWidth << " * " << atlas->TexHeight); + ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); +#endif + GizmoImguiEnd(); ImGui::PopStyleVar(); ImGuiWrapper::pop_toolbar_style(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp index 121263741..257571743 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp @@ -14,8 +14,8 @@ namespace GUI { class GLGizmoText : public GLGizmoBase { private: - std::vector m_avail_font_names; - char m_text[256] = { 0 }; + //std::vector m_avail_font_names; + char m_text[1024] = { 0 }; std::string m_font_name; float m_font_size = 16.f; int m_curr_font_idx = 0; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 5448aeabd..911e659fb 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -27,6 +27,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" +#include "libslic3r/Shape/TextShape.hpp" #include "3DScene.hpp" #include "GUI.hpp" #include "I18N.hpp" @@ -353,18 +354,24 @@ void ImGuiWrapper::set_language(const std::string &language) ImGui::GetIO().Fonts->GetGlyphRangesChineseFull() : // Simplified Chinese // Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese - ImGui::GetIO().Fonts->GetGlyphRangesChineseFull(); + ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon(); m_font_cjk = true; } else if (lang == "th") { ranges = ImGui::GetIO().Fonts->GetGlyphRangesThai(); // Default + Thai characters - } else { - ranges = ImGui::GetIO().Fonts->GetGlyphRangesDefault(); // Basic Latin, Extended Latin + } + else if (lang == "en") { + ranges = ImGui::GetIO().Fonts->GetGlyphRangesEnglish(); // Basic Latin + } + else{ + ranges = ImGui::GetIO().Fonts->GetGlyphRangesOthers(); } if (ranges != m_glyph_ranges) { m_glyph_ranges = ranges; destroy_font(); } + + m_glyph_basic_ranges = ImGui::GetIO().Fonts->GetGlyphRangesBasic(); } void ImGuiWrapper::set_display_size(float w, float h) @@ -1537,6 +1544,31 @@ void ImGuiWrapper::bold_text(const std::string& str) } } +bool ImGuiWrapper::push_font_by_name(std::string font_name) +{ + auto sys_font = im_fonts_map.find(font_name); + if (sys_font != im_fonts_map.end()) { + ImFont* font = sys_font->second; + if (font && font->ContainerAtlas && font->Glyphs.Size > 4) + ImGui::PushFont(font); + else { + ImGui::PushFont(default_font); + } + return true; + } + return false; +} + +bool ImGuiWrapper::pop_font_by_name(std::string font_name) +{ + auto sys_font = im_fonts_map.find(font_name); + if (sys_font != im_fonts_map.end()) { + ImGui::PopFont(); + return true; + } + return false; +} + void ImGuiWrapper::title(const std::string& str) { if (bold_font){ @@ -1757,6 +1789,7 @@ void ImGuiWrapper::init_font(bool compress) // Create ranges of characters from m_glyph_ranges, possibly adding some OS specific special characters. ImVector ranges; + ImVector basic_ranges; ImFontAtlas::GlyphRangesBuilder builder; builder.AddRanges(m_glyph_ranges); #ifdef __APPLE__ @@ -1771,20 +1804,43 @@ void ImGuiWrapper::init_font(bool compress) cfg.OversampleH = cfg.OversampleV = 1; //FIXME replace with io.Fonts->AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, m_font_size, nullptr, ranges.Data); //https://github.com/ocornut/imgui/issues/220 - ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Regular.ttf").c_str(), m_font_size, &cfg, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); - if (font == nullptr) { - font = io.Fonts->AddFontDefault(); - if (font == nullptr) { + default_font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Regular.ttf").c_str(), m_font_size, &cfg, ImGui::GetIO().Fonts->GetGlyphRangesChineseFull()); + if (default_font == nullptr) { + default_font = io.Fonts->AddFontDefault(); + if (default_font == nullptr) { throw Slic3r::RuntimeError("ImGui: Could not load deafult font"); } } - bold_font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Bold.ttf").c_str(), m_font_size, &cfg, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); + bold_font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Bold.ttf").c_str(), m_font_size, &cfg, ranges.Data); if (bold_font == nullptr) { bold_font = io.Fonts->AddFontDefault(); if (bold_font == nullptr) { throw Slic3r::RuntimeError("ImGui: Could not load deafult font"); } } + // Add System Font + builder.Clear(); + builder.AddRanges(m_glyph_basic_ranges); + builder.BuildRanges(&basic_ranges); + + std::map sys_fonts_map = get_occt_fonts_maps(); //map + im_fonts_map.clear(); //map + BOOST_LOG_TRIVIAL(info) << "init_im_font start"; + for (auto sys_font : sys_fonts_map) { + boost::filesystem::path font_path(sys_font.second); + if (!boost::filesystem::exists(font_path)) { + BOOST_LOG_TRIVIAL(trace) << "load font = " << sys_font.first << ", path = " << font_path << " is not exists"; + continue; + } + ImFont* im_font = io.Fonts->AddFontFromFileTTF(sys_font.second.c_str(), m_font_size, &cfg, basic_ranges.Data); + if (im_font == nullptr) { + BOOST_LOG_TRIVIAL(trace) << "load font = " << sys_font.first << " failed, path = " << font_path << " is not exists"; + continue; + } + im_fonts_map.insert({ sys_font.first, im_font }); + } + BOOST_LOG_TRIVIAL(info) << "init_im_font end"; + #ifdef __APPLE__ ImFontConfig config; config.MergeMode = true; @@ -1801,11 +1857,11 @@ void ImGuiWrapper::init_font(bool compress) int rect_id = io.Fonts->CustomRects.Size; // id of the rectangle added next // add rectangles for the icons to the font atlas for (auto& icon : font_icons) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz); + io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz); for (auto& icon : font_icons_large) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2); + io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2); for (auto& icon : font_icons_extra_large) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 4, icon_sz * 4, 3.0 * font_scale + icon_sz * 4); + io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz * 4, icon_sz * 4, 3.0 * font_scale + icon_sz * 4); // Build texture atlas unsigned char* pixels; @@ -1860,6 +1916,21 @@ void ImGuiWrapper::init_font(bool compress) rect_id++; } + if (m_fonts_names.size() == 0) { + std::vector to_delete_fonts; + for (auto im_font : im_fonts_map) { + if (im_font.second->Glyphs.Size < 4) { + to_delete_fonts.push_back(im_font.first); + } + } + for (auto to_delete_font : to_delete_fonts) { + sys_fonts_map.erase(to_delete_font); + im_fonts_map.erase(to_delete_font); + } + for (auto im_font : im_fonts_map) + m_fonts_names.push_back(im_font.first); + } + // Upload texture to graphics system GLint last_texture; glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 824271878..defbf1633 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -45,6 +45,7 @@ bool menu_item_with_icon(const char *label, const char *shortcut, ImVec2 icon_si class ImGuiWrapper { const ImWchar* m_glyph_ranges{ nullptr }; + const ImWchar* m_glyph_basic_ranges { nullptr }; // Chinese, Japanese, Korean bool m_font_cjk{ false }; float m_font_size{ 18.0 }; @@ -155,6 +156,11 @@ public: void bold_text(const std::string &str); void title(const std::string& str); + // set font + const std::vector get_fonts_names() const { return m_fonts_names; } + bool push_font_by_name(std::string font_name); + bool pop_font_by_name(std::string font_name); + void disabled_begin(bool disabled); void disabled_end(); @@ -217,7 +223,10 @@ private: static void clipboard_set(void* user_data, const char* text); LastSliderStatus m_last_slider_status; + ImFont* default_font = nullptr; ImFont* bold_font = nullptr; + std::map im_fonts_map; + std::vector m_fonts_names; }; class IMTexture