Add editing of text volume

This commit is contained in:
Filip Sykala 2021-09-15 15:14:04 +02:00
parent 8226f74413
commit 8add695de9
7 changed files with 440 additions and 131 deletions

View File

@ -206,6 +206,7 @@ add_library(libslic3r STATIC
Technologies.hpp Technologies.hpp
Tesselate.cpp Tesselate.cpp
Tesselate.hpp Tesselate.hpp
TextConfiguration.hpp
TriangleMesh.cpp TriangleMesh.cpp
TriangleMesh.hpp TriangleMesh.hpp
TriangleMeshSlicer.cpp TriangleMeshSlicer.cpp

View File

@ -10,18 +10,6 @@
using namespace Slic3r; using namespace Slic3r;
Emboss::FontItem::FontItem(const std::string &name, const std::string &path)
: name(name), path(path), type(Type::file_path)
{}
Emboss::FontItem::FontItem(const std::string &name, const std::string &path, Type type)
: name(name), path(path), type(type)
{}
Emboss::FontItem::FontItem(const std::wstring &name, const std::wstring &path)
: name(boost::nowide::narrow(name.c_str()))
, path(boost::nowide::narrow(path.c_str()))
, type(Type::file_path)
{}
// do not expose out of this file stbtt_ data types // do not expose out of this file stbtt_ data types
class Privat class Privat
{ {
@ -30,6 +18,9 @@ public:
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::Font &font); static std::optional<stbtt_fontinfo> load_font_info(const Emboss::Font &font);
static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness = 2.f); static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness = 2.f);
static FontItem create_font_item(std::wstring name, std::wstring path);
}; };
std::optional<stbtt_fontinfo> Privat::load_font_info(const Emboss::Font &font) std::optional<stbtt_fontinfo> Privat::load_font_info(const Emboss::Font &font)
@ -103,6 +94,11 @@ std::optional<Emboss::Glyph> Privat::get_glyph(stbtt_fontinfo &font_info, int un
return glyph; return glyph;
} }
FontItem Privat::create_font_item(std::wstring name, std::wstring path) {
return FontItem(boost::nowide::narrow(name.c_str()),
boost::nowide::narrow(path.c_str()));
}
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <wingdi.h> #include <wingdi.h>
@ -238,15 +234,14 @@ void get_OS_font()
} }
Emboss::FontList Emboss::get_font_list() FontList Emboss::get_font_list()
{ {
//auto a = get_font_path(L"none"); //auto a = get_font_path(L"none");
get_OS_font(); //get_OS_font();
//choose_font_dlg(); //choose_font_dlg();
//FontList list1 = get_font_list_by_enumeration(); //FontList list1 = get_font_list_by_enumeration();
//FontList list2 = get_font_list_by_register(); //FontList list2 = get_font_list_by_register();
//FontList list3 = get_font_list_by_folder(); //FontList list3 = get_font_list_by_folder();
return get_font_list_by_register(); return get_font_list_by_register();
} }
@ -260,7 +255,7 @@ bool exists_file(const std::wstring &name)
} }
} }
Emboss::FontList Emboss::get_font_list_by_register() { FontList Emboss::get_font_list_by_register() {
static const LPWSTR fontRegistryPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; static const LPWSTR fontRegistryPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
HKEY hKey; HKEY hKey;
LONG result; LONG result;
@ -310,7 +305,7 @@ Emboss::FontList Emboss::get_font_list_by_register() {
if (pos >= font_name_w.size()) continue; if (pos >= font_name_w.size()) continue;
// remove TrueType text from name // remove TrueType text from name
font_name_w = std::wstring(font_name_w, 0, pos); font_name_w = std::wstring(font_name_w, 0, pos);
font_list.emplace_back(font_name_w, path_w); font_list.emplace_back(Privat::create_font_item(font_name_w, path_w));
} while (result != ERROR_NO_MORE_ITEMS); } while (result != ERROR_NO_MORE_ITEMS);
delete[] font_name; delete[] font_name;
delete[] fileTTF_name; delete[] fileTTF_name;
@ -336,7 +331,7 @@ bool CALLBACK EnumFamCallBack(LPLOGFONT lplf,
UNREFERENCED_PARAMETER(lpntm); UNREFERENCED_PARAMETER(lpntm);
} }
Emboss::FontList Emboss::get_font_list_by_enumeration() { FontList Emboss::get_font_list_by_enumeration() {
HDC hDC = GetDC(NULL); HDC hDC = GetDC(NULL);
std::vector<std::wstring> font_names; std::vector<std::wstring> font_names;
@ -345,12 +340,12 @@ Emboss::FontList Emboss::get_font_list_by_enumeration() {
FontList font_list; FontList font_list;
for (const std::wstring &font_name : font_names) { for (const std::wstring &font_name : font_names) {
font_list.emplace_back(font_name, L""); font_list.emplace_back(Privat::create_font_item(font_name, L""));
} }
return font_list; return font_list;
} }
Emboss::FontList Emboss::get_font_list_by_folder() { FontList Emboss::get_font_list_by_folder() {
FontList result; FontList result;
WCHAR winDir[MAX_PATH]; WCHAR winDir[MAX_PATH];
UINT winDir_size = GetWindowsDirectory(winDir, MAX_PATH); UINT winDir_size = GetWindowsDirectory(winDir, MAX_PATH);
@ -367,7 +362,7 @@ Emboss::FontList Emboss::get_font_list_by_folder() {
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
std::wstring file_name(fd.cFileName); std::wstring file_name(fd.cFileName);
// TODO: find font name instead of filename // TODO: find font name instead of filename
result.emplace_back(file_name, search_dir + file_name); result.emplace_back(Privat::create_font_item(file_name, search_dir + file_name));
} while (::FindNextFile(hFind, &fd)); } while (::FindNextFile(hFind, &fd));
::FindClose(hFind); ::FindClose(hFind);
} }

View File

@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include <admesh/stl.h> // indexed_triangle_set #include <admesh/stl.h> // indexed_triangle_set
#include "Polygon.hpp" #include "Polygon.hpp"
#include "TextConfiguration.hpp"
namespace Slic3r { namespace Slic3r {
@ -19,28 +20,10 @@ class Emboss
public: public:
Emboss() = delete; Emboss() = delete;
struct FontItem
{
std::string name;
std::string path;
enum class Type;
Type type;
FontItem(const std::string &name, const std::string &path);
FontItem(const std::string &name, const std::string &path, Type type);
FontItem(const std::wstring &name, const std::wstring &path);
// way of load font described in path string
enum class Type {
file_path, // path is file loacation on computer - no move between computers
wx_font_descr // path is font descriptor generated by wxWidgets - limits for os/language move
};
};
using FontList = std::vector<FontItem>;
/// <summary> /// <summary>
/// Collect fonts registred inside OS /// Collect fonts registred inside OS
/// </summary> /// </summary>
/// <returns>OS resistred TTF font files(full path) with names</returns> /// <returns>OS registred TTF font files(full path) with names</returns>
static FontList get_font_list(); static FontList get_font_list();
#ifdef _WIN32 #ifdef _WIN32
static FontList get_font_list_by_register(); static FontList get_font_list_by_register();
@ -55,24 +38,6 @@ public:
/// <returns>File path to font when found</returns> /// <returns>File path to font when found</returns>
static std::optional<std::wstring> get_font_path(const std::wstring &font_face_name); static std::optional<std::wstring> get_font_path(const std::wstring &font_face_name);
// user defined font property
struct FontProp
{
// define extra space between letters, negative mean closer letter
int char_gap = 0;
// define extra space between lines, negative mean closer lines
int line_gap = 0;
// Precision of lettter outline curve in conversion to lines
float flatness = 2.0;
// Height of letter [in mm]
float size_in_mm = 10;
// Z depth of text [in mm]
float emboss = 5;
// TODO: add enum class Align: center/left/right
FontProp() = default;
};
// description of one letter // description of one letter
struct Glyph struct Glyph
{ {
@ -185,7 +150,7 @@ public:
return std::make_pair(res.first * m_scale, res.second * m_scale); return std::make_pair(res.first * m_scale, res.second * m_scale);
} }
float m_scale; float m_scale;
}; };
}; };

View File

@ -14,12 +14,14 @@
#include "Arrange.hpp" #include "Arrange.hpp"
#include "CustomGCode.hpp" #include "CustomGCode.hpp"
#include "enum_bitmask.hpp" #include "enum_bitmask.hpp"
#include "TextConfiguration.hpp"
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <optional>
namespace cereal { namespace cereal {
class BinaryInputArchive; class BinaryInputArchive;
@ -636,6 +638,10 @@ public:
// List of mesh facets painted for MMU segmentation. // List of mesh facets painted for MMU segmentation.
FacetsAnnotation mmu_segmentation_facets; FacetsAnnotation mmu_segmentation_facets;
// Is set only when volume is Embossed Text type
// Contain information how to re-create volume
std::optional<TextConfiguration> text_configuration;
// A parent object owning this modifier volume. // A parent object owning this modifier volume.
ModelObject* get_object() const { return this->object; } ModelObject* get_object() const { return this->object; }
ModelVolumeType type() const { return m_type; } ModelVolumeType type() const { return m_type; }

View File

@ -0,0 +1,70 @@
#ifndef slic3r_TextConfiguration_hpp_
#define slic3r_TextConfiguration_hpp_
#include <vector>
#include <string>
namespace Slic3r {
// represent selected font
// Name must be human readable is visible in gui
// (Path + Type) must define how to open font for using on different OS
struct FontItem
{
std::string name;
std::string path;
enum class Type;
Type type;
FontItem() : type(Type::undefined) {}
FontItem(const std::string &name, const std::string &path, Type type = Type::file_path)
: name(name), path(path), type(type)
{}
// way of load font described in path string
enum class Type {
undefined = 0,
file_path, // path is file loacation on computer - no move between computers
wx_font_descr, // path is font descriptor generated by wxWidgets - limits for os/language move
};
};
using FontList = std::vector<FontItem>;
// user defined font property
struct FontProp
{
// define extra space between letters, negative mean closer letter
int char_gap = 0;
// define extra space between lines, negative mean closer lines
int line_gap = 0;
// Precision of lettter outline curve in conversion to lines
float flatness = 2.0;
// Height of letter [in mm]
float size_in_mm = 10;
// Z depth of text [in mm]
float emboss = 5;
// TODO: add enum class Align: center/left/right
FontProp() = default;
};
// define how to create 'Text volume'
struct TextConfiguration
{
// define font
FontItem font_item;
// user modification of font
FontProp font_prop;
std::string text;
TextConfiguration() = default;
TextConfiguration(const FontItem & font_item,
const FontProp & font_prop,
const std::string &text)
: font_item(font_item), font_prop(font_prop), text(text)
{}
};
} // namespace Slic3r
#endif // slic3r_TextConfiguration_hpp_

View File

@ -8,6 +8,8 @@
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "nanosvg/nanosvg.h" // load SVG file
#include <wx/font.h> #include <wx/font.h>
#include <wx/fontdlg.h> #include <wx/fontdlg.h>
@ -21,13 +23,12 @@ public:
// os specific load of wxFont // os specific load of wxFont
static std::optional<Slic3r::Emboss::Font> load_font(const wxFont &font); static std::optional<Slic3r::Emboss::Font> load_font(const wxFont &font);
// Must be in gui because of wxWidget // Must be in gui because of wxWidget
static std::optional<Slic3r::Emboss::Font> load_font(const Emboss::FontItem &fi); static std::optional<Slic3r::Emboss::Font> load_font(const FontItem &fi);
static FontItem get_font_item(const wxFont &font);
static Slic3r::Emboss::FontItem get_font_item(const wxFont &font);
// load font used by Operating system as default GUI // load font used by Operating system as default GUI
static Slic3r::Emboss::FontItem get_os_font(); static FontItem get_os_font();
static std::string get_human_readable_name(const wxFont &font); static std::string get_human_readable_name(const wxFont &font);
// serialize / deserialize font // serialize / deserialize font
@ -52,23 +53,20 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
{ {
// TODO: suggest to use https://fontawesome.com/ // TODO: suggest to use https://fontawesome.com/
// (copy & paste) unicode symbols from web // (copy & paste) unicode symbols from web
bool is_font_loaded = load_font();
add_fonts(Emboss::get_font_list());
add_fonts({WxFontUtils::get_os_font()});
if (!is_font_loaded) { bool is_font_loaded = load_font();
FontList fl = Emboss::get_font_list();
m_font_list.insert(m_font_list.end(), fl.begin(), fl.end());
m_font_list.emplace_back(WxFontUtils::get_os_font());
while (!is_font_loaded && !m_font_list.empty()) {
// can't load so erase it from list // can't load so erase it from list
m_font_list.erase(m_font_list.begin() + m_font_selected); m_font_list.erase(m_font_list.begin() + m_font_selected);
m_font_selected = 0; // select first m_font_selected = 0; // select first
do{ is_font_loaded = load_font();
is_font_loaded = load_font();
if (!is_font_loaded) m_font_list.erase(m_font_list.begin());
} while (!is_font_loaded && !m_font_list.empty());
} }
int index = 0; sort_fonts();
for (char &c : _u8L("Embossed text")) { m_text[index++] = c; } set_default_configuration();
m_text[index] = '\0';
} }
GLGizmoEmboss::~GLGizmoEmboss() {} GLGizmoEmboss::~GLGizmoEmboss() {}
@ -88,50 +86,156 @@ std::string GLGizmoEmboss::on_get_name() const
void GLGizmoEmboss::on_render() {} void GLGizmoEmboss::on_render() {}
void GLGizmoEmboss::on_render_for_picking() {} void GLGizmoEmboss::on_render_for_picking() {}
// took from nanosvgrast.h function nsvgRasterize->nsvg__flattenShape
void flatten_cubic_bez(Slic3r::Polygon &polygon,
float tessTol,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3,
float x4,
float y4,
int level)
{
float x12, y12, x23, y23, x34, y34, x123, y123, x234, y234, x1234,
y1234;
float dx, dy, d2, d3;
if (level == 0) return;
x12 = (x1 + x2) * 0.5f;
y12 = (y1 + y2) * 0.5f;
x23 = (x2 + x3) * 0.5f;
y23 = (y2 + y3) * 0.5f;
x34 = (x3 + x4) * 0.5f;
y34 = (y3 + y4) * 0.5f;
x123 = (x12 + x23) * 0.5f;
y123 = (y12 + y23) * 0.5f;
dx = x4 - x1;
dy = y4 - y1;
d2 = std::abs(((x2 - x4) * dy - (y2 - y4) * dx));
d3 = std::abs(((x3 - x4) * dy - (y3 - y4) * dx));
if ((d2 + d3) * (d2 + d3) < tessTol * (dx * dx + dy * dy)) {
polygon.points.emplace_back(x4, y4);
return;
}
--level;
if (level == 0) return;
x234 = (x23 + x34) * 0.5f;
y234 = (y23 + y34) * 0.5f;
x1234 = (x123 + x234) * 0.5f;
y1234 = (y123 + y234) * 0.5f;
flatten_cubic_bez(polygon, tessTol, x1, y1, x12, y12, x123, y123, x1234, y1234, level);
flatten_cubic_bez(polygon, tessTol, x1234, y1234, x234, y234, x34, y34, x4, y4, level);
}
Slic3r::ExPolygons to_ExPolygons(NSVGimage *image,
float tessTol = 10.,
int max_level = 10)
{
Polygons polygons;
for (NSVGshape *shape = image->shapes; shape != NULL;
shape = shape->next) {
if (!(shape->flags & NSVG_FLAGS_VISIBLE)) continue;
Slic3r::Polygon polygon;
if (shape->fill.type != NSVG_PAINT_NONE) {
for (NSVGpath *path = shape->paths; path != NULL;
path = path->next) {
// Flatten path
polygon.points.emplace_back(path->pts[0], path->pts[1]);
for (size_t i = 0; i < path->npts - 1; i += 3) {
float *p = &path->pts[i * 2];
flatten_cubic_bez(polygon, tessTol, p[0], p[1], p[2],
p[3], p[4], p[5], p[6], p[7],
max_level);
}
if (path->closed) {
polygons.push_back(polygon);
polygon = Slic3r::Polygon();
}
}
}
polygons.push_back(polygon);
}
return union_ex(polygons);
}
#include "libslic3r/SVG.hpp"
void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit) void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
{ {
if (!m_gui_cfg.has_value()) m_gui_cfg.emplace(GuiCfg()); if (!m_gui_cfg.has_value()) m_gui_cfg.emplace(GuiCfg());
check_selection();
int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoCollapse; ImGuiWindowFlags_NoCollapse;
m_imgui->begin(on_get_name(), flag); m_imgui->begin(on_get_name(), flag);
if (!m_font.has_value()) {
ImGui::Text("Warning: No font is selected. Select correct one.");
}
draw_font_list(); draw_font_list();
static std::string fontName;
if (ImGui::Button(_L("choose font").c_str())) { if (ImGui::Button(_L("choose font").c_str())) {
static wxFontData data; // keep last selected font choose_font_by_dialog();
wxFontDialog font_dialog((wxWindow*)wxGetApp().mainframe, data); }
font_dialog.SetTitle(_L("Select font for Emboss"));
if (font_dialog.ShowModal() == wxID_OK) { ImGui::SameLine();
data = font_dialog.GetFontData(); if (ImGui::Button(_L("use system font").c_str())) {
wxFont font = data.GetChosenFont(); wxSystemSettings ss;
auto fontOpt = WxFontUtils::load_font(font); wxFont f = ss.GetFont(wxSYS_DEFAULT_GUI_FONT);
if (fontOpt.has_value()) { size_t font_index = m_font_list.size();
Emboss::FontItem fontItem = WxFontUtils::get_font_item(font); FontItem fi = WxFontUtils::get_font_item(f);
m_font_selected = m_font_list.size(); m_font_list.emplace_back(fi);
add_fonts({fontItem}); bool loaded = load_font(font_index);
m_font = fontOpt;
process();
}
}
} }
if (!fontName.empty()) ImGui::Text(fontName.c_str());
ImGui::SameLine(); ImGui::SameLine();
draw_add_button(); draw_add_button();
ImGui::InputFloat("Size[in mm]", &m_font_prop.size_in_mm); if (ImGui::Button("add svg")) {
ImGui::InputFloat("Emboss[in mm]", &m_font_prop.emboss); std::string filePath =
if (ImGui::InputFloat("Flatness", &m_font_prop.flatness)) "C:/Users/filip/Downloads/fontawesome-free-5.15.4-web/"
if(m_font.has_value()) m_font->cache.clear(); "fontawesome-free-5.15.4-web/svgs/solid/bicycle.svg";
ImGui::InputInt("CharGap[in font points]", &m_font_prop.char_gap); NSVGimage *image = nsvgParseFromFile(filePath.c_str(), "mm", 96.0f);
ImGui::InputInt("LineGap[in font points]", &m_font_prop.line_gap); ExPolygons polys = to_ExPolygons(image);
ImGui::InputFloat3("Origin", m_orientation.origin.data());
for (auto &poly : polys) poly.scale(1e5);
SVG svg("converted.svg", BoundingBox(polys.front().contour.points));
svg.draw(polys);
nsvgDelete(image);
}
if (ImGui::InputFloat("Size[in mm]", &m_font_prop.size_in_mm)) {
if (m_font_prop.size_in_mm < 0.1) m_font_prop.size_in_mm = 10;
process();
}
if (ImGui::InputFloat("Emboss[in mm]", &m_font_prop.emboss)) process();
if (ImGui::InputFloat("Flatness", &m_font_prop.flatness)) {
if (m_font.has_value()) m_font->cache.clear();
process();
}
if (ImGui::InputInt("CharGap[in font points]", &m_font_prop.char_gap)) process();
if (ImGui::InputInt("LineGap[in font points]", &m_font_prop.line_gap)) process();
//ImGui::InputFloat3("Origin", m_orientation.origin.data());
//if (ImGui::InputFloat3("Normal", m_normal.data())) m_normal.normalize(); //if (ImGui::InputFloat3("Normal", m_normal.data())) m_normal.normalize();
//if (ImGui::InputFloat3("Up", m_up.data())) m_up.normalize(); //if (ImGui::InputFloat3("Up", m_up.data())) m_up.normalize();
m_imgui->disabled_begin(!m_font.has_value()); m_imgui->disabled_begin(!m_font.has_value());
if (ImGui::Button("Preview")) process();
// create default text
if (m_volume == nullptr) {
if (ImGui::Button("Generate preview")) process();
}
m_imgui->disabled_end(); m_imgui->disabled_end();
ImVec2 input_size(-FLT_MIN, ImGui::GetTextLineHeight() * 6); ImVec2 input_size(-FLT_MIN, ImGui::GetTextLineHeight() * 6);
ImGuiInputTextFlags flags = ImGuiInputTextFlags flags =
@ -149,17 +253,7 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
// change text size // change text size
int max_text_size = static_cast<int>(m_text_size); int max_text_size = static_cast<int>(m_text_size);
if (ImGui::InputInt("max text size", &max_text_size, 8, 64)) { if (ImGui::InputInt("max text size", &max_text_size, 8, 64)) {
if (max_text_size < 4) max_text_size = 4; set_max_text_size(static_cast<size_t>(max_text_size));
std::unique_ptr<char[]> newData(new char[max_text_size]);
size_t index = 0;
while ((index+1) < max_text_size) {
if (m_text.get()[index] == '\0') break;
newData.get()[index] = m_text.get()[index];
++index;
}
newData.get()[index] = '\0';
m_text = std::move(newData);
m_text_size = max_text_size;
} }
// draw 2d triangle in IMGUI // draw 2d triangle in IMGUI
@ -172,7 +266,6 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
m_imgui->end(); m_imgui->end();
} }
bool GLGizmoEmboss::on_is_activable() const bool GLGizmoEmboss::on_is_activable() const
{ {
return !m_parent.get_selection().is_empty(); return !m_parent.get_selection().is_empty();
@ -195,8 +288,10 @@ void GLGizmoEmboss::on_set_state()
} }
m_volume = nullptr; m_volume = nullptr;
} else if (GLGizmoBase::m_state == GLGizmoBase::On) { } else if (GLGizmoBase::m_state == GLGizmoBase::On) {
if(!set_volume()) set_default_configuration();
// when open by hyperlink it needs to show up // when open by hyperlink it needs to show up
//request_rerender(); m_parent.reload_scene(true);
} }
} }
@ -263,6 +358,63 @@ bool GLGizmoEmboss::gizmo_event(SLAGizmoEventType action,
return false; return false;
} }
void GLGizmoEmboss::set_default_configuration() {
set_text(_u8L("Embossed text"));
m_font_prop = FontProp();
// may be set default font?
}
void GLGizmoEmboss::check_selection()
{
// is text created?
if (m_volume == nullptr) return;
ModelVolume* vol = get_selected_volume();
// is same volume selected?
if (m_volume == vol) return;
// Do not use actual edited value when switch volume
ImGui::SetKeyboardFocusHere(-1);
// is selected volume embossed?
if (vol!= nullptr && vol->text_configuration.has_value()) {
m_volume = vol;
load_configuration(*vol->text_configuration);
return;
}
// behave like adding new text
m_volume == nullptr;
}
ModelVolume *GLGizmoEmboss::get_selected_volume()
{
return get_selected_volume(m_parent.get_selection(),
wxGetApp().plater()->model().objects);
}
ModelVolume *GLGizmoEmboss::get_selected_volume(const Selection &selection,
const ModelObjectPtrs objects)
{
int object_idx = selection.get_object_idx();
// is more object selected?
if (object_idx == -1) return nullptr;
auto volume_idxs = selection.get_volume_idxs();
// is more volumes selected?
if (volume_idxs.size() != 1) return nullptr;
unsigned int vol_id_gl = *volume_idxs.begin();
const GLVolume * vol_gl = selection.get_volume(vol_id_gl);
const GLVolume::CompositeID &id = vol_gl->composite_id;
if (id.object_id >= objects.size()) return nullptr;
ModelObject *object = objects[id.object_id];
if (id.volume_id >= object->volumes.size()) return nullptr;
return object->volumes[id.volume_id];
}
// create_text_volume()
void GLGizmoEmboss::process() { void GLGizmoEmboss::process() {
if (!m_font.has_value()) return; if (!m_font.has_value()) return;
@ -305,6 +457,7 @@ void GLGizmoEmboss::process() {
// set a default extruder value, since user can't add it manually // set a default extruder value, since user can't add it manually
m_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); m_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
m_volume->text_configuration = create_configuration();
// select new added volume // select new added volume
ModelVolume *new_volume = m_volume; ModelVolume *new_volume = m_volume;
@ -343,7 +496,7 @@ void GLGizmoEmboss::draw_add_button() {
if (dialog.ShowModal() == wxID_OK) dialog.GetPaths(input_files); if (dialog.ShowModal() == wxID_OK) dialog.GetPaths(input_files);
if (input_files.IsEmpty()) return; if (input_files.IsEmpty()) return;
Emboss::FontList font_list; FontList font_list;
font_list.reserve(input_files.size()); font_list.reserve(input_files.size());
for (auto &input_file : input_files) { for (auto &input_file : input_files) {
std::string path = std::string(input_file.c_str()); std::string path = std::string(input_file.c_str());
@ -368,7 +521,7 @@ void GLGizmoEmboss::draw_font_list()
{ {
auto &current = m_font_list[m_font_selected]; auto &current = m_font_list[m_font_selected];
if (ImGui::BeginCombo("##font_selector", current.name.c_str())) { if (ImGui::BeginCombo("##font_selector", current.name.c_str())) {
for (const Emboss::FontItem &f : m_font_list) { for (const FontItem &f : m_font_list) {
ImGui::PushID((void *) &f.name); ImGui::PushID((void *) &f.name);
std::string name = std::string name =
(f.name.size() < m_gui_cfg->max_font_name) ? (f.name.size() < m_gui_cfg->max_font_name) ?
@ -411,6 +564,14 @@ void GLGizmoEmboss::draw_font_list()
} }
} }
bool GLGizmoEmboss::load_font(size_t font_index)
{
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() { bool GLGizmoEmboss::load_font() {
if (m_font_selected >= m_font_list.size()) return false; if (m_font_selected >= m_font_list.size()) return false;
auto font = WxFontUtils::load_font(m_font_list[m_font_selected]); auto font = WxFontUtils::load_font(m_font_list[m_font_selected]);
@ -419,18 +580,62 @@ bool GLGizmoEmboss::load_font() {
return true; return true;
} }
std::optional<Emboss::Font> WxFontUtils::load_font(const Emboss::FontItem &fi) void GLGizmoEmboss::set_text(const std::string &text) {
if (text.size() > m_text_size-1)
set_max_text_size(text.size() + 1);
int index = 0;
for (const char &c : text) m_text[index++] = c;
m_text[index] = '\0';
}
void GLGizmoEmboss::set_max_text_size(size_t size) {
if (size < 4) size = 4;
std::unique_ptr<char[]> newData(new char[size]);
size_t index = 0;
while ((index + 1) < size) {
if (m_text.get()[index] == '\0') break;
newData.get()[index] = m_text.get()[index];
++index;
}
newData.get()[index] = '\0';
m_text = std::move(newData);
m_text_size = size;
}
bool GLGizmoEmboss::choose_font_by_dialog() {
// keep last selected font did not work
// static wxFontData data;
// wxFontDialog font_dialog((wxWindow *) wxGetApp().mainframe, data);
wxFontDialog font_dialog(nullptr);
font_dialog.SetTitle(_L("Select font for Emboss"));
if (font_dialog.ShowModal() != wxID_OK) return false;
wxFontData data = font_dialog.GetFontData();
wxFont font = data.GetChosenFont();
size_t font_index = m_font_list.size();
m_font_list.emplace_back(WxFontUtils::get_font_item(font));
if (!load_font(font_index)) {
m_font_list.pop_back();
return false;
}
sort_fonts();
process();
return true;
}
std::optional<Emboss::Font> WxFontUtils::load_font(const FontItem &fi)
{ {
switch (fi.type) { switch (fi.type) {
case Emboss::FontItem::Type::file_path: case FontItem::Type::file_path:
return Emboss::load_font(fi.path.c_str()); return Emboss::load_font(fi.path.c_str());
case Emboss::FontItem::Type::wx_font_descr: case FontItem::Type::wx_font_descr:
return WxFontUtils::load_font(WxFontUtils::load_wxFont(fi.path)); return WxFontUtils::load_font(WxFontUtils::load_wxFont(fi.path));
} }
return {}; return {};
} }
std::optional<Slic3r::Emboss::Font> WxFontUtils::load_font(const wxFont &font) std::optional<Emboss::Font> WxFontUtils::load_font(const wxFont &font)
{ {
if (!font.IsOk()) return {}; if (!font.IsOk()) return {};
#ifdef _WIN32 #ifdef _WIN32
@ -448,18 +653,18 @@ std::optional<Slic3r::Emboss::Font> WxFontUtils::load_font(const wxFont &font)
#endif #endif
} }
Slic3r::Emboss::FontItem WxFontUtils::get_font_item(const wxFont &font) FontItem WxFontUtils::get_font_item(const wxFont &font)
{ {
std::string name = get_human_readable_name(font); std::string name = get_human_readable_name(font);
std::string fontDesc = store_wxFont(font); std::string fontDesc = store_wxFont(font);
return Emboss::FontItem(name, fontDesc, Emboss::FontItem::Type::wx_font_descr); return FontItem(name, fontDesc, FontItem::Type::wx_font_descr);
} }
Slic3r::Emboss::FontItem WxFontUtils::get_os_font() FontItem WxFontUtils::get_os_font()
{ {
wxSystemSettings ss; wxSystemSettings ss;
wxFont ss_font = ss.GetFont(wxSYS_ANSI_VAR_FONT); wxFont ss_font = ss.GetFont(wxSYS_ANSI_VAR_FONT);
Emboss::FontItem fi = get_font_item(ss_font); FontItem fi = get_font_item(ss_font);
fi.name += +" (" + _u8L("OS default") + ")"; fi.name += +" (" + _u8L("OS default") + ")";
return get_font_item(ss_font); return get_font_item(ss_font);
} }
@ -502,7 +707,7 @@ void GLGizmoEmboss::sort_fonts() {
return m_font_list[i1].name < m_font_list[i2].name; return m_font_list[i1].name < m_font_list[i2].name;
}); });
Emboss::FontList font_list; FontList font_list;
font_list.reserve(m_font_list.size()); font_list.reserve(m_font_list.size());
size_t selected = 0; size_t selected = 0;
for (const size_t &i : idx) { for (const size_t &i : idx) {
@ -513,18 +718,68 @@ void GLGizmoEmboss::sort_fonts() {
m_font_selected = selected; m_font_selected = selected;
} }
void GLGizmoEmboss::add_fonts(const Emboss::FontList &font_list) { void GLGizmoEmboss::add_fonts(const FontList &font_list) {
m_font_list.insert(m_font_list.end(), font_list.begin(), font_list.end()); m_font_list.insert(m_font_list.end(), font_list.begin(), font_list.end());
sort_fonts(); sort_fonts();
} }
bool GLGizmoEmboss::set_volume()
{
ModelVolume *vol = get_selected_volume();
// Is selected only one volume
if (vol == nullptr) return false;
// Is volume created by Emboss?
if (!vol->text_configuration.has_value()) return false;
// set selected volume
m_volume = vol;
load_configuration(*vol->text_configuration);
return true;
}
TextConfiguration GLGizmoEmboss::create_configuration() {
std::string text((const char *) m_text.get());
return TextConfiguration(m_font_list[m_font_selected], m_font_prop, text);
}
bool GLGizmoEmboss::load_configuration(const TextConfiguration &configuration)
{
size_t index = m_font_list.size();
for (const auto &font_item : m_font_list) {
if (font_item.type == configuration.font_item.type &&
font_item.path == configuration.font_item.path) {
index = &font_item - &m_font_list.front();
}
}
size_t prev_font_selected = m_font_selected;
// when not in font list add to list
if (index >= m_font_list.size()) {
m_font_selected = m_font_list.size();
add_fonts({configuration.font_item});
} else {
m_font_selected = index;
}
// When can't load font
if (!load_font()) {
// remove bad loadabled font, for correct prev index
m_font_list.erase(m_font_list.begin() + m_font_selected);
m_font_selected = prev_font_selected;
return false;
}
m_font_prop = configuration.font_prop;
set_text(configuration.text);
return true;
}
std::string GLGizmoEmboss::create_volume_name() std::string GLGizmoEmboss::create_volume_name()
{ {
size_t max_len = 20; size_t max_len = 20;
std::string text((const char *)m_text.get()); std::string text((const char *)m_text.get());
if (text.size() > max_len) if (text.size() > max_len)
text = text.substr(0, max_len - 3) + " .."; text = text.substr(0, max_len - 3) + " ..";
return _u8L("Text") + ": " + text; return _u8L("Text") + " - " + text;
} }
// any existing icon filename to not influence GUI // any existing icon filename to not influence GUI

View File

@ -37,14 +37,31 @@ protected:
virtual void on_set_state() override; virtual void on_set_state() override;
private: private:
void set_default_configuration();
void check_selection();
// more general function --> move to select
ModelVolume *get_selected_volume();
static ModelVolume *get_selected_volume(const Selection &selection, const ModelObjectPtrs objects);
void process(); void process();
void close(); void close();
void draw_font_list(); void draw_font_list();
void draw_add_button(); void draw_add_button();
bool load_font(); bool load_font();
// try to set font_index
bool load_font(size_t font_index);
void set_text(const std::string &text);
void set_max_text_size(size_t size);
bool choose_font_by_dialog();
void sort_fonts(); void sort_fonts();
void add_fonts(const Emboss::FontList &font_list); void add_fonts(const FontList &font_list);
bool set_volume();
// Create object described how to make a Volume
TextConfiguration create_configuration();
bool load_configuration(const TextConfiguration& configuration);
std::string create_volume_name(); std::string create_volume_name();
@ -58,15 +75,15 @@ private:
}; };
std::optional<GuiCfg> m_gui_cfg; std::optional<GuiCfg> m_gui_cfg;
Emboss::FontList m_font_list; FontList m_font_list;
size_t m_font_selected;// index to m_font_list size_t m_font_selected;// index to m_font_list
std::optional<Emboss::Font> m_font; std::optional<Emboss::Font> m_font;
size_t m_text_size; size_t m_text_size;
std::unique_ptr<char[]> m_text; std::unique_ptr<char[]> m_text;
Emboss::FontProp m_font_prop; FontProp m_font_prop;
// text position // text position
struct Orientation struct Orientation