diff --git a/resources/icons/make_bold.svg b/resources/icons/make_bold.svg
new file mode 100644
index 000000000..c94d9a8fc
--- /dev/null
+++ b/resources/icons/make_bold.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/resources/icons/make_italic.svg b/resources/icons/make_italic.svg
new file mode 100644
index 000000000..501910a2a
--- /dev/null
+++ b/resources/icons/make_italic.svg
@@ -0,0 +1,59 @@
+
+
diff --git a/resources/icons/make_unbold.svg b/resources/icons/make_unbold.svg
new file mode 100644
index 000000000..f71400251
--- /dev/null
+++ b/resources/icons/make_unbold.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/resources/icons/make_unitalic.svg b/resources/icons/make_unitalic.svg
new file mode 100644
index 000000000..89065588a
--- /dev/null
+++ b/resources/icons/make_unitalic.svg
@@ -0,0 +1,59 @@
+
+
diff --git a/resources/icons/search.svg b/resources/icons/search.svg
index 6421c7e05..c6cdd007e 100644
--- a/resources/icons/search.svg
+++ b/resources/icons/search.svg
@@ -1,4 +1,4 @@
\ No newline at end of file
+
+
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
index b38528be7..dee562565 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
@@ -36,6 +36,11 @@
// uncomment for easier debug
//#define ALLOW_DEBUG_MODE
+#ifdef ALLOW_DEBUG_MODE
+#define ALLOW_ADD_FONT_BY_FILE
+#endif // ALLOW_DEBUG_MODE
+#define ALLOW_ADD_FONT_BY_OS_SELECTOR
+
using namespace Slic3r;
using namespace Slic3r::GUI;
@@ -66,12 +71,9 @@ void GLGizmoEmboss::set_fine_position()
const Camera &camera = wxGetApp().plater()->get_camera();
Polygon hull = CameraUtils::create_hull2d(camera, *volume);
- // TODO: fix width - showing scroll in first draw of advanced.
- ImVec2 windows_size = m_gui_cfg->draw_advanced ?
- m_gui_cfg->minimal_window_size_with_advance :
- m_gui_cfg->minimal_window_size;
+ const ImVec2 &windows_size = get_minimal_window_size();
ImVec2 offset = ImGuiWrapper::suggest_location(windows_size, hull);
- m_gui_cfg->offset = offset;
+ m_set_window_offset = offset;
return;
Polygon rect({Point(offset.x, offset.y),
@@ -214,7 +216,6 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
ModelVolume *mv = m_volume;
wxGetApp().plater()->CallAfter([trmat, mv]() {
mv->set_transformation(trmat);
- mv->set_new_unique_id();
});
m_parent.toggle_model_objects_visibility(true);
@@ -252,6 +253,7 @@ std::string GLGizmoEmboss::on_get_name() const { return _u8L("Emboss"); }
void GLGizmoEmboss::on_render() {
// no volume selected
if (m_volume == nullptr) return;
+ if (m_parent.get_selection().is_empty()) return;
if (m_temp_transformation.has_value()) {
// draw text volume on temporary position
@@ -289,12 +291,9 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
initialize();
check_selection();
- ImVec2 min_window_size = m_gui_cfg->draw_advanced ?
- m_gui_cfg->minimal_window_size_with_advance :
- m_gui_cfg->minimal_window_size;
+ // TODO: fix width - showing scroll in first draw of advanced.
+ const ImVec2 &min_window_size = get_minimal_window_size();
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, min_window_size);
- // ImGui::SetNextWindowSize(ImVec2(0, min_window_size.y),
- // ImGuiCond_::ImGuiCond_Always);
#ifdef ALLOW_DEBUG_MODE
// draw suggested position of window
@@ -302,19 +301,21 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
#endif // ALLOW_DEBUG_MODE
// check if is set window offset
- if (m_gui_cfg->offset.has_value()) {
- ImGui::SetNextWindowPos(*m_gui_cfg->offset, ImGuiCond_Always);
- // clear request on offset
- m_gui_cfg->offset = {};
+ if (m_set_window_offset.has_value()) {
+ ImGui::SetNextWindowPos(*m_set_window_offset, ImGuiCond_Always);
+ m_set_window_offset.reset();
}
- int flag = // ImGuiWindowFlags_AlwaysAutoResize |
- // ImGuiWindowFlags_NoResize |
- ImGuiWindowFlags_NoCollapse;
- m_imgui->begin(on_get_name(), flag);
+ ImGuiWindowFlags flag = //ImGuiWindowFlags_AlwaysAutoResize
+ //ImGuiWindowFlags_NoResize
+ ImGuiWindowFlags_NoCollapse
+ ;
+ bool is_open = true;
+ ImGui::Begin(on_get_name().c_str(), &is_open, flag);
draw_window();
- m_imgui->end();
+ ImGui::End();
+ if (!is_open) close();
ImGui::PopStyleVar(); // WindowMinSize
}
@@ -388,43 +389,63 @@ void GLGizmoEmboss::initialize()
{
if (m_is_initialized) return;
m_is_initialized = true;
- m_gui_cfg.emplace(GuiCfg());
- float space = ImGui::GetTextLineHeightWithSpacing() -
- ImGui::GetTextLineHeight();
- m_gui_cfg->max_font_name_width = ImGui::CalcTextSize("Maximal font name").x;
- m_gui_cfg->icon_width = ImGui::GetTextLineHeight();
- float icon_width_with_spacing = m_gui_cfg->icon_width + space;
- float scroll_width = icon_width_with_spacing; // fix
- m_gui_cfg->combo_font_width = m_gui_cfg->max_font_name_width + space
- + 3 * icon_width_with_spacing
+ GuiCfg cfg; // initialize by default values;
+
+ float line_height = ImGui::GetTextLineHeight();
+ 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.icon_width = line_height;
+ 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
+ + icon_width_with_spacing
+ scroll_width;
-
- m_gui_cfg->duplicate_pos_x = m_gui_cfg->max_font_name_width + space;
- m_gui_cfg->rename_pos_x = m_gui_cfg->duplicate_pos_x +
- icon_width_with_spacing;
- m_gui_cfg->delete_pos_x = m_gui_cfg->rename_pos_x +
- icon_width_with_spacing;
-
- m_gui_cfg->text_size = ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() *
- m_gui_cfg->count_line_of_text);
-
+ 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");
-
- m_gui_cfg->advanced_input_width = letter_m_size.x * 6;
+ int count_letter_M_in_input = 6;
+ 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));
// calculate window size
const ImGuiStyle &style = ImGui::GetStyle();
- float input_height = letter_m_size.y + style.FramePadding.y * 2.f;
- float window_width = m_gui_cfg->combo_font_width + style.WindowPadding.x * 2.f;
- float window_height = input_height * 4.f + // header + combo font + advance + button
- style.ItemSpacing.y * 3.f +
- m_gui_cfg->text_size.y +
- style.WindowPadding.y * 2.f;
- m_gui_cfg->minimal_window_size = ImVec2(window_width, window_height);
- float advance_height = (input_height + style.ItemSpacing.y) * 6.f;
- m_gui_cfg->minimal_window_size_with_advance =
- ImVec2(window_width, window_height + advance_height);
+ float window_title = line_height + 2*style.FramePadding.y;// 21
+ float input_height = line_height_with_spacing + 2*style.FramePadding.y; // 25
+ float tree_header = line_height_with_spacing; // 19
+ float window_height =
+ window_title + // window title
+ cfg.text_size.y + // text field
+ 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;
+ cfg.minimal_window_size = ImVec2(window_width, window_height);
+
+ // 94
+ 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);
+
+ // 104
+ float advance_height = input_height * 4;
+ cfg.minimal_window_size_with_advance =
+ ImVec2(cfg.minimal_window_size_with_edit.x,
+ cfg.minimal_window_size_with_edit.y + advance_height);
+
+ m_gui_cfg.emplace(cfg);
// TODO: What to do when icon was NOT loaded? Generate them?
bool success = init_icons();
@@ -584,20 +605,20 @@ void GLGizmoEmboss::draw_window()
#endif // ALLOW_DEBUG_MODE
bool exist_font_file = m_font_manager.get_font_file() != nullptr;
if (!exist_font_file) {
- ImGui::Text("%s",_u8L("Warning: No font is selected. Select correct one.").c_str());
+ m_imgui->text_colored(
+ ImGuiWrapper::COL_ORANGE_LIGHT,
+ _L("Warning: No font is selected. Select correct one."));
}
- draw_font_list();
draw_text_input();
-
- bool &advanced = m_gui_cfg->draw_advanced;
- if (ImGui::Checkbox(_u8L("Advance").c_str(), &advanced)) {
- ImVec2 window_size =
- advanced ?
- ImVec2(0, m_gui_cfg->minimal_window_size_with_advance.y) :
- m_gui_cfg->minimal_window_size;
- ImGui::SetWindowSize(window_size, ImGuiCond_Always);
- }
- if (advanced) draw_advanced();
+ draw_model_type();
+ draw_style_list();
+ if (ImGui::TreeNode(_u8L("Edit style").c_str())) {
+ draw_style_edit();
+ ImGui::TreePop();
+ if (!m_is_edit_style)
+ set_minimal_window_size(true, m_is_advanced_edit_style);
+ } else if (m_is_edit_style)
+ set_minimal_window_size(false, m_is_advanced_edit_style);
if (ImGui::Button(_u8L("Close").c_str())) close();
@@ -618,141 +639,19 @@ void GLGizmoEmboss::draw_window()
m_imgui->disabled_end();
}
-void GLGizmoEmboss::draw_font_list()
-{
- const float &max_width = m_gui_cfg->max_font_name_width;
- std::optional rename_index, delete_index, duplicate_index;
-
- const FontItem &actual_font_item = m_font_manager.get_font_item();
- const std::string ¤t_name = actual_font_item.name;
- std::string trunc_name = ImGuiWrapper::trunc(current_name, max_width);
- const auto &fonts = m_font_manager.get_fonts();
- ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
- if (ImGui::BeginCombo("##font_selector", trunc_name.c_str())) {
- // first line
- if (ImGui::Button(_u8L("Choose font").c_str())) {
- choose_font_by_wxdialog();
- store_font_list_to_app_config();
- ImGui::CloseCurrentPopup();
- } else if (ImGui::IsItemHovered())
- ImGui::SetTooltip("%s",
- _u8L("Choose from installed font inside dialog.").c_str());
-
-#ifdef ALLOW_DEBUG_MODE
- ImGui::SameLine();
- // select font file by file browser
- if (ImGui::Button(_u8L("Add File").c_str())) {
- choose_true_type_file();
- store_font_list_to_app_config();
- ImGui::CloseCurrentPopup();
- } else if (ImGui::IsItemHovered())
- ImGui::SetTooltip("%s",_u8L("add file with font(.ttf, .ttc)").c_str());
-#endif // ALLOW_DEBUG_MODE
-
- ImGui::Separator();
- for (const auto &item : fonts) {
- size_t index = &item - &fonts.front();
- const FontItem &fi = item.font_item;
- ImGui::PushID(fi.name.c_str());
- std::string name = ImGuiWrapper::trunc(fi.name, max_width);
-
- bool is_selected = (&fi == &actual_font_item);
- ImGuiSelectableFlags_ flags = ImGuiSelectableFlags_AllowItemOverlap; // allow click buttons
- if (ImGui::Selectable(name.c_str(), is_selected, flags) ) {
- if (m_font_manager.load_font(index)) process();
- } else if (ImGui::IsItemHovered())
- ImGui::SetTooltip("%s", fi.name.c_str());
-
- // reorder items
- if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) {
- int other_index = index + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
- if (other_index >= 0 && other_index < fonts.size()) {
- std::swap(m_font_manager.get_font(index),
- m_font_manager.get_font(other_index));
- // fix selected index
- if (is_selected)
- m_font_manager.select(other_index);
- else if (&fonts[other_index].font_item == &actual_font_item)
- m_font_manager.select(index);
- ImGui::ResetMouseDragDelta();
- }
- }
-
- // draw buttons rename / duplicate / delete
- ImGui::SameLine(m_gui_cfg->rename_pos_x);
- if (draw_button(IconType::rename)) rename_index = index;
- ImGui::SameLine(m_gui_cfg->duplicate_pos_x);
- if (draw_button(IconType::duplicate)) duplicate_index = index;
- ImGui::SameLine(m_gui_cfg->delete_pos_x);
- if (draw_button(IconType::erase, is_selected)) delete_index = index;
- ImGui::PopID();
- }
- ImGui::EndCombo();
- }
-
- // duplicate font item
- if (duplicate_index.has_value()) {
- m_font_manager.duplicate(*duplicate_index);
- store_font_list_to_app_config();
- }
-
- // delete font item
- if (delete_index.has_value()) {
- m_font_manager.erase(*delete_index);
- store_font_list_to_app_config();
- }
-
- // rename modal window popup
- const char *rename_popup_id = "Rename_font";
- static FontItem* rename_item;
- static std::string new_name;
- if (rename_index.has_value() && !ImGui::IsPopupOpen(rename_popup_id)) {
- ImGui::OpenPopup(rename_popup_id);
- rename_item = &m_font_manager.get_font(*rename_index).font_item;
- new_name = rename_item->name; // initialize with original copy
- }
-
- if (ImGui::BeginPopupModal(rename_popup_id, 0, ImGuiWindowFlags_AlwaysAutoResize)) {
- const std::string &original_font_name = rename_item->name;
- std::string text_in_popup = GUI::format(_u8L("Change font name (%1%): "), original_font_name);
- text_in_popup += "\n" + _u8L("NOTE: Name has to be unique in font list.");
- ImGui::Text("%s", text_in_popup.c_str());
- ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
-
- bool is_unique = true;
- for (const auto &item : m_font_manager.get_fonts()) {
- const FontItem &fi = item.font_item;
- if (&fi == rename_item) continue; // could be same as original name
- if (fi.name == new_name) is_unique = false;
- }
- bool allow_change = is_unique && !new_name.empty();
-
- ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
- 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;
- ImGui::CloseCurrentPopup();
- store_font_list_to_app_config();
- }
- ImGui::EndPopup();
- }
-}
-
void GLGizmoEmboss::draw_text_input()
{
static const ImGuiInputTextFlags flags =
ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_AutoSelectAll;
ImFont *imgui_font = m_font_manager.get_imgui_font();
- bool exist_font = imgui_font != nullptr && imgui_font->IsLoaded();
+ bool exist_font = imgui_font != nullptr && imgui_font->IsLoaded();
if (exist_font) ImGui::PushFont(imgui_font);
- bool exist_change = false;
- float window_height = ImGui::GetWindowHeight();
- float minimal_height = m_gui_cfg->draw_advanced ?
- m_gui_cfg->minimal_window_size_with_advance.y :
- m_gui_cfg->minimal_window_size.y;
- float extra_height = window_height - minimal_height;
+ bool exist_change = false;
+ float window_height = ImGui::GetWindowHeight();
+ float minimal_height = get_minimal_window_size().y;
+ float extra_height = window_height - minimal_height;
ImVec2 text_size(m_gui_cfg->text_size.x,
m_gui_cfg->text_size.y + extra_height);
if (ImGui::InputTextMultiline("##Text", &m_text, text_size, flags)) {
@@ -762,8 +661,408 @@ void GLGizmoEmboss::draw_text_input()
if (exist_font) ImGui::PopFont();
+ // show warning about incorrectness view of font
+ // TODO: add char gap and line gap
+ std::string warning;
+ const FontProp& prop = m_font_manager.get_font_prop();
+ if (prop.skew.has_value())
+ warning = prop.boldness.has_value() ?
+ _u8L("Italic & Bold is NOT shown") :
+ _u8L("Italic is NOT shown");
+ else if (prop.boldness.has_value())
+ warning = _u8L("Boldness is NOT shown");
+
+ if (!warning.empty()) {
+ ImVec2 cursor = ImGui::GetCursorPos();
+ float width = ImGui::GetContentRegionAvailWidth();
+ ImVec2 size = ImGui::CalcTextSize(warning.c_str());
+ ImVec2 padding = ImGui::GetStyle().FramePadding;
+ ImGui::SetCursorPos(ImVec2(width - size.x + padding.x,
+ cursor.y - size.y - padding.y));
+ m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, warning);
+ ImGui::SetCursorPos(cursor);
+ }
+
+ // Extend font ranges
// imgui_font has to be unused
- if (exist_change) m_font_manager.check_imgui_font_range(m_text);
+ if (exist_change) m_font_manager.get_imgui_font(m_text);
+}
+
+void GLGizmoEmboss::draw_font_list()
+{
+ if (ImGui::BeginCombo("##font_selector", "Actual selected font")) {
+ std::vector fonts = {1, 3, 5, 8};
+ for (const auto &item : fonts) {
+ size_t index = &item - &fonts.front();
+ ImGui::PushID(index);
+
+ bool is_selected = false;
+ ImGuiSelectableFlags_ flags =
+ ImGuiSelectableFlags_AllowItemOverlap; // allow click buttons
+ if (ImGui::Selectable(("font name" + std::to_string(item)).c_str(),
+ is_selected)) {
+ // Select font
+ }
+ ImGui::PopID();
+ }
+ ImGui::EndCombo();
+ }
+
+#ifdef ALLOW_ADD_FONT_BY_FILE
+ ImGui::SameLine();
+ // select font file by file browser
+ if (draw_button(IconType::open_file)) {
+ choose_true_type_file();
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("add file with font(.ttf, .ttc)").c_str());
+#endif // ALLOW_ADD_FONT_BY_FILE
+
+#ifdef ALLOW_ADD_FONT_BY_OS_SELECTOR
+ ImGui::SameLine();
+ if (draw_button(IconType::system_selector)) {
+ choose_font_by_wxdialog();
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("Open dialog for choose from fonts.").c_str());
+#endif // ALLOW_ADD_FONT_BY_OS_SELECTOR
+
+}
+
+void GLGizmoEmboss::draw_model_type()
+{
+ std::optional new_type;
+ ModelVolumeType modifier = ModelVolumeType::PARAMETER_MODIFIER;
+ ModelVolumeType negative = ModelVolumeType::NEGATIVE_VOLUME;
+ ModelVolumeType part = ModelVolumeType::MODEL_PART;
+ ModelVolumeType type = (m_volume != nullptr) ? m_volume->type() :
+ ModelVolumeType::INVALID;
+ bool is_last_solid_part = false;
+ if (type == part) {
+ is_last_solid_part = true;
+ for (const ModelVolume* vol : m_volume->get_object()->volumes) {
+ if (vol == m_volume) continue;
+ if (vol->type() == part) {
+ is_last_solid_part = false;
+ break;
+ }
+ }
+ }
+ if (ImGui::RadioButton("modifier", type == modifier) && !is_last_solid_part)
+ new_type = modifier;
+ if(is_last_solid_part && ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("You can't change a type of the last solid part of the object.").c_str());
+
+ ImGui::SameLine();
+ if (ImGui::RadioButton("negative", type == negative) && !is_last_solid_part)
+ new_type = negative;
+ if(is_last_solid_part && ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("You can't change a type of the last solid part of the object.").c_str());
+
+ ImGui::SameLine();
+ if (ImGui::RadioButton("part", type == part))
+ new_type = part;
+
+ ImGui::SameLine();
+ m_imgui->disabled_begin(true);
+ ImGui::RadioButton("baked in", false);
+ m_imgui->disabled_end();
+
+ if (m_volume != nullptr && new_type.has_value() && !is_last_solid_part) {
+ GUI_App &app = wxGetApp();
+ Plater * plater = app.plater();
+ plater->take_snapshot(_L("Change Part Type"));
+ m_volume->set_type(*new_type);
+
+ // inspiration in ObjectList::change_part_type()
+ // how to view correct side panel with objects
+ ObjectList *obj_list = app.obj_list();
+ ModelVolume * volume = m_volume;
+ wxDataViewItemArray sel = obj_list->reorder_volumes_and_get_selection(
+ obj_list->get_selected_obj_idx(),
+ [volume](const ModelVolume *vol) { return vol == volume; });
+ if (!sel.IsEmpty()) obj_list->select_item(sel.front());
+
+ // TODO: fix way of view - color after change from volume to negative
+ }
+}
+
+void GLGizmoEmboss::draw_rename_style(const std::optional& rename_index)
+{
+ // rename modal window popup
+ const char * rename_popup_id = "Rename_font";
+ static FontItem * rename_item;
+ static std::string new_name;
+ if (rename_index.has_value() && !ImGui::IsPopupOpen(rename_popup_id)) {
+ ImGui::OpenPopup(rename_popup_id);
+ rename_item = &m_font_manager.get_font(*rename_index).font_item;
+ new_name = rename_item->name; // initialize with original copy
+ }
+
+ if (ImGui::BeginPopupModal(rename_popup_id, 0,
+ ImGuiWindowFlags_AlwaysAutoResize)) {
+ const std::string &original_font_name = rename_item->name;
+ std::string text_in_popup =
+ GUI::format(_u8L("Change font name (%1%): "), original_font_name);
+ text_in_popup += "\n" +
+ _u8L("NOTE: Name has to be unique in font list.");
+ ImGui::Text("%s", text_in_popup.c_str());
+ ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
+
+ bool is_unique = true;
+ for (const auto &item : m_font_manager.get_fonts()) {
+ const FontItem &fi = item.font_item;
+ if (&fi == rename_item)
+ continue; // could be same as original name
+ if (fi.name == new_name) is_unique = false;
+ }
+ bool allow_change = is_unique && !new_name.empty();
+
+ ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
+ 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;
+ ImGui::CloseCurrentPopup();
+ store_font_list_to_app_config();
+ }
+ ImGui::EndPopup();
+ }
+}
+
+void GLGizmoEmboss::draw_style_list() {
+ const float & max_width = m_gui_cfg->max_font_name_width;
+ std::optional rename_index, delete_index, duplicate_index;
+
+ const FontItem & actual_font_item = m_font_manager.get_font_item();
+ const std::string ¤t_name = actual_font_item.name;
+ std::string trunc_name = ImGuiWrapper::trunc(current_name, max_width);
+ const auto &fonts = m_font_manager.get_fonts();
+
+ ImGui::Text("%s", _u8L("Style").c_str());
+ ImGui::SameLine();
+ ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
+ if (ImGui::BeginCombo("##style_selector", trunc_name.c_str())) {
+ for (const auto &item : fonts) {
+ size_t index = &item - &fonts.front();
+ const FontItem & fi = item.font_item;
+ const std::string &actual_style_name = fi.name;
+ ImGui::PushID(actual_style_name.c_str());
+ std::string name_truncated = ImGuiWrapper::trunc(actual_style_name,
+ max_width);
+
+ bool is_selected = (&fi == &actual_font_item);
+ ImGuiSelectableFlags_ flags =
+ ImGuiSelectableFlags_AllowItemOverlap; // allow click buttons
+ if (ImGui::Selectable(name_truncated.c_str(), is_selected,
+ flags)) {
+ if (m_font_manager.load_font(index)) process();
+ } else if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", actual_style_name.c_str());
+
+ // reorder items
+ if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) {
+ int other_index = index +
+ (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 :
+ 1);
+ if (other_index >= 0 && other_index < fonts.size()) {
+ std::swap(m_font_manager.get_font(index),
+ m_font_manager.get_font(other_index));
+ // fix selected index
+ if (is_selected)
+ m_font_manager.select(other_index);
+ else if (&fonts[other_index].font_item ==
+ &actual_font_item)
+ m_font_manager.select(index);
+ ImGui::ResetMouseDragDelta();
+ }
+ }
+
+ ImGui::SameLine(m_gui_cfg->delete_pos_x);
+ if (draw_button(IconType::erase, is_selected) && !is_selected)
+ delete_index = index;
+ if (ImGui::IsItemHovered()) {
+ std::string tooltip = (is_selected)?
+ GUI::format(_L("Active style \"%1%\" can't be deleted."), actual_style_name) :
+ GUI::format(_L("Delete \"%1%\" style."), actual_style_name);
+ ImGui::SetTooltip("%s", tooltip.c_str());
+ }
+ ImGui::PopID();
+ }
+ ImGui::EndCombo();
+ }
+
+ ImGui::SameLine();
+ if (draw_button(IconType::rename))
+ rename_index = &m_font_manager.get_font() - &fonts.front();
+ if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("Rename actual style.").c_str());
+
+ ImGui::SameLine();
+ if (draw_button(IconType::duplicate))
+ duplicate_index = &m_font_manager.get_font() - &fonts.front();
+ if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("Duplicate style.").c_str());
+
+ // duplicate font item
+ if (duplicate_index.has_value()) {
+ m_font_manager.duplicate(*duplicate_index);
+ store_font_list_to_app_config();
+ }
+
+ // delete font item
+ if (delete_index.has_value()) {
+ m_font_manager.erase(*delete_index);
+ store_font_list_to_app_config();
+ }
+
+ draw_rename_style(rename_index);
+
+ // TODO: Is style changed against stored one
+ bool is_changed = false;
+
+ ImGui::SameLine();
+ if (draw_button(IconType::save, !is_changed)) {
+ // TODO: make save style
+ }
+ if (ImGui::IsItemHovered())
+ if (is_changed)
+ ImGui::SetTooltip("%s", _u8L("Save current settings to selected style").c_str());
+ else
+ ImGui::SetTooltip("%s", _u8L("No changes to save into style").c_str());
+
+ if (is_changed) {
+ ImGui::SameLine();
+ if (draw_button(IconType::undo)) {
+ // TODO: make undo changes in style
+ }
+ if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("Reload original value of selected style").c_str());
+ }
+}
+
+bool GLGizmoEmboss::italic_button()
+{
+ FontManager::Item& item = m_font_manager.get_font();
+ std::optional &wx_font = item.wx_font;
+ if (!wx_font.has_value()) {
+ draw_icon(IconType::italic, IconState::disabled);
+ return false;
+ }
+
+ std::optional &skew = item.font_item.prop.skew;
+ bool is_font_italic = skew.has_value() || WxFontUtils::is_italic(*wx_font);
+ if (is_font_italic) {
+ if (draw_button(IconType::unitalic)) {
+ skew.reset();
+ wx_font->SetStyle(wxFontStyle::wxFONTSTYLE_NORMAL);
+ return true;
+ }
+ if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("Unset italic").c_str());
+ } else {
+ if (draw_button(IconType::italic)) {
+ std::shared_ptr &font_file = item.font_file;
+ bool is_set = WxFontUtils::set_italic(*wx_font, font_file);
+ // add skew when wxFont can't set it
+ if (!is_set) skew = 0.2f;
+ return true;
+ }
+ if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("Set italic").c_str());
+ }
+ return false;
+}
+
+bool GLGizmoEmboss::bold_button() {
+ FontManager::Item & item = m_font_manager.get_font();
+ std::optional &wx_font = item.wx_font;
+ if (!wx_font.has_value()) {
+ draw_icon(IconType::bold, IconState::disabled);
+ return false;
+ }
+
+ std::optional &boldness = item.font_item.prop.boldness;
+ bool is_font_bold = boldness.has_value() || WxFontUtils::is_bold(*wx_font);
+ if (is_font_bold) {
+ if (draw_button(IconType::unbold)) {
+ boldness.reset();
+ wx_font->SetWeight(wxFontWeight::wxFONTWEIGHT_NORMAL);
+ return true;
+ }
+ if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("Unset bold").c_str());
+ } else {
+ if (draw_button(IconType::bold)) {
+ std::shared_ptr &font_file = item.font_file;
+ bool is_set = WxFontUtils::set_bold(*wx_font, font_file);
+ // add boldness when wxFont can't set it
+ if (!is_set) boldness = 20.f;
+ return true;
+ }
+ if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", _u8L("Set bold").c_str());
+ }
+ return false;
+}
+
+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);
+ draw_font_list();
+ ImGui::SameLine();
+ bool exist_change = false;
+ exist_change |= italic_button();
+ ImGui::SameLine();
+ exist_change |= bold_button();
+
+ FontManager::Item &item = m_font_manager.get_font();
+ FontItem & fi = item.font_item;
+ std::optional &wx_font = item.wx_font;
+
+ // TODO: should not be there
+ // when actual font not loaded try to load
+ if (!wx_font.has_value() && fi.type == WxFontUtils::get_actual_type())
+ wx_font = WxFontUtils::load_wxFont(fi.path);
+
+ 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);
+ if (ImGui::InputFloat("##line height", &font_prop.size_in_mm, 0.1f, 1.f, "%.1f mm")) {
+ if (font_prop.size_in_mm < 0.1) font_prop.size_in_mm = 10;
+ // store font size into path
+ if (fi.type == WxFontUtils::get_actual_type()) {
+ if (wx_font.has_value()) {
+ wx_font->SetPointSize(font_prop.size_in_mm);
+ fi.path = WxFontUtils::store_wxFont(*wx_font);
+ }
+ }
+ m_font_manager.load_imgui_font(m_text);
+ exist_change = true;
+ }
+ if (exist_change) {
+ std::shared_ptr &font_file = item.font_file;
+ font_file->cache.clear();
+ store_font_item_to_app_config();
+ process();
+ }
+
+ ImGui::Text("%s", tr.depth.c_str());
+ ImGui::SameLine(m_gui_cfg->style_edit_text_width);
+ ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
+ if (ImGui::InputFloat("##size in Z", &font_prop.emboss, 0.1f, 0.25, "%.2f mm")) {
+ process();
+ }
+
+ if (ImGui::TreeNode(_u8L("advanced").c_str())) {
+ draw_advanced();
+ ImGui::TreePop();
+ if (!m_is_advanced_edit_style)
+ set_minimal_window_size(true, true);
+ } else if (m_is_advanced_edit_style)
+ set_minimal_window_size(true, false);
}
void GLGizmoEmboss::draw_advanced()
@@ -776,47 +1075,27 @@ void GLGizmoEmboss::draw_advanced()
FontItem &fi = m_font_manager.get_font_item();
FontProp &font_prop = fi.prop;
- bool exist_change = false;
-
- ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
- if (ImGui::InputFloat(_u8L("Size[in mm]").c_str(),
- &font_prop.size_in_mm)) {
- if (font_prop.size_in_mm < 0.1) font_prop.size_in_mm = 10;
- // store font size into path
- if (fi.type == WxFontUtils::get_actual_type()) {
- std::optional wx_font = WxFontUtils::load_wxFont(fi.path);
- if (wx_font.has_value()) {
- wx_font->SetPointSize(font_prop.size_in_mm);
- fi.path = WxFontUtils::store_wxFont(*wx_font);
- }
- }
- m_font_manager.load_imgui_font();
- font_file->cache.clear();
- exist_change = true;
- }
-
- ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
- if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &font_prop.emboss))
- exist_change = true;
+ bool exist_change = false;
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
if (ImGuiWrapper::input_optional_int(_u8L("CharGap[in font points]").c_str(), font_prop.char_gap)) {
font_file->cache.clear();
+ m_font_manager.load_imgui_font(m_text);
exist_change = true;
}
ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width);
- if (ImGuiWrapper::input_optional_int(_u8L("LineGap[in font points]").c_str(), font_prop.line_gap))
+ if (ImGuiWrapper::input_optional_int(_u8L("LineGap [in font points]").c_str(), font_prop.line_gap))
exist_change = true;
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_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 chars"))){
+ 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 chars"))){
font_file->cache.clear();
exist_change = true;
}
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
- if (m_imgui->slider_optional_float(_u8L("Skew ratio").c_str(), font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("italic strength"))){
+ 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"))){
font_file->cache.clear();
exist_change = true;
}
@@ -845,7 +1124,8 @@ void GLGizmoEmboss::draw_advanced()
process();
}
-
+ auto& atlas = m_font_manager.m_imgui_font_atlas;
+ ImGui::Image(atlas.TexID, ImVec2(atlas.TexWidth, atlas.TexHeight));
#ifdef ALLOW_DEBUG_MODE
ImGui::Text("family = %s", (font_prop.family.has_value() ?
font_prop.family->c_str() :
@@ -862,12 +1142,33 @@ void GLGizmoEmboss::draw_advanced()
std::string descriptor = fi.path;
ImGui::Text("descriptor = %s", descriptor.c_str());
- ImGui::Image(m_imgui_font_atlas.TexID,
- ImVec2(m_imgui_font_atlas.TexWidth,
- m_imgui_font_atlas.TexHeight));
#endif // ALLOW_DEBUG_MODE
}
+void GLGizmoEmboss::set_minimal_window_size(bool is_edit_style,
+ bool is_advance_edit_style)
+{
+ ImVec2 window_size = ImGui::GetWindowSize();
+ const ImVec2& min_win_size_prev = get_minimal_window_size();
+ ImVec2 diff(window_size.x - min_win_size_prev.x,
+ window_size.y - min_win_size_prev.y);
+ float diff_y = ImGui::GetWindowSize().y - get_minimal_window_size().y;
+ m_is_edit_style = is_edit_style;
+ m_is_advanced_edit_style = is_advance_edit_style;
+ const ImVec2 &min_win_size = get_minimal_window_size();
+ ImGui::SetWindowSize(ImVec2(0.f, min_win_size.y + diff.y),
+ ImGuiCond_Always);
+}
+
+const ImVec2 &GLGizmoEmboss::get_minimal_window_size() const
+{
+ return (m_is_edit_style) ?
+ ((m_is_advanced_edit_style) ?
+ m_gui_cfg->minimal_window_size_with_advance :
+ m_gui_cfg->minimal_window_size_with_edit) :
+ m_gui_cfg->minimal_window_size;
+}
+
bool GLGizmoEmboss::choose_font_by_wxdialog()
{
wxFontData data;
@@ -885,9 +1186,9 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
if (font_dialog.ShowModal() != wxID_OK) return false;
data = font_dialog.GetFontData();
- wxFont font = data.GetChosenFont();
+ wxFont wx_font = data.GetChosenFont();
size_t font_index = m_font_manager.get_fonts().size();
- FontItem font_item = WxFontUtils::get_font_item(font);
+ FontItem font_item = WxFontUtils::get_font_item(wx_font);
m_font_manager.add_font(font_item);
// Check that deserialization NOT influence font
@@ -897,7 +1198,7 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
// Try load and use new added font
if ((use_deserialized_font && !m_font_manager.load_font(font_index)) ||
- (!use_deserialized_font && !m_font_manager.load_font(font_index, font)) ||
+ (!use_deserialized_font && !m_font_manager.load_font(font_index, wx_font)) ||
!process()) {
m_font_manager.erase(font_index);
wxString message = GUI::format_wxstr(
@@ -910,8 +1211,7 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
}
// fix dynamic creation of italic font
- wxFontStyle wx_style = font.GetStyle();
- if ((wx_style == wxFONTSTYLE_ITALIC || wx_style == wxFONTSTYLE_SLANT) &&
+ if (WxFontUtils::is_italic(wx_font) &&
!Emboss::is_italic(*m_font_manager.get_font_file())) {
m_font_manager.get_font_item().prop.skew = 0.2;
}
@@ -1089,12 +1389,23 @@ std::string GLGizmoEmboss::create_volume_name()
bool GLGizmoEmboss::init_icons()
{
- std::string path = resources_dir() + "/icons/";
-
// icon order has to match the enum IconType
- std::vector filenames = {path + "wrench.svg",
- path + "delete.svg",
- path + "add_copies.svg"};
+ std::vector filenames{
+ "edit_button.svg",
+ "delete.svg",
+ "add_copies.svg",
+ "save.svg",
+ "undo.svg",
+ "make_italic.svg",
+ "make_unitalic.svg",
+ "make_bold.svg",
+ "make_unbold.svg",
+ "search.svg",
+ "open.svg"
+ };
+ assert(filenames.size() == static_cast(IconType::_count));
+ std::string path = resources_dir() + "/icons/";
+ for (std::string &filename : filenames) filename = path + filename;
// state order has to match the enum IconState
std::vector> states;
@@ -1114,6 +1425,10 @@ bool GLGizmoEmboss::init_icons()
void GLGizmoEmboss::draw_icon(IconType icon, IconState state)
{
+ // canot draw count
+ assert(icon != IconType::_count);
+ if (icon == IconType::_count) return;
+
unsigned int icons_texture_id = m_icons_texture.get_id();
int tex_width = m_icons_texture.get_width();
int tex_height = m_icons_texture.get_height();
@@ -1122,9 +1437,8 @@ void GLGizmoEmboss::draw_icon(IconType icon, IconState state)
if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1))
return;
ImTextureID tex_id = (void *) (intptr_t) (GLuint) icons_texture_id;
- // ImVec2 image_size(tex_width, tex_height);
- size_t count_icons = 3; // wrench | delete | copy
+ size_t count_icons = static_cast(IconType::_count);
size_t count_states = 3; // activable | hovered | disabled
ImVec2 icon_size(tex_width / count_states, tex_height / count_icons);
@@ -1132,7 +1446,6 @@ void GLGizmoEmboss::draw_icon(IconType icon, IconState state)
static_cast(icon) * icon_size.y);
ImVec2 uv0(start.x / tex_width, start.y / tex_height);
-
ImVec2 uv1((start.x + icon_size.x) / tex_width,
(start.y + icon_size.y) / tex_height);
@@ -1141,42 +1454,17 @@ void GLGizmoEmboss::draw_icon(IconType icon, IconState state)
bool GLGizmoEmboss::draw_button(IconType icon, bool disable)
{
- float line_spacing = ImGui::GetTextLineHeightWithSpacing() -
- ImGui::GetTextLineHeight();
- float cursor_pos_y = ImGui::GetCursorPosY();
- ImGui::SetCursorPosY(cursor_pos_y - line_spacing / 2);
- ScopeGuard sg([cursor_pos_y]() {
- ImGui::SetCursorPosY(cursor_pos_y);
- ImGui::NewLine();
- });
-
if (disable) {
draw_icon(icon, IconState::disabled);
- if (ImGui::IsItemHovered() && icon == IconType::erase)
- ImGui::SetTooltip("%s",_u8L("Active font can't be removed").c_str());
return false;
}
float cursor_x = ImGui::GetCursorPosX();
-
draw_icon(icon, IconState::activable);
if (ImGui::IsItemClicked()) return true;
-
if (ImGui::IsItemHovered()) {
- std::string tooltip;
- switch (icon) {
- case IconType::rename: tooltip = _u8L("rename"); break;
- case IconType::erase: tooltip = _u8L("delete"); break;
- case IconType::duplicate:tooltip = _u8L("duplicate"); break;
- default: break;
- }
- if (!tooltip.empty())
- ImGui::SetTooltip("%s", tooltip.c_str());
-
// redraw image over previous
- ImGui::SameLine();
- ImGui::SetCursorPosX(cursor_x);
-
+ ImGui::SameLine(cursor_x);
draw_icon(icon, IconState::hovered);
}
return false;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp
index 77ad9480b..35d13ad5f 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp
@@ -100,9 +100,18 @@ private:
bool process();
void close();
void draw_window();
- void draw_font_list();
void draw_text_input();
+ void draw_model_type();
+ void draw_style_list();
+ void draw_rename_style(const std::optional& rename_index);
+ void draw_font_list();
+ void draw_style_edit();
+ bool italic_button();
+ bool bold_button();
void draw_advanced();
+
+ void set_minimal_window_size(bool is_edit_style, bool is_advance_edit_style);
+ const ImVec2 &get_minimal_window_size() const;
// process mouse event
bool on_mouse_for_rotation(const wxMouseEvent &mouse_event);
bool on_mouse_for_translate(const wxMouseEvent &mouse_event);
@@ -128,26 +137,35 @@ private:
struct GuiCfg
{
size_t max_count_char_in_volume_name = 20;
- int count_line_of_text = 6;
- bool draw_advanced = false;
-
- // setted only when wanted to use - not all the time
- std::optional offset;
-
// Zero means it is calculated in init function
- ImVec2 minimal_window_size = ImVec2(0, 0);
+ ImVec2 minimal_window_size = ImVec2(0, 0);
+ 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 rename_pos_x = 0.f;
float delete_pos_x = 0.f;
- float duplicate_pos_x = 0.f;
float max_font_name_width = 0.f;
float icon_width = 0.f;
+
+ float style_edit_text_width = 0.f;
+
ImVec2 text_size;
+
+ // Only translations needed for calc GUI size
+ struct Translations
+ {
+ std::string font;
+ std::string size;
+ std::string depth;
+ };
+ Translations translations;
GuiCfg() = default;
};
- std::optional m_gui_cfg;
+ std::optional m_gui_cfg;
+ // setted only when wanted to use - not all the time
+ std::optional m_set_window_offset;
+ bool m_is_edit_style = false;
+ bool m_is_advanced_edit_style = false;
FontManager m_font_manager;
@@ -175,7 +193,20 @@ private:
// drawing icons
GLTexture m_icons_texture;
bool init_icons();
- enum class IconType: unsigned { rename = 0, erase /*1*/, duplicate /*2*/};
+ enum class IconType : unsigned {
+ rename = 0,
+ erase,
+ duplicate,
+ save,
+ undo,
+ italic,
+ unitalic,
+ bold,
+ unbold,
+ system_selector,
+ open_file,
+ _count /* automatic calc of icon size */
+ };
enum class IconState: unsigned { activable = 0, hovered /*1*/, disabled /*2*/};
void draw_icon(IconType icon, IconState state);
bool draw_button(IconType icon, bool disable = false);
diff --git a/src/slic3r/Utils/FontManager.cpp b/src/slic3r/Utils/FontManager.cpp
index 99ee34237..74ea8f6d0 100644
--- a/src/slic3r/Utils/FontManager.cpp
+++ b/src/slic3r/Utils/FontManager.cpp
@@ -10,10 +10,13 @@ using namespace Slic3r;
using namespace Slic3r::GUI;
FontManager::FontManager(const ImWchar *language_glyph_range)
- : m_imgui_init_glyph_range(language_glyph_range),
- m_font_selected(0)
+ : m_imgui_init_glyph_range(language_glyph_range), m_font_selected(0)
{}
+FontManager::~FontManager() {
+ free_imgui_fonts();
+}
+
void FontManager::select(size_t index)
{
if (index < m_font_list.size())
@@ -25,6 +28,11 @@ void FontManager::duplicate(size_t index) {
Item item = m_font_list[index]; // copy
make_unique_name(item.font_item.name);
+ // take original font imgui pointer
+ ImFont *imgui_font = get_imgui_font(index);
+ if (imgui_font != nullptr)
+ m_font_list[index].imgui_font_index.reset();
+
m_font_list.insert(m_font_list.begin() + index, item);
// fix selected index
if (index < m_font_selected) ++m_font_selected;
@@ -32,6 +40,11 @@ void FontManager::duplicate(size_t index) {
void FontManager::erase(size_t index) {
if (index >= m_font_list.size()) return;
+
+ ImFont *imgui_font = get_imgui_font(index);
+ if (imgui_font != nullptr)
+ IM_DELETE(imgui_font);
+
m_font_list.erase(m_font_list.begin() + index);
// fix selected index
if (index < m_font_selected) --m_font_selected;
@@ -49,13 +62,13 @@ bool FontManager::load_font(size_t font_index)
bool FontManager::load_font(size_t font_index, const wxFont &font)
{
if (font_index >= m_font_list.size()) return false;
+ m_font_list[font_index].wx_font = font;
std::swap(font_index, m_font_selected);
bool is_loaded = load_font(font);
if (!is_loaded) std::swap(font_index, m_font_selected);
return is_loaded;
}
-
static std::string get_file_name(const std::string &file_path)
{
size_t pos_last_delimiter = file_path.find_last_of('\\');
@@ -84,13 +97,13 @@ bool FontManager::load_font()
return true;
}
if (fi.type != WxFontUtils::get_actual_type()) return false;
- std::optional wx_font = WxFontUtils::load_wxFont(fi.path);
- if (!wx_font.has_value()) return false;
+ item.wx_font = WxFontUtils::load_wxFont(fi.path);
+ if (!item.wx_font.has_value()) return false;
// fill font name after load from .3mf
if (fi.name.empty())
- fi.name = WxFontUtils::get_human_readable_name(*wx_font);
- return load_font(*wx_font);
+ fi.name = WxFontUtils::get_human_readable_name(*item.wx_font);
+ return load_font(*item.wx_font);
}
bool FontManager::load_first_valid_font() {
@@ -121,25 +134,85 @@ void FontManager::add_fonts(FontList font_list)
std::shared_ptr &FontManager::get_font_file()
{
+ // TODO: fix not selected font
+ //if (m_font_selected >= m_font_list.size()) return nullptr;
return m_font_list[m_font_selected].font_file;
}
const FontItem &FontManager::get_font_item() const
{
+ // TODO: fix not selected font
return m_font_list[m_font_selected].font_item;
}
FontItem &FontManager::get_font_item()
{
+ // TODO: fix not selected font
return m_font_list[m_font_selected].font_item;
}
-ImFont *FontManager::get_imgui_font()
+const FontProp &FontManager::get_font_prop() const
{
- return m_font_list[m_font_selected].imgui_font;
+ // TODO: fix not selected font
+ return m_font_list[m_font_selected].font_item.prop;
}
-const std::vector &Slic3r::GUI::FontManager::get_fonts() const
+FontProp &FontManager::get_font_prop()
+{
+ // TODO: fix not selected font
+ return m_font_list[m_font_selected].font_item.prop;
+}
+
+std::optional &FontManager::get_wx_font()
+{
+ return m_font_list[m_font_selected].wx_font;
+}
+
+const std::optional &FontManager::get_wx_font() const
+{
+ return m_font_list[m_font_selected].wx_font;
+}
+
+ImFont *FontManager::get_imgui_font(const std::string &text)
+{
+ return get_imgui_font(m_font_selected, text);
+}
+
+ImFont *FontManager::get_imgui_font(size_t item_index, const std::string &text)
+{
+ // is selected font
+ if (item_index >= m_font_list.size()) return nullptr;
+
+ Item &item = m_font_list[item_index];
+ // check is already loaded
+ if (!item.imgui_font_index.has_value()) return nullptr;
+ size_t index = *item.imgui_font_index;
+ auto & fonts = m_imgui_font_atlas.Fonts;
+
+ // check correct index
+ assert(index < fonts.size());
+ if (index >= fonts.size()) return nullptr;
+ ImFont *font = fonts[index];
+ if (font == nullptr) return nullptr;
+
+ if (!text.empty() && !is_text_in_ranges(font, text))
+ extend_imgui_font_range(item_index, text);
+
+ return font;
+}
+
+void FontManager::free_except_active_font() {
+ free_imgui_fonts();
+
+ // free font_files
+ const Item &act_item = m_font_list[m_font_selected];
+ for (auto &item : m_font_list) {
+ if (&item == &act_item) continue; // keep alive actual font file
+ item.font_file = nullptr;
+ }
+}
+
+const std::vector &FontManager::get_fonts() const
{
return m_font_list;
}
@@ -154,6 +227,11 @@ const FontManager::Item &FontManager::get_font() const
return m_font_list[m_font_selected];
}
+FontManager::Item &FontManager::get_font()
+{
+ return m_font_list[m_font_selected];
+}
+
FontManager::Item &FontManager::get_font(size_t index)
{
return m_font_list[index];
@@ -188,28 +266,28 @@ void FontManager::make_unique_name(std::string &name) {
name = new_name;
}
-void FontManager::check_imgui_font_range(const std::string& text)
+bool FontManager::is_text_in_ranges(const ImFont *font, const std::string &text)
{
- const ImFont *font = m_imgui_font_atlas.Fonts.front();
- if (!font->IsLoaded()) {
- // when create font no one letter in text was inside font
- // check text again
- load_imgui_font();
- return;
- }
- if (font->ConfigData == nullptr) return;
- const ImWchar *ranges = font->ConfigData->GlyphRanges;
- auto is_in_ranges = [ranges](unsigned int letter) -> bool {
- for (const ImWchar *range = ranges; range[0] && range[1]; range += 2) {
- ImWchar from = range[0];
- ImWchar to = range[1];
- if (from <= letter && letter <= to) return true;
- if (letter < to) return false; // ranges should be sorted
- }
- return false;
- };
+ if (font == nullptr) return false;
+ if (!font->IsLoaded()) return false;
+ const ImFontConfig *fc = font->ConfigData;
+ if (fc == nullptr) return false;
+ return is_text_in_ranges(fc->GlyphRanges, text);
+}
- bool exist_unknown = false;
+bool FontManager::is_char_in_ranges(const ImWchar *ranges, unsigned int letter)
+{
+ for (const ImWchar *range = ranges; range[0] && range[1]; range += 2) {
+ ImWchar from = range[0];
+ ImWchar to = range[1];
+ if (from <= letter && letter <= to) return true;
+ if (letter < to) return false; // ranges should be sorted
+ }
+ return false;
+};
+
+bool FontManager::is_text_in_ranges(const ImWchar *ranges, const std::string &text)
+{
const char *text_char_ptr = text.c_str();
while (*text_char_ptr) {
unsigned int c = 0;
@@ -217,12 +295,28 @@ void FontManager::check_imgui_font_range(const std::string& text)
int c_len = ImTextCharFromUtf8(&c, text_char_ptr, NULL);
text_char_ptr += c_len;
if (c_len == 0) break;
- if (!is_in_ranges(c)) {
- exist_unknown = true;
- break;
- }
+ if (!is_char_in_ranges(ranges, c)) return false;
}
- if (exist_unknown) load_imgui_font();
+ return true;
+}
+
+void FontManager::extend_imgui_font_range(size_t index, const std::string& text)
+{
+ auto &font_index_opt = m_font_list[m_font_selected].imgui_font_index;
+ if (!font_index_opt.has_value()) load_imgui_font(index, text);
+
+ // TODO: start using merge mode
+ // ImFontConfig::MergeMode = true;
+
+ free_imgui_fonts();
+ load_imgui_font(index, text);
+}
+
+void FontManager::free_imgui_fonts()
+{
+ for (auto &item : m_font_list)
+ item.imgui_font_index.reset();
+ m_imgui_font_atlas.Clear();
}
bool FontManager::load_font(const wxFont &font)
@@ -234,10 +328,16 @@ bool FontManager::load_font(const wxFont &font)
return true;
}
-void FontManager::load_imgui_font(const std::string &text)
+void FontManager::load_imgui_font(const std::string &text) {
+ load_imgui_font(m_font_selected, text);
+}
+
+void FontManager::load_imgui_font(size_t index, const std::string &text)
{
- Item &item = m_font_list[m_font_selected];
+ if (index >= m_font_list.size()) return;
+ Item &item = m_font_list[index];
if (item.font_file == nullptr) return;
+ const Emboss::FontFile &font_file = *item.font_file;
// TODO: Create glyph range
ImFontGlyphRangesBuilder builder;
@@ -247,8 +347,12 @@ void FontManager::load_imgui_font(const std::string &text)
item.font_ranges.clear();
builder.BuildRanges(&item.font_ranges);
+
+ m_imgui_font_atlas.Flags |= ImFontAtlasFlags_NoMouseCursors |
+ ImFontAtlasFlags_NoPowerOfTwoHeight;
+
const FontProp &font_prop = item.font_item.prop;
- int font_size = static_cast(
+ int font_size = static_cast(
std::round(std::abs(font_prop.size_in_mm / 0.3528)));
if (font_size < m_cfg.min_imgui_font_size)
font_size = m_cfg.min_imgui_font_size;
@@ -256,12 +360,17 @@ void FontManager::load_imgui_font(const std::string &text)
font_size = m_cfg.max_imgui_font_size;
ImFontConfig font_config;
+ // 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));
+ }
font_config.FontDataOwnedByAtlas = false;
- m_imgui_font_atlas.Flags |= ImFontAtlasFlags_NoMouseCursors |
- ImFontAtlasFlags_NoPowerOfTwoHeight;
- m_imgui_font_atlas.Clear();
- const std::vector &buffer = item.font_file->buffer;
+ const std::vector &buffer = font_file.buffer;
m_imgui_font_atlas.AddFontFromMemoryTTF(
(void *) buffer.data(), buffer.size(), font_size, &font_config, item.font_ranges.Data);
@@ -287,5 +396,7 @@ void FontManager::load_imgui_font(const std::string &text)
// Store our identifier
m_imgui_font_atlas.TexID = (ImTextureID) (intptr_t) font_texture;
- item.imgui_font = m_imgui_font_atlas.Fonts.front();
+ assert(!m_imgui_font_atlas.Fonts.empty());
+ if (m_imgui_font_atlas.Fonts.empty()) return;
+ item.imgui_font_index = m_imgui_font_atlas.Fonts.size() - 1;
}
diff --git a/src/slic3r/Utils/FontManager.hpp b/src/slic3r/Utils/FontManager.hpp
index a4b7529ae..5aae8df9b 100644
--- a/src/slic3r/Utils/FontManager.hpp
+++ b/src/slic3r/Utils/FontManager.hpp
@@ -17,6 +17,8 @@ class FontManager
{
public:
FontManager(const ImWchar *language_glyph_range);
+ ~FontManager();
+
void select(size_t index);
void duplicate(size_t index);
void erase(size_t index);
@@ -29,10 +31,7 @@ public:
bool load_font(size_t font_index, const wxFont &font);
void load_imgui_font(const std::string &text = "");
-
- // extend actual imgui font when exist unknown char in text
- // NOTE: imgui_font has to be unused
- void check_imgui_font_range(const std::string &text);
+ void load_imgui_font(size_t index, const std::string &text);
// erase font when not possible to load
bool load_first_valid_font();
@@ -49,8 +48,21 @@ public:
const FontItem &get_font_item() const;
FontItem &get_font_item();
+ // getter on active font property
+ const FontProp &get_font_prop() const;
+ FontProp &get_font_prop();
+
+ // getter on activ wx font
+ const std::optional &get_wx_font() const;
+ std::optional &get_wx_font();
+
// getter on acitve font pointer for imgui
- ImFont *get_imgui_font();
+ // text could extend font atlas when not in glyph range
+ ImFont *get_imgui_font(const std::string &text = "");
+
+ // getter on index selected font pointer for imgui
+ // text could extend font atlas when not in glyph range
+ ImFont *get_imgui_font(size_t item_index, const std::string &text = "");
// free used memory and font file data
void free_except_active_font();
@@ -61,6 +73,7 @@ public:
std::vector- &get_fonts();
const Item &get_font() const;
+ Item &get_font();
const Item &get_font(size_t index) const;
Item &get_font(size_t index);
@@ -74,14 +87,31 @@ public:
// share font file data with emboss job thread
std::shared_ptr font_file = nullptr;
- // ImGui font
- ImFont *imgui_font;
+ std::optional imgui_font_index;
// must live same as imgui_font inside of atlas
ImVector font_ranges;
+
+ // wx widget font
+ std::optional wx_font;
};
+ // TODO: make private
+ ImFontAtlas m_imgui_font_atlas;
+
private:
+ // extend actual imgui font when exist unknown char in text
+ // NOTE: imgui_font has to be unused
+ void extend_imgui_font_range(size_t font_index, const std::string &text);
+
+ // Move to imgui utils
+ static bool is_text_in_ranges(const ImFont *font, const std::string &text);
+ static bool is_text_in_ranges(const ImWchar *ranges, const std::string &text);
+ static bool is_char_in_ranges(const ImWchar *ranges, unsigned int letter);
+
+ bool check_imgui_font_range(ImFont *font, const std::string &text);
+ void free_imgui_fonts();
+
struct Configuration
{
// limits for imgui loaded font
@@ -100,7 +130,7 @@ private:
size_t m_font_selected; // index to m_font_list
// store all font GLImages
- ImFontAtlas m_imgui_font_atlas;
+ //ImFontAtlas m_imgui_font_atlas;
const ImWchar *m_imgui_init_glyph_range;
};
diff --git a/src/slic3r/Utils/WxFontUtils.cpp b/src/slic3r/Utils/WxFontUtils.cpp
index fc294ff17..665515d48 100644
--- a/src/slic3r/Utils/WxFontUtils.cpp
+++ b/src/slic3r/Utils/WxFontUtils.cpp
@@ -210,3 +210,62 @@ void WxFontUtils::update_property(FontProp &font_prop, const wxFont &font)
if (it != from_weight.end()) font_prop.weight = it->second;
}
}
+
+bool WxFontUtils::is_italic(const wxFont &font) {
+ wxFontStyle wx_style = font.GetStyle();
+ return wx_style == wxFONTSTYLE_ITALIC ||
+ wx_style == wxFONTSTYLE_SLANT;
+}
+
+bool WxFontUtils::is_bold(const wxFont &font) {
+ wxFontWeight wx_weight = font.GetWeight();
+ return wx_weight != wxFONTWEIGHT_NORMAL;
+}
+
+bool WxFontUtils::set_italic(wxFont &font, std::shared_ptr& font_file)
+{
+ static std::vector italic_styles = {
+ wxFontStyle::wxFONTSTYLE_ITALIC,
+ wxFontStyle::wxFONTSTYLE_SLANT
+ };
+ if (font_file == nullptr)
+ font_file = WxFontUtils::load_font(font);
+
+ for (wxFontStyle style : italic_styles) {
+ font.SetStyle(style);
+ std::unique_ptr act_font_file = WxFontUtils::load_font(font);
+ if (act_font_file == nullptr) continue;
+
+ // is still same font file pointer?
+ if (font_file != nullptr)
+ if (act_font_file->buffer == font_file->buffer) continue;
+
+ font_file = std::move(act_font_file);
+ return true;
+ }
+ return false;
+}
+
+bool WxFontUtils::set_bold(wxFont &font, std::shared_ptr& font_file)
+{
+ static std::vector bold_weight = {
+ wxFontWeight::wxFONTWEIGHT_BOLD,
+ wxFontWeight::wxFONTWEIGHT_HEAVY,
+ wxFontWeight::wxFONTWEIGHT_EXTRABOLD,
+ wxFontWeight::wxFONTWEIGHT_EXTRAHEAVY
+ };
+ if (font_file == nullptr)
+ font_file = WxFontUtils::load_font(font);
+
+ for (wxFontWeight weight : bold_weight) {
+ font.SetWeight(weight);
+ std::unique_ptr act_font_file = WxFontUtils::load_font(font);
+ if (act_font_file == nullptr) continue;
+ if (font_file != nullptr)
+ // is still same font?
+ if (act_font_file->buffer == font_file->buffer) continue;
+ font_file = std::move(act_font_file);
+ return true;
+ }
+ return false;
+}
\ No newline at end of file
diff --git a/src/slic3r/Utils/WxFontUtils.hpp b/src/slic3r/Utils/WxFontUtils.hpp
index a42b2d93c..0ee1c2ca2 100644
--- a/src/slic3r/Utils/WxFontUtils.hpp
+++ b/src/slic3r/Utils/WxFontUtils.hpp
@@ -27,8 +27,7 @@ public:
// serialize / deserialize font
static std::string store_wxFont(const wxFont &font);
- static std::optional load_wxFont(
- const std::string &font_descriptor);
+ static std::optional load_wxFont(const std::string &font_descriptor);
// Try to create similar font, loaded from 3mf from different Computer
static std::optional create_wxFont(const FontItem &fi,
@@ -36,6 +35,21 @@ public:
// update font property by wxFont
static void update_property(FontProp &font_prop, const wxFont &font);
+ static bool is_italic(const wxFont &font);
+ static bool is_bold(const wxFont &font);
+
+ // Font could not support italic than return FALSE.
+ // For check of support is neccessary font file pointer.
+ // Font file is optional it could be created inside of function, but it slow down.
+ // To not load font file twice on success font_file contain new created font file.
+ static bool set_italic(wxFont &font, std::shared_ptr& font_file = std::shared_ptr());
+
+ // Font could not support bold than return FALSE.
+ // For check of support is neccessary font file pointer.
+ // Font file is optional it could be created inside of function, but it slow down.
+ // To not load font file twice on success font_file contain new created font file.
+ static bool set_bold(wxFont &font, std::shared_ptr& font_file = std::shared_ptr());
+
// map to convert wxFont type to string and vice versa
static const std::map from_family;
static const std::map to_family;