From 110d81f6f7261571b2c27bb5c0b2f2fb851d8dcf Mon Sep 17 00:00:00 2001 From: "liz.li" Date: Sat, 10 Dec 2022 18:51:24 +0800 Subject: [PATCH] ENH: font preview Change-Id: I8151036cedcba9c57183414a9d134741bb2166a5 Signed-off-by: Stone Li --- src/imgui/imgui.h | 1 + src/imgui/imgui_widgets.cpp | 155 ++++++++++++++++++++++++++ src/libslic3r/Shape/TextShape.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 2 + src/slic3r/GUI/GLTexture.cpp | 126 +++++++++++++++++++-- src/slic3r/GUI/GLTexture.hpp | 5 +- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 85 +++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoText.hpp | 20 +++- 9 files changed, 372 insertions(+), 26 deletions(-) diff --git a/src/imgui/imgui.h b/src/imgui/imgui.h index c233ca6c9..750e45824 100644 --- a/src/imgui/imgui.h +++ b/src/imgui/imgui.h @@ -620,6 +620,7 @@ namespace ImGui // - A selectable highlights when hovered, and can display another color when selected. // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height + IMGUI_API bool BBLImageSelectable(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& font_size, int font_line, const ImVec4& tint_col, const ImVec2& uv0, const ImVec2& uv1, bool selected = false); IMGUI_API bool BBLSelectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. diff --git a/src/imgui/imgui_widgets.cpp b/src/imgui/imgui_widgets.cpp index 12fa977cc..810a62d7a 100644 --- a/src/imgui/imgui_widgets.cpp +++ b/src/imgui/imgui_widgets.cpp @@ -7064,6 +7064,161 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl return pressed; } +bool ImGui::BBLImageSelectable(ImTextureID user_texture_id, const ImVec2& size_arg, const ImVec2& font_size, int font_line, const ImVec4& tint_col, const ImVec2& uv0, const ImVec2& uv1, bool selected) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#BBLImageSelectable"); + PopID(); + + ImGuiSelectableFlags flags = 0; + + // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle. + ImVec2 size(size_arg.x != 0.0f ? size_arg.x : 0.0f, size_arg.y != 0.0f ? size_arg.y : 0.0f); + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(size, 0.0f); + + // Fill horizontal space + // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. + const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; + const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; + const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; + if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) size.x = ImMax(0.0f, max_x - min_x); + + // Text stays at the submission position, but bounding box may be extended on both sides + const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); + const ImVec2 text_min = ImVec2(pos.x + arrow_size, pos.y); + const ImVec2 text_max(min_x + size.x, pos.y + size.y); + + // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. + ImRect bb(min_x, pos.y, text_max.x, text_max.y); + if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) { + const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x; + const float spacing_y = style.ItemSpacing.y; + const float spacing_L = IM_FLOOR(spacing_x * 0.50f); + const float spacing_U = IM_FLOOR(spacing_y * 0.50f); + bb.Min.x -= spacing_L; + bb.Min.y -= spacing_U; + bb.Max.x += (spacing_x - spacing_L); + bb.Max.y += (spacing_y - spacing_U); + } + // if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } + + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; + if (span_all_columns) { + window->ClipRect.Min.x = window->ParentWorkRect.Min.x; + window->ClipRect.Max.x = window->ParentWorkRect.Max.x; + } + + bool item_add; + if (flags & ImGuiSelectableFlags_Disabled) { + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus; + item_add = ItemAdd(bb, id); + g.CurrentItemFlags = backup_item_flags; + } + else { + item_add = ItemAdd(bb, id); + } + + if (span_all_columns) { + window->ClipRect.Min.x = backup_clip_rect_min_x; + window->ClipRect.Max.x = backup_clip_rect_max_x; + } + + if (!item_add) return false; + + // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, + // which would be advantageous since most selectable are not selected. + if (span_all_columns && window->DC.CurrentColumns) + PushColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePushBackgroundChannel(); + + // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries + ImGuiButtonFlags button_flags = 0; + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } + if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } + if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } + if (flags & ImGuiSelectableFlags_Disabled) { button_flags |= ImGuiButtonFlags_Disabled; } + if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } + if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; } + + if (flags & ImGuiSelectableFlags_Disabled) selected = false; + + const bool was_selected = selected; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + if (hovered || g.ActiveId == id) { + ImGui::PushStyleColor(ImGuiCol_Border, GetColorU32(ImGuiCol_BorderActive)); + if (arrow_size == 0) { + RenderFrameBorder(bb.Min, ImVec2(bb.Max.x - style.WindowPadding.x, bb.Max.y), style.FrameRounding); + } + else { + RenderFrameBorder(ImVec2(bb.Min.x + style.WindowPadding.x, bb.Min.y), ImVec2(bb.Max.x - style.WindowPadding.x, bb.Max.y), style.FrameRounding); + } + ImGui::PopStyleColor(1); + } + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard + if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) { + if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { + SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent, ImRect(bb.Min - window->Pos, bb.Max - window->Pos)); + g.NavDisableHighlight = true; + } + } + if (pressed) MarkItemEdited(id); + + if (flags & ImGuiSelectableFlags_AllowItemOverlap) SetItemAllowOverlap(); + + // In this branch, Selectable() cannot toggle the selection so this will never trigger. + if (selected != was_selected) //-V547 + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + // Render + if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld)) hovered = true; + if (hovered || selected) { + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + if (arrow_size == 0) { + RenderFrame(bb.Min, ImVec2(bb.Max.x - style.WindowPadding.x, bb.Max.y), col, false, 0.0f); + } + else { + RenderFrame(ImVec2(bb.Min.x + style.WindowPadding.x, bb.Min.y), ImVec2(bb.Max.x - style.WindowPadding.x, bb.Max.y), col, false, 0.0f); + } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + } + + if (span_all_columns && window->DC.CurrentColumns) + PopColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePopBackgroundChannel(); + + if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImVec2 p_min = bb.Min + ImVec2(2 * style.ItemSpacing.x, (bb.Max.y - bb.Min.y - font_size.y) / 2); + ImVec2 p_max = p_min + font_size; + window->DrawList->AddImage(user_texture_id, p_min, p_max, uv0, uv1, GetColorU32(tint_col)); + + if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); + + // Automatically close popups + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.CurrentItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) + CloseCurrentPopup(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); + + return pressed; +} + bool ImGui::BBLSelectable(const char *label, bool selected, ImGuiSelectableFlags flags, const ImVec2 &size_arg) { ImGuiWindow *window = GetCurrentWindow(); diff --git a/src/libslic3r/Shape/TextShape.cpp b/src/libslic3r/Shape/TextShape.cpp index 1fe958721..d13bcca98 100644 --- a/src/libslic3r/Shape/TextShape.cpp +++ b/src/libslic3r/Shape/TextShape.cpp @@ -34,7 +34,7 @@ static std::map g_occt_fonts_maps; //map 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"}; +"Condensed", "Ultra", "Extra", "Expanded", "Extended", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Al Tarikh"}; std::map get_occt_fonts_maps() { diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 310d2b4d6..86d622409 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1881,6 +1881,8 @@ void GLCanvas3D::render(bool only_init) _render_overlays(); if (wxGetApp().plater()->is_render_statistic_dialog_visible()) { + ImGui::ShowMetricsWindow(); + ImGuiWrapper& imgui = *wxGetApp().imgui(); imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); imgui.text("FPS (SwapBuffers() calls per second):"); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index f0598b399..d5082c886 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -27,6 +27,7 @@ #include "libslic3r/Utils.hpp" #include "GUI_App.hpp" +#include namespace Slic3r { namespace GUI { @@ -468,7 +469,13 @@ void GLTexture::reset() m_original_width = m_original_height = 0; } -bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &font, wxColor background, wxColor foreground) +bool GLTexture::generate_from_text_string(const std::string& text_str, wxFont &font, wxColor background, wxColor foreground) +{ + int w,h,hl; + return generate_from_text(text_str, font, background, foreground); +} + +bool GLTexture::generate_from_text(const std::string &text_str, wxFont &font, wxColor background, wxColor foreground) { if (text_str.empty()) { @@ -488,7 +495,7 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f m_original_width = (int)w; m_original_height = (int)h; m_width = (int)next_highest_power_of_2((uint32_t)w); - m_height = (int)next_highest_power_of_2((uint32_t)h); + m_height = (int)next_highest_power_of_2((uint32_t)h); // generates bitmap wxBitmap bitmap(m_width, m_height); @@ -499,7 +506,7 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f // draw message memDC.SetTextForeground(*wxWHITE); - memDC.DrawLabel(msg, wxRect(0,0, m_original_width, m_original_height), wxALIGN_CENTER); + memDC.DrawLabel(msg, wxRect(0, 0, m_original_width, m_original_height), wxALIGN_CENTER); memDC.SelectObject(wxNullBitmap); @@ -508,7 +515,7 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f // prepare buffer std::vector data(4 * m_width * m_height, 0); - const unsigned char *src = image.GetData(); + const unsigned char* src = image.GetData(); /* for debug use std::ofstream fout; fout.open(text_str+std::to_string(m_width)+"_"+std::to_string(m_height)+".rgb", std::ios::out); @@ -520,7 +527,7 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f *dst++ = foreground.Red(); *dst++ = foreground.Green(); *dst++ = foreground.Blue(); - *dst++ = (unsigned char)std::min(255, *src); + *dst++ = (unsigned char)std::min(255, *src); src += 3; } } @@ -530,9 +537,9 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); if (GLEW_EXT_texture_compression_s3tc) - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); else - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); @@ -541,6 +548,111 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f return true; } +bool GLTexture::generate_texture_from_text(const std::string& text_str, wxFont& font, int& ww, int& hh, int& hl, wxColor background, wxColor foreground) +{ + if (text_str.empty()) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":no text string, should not happen\n"; + return false; + } + + wxString msg = _(text_str); + wxMemoryDC memDC; + + memDC.SetFont(font); + + // calculates texture size + wxCoord w, h, ll; + wxClientDC dc(wxGetApp().GetTopWindow()); + dc.SetFont(font); + dc.GetMultiLineTextExtent(msg, &w, &h, &ll, &font); + + + m_original_width = (int)w; + m_original_height = (int)h; + m_width = (int)next_highest_power_of_2((uint32_t)w); + m_height = (int)next_highest_power_of_2((uint32_t)h); + ww = m_width; + hh = m_height; + hl = ll; + // generates bitmap + wxBitmap bitmap(m_width, m_height); + + memDC.SelectObject(bitmap); + memDC.SetBackground(wxBrush(background)); + memDC.Clear(); + + // draw message + memDC.SetTextForeground(*wxWHITE); + + wxGCDC dc2(memDC); + dc2.SetFont(font); + dc2.SetBackground(wxBrush(background)); + dc2.SetTextForeground(*wxWHITE); + dc2.DrawLabel(msg, wxRect(0, 0, m_width, m_height), wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + + memDC.SelectObject(wxNullBitmap); + + // Convert the bitmap into a linear data ready to be loaded into the GPU. + wxImage image = bitmap.ConvertToImage(); + + // prepare buffer + std::vector data(4 * m_width * m_height, 0); + const unsigned char* src = image.GetData(); + /* for debug use + std::ofstream fout; + fout.open(text_str+std::to_string(m_width)+"_"+std::to_string(m_height)+".rgb", std::ios::out); + fout.write((const char*)src, 3 * m_width * m_height); + fout.close();*/ + bool found = false; + for (int h = 0; h < m_height; ++h) { + unsigned char* dst = data.data() + 4 * h * m_width; + for (int w = 0; w < m_width; ++w) { + *dst++ = foreground.Red(); + *dst++ = foreground.Green(); + *dst++ = foreground.Blue(); + *dst++ = (unsigned char)std::min(255, *src); + if ((*src) != background.Red() && !found) { + found = true; + if (m_height - h < font.GetPointSize()) + return false; + } + src += 3; + } + } + if (!found) + return false; + + found = false; + src -= 3; + for (int h = m_height; h > 0; --h) { + for (int w = m_width; w > 0; --w) { + if ((*src) != background.Red() && !found) { + found = true; + if (h < font.GetPointSize()) + return false; + } + src -= 3; + } + } + if (!found) + return false; + + // sends buffer to gpu + glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + glsafe(::glGenTextures(1, &m_id)); + glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); + if (GLEW_EXT_texture_compression_s3tc) + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + else + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + + return true; +} void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top) { diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index 4649b9f68..53fbe1a6a 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -106,7 +106,10 @@ namespace GUI { //BBS: add generate logic for text strings int m_original_width; int m_original_height; - bool generate_from_text_string(const std::string &text_str, wxFont &font, wxColor background = *wxBLACK, wxColor foreground = *wxWHITE); + + bool generate_texture_from_text(const std::string& text_str, wxFont& font, int& ww, int& hh, int &hl, wxColor background = *wxBLACK, wxColor foreground = *wxWHITE); + bool generate_from_text(const std::string& text_str, wxFont& font, wxColor background = *wxBLACK, wxColor foreground = *wxWHITE); + bool generate_from_text_string(const std::string& text_str, wxFont& font, wxColor background = *wxBLACK, wxColor foreground = *wxWHITE); unsigned int get_id() const { return m_id; } int get_width() const { return m_width; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 240674c9b..6d4359d43 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -185,7 +185,7 @@ public: void render() { m_tooltip.clear(); on_render(); } void render_for_picking() { on_render_for_picking(); } void render_input_window(float x, float y, float bottom_limit); - void on_change_color_mode(bool is_dark) { m_is_dark_mode = is_dark; } + virtual void on_change_color_mode(bool is_dark) { m_is_dark_mode = is_dark; } virtual std::string get_tooltip() const { return ""; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index cf92051df..f5e54ce56 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -23,20 +23,66 @@ namespace Slic3r { namespace GUI { -static double g_normal_precise = 0.0015; +static const wxColour FONT_TEXTURE_BG = wxColour(0, 0, 0, 0); +static const wxColour FONT_TEXTURE_FG = *wxWHITE; +static const int FONT_SIZE = 12; + GLGizmoText::GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { } +GLGizmoText::~GLGizmoText() +{ + for (int i = 0; i < m_textures.size(); i++) { + if (m_textures[i].texture != nullptr) + delete m_textures[i].texture; + } +} + bool GLGizmoText::on_init() { m_avail_font_names = init_occt_fonts(); + update_font_texture(); + m_scale = m_imgui->get_font_size(); m_shortcut_key = WXK_CONTROL_T; return true; } +void GLGizmoText::update_font_texture() +{ + for (int i = 0; i < m_textures.size(); i++) { + if (m_textures[i].texture != nullptr) + delete m_textures[i].texture; + } + m_combo_width = 0.0f; + m_combo_height = 0.0f; + m_textures.clear(); + m_textures.reserve(m_avail_font_names.size()); + for (int i = 0; i < m_avail_font_names.size(); i++) + { + GLTexture* texture = new GLTexture(); + auto face = wxString::FromUTF8(m_avail_font_names[i]); + auto retina_scale = m_parent.get_scale(); + wxFont font { (int)round(retina_scale * FONT_SIZE), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, face }; + int w, h, hl; + if (texture->generate_texture_from_text(m_avail_font_names[i], font, w, h, hl, FONT_TEXTURE_BG, FONT_TEXTURE_FG)) { + //if (h < m_imgui->scaled(2.f)) { + TextureInfo info; + info.texture = texture; + info.w = w; + info.h = h; + info.hl = hl; + info.font_name = m_avail_font_names[i]; + m_textures.push_back(info); + m_combo_width = std::max(m_combo_width, static_cast(texture->m_original_width)); + //} + } + } + m_combo_height = m_imgui->scaled(32.f / 15.f); +} + void GLGizmoText::on_set_state() { } @@ -114,6 +160,8 @@ void GLGizmoText::push_combo_style(const float scale) { ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG_DARK); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImGuiWrapper::COL_WINDOW_BG_DARK); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImGuiWrapper::COL_WINDOW_BG_DARK); ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f }); } else { @@ -125,6 +173,8 @@ void GLGizmoText::push_combo_style(const float scale) { ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImGuiWrapper::COL_WINDOW_BG); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImGuiWrapper::COL_WINDOW_BG); ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f }); } } @@ -132,12 +182,21 @@ void GLGizmoText::push_combo_style(const float scale) { void GLGizmoText::pop_combo_style() { ImGui::PopStyleVar(2); - ImGui::PopStyleColor(7); + ImGui::PopStyleColor(9); } // BBS void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) { + if (m_imgui->get_font_size() != m_scale) { + m_scale = m_imgui->get_font_size(); + update_font_texture(); + } + if (m_textures.size() == 0) { + BOOST_LOG_TRIVIAL(info) << "GLGizmoText has no texture"; + return; + } + const float win_h = ImGui::GetWindowHeight(); y = std::min(y, bottom_limit - win_h); GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); @@ -178,35 +237,31 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::AlignTextToFramePadding(); - const char** cstr_font_names = (const char**)calloc(m_avail_font_names.size(), sizeof(const char*)); - for (int i = 0; i < m_avail_font_names.size(); i++) - cstr_font_names[i] = m_avail_font_names[i].c_str(); - m_imgui->text(_L("Font")); 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)) { + if (ImGui::BBLBeginCombo("##Font", m_textures[m_curr_font_idx].font_name.c_str(), 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]); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 4)); + for (int i = 0; i < m_textures.size(); i++) { const bool is_selected = (m_curr_font_idx == i); - 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})) { + ImTextureID icon_id = (ImTextureID)(intptr_t)(m_textures[i].texture->get_id()); + ImVec4 tint_color = ImGui::GetStyleColorVec4(ImGuiCol_Text); + ImVec2 selectable_size(std::max((input_text_size + ImGui::GetFrameHeight() * 2), m_combo_width), m_combo_height); + if (ImGui::BBLImageSelectable(icon_id, selectable_size, { (float)m_textures[i].w, (float)m_textures[i].h }, m_textures[i].hl, tint_color, { 0, 0 }, {1, 1}, is_selected)) { m_curr_font_idx = i; - m_font_name = cstr_font_names[m_curr_font_idx]; + m_font_name = m_textures[m_curr_font_idx].font_name; } if (is_selected) { ImGui::SetItemDefaultFocus(); } - m_imgui->pop_font_by_name(m_avail_font_names[i]); } - ImGui::PopStyleVar(2); + ImGui::PopStyleVar(3); ImGui::EndCombo(); } - m_imgui->pop_font_by_name(cstr_font_names[font_index]); pop_combo_style(); ImGui::AlignTextToFramePadding(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp index 725daefb4..668e6bf0f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp @@ -3,7 +3,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/3DScene.hpp" - +#include "../GLTexture.hpp" namespace Slic3r { @@ -22,9 +22,27 @@ private: bool m_bold = true; bool m_italic = false; float m_thickness = 2.f; + float m_combo_height = 0.0f; + float m_combo_width = 0.0f; + float m_scale; + + class TextureInfo { + public: + GLTexture* texture { nullptr }; + int h; + int w; + int hl; + + std::string font_name; + }; + + std::vector m_textures; public: GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + ~GLGizmoText(); + + void update_font_texture(); protected: virtual bool on_init() override;