Move font property inside of font item to store together with font

This commit is contained in:
Filip Sykala 2022-01-07 18:50:57 +01:00
parent ce1df3eada
commit ef6860d4ee
8 changed files with 259 additions and 156 deletions

View File

@ -148,14 +148,48 @@ std::optional<Emboss::Glyph> 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<int>(glyph_opt->advance_width / Emboss::SHAPE_SCALE);
glyph_opt->left_side_bearing =
static_cast<int>(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<int>(line_height / SHAPE_SCALE);
cursor.x() = 0;
cursor.y() -= static_cast<int>(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<Glyph> 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<int>((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<int>(width / SHAPE_SCALE);
cursor.x() += glyph_opt->advance_width;
expolygons_append(result, expolygons);
}
result = Slic3r::union_ex(result);

View File

@ -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<int, Glyph>;
/// <summary>
/// keep information from file about font
/// + cache shape of glyphs (optionaly modified)
/// + user defined modification of font
/// </summary>
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<unsigned char> &&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;
};
/// <summary>
/// Load font file into buffer
/// </summary>

View File

@ -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<TextConfiguration> 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<TextConfiguration> 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);
}

View File

@ -7,6 +7,45 @@
namespace Slic3r {
// user defined font property
struct FontProp
{
// define extra space between letters, negative mean closer letter
std::optional<int> char_gap;
// define extra space between lines, negative mean closer lines
std::optional<int> line_gap;
// Z depth of text [in mm]
float emboss;
// positive value mean wider character shape
// negative value mean tiner character shape
std::optional<float> boldness; // [in mm]
// positive value mean italic of character (CW)
// negative value mean CCW skew (unItalic)
std::optional<float> 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<std::string> family;
std::optional<std::string> face_name;
std::optional<std::string> style;
std::optional<std::string> 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<FontItem>;
// user defined font property
struct FontProp
{
// define extra space between letters, negative mean closer letter
std::optional<int> char_gap = 0;
// define extra space between lines, negative mean closer lines
std::optional<int> 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<float> boldness = 0.f; // [in mm]
// positive value mean italic of character (CW)
// negative value mean CCW skew (unItalic)
std::optional<float> 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<std::string> family;
std::optional<std::string> face_name;
std::optional<std::string> style;
std::optional<std::string> weight;
FontProp() = default;
};
using FontList = std::vector<FontItem>;
// 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)
{}
};

View File

@ -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<wxFont> 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<int>(
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<Emboss::ProjectScale>(
std::make_unique<Emboss::ProjectZ>(m_font_prop.emboss / scale), scale);
std::make_unique<Emboss::ProjectZ>(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<std::string, std::string>& 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<float>::epsilon()) return false;
value = value_;
return true;
}
static bool read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<int>& 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<std::string, std::string>& section, const std::string& key, std::optional<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<float>::epsilon()) return false;
value = value_;
return true;
}
std::optional<FontItem> GLGizmoEmboss::get_font_item(
const std::map<std::string, std::string> &app_cfg_section)
{
@ -1323,10 +1353,20 @@ std::optional<FontItem> 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)

View File

@ -167,7 +167,6 @@ private:
// to share data with job thread
std::shared_ptr<Emboss::Font> 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<FontItem> get_font_item(const std::map<std::string, std::string> &app_cfg_section);
void set_font_item(AppConfig &cfg, const FontItem &fi, unsigned index);

View File

@ -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;

View File

@ -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
}