diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index d6bd797791..ac7a8393d4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -487,7 +487,7 @@ void GLGizmoEmboss::initialize() float line_height_with_spacing = ImGui::GetTextLineHeightWithSpacing(); float space = line_height_with_spacing - line_height; - cfg.max_font_name_width = ImGui::CalcTextSize("Maximal font name").x; + cfg.max_font_name_width = ImGui::CalcTextSize("Maximal font name, extended").x; cfg.icon_width = std::ceil(line_height); // make size pair number @@ -495,24 +495,43 @@ void GLGizmoEmboss::initialize() float icon_width_with_spacing = cfg.icon_width + space; float scroll_width = icon_width_with_spacing; // TODO: fix it - cfg.combo_font_width = cfg.max_font_name_width + space + cfg.style_combobox_width = cfg.max_font_name_width + space + icon_width_with_spacing + scroll_width; cfg.delete_pos_x = cfg.max_font_name_width + space; int count_line_of_text = 3; cfg.text_size = ImVec2(-FLT_MIN, line_height_with_spacing * count_line_of_text); ImVec2 letter_m_size = ImGui::CalcTextSize("M"); - int count_letter_M_in_input = 6; + int count_letter_M_in_input = 12; cfg.advanced_input_width = letter_m_size.x * count_letter_M_in_input; GuiCfg::Translations &tr = cfg.translations; tr.font = _u8L("Font"); tr.size = _u8L("Height"); tr.depth = _u8L("Depth"); - cfg.style_edit_text_width = - 3 * space + ImGui::GetTreeNodeToLabelSpacing() + - std::max(ImGui::CalcTextSize(tr.font.c_str()).x, - std::max(ImGui::CalcTextSize(tr.size.c_str()).x, - ImGui::CalcTextSize(tr.depth.c_str()).x)); + float max_edit_text_width = std::max( + {ImGui::CalcTextSize(tr.font.c_str()).x, + ImGui::CalcTextSize(tr.size.c_str()).x, + ImGui::CalcTextSize(tr.depth.c_str()).x }); + cfg.edit_input_offset = + 3 * space + ImGui::GetTreeNodeToLabelSpacing() + max_edit_text_width; + + tr.char_gap = _u8L("Char gap"); + tr.line_gap = _u8L("Line gap"); + tr.boldness = _u8L("Boldness"); + tr.italic = _u8L("Skew ratio"); + tr.surface_distance = _u8L("Z-move"); + tr.angle = _u8L("Z-rot"); + tr.collection = _u8L("Collection"); + float max_advanced_text_width = std::max( + {ImGui::CalcTextSize(tr.char_gap.c_str()).x, + ImGui::CalcTextSize(tr.line_gap.c_str()).x, + ImGui::CalcTextSize(tr.boldness.c_str()).x, + ImGui::CalcTextSize(tr.italic.c_str()).x, + ImGui::CalcTextSize(tr.surface_distance.c_str()).x, + ImGui::CalcTextSize(tr.angle.c_str()).x, + ImGui::CalcTextSize(tr.collection.c_str()).x }); + cfg.advanced_input_offset = + 3 * space + 2* ImGui::GetTreeNodeToLabelSpacing() + max_advanced_text_width; // calculate window size const ImGuiStyle &style = ImGui::GetStyle(); @@ -525,15 +544,16 @@ void GLGizmoEmboss::initialize() input_height * 3 + // type Radios + style selector + close button tree_header + // Edit style 2 * style.WindowPadding.y; - float window_width = cfg.combo_font_width + style.WindowPadding.x * 2; + float window_width = cfg.style_combobox_width + style.WindowPadding.x * 2; cfg.minimal_window_size = ImVec2(window_width, window_height); float addition_edit_height = input_height * 3 + tree_header; cfg.minimal_window_size_with_edit = ImVec2(cfg.minimal_window_size.x, cfg.minimal_window_size.y + addition_edit_height); - - float advance_height = input_height * 6; + // 6 = charGap, LineGap, Bold, italic, surfDist, angle + // 4 = 1px for fix each edit image of drag float + float advance_height = input_height * 6 + 8; cfg.minimal_window_size_with_advance = ImVec2(cfg.minimal_window_size_with_edit.x, cfg.minimal_window_size_with_edit.y + advance_height); @@ -984,7 +1004,6 @@ void GLGizmoEmboss::draw_rename_style(bool start_rename) is_unique && !new_name.empty(); ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue; - ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width); if ((ImGui::InputText("##font name", &new_name, flags) && allow_change) || m_imgui->button(_L("ok"), ImVec2(0.f, 0.f), allow_change)) { rename_item->name = new_name; @@ -1008,9 +1027,7 @@ void GLGizmoEmboss::draw_style_list() { trunc_name = ImGuiWrapper::trunc(current_name, max_width); } - ImGui::Text("%s", _u8L("Style").c_str()); - ImGui::SameLine(); - ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width); + ImGui::SetNextItemWidth(m_gui_cfg->style_combobox_width); if (ImGui::BeginCombo("##style_selector", trunc_name.c_str())) { m_font_manager.init_style_images(m_gui_cfg->max_style_image_width); const auto &fonts = m_font_manager.get_fonts(); @@ -1070,7 +1087,8 @@ void GLGizmoEmboss::draw_style_list() { swap_indexes->second); ImGui::EndCombo(); - } + }else if (ImGui::IsItemHovered()) + ImGui::SetTooltip("%s", _u8L("Style selector").c_str()); // delete font item if (delete_index.has_value()) @@ -1223,8 +1241,8 @@ bool GLGizmoEmboss::bold_button() { void GLGizmoEmboss::draw_style_edit() { const GuiCfg::Translations &tr = m_gui_cfg->translations; ImGui::Text("%s", tr.font.c_str()); - ImGui::SameLine(m_gui_cfg->style_edit_text_width); - ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width); + ImGui::SameLine(m_gui_cfg->edit_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); draw_font_list(); ImGui::SameLine(); bool exist_change = false; @@ -1247,8 +1265,8 @@ void GLGizmoEmboss::draw_style_edit() { FontProp &font_prop = fi.prop; ImGui::Text("%s", tr.size.c_str()); - ImGui::SameLine(m_gui_cfg->style_edit_text_width); - ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width); + ImGui::SameLine(m_gui_cfg->edit_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); if (ImGui::InputFloat("##line height", &font_prop.size_in_mm, 0.1f, 1.f, "%.1f mm")) { // size can't be zero or negative if (font_prop.size_in_mm < std::numeric_limits::epsilon()) @@ -1267,8 +1285,8 @@ void GLGizmoEmboss::draw_style_edit() { #ifdef SHOW_WX_WEIGHT_INPUT if (wx_font.has_value()) { ImGui::Text("%s", "weight"); - ImGui::SameLine(m_gui_cfg->style_edit_text_width); - ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width); + ImGui::SameLine(m_gui_cfg->edit_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); int weight = wx_font->GetNumericWeight(); int min_weight = 1, max_weight = 1000; if (ImGui::SliderInt("##weight", &weight, min_weight, max_weight)) { @@ -1291,8 +1309,8 @@ void GLGizmoEmboss::draw_style_edit() { #endif // SHOW_WX_WEIGHT_INPUT ImGui::Text("%s", tr.depth.c_str()); - ImGui::SameLine(m_gui_cfg->style_edit_text_width); - ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width); + ImGui::SameLine(m_gui_cfg->edit_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); if (ImGui::InputFloat("##size in Z", &font_prop.emboss, 0.1f, 0.25, "%.2f mm")) { process(); } @@ -1317,33 +1335,46 @@ void GLGizmoEmboss::draw_advanced() FontProp &font_prop = m_font_manager.get_font_item().prop; bool exist_change = false; - float item_width = 2 * m_gui_cfg->advanced_input_width; - ImGui::SetNextItemWidth(item_width); - if (ImGuiWrapper::input_optional_int(_u8L("CharGap[in font points]").c_str(), font_prop.char_gap)) { + auto &tr = m_gui_cfg->translations; + std::string units = _u8L("font points"); + std::string units_fmt = "%.0f " + units; + ImGui::Text("%s", tr.char_gap.c_str()); + ImGui::SameLine(m_gui_cfg->advanced_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); + if (m_imgui->slider_optional_int("## CharGap [in font points]", font_prop.char_gap, -font_file->ascent/2, font_file->ascent/2, units_fmt.c_str(), 1.f, false, _L("Distance between letters"))) { // char gap is stored inside of imgui font atlas m_font_manager.clear_imgui_font(); exist_change = true; } - ImGui::SetNextItemWidth(item_width); - if (ImGuiWrapper::input_optional_int(_u8L("LineGap [in font points]").c_str(), font_prop.line_gap)) + ImGui::Text("%s", tr.line_gap.c_str()); + ImGui::SameLine(m_gui_cfg->advanced_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); + if (m_imgui->slider_optional_int("## LineGap [in font points]", font_prop.line_gap, -font_file->ascent / 2, font_file->ascent / 2, units_fmt.c_str(), 1.f, false, _L("Distance between lines"))) { + m_font_manager.clear_imgui_font(); exist_change = true; - - ImGui::SetNextItemWidth(item_width); - if (m_imgui->slider_optional_float(_u8L("Boldness [in font points]").c_str(), font_prop.boldness, -200.f, 200.f, "%.0f", 1.f, false, _L("Tiny / Wide glyphs"))) + } + + ImGui::Text("%s", tr.boldness.c_str()); + ImGui::SameLine(m_gui_cfg->advanced_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); + if (m_imgui->slider_optional_float("## Boldness [in font points]", font_prop.boldness, -200.f, 200.f, units_fmt.c_str(), 1.f, false, _L("Tiny / Wide glyphs"))) exist_change = true; - - - ImGui::SetNextItemWidth(item_width); - if (m_imgui->slider_optional_float(_u8L("Italic [Skew ratio]").c_str(), font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("Italic strength ratio"))) + + ImGui::Text("%s", tr.italic.c_str()); + ImGui::SameLine(m_gui_cfg->advanced_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); + if (m_imgui->slider_optional_float("## Italic [Skew ratio]", font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("Italic strength ratio"))) exist_change = true; float prev_distance = font_prop.distance.has_value() ? *font_prop.distance : .0f; float min_distance = -2 * font_prop.emboss, max_distance = 2 * font_prop.emboss; - ImGui::SetNextItemWidth(item_width); - if (m_imgui->slider_optional_float(_u8L("Surface distance").c_str(), font_prop.distance, + ImGui::Text("%s", tr.surface_distance.c_str()); + ImGui::SameLine(m_gui_cfg->advanced_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); + if (m_imgui->slider_optional_float("## Surface distance", font_prop.distance, min_distance, max_distance, "%.2f mm", 1.f, false, _L("Distance from model surface")) && m_volume != nullptr && m_volume->text_configuration.has_value()) { @@ -1368,8 +1399,10 @@ void GLGizmoEmboss::draw_advanced() std::optional &angle = font_prop.angle; float prev_angle = angle.has_value() ? *angle : .0f; float angle_deg = prev_angle * 180 / M_PI; - ImGui::SetNextItemWidth(item_width); - if (m_imgui->slider_float(_u8L("Angle").c_str(), &angle_deg, + ImGui::Text("%s", tr.angle.c_str()); + ImGui::SameLine(m_gui_cfg->advanced_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); + if (m_imgui->slider_float("## Angle", &angle_deg, -180.f, 180.f, u8"%.2f °", 1.f, false, _L("Rotation of text")) ){ if (std::fabs(angle_deg) < std::numeric_limits::epsilon()) { angle.reset(); @@ -1398,9 +1431,10 @@ void GLGizmoEmboss::draw_advanced() // when more collection add selector if (font_file->count > 1) { - ImGui::SetNextItemWidth(item_width); - if (ImGui::BeginCombo(_u8L("Font collection").c_str(), - std::to_string(font_file->index).c_str())) { + ImGui::Text("%s", tr.collection.c_str()); + ImGui::SameLine(m_gui_cfg->advanced_input_offset); + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); + if (ImGui::BeginCombo("## Font collection", std::to_string(font_file->index).c_str())) { for (unsigned int i = 0; i < font_file->count; ++i) { ImGui::PushID(1 << (10 + i)); bool is_selected = i == font_file->index; @@ -1411,6 +1445,8 @@ void GLGizmoEmboss::draw_advanced() ImGui::PopID(); } ImGui::EndCombo(); + } else if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", _u8L("Select from True Type Collection.").c_str()); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 5d3c597379..a159479081 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -133,7 +133,7 @@ private: ImVec2 minimal_window_size_with_edit = ImVec2(0, 0); ImVec2 minimal_window_size_with_advance = ImVec2(0, 0); float advanced_input_width = 0.f; - float combo_font_width = 0.f; + float style_combobox_width = 0.f; float delete_pos_x = 0.f; float max_font_name_width = 0.f; unsigned int icon_width = 0.f; @@ -141,16 +141,27 @@ private: float min_style_image_height = 0.f; int max_style_image_width = 0.f; - float style_edit_text_width = 0.f; + float edit_input_offset = 0.f; + float advanced_input_offset = 0.f; ImVec2 text_size; // Only translations needed for calc GUI size struct Translations { + // edit style std::string font; std::string size; std::string depth; + + // advanced + std::string char_gap; + std::string line_gap; + std::string boldness; + std::string italic; + std::string surface_distance; + std::string angle; + std::string collection; }; Translations translations; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 581c191476..929baf7fb6 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -1271,6 +1271,35 @@ bool ImGuiWrapper::slider_optional_float(const char * label, return input_optional(v, func, is_default); } +bool ImGuiWrapper::slider_optional_int(const char * label, + std::optional &v, + int v_min, + int v_max, + const char * format, + float power, + bool clamp, + const wxString & tooltip, + bool show_edit_btn) +{ + std::optional val; + if (v.has_value()) val = static_cast(*v); + auto func = [&](float &value) { + return slider_float(label, &value, v_min, v_max, format, power, clamp, tooltip, show_edit_btn); + }; + std::function is_default = + [](const float &value) -> bool { + return std::fabs(value) < 0.9f; + }; + + if (input_optional(val, func, is_default)) { + if (val.has_value()) + v = static_cast(std::round(*val)); + else + v.reset(); + return true; + } else return false; +} + std::string ImGuiWrapper::trunc(const std::string &text, float width, const char * tail) diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index a336606f42..409a953753 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -140,7 +140,9 @@ public: // Input [optional] float for nonzero value more info in ImGui::InputFloat static bool input_optional_float(const char* label, std::optional &v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); static bool drag_optional_float(const char* label, std::optional &v, float v_speed, float v_min, float v_max, const char* format, float power); + bool slider_optional_float(const char* label, std::optional &v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); + bool slider_optional_int(const char* label, std::optional &v, int v_min, int v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); /// /// Truncate text by ImGui draw function to specific width /// NOTE 1: ImGui must be initialized diff --git a/src/slic3r/Utils/FontManager.cpp b/src/slic3r/Utils/FontManager.cpp index 9a77dd8d77..d225a81d87 100644 --- a/src/slic3r/Utils/FontManager.cpp +++ b/src/slic3r/Utils/FontManager.cpp @@ -581,11 +581,14 @@ ImFont * FontManager::load_imgui_font(size_t index, const std::string &text) // TODO: start using merge mode //font_config.MergeMode = true; if (font_prop.char_gap.has_value()) { - double coef = font_size / (double)font_file.ascent; - double char_gap_double = coef * (*font_prop.char_gap); - font_config.GlyphExtraSpacing.x = - static_cast(std::round(char_gap_double)); + float coef = font_size / (double) font_file.ascent; + font_config.GlyphExtraSpacing.x = coef * (*font_prop.char_gap); } + if (font_prop.line_gap.has_value()) { + float coef = font_size / (double) font_file.ascent; + font_config.GlyphExtraSpacing.y = coef * (*font_prop.line_gap); + } + font_config.FontDataOwnedByAtlas = false; const std::vector &buffer = font_file.buffer;