diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 23a3d244a..689e61aa2 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -148,14 +148,48 @@ std::optional Private::get_glyph( // IMPROVE: multiple loadig glyph without data // has definition inside of font? if (!glyph_opt.has_value()) return {}; + + if (font_prop.char_gap.has_value()) + glyph_opt->advance_width += *font_prop.char_gap; + + // scale glyph size + glyph_opt->advance_width = + static_cast(glyph_opt->advance_width / Emboss::SHAPE_SCALE); + glyph_opt->left_side_bearing = + static_cast(glyph_opt->left_side_bearing / Emboss::SHAPE_SCALE); + + if (font_prop.boldness.has_value()) { + float delta = *font_prop.boldness / Emboss::SHAPE_SCALE; + glyph_opt->shape = offset_ex(glyph_opt->shape, delta); + } + + if (font_prop.skew.has_value()) { + const float &ratio = *font_prop.skew; + auto skew = [&ratio](Slic3r::Polygon &polygon) { + for (Slic3r::Point &p : polygon.points) { p.x() += p.y() * ratio; } + }; + for (ExPolygon &expolygon : glyph_opt->shape) { + skew(expolygon.contour); + for (Slic3r::Polygon &hole : expolygon.holes) skew(hole); + } + } + + // union of shape + // (for sure) I do not believe in font corectness + // modification like bold or skew could create artefacts + glyph_opt->shape = Slic3r::union_ex(glyph_opt->shape); + // unify multipoints with similar position. Could appear after union + dilate_to_unique_points(glyph_opt->shape); + cache[unicode] = *glyph_opt; + return glyph_opt; } FontItem Private::create_font_item(std::wstring name, std::wstring path) { return FontItem(boost::nowide::narrow(name.c_str()), boost::nowide::narrow(path.c_str()), - FontItem::Type::file_path); + FontItem::Type::file_path, FontProp()); } ExPolygons Private::dilate_to_unique_points(ExPolygons &expolygons) @@ -549,8 +583,10 @@ ExPolygons Emboss::text2shapes(Font & font, int line_height = font.ascent - font.descent + font.linegap; if (font_prop.line_gap.has_value()) line_height += *font_prop.line_gap; + line_height = static_cast(line_height / SHAPE_SCALE); + cursor.x() = 0; - cursor.y() -= static_cast(line_height / SHAPE_SCALE); + cursor.y() -= line_height; continue; } if (wc == '\t') { @@ -558,10 +594,7 @@ ExPolygons Emboss::text2shapes(Font & font, const int count_spaces = 4; std::optional space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt); if (!space_opt.has_value()) continue; - int width = space_opt->advance_width; - if (font_prop.char_gap.has_value()) - width += *font_prop.char_gap; - cursor.x() += static_cast((count_spaces * width) / SHAPE_SCALE); + cursor.x() += count_spaces * space_opt->advance_width; continue; } @@ -574,29 +607,7 @@ ExPolygons Emboss::text2shapes(Font & font, for (ExPolygon &expolygon : expolygons) expolygon.translate(cursor); - if (font_prop.boldness.has_value()) { - float delta = *font_prop.boldness / SHAPE_SCALE; - expolygons = offset_ex(expolygons, delta); - } - - if (font_prop.skew.has_value()) { - const float& ratio = *font_prop.skew; - auto skew = [&ratio](Polygon &polygon) { - for (Point &p : polygon.points) { - p.x() += p.y() * ratio; - } - }; - for (ExPolygon &expolygon : expolygons) { - skew(expolygon.contour); - for (Polygon &hole : expolygon.holes) - skew(hole); - } - } - - int width = glyph_opt->advance_width; - if (font_prop.char_gap.has_value()) - width += *font_prop.char_gap; - cursor.x() += static_cast(width / SHAPE_SCALE); + cursor.x() += glyph_opt->advance_width; expolygons_append(result, expolygons); } result = Slic3r::union_ex(result); diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 13a95df3f..0b03846f1 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -46,13 +46,15 @@ public: struct Glyph { ExPolygons shape; - int advance_width, left_side_bearing; + int advance_width=0, left_side_bearing=0; }; // cache for glyph by unicode using Glyphs = std::map; /// /// keep information from file about font + /// + cache shape of glyphs (optionaly modified) + /// + user defined modification of font /// struct Font { @@ -65,6 +67,10 @@ public: // vertical position is "scale*(ascent - descent + lineGap)" const int ascent, descent, linegap; + // user defined font modification + // + emboss parameter + FontProp prop; + Emboss::Glyphs cache; // cache of glyphs Font(std::vector &&buffer, @@ -78,9 +84,21 @@ public: , ascent(ascent) , descent(descent) , linegap(linegap) + , prop(7.f, 1.f) {} }; + + struct UserFont + { + // description of file + Font file_font; + // user defined font modification + FontProp prop; + // cache of glyphs + Emboss::Glyphs cache; + }; + /// /// Load font file into buffer /// diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 1ae6823bd..df6925a42 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -3255,7 +3255,7 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex stream << FONT_DESCRIPTOR_TYPE_ATTR << "=\"" << TextConfigurationSerialization::to_string.at(fi.type) << "\" "; // font property - const FontProp &fp = tc.font_prop; + const FontProp &fp = tc.font_item.prop; if (fp.char_gap.has_value()) stream << CHAR_GAP_ATTR << "=\"" << *fp.char_gap << "\" "; if (fp.line_gap.has_value()) @@ -3282,13 +3282,6 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex std::optional TextConfigurationSerialization::read(const char **attributes, unsigned int num_attributes) { - std::string text = get_attribute_value_string(attributes, num_attributes, TEXT_DATA_ATTR); - std::string font_name = ""; - std::string font_descriptor = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_ATTR); - std::string type_str = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_TYPE_ATTR); - FontItem::Type type = TextConfigurationSerialization::get_type(type_str); - FontItem fi(font_name, font_descriptor, type); - FontProp fp; int char_gap = get_attribute_value_int(attributes, num_attributes, CHAR_GAP_ATTR); if (char_gap != 0) fp.char_gap = char_gap; @@ -3313,7 +3306,14 @@ std::optional TextConfigurationSerialization::read(const char std::string weight = get_attribute_value_string(attributes, num_attributes, FONT_WEIGHT_ATTR); if (!weight.empty()) fp.weight = weight; - return TextConfiguration(fi, fp, text); + std::string font_name = ""; + std::string font_descriptor = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_ATTR); + std::string type_str = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_TYPE_ATTR); + FontItem::Type type = TextConfigurationSerialization::get_type(type_str); + FontItem fi(font_name, font_descriptor, type, fp); + + std::string text = get_attribute_value_string(attributes, num_attributes, TEXT_DATA_ATTR); + return TextConfiguration(fi, text); } diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp index 9c2abd61c..9f0dab858 100644 --- a/src/libslic3r/TextConfiguration.hpp +++ b/src/libslic3r/TextConfiguration.hpp @@ -7,6 +7,45 @@ namespace Slic3r { +// user defined font property +struct FontProp +{ + // define extra space between letters, negative mean closer letter + std::optional char_gap; + // define extra space between lines, negative mean closer lines + std::optional line_gap; + // Z depth of text [in mm] + float emboss; + + // positive value mean wider character shape + // negative value mean tiner character shape + std::optional boldness; // [in mm] + + // positive value mean italic of character (CW) + // negative value mean CCW skew (unItalic) + std::optional skew; + + // TODO: add enum class Align: center/left/right + + ////// + // Duplicit data to wxFontDescriptor + // used for store/load .3mf file + ////// + + // Height of letter [in mm], + // duplicit to wxFont::PointSize + float size_in_mm; + // Define type of font + std::optional family; + std::optional face_name; + std::optional style; + std::optional weight; + + FontProp(float line_height = 10.f, float depth = 2.f) + : emboss(depth), size_in_mm(line_height) + {} +}; + // represent selected font // Name must be human readable is visible in gui // (Path + Type) must define how to open font for using on different OS @@ -16,10 +55,17 @@ struct FontItem std::string path; enum class Type; Type type; + FontProp prop; FontItem() : type(Type::undefined){} // set undefined type - FontItem(const std::string &name, const std::string &path, Type type) - : name(name), path(path), type(type) + + // when name is empty than Font item was loaded from .3mf file + // and potentionaly it is not reproducable + FontItem(const std::string &name, + const std::string &path, + Type type, + const FontProp & prop) + : name(name), path(path), type(type), prop(prop) {} // define data stored in path @@ -32,60 +78,19 @@ struct FontItem wx_mac_font_descr // path is font descriptor generated by wxWidgets on windows }; }; -using FontList = std::vector; - -// user defined font property -struct FontProp -{ - // define extra space between letters, negative mean closer letter - std::optional char_gap = 0; - // define extra space between lines, negative mean closer lines - std::optional line_gap = 0; - // Z depth of text [in mm] - float emboss = 5; - - // positive value mean wider character shape - // negative value mean tiner character shape - std::optional boldness = 0.f; // [in mm] - - // positive value mean italic of character (CW) - // negative value mean CCW skew (unItalic) - std::optional skew = 0.f; - - // TODO: add enum class Align: center/left/right - - ////// - // Duplicit data to wxFontDescriptor - // used for store/load .3mf file - ////// - - // Height of letter [in mm], - // duplicit to wxFont::PointSize - float size_in_mm = 10; - // Define type of font - std::optional family; - std::optional face_name; - std::optional style; - std::optional weight; - - FontProp() = default; -}; +using FontList = std::vector; // define how to create 'Text volume' struct TextConfiguration { // define font FontItem font_item; - // user modification of font - FontProp font_prop; std::string text = "None"; TextConfiguration() = default; // optional needs empty constructor - TextConfiguration(const FontItem & font_item, - const FontProp & font_prop, - const std::string &text) - : font_item(font_item), font_prop(font_prop), text(text) + TextConfiguration(const FontItem &font_item, const std::string &text) + : font_item(font_item), text(text) {} }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 099c94ee4..c247b602b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -68,7 +68,7 @@ void GLGizmoEmboss::set_fine_position() const Camera &camera = wxGetApp().plater()->get_camera(); Polygon hull = CameraUtils::create_hull2d(camera, *volume); - // TODO: fix width + // TODO: fix width - showing scroll bar during first show advanced ImVec2 windows_size = m_gui_cfg->draw_advanced ? m_gui_cfg->minimal_window_size_with_advance : m_gui_cfg->minimal_window_size; @@ -371,8 +371,8 @@ void GLGizmoEmboss::on_set_state() set_fine_position(); // when open by hyperlink it needs to show up + // or after key 'T' windows doesn't appear m_parent.reload_scene(true); - // TODO: after key T windows doesn't appear } } @@ -453,9 +453,8 @@ FontList GLGizmoEmboss::create_default_font_list() { void GLGizmoEmboss::set_default_configuration() { - m_text = _u8L("Embossed text"); - m_font_prop = FontProp(); - load_font(); // reload actual font - because of font size + m_text = _u8L("Embossed text"); + //load_font(); // reload actual font - because of font size } Slic3r::TriangleMesh GLGizmoEmboss::create_default_mesh() @@ -475,8 +474,8 @@ Slic3r::TriangleMesh GLGizmoEmboss::create_mesh() // It is neccessary to create some shape // Emboss text window is opened by creation new embosstext object if (m_font == nullptr) return create_default_mesh(); - - TriangleMesh result = create_mesh(m_text.c_str(), *m_font, m_font_prop); + const FontItem &fi = m_font_list[m_font_selected]; + TriangleMesh result = create_mesh(m_text.c_str(), *m_font, fi.prop); if (result.its.empty()) return create_default_mesh(); return result; } @@ -511,7 +510,6 @@ void GLGizmoEmboss::check_selection() // successfull load volume for editing return; - // behave like adding new text m_volume = nullptr; set_default_configuration(); @@ -659,16 +657,9 @@ void GLGizmoEmboss::draw_font_list() std::string name = ImGuiWrapper::trunc(f.name, max_width); size_t index = &f - &m_font_list.front(); bool is_selected = index == m_font_selected; - auto flags = - ImGuiSelectableFlags_AllowItemOverlap; // allow clic buttons + auto flags = ImGuiSelectableFlags_AllowItemOverlap; // allow click buttons if (ImGui::Selectable(name.c_str(), is_selected, flags)) { - size_t prev_font_selected = m_font_selected; - m_font_selected = index; - if (!load_font()) { - m_font_selected = prev_font_selected; - } else { - process(); - } + if (load_font(index)) process(); } else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", f.name.c_str()); @@ -745,16 +736,19 @@ void GLGizmoEmboss::draw_text_input() void GLGizmoEmboss::draw_advanced() { + FontItem &fi = m_font_list[m_font_selected]; + FontProp &font_prop = fi.prop; + ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); if (ImGui::InputFloat(_u8L("Size[in mm]").c_str(), - &m_font_prop.size_in_mm)) { - if (m_font_prop.size_in_mm < 0.1) m_font_prop.size_in_mm = 10; + &font_prop.size_in_mm)) { + if (font_prop.size_in_mm < 0.1) font_prop.size_in_mm = 10; // store font size into path FontItem &fi = m_font_list[m_font_selected]; if (fi.type == WxFontUtils::get_actual_type()) { std::optional wx_font = WxFontUtils::load_wxFont(fi.path); if (wx_font.has_value()) { - wx_font->SetPointSize(m_font_prop.size_in_mm); + wx_font->SetPointSize(font_prop.size_in_mm); fi.path = WxFontUtils::store_wxFont(*wx_font); } } @@ -763,24 +757,30 @@ void GLGizmoEmboss::draw_advanced() process(); } ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); - if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &m_font_prop.emboss)) + if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &font_prop.emboss)) process(); ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width); - if(ImGuiWrapper::input_optional_int(_u8L("CharGap[in font points]").c_str(), m_font_prop.char_gap)) + if (ImGuiWrapper::input_optional_int(_u8L("CharGap[in font points]").c_str(), font_prop.char_gap)) { + m_font->cache.clear(); process(); + } ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width); - if (ImGuiWrapper::input_optional_int(_u8L("LineGap[in font points]").c_str(), m_font_prop.line_gap)) + if (ImGuiWrapper::input_optional_int(_u8L("LineGap[in font points]").c_str(), font_prop.line_gap)) process(); ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width); - if (m_imgui->slider_optional_float(_u8L("Boldness[in font points]").c_str(), m_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"))){ + m_font->cache.clear(); process(); + } ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width); - if (m_imgui->slider_optional_float(_u8L("Skew ratio").c_str(), m_font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("italic strength"))) + 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"))){ + m_font->cache.clear(); process(); + } // when more collection add selector if (m_font != nullptr && m_font->count > 1) { @@ -804,17 +804,17 @@ void GLGizmoEmboss::draw_advanced() #ifdef ALLOW_DEBUG_MODE std::string descriptor = m_font_list[m_font_selected].path; - ImGui::Text("family = %s", (m_font_prop.family.has_value() ? - m_font_prop.family->c_str() : + ImGui::Text("family = %s", (font_prop.family.has_value() ? + font_prop.family->c_str() : " --- ")); - ImGui::Text("face name = %s", (m_font_prop.face_name.has_value() ? - m_font_prop.face_name->c_str() : + ImGui::Text("face name = %s", (font_prop.face_name.has_value() ? + font_prop.face_name->c_str() : " --- ")); ImGui::Text("style = %s", - (m_font_prop.style.has_value() ? m_font_prop.style->c_str() : + (font_prop.style.has_value() ? font_prop.style->c_str() : " --- ")); - ImGui::Text("weight = %s", (m_font_prop.weight.has_value() ? - m_font_prop.weight->c_str() : + ImGui::Text("weight = %s", (font_prop.weight.has_value() ? + font_prop.weight->c_str() : " --- ")); ImGui::Text("descriptor = %s", descriptor.c_str()); ImGui::Image(m_imgui_font_atlas.TexID, @@ -825,6 +825,7 @@ void GLGizmoEmboss::draw_advanced() bool GLGizmoEmboss::load_font(size_t font_index) { + if (font_index >= m_font_list.size()) return false; std::swap(font_index, m_font_selected); bool is_loaded = load_font(); if (!is_loaded) std::swap(font_index, m_font_selected); @@ -860,20 +861,6 @@ bool GLGizmoEmboss::load_font(const wxFont &font) auto font_ptr = WxFontUtils::load_font(font); if (font_ptr == nullptr) return false; m_font = std::move(font_ptr); - WxFontUtils::update_property(m_font_prop, font); - -#ifdef __linux__ - // dynamic creation of italic, on linux is italic made by skew of normal font - wxFontStyle style = font.GetStyle(); - if (style == wxFONTSTYLE_ITALIC && - !Emboss::is_italic(*m_font) ) { - m_font_prop.skew = 0.2; - } -#endif - - // TODO: decide when rewrite emboss depth - m_font_prop.emboss = m_font_prop.size_in_mm / 2.f; - load_imgui_font(); return true; } @@ -926,8 +913,9 @@ void GLGizmoEmboss::load_imgui_font() m_imgui_font_ranges.clear(); builder.BuildRanges(&m_imgui_font_ranges); + const FontProp &font_prop = m_font_list[m_font_selected].prop; int font_size = static_cast( - std::round(std::abs(m_font_prop.size_in_mm / 0.3528))); + std::round(std::abs(font_prop.size_in_mm / 0.3528))); if (font_size < m_gui_cfg->min_imgui_font_size) font_size = m_gui_cfg->min_imgui_font_size; if (font_size > m_gui_cfg->max_imgui_font_size) @@ -988,7 +976,6 @@ bool GLGizmoEmboss::choose_font_by_wxdialog() size_t font_index = m_font_list.size(); FontItem font_item = WxFontUtils::get_font_item(font); m_font_list.emplace_back(font_item); - FontProp old_font_prop = m_font_prop; // copy // Check that deserialization NOT influence font // false - use direct selected wxFont in dialog @@ -1002,8 +989,6 @@ bool GLGizmoEmboss::choose_font_by_wxdialog() std::swap(font_index, m_font_selected); // when not process // remove form font list m_font_list.pop_back(); - // reverse property - m_font_prop = old_font_prop; // when not process wxString message = GUI::format_wxstr( _L("Font '%1%' can't be used. Please select another."), font_item.name); @@ -1029,7 +1014,7 @@ bool GLGizmoEmboss::choose_true_type_file() for (auto &input_file : input_files) { std::string path = std::string(input_file.c_str()); std::string name = get_file_name(path); - m_font_list.emplace_back(name, path, FontItem::Type::file_path); + m_font_list.emplace_back(name, path, FontItem::Type::file_path, FontProp()); // set first valid added font as active if (!font_loaded) { @@ -1064,9 +1049,10 @@ bool GLGizmoEmboss::choose_svg_file() BoundingBox bb; for (const auto &p : polys) bb.merge(p.contour.points); - float scale = m_font_prop.size_in_mm / std::max(bb.max.x(), bb.max.y()); + const FontProp &fp = m_font_list[m_font_selected].prop; + float scale = fp.size_in_mm / std::max(bb.max.x(), bb.max.y()); auto project = std::make_unique( - std::make_unique(m_font_prop.emboss / scale), scale); + std::make_unique(fp.emboss / scale), scale); indexed_triangle_set its = Emboss::polygons2model(polys, *project); return false; // test store: @@ -1078,8 +1064,7 @@ bool GLGizmoEmboss::choose_svg_file() TextConfiguration GLGizmoEmboss::create_configuration() { - return TextConfiguration(m_font_list[m_font_selected], m_font_prop, - m_text); + return TextConfiguration(m_font_list[m_font_selected], m_text); } bool GLGizmoEmboss::load_configuration(ModelVolume *volume) @@ -1108,18 +1093,16 @@ bool GLGizmoEmboss::load_configuration(ModelVolume *volume) m_font_selected = it - m_font_list.begin(); } - m_font_prop = configuration.font_prop; m_text = configuration.text; m_volume = volume; if (!load_font()) { // create similar font - auto wx_font = WxFontUtils::create_wxFont(c_font_item, - configuration.font_prop); + auto wx_font = WxFontUtils::create_wxFont(c_font_item, configuration.font_item.prop); if (wx_font.has_value()) { // fix not loadable font item - m_font_list[m_font_selected] = WxFontUtils::get_font_item( - *wx_font); + m_font_list[m_font_selected] = WxFontUtils::get_font_item(*wx_font); + m_font_list[m_font_selected].prop = configuration.font_item.prop; if (!load_font(*wx_font)) return false; } else { // can't create similar font use previous @@ -1143,9 +1126,9 @@ void GLGizmoEmboss::create_notification_not_valid_font( auto level = NotificationManager::NotificationLevel::WarningNotificationLevel; - const auto &origin_family = tc.font_prop.face_name; - const auto &actual_family = m_font_prop.face_name; const auto &fi = m_font_list[m_font_selected]; + const auto &origin_family = tc.font_item.prop.face_name; + const auto &actual_family = fi.prop.face_name; const std::string &origin_font_name = origin_family.has_value() ? *origin_family : @@ -1308,12 +1291,59 @@ void GLGizmoEmboss::store_font_list() const std::string GLGizmoEmboss::APP_CONFIG_FONT_NAME = "name"; const std::string GLGizmoEmboss::APP_CONFIG_FONT_DESCRIPTOR = "descriptor"; +const std::string GLGizmoEmboss::APP_CONFIG_FONT_LINE_HEIGHT = "line_height"; +const std::string GLGizmoEmboss::APP_CONFIG_FONT_DEPTH = "depth"; +const std::string GLGizmoEmboss::APP_CONFIG_FONT_BOLDNESS = "boldness"; +const std::string GLGizmoEmboss::APP_CONFIG_FONT_SKEW = "skew"; +const std::string GLGizmoEmboss::APP_CONFIG_FONT_CHAR_GAP = "char_gap"; +const std::string GLGizmoEmboss::APP_CONFIG_FONT_LINE_GAP = "line_gap"; std::string GLGizmoEmboss::get_app_config_font_section(unsigned index) { return AppConfig::SECTION_FONT + ':' + std::to_string(index); } +#include "fast_float/fast_float.h" +static bool read(const std::map& section, const std::string& key, float& value){ + auto item = section.find(key); + if (item == section.end()) return false; + const std::string &data = item->second; + if (data.empty()) return false; + float value_; + fast_float::from_chars(data.c_str(), data.c_str() + data.length(), value_); + // read only non zero value + if (fabs(value_) <= std::numeric_limits::epsilon()) return false; + + value = value_; + return true; +} + +static bool read(const std::map& section, const std::string& key, std::optional& value){ + auto item = section.find(key); + if (item == section.end()) return false; + const std::string &data = item->second; + if (data.empty()) return false; + int value_ = std::atoi(data.c_str()); + if (value_ == 0) return false; + + value = value_; + return true; +} + +static bool read(const std::map& section, const std::string& key, std::optional& value){ + auto item = section.find(key); + if (item == section.end()) return false; + const std::string &data = item->second; + if (data.empty()) return false; + float value_; + fast_float::from_chars(data.c_str(), data.c_str() + data.length(), value_); + // read only non zero value + if (fabs(value_) <= std::numeric_limits::epsilon()) return false; + + value = value_; + return true; +} + std::optional GLGizmoEmboss::get_font_item( const std::map &app_cfg_section) { @@ -1323,10 +1353,20 @@ std::optional GLGizmoEmboss::get_font_item( auto name_it = app_cfg_section.find(APP_CONFIG_FONT_NAME); static const std::string default_name = "font_name"; - const std::string & name = (name_it == app_cfg_section.end()) ? - default_name : - name_it->second; - return FontItem(name, path, WxFontUtils::get_actual_type()); + const std::string &name = + (name_it == app_cfg_section.end()) ? + default_name : name_it->second; + + FontProp fp; + read(app_cfg_section, APP_CONFIG_FONT_LINE_HEIGHT, fp.size_in_mm); + read(app_cfg_section, APP_CONFIG_FONT_DEPTH, fp.emboss); + read(app_cfg_section, APP_CONFIG_FONT_BOLDNESS, fp.boldness); + read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew); + read(app_cfg_section, APP_CONFIG_FONT_CHAR_GAP, fp.char_gap); + read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap); + + FontItem::Type type = WxFontUtils::get_actual_type(); + return FontItem(name, path, type, fp); } void GLGizmoEmboss::set_font_item(AppConfig & cfg, @@ -1337,6 +1377,17 @@ void GLGizmoEmboss::set_font_item(AppConfig & cfg, cfg.clear_section(section_name); cfg.set(section_name, APP_CONFIG_FONT_NAME, fi.name); cfg.set(section_name, APP_CONFIG_FONT_DESCRIPTOR, fi.path); + const FontProp &fp = fi.prop; + cfg.set(section_name, APP_CONFIG_FONT_LINE_HEIGHT, std::to_string(fp.size_in_mm)); + cfg.set(section_name, APP_CONFIG_FONT_DEPTH, std::to_string(fp.emboss)); + if (fp.boldness.has_value()) + cfg.set(section_name, APP_CONFIG_FONT_BOLDNESS, std::to_string(*fp.boldness)); + if (fp.skew.has_value()) + cfg.set(section_name, APP_CONFIG_FONT_SKEW, std::to_string(*fp.skew)); + if (fp.char_gap.has_value()) + cfg.set(section_name, APP_CONFIG_FONT_CHAR_GAP, std::to_string(*fp.char_gap)); + if (fp.line_gap.has_value()) + cfg.set(section_name, APP_CONFIG_FONT_LINE_GAP, std::to_string(*fp.line_gap)); } std::string GLGizmoEmboss::get_file_name(const std::string &file_path) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 20981d71d..69549625b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -167,7 +167,6 @@ private: // to share data with job thread std::shared_ptr m_font; std::string m_text; - FontProp m_font_prop; // actual volume ModelVolume *m_volume; @@ -199,8 +198,16 @@ private: // load / store appConfig void load_font_list(); void store_font_list(); + + // app config Attribute names static const std::string APP_CONFIG_FONT_NAME; static const std::string APP_CONFIG_FONT_DESCRIPTOR; + static const std::string APP_CONFIG_FONT_LINE_HEIGHT; + static const std::string APP_CONFIG_FONT_DEPTH; + static const std::string APP_CONFIG_FONT_BOLDNESS; + static const std::string APP_CONFIG_FONT_SKEW; + static const std::string APP_CONFIG_FONT_CHAR_GAP; + static const std::string APP_CONFIG_FONT_LINE_GAP; std::string get_app_config_font_section(unsigned index); std::optional get_font_item(const std::map &app_cfg_section); void set_font_item(AppConfig &cfg, const FontItem &fi, unsigned index); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 259b1d7d3..adaf4bbc5 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -31,7 +31,7 @@ void EmbossJob::process(Ctl &ctl) { // Do NOT process empty string if (text.empty()) return; - const FontProp &prop = cfg.font_prop; + const FontProp &prop = cfg.font_item.prop; ExPolygons shapes = Emboss::text2shapes(*m_input->font, text.c_str(), prop); if (ctl.was_canceled()) return; diff --git a/src/slic3r/Utils/WxFontUtils.cpp b/src/slic3r/Utils/WxFontUtils.cpp index 5a8853cf3..efb9fcd97 100644 --- a/src/slic3r/Utils/WxFontUtils.cpp +++ b/src/slic3r/Utils/WxFontUtils.cpp @@ -63,8 +63,11 @@ FontItem WxFontUtils::get_font_item(const wxFont &font) std::string name = get_human_readable_name(font); std::string fontDesc = store_wxFont(font); FontItem::Type type = get_actual_type(); - // wxFont f = font; // copy - return FontItem(name, fontDesc, type); + + // synchronize font property with actual font + FontProp font_prop; + WxFontUtils::update_property(font_prop, font); + return FontItem(name, fontDesc, type, font_prop); } FontItem WxFontUtils::get_os_font() @@ -183,6 +186,7 @@ void WxFontUtils::update_property(FontProp &font_prop, const wxFont &font) // is approximately 0.0139 inch or 352.8 um. But it is too small, so I // decide use point size as mm for emboss font_prop.size_in_mm = font.GetPointSize(); // *0.3528f; + font_prop.emboss = font_prop.size_in_mm / 2.f; wxString wx_face_name = font.GetFaceName(); std::string face_name((const char *) wx_face_name.ToUTF8()); @@ -206,5 +210,12 @@ void WxFontUtils::update_property(FontProp &font_prop, const wxFont &font) if (it != from_weight.end()) font_prop.weight = it->second; } - +#ifdef __linux__ + // dynamic creation of italic, on linux is italic made by skew of normal font + wxFontStyle style = font.GetStyle(); + if ((style == wxFONTSTYLE_ITALIC || style == wxFONTSTYLE_SLANT) && + !Emboss::is_italic(*m_font)) { + font_prop.skew = 0.2; + } +#endif }