mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 12:45:56 +08:00
Separate font manager to be able manage imgui font for all fonts
Separate FontListSerializable Rename Emboss::Font to Emboss::FontFile
This commit is contained in:
parent
2c3477d3d7
commit
4d31128837
@ -22,10 +22,10 @@ class Private
|
|||||||
public:
|
public:
|
||||||
Private() = delete;
|
Private() = delete;
|
||||||
|
|
||||||
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::Font &font);
|
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::FontFile &font);
|
||||||
static std::optional<stbtt_fontinfo> load_font_info(const unsigned char *data, unsigned int index = 0);
|
static std::optional<stbtt_fontinfo> load_font_info(const unsigned char *data, unsigned int index = 0);
|
||||||
static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness);
|
static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness);
|
||||||
static std::optional<Emboss::Glyph> get_glyph(int unicode, const Emboss::Font &font, const FontProp &font_prop,
|
static std::optional<Emboss::Glyph> get_glyph(int unicode, const Emboss::FontFile &font, const FontProp &font_prop,
|
||||||
Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt);
|
Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt);
|
||||||
|
|
||||||
static FontItem create_font_item(std::wstring name, std::wstring path);
|
static FontItem create_font_item(std::wstring name, std::wstring path);
|
||||||
@ -42,7 +42,7 @@ public:
|
|||||||
static Point to_point(const stbtt__point &point);
|
static Point to_point(const stbtt__point &point);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::Font &font)
|
std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::FontFile &font)
|
||||||
{
|
{
|
||||||
return load_font_info(font.buffer.data(), font.index);
|
return load_font_info(font.buffer.data(), font.index);
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ std::optional<Emboss::Glyph> Private::get_glyph(stbtt_fontinfo &font_info, int u
|
|||||||
|
|
||||||
std::optional<Emboss::Glyph> Private::get_glyph(
|
std::optional<Emboss::Glyph> Private::get_glyph(
|
||||||
int unicode,
|
int unicode,
|
||||||
const Emboss::Font & font,
|
const Emboss::FontFile & font,
|
||||||
const FontProp & font_prop,
|
const FontProp & font_prop,
|
||||||
Emboss::Glyphs & cache,
|
Emboss::Glyphs & cache,
|
||||||
std::optional<stbtt_fontinfo> &font_info_opt)
|
std::optional<stbtt_fontinfo> &font_info_opt)
|
||||||
@ -465,7 +465,8 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::unique_ptr<Emboss::Font> Emboss::load_font(std::vector<unsigned char>&& data)
|
std::unique_ptr<Emboss::FontFile> Emboss::load_font(
|
||||||
|
std::vector<unsigned char> &&data)
|
||||||
{
|
{
|
||||||
unsigned int collection_size = 0;
|
unsigned int collection_size = 0;
|
||||||
int font_offset = 0;
|
int font_offset = 0;
|
||||||
@ -485,11 +486,11 @@ std::unique_ptr<Emboss::Font> Emboss::load_font(std::vector<unsigned char>&& dat
|
|||||||
// load information about line gap
|
// load information about line gap
|
||||||
int ascent, descent, linegap;
|
int ascent, descent, linegap;
|
||||||
stbtt_GetFontVMetrics(info, &ascent, &descent, &linegap);
|
stbtt_GetFontVMetrics(info, &ascent, &descent, &linegap);
|
||||||
return std::make_unique<Emboss::Font>(
|
return std::make_unique<Emboss::FontFile>(
|
||||||
std::move(data), collection_size, ascent, descent, linegap);
|
std::move(data), collection_size, ascent, descent, linegap);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Emboss::Font> Emboss::load_font(const char *file_path)
|
std::unique_ptr<Emboss::FontFile> Emboss::load_font(const char *file_path)
|
||||||
{
|
{
|
||||||
FILE *file = fopen(file_path, "rb");
|
FILE *file = fopen(file_path, "rb");
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
@ -520,7 +521,7 @@ std::unique_ptr<Emboss::Font> Emboss::load_font(const char *file_path)
|
|||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::unique_ptr<Emboss::Font> Emboss::load_font(HFONT hfont)
|
std::unique_ptr<Emboss::FontFile> Emboss::load_font(HFONT hfont)
|
||||||
{
|
{
|
||||||
HDC hdc = ::CreateCompatibleDC(NULL);
|
HDC hdc = ::CreateCompatibleDC(NULL);
|
||||||
if (hdc == NULL) {
|
if (hdc == NULL) {
|
||||||
@ -559,7 +560,7 @@ std::unique_ptr<Emboss::Font> Emboss::load_font(HFONT hfont)
|
|||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
std::optional<Emboss::Glyph> Emboss::letter2glyph(const Font &font,
|
std::optional<Emboss::Glyph> Emboss::letter2glyph(const FontFile &font,
|
||||||
int letter,
|
int letter,
|
||||||
float flatness)
|
float flatness)
|
||||||
{
|
{
|
||||||
@ -568,7 +569,7 @@ std::optional<Emboss::Glyph> Emboss::letter2glyph(const Font &font,
|
|||||||
return Private::get_glyph(*font_info_opt, letter, flatness);
|
return Private::get_glyph(*font_info_opt, letter, flatness);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExPolygons Emboss::text2shapes(Font & font,
|
ExPolygons Emboss::text2shapes(FontFile & font,
|
||||||
const char * text,
|
const char * text,
|
||||||
const FontProp &font_prop)
|
const FontProp &font_prop)
|
||||||
{
|
{
|
||||||
@ -614,7 +615,7 @@ ExPolygons Emboss::text2shapes(Font & font,
|
|||||||
return Private::dilate_to_unique_points(result);
|
return Private::dilate_to_unique_points(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Emboss::is_italic(Font &font) {
|
bool Emboss::is_italic(FontFile &font) {
|
||||||
std::optional<stbtt_fontinfo> font_info_opt =
|
std::optional<stbtt_fontinfo> font_info_opt =
|
||||||
Private::load_font_info(font);
|
Private::load_font_info(font);
|
||||||
|
|
||||||
|
@ -53,10 +53,11 @@ public:
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// keep information from file about font
|
/// keep information from file about font
|
||||||
|
/// (store file data itself)
|
||||||
|
/// + cache data readed from buffer
|
||||||
/// + cache shape of glyphs (optionaly modified)
|
/// + cache shape of glyphs (optionaly modified)
|
||||||
/// + user defined modification of font
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
struct Font
|
struct FontFile
|
||||||
{
|
{
|
||||||
// loaded data from font file
|
// loaded data from font file
|
||||||
const std::vector<unsigned char> buffer;
|
const std::vector<unsigned char> buffer;
|
||||||
@ -67,13 +68,9 @@ public:
|
|||||||
// vertical position is "scale*(ascent - descent + lineGap)"
|
// vertical position is "scale*(ascent - descent + lineGap)"
|
||||||
const int ascent, descent, linegap;
|
const int ascent, descent, linegap;
|
||||||
|
|
||||||
// user defined font modification
|
|
||||||
// + emboss parameter
|
|
||||||
FontProp prop;
|
|
||||||
|
|
||||||
Emboss::Glyphs cache; // cache of glyphs
|
Emboss::Glyphs cache; // cache of glyphs
|
||||||
|
|
||||||
Font(std::vector<unsigned char> &&buffer,
|
FontFile(std::vector<unsigned char> &&buffer,
|
||||||
unsigned int count,
|
unsigned int count,
|
||||||
int ascent,
|
int ascent,
|
||||||
int descent,
|
int descent,
|
||||||
@ -84,33 +81,21 @@ public:
|
|||||||
, ascent(ascent)
|
, ascent(ascent)
|
||||||
, descent(descent)
|
, descent(descent)
|
||||||
, linegap(linegap)
|
, 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>
|
/// <summary>
|
||||||
/// Load font file into buffer
|
/// Load font file into buffer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="file_path">Location of .ttf or .ttc font file</param>
|
/// <param name="file_path">Location of .ttf or .ttc font file</param>
|
||||||
/// <returns>Font object when loaded.</returns>
|
/// <returns>Font object when loaded.</returns>
|
||||||
static std::unique_ptr<Font> load_font(const char *file_path);
|
static std::unique_ptr<FontFile> load_font(const char *file_path);
|
||||||
// data = raw file data
|
// data = raw file data
|
||||||
static std::unique_ptr<Font> load_font(std::vector<unsigned char>&& data);
|
static std::unique_ptr<FontFile> load_font(std::vector<unsigned char>&& data);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// fix for unknown pointer HFONT
|
// fix for unknown pointer HFONT
|
||||||
using HFONT = void*;
|
using HFONT = void*;
|
||||||
static std::unique_ptr<Font> load_font(HFONT hfont);
|
static std::unique_ptr<FontFile> load_font(HFONT hfont);
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -120,7 +105,7 @@ public:
|
|||||||
/// <param name="letter">One character defined by unicode codepoint</param>
|
/// <param name="letter">One character defined by unicode codepoint</param>
|
||||||
/// <param name="flatness">Precision of lettter outline curve in conversion to lines</param>
|
/// <param name="flatness">Precision of lettter outline curve in conversion to lines</param>
|
||||||
/// <returns>inner polygon cw(outer ccw)</returns>
|
/// <returns>inner polygon cw(outer ccw)</returns>
|
||||||
static std::optional<Glyph> letter2glyph(const Font &font, int letter, float flatness);
|
static std::optional<Glyph> letter2glyph(const FontFile &font, int letter, float flatness);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert text into polygons
|
/// Convert text into polygons
|
||||||
@ -129,7 +114,7 @@ public:
|
|||||||
/// <param name="text">Characters to convert</param>
|
/// <param name="text">Characters to convert</param>
|
||||||
/// <param name="font_prop">User defined property of the font</param>
|
/// <param name="font_prop">User defined property of the font</param>
|
||||||
/// <returns>Inner polygon cw(outer ccw)</returns>
|
/// <returns>Inner polygon cw(outer ccw)</returns>
|
||||||
static ExPolygons text2shapes(Font & font,
|
static ExPolygons text2shapes(FontFile & font,
|
||||||
const char * text,
|
const char * text,
|
||||||
const FontProp &font_prop);
|
const FontProp &font_prop);
|
||||||
|
|
||||||
@ -139,7 +124,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="font">Selector of font</param>
|
/// <param name="font">Selector of font</param>
|
||||||
/// <returns>True when the font description contains italic/obligue otherwise False</returns>
|
/// <returns>True when the font description contains italic/obligue otherwise False</returns>
|
||||||
static bool is_italic(Font &font);
|
static bool is_italic(FontFile &font);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Project 2d point into space
|
/// Project 2d point into space
|
||||||
|
@ -873,6 +873,11 @@ private:
|
|||||||
this->calculate_convex_hull();
|
this->calculate_convex_hull();
|
||||||
} else
|
} else
|
||||||
m_convex_hull.reset();
|
m_convex_hull.reset();
|
||||||
|
//TextConfiguration tc;
|
||||||
|
//cereal::load_by_value(ar, tc);
|
||||||
|
//if (tc.font_item.type != FontItem::Type::undefined) {
|
||||||
|
// text_configuration = tc;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
template<class Archive> void save(Archive &ar) const {
|
template<class Archive> void save(Archive &ar) const {
|
||||||
bool has_convex_hull = m_convex_hull.get() != nullptr;
|
bool has_convex_hull = m_convex_hull.get() != nullptr;
|
||||||
@ -883,6 +888,8 @@ private:
|
|||||||
cereal::save_by_value(ar, config);
|
cereal::save_by_value(ar, config);
|
||||||
if (has_convex_hull)
|
if (has_convex_hull)
|
||||||
cereal::save_optional(ar, m_convex_hull);
|
cereal::save_optional(ar, m_convex_hull);
|
||||||
|
//if (text_configuration.has_value())
|
||||||
|
// cereal::save_by_value(ar, *text_configuration);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,6 +44,30 @@ struct FontProp
|
|||||||
FontProp(float line_height = 10.f, float depth = 2.f)
|
FontProp(float line_height = 10.f, float depth = 2.f)
|
||||||
: emboss(depth), size_in_mm(line_height)
|
: emboss(depth), size_in_mm(line_height)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
bool operator==(const FontProp& other) const {
|
||||||
|
auto is_equal = [](const float &v1, const float &v2) {
|
||||||
|
return fabs(v1 - v2) < std::numeric_limits<float>::epsilon();
|
||||||
|
};
|
||||||
|
auto is_equal_ = [&is_equal](const std::optional<float> &v1,
|
||||||
|
const std::optional<float> &v2) {
|
||||||
|
return (!v1.has_value() && !v2.has_value()) ||
|
||||||
|
(v1.has_value() && v2.has_value() && is_equal(*v1, *v2));
|
||||||
|
};
|
||||||
|
return
|
||||||
|
char_gap == other.char_gap &&
|
||||||
|
line_gap == other.line_gap &&
|
||||||
|
is_equal(emboss, other.emboss) &&
|
||||||
|
is_equal(size_in_mm, other.size_in_mm) &&
|
||||||
|
is_equal_(boldness, other.boldness) &&
|
||||||
|
is_equal_(skew, other.skew);
|
||||||
|
}
|
||||||
|
|
||||||
|
// undo / redo stack recovery
|
||||||
|
template<class Archive> void serialize(Archive &ar)
|
||||||
|
{
|
||||||
|
ar(char_gap, line_gap, emboss, boldness, skew, size_in_mm, family, face_name, style, weight);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// represent selected font
|
// represent selected font
|
||||||
@ -78,6 +102,12 @@ struct FontItem
|
|||||||
wx_lin_font_descr, // path is font descriptor generated by wxWidgets on windows
|
wx_lin_font_descr, // path is font descriptor generated by wxWidgets on windows
|
||||||
wx_mac_font_descr // path is font descriptor generated by wxWidgets on windows
|
wx_mac_font_descr // path is font descriptor generated by wxWidgets on windows
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// undo / redo stack recovery
|
||||||
|
template<class Archive> void serialize(Archive &ar)
|
||||||
|
{
|
||||||
|
ar(name, path, (int) type, prop);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Font item name inside list is unique
|
// Font item name inside list is unique
|
||||||
@ -99,6 +129,9 @@ struct TextConfiguration
|
|||||||
TextConfiguration(const FontItem &font_item, const std::string &text)
|
TextConfiguration(const FontItem &font_item, const std::string &text)
|
||||||
: font_item(font_item), text(text)
|
: font_item(font_item), text(text)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// undo / redo stack recovery
|
||||||
|
template<class Archive> void serialize(Archive &ar){ ar(text, font_item); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -234,6 +234,10 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
Utils/FlashAir.hpp
|
Utils/FlashAir.hpp
|
||||||
Utils/FontConfigHelp.cpp
|
Utils/FontConfigHelp.cpp
|
||||||
Utils/FontConfigHelp.hpp
|
Utils/FontConfigHelp.hpp
|
||||||
|
Utils/FontListSerializable.cpp
|
||||||
|
Utils/FontListSerializable.hpp
|
||||||
|
Utils/FontManager.cpp
|
||||||
|
Utils/FontManager.hpp
|
||||||
Utils/AstroBox.cpp
|
Utils/AstroBox.cpp
|
||||||
Utils/AstroBox.hpp
|
Utils/AstroBox.hpp
|
||||||
Utils/Repetier.cpp
|
Utils/Repetier.cpp
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "slic3r/GUI/Jobs/EmbossJob.hpp"
|
#include "slic3r/GUI/Jobs/EmbossJob.hpp"
|
||||||
#include "slic3r/GUI/Jobs/NotificationProgressIndicator.hpp"
|
#include "slic3r/GUI/Jobs/NotificationProgressIndicator.hpp"
|
||||||
#include "slic3r/Utils/WxFontUtils.hpp"
|
#include "slic3r/Utils/WxFontUtils.hpp"
|
||||||
|
#include "slic3r/Utils/FontListSerializable.hpp"
|
||||||
|
|
||||||
// TODO: remove include
|
// TODO: remove include
|
||||||
#include "libslic3r/SVG.hpp" // debug store
|
#include "libslic3r/SVG.hpp" // debug store
|
||||||
@ -36,19 +37,16 @@
|
|||||||
// uncomment for easier debug
|
// uncomment for easier debug
|
||||||
//#define ALLOW_DEBUG_MODE
|
//#define ALLOW_DEBUG_MODE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::GUI;
|
using namespace Slic3r::GUI;
|
||||||
|
|
||||||
GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
|
GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
|
||||||
: GLGizmoBase(parent, M_ICON_FILENAME, -2)
|
: GLGizmoBase(parent, M_ICON_FILENAME, -2)
|
||||||
, m_font_selected(0)
|
|
||||||
, m_font(nullptr)
|
|
||||||
, m_volume(nullptr)
|
, m_volume(nullptr)
|
||||||
, m_exist_notification(false)
|
, m_exist_notification(false)
|
||||||
, m_is_initialized(false) // initialize on first opening gizmo
|
, m_is_initialized(false) // initialize on first opening gizmo
|
||||||
, m_rotate_gizmo(parent, GLGizmoRotate::Axis::Z) // grab id = 2 (Z axis)
|
, m_rotate_gizmo(parent, GLGizmoRotate::Axis::Z) // grab id = 2 (Z axis)
|
||||||
|
, m_font_manager(m_imgui->get_glyph_ranges())
|
||||||
{
|
{
|
||||||
m_rotate_gizmo.set_group_id(0);
|
m_rotate_gizmo.set_group_id(0);
|
||||||
// TODO: add suggestion to use https://fontawesome.com/
|
// TODO: add suggestion to use https://fontawesome.com/
|
||||||
@ -118,7 +116,7 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
|
|||||||
const Selection &selection = m_parent.get_selection();
|
const Selection &selection = m_parent.get_selection();
|
||||||
if(selection.is_empty()) return;
|
if(selection.is_empty()) return;
|
||||||
|
|
||||||
set_default_configuration();
|
set_default_text();
|
||||||
|
|
||||||
// By position of cursor create transformation to put text on surface of model
|
// By position of cursor create transformation to put text on surface of model
|
||||||
Transform3d transformation;
|
Transform3d transformation;
|
||||||
@ -355,7 +353,7 @@ void GLGizmoEmboss::on_set_state()
|
|||||||
bool create_new_object = selection.is_empty();
|
bool create_new_object = selection.is_empty();
|
||||||
// When add Text on empty plate, Create new object with volume
|
// When add Text on empty plate, Create new object with volume
|
||||||
if (create_new_object) {
|
if (create_new_object) {
|
||||||
set_default_configuration();
|
set_default_text();
|
||||||
create_emboss_object(create_mesh(), create_volume_name(), create_configuration());
|
create_emboss_object(create_mesh(), create_volume_name(), create_configuration());
|
||||||
|
|
||||||
// gizmo will open when successfuly create new object
|
// gizmo will open when successfuly create new object
|
||||||
@ -428,26 +426,26 @@ void GLGizmoEmboss::initialize()
|
|||||||
m_gui_cfg->minimal_window_size_with_advance =
|
m_gui_cfg->minimal_window_size_with_advance =
|
||||||
ImVec2(window_width, window_height + advance_height);
|
ImVec2(window_width, window_height + advance_height);
|
||||||
|
|
||||||
// TODO: What to do when icon was NOT loaded?
|
// TODO: What to do when icon was NOT loaded? Generate them?
|
||||||
bool success = init_icons();
|
bool success = init_icons();
|
||||||
assert(success);
|
assert(success);
|
||||||
load_font_list_from_app_config();
|
|
||||||
|
|
||||||
// try to load valid font
|
const AppConfig *app_cfg = wxGetApp().app_config;
|
||||||
m_font_selected = 0;
|
FontList font_list = load_font_list_from_app_config(app_cfg);
|
||||||
bool is_font_loaded = load_font();
|
m_font_manager.add_fonts(font_list);
|
||||||
while (!is_font_loaded && !m_font_list.empty()) {
|
if (!m_font_manager.load_first_valid_font()) {
|
||||||
// can't load so erase it from list
|
FontList font_list = FontListSerializable::create_default_font_list();
|
||||||
m_font_list.erase(m_font_list.begin());
|
m_font_manager.add_fonts(font_list);
|
||||||
is_font_loaded = load_font();
|
// TODO: What to do when default fonts are not loadable?
|
||||||
|
bool success = m_font_manager.load_first_valid_font();
|
||||||
|
assert(success);
|
||||||
}
|
}
|
||||||
set_default_configuration();
|
set_default_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::set_default_configuration()
|
void GLGizmoEmboss::set_default_text()
|
||||||
{
|
{
|
||||||
m_text = _u8L("Embossed text");
|
m_text = _u8L("Embossed text");
|
||||||
//load_font(); // reload actual font - because of font size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Slic3r::TriangleMesh GLGizmoEmboss::create_default_mesh()
|
Slic3r::TriangleMesh GLGizmoEmboss::create_default_mesh()
|
||||||
@ -466,15 +464,17 @@ Slic3r::TriangleMesh GLGizmoEmboss::create_mesh()
|
|||||||
{
|
{
|
||||||
// It is neccessary to create some shape
|
// It is neccessary to create some shape
|
||||||
// Emboss text window is opened by creation new embosstext object
|
// Emboss text window is opened by creation new embosstext object
|
||||||
if (m_font == nullptr) return create_default_mesh();
|
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
||||||
const FontItem &fi = m_font_list[m_font_selected];
|
if (font_file == nullptr || m_font_manager.get_fonts().empty())
|
||||||
TriangleMesh result = create_mesh(m_text.c_str(), *m_font, fi.prop);
|
return create_default_mesh();
|
||||||
|
const FontItem &fi = m_font_manager.get_font_item();
|
||||||
|
TriangleMesh result = create_mesh(m_text.c_str(), *font_file, fi.prop);
|
||||||
if (result.its.empty()) return create_default_mesh();
|
if (result.its.empty()) return create_default_mesh();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Slic3r::TriangleMesh GLGizmoEmboss::create_mesh(const char * text,
|
Slic3r::TriangleMesh GLGizmoEmboss::create_mesh(const char * text,
|
||||||
Emboss::Font &font,
|
Emboss::FontFile &font,
|
||||||
const FontProp & font_prop)
|
const FontProp & font_prop)
|
||||||
{
|
{
|
||||||
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
|
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
|
||||||
@ -505,7 +505,7 @@ void GLGizmoEmboss::check_selection()
|
|||||||
|
|
||||||
// behave like adding new text
|
// behave like adding new text
|
||||||
m_volume = nullptr;
|
m_volume = nullptr;
|
||||||
set_default_configuration();
|
set_default_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelVolume *GLGizmoEmboss::get_selected_volume()
|
ModelVolume *GLGizmoEmboss::get_selected_volume()
|
||||||
@ -551,9 +551,11 @@ bool GLGizmoEmboss::process()
|
|||||||
if (m_volume == nullptr) return false;
|
if (m_volume == nullptr) return false;
|
||||||
|
|
||||||
// exist loaded font?
|
// exist loaded font?
|
||||||
if (m_font == nullptr) return false;
|
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
||||||
auto data = std::make_unique<EmbossData>(
|
if (font_file == nullptr) return false;
|
||||||
m_font, create_configuration(), create_volume_name(), m_volume);
|
auto data = std::make_unique<EmbossData>(font_file,
|
||||||
|
create_configuration(),
|
||||||
|
create_volume_name(), m_volume);
|
||||||
|
|
||||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||||
replace_job(worker, std::make_unique<EmbossJob>(std::move(data)));
|
replace_job(worker, std::make_unique<EmbossJob>(std::move(data)));
|
||||||
@ -580,7 +582,8 @@ void GLGizmoEmboss::draw_window()
|
|||||||
bool loaded = load_font(font_index);
|
bool loaded = load_font(font_index);
|
||||||
}
|
}
|
||||||
#endif // ALLOW_DEBUG_MODE
|
#endif // ALLOW_DEBUG_MODE
|
||||||
if (m_font == nullptr) {
|
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());
|
ImGui::Text("%s",_u8L("Warning: No font is selected. Select correct one.").c_str());
|
||||||
}
|
}
|
||||||
draw_font_list();
|
draw_font_list();
|
||||||
@ -599,7 +602,7 @@ void GLGizmoEmboss::draw_window()
|
|||||||
if (ImGui::Button(_u8L("Close").c_str())) close();
|
if (ImGui::Button(_u8L("Close").c_str())) close();
|
||||||
|
|
||||||
// Option to create text volume when reselecting volumes
|
// Option to create text volume when reselecting volumes
|
||||||
m_imgui->disabled_begin(m_font == nullptr);
|
m_imgui->disabled_begin(!exist_font_file);
|
||||||
if (m_volume == nullptr) {
|
if (m_volume == nullptr) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button(_u8L("Generate preview").c_str())) {
|
if (ImGui::Button(_u8L("Generate preview").c_str())) {
|
||||||
@ -620,8 +623,10 @@ void GLGizmoEmboss::draw_font_list()
|
|||||||
const float &max_width = m_gui_cfg->max_font_name_width;
|
const float &max_width = m_gui_cfg->max_font_name_width;
|
||||||
std::optional<size_t> rename_index, delete_index, duplicate_index;
|
std::optional<size_t> rename_index, delete_index, duplicate_index;
|
||||||
|
|
||||||
const std::string& current_name = m_font_list[m_font_selected].name;
|
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);
|
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);
|
ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
|
||||||
if (ImGui::BeginCombo("##font_selector", trunc_name.c_str())) {
|
if (ImGui::BeginCombo("##font_selector", trunc_name.c_str())) {
|
||||||
// first line
|
// first line
|
||||||
@ -645,25 +650,30 @@ void GLGizmoEmboss::draw_font_list()
|
|||||||
#endif // ALLOW_DEBUG_MODE
|
#endif // ALLOW_DEBUG_MODE
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
for (FontItem &f : m_font_list) {
|
for (const auto &item : fonts) {
|
||||||
ImGui::PushID(f.name.c_str());
|
size_t index = &item - &fonts.front();
|
||||||
std::string name = ImGuiWrapper::trunc(f.name, max_width);
|
const FontItem &fi = item.font_item;
|
||||||
size_t index = &f - &m_font_list.front();
|
ImGui::PushID(fi.name.c_str());
|
||||||
bool is_selected = index == m_font_selected;
|
std::string name = ImGuiWrapper::trunc(fi.name, max_width);
|
||||||
|
|
||||||
|
bool is_selected = (&fi == &actual_font_item);
|
||||||
ImGuiSelectableFlags_ flags = ImGuiSelectableFlags_AllowItemOverlap; // allow click buttons
|
ImGuiSelectableFlags_ flags = ImGuiSelectableFlags_AllowItemOverlap; // allow click buttons
|
||||||
if (ImGui::Selectable(name.c_str(), is_selected, flags) ) {
|
if (ImGui::Selectable(name.c_str(), is_selected, flags) ) {
|
||||||
if (load_font(index)) process();
|
if (m_font_manager.load_font(index)) process();
|
||||||
} else if (ImGui::IsItemHovered())
|
} else if (ImGui::IsItemHovered())
|
||||||
ImGui::SetTooltip("%s", f.name.c_str());
|
ImGui::SetTooltip("%s", fi.name.c_str());
|
||||||
|
|
||||||
// reorder items
|
// reorder items
|
||||||
if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) {
|
if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) {
|
||||||
int other_index = index + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
|
int other_index = index + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
|
||||||
if (other_index >= 0 && other_index < m_font_list.size()) {
|
if (other_index >= 0 && other_index < fonts.size()) {
|
||||||
std::swap(m_font_list[index], m_font_list[other_index]);
|
std::swap(m_font_manager.get_font(index),
|
||||||
|
m_font_manager.get_font(other_index));
|
||||||
// fix selected index
|
// fix selected index
|
||||||
if (m_font_selected == other_index) m_font_selected = index;
|
if (is_selected)
|
||||||
else if (m_font_selected == index) m_font_selected = other_index;
|
m_font_manager.select(other_index);
|
||||||
|
else if (&fonts[other_index].font_item == &actual_font_item)
|
||||||
|
m_font_manager.select(index);
|
||||||
ImGui::ResetMouseDragDelta();
|
ImGui::ResetMouseDragDelta();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,21 +692,13 @@ void GLGizmoEmboss::draw_font_list()
|
|||||||
|
|
||||||
// duplicate font item
|
// duplicate font item
|
||||||
if (duplicate_index.has_value()) {
|
if (duplicate_index.has_value()) {
|
||||||
size_t index = *duplicate_index;
|
m_font_manager.duplicate(*duplicate_index);
|
||||||
FontItem fi = m_font_list[index]; // copy
|
|
||||||
make_unique_name(fi.name, m_font_list);
|
|
||||||
m_font_list.insert(m_font_list.begin() + index, fi);
|
|
||||||
// fix selected index
|
|
||||||
if (index < m_font_selected) ++m_font_selected;
|
|
||||||
store_font_list_to_app_config();
|
store_font_list_to_app_config();
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete font item
|
// delete font item
|
||||||
if (delete_index.has_value()) {
|
if (delete_index.has_value()) {
|
||||||
size_t index = *delete_index;
|
m_font_manager.erase(*delete_index);
|
||||||
m_font_list.erase(m_font_list.begin() + index);
|
|
||||||
// fix selected index
|
|
||||||
if (index < m_font_selected) --m_font_selected;
|
|
||||||
store_font_list_to_app_config();
|
store_font_list_to_app_config();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,7 +708,7 @@ void GLGizmoEmboss::draw_font_list()
|
|||||||
static std::string new_name;
|
static std::string new_name;
|
||||||
if (rename_index.has_value() && !ImGui::IsPopupOpen(rename_popup_id)) {
|
if (rename_index.has_value() && !ImGui::IsPopupOpen(rename_popup_id)) {
|
||||||
ImGui::OpenPopup(rename_popup_id);
|
ImGui::OpenPopup(rename_popup_id);
|
||||||
rename_item = &m_font_list[*rename_index];
|
rename_item = &m_font_manager.get_font(*rename_index).font_item;
|
||||||
new_name = rename_item->name; // initialize with original copy
|
new_name = rename_item->name; // initialize with original copy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,7 +720,8 @@ void GLGizmoEmboss::draw_font_list()
|
|||||||
ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
|
ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
|
||||||
|
|
||||||
bool is_unique = true;
|
bool is_unique = true;
|
||||||
for (const FontItem &fi : m_font_list) {
|
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 == rename_item) continue; // could be same as original name
|
||||||
if (fi.name == new_name) is_unique = false;
|
if (fi.name == new_name) is_unique = false;
|
||||||
}
|
}
|
||||||
@ -740,8 +743,7 @@ void GLGizmoEmboss::draw_text_input()
|
|||||||
static const ImGuiInputTextFlags flags =
|
static const ImGuiInputTextFlags flags =
|
||||||
ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_AutoSelectAll;
|
ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_AutoSelectAll;
|
||||||
|
|
||||||
ImVector<ImFont *> &fonts = m_imgui_font_atlas.Fonts;
|
ImFont *imgui_font = m_font_manager.get_imgui_font();
|
||||||
ImFont * imgui_font = fonts.empty() ? nullptr : fonts.front();
|
|
||||||
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);
|
if (exist_font) ImGui::PushFont(imgui_font);
|
||||||
|
|
||||||
@ -761,17 +763,18 @@ void GLGizmoEmboss::draw_text_input()
|
|||||||
if (exist_font) ImGui::PopFont();
|
if (exist_font) ImGui::PopFont();
|
||||||
|
|
||||||
// imgui_font has to be unused
|
// imgui_font has to be unused
|
||||||
if (exist_change) check_imgui_font_range();
|
if (exist_change) m_font_manager.check_imgui_font_range(m_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::draw_advanced()
|
void GLGizmoEmboss::draw_advanced()
|
||||||
{
|
{
|
||||||
if (m_font != nullptr) {
|
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
||||||
ImGui::Text("%s", _u8L("Advanced font options could be change only for corect font.\nStart with select correct font."));
|
if (font_file == nullptr) {
|
||||||
|
ImGui::Text("%s", _u8L("Advanced font options could be change only for corect font.\nStart with select correct font.").c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FontItem &fi = m_font_list[m_font_selected];
|
FontItem &fi = m_font_manager.get_font_item();
|
||||||
FontProp &font_prop = fi.prop;
|
FontProp &font_prop = fi.prop;
|
||||||
bool exist_change = false;
|
bool exist_change = false;
|
||||||
|
|
||||||
@ -787,8 +790,8 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
fi.path = WxFontUtils::store_wxFont(*wx_font);
|
fi.path = WxFontUtils::store_wxFont(*wx_font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
load_imgui_font();
|
m_font_manager.load_imgui_font();
|
||||||
m_font->cache.clear();
|
font_file->cache.clear();
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -798,7 +801,7 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
|
|
||||||
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
|
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)) {
|
if (ImGuiWrapper::input_optional_int(_u8L("CharGap[in font points]").c_str(), font_prop.char_gap)) {
|
||||||
m_font->cache.clear();
|
font_file->cache.clear();
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,27 +811,27 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
|
|
||||||
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
|
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"))){
|
||||||
m_font->cache.clear();
|
font_file->cache.clear();
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
|
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("Skew ratio").c_str(), font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("italic strength"))){
|
||||||
m_font->cache.clear();
|
font_file->cache.clear();
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// when more collection add selector
|
// when more collection add selector
|
||||||
if (m_font != nullptr && m_font->count > 1) {
|
if (font_file != nullptr && font_file->count > 1) {
|
||||||
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
|
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
|
||||||
if (ImGui::BeginCombo(_u8L("Font collection").c_str(),
|
if (ImGui::BeginCombo(_u8L("Font collection").c_str(),
|
||||||
std::to_string(m_font->index).c_str())) {
|
std::to_string(font_file->index).c_str())) {
|
||||||
for (unsigned int i = 0; i < m_font->count; ++i) {
|
for (unsigned int i = 0; i < font_file->count; ++i) {
|
||||||
ImGui::PushID(1 << (10 + i));
|
ImGui::PushID(1 << (10 + i));
|
||||||
if (ImGui::Selectable(std::to_string(i).c_str(),
|
if (ImGui::Selectable(std::to_string(i).c_str(),
|
||||||
i == m_font->index)) {
|
i == font_file->index)) {
|
||||||
m_font->index = i;
|
font_file->index = i;
|
||||||
m_font->cache.clear();
|
font_file->cache.clear();
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
@ -844,7 +847,6 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
|
|
||||||
|
|
||||||
#ifdef ALLOW_DEBUG_MODE
|
#ifdef ALLOW_DEBUG_MODE
|
||||||
std::string descriptor = m_font_list[m_font_selected].path;
|
|
||||||
ImGui::Text("family = %s", (font_prop.family.has_value() ?
|
ImGui::Text("family = %s", (font_prop.family.has_value() ?
|
||||||
font_prop.family->c_str() :
|
font_prop.family->c_str() :
|
||||||
" --- "));
|
" --- "));
|
||||||
@ -857,6 +859,8 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
ImGui::Text("weight = %s", (font_prop.weight.has_value() ?
|
ImGui::Text("weight = %s", (font_prop.weight.has_value() ?
|
||||||
font_prop.weight->c_str() :
|
font_prop.weight->c_str() :
|
||||||
" --- "));
|
" --- "));
|
||||||
|
|
||||||
|
std::string descriptor = fi.path;
|
||||||
ImGui::Text("descriptor = %s", descriptor.c_str());
|
ImGui::Text("descriptor = %s", descriptor.c_str());
|
||||||
ImGui::Image(m_imgui_font_atlas.TexID,
|
ImGui::Image(m_imgui_font_atlas.TexID,
|
||||||
ImVec2(m_imgui_font_atlas.TexWidth,
|
ImVec2(m_imgui_font_atlas.TexWidth,
|
||||||
@ -864,171 +868,13 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
#endif // ALLOW_DEBUG_MODE
|
#endif // ALLOW_DEBUG_MODE
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
return is_loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLGizmoEmboss::load_font()
|
|
||||||
{
|
|
||||||
if (m_font_selected >= m_font_list.size()) return false;
|
|
||||||
FontItem &fi = m_font_list[m_font_selected];
|
|
||||||
if (fi.type == FontItem::Type::file_path) {
|
|
||||||
// fill font name after load from .3mf
|
|
||||||
if (fi.name.empty())
|
|
||||||
fi.name = Slic3r::GUI::GLGizmoEmboss::get_file_name(fi.path);
|
|
||||||
std::unique_ptr<Emboss::Font> font_ptr = Emboss::load_font(fi.path.c_str());
|
|
||||||
if (font_ptr == nullptr) return false;
|
|
||||||
m_font = std::move(font_ptr);
|
|
||||||
load_imgui_font();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (fi.type != WxFontUtils::get_actual_type()) return false;
|
|
||||||
std::optional<wxFont> wx_font = WxFontUtils::load_wxFont(fi.path);
|
|
||||||
if (!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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
load_imgui_font();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoEmboss::check_imgui_font_range()
|
|
||||||
{
|
|
||||||
const char *text = m_text.c_str();
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool exist_unknown = false;
|
|
||||||
while (*text) {
|
|
||||||
unsigned int c = 0;
|
|
||||||
int c_len = ImTextCharFromUtf8(&c, text, NULL);
|
|
||||||
text += c_len;
|
|
||||||
if (c_len == 0) break;
|
|
||||||
if (!is_in_ranges(c)) {
|
|
||||||
exist_unknown = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (exist_unknown) load_imgui_font();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoEmboss::load_imgui_font()
|
|
||||||
{
|
|
||||||
if (m_font == nullptr) return;
|
|
||||||
|
|
||||||
ImFontGlyphRangesBuilder builder;
|
|
||||||
builder.AddRanges(m_imgui->get_glyph_ranges());
|
|
||||||
builder.AddText(m_text.c_str());
|
|
||||||
|
|
||||||
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(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)
|
|
||||||
font_size = m_gui_cfg->max_imgui_font_size;
|
|
||||||
|
|
||||||
ImFontConfig font_config;
|
|
||||||
font_config.FontDataOwnedByAtlas = false;
|
|
||||||
m_imgui_font_atlas.Flags |= ImFontAtlasFlags_NoMouseCursors |
|
|
||||||
ImFontAtlasFlags_NoPowerOfTwoHeight;
|
|
||||||
m_imgui_font_atlas.Clear();
|
|
||||||
m_imgui_font_atlas.AddFontFromMemoryTTF((void *) m_font->buffer.data(),
|
|
||||||
m_font->buffer.size(), font_size,
|
|
||||||
&font_config,
|
|
||||||
m_imgui_font_ranges.Data);
|
|
||||||
|
|
||||||
unsigned char *pixels;
|
|
||||||
int width, height;
|
|
||||||
m_imgui_font_atlas.GetTexDataAsAlpha8(&pixels, &width, &height);
|
|
||||||
|
|
||||||
// Upload texture to graphics system
|
|
||||||
GLint last_texture;
|
|
||||||
glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
|
|
||||||
ScopeGuard sg([last_texture]() {
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture));
|
|
||||||
});
|
|
||||||
|
|
||||||
GLuint font_texture;
|
|
||||||
glsafe(::glGenTextures(1, &font_texture));
|
|
||||||
glsafe(::glBindTexture(GL_TEXTURE_2D, font_texture));
|
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
|
||||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
|
||||||
glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
|
||||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
|
|
||||||
GL_ALPHA, GL_UNSIGNED_BYTE, pixels));
|
|
||||||
|
|
||||||
// Store our identifier
|
|
||||||
m_imgui_font_atlas.TexID = (ImTextureID) (intptr_t) font_texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoEmboss::make_unique_name(std::string &name, const FontList &list)
|
|
||||||
{
|
|
||||||
auto is_unique = [&list](const std::string &name)->bool {
|
|
||||||
for (const FontItem &fi : list)
|
|
||||||
if (fi.name == name) return false;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (name.empty()) name = "font";
|
|
||||||
if (is_unique(name)) return;
|
|
||||||
|
|
||||||
auto pos = name.find(" (");
|
|
||||||
if (pos != std::string::npos &&
|
|
||||||
name.find(")", pos) != std::string::npos) {
|
|
||||||
// short name by ord number
|
|
||||||
name = name.substr(0, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
int order = 1; // start with value 2 to represents same font name
|
|
||||||
std::string new_name;
|
|
||||||
do {
|
|
||||||
new_name = name + " (" + std::to_string(++order) + ")";
|
|
||||||
} while (!is_unique(new_name));
|
|
||||||
name = new_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GLGizmoEmboss::choose_font_by_wxdialog()
|
bool GLGizmoEmboss::choose_font_by_wxdialog()
|
||||||
{
|
{
|
||||||
wxFontData data;
|
wxFontData data;
|
||||||
data.EnableEffects(false);
|
data.EnableEffects(false);
|
||||||
data.RestrictSelection(wxFONTRESTRICT_SCALABLE);
|
data.RestrictSelection(wxFONTRESTRICT_SCALABLE);
|
||||||
// set previous selected font
|
// set previous selected font
|
||||||
FontItem &selected_font_item = m_font_list[m_font_selected];
|
FontItem &selected_font_item = m_font_manager.get_font_item();
|
||||||
if (selected_font_item.type == WxFontUtils::get_actual_type()) {
|
if (selected_font_item.type == WxFontUtils::get_actual_type()) {
|
||||||
std::optional<wxFont> selected_font = WxFontUtils::load_wxFont(
|
std::optional<wxFont> selected_font = WxFontUtils::load_wxFont(
|
||||||
selected_font_item.path);
|
selected_font_item.path);
|
||||||
@ -1040,32 +886,20 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
|
|||||||
|
|
||||||
data = font_dialog.GetFontData();
|
data = font_dialog.GetFontData();
|
||||||
wxFont font = data.GetChosenFont();
|
wxFont font = data.GetChosenFont();
|
||||||
size_t font_index = m_font_list.size();
|
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(font);
|
||||||
|
m_font_manager.add_font(font_item);
|
||||||
// fix dynamic creation of italic font
|
|
||||||
wxFontStyle wx_style = font.GetStyle();
|
|
||||||
if ((wx_style == wxFONTSTYLE_ITALIC || wx_style == wxFONTSTYLE_SLANT) &&
|
|
||||||
!Emboss::is_italic(*m_font)) {
|
|
||||||
font_item.prop.skew = 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
make_unique_name(font_item.name, m_font_list);
|
|
||||||
m_font_list.emplace_back(font_item);
|
|
||||||
|
|
||||||
// Check that deserialization NOT influence font
|
// Check that deserialization NOT influence font
|
||||||
// false - use direct selected wxFont in dialog
|
// false - use direct selected wxFont in dialog
|
||||||
// true - use font item (serialize and deserialize wxFont)
|
// true - use font item (serialize and deserialize wxFont)
|
||||||
bool use_deserialized_font = false;
|
bool use_deserialized_font = false;
|
||||||
if (!use_deserialized_font) m_font_selected = font_index;
|
|
||||||
// Try load and use new added font
|
// Try load and use new added font
|
||||||
if ((!use_deserialized_font && !load_font(font)) ||
|
if ((use_deserialized_font && !m_font_manager.load_font(font_index)) ||
|
||||||
(use_deserialized_font && !load_font(font_index)) ||
|
(!use_deserialized_font && !m_font_manager.load_font(font_index, font)) ||
|
||||||
!process()) {
|
!process()) {
|
||||||
// reverse index for font_selected
|
m_font_manager.erase(font_index);
|
||||||
std::swap(font_index, m_font_selected); // when not process
|
|
||||||
// remove form font list
|
|
||||||
m_font_list.pop_back();
|
|
||||||
wxString message = GUI::format_wxstr(
|
wxString message = GUI::format_wxstr(
|
||||||
_L("Font '%1%' can't be used. Please select another."),
|
_L("Font '%1%' can't be used. Please select another."),
|
||||||
font_item.name);
|
font_item.name);
|
||||||
@ -1074,6 +908,14 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
|
|||||||
not_loaded_font_message.ShowModal();
|
not_loaded_font_message.ShowModal();
|
||||||
return choose_font_by_wxdialog();
|
return choose_font_by_wxdialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fix dynamic creation of italic font
|
||||||
|
wxFontStyle wx_style = font.GetStyle();
|
||||||
|
if ((wx_style == wxFONTSTYLE_ITALIC || wx_style == wxFONTSTYLE_SLANT) &&
|
||||||
|
!Emboss::is_italic(*m_font_manager.get_font_file())) {
|
||||||
|
m_font_manager.get_font_item().prop.skew = 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1091,14 +933,15 @@ bool GLGizmoEmboss::choose_true_type_file()
|
|||||||
for (auto &input_file : input_files) {
|
for (auto &input_file : input_files) {
|
||||||
std::string path = std::string(input_file.c_str());
|
std::string path = std::string(input_file.c_str());
|
||||||
std::string name = get_file_name(path);
|
std::string name = get_file_name(path);
|
||||||
make_unique_name(name, m_font_list);
|
//make_unique_name(name, m_font_list);
|
||||||
m_font_list.emplace_back(name, path, FontItem::Type::file_path, FontProp());
|
FontItem fi(name, path, FontItem::Type::file_path, FontProp());
|
||||||
|
m_font_manager.add_font(fi);
|
||||||
|
|
||||||
// set first valid added font as active
|
// set first valid added font as active
|
||||||
if (!font_loaded) {
|
if (!font_loaded) {
|
||||||
if (!load_font(m_font_list.size() - 1))
|
if (!m_font_manager.load_font(m_font_manager.get_fonts().size() - 1)) {
|
||||||
m_font_list.pop_back();
|
//m_font_list.pop_back();
|
||||||
else
|
} else
|
||||||
font_loaded = true;
|
font_loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1127,7 +970,7 @@ bool GLGizmoEmboss::choose_svg_file()
|
|||||||
|
|
||||||
BoundingBox bb;
|
BoundingBox bb;
|
||||||
for (const auto &p : polys) bb.merge(p.contour.points);
|
for (const auto &p : polys) bb.merge(p.contour.points);
|
||||||
const FontProp &fp = m_font_list[m_font_selected].prop;
|
const FontProp &fp = m_font_manager.get_font_item().prop;
|
||||||
float scale = fp.size_in_mm / std::max(bb.max.x(), bb.max.y());
|
float scale = fp.size_in_mm / std::max(bb.max.x(), bb.max.y());
|
||||||
auto project = std::make_unique<Emboss::ProjectScale>(
|
auto project = std::make_unique<Emboss::ProjectScale>(
|
||||||
std::make_unique<Emboss::ProjectZ>(fp.emboss / scale), scale);
|
std::make_unique<Emboss::ProjectZ>(fp.emboss / scale), scale);
|
||||||
@ -1142,7 +985,7 @@ bool GLGizmoEmboss::choose_svg_file()
|
|||||||
|
|
||||||
TextConfiguration GLGizmoEmboss::create_configuration()
|
TextConfiguration GLGizmoEmboss::create_configuration()
|
||||||
{
|
{
|
||||||
return TextConfiguration(m_font_list[m_font_selected], m_text);
|
return TextConfiguration(m_font_manager.get_font_item(), m_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLGizmoEmboss::load_configuration(ModelVolume *volume)
|
bool GLGizmoEmboss::load_configuration(ModelVolume *volume)
|
||||||
@ -1154,43 +997,41 @@ bool GLGizmoEmboss::load_configuration(ModelVolume *volume)
|
|||||||
FontItem & c_font_item = configuration.font_item;
|
FontItem & c_font_item = configuration.font_item;
|
||||||
|
|
||||||
// try to find font in local font list
|
// try to find font in local font list
|
||||||
auto is_config = [&c_font_item](const FontItem &font_item) -> bool {
|
auto is_config = [&c_font_item](const FontManager::Item &font_item) -> bool {
|
||||||
return font_item.path == c_font_item.path;
|
const FontItem &fi = font_item.font_item;
|
||||||
|
return fi.path == c_font_item.path && fi.prop == c_font_item.prop;
|
||||||
};
|
};
|
||||||
auto it = std::find_if(m_font_list.begin(), m_font_list.end(), is_config);
|
const auto& fonts = m_font_manager.get_fonts();
|
||||||
|
auto it = std::find_if(fonts.begin(), fonts.end(), is_config);
|
||||||
size_t prev_font_selected = m_font_selected;
|
bool found_font = it != fonts.end();
|
||||||
|
size_t font_index;
|
||||||
if (it == m_font_list.end()) {
|
if (!found_font) {
|
||||||
// font is not in list
|
// font is not in list
|
||||||
// add font to list
|
// add font to list
|
||||||
m_font_selected = m_font_list.size();
|
font_index = fonts.size();
|
||||||
make_unique_name(c_font_item.name, m_font_list);
|
m_font_manager.add_font(c_font_item);
|
||||||
m_font_list.emplace_back(c_font_item);
|
|
||||||
} else {
|
} else {
|
||||||
// font is found in list
|
// font is found in list
|
||||||
m_font_selected = it - m_font_list.begin();
|
font_index = it - fonts.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_text = configuration.text;
|
m_text = configuration.text;
|
||||||
m_volume = volume;
|
m_volume = volume;
|
||||||
|
|
||||||
if (!load_font()) {
|
if (!m_font_manager.load_font(font_index)) {
|
||||||
// create similar font
|
// create similar font
|
||||||
auto wx_font = WxFontUtils::create_wxFont(c_font_item, configuration.font_item.prop);
|
auto wx_font = WxFontUtils::create_wxFont(c_font_item, configuration.font_item.prop);
|
||||||
if (wx_font.has_value()) {
|
if (wx_font.has_value()) {
|
||||||
// fix not loadable font item
|
// fix not loadable font item
|
||||||
FontItem &fi = m_font_list[m_font_selected];
|
FontItem &fi = m_font_manager.get_font_item();
|
||||||
FontItem fi_new = WxFontUtils::get_font_item(*wx_font);
|
FontItem fi_new = WxFontUtils::get_font_item(*wx_font);
|
||||||
fi_new.name = fi.name; // use previous name
|
fi_new.name = fi.name; // use previous name
|
||||||
fi = fi_new; // rewrite font item
|
fi = fi_new; // rewrite font item
|
||||||
fi.prop = configuration.font_item.prop;
|
fi.prop = configuration.font_item.prop;
|
||||||
if (!load_font(*wx_font)) return false;
|
if (!m_font_manager.load_font(font_index, *wx_font)) return false;
|
||||||
} else {
|
} else {
|
||||||
// can't create similar font use previous
|
// can't create similar font use previous
|
||||||
m_font_list.erase(m_font_list.begin() + m_font_selected);
|
m_font_manager.erase(font_index);
|
||||||
m_font_selected = prev_font_selected;
|
|
||||||
if (!load_font()) return false;
|
|
||||||
}
|
}
|
||||||
create_notification_not_valid_font(configuration);
|
create_notification_not_valid_font(configuration);
|
||||||
}
|
}
|
||||||
@ -1208,7 +1049,7 @@ void GLGizmoEmboss::create_notification_not_valid_font(
|
|||||||
auto level =
|
auto level =
|
||||||
NotificationManager::NotificationLevel::WarningNotificationLevel;
|
NotificationManager::NotificationLevel::WarningNotificationLevel;
|
||||||
|
|
||||||
const auto &fi = m_font_list[m_font_selected];
|
const auto &fi = m_font_manager.get_font_item();
|
||||||
const auto &origin_family = tc.font_item.prop.face_name;
|
const auto &origin_family = tc.font_item.prop.face_name;
|
||||||
const auto &actual_family = fi.prop.face_name;
|
const auto &actual_family = fi.prop.face_name;
|
||||||
|
|
||||||
@ -1341,54 +1182,28 @@ bool GLGizmoEmboss::draw_button(IconType icon, bool disable)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FontListSerializable
|
FontList GLGizmoEmboss::load_font_list_from_app_config(const AppConfig *cfg)
|
||||||
{
|
{
|
||||||
static const std::string APP_CONFIG_FONT_NAME;
|
FontList result;
|
||||||
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;
|
|
||||||
public:
|
|
||||||
FontListSerializable() = delete;
|
|
||||||
|
|
||||||
static FontList create_default_font_list();
|
|
||||||
static std::string create_section_name(unsigned index);
|
|
||||||
static std::optional<FontItem> load_font_item(const std::map<std::string, std::string> &app_cfg_section);
|
|
||||||
static void store_font_item(AppConfig &cfg, const FontItem &fi, unsigned index);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// TODO: move to app config like read from section
|
|
||||||
static bool read(const std::map<std::string, std::string>& section, const std::string& key, float& value);
|
|
||||||
static bool read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<int>& value);
|
|
||||||
static bool read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<float>& value);
|
|
||||||
};
|
|
||||||
|
|
||||||
void GLGizmoEmboss::load_font_list_from_app_config()
|
|
||||||
{
|
|
||||||
const AppConfig *cfg = wxGetApp().app_config;
|
|
||||||
unsigned index = 1;
|
unsigned index = 1;
|
||||||
std::string section_name = FontListSerializable::create_section_name(index++);
|
std::string section_name = FontListSerializable::create_section_name(index++);
|
||||||
while (cfg->has_section(section_name)) {
|
while (cfg->has_section(section_name)) {
|
||||||
std::optional<FontItem> fi = FontListSerializable::load_font_item(cfg->get_section(section_name));
|
std::optional<FontItem> fi = FontListSerializable::load_font_item(cfg->get_section(section_name));
|
||||||
if (fi.has_value()) {
|
if (fi.has_value()) result.emplace_back(*fi);
|
||||||
make_unique_name(fi->name, m_font_list);
|
|
||||||
m_font_list.emplace_back(*fi);
|
|
||||||
}
|
|
||||||
section_name = FontListSerializable::create_section_name(index++);
|
section_name = FontListSerializable::create_section_name(index++);
|
||||||
}
|
}
|
||||||
if (m_font_list.empty())
|
if (result.empty())
|
||||||
m_font_list = FontListSerializable::create_default_font_list();
|
return FontListSerializable::create_default_font_list();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::store_font_list_to_app_config() const
|
void GLGizmoEmboss::store_font_list_to_app_config() const
|
||||||
{
|
{
|
||||||
AppConfig *cfg = wxGetApp().app_config;
|
AppConfig *cfg = wxGetApp().app_config;
|
||||||
unsigned index = 1;
|
unsigned index = 1;
|
||||||
for (const FontItem &fi : m_font_list) {
|
for (const auto& item : m_font_manager.get_fonts()) {
|
||||||
// skip file paths + fonts from other OS
|
const FontItem &fi = item.font_item;
|
||||||
|
// skip file paths + fonts from other OS(loaded from .3mf)
|
||||||
if (fi.type != WxFontUtils::get_actual_type()) continue;
|
if (fi.type != WxFontUtils::get_actual_type()) continue;
|
||||||
FontListSerializable::store_font_item(*cfg, fi, index++);
|
FontListSerializable::store_font_item(*cfg, fi, index++);
|
||||||
}
|
}
|
||||||
@ -1404,119 +1219,12 @@ void GLGizmoEmboss::store_font_list_to_app_config() const
|
|||||||
void GLGizmoEmboss::store_font_item_to_app_config() const
|
void GLGizmoEmboss::store_font_item_to_app_config() const
|
||||||
{
|
{
|
||||||
AppConfig *cfg = wxGetApp().app_config;
|
AppConfig *cfg = wxGetApp().app_config;
|
||||||
unsigned index = m_font_selected + 1;
|
// index of section start from 1
|
||||||
FontListSerializable::store_font_item(
|
const FontItem &fi = m_font_manager.get_font_item();
|
||||||
*cfg, m_font_list[m_font_selected], index);
|
size_t index = &m_font_manager.get_font() -
|
||||||
}
|
&m_font_manager.get_fonts().front();
|
||||||
|
// TODO: fix index when, not serialized font is in list
|
||||||
const std::string FontListSerializable::APP_CONFIG_FONT_NAME = "name";
|
FontListSerializable::store_font_item(*cfg, fi, index);
|
||||||
const std::string FontListSerializable::APP_CONFIG_FONT_DESCRIPTOR = "descriptor";
|
|
||||||
const std::string FontListSerializable::APP_CONFIG_FONT_LINE_HEIGHT = "line_height";
|
|
||||||
const std::string FontListSerializable::APP_CONFIG_FONT_DEPTH = "depth";
|
|
||||||
const std::string FontListSerializable::APP_CONFIG_FONT_BOLDNESS = "boldness";
|
|
||||||
const std::string FontListSerializable::APP_CONFIG_FONT_SKEW = "skew";
|
|
||||||
const std::string FontListSerializable::APP_CONFIG_FONT_CHAR_GAP = "char_gap";
|
|
||||||
const std::string FontListSerializable::APP_CONFIG_FONT_LINE_GAP = "line_gap";
|
|
||||||
|
|
||||||
FontList FontListSerializable::create_default_font_list()
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
WxFontUtils::get_font_item(wxFont(5, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL))
|
|
||||||
, WxFontUtils::get_font_item(wxFont(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD))
|
|
||||||
, WxFontUtils::get_os_font()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string FontListSerializable::create_section_name(unsigned index)
|
|
||||||
{
|
|
||||||
return AppConfig::SECTION_FONT + ':' + std::to_string(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "fast_float/fast_float.h"
|
|
||||||
bool FontListSerializable::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FontListSerializable::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FontListSerializable::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> FontListSerializable::load_font_item(
|
|
||||||
const std::map<std::string, std::string> &app_cfg_section)
|
|
||||||
{
|
|
||||||
auto path_it = app_cfg_section.find(APP_CONFIG_FONT_DESCRIPTOR);
|
|
||||||
if (path_it == app_cfg_section.end()) return {};
|
|
||||||
const std::string &path = path_it->second;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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 FontListSerializable::store_font_item(AppConfig & cfg,
|
|
||||||
const FontItem &fi,
|
|
||||||
unsigned index)
|
|
||||||
{
|
|
||||||
std::string section_name = create_section_name(index);
|
|
||||||
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)
|
std::string GLGizmoEmboss::get_file_name(const std::string &file_path)
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "GLGizmoRotate.hpp"
|
#include "GLGizmoRotate.hpp"
|
||||||
#include "slic3r/GUI/GLTexture.hpp"
|
#include "slic3r/GUI/GLTexture.hpp"
|
||||||
#include "slic3r/Utils/RaycastManager.hpp"
|
#include "slic3r/Utils/RaycastManager.hpp"
|
||||||
|
#include "slic3r/Utils/FontManager.hpp"
|
||||||
|
|
||||||
#include "admesh/stl.h" // indexed_triangle_set
|
#include "admesh/stl.h" // indexed_triangle_set
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -74,7 +75,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void initialize();
|
void initialize();
|
||||||
void set_default_configuration();
|
void set_default_text();
|
||||||
TriangleMesh create_default_mesh();
|
TriangleMesh create_default_mesh();
|
||||||
TriangleMesh create_mesh();
|
TriangleMesh create_mesh();
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ private:
|
|||||||
/// <param name="font_prop">Property of font</param>
|
/// <param name="font_prop">Property of font</param>
|
||||||
/// <returns>Triangle mesh model</returns>
|
/// <returns>Triangle mesh model</returns>
|
||||||
static TriangleMesh create_mesh(const char * text,
|
static TriangleMesh create_mesh(const char * text,
|
||||||
Emboss::Font & font,
|
Emboss::FontFile & font,
|
||||||
const FontProp &font_prop);
|
const FontProp &font_prop);
|
||||||
|
|
||||||
void check_selection();
|
void check_selection();
|
||||||
@ -106,15 +107,6 @@ private:
|
|||||||
bool on_mouse_for_rotation(const wxMouseEvent &mouse_event);
|
bool on_mouse_for_rotation(const wxMouseEvent &mouse_event);
|
||||||
bool on_mouse_for_translate(const wxMouseEvent &mouse_event);
|
bool on_mouse_for_translate(const wxMouseEvent &mouse_event);
|
||||||
|
|
||||||
bool load_font();
|
|
||||||
// try to set font_index
|
|
||||||
bool load_font(size_t font_index);
|
|
||||||
bool load_font(const wxFont &font);
|
|
||||||
void load_imgui_font();
|
|
||||||
void check_imgui_font_range();
|
|
||||||
|
|
||||||
// TODO: move to fontList utils
|
|
||||||
static void make_unique_name(std::string &name, const FontList &list);
|
|
||||||
bool choose_font_by_wxdialog();
|
bool choose_font_by_wxdialog();
|
||||||
bool choose_true_type_file();
|
bool choose_true_type_file();
|
||||||
bool choose_svg_file();
|
bool choose_svg_file();
|
||||||
@ -137,11 +129,6 @@ private:
|
|||||||
{
|
{
|
||||||
size_t max_count_char_in_volume_name = 20;
|
size_t max_count_char_in_volume_name = 20;
|
||||||
int count_line_of_text = 6;
|
int count_line_of_text = 6;
|
||||||
// limits for font size inside gizmo
|
|
||||||
// When out of limits no change in size will appear in text input
|
|
||||||
int min_imgui_font_size = 18;
|
|
||||||
int max_imgui_font_size = 60;
|
|
||||||
|
|
||||||
bool draw_advanced = false;
|
bool draw_advanced = false;
|
||||||
|
|
||||||
// setted only when wanted to use - not all the time
|
// setted only when wanted to use - not all the time
|
||||||
@ -162,11 +149,11 @@ private:
|
|||||||
};
|
};
|
||||||
std::optional<GuiCfg> m_gui_cfg;
|
std::optional<GuiCfg> m_gui_cfg;
|
||||||
|
|
||||||
FontList m_font_list;
|
FontManager m_font_manager;
|
||||||
size_t m_font_selected;// index to m_font_list
|
|
||||||
|
//FontList m_font_list;
|
||||||
|
//size_t m_font_selected;// index to m_font_list
|
||||||
|
|
||||||
// to share data with job thread
|
|
||||||
std::shared_ptr<Emboss::Font> m_font;
|
|
||||||
std::string m_text;
|
std::string m_text;
|
||||||
|
|
||||||
// actual volume
|
// actual volume
|
||||||
@ -185,11 +172,6 @@ private:
|
|||||||
// initialize when GL is accessible
|
// initialize when GL is accessible
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
|
|
||||||
// imgui font
|
|
||||||
ImFontAtlas m_imgui_font_atlas;
|
|
||||||
// must live same as font in atlas
|
|
||||||
ImVector<ImWchar> m_imgui_font_ranges;
|
|
||||||
|
|
||||||
// drawing icons
|
// drawing icons
|
||||||
GLTexture m_icons_texture;
|
GLTexture m_icons_texture;
|
||||||
bool init_icons();
|
bool init_icons();
|
||||||
@ -199,7 +181,7 @@ private:
|
|||||||
bool draw_button(IconType icon, bool disable = false);
|
bool draw_button(IconType icon, bool disable = false);
|
||||||
|
|
||||||
// load / store appConfig
|
// load / store appConfig
|
||||||
void load_font_list_from_app_config();
|
static FontList load_font_list_from_app_config(const AppConfig *cfg);
|
||||||
void store_font_list_to_app_config() const;
|
void store_font_list_to_app_config() const;
|
||||||
void store_font_item_to_app_config() const;
|
void store_font_item_to_app_config() const;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Slic3r::GUI {
|
|||||||
struct EmbossData
|
struct EmbossData
|
||||||
{
|
{
|
||||||
// Pointer on Data of font (glyph shapes)
|
// Pointer on Data of font (glyph shapes)
|
||||||
std::shared_ptr<Emboss::Font> font;
|
std::shared_ptr<Emboss::FontFile> font;
|
||||||
// font item is not used for create object
|
// font item is not used for create object
|
||||||
TextConfiguration text_configuration;
|
TextConfiguration text_configuration;
|
||||||
// new volume name created from text
|
// new volume name created from text
|
||||||
@ -28,7 +28,7 @@ struct EmbossData
|
|||||||
// Change of volume change id, last change could disapear
|
// Change of volume change id, last change could disapear
|
||||||
//ObjectID volume_id;
|
//ObjectID volume_id;
|
||||||
|
|
||||||
EmbossData(std::shared_ptr<Emboss::Font> font,
|
EmbossData(std::shared_ptr<Emboss::FontFile> font,
|
||||||
TextConfiguration text_configuration,
|
TextConfiguration text_configuration,
|
||||||
std::string volume_name,
|
std::string volume_name,
|
||||||
ModelVolume * volume)
|
ModelVolume * volume)
|
||||||
|
117
src/slic3r/Utils/FontListSerializable.cpp
Normal file
117
src/slic3r/Utils/FontListSerializable.cpp
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
#include "FontListSerializable.hpp"
|
||||||
|
|
||||||
|
#include <libslic3r/AppConfig.hpp>
|
||||||
|
#include "WxFontUtils.hpp"
|
||||||
|
|
||||||
|
using namespace Slic3r;
|
||||||
|
using namespace Slic3r::GUI;
|
||||||
|
|
||||||
|
const std::string FontListSerializable::APP_CONFIG_FONT_NAME = "name";
|
||||||
|
const std::string FontListSerializable::APP_CONFIG_FONT_DESCRIPTOR = "descriptor";
|
||||||
|
const std::string FontListSerializable::APP_CONFIG_FONT_LINE_HEIGHT = "line_height";
|
||||||
|
const std::string FontListSerializable::APP_CONFIG_FONT_DEPTH = "depth";
|
||||||
|
const std::string FontListSerializable::APP_CONFIG_FONT_BOLDNESS = "boldness";
|
||||||
|
const std::string FontListSerializable::APP_CONFIG_FONT_SKEW = "skew";
|
||||||
|
const std::string FontListSerializable::APP_CONFIG_FONT_CHAR_GAP = "char_gap";
|
||||||
|
const std::string FontListSerializable::APP_CONFIG_FONT_LINE_GAP = "line_gap";
|
||||||
|
|
||||||
|
FontList FontListSerializable::create_default_font_list()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
WxFontUtils::get_font_item(wxFont(5, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL))
|
||||||
|
, WxFontUtils::get_font_item(wxFont(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD))
|
||||||
|
, WxFontUtils::get_os_font()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FontListSerializable::create_section_name(unsigned index)
|
||||||
|
{
|
||||||
|
return AppConfig::SECTION_FONT + ':' + std::to_string(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "fast_float/fast_float.h"
|
||||||
|
bool FontListSerializable::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontListSerializable::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontListSerializable::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> FontListSerializable::load_font_item(
|
||||||
|
const std::map<std::string, std::string> &app_cfg_section)
|
||||||
|
{
|
||||||
|
auto path_it = app_cfg_section.find(APP_CONFIG_FONT_DESCRIPTOR);
|
||||||
|
if (path_it == app_cfg_section.end()) return {};
|
||||||
|
const std::string &path = path_it->second;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 FontListSerializable::store_font_item(AppConfig & cfg,
|
||||||
|
const FontItem &fi,
|
||||||
|
unsigned index)
|
||||||
|
{
|
||||||
|
std::string section_name = create_section_name(index);
|
||||||
|
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));
|
||||||
|
}
|
45
src/slic3r/Utils/FontListSerializable.hpp
Normal file
45
src/slic3r/Utils/FontListSerializable.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef slic3r_FontListSerializable_hpp_
|
||||||
|
#define slic3r_FontListSerializable_hpp_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <libslic3r/TextConfiguration.hpp> // FontList+FontItem
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
class AppConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Slic3r::GUI {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For store/load font list to/from AppConfig
|
||||||
|
/// </summary>
|
||||||
|
class FontListSerializable
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
public:
|
||||||
|
FontListSerializable() = delete;
|
||||||
|
|
||||||
|
static FontList create_default_font_list();
|
||||||
|
static std::string create_section_name(unsigned index);
|
||||||
|
static std::optional<FontItem> load_font_item(const std::map<std::string, std::string> &app_cfg_section);
|
||||||
|
static void store_font_item(AppConfig &cfg, const FontItem &fi, unsigned index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TODO: move to app config like read from section
|
||||||
|
static bool read(const std::map<std::string, std::string>& section, const std::string& key, float& value);
|
||||||
|
static bool read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<int>& value);
|
||||||
|
static bool read(const std::map<std::string, std::string>& section, const std::string& key, std::optional<float>& value);
|
||||||
|
};
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // #define slic3r_FontListSerializable_hpp_
|
||||||
|
|
291
src/slic3r/Utils/FontManager.cpp
Normal file
291
src/slic3r/Utils/FontManager.cpp
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
#include "FontManager.hpp"
|
||||||
|
#include <wx/font.h>
|
||||||
|
#include <GL/glew.h> // Imgui texture
|
||||||
|
#include <imgui/imgui_internal.h> // ImTextCharFromUtf8
|
||||||
|
#include "WxFontUtils.hpp"
|
||||||
|
#include "libslic3r/Utils.hpp" // ScopeGuard
|
||||||
|
#include "slic3r/GUI/3DScene.hpp" // ::glsafe
|
||||||
|
|
||||||
|
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)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void FontManager::select(size_t index)
|
||||||
|
{
|
||||||
|
if (index < m_font_list.size())
|
||||||
|
m_font_selected = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontManager::duplicate(size_t index) {
|
||||||
|
if (index >= m_font_list.size()) return;
|
||||||
|
Item item = m_font_list[index]; // copy
|
||||||
|
make_unique_name(item.font_item.name);
|
||||||
|
|
||||||
|
m_font_list.insert(m_font_list.begin() + index, item);
|
||||||
|
// fix selected index
|
||||||
|
if (index < m_font_selected) ++m_font_selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontManager::erase(size_t index) {
|
||||||
|
if (index >= m_font_list.size()) return;
|
||||||
|
m_font_list.erase(m_font_list.begin() + index);
|
||||||
|
// fix selected index
|
||||||
|
if (index < m_font_selected) --m_font_selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontManager::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);
|
||||||
|
return is_loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontManager::load_font(size_t font_index, const wxFont &font)
|
||||||
|
{
|
||||||
|
if (font_index >= m_font_list.size()) return false;
|
||||||
|
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('\\');
|
||||||
|
size_t pos_point = file_path.find_last_of('.');
|
||||||
|
size_t offset = pos_last_delimiter + 1;
|
||||||
|
size_t count = pos_point - pos_last_delimiter - 1;
|
||||||
|
return file_path.substr(offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontManager::load_font()
|
||||||
|
{
|
||||||
|
// next condition may be safely removed
|
||||||
|
if (m_font_selected >= m_font_list.size()) return false;
|
||||||
|
|
||||||
|
Item &item = m_font_list[m_font_selected];
|
||||||
|
FontItem &fi = item.font_item;
|
||||||
|
if (fi.type == FontItem::Type::file_path) {
|
||||||
|
// fill font name after load from .3mf
|
||||||
|
if (fi.name.empty())
|
||||||
|
fi.name = get_file_name(fi.path);
|
||||||
|
std::unique_ptr<Emboss::FontFile> font_ptr = Emboss::load_font(
|
||||||
|
fi.path.c_str());
|
||||||
|
if (font_ptr == nullptr) return false;
|
||||||
|
item.font_file = std::move(font_ptr);
|
||||||
|
load_imgui_font();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (fi.type != WxFontUtils::get_actual_type()) return false;
|
||||||
|
std::optional<wxFont> wx_font = WxFontUtils::load_wxFont(fi.path);
|
||||||
|
if (!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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontManager::load_first_valid_font() {
|
||||||
|
// try to load valid font
|
||||||
|
m_font_selected = 0;
|
||||||
|
bool is_font_loaded = load_font();
|
||||||
|
while (!is_font_loaded && !m_font_list.empty()) {
|
||||||
|
// can't load so erase it from list
|
||||||
|
m_font_list.erase(m_font_list.begin());
|
||||||
|
is_font_loaded = load_font();
|
||||||
|
}
|
||||||
|
return !m_font_list.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontManager::add_font(FontItem font_item)
|
||||||
|
{
|
||||||
|
make_unique_name(font_item.name);
|
||||||
|
Item item;
|
||||||
|
item.font_item = font_item;
|
||||||
|
m_font_list.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontManager::add_fonts(FontList font_list)
|
||||||
|
{
|
||||||
|
for (const FontItem &fi : font_list)
|
||||||
|
add_font(fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Emboss::FontFile> &FontManager::get_font_file()
|
||||||
|
{
|
||||||
|
return m_font_list[m_font_selected].font_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FontItem &FontManager::get_font_item() const
|
||||||
|
{
|
||||||
|
return m_font_list[m_font_selected].font_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
FontItem &FontManager::get_font_item()
|
||||||
|
{
|
||||||
|
return m_font_list[m_font_selected].font_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImFont *FontManager::get_imgui_font()
|
||||||
|
{
|
||||||
|
return m_font_list[m_font_selected].imgui_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<FontManager::Item> &Slic3r::GUI::FontManager::get_fonts() const
|
||||||
|
{
|
||||||
|
return m_font_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<FontManager::Item> &FontManager::get_fonts()
|
||||||
|
{
|
||||||
|
return m_font_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FontManager::Item &FontManager::get_font() const
|
||||||
|
{
|
||||||
|
return m_font_list[m_font_selected];
|
||||||
|
}
|
||||||
|
|
||||||
|
FontManager::Item &FontManager::get_font(size_t index)
|
||||||
|
{
|
||||||
|
return m_font_list[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const FontManager::Item &FontManager::get_font(size_t index) const
|
||||||
|
{
|
||||||
|
return m_font_list[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontManager::make_unique_name(std::string &name) {
|
||||||
|
auto is_unique = [&](const std::string &name) -> bool {
|
||||||
|
for (const Item &it : m_font_list)
|
||||||
|
if (it.font_item.name == name) return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (name.empty()) name = "font";
|
||||||
|
if (is_unique(name)) return;
|
||||||
|
|
||||||
|
auto pos = name.find(" (");
|
||||||
|
if (pos != std::string::npos && name.find(")", pos) != std::string::npos) {
|
||||||
|
// short name by ord number
|
||||||
|
name = name.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int order = 1; // start with value 2 to represents same font name
|
||||||
|
std::string new_name;
|
||||||
|
do {
|
||||||
|
new_name = name + " (" + std::to_string(++order) + ")";
|
||||||
|
} while (!is_unique(new_name));
|
||||||
|
name = new_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontManager::check_imgui_font_range(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;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool exist_unknown = false;
|
||||||
|
const char *text_char_ptr = text.c_str();
|
||||||
|
while (*text_char_ptr) {
|
||||||
|
unsigned int c = 0;
|
||||||
|
// UTF-8 to 32-bit character need imgui_internal
|
||||||
|
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 (exist_unknown) load_imgui_font();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontManager::load_font(const wxFont &font)
|
||||||
|
{
|
||||||
|
auto font_ptr = WxFontUtils::load_font(font);
|
||||||
|
if (font_ptr == nullptr) return false;
|
||||||
|
m_font_list[m_font_selected].font_file = std::move(font_ptr);
|
||||||
|
load_imgui_font();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontManager::load_imgui_font(const std::string &text)
|
||||||
|
{
|
||||||
|
Item &item = m_font_list[m_font_selected];
|
||||||
|
if (item.font_file == nullptr) return;
|
||||||
|
|
||||||
|
// TODO: Create glyph range
|
||||||
|
ImFontGlyphRangesBuilder builder;
|
||||||
|
builder.AddRanges(m_imgui_init_glyph_range);
|
||||||
|
if (!text.empty())
|
||||||
|
builder.AddText(text.c_str());
|
||||||
|
item.font_ranges.clear();
|
||||||
|
|
||||||
|
builder.BuildRanges(&item.font_ranges);
|
||||||
|
const FontProp &font_prop = item.font_item.prop;
|
||||||
|
int font_size = static_cast<int>(
|
||||||
|
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;
|
||||||
|
if (font_size > m_cfg.max_imgui_font_size)
|
||||||
|
font_size = m_cfg.max_imgui_font_size;
|
||||||
|
|
||||||
|
ImFontConfig font_config;
|
||||||
|
font_config.FontDataOwnedByAtlas = false;
|
||||||
|
m_imgui_font_atlas.Flags |= ImFontAtlasFlags_NoMouseCursors |
|
||||||
|
ImFontAtlasFlags_NoPowerOfTwoHeight;
|
||||||
|
m_imgui_font_atlas.Clear();
|
||||||
|
|
||||||
|
const std::vector<unsigned char> &buffer = item.font_file->buffer;
|
||||||
|
m_imgui_font_atlas.AddFontFromMemoryTTF(
|
||||||
|
(void *) buffer.data(), buffer.size(), font_size, &font_config, item.font_ranges.Data);
|
||||||
|
|
||||||
|
unsigned char *pixels;
|
||||||
|
int width, height;
|
||||||
|
m_imgui_font_atlas.GetTexDataAsAlpha8(&pixels, &width, &height);
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
GLint last_texture;
|
||||||
|
glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
|
||||||
|
ScopeGuard sg([last_texture]() {
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture));
|
||||||
|
});
|
||||||
|
|
||||||
|
GLuint font_texture;
|
||||||
|
glsafe(::glGenTextures(1, &font_texture));
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, font_texture));
|
||||||
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||||
|
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||||
|
glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||||
|
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
|
||||||
|
GL_ALPHA, GL_UNSIGNED_BYTE, pixels));
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
m_imgui_font_atlas.TexID = (ImTextureID) (intptr_t) font_texture;
|
||||||
|
item.imgui_font = m_imgui_font_atlas.Fonts.front();
|
||||||
|
}
|
109
src/slic3r/Utils/FontManager.hpp
Normal file
109
src/slic3r/Utils/FontManager.hpp
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#ifndef slic3r_FontManager_hpp_
|
||||||
|
#define slic3r_FontManager_hpp_
|
||||||
|
|
||||||
|
#include <imgui/imgui.h>
|
||||||
|
#include "libslic3r/Emboss.hpp"
|
||||||
|
|
||||||
|
class wxFont;
|
||||||
|
|
||||||
|
namespace Slic3r::GUI {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GUI list of loaded fonts
|
||||||
|
/// Keep pointer to ImGui font pointers
|
||||||
|
/// Keep file data of TTF files
|
||||||
|
/// </summary>
|
||||||
|
class FontManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FontManager(const ImWchar *language_glyph_range);
|
||||||
|
void select(size_t index);
|
||||||
|
void duplicate(size_t index);
|
||||||
|
void erase(size_t index);
|
||||||
|
|
||||||
|
// load actual selected font
|
||||||
|
bool load_font();
|
||||||
|
// try to select and load font_index
|
||||||
|
bool load_font(size_t font_index);
|
||||||
|
// fastering load font on index by wxFont
|
||||||
|
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);
|
||||||
|
|
||||||
|
// erase font when not possible to load
|
||||||
|
bool load_first_valid_font();
|
||||||
|
|
||||||
|
// add font into manager
|
||||||
|
void add_font(FontItem font_item);
|
||||||
|
// add multiple font into manager
|
||||||
|
void add_fonts(FontList font_list);
|
||||||
|
|
||||||
|
// getter on active font file for access to glyphs
|
||||||
|
std::shared_ptr<Emboss::FontFile> &get_font_file();
|
||||||
|
|
||||||
|
// getter on active font item for access to font property
|
||||||
|
const FontItem &get_font_item() const;
|
||||||
|
FontItem &get_font_item();
|
||||||
|
|
||||||
|
// getter on acitve font pointer for imgui
|
||||||
|
ImFont *get_imgui_font();
|
||||||
|
|
||||||
|
// free used memory and font file data
|
||||||
|
void free_except_active_font();
|
||||||
|
|
||||||
|
struct Item;
|
||||||
|
// access to all managed fonts
|
||||||
|
const std::vector<Item> &get_fonts() const;
|
||||||
|
|
||||||
|
std::vector<Item> &get_fonts();
|
||||||
|
const Item &get_font() const;
|
||||||
|
const Item &get_font(size_t index) const;
|
||||||
|
Item &get_font(size_t index);
|
||||||
|
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
FontItem font_item;
|
||||||
|
|
||||||
|
// cache for view font name with maximal width in imgui
|
||||||
|
std::string truncated_name;
|
||||||
|
|
||||||
|
// share font file data with emboss job thread
|
||||||
|
std::shared_ptr<Emboss::FontFile> font_file = nullptr;
|
||||||
|
|
||||||
|
// ImGui font
|
||||||
|
ImFont *imgui_font;
|
||||||
|
|
||||||
|
// must live same as imgui_font inside of atlas
|
||||||
|
ImVector<ImWchar> font_ranges;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Configuration
|
||||||
|
{
|
||||||
|
// limits for imgui loaded font
|
||||||
|
// Value out of limits is crop
|
||||||
|
int min_imgui_font_size = 18;
|
||||||
|
int max_imgui_font_size = 60;
|
||||||
|
} m_cfg;
|
||||||
|
|
||||||
|
// load actual font by wx font
|
||||||
|
bool load_font(const wxFont &font);
|
||||||
|
|
||||||
|
void make_unique_name(std::string &name);
|
||||||
|
|
||||||
|
// Privat member
|
||||||
|
std::vector<Item> m_font_list;
|
||||||
|
size_t m_font_selected; // index to m_font_list
|
||||||
|
|
||||||
|
// store all font GLImages
|
||||||
|
ImFontAtlas m_imgui_font_atlas;
|
||||||
|
const ImWchar *m_imgui_init_glyph_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_FontManager_hpp_
|
@ -12,7 +12,7 @@
|
|||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::GUI;
|
using namespace Slic3r::GUI;
|
||||||
|
|
||||||
std::unique_ptr<Emboss::Font> WxFontUtils::load_font(const wxFont &font)
|
std::unique_ptr<Emboss::FontFile> WxFontUtils::load_font(const wxFont &font)
|
||||||
{
|
{
|
||||||
if (!font.IsOk()) return nullptr;
|
if (!font.IsOk()) return nullptr;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -16,7 +16,7 @@ public:
|
|||||||
WxFontUtils() = delete;
|
WxFontUtils() = delete;
|
||||||
|
|
||||||
// os specific load of wxFont
|
// os specific load of wxFont
|
||||||
static std::unique_ptr<Slic3r::Emboss::Font> load_font(const wxFont &font);
|
static std::unique_ptr<Slic3r::Emboss::FontFile> load_font(const wxFont &font);
|
||||||
|
|
||||||
static FontItem::Type get_actual_type();
|
static FontItem::Type get_actual_type();
|
||||||
static FontItem get_font_item(const wxFont &font);
|
static FontItem get_font_item(const wxFont &font);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user