Show user warning about unknown symbols by font inside of input text
Fix correct selection of collection ascent, descent, ... Remove boost log from emboss --> not work properly on thread
This commit is contained in:
parent
68c34210d2
commit
331d4d4557
@ -22,6 +22,7 @@ class Private
|
||||
{
|
||||
public:
|
||||
Private() = delete;
|
||||
static bool is_valid(const Emboss::FontFile &font, unsigned int index);
|
||||
static std::optional<stbtt_fontinfo> load_font_info(const unsigned char *data, unsigned int index = 0);
|
||||
static std::optional<Emboss::Glyph> get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness);
|
||||
|
||||
@ -43,17 +44,27 @@ public:
|
||||
static Point to_point(const stbtt__point &point);
|
||||
};
|
||||
|
||||
bool Private::is_valid(const Emboss::FontFile &font, unsigned int index) {
|
||||
if (font.data == nullptr) return false;
|
||||
if (font.data->empty()) return false;
|
||||
if (font.count == 0) return false;
|
||||
if (index >= font.count) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<stbtt_fontinfo> Private::load_font_info(
|
||||
const unsigned char *data, unsigned int index)
|
||||
{
|
||||
int font_offset = stbtt_GetFontOffsetForIndex(data, index);
|
||||
if (font_offset < 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Font index(" << index << ") doesn't exist." << std::endl;
|
||||
assert(false);
|
||||
// "Font index(" << index << ") doesn't exist.";
|
||||
return {};
|
||||
}
|
||||
stbtt_fontinfo font_info;
|
||||
if (stbtt_InitFont(&font_info, data, font_offset) == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Can't initialize font." << std::endl;
|
||||
// Can't initialize font.
|
||||
assert(false);
|
||||
return {};
|
||||
}
|
||||
return font_info;
|
||||
@ -63,12 +74,12 @@ std::optional<Emboss::Glyph> Private::get_glyph(const stbtt_fontinfo &font_info,
|
||||
{
|
||||
int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter);
|
||||
if (glyph_index == 0) {
|
||||
wchar_t wchar = static_cast<wchar_t>(unicode_letter);
|
||||
BOOST_LOG_TRIVIAL(error) << "Character unicode letter ("
|
||||
<< "decimal value = " << std::dec << unicode_letter << ", "
|
||||
<< "hexadecimal value = U+" << std::hex << unicode_letter << std::dec << ", "
|
||||
<< "wchar value = " << wchar
|
||||
<< ") is NOT defined inside of the font. \n";
|
||||
//wchar_t wchar = static_cast<wchar_t>(unicode_letter);
|
||||
//<< "Character unicode letter ("
|
||||
//<< "decimal value = " << std::dec << unicode_letter << ", "
|
||||
//<< "hexadecimal value = U+" << std::hex << unicode_letter << std::dec << ", "
|
||||
//<< "wchar value = " << wchar
|
||||
//<< ") is NOT defined inside of the font. \n";
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -137,16 +148,18 @@ const Emboss::Glyph* Private::get_glyph(
|
||||
auto glyph_item = cache.find(unicode);
|
||||
if (glyph_item != cache.end()) return &glyph_item->second;
|
||||
|
||||
if (!font_info_opt.has_value()) {
|
||||
unsigned int font_index = font_prop.collection_number.has_value()?
|
||||
unsigned int font_index = font_prop.collection_number.has_value()?
|
||||
*font_prop.collection_number : 0;
|
||||
if (font_index >= font.count) return nullptr;
|
||||
if (!is_valid(font, font_index)) return nullptr;
|
||||
|
||||
if (!font_info_opt.has_value()) {
|
||||
|
||||
font_info_opt = Private::load_font_info(font.data->data(), font_index);
|
||||
// can load font info?
|
||||
if (!font_info_opt.has_value()) return nullptr;
|
||||
}
|
||||
float flatness = static_cast<float>(
|
||||
font.ascent * RESOLUTION / font_prop.size_in_mm);
|
||||
|
||||
float flatness = static_cast<float>(font.infos[font_index].ascent * RESOLUTION / font_prop.size_in_mm);
|
||||
std::optional<Emboss::Glyph> glyph_opt =
|
||||
Private::get_glyph(*font_info_opt, unicode, flatness);
|
||||
|
||||
@ -351,8 +364,9 @@ FontList Emboss::get_font_list_by_register() {
|
||||
// Open Windows font registry key
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, fontRegistryPath, 0, KEY_READ, &hKey);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
std::wcerr << L"Can not Open register key (" << fontRegistryPath << ")"
|
||||
<< L", function 'RegOpenKeyEx' return code: " << result << std::endl;
|
||||
assert(false);
|
||||
//std::wcerr << L"Can not Open register key (" << fontRegistryPath << ")"
|
||||
// << L", function 'RegOpenKeyEx' return code: " << result << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -360,8 +374,8 @@ FontList Emboss::get_font_list_by_register() {
|
||||
result = RegQueryInfoKey(hKey, 0, 0, 0, 0, 0, 0, 0, &maxValueNameSize,
|
||||
&maxValueDataSize, 0, 0);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Can not earn query key, function 'RegQueryInfoKey' return code: "
|
||||
<< result << std::endl;
|
||||
assert(false);
|
||||
// Can not earn query key, function 'RegQueryInfoKey' return code: result
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -475,47 +489,61 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(
|
||||
int collection_size = stbtt_GetNumberOfFonts(data->data());
|
||||
// at least one font must be inside collection
|
||||
if (collection_size < 1) {
|
||||
BOOST_LOG_TRIVIAL(error) << "There is no font collection inside data." << std::endl;
|
||||
assert(false);
|
||||
// There is no font collection inside font data
|
||||
return nullptr;
|
||||
}
|
||||
auto font_info = Private::load_font_info(data->data());
|
||||
if (!font_info.has_value()) return nullptr;
|
||||
|
||||
const stbtt_fontinfo *info = &(*font_info);
|
||||
// load information about line gap
|
||||
int ascent, descent, linegap;
|
||||
stbtt_GetFontVMetrics(info, &ascent, &descent, &linegap);
|
||||
unsigned int c_size = static_cast<unsigned int>(collection_size);
|
||||
std::vector<FontFile::Info> infos;
|
||||
infos.reserve(c_size);
|
||||
for (unsigned int i = 0; i < c_size; ++i) {
|
||||
auto font_info = Private::load_font_info(data->data(), i);
|
||||
if (!font_info.has_value()) return nullptr;
|
||||
|
||||
const stbtt_fontinfo *info = &(*font_info);
|
||||
// load information about line gap
|
||||
int ascent, descent, linegap;
|
||||
stbtt_GetFontVMetrics(info, &ascent, &descent, &linegap);
|
||||
|
||||
float pixels = 1000.; // value is irelevant
|
||||
float em_pixels = stbtt_ScaleForMappingEmToPixels(info, pixels);
|
||||
int units_per_em = static_cast<int>(std::round(pixels / em_pixels));
|
||||
|
||||
infos.emplace_back(FontFile::Info{ascent, descent, linegap, units_per_em});
|
||||
}
|
||||
|
||||
float pixels = 1000.; // value is irelevant
|
||||
float em_pixels = stbtt_ScaleForMappingEmToPixels(info, pixels);
|
||||
int units_per_em = static_cast<int>(std::round(pixels / em_pixels));
|
||||
return std::make_unique<Emboss::FontFile>(
|
||||
std::move(data), collection_size, ascent, descent, linegap, units_per_em);
|
||||
std::move(data), collection_size, std::move(infos));
|
||||
}
|
||||
|
||||
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(const char *file_path)
|
||||
{
|
||||
FILE *file = fopen(file_path, "rb");
|
||||
if (file == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Couldn't open " << file_path << " for reading." << std::endl;
|
||||
assert(false);
|
||||
// BOOST_LOG_TRIVIAL(error) << "Couldn't open " << file_path << " for reading." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// find size of file
|
||||
if (fseek(file, 0L, SEEK_END) != 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Couldn't fseek file " << file_path << " for size measure." << std::endl;
|
||||
assert(false);
|
||||
// BOOST_LOG_TRIVIAL(error) << "Couldn't fseek file " << file_path << " for size measure." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
size_t size = ftell(file);
|
||||
if (size == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Size of font file is zero. Can't read." << std::endl;
|
||||
assert(false);
|
||||
// BOOST_LOG_TRIVIAL(error) << "Size of font file is zero. Can't read." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
rewind(file);
|
||||
auto buffer = std::make_unique<std::vector<unsigned char>>(size);
|
||||
size_t count_loaded_bytes = fread((void *) &buffer->front(), 1, size, file);
|
||||
if (count_loaded_bytes != size) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Different loaded(from file) data size." << std::endl;
|
||||
assert(false);
|
||||
// BOOST_LOG_TRIVIAL(error) << "Different loaded(from file) data size." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
return create_font_file(std::move(buffer));
|
||||
@ -563,7 +591,8 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
|
||||
{
|
||||
HDC hdc = ::CreateCompatibleDC(NULL);
|
||||
if (hdc == NULL) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Can't create HDC by CreateCompatibleDC(NULL)." << std::endl;
|
||||
assert(false);
|
||||
// BOOST_LOG_TRIVIAL(error) << "Can't create HDC by CreateCompatibleDC(NULL)." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -577,7 +606,8 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
|
||||
size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer->data(), size);
|
||||
::DeleteDC(hdc);
|
||||
if (size != loaded_size) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Different loaded(from HFONT) data size." << std::endl;
|
||||
assert(false);
|
||||
// BOOST_LOG_TRIVIAL(error) << "Different loaded(from HFONT) data size." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
return create_font_file(std::move(buffer));
|
||||
@ -585,10 +615,12 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
|
||||
#endif // _WIN32
|
||||
|
||||
std::optional<Emboss::Glyph> Emboss::letter2glyph(const FontFile &font,
|
||||
unsigned int font_index,
|
||||
int letter,
|
||||
float flatness)
|
||||
{
|
||||
auto font_info_opt = Private::load_font_info(font.data->data(), 0);
|
||||
if (!Private::is_valid(font, font_index)) return {};
|
||||
auto font_info_opt = Private::load_font_info(font.data->data(), font_index);
|
||||
if (!font_info_opt.has_value()) return {};
|
||||
return Private::get_glyph(*font_info_opt, letter, flatness);
|
||||
}
|
||||
@ -603,11 +635,15 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
|
||||
Point cursor(0, 0);
|
||||
ExPolygons result;
|
||||
const FontFile& font = *font_with_cache.font_file;
|
||||
unsigned int font_index = font_prop.collection_number.has_value()?
|
||||
*font_prop.collection_number : 0;
|
||||
if (!Private::is_valid(font, font_index)) return {};
|
||||
const FontFile::Info& info = font.infos[font_index];
|
||||
Emboss::Glyphs& cache = *font_with_cache.cache;
|
||||
std::wstring ws = boost::nowide::widen(text);
|
||||
for (wchar_t wc: ws){
|
||||
if (wc == '\n') {
|
||||
int line_height = font.ascent - font.descent + font.linegap;
|
||||
int line_height = info.ascent - info.descent + info.linegap;
|
||||
if (font_prop.line_gap.has_value())
|
||||
line_height += *font_prop.line_gap;
|
||||
line_height = static_cast<int>(line_height / SHAPE_SCALE);
|
||||
@ -693,6 +729,40 @@ bool Emboss::is_italic(const FontFile &font, unsigned int font_index)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Emboss::create_range_text(const std::string &text,
|
||||
const FontFile &font,
|
||||
unsigned int font_index,
|
||||
bool *exist_unknown)
|
||||
{
|
||||
if (!Private::is_valid(font, font_index)) return {};
|
||||
|
||||
std::wstring ws = boost::nowide::widen(text);
|
||||
|
||||
// need remove symbols not contained in font
|
||||
std::sort(ws.begin(), ws.end());
|
||||
|
||||
auto font_info_opt = Private::load_font_info(font.data->data(), 0);
|
||||
if (!font_info_opt.has_value()) return {};
|
||||
const stbtt_fontinfo *font_info = &(*font_info_opt);
|
||||
|
||||
if (exist_unknown != nullptr) *exist_unknown = false;
|
||||
int prev_unicode = -1;
|
||||
ws.erase(std::remove_if(ws.begin(), ws.end(),
|
||||
[&prev_unicode, font_info, exist_unknown](wchar_t wc) -> bool {
|
||||
int unicode = static_cast<int>(wc);
|
||||
// is duplicit
|
||||
if (prev_unicode == unicode) return true;
|
||||
prev_unicode = unicode;
|
||||
bool is_unknown = !stbtt_FindGlyphIndex(font_info, unicode);
|
||||
if (is_unknown && exist_unknown != nullptr)
|
||||
*exist_unknown = true;
|
||||
return is_unknown;
|
||||
}), ws.end());
|
||||
|
||||
return boost::nowide::narrow(ws);
|
||||
}
|
||||
|
||||
|
||||
indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
|
||||
const IProject &projection)
|
||||
{
|
||||
|
@ -71,32 +71,39 @@ public:
|
||||
// count of fonts when data are collection of fonts
|
||||
unsigned int count;
|
||||
|
||||
// vertical position is "scale*(ascent - descent + lineGap)"
|
||||
int ascent, descent, linegap;
|
||||
struct Info
|
||||
{
|
||||
// vertical position is "scale*(ascent - descent + lineGap)"
|
||||
int ascent, descent, linegap;
|
||||
|
||||
// for convert font units to pixel
|
||||
int unit_per_em;
|
||||
// for convert font units to pixel
|
||||
int unit_per_em;
|
||||
};
|
||||
// info for each font in data
|
||||
std::vector<Info> infos;
|
||||
|
||||
FontFile(std::unique_ptr<std::vector<unsigned char>> data,
|
||||
unsigned int count,
|
||||
int ascent,
|
||||
int descent,
|
||||
int linegap,
|
||||
int unit_per_em)
|
||||
unsigned int count,
|
||||
std::vector<Info> &&infos)
|
||||
: data(std::move(data))
|
||||
, count(count)
|
||||
, ascent(ascent)
|
||||
, descent(descent)
|
||||
, linegap(linegap)
|
||||
, unit_per_em(unit_per_em)
|
||||
, infos(std::move(infos))
|
||||
{
|
||||
assert(this->data != nullptr);
|
||||
assert(!this->data->empty());
|
||||
assert(count == this->infos.size());
|
||||
}
|
||||
bool operator==(const FontFile &other) const {
|
||||
return count == other.count && ascent == other.ascent &&
|
||||
descent == other.descent && linegap == other.linegap &&
|
||||
data->size() == other.data->size();
|
||||
//&& *data == *other.data;
|
||||
if (count != other.count || data->size() != other.data->size())
|
||||
return false;
|
||||
//if(*data != *other.data) return false;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (infos[i].ascent != other.infos[i].ascent ||
|
||||
infos[i].descent == other.infos[i].descent ||
|
||||
infos[i].linegap == other.infos[i].linegap)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@ -140,10 +147,11 @@ public:
|
||||
/// convert letter into polygons
|
||||
/// </summary>
|
||||
/// <param name="font">Define fonts</param>
|
||||
/// <param name="font_index">Index of font in collection</param>
|
||||
/// <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 FontFile &font, int letter, float flatness);
|
||||
static std::optional<Glyph> letter2glyph(const FontFile &font, unsigned int font_index, int letter, float flatness);
|
||||
|
||||
/// <summary>
|
||||
/// Convert text into polygons
|
||||
@ -152,9 +160,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(FontFileWithCache &font,
|
||||
const char * text,
|
||||
const FontProp &font_prop);
|
||||
static ExPolygons text2shapes(FontFileWithCache &font, const char *text, const FontProp &font_prop);
|
||||
|
||||
/// <summary>
|
||||
/// Use data from font property to modify transformation
|
||||
@ -162,8 +168,7 @@ public:
|
||||
/// <param name="font_prop">Z-move as surface distance(FontProp::distance)
|
||||
/// Z-rotation as angle to Y axis(FontProp::angle)</param>
|
||||
/// <param name="transformation">In / Out transformation to modify by property</param>
|
||||
static void apply_transformation(const FontProp &font_prop,
|
||||
Transform3d &transformation);
|
||||
static void apply_transformation(const FontProp &font_prop, Transform3d &transformation);
|
||||
|
||||
/// <summary>
|
||||
/// Read information from naming table of font file
|
||||
@ -174,6 +179,16 @@ public:
|
||||
/// <returns>True when the font description contains italic/obligue otherwise False</returns>
|
||||
static bool is_italic(const FontFile &font, unsigned int font_index);
|
||||
|
||||
/// <summary>
|
||||
/// Create unique character set from string with filtered from text with only character from font
|
||||
/// </summary>
|
||||
/// <param name="text">Source vector of glyphs</param>
|
||||
/// <param name="font">Font descriptor</param>
|
||||
/// <param name="font_index">Define font in collection</param>
|
||||
/// <param name="exist_unknown">True when text contain glyph unknown in font</param>
|
||||
/// <returns>Unique set of character from text contained in font</returns>
|
||||
static std::string create_range_text(const std::string &text, const FontFile &font, unsigned int font_index, bool* exist_unknown = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// Project 2d point into space
|
||||
/// Could be plane, sphere, cylindric, ...
|
||||
|
@ -186,10 +186,8 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Moving()) return false;
|
||||
|
||||
m_rotate_gizmo.on_mouse(mouse_event);
|
||||
use_grabbers(mouse_event);
|
||||
|
||||
if (!m_dragging) return false;
|
||||
bool used = use_grabbers(mouse_event);
|
||||
if (!m_dragging) return used;
|
||||
|
||||
assert(m_volume != nullptr);
|
||||
assert(m_volume->text_configuration.has_value());
|
||||
@ -220,14 +218,12 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
||||
if (m_font_manager.is_activ_font()) {
|
||||
m_font_manager.get_font_prop().angle = angle_opt;
|
||||
}
|
||||
return true;
|
||||
} else if (mouse_event.LeftUp()) {
|
||||
// apply rotation
|
||||
m_parent.do_rotate(L("Text-Rotate"));
|
||||
start_angle.reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return used;
|
||||
}
|
||||
|
||||
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
||||
@ -515,6 +511,7 @@ void GLGizmoEmboss::on_stop_dragging()
|
||||
// When fixing, move grabber above text (not on side)
|
||||
m_rotate_gizmo.set_angle(0);
|
||||
}
|
||||
void GLGizmoEmboss::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(data); }
|
||||
|
||||
void GLGizmoEmboss::initialize()
|
||||
{
|
||||
@ -768,6 +765,24 @@ ModelVolume *GLGizmoEmboss::get_selected_volume(const Selection &selection,
|
||||
return get_model_volume(vol_gl, objects);
|
||||
}
|
||||
|
||||
static inline void execute_job(std::shared_ptr<Job> j)
|
||||
{
|
||||
struct MyCtl : public Job::Ctl
|
||||
{
|
||||
void update_status(int st, const std::string &msg = "") override{};
|
||||
bool was_canceled() const override { return false; }
|
||||
std::future<void> call_on_main_thread(std::function<void()> fn) override
|
||||
{
|
||||
return std::future<void>{};
|
||||
}
|
||||
} ctl;
|
||||
j->process(ctl);
|
||||
wxGetApp().plater()->CallAfter([j]() {
|
||||
std::exception_ptr e_ptr = nullptr;
|
||||
j->finalize(false, e_ptr);
|
||||
});
|
||||
}
|
||||
|
||||
bool GLGizmoEmboss::process()
|
||||
{
|
||||
// no volume is selected -> selection from right panel
|
||||
@ -795,17 +810,8 @@ bool GLGizmoEmboss::process()
|
||||
//*
|
||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||
queue_job(worker, std::make_unique<EmbossUpdateJob>(std::move(data)));
|
||||
/*/
|
||||
// Run Job on main thread (blocking)
|
||||
EmbossUpdateJob j(std::move(data));
|
||||
struct MyCtl:public Job::Ctl{
|
||||
void update_status(int st, const std::string &msg = "") override{};
|
||||
bool was_canceled() const override { return false; }
|
||||
std::future<void> call_on_main_thread(std::function<void()> fn) override{return std::future<void>{};}
|
||||
} ctl;
|
||||
j.process(ctl);
|
||||
std::exception_ptr e_ptr = nullptr;
|
||||
j.finalize(false, e_ptr);
|
||||
/*/ // Run Job on main thread (blocking) - ONLY DEBUG
|
||||
execute_job(std::make_shared<EmbossUpdateJob>(std::move(data)));
|
||||
// */
|
||||
|
||||
// notification is removed befor object is changed by job
|
||||
@ -932,15 +938,28 @@ void GLGizmoEmboss::draw_window()
|
||||
|
||||
void GLGizmoEmboss::draw_text_input()
|
||||
{
|
||||
auto create_range_text = [&manager = m_font_manager, &text = m_text, &exist_unknown = m_text_contain_unknown_glyph]() {
|
||||
auto &font_file = manager.get_font_file();
|
||||
const auto &cn = manager.get_font_prop().collection_number;
|
||||
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
||||
return Emboss::create_range_text(text, *font_file, font_index, &exist_unknown);
|
||||
};
|
||||
|
||||
static const ImGuiInputTextFlags flags =
|
||||
ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_AutoSelectAll;
|
||||
|
||||
ImFont *imgui_font = (m_font_manager.is_activ_font())?
|
||||
m_font_manager.get_imgui_font(m_text) : nullptr;
|
||||
bool exist_font = imgui_font != nullptr && imgui_font->IsLoaded();
|
||||
ImFont *imgui_font = m_font_manager.get_imgui_font();
|
||||
if (imgui_font == nullptr) {
|
||||
// try create new imgui font
|
||||
imgui_font = m_font_manager.create_imgui_font(create_range_text());
|
||||
}
|
||||
bool exist_font = imgui_font != nullptr;
|
||||
assert(!exist_font || imgui_font->IsLoaded());
|
||||
if (exist_font) ImGui::PushFont(imgui_font);
|
||||
|
||||
bool exist_change = false;
|
||||
// flag for extend font ranges if neccessary
|
||||
// ranges can't be extend during font is activ(pushed)
|
||||
std::string range_text;
|
||||
float window_height = ImGui::GetWindowHeight();
|
||||
float minimal_height = get_minimal_window_size().y;
|
||||
float extra_height = window_height - minimal_height;
|
||||
@ -948,7 +967,7 @@ void GLGizmoEmboss::draw_text_input()
|
||||
m_gui_cfg->text_size.y + extra_height);
|
||||
if (ImGui::InputTextMultiline("##Text", &m_text, text_size, flags)) {
|
||||
process();
|
||||
exist_change = true;
|
||||
range_text = create_range_text();
|
||||
}
|
||||
|
||||
if (exist_font) ImGui::PopFont();
|
||||
@ -971,34 +990,34 @@ void GLGizmoEmboss::draw_text_input()
|
||||
tool_tip += t;
|
||||
}
|
||||
};
|
||||
if (m_text_contain_unknown_glyph)
|
||||
append_warning(_u8L("Bad symbol"),
|
||||
_u8L("Text contain character glyph (represented by '?') unknown by font."));
|
||||
|
||||
const FontProp &prop = m_font_manager.get_font_prop();
|
||||
if (prop.skew.has_value()) {
|
||||
if (prop.skew.has_value())
|
||||
append_warning(_u8L("Skew"),
|
||||
_u8L("Unsupported visualization of font skew for text input."));
|
||||
}
|
||||
if (prop.boldness.has_value()) {
|
||||
if (prop.boldness.has_value())
|
||||
append_warning(_u8L("Boldness"),
|
||||
_u8L("Unsupported visualization of font boldness for text input."));
|
||||
}
|
||||
if (prop.line_gap.has_value()) {
|
||||
if (prop.line_gap.has_value())
|
||||
append_warning(_u8L("Line gap"),
|
||||
_u8L("Unsupported visualization of gap between lines inside text input."));
|
||||
}
|
||||
float imgui_size = FontManager::get_imgui_font_size(prop, *m_font_manager.get_font_file());
|
||||
if (imgui_size > FontManager::max_imgui_font_size) {
|
||||
if (imgui_size > FontManager::max_imgui_font_size)
|
||||
append_warning(_u8L("To tall"),
|
||||
_u8L("Diminished font height inside text input."));
|
||||
}
|
||||
if (imgui_size < FontManager::min_imgui_font_size) {
|
||||
if (imgui_size < FontManager::min_imgui_font_size)
|
||||
append_warning(_u8L("To small"),
|
||||
_u8L("Enlarged font height inside text input."));
|
||||
}
|
||||
if (!who.empty()) {
|
||||
if (!who.empty())
|
||||
warning = GUI::format(_u8L("%1% is NOT shown."), who);
|
||||
}
|
||||
}
|
||||
|
||||
if (!warning.empty()) {
|
||||
if (ImGui::IsItemHovered() && !tool_tip.empty())
|
||||
ImGui::SetTooltip("%s", tool_tip.c_str());
|
||||
ImVec2 cursor = ImGui::GetCursorPos();
|
||||
float width = ImGui::GetContentRegionAvailWidth();
|
||||
ImVec2 size = ImGui::CalcTextSize(warning.c_str());
|
||||
@ -1006,14 +1025,17 @@ void GLGizmoEmboss::draw_text_input()
|
||||
ImGui::SetCursorPos(ImVec2(width - size.x + padding.x,
|
||||
cursor.y - size.y - padding.y));
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, warning);
|
||||
if (ImGui::IsItemHovered() && !tool_tip.empty())
|
||||
ImGui::SetTooltip("%s", tool_tip.c_str());
|
||||
ImGui::SetCursorPos(cursor);
|
||||
}
|
||||
|
||||
// IMPROVE: only extend not clear
|
||||
// Extend font ranges
|
||||
// imgui_font has to be unused
|
||||
if (exist_change) m_font_manager.clear_imgui_font();
|
||||
if (!range_text.empty() &&
|
||||
!m_imgui->contain_all_glyphs(imgui_font, range_text) ) {
|
||||
m_font_manager.clear_imgui_font();
|
||||
m_font_manager.create_imgui_font(range_text);
|
||||
}
|
||||
}
|
||||
|
||||
//#define DEBUG_NOT_LOADABLE_FONTS
|
||||
@ -1057,8 +1079,8 @@ protected:
|
||||
/*/
|
||||
// Slow copy of font files to try load font
|
||||
// After this all files are loadable
|
||||
auto ff = WxFontUtils::create_font_file(wx_font);
|
||||
if (ff == nullptr) {
|
||||
auto font_file = WxFontUtils::create_font_file(wx_font);
|
||||
if (font_file == nullptr) {
|
||||
#ifdef DEBUG_NOT_LOADABLE_FONTS
|
||||
m_efacenames.emplace_back(facename.c_str());
|
||||
#endif // DEBUG_NOT_LOADABLE_FONTS
|
||||
@ -1802,16 +1824,19 @@ void GLGizmoEmboss::draw_advanced()
|
||||
}
|
||||
|
||||
FontProp &font_prop = m_font_manager.get_font_item().prop;
|
||||
const auto &cn = m_font_manager.get_font_prop().collection_number;
|
||||
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
||||
const auto &font_info = font_file->infos[font_index];
|
||||
|
||||
#ifdef SHOW_FONT_FILE_PROPERTY
|
||||
ImGui::SameLine();
|
||||
auto& ff = m_font_manager.get_font().font_file_with_cache;
|
||||
int cache_size = ff.has_value()? (int)ff.cache->size() : 0;
|
||||
std::string ff_property =
|
||||
"ascent=" + std::to_string(font_file->ascent) +
|
||||
", descent=" + std::to_string(font_file->descent) +
|
||||
", lineGap=" + std::to_string(font_file->linegap) +
|
||||
", unitPerEm=" + std::to_string(font_file->unit_per_em) +
|
||||
"ascent=" + std::to_string(font_info.ascent) +
|
||||
", descent=" + std::to_string(font_info.descent) +
|
||||
", lineGap=" + std::to_string(font_info.linegap) +
|
||||
", unitPerEm=" + std::to_string(font_info.unit_per_em) +
|
||||
", cache(" + std::to_string(cache_size) + " glyphs)";
|
||||
if (font_file->count > 1) {
|
||||
unsigned int collection = font_prop.collection_number.has_value() ?
|
||||
@ -1830,8 +1855,9 @@ void GLGizmoEmboss::draw_advanced()
|
||||
// input gap between letters
|
||||
auto def_char_gap = m_stored_font_item.has_value() ?
|
||||
&m_stored_font_item->prop.char_gap : nullptr;
|
||||
int min_char_gap = -font_file->ascent / 2,
|
||||
max_char_gap = font_file->ascent / 2;
|
||||
|
||||
int half_ascent = font_info.ascent / 2;
|
||||
int min_char_gap = -half_ascent, max_char_gap = half_ascent;
|
||||
if (rev_slider(tr.char_gap, font_prop.char_gap, def_char_gap, _u8L("Revert gap between letters"),
|
||||
min_char_gap, max_char_gap, units_fmt, _L("Distance between letters"))){
|
||||
// char gap is stored inside of imgui font atlas
|
||||
@ -1842,8 +1868,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
// input gap between lines
|
||||
auto def_line_gap = m_stored_font_item.has_value() ?
|
||||
&m_stored_font_item->prop.line_gap : nullptr;
|
||||
int min_line_gap = -font_file->ascent / 2,
|
||||
max_line_gap = font_file->ascent / 2;
|
||||
int min_line_gap = -half_ascent, max_line_gap = half_ascent;
|
||||
if (rev_slider(tr.line_gap, font_prop.line_gap, def_line_gap, _u8L("Revert gap between lines"),
|
||||
min_line_gap, max_line_gap, units_fmt, _L("Distance between lines"))){
|
||||
// char gap is stored inside of imgui font atlas
|
||||
|
@ -65,6 +65,7 @@ protected:
|
||||
void on_disable_grabber(unsigned int id) override { m_rotate_gizmo.disable_grabber(); }
|
||||
void on_start_dragging() override;
|
||||
void on_stop_dragging() override;
|
||||
void on_dragging(const UpdateData &data) override;
|
||||
|
||||
/// <summary>
|
||||
/// Rotate by text on dragging rotate grabers
|
||||
@ -217,7 +218,10 @@ private:
|
||||
void fill_stored_font_items();
|
||||
void select_stored_font_item();
|
||||
|
||||
// Text to emboss
|
||||
std::string m_text;
|
||||
// True when m_text contain character unknown by selected font
|
||||
bool m_text_contain_unknown_glyph = false;
|
||||
|
||||
// cancel for previous update of volume to cancel finalize part
|
||||
std::shared_ptr<std::atomic<bool>> m_update_job_cancel;
|
||||
|
@ -1460,6 +1460,44 @@ void ImGuiWrapper::draw(
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::contain_all_glyphs(const ImFont *font,
|
||||
const std::string &text)
|
||||
{
|
||||
if (font == nullptr) return false;
|
||||
if (!font->IsLoaded()) return false;
|
||||
const ImFontConfig *fc = font->ConfigData;
|
||||
if (fc == nullptr) return false;
|
||||
if (text.empty()) return true;
|
||||
return is_chars_in_ranges(fc->GlyphRanges, text.c_str());
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::is_char_in_ranges(const ImWchar *ranges,
|
||||
unsigned int letter)
|
||||
{
|
||||
for (const ImWchar *range = ranges; range[0] && range[1]; range += 2) {
|
||||
ImWchar from = range[0];
|
||||
ImWchar to = range[1];
|
||||
if (from <= letter && letter <= to) return true;
|
||||
if (letter < to) return false; // ranges should be sorted
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
bool ImGuiWrapper::is_chars_in_ranges(const ImWchar *ranges,
|
||||
const char *chars_ptr)
|
||||
{
|
||||
while (*chars_ptr) {
|
||||
unsigned int c = 0;
|
||||
// UTF-8 to 32-bit character need imgui_internal
|
||||
int c_len = ImTextCharFromUtf8(&c, chars_ptr, NULL);
|
||||
chars_ptr += c_len;
|
||||
if (c_len == 0) break;
|
||||
if (!is_char_in_ranges(ranges, c)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
static const ImWchar ranges_keyboard_shortcuts[] =
|
||||
{
|
||||
|
@ -194,6 +194,17 @@ public:
|
||||
ImU32 color = ImGui::GetColorU32(COL_ORANGE_LIGHT),
|
||||
float thickness = 3.f);
|
||||
|
||||
/// <summary>
|
||||
/// Check that font ranges contain all chars in string
|
||||
/// (rendered Unicodes are stored in GlyphRanges)
|
||||
/// </summary>
|
||||
/// <param name="font">Contain glyph ranges</param>
|
||||
/// <param name="text">Vector of character to check</param>
|
||||
/// <returns>True when all glyphs from text are in font ranges</returns>
|
||||
static bool contain_all_glyphs(const ImFont *font, const std::string &text);
|
||||
static bool is_chars_in_ranges(const ImWchar *ranges, const char *chars_ptr);
|
||||
static bool is_char_in_ranges(const ImWchar *ranges, unsigned int letter);
|
||||
|
||||
bool requires_extra_frame() const { return m_requires_extra_frame; }
|
||||
void set_requires_extra_frame() { m_requires_extra_frame = true; }
|
||||
void reset_requires_extra_frame() { m_requires_extra_frame = false; }
|
||||
|
@ -46,7 +46,9 @@ void CreateFontStyleImagesJob::process(Ctl &ctl)
|
||||
// dot per inch for monitor
|
||||
int dpi = get_dpi_for_window(mf);
|
||||
double ppm = dpi / 25.4; // pixel per milimeter
|
||||
double unit_per_em = item.font.font_file->unit_per_em;
|
||||
const auto &cn = item.prop.collection_number;
|
||||
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
||||
double unit_per_em = item.font.font_file->infos[font_index].unit_per_em;
|
||||
double scale = item.prop.size_in_mm / unit_per_em * Emboss::SHAPE_SCALE * ppm;
|
||||
scales[index] = scale;
|
||||
|
||||
|
@ -312,7 +312,9 @@ TriangleMesh priv::create_mesh(const char *text,
|
||||
if (shapes.empty()) return {};
|
||||
if (was_canceled()) return {};
|
||||
|
||||
int unit_per_em = font.font_file->unit_per_em;
|
||||
const auto &cn = font_prop.collection_number;
|
||||
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
||||
int unit_per_em = font.font_file->infos[font_index].unit_per_em;
|
||||
float scale = font_prop.size_in_mm / unit_per_em;
|
||||
float depth = font_prop.emboss / scale;
|
||||
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "slic3r/GUI/3DScene.hpp" // ::glsafe
|
||||
#include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp" // check of font ranges
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::GUI;
|
||||
@ -224,39 +225,40 @@ void FontManager::clear_imgui_font() {
|
||||
if (!is_activ_font()) return;
|
||||
free_imgui_fonts();
|
||||
return;
|
||||
|
||||
ImFont *imgui_font = get_imgui_font(m_font_selected);
|
||||
m_font_list[m_font_selected].imgui_font_index.reset();
|
||||
if (imgui_font != nullptr) IM_DELETE(imgui_font);
|
||||
}
|
||||
|
||||
ImFont *FontManager::get_imgui_font(const std::string &text)
|
||||
ImFont *FontManager::get_imgui_font()
|
||||
{
|
||||
if (!is_activ_font()) return nullptr;
|
||||
return get_imgui_font(m_font_selected, text);
|
||||
return get_imgui_font(m_font_selected);
|
||||
}
|
||||
|
||||
ImFont *FontManager::get_imgui_font(size_t item_index, const std::string &text)
|
||||
ImFont *FontManager::create_imgui_font(const std::string &text)
|
||||
{
|
||||
return create_imgui_font(m_font_selected, text);
|
||||
}
|
||||
|
||||
ImFont *FontManager::get_imgui_font(size_t item_index)
|
||||
{
|
||||
if (!is_activ_font()) return nullptr;
|
||||
Item &item = m_font_list[item_index];
|
||||
// check is already loaded
|
||||
if (!item.imgui_font_index.has_value())
|
||||
return load_imgui_font(item_index, text);
|
||||
if (!item.imgui_font_index.has_value()) return nullptr;
|
||||
|
||||
size_t index = *item.imgui_font_index;
|
||||
auto & fonts = m_imgui_font_atlas.Fonts;
|
||||
size_t index = *item.imgui_font_index;
|
||||
ImVector<ImFont *> &fonts = m_imgui_font_atlas.Fonts;
|
||||
|
||||
// check correct index
|
||||
int f_size = fonts.size();
|
||||
assert(f_size > 0 && index < (size_t)f_size);
|
||||
assert(f_size > 0 && index < (size_t) f_size);
|
||||
if (f_size <= 0 || index >= (size_t) f_size) return nullptr;
|
||||
ImFont *font = fonts[index];
|
||||
if (font == nullptr) return nullptr;
|
||||
if (!font->IsLoaded()) return nullptr;
|
||||
if (font->Scale <= 0.f) return nullptr;
|
||||
// automatic extend range
|
||||
if (!text.empty() && !is_text_in_ranges(font, text))
|
||||
return extend_imgui_font_range(item_index, text);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
@ -327,51 +329,17 @@ bool FontManager::set_up_font_file(size_t item_index)
|
||||
return set_wx_font(item_index, *item.wx_font);
|
||||
}
|
||||
|
||||
bool FontManager::is_text_in_ranges(const ImFont *font, const std::string &text)
|
||||
{
|
||||
if (font == nullptr) return false;
|
||||
if (!font->IsLoaded()) return false;
|
||||
const ImFontConfig *fc = font->ConfigData;
|
||||
if (fc == nullptr) return false;
|
||||
return is_text_in_ranges(fc->GlyphRanges, text);
|
||||
}
|
||||
|
||||
bool FontManager::is_char_in_ranges(const ImWchar *ranges, unsigned int letter)
|
||||
{
|
||||
for (const ImWchar *range = ranges; range[0] && range[1]; range += 2) {
|
||||
ImWchar from = range[0];
|
||||
ImWchar to = range[1];
|
||||
if (from <= letter && letter <= to) return true;
|
||||
if (letter < to) return false; // ranges should be sorted
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
bool FontManager::is_text_in_ranges(const ImWchar *ranges, const std::string &text)
|
||||
{
|
||||
const char *text_char_ptr = text.c_str();
|
||||
while (*text_char_ptr) {
|
||||
unsigned int c = 0;
|
||||
// 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_char_in_ranges(ranges, c)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ImFont* FontManager::extend_imgui_font_range(size_t index, const std::string& text)
|
||||
{
|
||||
auto &font_index_opt = m_font_list[m_font_selected].imgui_font_index;
|
||||
if (!font_index_opt.has_value())
|
||||
return load_imgui_font(index, text);
|
||||
return create_imgui_font(index, text);
|
||||
|
||||
// TODO: start using merge mode
|
||||
// ImFontConfig::MergeMode = true;
|
||||
|
||||
free_imgui_fonts();
|
||||
return load_imgui_font(index, text);
|
||||
return create_imgui_font(index, text);
|
||||
}
|
||||
|
||||
#include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp"
|
||||
@ -460,15 +428,19 @@ float FontManager::max_imgui_font_size = 60.f;
|
||||
float FontManager::get_imgui_font_size(const FontProp &prop,
|
||||
const Emboss::FontFile &file)
|
||||
{
|
||||
const auto &cn = prop.collection_number;
|
||||
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
||||
const auto &font_info = file.infos[font_index];
|
||||
// coeficient for convert line height to font size
|
||||
float c1 = (file.ascent - file.descent + file.linegap) / (float) file.unit_per_em;
|
||||
float c1 = (font_info.ascent - font_info.descent + font_info.linegap) /
|
||||
(float) font_info.unit_per_em;
|
||||
|
||||
// The point size is defined as 1/72 of the Anglo-Saxon inch (25.4 mm):
|
||||
// It is approximately 0.0139 inch or 352.8 um.
|
||||
return c1 * std::abs(prop.size_in_mm) / 0.3528f;
|
||||
}
|
||||
|
||||
ImFont * FontManager::load_imgui_font(size_t index, const std::string &text)
|
||||
ImFont *FontManager::create_imgui_font(size_t index, const std::string &text)
|
||||
{
|
||||
free_imgui_fonts(); // TODO: remove it after correct initialization
|
||||
|
||||
@ -499,19 +471,23 @@ ImFont * FontManager::load_imgui_font(size_t index, const std::string &text)
|
||||
ImFontConfig font_config;
|
||||
// TODO: start using merge mode
|
||||
//font_config.MergeMode = true;
|
||||
|
||||
const auto &cn = font_prop.collection_number;
|
||||
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
||||
const auto &font_info = font_file.infos[font_index];
|
||||
if (font_prop.char_gap.has_value()) {
|
||||
float coef = font_size / (double) font_file.unit_per_em;
|
||||
float coef = font_size / (double) font_info.unit_per_em;
|
||||
font_config.GlyphExtraSpacing.x = coef * (*font_prop.char_gap);
|
||||
}
|
||||
if (font_prop.line_gap.has_value()) {
|
||||
float coef = font_size / (double) font_file.unit_per_em;
|
||||
float coef = font_size / (double) font_info.unit_per_em;
|
||||
font_config.GlyphExtraSpacing.y = coef * (*font_prop.line_gap);
|
||||
}
|
||||
|
||||
font_config.FontDataOwnedByAtlas = false;
|
||||
|
||||
const std::vector<unsigned char> &buffer = *font_file.data;
|
||||
m_imgui_font_atlas.AddFontFromMemoryTTF(
|
||||
ImFont * font = m_imgui_font_atlas.AddFontFromMemoryTTF(
|
||||
(void *) buffer.data(), buffer.size(), font_size, &font_config, item.font_ranges.Data);
|
||||
|
||||
unsigned char *pixels;
|
||||
@ -538,8 +514,10 @@ ImFont * FontManager::load_imgui_font(size_t index, const std::string &text)
|
||||
m_imgui_font_atlas.TexID = (ImTextureID) (intptr_t) font_texture;
|
||||
assert(!m_imgui_font_atlas.Fonts.empty());
|
||||
if (m_imgui_font_atlas.Fonts.empty()) return nullptr;
|
||||
assert(font == m_imgui_font_atlas.Fonts.back());
|
||||
item.imgui_font_index = m_imgui_font_atlas.Fonts.size() - 1;
|
||||
return m_imgui_font_atlas.Fonts.back();
|
||||
assert(font->IsLoaded());
|
||||
return font;
|
||||
}
|
||||
|
||||
bool FontManager::set_wx_font(size_t item_index, const wxFont &wx_font) {
|
||||
|
@ -99,7 +99,9 @@ public:
|
||||
// Getter on acitve font pointer for imgui
|
||||
// Initialize imgui font(generate texture) when doesn't exist yet.
|
||||
// Extend font atlas when not in glyph range
|
||||
ImFont *get_imgui_font(const std::string &text);
|
||||
ImFont *get_imgui_font();
|
||||
// initialize font range by unique symbols in text
|
||||
ImFont *create_imgui_font(const std::string& text);
|
||||
|
||||
// free used memory and font file data
|
||||
void free_except_active_font();
|
||||
@ -166,7 +168,7 @@ private:
|
||||
|
||||
void duplicate(size_t index);
|
||||
// load actual selected font
|
||||
ImFont *load_imgui_font(size_t index, const std::string &text);
|
||||
ImFont *create_imgui_font(size_t index, const std::string &text);
|
||||
|
||||
bool load_active_font();
|
||||
|
||||
@ -174,18 +176,13 @@ private:
|
||||
|
||||
// getter on index selected font pointer for imgui
|
||||
// text could extend font atlas when not in glyph range
|
||||
ImFont *get_imgui_font(size_t item_index, const std::string &text = "");
|
||||
ImFont *get_imgui_font(size_t item_index);
|
||||
|
||||
// extend actual imgui font when exist unknown char in text
|
||||
// NOTE: imgui_font has to be unused
|
||||
// return true when extend range otherwise FALSE
|
||||
ImFont *extend_imgui_font_range(size_t font_index, const std::string &text);
|
||||
|
||||
// Move to imgui utils
|
||||
static bool is_text_in_ranges(const ImFont *font, const std::string &text);
|
||||
static bool is_text_in_ranges(const ImWchar *ranges, const std::string &text);
|
||||
static bool is_char_in_ranges(const ImWchar *ranges, unsigned int letter);
|
||||
|
||||
void free_imgui_fonts();
|
||||
|
||||
bool set_up_font_file(size_t item_index);
|
||||
|
@ -136,13 +136,15 @@ TEST_CASE("Read glyph C shape from font, stb library calls ONLY", "[Emboss]") {
|
||||
TEST_CASE("Convert glyph % to model", "[Emboss]")
|
||||
{
|
||||
std::string font_path = get_font_filepath();
|
||||
unsigned int font_index = 0; // collection
|
||||
char letter = '%';
|
||||
float flatness = 2.;
|
||||
|
||||
auto font = Emboss::create_font_file(font_path.c_str());
|
||||
REQUIRE(font != nullptr);
|
||||
|
||||
std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font, letter, flatness);
|
||||
std::optional<Emboss::Glyph> glyph =
|
||||
Emboss::letter2glyph(*font, font_index, letter, flatness);
|
||||
REQUIRE(glyph.has_value());
|
||||
|
||||
ExPolygons shape = glyph->shape;
|
||||
@ -301,12 +303,13 @@ TEST_CASE("Cut surface", "[]")
|
||||
std::string font_path = get_font_filepath();
|
||||
char letter = '%';
|
||||
float flatness = 2.;
|
||||
unsigned int font_index = 0; // collection
|
||||
|
||||
auto font = Emboss::create_font_file(font_path.c_str());
|
||||
REQUIRE(font != nullptr);
|
||||
|
||||
std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font, letter,
|
||||
flatness);
|
||||
std::optional<Emboss::Glyph> glyph =
|
||||
Emboss::letter2glyph(*font, font_index, letter, flatness);
|
||||
REQUIRE(glyph.has_value());
|
||||
|
||||
ExPolygons shape = glyph->shape;
|
||||
@ -586,14 +589,15 @@ using MyMesh = Slic3r::MeshBoolean::cgal2::CGALMesh;
|
||||
TEST_CASE("Emboss extrude cut", "[Emboss-Cut]")
|
||||
{
|
||||
std::string font_path = get_font_filepath();
|
||||
unsigned int font_index = 0; // collection
|
||||
char letter = '%';
|
||||
float flatness = 2.;
|
||||
|
||||
auto font = Emboss::create_font_file(font_path.c_str());
|
||||
REQUIRE(font != nullptr);
|
||||
|
||||
std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font, letter,
|
||||
flatness);
|
||||
std::optional<Emboss::Glyph> glyph =
|
||||
Emboss::letter2glyph(*font, font_index, letter, flatness);
|
||||
REQUIRE(glyph.has_value());
|
||||
|
||||
ExPolygons shape = glyph->shape;
|
||||
|
Loading…
Reference in New Issue
Block a user