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:
|
||||
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<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);
|
||||
|
||||
static FontItem create_font_item(std::wstring name, std::wstring path);
|
||||
@ -42,7 +42,7 @@ public:
|
||||
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);
|
||||
}
|
||||
@ -125,7 +125,7 @@ std::optional<Emboss::Glyph> Private::get_glyph(stbtt_fontinfo &font_info, int u
|
||||
|
||||
std::optional<Emboss::Glyph> Private::get_glyph(
|
||||
int unicode,
|
||||
const Emboss::Font & font,
|
||||
const Emboss::FontFile & font,
|
||||
const FontProp & font_prop,
|
||||
Emboss::Glyphs & cache,
|
||||
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
|
||||
|
||||
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;
|
||||
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
|
||||
int 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::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");
|
||||
if (file == nullptr) {
|
||||
@ -520,7 +521,7 @@ std::unique_ptr<Emboss::Font> Emboss::load_font(const char *file_path)
|
||||
|
||||
|
||||
#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);
|
||||
if (hdc == NULL) {
|
||||
@ -559,16 +560,16 @@ std::unique_ptr<Emboss::Font> Emboss::load_font(HFONT hfont)
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
std::optional<Emboss::Glyph> Emboss::letter2glyph(const Font &font,
|
||||
int letter,
|
||||
float flatness)
|
||||
std::optional<Emboss::Glyph> Emboss::letter2glyph(const FontFile &font,
|
||||
int letter,
|
||||
float flatness)
|
||||
{
|
||||
auto font_info_opt = Private::load_font_info(font);
|
||||
if (!font_info_opt.has_value()) return {};
|
||||
return Private::get_glyph(*font_info_opt, letter, flatness);
|
||||
}
|
||||
|
||||
ExPolygons Emboss::text2shapes(Font & font,
|
||||
ExPolygons Emboss::text2shapes(FontFile & font,
|
||||
const char * text,
|
||||
const FontProp &font_prop)
|
||||
{
|
||||
@ -614,7 +615,7 @@ ExPolygons Emboss::text2shapes(Font & font,
|
||||
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 =
|
||||
Private::load_font_info(font);
|
||||
|
||||
|
@ -52,11 +52,12 @@ public:
|
||||
using Glyphs = std::map<int, Glyph>;
|
||||
|
||||
/// <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)
|
||||
/// + user defined modification of font
|
||||
/// </summary>
|
||||
struct Font
|
||||
struct FontFile
|
||||
{
|
||||
// loaded data from font file
|
||||
const std::vector<unsigned char> buffer;
|
||||
@ -67,50 +68,34 @@ public:
|
||||
// vertical position is "scale*(ascent - descent + lineGap)"
|
||||
const int ascent, descent, linegap;
|
||||
|
||||
// user defined font modification
|
||||
// + emboss parameter
|
||||
FontProp prop;
|
||||
|
||||
Emboss::Glyphs cache; // cache of glyphs
|
||||
|
||||
Font(std::vector<unsigned char> &&buffer,
|
||||
unsigned int count,
|
||||
int ascent,
|
||||
int descent,
|
||||
int linegap)
|
||||
FontFile(std::vector<unsigned char> &&buffer,
|
||||
unsigned int count,
|
||||
int ascent,
|
||||
int descent,
|
||||
int linegap)
|
||||
: buffer(std::move(buffer))
|
||||
, index(0) // select default font on index 0
|
||||
, count(count)
|
||||
, ascent(ascent)
|
||||
, descent(descent)
|
||||
, linegap(linegap)
|
||||
, prop(7.f, 1.f)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
struct UserFont
|
||||
{
|
||||
// description of file
|
||||
Font file_font;
|
||||
// user defined font modification
|
||||
FontProp prop;
|
||||
// cache of glyphs
|
||||
Emboss::Glyphs cache;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Load font file into buffer
|
||||
/// </summary>
|
||||
/// <param name="file_path">Location of .ttf or .ttc font file</param>
|
||||
/// <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
|
||||
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
|
||||
// fix for unknown pointer HFONT
|
||||
using HFONT = void*;
|
||||
static std::unique_ptr<Font> load_font(HFONT hfont);
|
||||
static std::unique_ptr<FontFile> load_font(HFONT hfont);
|
||||
#endif // _WIN32
|
||||
|
||||
/// <summary>
|
||||
@ -120,7 +105,7 @@ public:
|
||||
/// <param name="letter">One character defined by unicode codepoint</param>
|
||||
/// <param name="flatness">Precision of lettter outline curve in conversion to lines</param>
|
||||
/// <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>
|
||||
/// Convert text into polygons
|
||||
@ -129,7 +114,7 @@ public:
|
||||
/// <param name="text">Characters to convert</param>
|
||||
/// <param name="font_prop">User defined property of the font</param>
|
||||
/// <returns>Inner polygon cw(outer ccw)</returns>
|
||||
static ExPolygons text2shapes(Font & font,
|
||||
static ExPolygons text2shapes(FontFile & font,
|
||||
const char * text,
|
||||
const FontProp &font_prop);
|
||||
|
||||
@ -139,7 +124,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="font">Selector of font</param>
|
||||
/// <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>
|
||||
/// Project 2d point into space
|
||||
|
@ -873,6 +873,11 @@ private:
|
||||
this->calculate_convex_hull();
|
||||
} else
|
||||
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 {
|
||||
bool has_convex_hull = m_convex_hull.get() != nullptr;
|
||||
@ -883,6 +888,8 @@ private:
|
||||
cereal::save_by_value(ar, config);
|
||||
if (has_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)
|
||||
: 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
|
||||
@ -78,6 +102,12 @@ struct FontItem
|
||||
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
|
||||
};
|
||||
|
||||
// undo / redo stack recovery
|
||||
template<class Archive> void serialize(Archive &ar)
|
||||
{
|
||||
ar(name, path, (int) type, prop);
|
||||
}
|
||||
};
|
||||
|
||||
// Font item name inside list is unique
|
||||
@ -99,6 +129,9 @@ struct TextConfiguration
|
||||
TextConfiguration(const FontItem &font_item, const std::string &text)
|
||||
: font_item(font_item), text(text)
|
||||
{}
|
||||
|
||||
// undo / redo stack recovery
|
||||
template<class Archive> void serialize(Archive &ar){ ar(text, font_item); }
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -234,6 +234,10 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/FlashAir.hpp
|
||||
Utils/FontConfigHelp.cpp
|
||||
Utils/FontConfigHelp.hpp
|
||||
Utils/FontListSerializable.cpp
|
||||
Utils/FontListSerializable.hpp
|
||||
Utils/FontManager.cpp
|
||||
Utils/FontManager.hpp
|
||||
Utils/AstroBox.cpp
|
||||
Utils/AstroBox.hpp
|
||||
Utils/Repetier.cpp
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "slic3r/GUI/Jobs/EmbossJob.hpp"
|
||||
#include "slic3r/GUI/Jobs/NotificationProgressIndicator.hpp"
|
||||
#include "slic3r/Utils/WxFontUtils.hpp"
|
||||
#include "slic3r/Utils/FontListSerializable.hpp"
|
||||
|
||||
// TODO: remove include
|
||||
#include "libslic3r/SVG.hpp" // debug store
|
||||
@ -36,19 +37,16 @@
|
||||
// uncomment for easier debug
|
||||
//#define ALLOW_DEBUG_MODE
|
||||
|
||||
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::GUI;
|
||||
|
||||
GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
|
||||
: GLGizmoBase(parent, M_ICON_FILENAME, -2)
|
||||
, m_font_selected(0)
|
||||
, m_font(nullptr)
|
||||
, m_volume(nullptr)
|
||||
, m_exist_notification(false)
|
||||
, m_is_initialized(false) // initialize on first opening gizmo
|
||||
, 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);
|
||||
// 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();
|
||||
if(selection.is_empty()) return;
|
||||
|
||||
set_default_configuration();
|
||||
set_default_text();
|
||||
|
||||
// By position of cursor create transformation to put text on surface of model
|
||||
Transform3d transformation;
|
||||
@ -355,7 +353,7 @@ void GLGizmoEmboss::on_set_state()
|
||||
bool create_new_object = selection.is_empty();
|
||||
// When add Text on empty plate, Create new object with volume
|
||||
if (create_new_object) {
|
||||
set_default_configuration();
|
||||
set_default_text();
|
||||
create_emboss_object(create_mesh(), create_volume_name(), create_configuration());
|
||||
|
||||
// gizmo will open when successfuly create new object
|
||||
@ -428,26 +426,26 @@ void GLGizmoEmboss::initialize()
|
||||
m_gui_cfg->minimal_window_size_with_advance =
|
||||
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();
|
||||
assert(success);
|
||||
load_font_list_from_app_config();
|
||||
|
||||
// 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();
|
||||
const AppConfig *app_cfg = wxGetApp().app_config;
|
||||
FontList font_list = load_font_list_from_app_config(app_cfg);
|
||||
m_font_manager.add_fonts(font_list);
|
||||
if (!m_font_manager.load_first_valid_font()) {
|
||||
FontList font_list = FontListSerializable::create_default_font_list();
|
||||
m_font_manager.add_fonts(font_list);
|
||||
// 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");
|
||||
//load_font(); // reload actual font - because of font size
|
||||
}
|
||||
|
||||
Slic3r::TriangleMesh GLGizmoEmboss::create_default_mesh()
|
||||
@ -466,16 +464,18 @@ Slic3r::TriangleMesh GLGizmoEmboss::create_mesh()
|
||||
{
|
||||
// It is neccessary to create some shape
|
||||
// Emboss text window is opened by creation new embosstext object
|
||||
if (m_font == nullptr) return create_default_mesh();
|
||||
const FontItem &fi = m_font_list[m_font_selected];
|
||||
TriangleMesh result = create_mesh(m_text.c_str(), *m_font, fi.prop);
|
||||
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
||||
if (font_file == nullptr || m_font_manager.get_fonts().empty())
|
||||
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();
|
||||
return result;
|
||||
}
|
||||
|
||||
Slic3r::TriangleMesh GLGizmoEmboss::create_mesh(const char * text,
|
||||
Emboss::Font &font,
|
||||
const FontProp& font_prop)
|
||||
Slic3r::TriangleMesh GLGizmoEmboss::create_mesh(const char * text,
|
||||
Emboss::FontFile &font,
|
||||
const FontProp & font_prop)
|
||||
{
|
||||
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
|
||||
float scale = font_prop.size_in_mm / font.ascent;
|
||||
@ -505,7 +505,7 @@ void GLGizmoEmboss::check_selection()
|
||||
|
||||
// behave like adding new text
|
||||
m_volume = nullptr;
|
||||
set_default_configuration();
|
||||
set_default_text();
|
||||
}
|
||||
|
||||
ModelVolume *GLGizmoEmboss::get_selected_volume()
|
||||
@ -551,9 +551,11 @@ bool GLGizmoEmboss::process()
|
||||
if (m_volume == nullptr) return false;
|
||||
|
||||
// exist loaded font?
|
||||
if (m_font == nullptr) return false;
|
||||
auto data = std::make_unique<EmbossData>(
|
||||
m_font, create_configuration(), create_volume_name(), m_volume);
|
||||
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
||||
if (font_file == nullptr) return false;
|
||||
auto data = std::make_unique<EmbossData>(font_file,
|
||||
create_configuration(),
|
||||
create_volume_name(), m_volume);
|
||||
|
||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||
replace_job(worker, std::make_unique<EmbossJob>(std::move(data)));
|
||||
@ -580,7 +582,8 @@ void GLGizmoEmboss::draw_window()
|
||||
bool loaded = load_font(font_index);
|
||||
}
|
||||
#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());
|
||||
}
|
||||
draw_font_list();
|
||||
@ -599,7 +602,7 @@ void GLGizmoEmboss::draw_window()
|
||||
if (ImGui::Button(_u8L("Close").c_str())) close();
|
||||
|
||||
// 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) {
|
||||
ImGui::SameLine();
|
||||
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;
|
||||
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);
|
||||
const auto &fonts = m_font_manager.get_fonts();
|
||||
ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
|
||||
if (ImGui::BeginCombo("##font_selector", trunc_name.c_str())) {
|
||||
// first line
|
||||
@ -645,25 +650,30 @@ void GLGizmoEmboss::draw_font_list()
|
||||
#endif // ALLOW_DEBUG_MODE
|
||||
|
||||
ImGui::Separator();
|
||||
for (FontItem &f : m_font_list) {
|
||||
ImGui::PushID(f.name.c_str());
|
||||
std::string name = ImGuiWrapper::trunc(f.name, max_width);
|
||||
size_t index = &f - &m_font_list.front();
|
||||
bool is_selected = index == m_font_selected;
|
||||
for (const auto &item : fonts) {
|
||||
size_t index = &item - &fonts.front();
|
||||
const FontItem &fi = item.font_item;
|
||||
ImGui::PushID(fi.name.c_str());
|
||||
std::string name = ImGuiWrapper::trunc(fi.name, max_width);
|
||||
|
||||
bool is_selected = (&fi == &actual_font_item);
|
||||
ImGuiSelectableFlags_ flags = ImGuiSelectableFlags_AllowItemOverlap; // allow click buttons
|
||||
if (ImGui::Selectable(name.c_str(), is_selected, flags) ) {
|
||||
if (load_font(index)) process();
|
||||
if (m_font_manager.load_font(index)) process();
|
||||
} else if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", f.name.c_str());
|
||||
ImGui::SetTooltip("%s", fi.name.c_str());
|
||||
|
||||
// reorder items
|
||||
if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) {
|
||||
int other_index = index + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
|
||||
if (other_index >= 0 && other_index < m_font_list.size()) {
|
||||
std::swap(m_font_list[index], m_font_list[other_index]);
|
||||
if (other_index >= 0 && other_index < fonts.size()) {
|
||||
std::swap(m_font_manager.get_font(index),
|
||||
m_font_manager.get_font(other_index));
|
||||
// fix selected index
|
||||
if (m_font_selected == other_index) m_font_selected = index;
|
||||
else if (m_font_selected == index) m_font_selected = other_index;
|
||||
if (is_selected)
|
||||
m_font_manager.select(other_index);
|
||||
else if (&fonts[other_index].font_item == &actual_font_item)
|
||||
m_font_manager.select(index);
|
||||
ImGui::ResetMouseDragDelta();
|
||||
}
|
||||
}
|
||||
@ -682,21 +692,13 @@ void GLGizmoEmboss::draw_font_list()
|
||||
|
||||
// duplicate font item
|
||||
if (duplicate_index.has_value()) {
|
||||
size_t index = *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;
|
||||
m_font_manager.duplicate(*duplicate_index);
|
||||
store_font_list_to_app_config();
|
||||
}
|
||||
|
||||
// delete font item
|
||||
if (delete_index.has_value()) {
|
||||
size_t index = *delete_index;
|
||||
m_font_list.erase(m_font_list.begin() + index);
|
||||
// fix selected index
|
||||
if (index < m_font_selected) --m_font_selected;
|
||||
m_font_manager.erase(*delete_index);
|
||||
store_font_list_to_app_config();
|
||||
}
|
||||
|
||||
@ -706,7 +708,7 @@ void GLGizmoEmboss::draw_font_list()
|
||||
static std::string new_name;
|
||||
if (rename_index.has_value() && !ImGui::IsPopupOpen(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
|
||||
}
|
||||
|
||||
@ -718,7 +720,8 @@ void GLGizmoEmboss::draw_font_list()
|
||||
ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
|
||||
|
||||
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.name == new_name) is_unique = false;
|
||||
}
|
||||
@ -740,8 +743,7 @@ void GLGizmoEmboss::draw_text_input()
|
||||
static const ImGuiInputTextFlags flags =
|
||||
ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_AutoSelectAll;
|
||||
|
||||
ImVector<ImFont *> &fonts = m_imgui_font_atlas.Fonts;
|
||||
ImFont * imgui_font = fonts.empty() ? nullptr : fonts.front();
|
||||
ImFont *imgui_font = m_font_manager.get_imgui_font();
|
||||
bool exist_font = imgui_font != nullptr && imgui_font->IsLoaded();
|
||||
if (exist_font) ImGui::PushFont(imgui_font);
|
||||
|
||||
@ -761,17 +763,18 @@ void GLGizmoEmboss::draw_text_input()
|
||||
if (exist_font) ImGui::PopFont();
|
||||
|
||||
// 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()
|
||||
{
|
||||
if (m_font != nullptr) {
|
||||
ImGui::Text("%s", _u8L("Advanced font options could be change only for corect font.\nStart with select correct font."));
|
||||
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
||||
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;
|
||||
}
|
||||
|
||||
FontItem &fi = m_font_list[m_font_selected];
|
||||
FontItem &fi = m_font_manager.get_font_item();
|
||||
FontProp &font_prop = fi.prop;
|
||||
bool exist_change = false;
|
||||
|
||||
@ -787,8 +790,8 @@ void GLGizmoEmboss::draw_advanced()
|
||||
fi.path = WxFontUtils::store_wxFont(*wx_font);
|
||||
}
|
||||
}
|
||||
load_imgui_font();
|
||||
m_font->cache.clear();
|
||||
m_font_manager.load_imgui_font();
|
||||
font_file->cache.clear();
|
||||
exist_change = true;
|
||||
}
|
||||
|
||||
@ -798,7 +801,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
|
||||
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)) {
|
||||
m_font->cache.clear();
|
||||
font_file->cache.clear();
|
||||
exist_change = true;
|
||||
}
|
||||
|
||||
@ -808,27 +811,27 @@ void GLGizmoEmboss::draw_advanced()
|
||||
|
||||
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"))){
|
||||
m_font->cache.clear();
|
||||
font_file->cache.clear();
|
||||
exist_change = true;
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
|
||||
if (m_imgui->slider_optional_float(_u8L("Skew ratio").c_str(), font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("italic strength"))){
|
||||
m_font->cache.clear();
|
||||
font_file->cache.clear();
|
||||
exist_change = true;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (ImGui::BeginCombo(_u8L("Font collection").c_str(),
|
||||
std::to_string(m_font->index).c_str())) {
|
||||
for (unsigned int i = 0; i < m_font->count; ++i) {
|
||||
std::to_string(font_file->index).c_str())) {
|
||||
for (unsigned int i = 0; i < font_file->count; ++i) {
|
||||
ImGui::PushID(1 << (10 + i));
|
||||
if (ImGui::Selectable(std::to_string(i).c_str(),
|
||||
i == m_font->index)) {
|
||||
m_font->index = i;
|
||||
m_font->cache.clear();
|
||||
i == font_file->index)) {
|
||||
font_file->index = i;
|
||||
font_file->cache.clear();
|
||||
exist_change = true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
@ -844,7 +847,6 @@ void GLGizmoEmboss::draw_advanced()
|
||||
|
||||
|
||||
#ifdef ALLOW_DEBUG_MODE
|
||||
std::string descriptor = m_font_list[m_font_selected].path;
|
||||
ImGui::Text("family = %s", (font_prop.family.has_value() ?
|
||||
font_prop.family->c_str() :
|
||||
" --- "));
|
||||
@ -857,6 +859,8 @@ void GLGizmoEmboss::draw_advanced()
|
||||
ImGui::Text("weight = %s", (font_prop.weight.has_value() ?
|
||||
font_prop.weight->c_str() :
|
||||
" --- "));
|
||||
|
||||
std::string descriptor = fi.path;
|
||||
ImGui::Text("descriptor = %s", descriptor.c_str());
|
||||
ImGui::Image(m_imgui_font_atlas.TexID,
|
||||
ImVec2(m_imgui_font_atlas.TexWidth,
|
||||
@ -864,171 +868,13 @@ void GLGizmoEmboss::draw_advanced()
|
||||
#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()
|
||||
{
|
||||
wxFontData data;
|
||||
data.EnableEffects(false);
|
||||
data.RestrictSelection(wxFONTRESTRICT_SCALABLE);
|
||||
// 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()) {
|
||||
std::optional<wxFont> selected_font = WxFontUtils::load_wxFont(
|
||||
selected_font_item.path);
|
||||
@ -1040,32 +886,20 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
|
||||
|
||||
data = font_dialog.GetFontData();
|
||||
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);
|
||||
|
||||
// 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);
|
||||
m_font_manager.add_font(font_item);
|
||||
|
||||
// Check that deserialization NOT influence font
|
||||
// false - use direct selected wxFont in dialog
|
||||
// true - use font item (serialize and deserialize wxFont)
|
||||
bool use_deserialized_font = false;
|
||||
if (!use_deserialized_font) m_font_selected = font_index;
|
||||
|
||||
// Try load and use new added font
|
||||
if ((!use_deserialized_font && !load_font(font)) ||
|
||||
(use_deserialized_font && !load_font(font_index)) ||
|
||||
if ((use_deserialized_font && !m_font_manager.load_font(font_index)) ||
|
||||
(!use_deserialized_font && !m_font_manager.load_font(font_index, font)) ||
|
||||
!process()) {
|
||||
// reverse index for font_selected
|
||||
std::swap(font_index, m_font_selected); // when not process
|
||||
// remove form font list
|
||||
m_font_list.pop_back();
|
||||
m_font_manager.erase(font_index);
|
||||
wxString message = GUI::format_wxstr(
|
||||
_L("Font '%1%' can't be used. Please select another."),
|
||||
font_item.name);
|
||||
@ -1074,6 +908,14 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
|
||||
not_loaded_font_message.ShowModal();
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1091,14 +933,15 @@ bool GLGizmoEmboss::choose_true_type_file()
|
||||
for (auto &input_file : input_files) {
|
||||
std::string path = std::string(input_file.c_str());
|
||||
std::string name = get_file_name(path);
|
||||
make_unique_name(name, m_font_list);
|
||||
m_font_list.emplace_back(name, path, FontItem::Type::file_path, FontProp());
|
||||
//make_unique_name(name, m_font_list);
|
||||
FontItem fi(name, path, FontItem::Type::file_path, FontProp());
|
||||
m_font_manager.add_font(fi);
|
||||
|
||||
// set first valid added font as active
|
||||
if (!font_loaded) {
|
||||
if (!load_font(m_font_list.size() - 1))
|
||||
m_font_list.pop_back();
|
||||
else
|
||||
if (!m_font_manager.load_font(m_font_manager.get_fonts().size() - 1)) {
|
||||
//m_font_list.pop_back();
|
||||
} else
|
||||
font_loaded = true;
|
||||
}
|
||||
}
|
||||
@ -1127,7 +970,7 @@ bool GLGizmoEmboss::choose_svg_file()
|
||||
|
||||
BoundingBox bb;
|
||||
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());
|
||||
auto project = std::make_unique<Emboss::ProjectScale>(
|
||||
std::make_unique<Emboss::ProjectZ>(fp.emboss / scale), scale);
|
||||
@ -1142,7 +985,7 @@ bool GLGizmoEmboss::choose_svg_file()
|
||||
|
||||
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)
|
||||
@ -1154,43 +997,41 @@ bool GLGizmoEmboss::load_configuration(ModelVolume *volume)
|
||||
FontItem & c_font_item = configuration.font_item;
|
||||
|
||||
// try to find font in local font list
|
||||
auto is_config = [&c_font_item](const FontItem &font_item) -> bool {
|
||||
return font_item.path == c_font_item.path;
|
||||
auto is_config = [&c_font_item](const FontManager::Item &font_item) -> bool {
|
||||
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);
|
||||
|
||||
size_t prev_font_selected = m_font_selected;
|
||||
|
||||
if (it == m_font_list.end()) {
|
||||
const auto& fonts = m_font_manager.get_fonts();
|
||||
auto it = std::find_if(fonts.begin(), fonts.end(), is_config);
|
||||
bool found_font = it != fonts.end();
|
||||
size_t font_index;
|
||||
if (!found_font) {
|
||||
// font is not in list
|
||||
// add font to list
|
||||
m_font_selected = m_font_list.size();
|
||||
make_unique_name(c_font_item.name, m_font_list);
|
||||
m_font_list.emplace_back(c_font_item);
|
||||
font_index = fonts.size();
|
||||
m_font_manager.add_font(c_font_item);
|
||||
} else {
|
||||
// font is found in list
|
||||
m_font_selected = it - m_font_list.begin();
|
||||
font_index = it - fonts.begin();
|
||||
}
|
||||
|
||||
m_text = configuration.text;
|
||||
m_volume = volume;
|
||||
|
||||
if (!load_font()) {
|
||||
if (!m_font_manager.load_font(font_index)) {
|
||||
// create similar font
|
||||
auto wx_font = WxFontUtils::create_wxFont(c_font_item, configuration.font_item.prop);
|
||||
if (wx_font.has_value()) {
|
||||
// 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);
|
||||
fi_new.name = fi.name; // use previous name
|
||||
fi = fi_new; // rewrite font item
|
||||
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 {
|
||||
// can't create similar font use previous
|
||||
m_font_list.erase(m_font_list.begin() + m_font_selected);
|
||||
m_font_selected = prev_font_selected;
|
||||
if (!load_font()) return false;
|
||||
m_font_manager.erase(font_index);
|
||||
}
|
||||
create_notification_not_valid_font(configuration);
|
||||
}
|
||||
@ -1208,7 +1049,7 @@ void GLGizmoEmboss::create_notification_not_valid_font(
|
||||
auto level =
|
||||
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 &actual_family = fi.prop.face_name;
|
||||
|
||||
@ -1341,54 +1182,28 @@ bool GLGizmoEmboss::draw_button(IconType icon, bool disable)
|
||||
return false;
|
||||
}
|
||||
|
||||
class FontListSerializable
|
||||
FontList GLGizmoEmboss::load_font_list_from_app_config(const AppConfig *cfg)
|
||||
{
|
||||
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);
|
||||
};
|
||||
|
||||
void GLGizmoEmboss::load_font_list_from_app_config()
|
||||
{
|
||||
const AppConfig *cfg = wxGetApp().app_config;
|
||||
unsigned index = 1;
|
||||
std::string section_name = FontListSerializable::create_section_name(index++);
|
||||
FontList result;
|
||||
unsigned index = 1;
|
||||
std::string section_name = FontListSerializable::create_section_name(index++);
|
||||
while (cfg->has_section(section_name)) {
|
||||
std::optional<FontItem> fi = FontListSerializable::load_font_item(cfg->get_section(section_name));
|
||||
if (fi.has_value()) {
|
||||
make_unique_name(fi->name, m_font_list);
|
||||
m_font_list.emplace_back(*fi);
|
||||
}
|
||||
if (fi.has_value()) result.emplace_back(*fi);
|
||||
section_name = FontListSerializable::create_section_name(index++);
|
||||
}
|
||||
if (m_font_list.empty())
|
||||
m_font_list = FontListSerializable::create_default_font_list();
|
||||
if (result.empty())
|
||||
return FontListSerializable::create_default_font_list();
|
||||
return result;
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::store_font_list_to_app_config() const
|
||||
{
|
||||
AppConfig *cfg = wxGetApp().app_config;
|
||||
unsigned index = 1;
|
||||
for (const FontItem &fi : m_font_list) {
|
||||
// skip file paths + fonts from other OS
|
||||
for (const auto& item : m_font_manager.get_fonts()) {
|
||||
const FontItem &fi = item.font_item;
|
||||
// skip file paths + fonts from other OS(loaded from .3mf)
|
||||
if (fi.type != WxFontUtils::get_actual_type()) continue;
|
||||
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
|
||||
{
|
||||
AppConfig *cfg = wxGetApp().app_config;
|
||||
unsigned index = m_font_selected + 1;
|
||||
FontListSerializable::store_font_item(
|
||||
*cfg, m_font_list[m_font_selected], index);
|
||||
}
|
||||
|
||||
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));
|
||||
// index of section start from 1
|
||||
const FontItem &fi = m_font_manager.get_font_item();
|
||||
size_t index = &m_font_manager.get_font() -
|
||||
&m_font_manager.get_fonts().front();
|
||||
// TODO: fix index when, not serialized font is in list
|
||||
FontListSerializable::store_font_item(*cfg, fi, index);
|
||||
}
|
||||
|
||||
std::string GLGizmoEmboss::get_file_name(const std::string &file_path)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "GLGizmoRotate.hpp"
|
||||
#include "slic3r/GUI/GLTexture.hpp"
|
||||
#include "slic3r/Utils/RaycastManager.hpp"
|
||||
#include "slic3r/Utils/FontManager.hpp"
|
||||
|
||||
#include "admesh/stl.h" // indexed_triangle_set
|
||||
#include <optional>
|
||||
@ -74,7 +75,7 @@ protected:
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
void set_default_configuration();
|
||||
void set_default_text();
|
||||
TriangleMesh create_default_mesh();
|
||||
TriangleMesh create_mesh();
|
||||
|
||||
@ -87,7 +88,7 @@ private:
|
||||
/// <param name="font_prop">Property of font</param>
|
||||
/// <returns>Triangle mesh model</returns>
|
||||
static TriangleMesh create_mesh(const char * text,
|
||||
Emboss::Font & font,
|
||||
Emboss::FontFile & font,
|
||||
const FontProp &font_prop);
|
||||
|
||||
void check_selection();
|
||||
@ -106,15 +107,6 @@ private:
|
||||
bool on_mouse_for_rotation(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_true_type_file();
|
||||
bool choose_svg_file();
|
||||
@ -137,11 +129,6 @@ private:
|
||||
{
|
||||
size_t max_count_char_in_volume_name = 20;
|
||||
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;
|
||||
|
||||
// setted only when wanted to use - not all the time
|
||||
@ -162,11 +149,11 @@ private:
|
||||
};
|
||||
std::optional<GuiCfg> m_gui_cfg;
|
||||
|
||||
FontList m_font_list;
|
||||
size_t m_font_selected;// index to m_font_list
|
||||
FontManager m_font_manager;
|
||||
|
||||
// to share data with job thread
|
||||
std::shared_ptr<Emboss::Font> m_font;
|
||||
//FontList m_font_list;
|
||||
//size_t m_font_selected;// index to m_font_list
|
||||
|
||||
std::string m_text;
|
||||
|
||||
// actual volume
|
||||
@ -185,11 +172,6 @@ private:
|
||||
// initialize when GL is accessible
|
||||
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
|
||||
GLTexture m_icons_texture;
|
||||
bool init_icons();
|
||||
@ -199,7 +181,7 @@ private:
|
||||
bool draw_button(IconType icon, bool disable = false);
|
||||
|
||||
// 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_item_to_app_config() const;
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace Slic3r::GUI {
|
||||
struct EmbossData
|
||||
{
|
||||
// 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
|
||||
TextConfiguration text_configuration;
|
||||
// new volume name created from text
|
||||
@ -28,10 +28,10 @@ struct EmbossData
|
||||
// Change of volume change id, last change could disapear
|
||||
//ObjectID volume_id;
|
||||
|
||||
EmbossData(std::shared_ptr<Emboss::Font> font,
|
||||
TextConfiguration text_configuration,
|
||||
std::string volume_name,
|
||||
ModelVolume * volume)
|
||||
EmbossData(std::shared_ptr<Emboss::FontFile> font,
|
||||
TextConfiguration text_configuration,
|
||||
std::string volume_name,
|
||||
ModelVolume * volume)
|
||||
: font(std::move(font))
|
||||
, text_configuration(text_configuration)
|
||||
, volume_name(volume_name)
|
||||
|
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::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;
|
||||
#ifdef _WIN32
|
||||
|
@ -16,7 +16,7 @@ public:
|
||||
WxFontUtils() = delete;
|
||||
|
||||
// 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 get_font_item(const wxFont &font);
|
||||
|
Loading…
Reference in New Issue
Block a user