Set fine position

This commit is contained in:
Filip Sykala 2021-11-08 11:29:47 +01:00
parent 2bf876e96c
commit 378d8af7ac
6 changed files with 536 additions and 311 deletions

View File

@ -1,6 +1,8 @@
#include "CameraUtils.hpp" #include "CameraUtils.hpp"
#include <igl/project.h> // projecting points #include <igl/project.h> // projecting points
#include "slic3r/GUI/3DScene.hpp" // GLVolume
using namespace Slic3r; using namespace Slic3r;
using namespace GUI; using namespace GUI;
@ -33,3 +35,18 @@ Points CameraUtils::project(const Camera & camera,
} }
return result; return result;
} }
Slic3r::Polygon CameraUtils::create_hull2d(const Camera & camera,
const GLVolume &volume)
{
const indexed_triangle_set &its = volume.convex_hull()->its;
const Transform3d &trafoMat = volume.get_instance_transformation()
.get_matrix();
std::vector<Vec3d> vertices;
vertices.reserve(its.vertices.size());
for (const Vec3f &vertex : its.vertices)
vertices.emplace_back(trafoMat * vertex.cast<double>());
Points vertices_2d = project(camera, vertices);
return Geometry::convex_hull(vertices_2d);
}

View File

@ -3,9 +3,11 @@
#include "Camera.hpp" #include "Camera.hpp"
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
namespace Slic3r {
class GLVolume;
}
namespace Slic3r::GUI { namespace Slic3r::GUI {
/// <summary> /// <summary>
/// Help divide camera data and camera functions /// Help divide camera data and camera functions
/// This utility work with camera data by static funtions /// This utility work with camera data by static funtions
@ -16,14 +18,22 @@ public:
CameraUtils() = delete; // only static functions CameraUtils() = delete; // only static functions
/// <summary> /// <summary>
/// project point throw camera to 2d coordinate into imgui window /// Project point throw camera to 2d coordinate into imgui window
/// </summary> /// </summary>
/// <param name="its">IN/OUT triangle mesh to be simplified.</param> /// <param name="camera">Projection params</param>
/// <param name="its">IN/OUT triangle mesh to be simplified.</param> /// <param name="points">Point to project.</param>
/// <returns>projected points by camera into coordinate of camera. /// <returns>projected points by camera into coordinate of camera.
/// x(from left to right), y(from top to bottom)</returns> /// x(from left to right), y(from top to bottom)</returns>
static Points project(const Camera& camera, const std::vector<Vec3d> &points); static Points project(const Camera& camera, const std::vector<Vec3d> &points);
/// <summary>
/// Create hull around GLVolume in 2d space of camera
/// </summary>
/// <param name="camera">Projection params</param>
/// <param name="volume">Outline by 3d object</param>
/// <returns>Polygon around object</returns>
static Polygon create_hull2d(const Camera &camera, const GLVolume &volume);
}; };
} // Slic3r::GUI } // Slic3r::GUI

View File

@ -12,6 +12,7 @@
// TODO: remove include // TODO: remove include
#include "libslic3r/SVG.hpp" // debug store #include "libslic3r/SVG.hpp" // debug store
#include "libslic3r/Geometry.hpp" // covex hull 2d
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/ClipperUtils.hpp" // union_ex #include "libslic3r/ClipperUtils.hpp" // union_ex
@ -40,7 +41,7 @@
#endif #endif
// uncomment for easier debug // uncomment for easier debug
// #define ALLOW_DEBUG_MODE //#define ALLOW_DEBUG_MODE
namespace Slic3r { namespace Slic3r {
class WxFontUtils class WxFontUtils
@ -184,7 +185,6 @@ public:
} }
}; };
#endif // __linux__ #endif // __linux__
} // namespace Slic3r } // namespace Slic3r
using namespace Slic3r; using namespace Slic3r;
@ -203,17 +203,76 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
GLGizmoEmboss::~GLGizmoEmboss() {} GLGizmoEmboss::~GLGizmoEmboss() {}
void GLGizmoEmboss::set_fine_position()
{
const Selection & selection = m_parent.get_selection();
const Selection::IndicesList indices = selection.get_volume_idxs();
// no selected volume
if (indices.empty()) return;
const GLVolume *volume = selection.get_volume(*indices.begin());
// bad volume selected (e.g. deleted one)
if (volume == nullptr) return;
const Camera &camera = wxGetApp().plater()->get_camera();
Polygon hull = CameraUtils::create_hull2d(camera, *volume);
// TODO: fix width
ImVec2 windows_size = m_gui_cfg->draw_advanced ?
m_gui_cfg->minimal_window_size_with_advance :
m_gui_cfg->minimal_window_size;
ImVec2 offset = ImGuiWrapper::suggest_location(windows_size, hull);
m_gui_cfg->offset = offset;
return;
Polygon rect({Point(offset.x, offset.y),
Point(offset.x + windows_size.x, offset.y),
Point(offset.x + windows_size.x, offset.y + windows_size.y),
Point(offset.x, offset.y + windows_size.y)});
ImGuiWrapper::draw(hull);
ImGuiWrapper::draw(rect);
// m_gui_cfg->offset = offset;
}
#ifdef ALLOW_DEBUG_MODE
static void draw_fine_position(const Selection &selection)
{
const Selection::IndicesList indices = selection.get_volume_idxs();
// no selected volume
if (indices.empty()) return;
const GLVolume *volume = selection.get_volume(*indices.begin());
// bad volume selected (e.g. deleted one)
if (volume == nullptr) return;
const Camera &camera = wxGetApp().plater()->get_camera();
Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *volume);
ImVec2 windows_size(174, 202);
ImVec2 offset = ImGuiWrapper::suggest_location(windows_size, hull);
Slic3r::Polygon rect(
{Point(offset.x, offset.y), Point(offset.x + windows_size.x, offset.y),
Point(offset.x + windows_size.x, offset.y + windows_size.y),
Point(offset.x, offset.y + windows_size.y)});
ImGuiWrapper::draw(hull);
ImGuiWrapper::draw(rect);
}
#endif // ALLOW_DEBUG_MODE
void GLGizmoEmboss::set_volume_type(ModelVolumeType volume_type)
{
if (m_volume == nullptr) return;
m_volume->set_type(volume_type);
refresh_object_list();
m_parent.reload_scene(true);
}
bool GLGizmoEmboss::on_init() bool GLGizmoEmboss::on_init()
{ {
//m_grabbers.emplace_back(); // m_grabbers.emplace_back();
m_shortcut_key = WXK_CONTROL_T; m_shortcut_key = WXK_CONTROL_T;
return true; return true;
} }
std::string GLGizmoEmboss::on_get_name() const std::string GLGizmoEmboss::on_get_name() const { return _u8L("Emboss"); }
{
return _u8L("Emboss");
}
void GLGizmoEmboss::on_render() {} void GLGizmoEmboss::on_render() {}
void GLGizmoEmboss::on_render_for_picking() {} void GLGizmoEmboss::on_render_for_picking() {}
@ -221,19 +280,39 @@ void GLGizmoEmboss::on_render_for_picking() {}
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)
{ {
check_selection(); check_selection();
int flag = //ImGuiWindowFlags_AlwaysAutoResize | int flag = // ImGuiWindowFlags_AlwaysAutoResize |
// ImGuiWindowFlags_NoResize | // ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoCollapse; ImGuiWindowFlags_NoCollapse;
ImVec2 min_window_size = m_gui_cfg->draw_advanced ?
m_gui_cfg->minimal_window_size_with_advance :
m_gui_cfg->minimal_window_size;
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, min_window_size);
// ImGui::SetNextWindowSize(ImVec2(0, min_window_size.y),
// ImGuiCond_::ImGuiCond_Always);
#ifdef ALLOW_DEBUG_MODE
// draw suggested position of window
draw_fine_position(m_parent.get_selection());
#endif // ALLOW_DEBUG_MODE
// check if is set window offset
if (m_gui_cfg->offset.has_value()) {
ImGui::SetNextWindowPos(*m_gui_cfg->offset, ImGuiCond_Always);
// clear request on offset
m_gui_cfg->offset = {};
}
m_imgui->begin(on_get_name(), flag); m_imgui->begin(on_get_name(), flag);
draw_window(); draw_window();
m_imgui->end(); m_imgui->end();
ImGui::PopStyleVar(); // WindowMinSize
} }
void GLGizmoEmboss::on_set_state() void GLGizmoEmboss::on_set_state()
{ {
// Closing gizmo. e.g. selecting another one // Closing gizmo. e.g. selecting another one
if (GLGizmoBase::m_state == GLGizmoBase::Off) { if (GLGizmoBase::m_state == GLGizmoBase::Off) {
// refuse outgoing during text preview // refuse outgoing during text preview
if (false) { if (false) {
GLGizmoBase::m_state = GLGizmoBase::On; GLGizmoBase::m_state = GLGizmoBase::On;
@ -279,10 +358,8 @@ void GLGizmoEmboss::initialize()
m_gui_cfg->icon_width = ImGui::GetTextLineHeight(); m_gui_cfg->icon_width = ImGui::GetTextLineHeight();
m_gui_cfg->icon_width_with_spacing = m_gui_cfg->icon_width + space; m_gui_cfg->icon_width_with_spacing = m_gui_cfg->icon_width + space;
float scroll_width = m_gui_cfg->icon_width_with_spacing; // fix float scroll_width = m_gui_cfg->icon_width_with_spacing; // fix
m_gui_cfg->combo_font_width = m_gui_cfg->combo_font_width = m_gui_cfg->max_font_name_width +
m_gui_cfg->max_font_name_width +
2 * m_gui_cfg->icon_width_with_spacing + 2 * m_gui_cfg->icon_width_with_spacing +
scroll_width; scroll_width;
@ -290,8 +367,10 @@ void GLGizmoEmboss::initialize()
m_gui_cfg->delete_pos_x = m_gui_cfg->rename_pos_x + m_gui_cfg->delete_pos_x = m_gui_cfg->rename_pos_x +
m_gui_cfg->icon_width_with_spacing; m_gui_cfg->icon_width_with_spacing;
m_gui_cfg->text_size = m_gui_cfg->text_size = ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() *
ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * m_gui_cfg->count_line_of_text); m_gui_cfg->count_line_of_text);
m_gui_cfg->advanced_input_width = ImGui::CalcTextSize("M").x * 6;
// TODO: What to do when icon was NOT loaded? // TODO: What to do when icon was NOT loaded?
bool success = init_icons(); bool success = init_icons();
@ -318,7 +397,8 @@ FontList GLGizmoEmboss::create_default_font_list() {
}; };
} }
void GLGizmoEmboss::set_default_configuration() { void GLGizmoEmboss::set_default_configuration()
{
m_text = _u8L("Embossed text"); m_text = _u8L("Embossed text");
m_font_prop = FontProp(); m_font_prop = FontProp();
load_font(); // reload actual font - because of font size load_font(); // reload actual font - because of font size
@ -327,16 +407,15 @@ void GLGizmoEmboss::set_default_configuration() {
#include "imgui/imgui_internal.h" // to unfocus input --> ClearActiveID #include "imgui/imgui_internal.h" // to unfocus input --> ClearActiveID
void GLGizmoEmboss::check_selection() void GLGizmoEmboss::check_selection()
{ {
ModelVolume* vol = get_selected_volume(); ModelVolume *vol = get_selected_volume();
// is same volume selected? // is same volume selected?
if (vol!= nullptr && m_volume == vol) return; if (vol != nullptr && m_volume == vol) return;
// for changed volume notification is NOT valid // for changed volume notification is NOT valid
remove_notification_not_valid_font(); remove_notification_not_valid_font();
// Do not use focused input value when switch volume(it must swith value) // Do not use focused input value when switch volume(it must swith value)
if (m_volume != nullptr) if (m_volume != nullptr) ImGui::ClearActiveID();
ImGui::ClearActiveID();
// is select embossed volume? // is select embossed volume?
if (load_configuration(vol)) { if (load_configuration(vol)) {
@ -397,15 +476,8 @@ bool GLGizmoEmboss::process()
return add_volume(create_volume_name(), its); return add_volume(create_volume_name(), its);
} }
void GLGizmoEmboss::set_volume_type(ModelVolumeType volume_type) bool GLGizmoEmboss::add_volume(const std::string & name,
{ indexed_triangle_set &its)
if (m_volume == nullptr) return;
m_volume->set_type(volume_type);
refresh_object_list();
m_parent.reload_scene(true);
}
bool GLGizmoEmboss::add_volume(const std::string &name, indexed_triangle_set &its)
{ {
if (its.indices.empty()) return false; if (its.indices.empty()) return false;
// add object // add object
@ -414,7 +486,7 @@ bool GLGizmoEmboss::add_volume(const std::string &name, indexed_triangle_set &it
Vec3d shift = tm.bounding_box().center(); Vec3d shift = tm.bounding_box().center();
tm.translate(-shift.cast<float>()); tm.translate(-shift.cast<float>());
GUI_App & app = wxGetApp(); GUI_App &app = wxGetApp();
Plater * plater = app.plater(); Plater * plater = app.plater();
plater->take_snapshot(_L("Add") + " " + name); plater->take_snapshot(_L("Add") + " " + name);
if (m_volume == nullptr) { if (m_volume == nullptr) {
@ -454,70 +526,22 @@ bool GLGizmoEmboss::add_volume(const std::string &name, indexed_triangle_set &it
return true; return true;
} }
void GLGizmoEmboss::close() { void GLGizmoEmboss::close()
{
// close gizmo == open it again // close gizmo == open it again
m_parent.get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss); m_parent.get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss);
} }
static void draw(const Slic3r::Polygon &polygon,
ImU32 color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f)),
float thickness = 1.f)
{
// minimal one line
if (polygon.size()<2) return;
auto dl = ImGui::GetOverlayDrawList();
//auto dl = ImGui::GetWindowDrawList();
const Point* prev_point = &polygon.points.back();
for (const Point &point : polygon.points) {
ImVec2 p1(prev_point->x(), prev_point->y());
ImVec2 p2(point.x(), point.y());
dl->AddLine(p1, p2, color, thickness);
prev_point = &point;
}
}
#include "libslic3r/Geometry.hpp"
static void draw_hull(const GLVolume& volume)
{
const TriangleMesh &tm = *volume.convex_hull();
ImGui::Text("hull size %d", (int) tm.its.vertices.size());
//Slic3r::Polygon test_triangle({Point(100, 100), Point(200, 150), Point(120, 210)});
//draw(test_triangle);
// transform 3d hull
Geometry::Transformation trafo = volume.get_instance_transformation();
const Transform3d & trafoMat = trafo.get_matrix();
std::vector<Vec3d> vertices;
vertices.reserve(tm.its.vertices.size());
for (const Vec3f &vertex : tm.its.vertices)
vertices.emplace_back(trafoMat * vertex.cast<double>());
const Camera& camera = wxGetApp().plater()->get_camera();
Points vertices_2d = CameraUtils::project(camera, vertices);
Slic3r::Polygon chull = Geometry::convex_hull(vertices_2d);
draw(chull, ImGui::GetColorU32(ImVec4(0.7f, 0.1f, 0.2f, 0.75f)), 3.f);
}
void GLGizmoEmboss::draw_window() void GLGizmoEmboss::draw_window()
{ {
#ifdef ALLOW_DEBUG_MODE #ifdef ALLOW_DEBUG_MODE
if(ImGui::Button("re-process")) process(); if (ImGui::Button("re-process")) process();
if(ImGui::Button("add svg")) choose_svg_file(); if (ImGui::Button("add svg")) choose_svg_file();
if(ImGui::Button("use system font")) { if (ImGui::Button("use system font")) {
size_t font_index = m_font_list.size(); size_t font_index = m_font_list.size();
m_font_list.emplace_back(WxFontUtils::get_os_font()); m_font_list.emplace_back(WxFontUtils::get_os_font());
bool loaded = load_font(font_index); bool loaded = load_font(font_index);
} }
const Selection &selection = m_parent.get_selection();
const GLVolume * volume = selection.get_volume(
*selection.get_volume_idxs().begin());
if (volume != nullptr) draw_hull(*volume);
#endif // ALLOW_DEBUG_MODE #endif // ALLOW_DEBUG_MODE
if (!m_font.has_value()) { if (!m_font.has_value()) {
ImGui::Text(_u8L("Warning: No font is selected. Select correct one.").c_str()); ImGui::Text(_u8L("Warning: No font is selected. Select correct one.").c_str());
@ -525,8 +549,14 @@ void GLGizmoEmboss::draw_window()
draw_font_list(); draw_font_list();
draw_text_input(); draw_text_input();
static bool advanced = false; bool &advanced = m_gui_cfg->draw_advanced;
ImGui::Checkbox(_u8L("Advance").c_str(), &advanced); if (ImGui::Checkbox(_u8L("Advance").c_str(), &advanced)) {
ImVec2 window_size =
advanced ?
ImVec2(0, m_gui_cfg->minimal_window_size_with_advance.y) :
m_gui_cfg->minimal_window_size;
ImGui::SetWindowSize(window_size, ImGuiCond_Always);
}
if (advanced) draw_advanced(); if (advanced) draw_advanced();
if (ImGui::Button(_u8L("Close").c_str())) close(); if (ImGui::Button(_u8L("Close").c_str())) close();
@ -542,9 +572,10 @@ void GLGizmoEmboss::draw_window()
void GLGizmoEmboss::draw_font_list() void GLGizmoEmboss::draw_font_list()
{ {
const float& max_width = m_gui_cfg->max_font_name_width; const float & max_width = m_gui_cfg->max_font_name_width;
std::optional<size_t> rename_index; std::optional<size_t> rename_index;
std::string current_name = imgui_trunc(m_font_list[m_font_selected].name, max_width); std::string current_name = imgui_trunc(m_font_list[m_font_selected].name,
max_width);
ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width); ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
if (ImGui::BeginCombo("##font_selector", current_name.c_str())) { if (ImGui::BeginCombo("##font_selector", current_name.c_str())) {
// first line // first line
@ -552,14 +583,17 @@ void GLGizmoEmboss::draw_font_list()
choose_font_by_wxdialog(); choose_font_by_wxdialog();
store_font_list(); store_font_list();
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} else if (ImGui::IsItemHovered()) ImGui::SetTooltip(_u8L("Choose from installed font inside dialog.").c_str()); } else if (ImGui::IsItemHovered())
ImGui::SetTooltip(
_u8L("Choose from installed font inside dialog.").c_str());
// select font file by file browser // select font file by file browser
//if (ImGui::Button(_u8L("Add File").c_str())) { // if (ImGui::Button(_u8L("Add File").c_str())) {
// choose_true_type_file(); // choose_true_type_file();
// store_font_list(); // store_font_list();
// ImGui::CloseCurrentPopup(); // ImGui::CloseCurrentPopup();
//} else if (ImGui::IsItemHovered()) ImGui::SetTooltip(_u8L("add file with font(.ttf, .ttc)").c_str()); //} else if (ImGui::IsItemHovered()) ImGui::SetTooltip(_u8L("add file
//with font(.ttf, .ttc)").c_str());
ImGui::Separator(); ImGui::Separator();
@ -568,7 +602,8 @@ void GLGizmoEmboss::draw_font_list()
std::string name = imgui_trunc(f.name, max_width); std::string name = imgui_trunc(f.name, max_width);
size_t index = &f - &m_font_list.front(); size_t index = &f - &m_font_list.front();
bool is_selected = index == m_font_selected; bool is_selected = index == m_font_selected;
auto flags = ImGuiSelectableFlags_AllowItemOverlap; // allow clic buttons auto flags =
ImGuiSelectableFlags_AllowItemOverlap; // allow clic buttons
if (ImGui::Selectable(name.c_str(), is_selected, flags)) { if (ImGui::Selectable(name.c_str(), is_selected, flags)) {
size_t prev_font_selected = m_font_selected; size_t prev_font_selected = m_font_selected;
m_font_selected = index; m_font_selected = index;
@ -598,19 +633,21 @@ void GLGizmoEmboss::draw_font_list()
} }
// rename modal window popup // rename modal window popup
const char *rename_popup_id = "Rename_font"; const char * rename_popup_id = "Rename_font";
static size_t rename_id; static size_t rename_id;
if (rename_index.has_value() && !ImGui::IsPopupOpen(rename_popup_id)) { if (rename_index.has_value() && !ImGui::IsPopupOpen(rename_popup_id)) {
ImGui::OpenPopup(rename_popup_id); ImGui::OpenPopup(rename_popup_id);
rename_id = *rename_index; rename_id = *rename_index;
} }
if (ImGui::BeginPopupModal(rename_popup_id)) { if (ImGui::BeginPopupModal(rename_popup_id)) {
FontItem &fi = m_font_list[rename_id]; FontItem & fi = m_font_list[rename_id];
std::string rename_popup = GUI::format(_u8L("Change font name (%1%): "), fi.name); std::string rename_popup =
GUI::format(_u8L("Change font name (%1%): "), fi.name);
ImGui::Text(rename_popup.c_str()); ImGui::Text(rename_popup.c_str());
ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width); ImGui::SetNextItemWidth(m_gui_cfg->combo_font_width);
if (ImGui::InputText("##font name", &fi.name, ImGuiInputTextFlags_EnterReturnsTrue) || if (ImGui::InputText("##font name", &fi.name,
ImGui::Button("ok")){ ImGuiInputTextFlags_EnterReturnsTrue) ||
ImGui::Button("ok")) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
store_font_list(); store_font_list();
} }
@ -621,16 +658,16 @@ void GLGizmoEmboss::draw_font_list()
void GLGizmoEmboss::draw_text_input() void GLGizmoEmboss::draw_text_input()
{ {
static const ImGuiInputTextFlags flags = static const ImGuiInputTextFlags flags =
ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_AutoSelectAll;
ImGuiInputTextFlags_AutoSelectAll ;
ImVector<ImFont *> &fonts = m_imgui_font_atlas.Fonts; ImVector<ImFont *> &fonts = m_imgui_font_atlas.Fonts;
ImFont *imgui_font = fonts.empty()? nullptr : fonts.front(); ImFont * imgui_font = fonts.empty() ? nullptr : fonts.front();
bool exist_font = imgui_font != nullptr && imgui_font->IsLoaded(); bool exist_font = imgui_font != nullptr && imgui_font->IsLoaded();
if (exist_font) ImGui::PushFont(imgui_font); if (exist_font) ImGui::PushFont(imgui_font);
bool exist_change = false; bool exist_change = false;
if (ImGui::InputTextMultiline("##Text", &m_text, m_gui_cfg->text_size, flags)) { if (ImGui::InputTextMultiline("##Text", &m_text, m_gui_cfg->text_size,
flags)) {
process(); process();
exist_change = true; exist_change = true;
} }
@ -641,11 +678,14 @@ void GLGizmoEmboss::draw_text_input()
if (exist_change) check_imgui_font_range(); if (exist_change) check_imgui_font_range();
} }
void GLGizmoEmboss::draw_advanced() { void GLGizmoEmboss::draw_advanced()
if (ImGui::InputFloat(_u8L("Size[in mm]").c_str(), &m_font_prop.size_in_mm)) { {
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
if (ImGui::InputFloat(_u8L("Size[in mm]").c_str(),
&m_font_prop.size_in_mm)) {
if (m_font_prop.size_in_mm < 0.1) m_font_prop.size_in_mm = 10; if (m_font_prop.size_in_mm < 0.1) m_font_prop.size_in_mm = 10;
// store font size into path // store font size into path
FontItem& fi = m_font_list[m_font_selected]; FontItem &fi = m_font_list[m_font_selected];
if (fi.type == WxFontUtils::get_actual_type()) { if (fi.type == WxFontUtils::get_actual_type()) {
std::optional<wxFont> wx_font = WxFontUtils::load_wxFont(fi.path); std::optional<wxFont> wx_font = WxFontUtils::load_wxFont(fi.path);
if (wx_font.has_value()) { if (wx_font.has_value()) {
@ -657,13 +697,21 @@ void GLGizmoEmboss::draw_advanced() {
if (m_font.has_value()) m_font->cache.clear(); if (m_font.has_value()) m_font->cache.clear();
process(); process();
} }
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &m_font_prop.emboss)) process(); if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &m_font_prop.emboss))
if (ImGui::InputInt(_u8L("CharGap[in font points]").c_str(), &m_font_prop.char_gap)) process(); process();
if (ImGui::InputInt(_u8L("LineGap[in font points]").c_str(), &m_font_prop.line_gap)) process(); ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width);
if (ImGui::InputInt(_u8L("CharGap[in font points]").c_str(),
&m_font_prop.char_gap))
process();
ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width);
if (ImGui::InputInt(_u8L("LineGap[in font points]").c_str(),
&m_font_prop.line_gap))
process();
// when more collection add selector // when more collection add selector
if (m_font.has_value() && m_font->count > 1) { if (m_font.has_value() && m_font->count > 1) {
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
if (ImGui::BeginCombo(_u8L("Font collection").c_str(), if (ImGui::BeginCombo(_u8L("Font collection").c_str(),
std::to_string(m_font->index).c_str())) { std::to_string(m_font->index).c_str())) {
for (unsigned int i = 0; i < m_font->count; ++i) { for (unsigned int i = 0; i < m_font->count; ++i) {
@ -682,12 +730,22 @@ void GLGizmoEmboss::draw_advanced() {
#ifdef ALLOW_DEBUG_MODE #ifdef ALLOW_DEBUG_MODE
std::string descriptor = m_font_list[m_font_selected].path; std::string descriptor = m_font_list[m_font_selected].path;
ImGui::Text("family = %s", (m_font_prop.family.has_value()?m_font_prop.family->c_str() : " --- ")); ImGui::Text("family = %s", (m_font_prop.family.has_value() ?
ImGui::Text("face name = %s", (m_font_prop.face_name.has_value()?m_font_prop.face_name->c_str() : " --- ")); m_font_prop.family->c_str() :
ImGui::Text("style = %s", (m_font_prop.style.has_value()?m_font_prop.style->c_str() : " --- ")); " --- "));
ImGui::Text("weight = %s", (m_font_prop.weight.has_value()? m_font_prop.weight->c_str() : " --- ")); ImGui::Text("face name = %s", (m_font_prop.face_name.has_value() ?
m_font_prop.face_name->c_str() :
" --- "));
ImGui::Text("style = %s",
(m_font_prop.style.has_value() ? m_font_prop.style->c_str() :
" --- "));
ImGui::Text("weight = %s", (m_font_prop.weight.has_value() ?
m_font_prop.weight->c_str() :
" --- "));
ImGui::Text("descriptor = %s", descriptor.c_str()); ImGui::Text("descriptor = %s", descriptor.c_str());
ImGui::Image(m_imgui_font_atlas.TexID, ImVec2(m_imgui_font_atlas.TexWidth, m_imgui_font_atlas.TexHeight)); ImGui::Image(m_imgui_font_atlas.TexID,
ImVec2(m_imgui_font_atlas.TexWidth,
m_imgui_font_atlas.TexHeight));
#endif // ALLOW_DEBUG_MODE #endif // ALLOW_DEBUG_MODE
} }
@ -701,7 +759,8 @@ bool GLGizmoEmboss::create_default_model_object()
// e.g. selected font don't have letter for "Emboss text" // e.g. selected font don't have letter for "Emboss text"
// try select another font // try select another font
for (size_t font_index = 0; font_index < m_font_list.size(); ++font_index) { for (size_t font_index = 0; font_index < m_font_list.size();
++font_index) {
if (!load_font(font_index)) continue; if (!load_font(font_index)) continue;
// Is fixed by change to font from font list? // Is fixed by change to font from font list?
if (process()) return true; if (process()) return true;
@ -730,16 +789,18 @@ bool GLGizmoEmboss::create_default_model_object()
void GLGizmoEmboss::refresh_object_list() void GLGizmoEmboss::refresh_object_list()
{ {
const Selection &selection = m_parent.get_selection(); const Selection &selection = m_parent.get_selection();
if (selection.is_empty() || if (selection.is_empty() || selection.get_object_idx() < 0 ||
selection.get_object_idx() < 0 ||
m_volume == nullptr) m_volume == nullptr)
return; return;
ObjectList *obj_list = wxGetApp().obj_list(); ObjectList * obj_list = wxGetApp().obj_list();
ModelVolume *volume = m_volume; // copy for lambda ModelVolume *volume = m_volume; // copy for lambda
auto add_to_selection = [volume](const ModelVolume *vol) { return vol == volume; }; auto add_to_selection = [volume](const ModelVolume *vol) {
wxDataViewItemArray sel = obj_list->reorder_volumes_and_get_selection( return vol == volume;
selection.get_object_idx(), add_to_selection); };
wxDataViewItemArray sel =
obj_list->reorder_volumes_and_get_selection(selection.get_object_idx(),
add_to_selection);
if (!sel.IsEmpty()) obj_list->select_item(sel.front()); if (!sel.IsEmpty()) obj_list->select_item(sel.front());
obj_list->selection_changed(); obj_list->selection_changed();
} }
@ -752,13 +813,16 @@ bool GLGizmoEmboss::load_font(size_t font_index)
return is_loaded; 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;
FontItem& fi = m_font_list[m_font_selected]; FontItem &fi = m_font_list[m_font_selected];
if (fi.type == FontItem::Type::file_path) { if (fi.type == FontItem::Type::file_path) {
// fill font name after load from .3mf // fill font name after load from .3mf
if (fi.name.empty()) fi.name = Slic3r::GUI::GLGizmoEmboss::get_file_name(fi.path); if (fi.name.empty())
std::optional<Emboss::Font> font_opt = Emboss::load_font(fi.path.c_str()); fi.name = Slic3r::GUI::GLGizmoEmboss::get_file_name(fi.path);
std::optional<Emboss::Font> font_opt = Emboss::load_font(
fi.path.c_str());
if (!font_opt.has_value()) return false; if (!font_opt.has_value()) return false;
m_font = font_opt; m_font = font_opt;
load_imgui_font(); load_imgui_font();
@ -769,11 +833,12 @@ bool GLGizmoEmboss::load_font() {
if (!wx_font.has_value()) return false; if (!wx_font.has_value()) return false;
// fill font name after load from .3mf // fill font name after load from .3mf
if (fi.name.empty()) fi.name = WxFontUtils::get_human_readable_name(*wx_font); if (fi.name.empty())
fi.name = WxFontUtils::get_human_readable_name(*wx_font);
return load_font(*wx_font); return load_font(*wx_font);
} }
bool GLGizmoEmboss::load_font(const wxFont& font) bool GLGizmoEmboss::load_font(const wxFont &font)
{ {
auto font_opt = WxFontUtils::load_font(font); auto font_opt = WxFontUtils::load_font(font);
if (!font_opt.has_value()) return false; if (!font_opt.has_value()) return false;
@ -821,7 +886,8 @@ void GLGizmoEmboss::check_imgui_font_range()
if (exist_unknown) load_imgui_font(); if (exist_unknown) load_imgui_font();
} }
void GLGizmoEmboss::load_imgui_font() { void GLGizmoEmboss::load_imgui_font()
{
if (!m_font.has_value()) return; if (!m_font.has_value()) return;
ImFontGlyphRangesBuilder builder; ImFontGlyphRangesBuilder builder;
@ -843,9 +909,10 @@ void GLGizmoEmboss::load_imgui_font() {
m_imgui_font_atlas.Flags |= ImFontAtlasFlags_NoMouseCursors | m_imgui_font_atlas.Flags |= ImFontAtlasFlags_NoMouseCursors |
ImFontAtlasFlags_NoPowerOfTwoHeight; ImFontAtlasFlags_NoPowerOfTwoHeight;
m_imgui_font_atlas.Clear(); m_imgui_font_atlas.Clear();
m_imgui_font_atlas.AddFontFromMemoryTTF( m_imgui_font_atlas.AddFontFromMemoryTTF((void *) m_font->buffer.data(),
(void *) m_font->buffer.data(), m_font->buffer.size(), m_font->buffer.size(), font_size,
font_size, &font_config, m_imgui_font_ranges.Data); &font_config,
m_imgui_font_ranges.Data);
unsigned char *pixels; unsigned char *pixels;
int width, height; int width, height;
@ -854,7 +921,9 @@ void GLGizmoEmboss::load_imgui_font() {
// Upload texture to graphics system // Upload texture to graphics system
GLint last_texture; GLint last_texture;
glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
ScopeGuard sg([last_texture]() { glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture));}); ScopeGuard sg([last_texture]() {
glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture));
});
GLuint font_texture; GLuint font_texture;
glsafe(::glGenTextures(1, &font_texture)); glsafe(::glGenTextures(1, &font_texture));
@ -877,9 +946,9 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
// set previous selected font // set previous selected font
FontItem &selected_font_item = m_font_list[m_font_selected]; FontItem &selected_font_item = m_font_list[m_font_selected];
if (selected_font_item.type == WxFontUtils::get_actual_type()) { if (selected_font_item.type == WxFontUtils::get_actual_type()) {
std::optional<wxFont> selected_font = WxFontUtils::load_wxFont(selected_font_item.path); std::optional<wxFont> selected_font = WxFontUtils::load_wxFont(
if (selected_font.has_value()) selected_font_item.path);
data.SetInitialFont(*selected_font); if (selected_font.has_value()) data.SetInitialFont(*selected_font);
} }
wxFontDialog font_dialog(wxGetApp().mainframe, data); wxFontDialog font_dialog(wxGetApp().mainframe, data);
@ -899,15 +968,16 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
if (!use_deserialized_font) m_font_selected = font_index; if (!use_deserialized_font) m_font_selected = font_index;
// Try load and use new added font // Try load and use new added font
if ((!use_deserialized_font && !load_font(font)) || if ((!use_deserialized_font && !load_font(font)) ||
(use_deserialized_font && !load_font(font_index)) || (use_deserialized_font && !load_font(font_index)) || !process()) {
!process()) {
// reverse index for font_selected // reverse index for font_selected
std::swap(font_index, m_font_selected); // when not process std::swap(font_index, m_font_selected); // when not process
// remove form font list // remove form font list
m_font_list.pop_back(); m_font_list.pop_back();
// reverse property // reverse property
m_font_prop = old_font_prop; // when not process m_font_prop = old_font_prop; // when not process
wxString message = GUI::format_wxstr(_L("Font '%1%' can't be used. Please select another."), font_item.name); wxString message = GUI::format_wxstr(
_L("Font '%1%' can't be used. Please select another."),
font_item.name);
wxString title = _L("Selected font is NOT True-type."); wxString title = _L("Selected font is NOT True-type.");
MessageDialog not_loaded_font_message(nullptr, message, title, wxOK); MessageDialog not_loaded_font_message(nullptr, message, title, wxOK);
not_loaded_font_message.ShowModal(); not_loaded_font_message.ShowModal();
@ -950,11 +1020,12 @@ bool GLGizmoEmboss::choose_svg_file()
wxString fontDir = wxEmptyString; wxString fontDir = wxEmptyString;
wxString selectedFile = wxEmptyString; wxString selectedFile = wxEmptyString;
wxFileDialog dialog(nullptr, _L("Choose SVG file:"), fontDir, wxFileDialog dialog(nullptr, _L("Choose SVG file:"), fontDir,
selectedFile, file_wildcards(FT_SVG), wxFD_OPEN | wxFD_FILE_MUST_EXIST); selectedFile, file_wildcards(FT_SVG),
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (dialog.ShowModal() == wxID_OK) dialog.GetPaths(input_files); if (dialog.ShowModal() == wxID_OK) dialog.GetPaths(input_files);
if (input_files.IsEmpty()) return false; if (input_files.IsEmpty()) return false;
if (input_files.size() != 1) return false; if (input_files.size() != 1) return false;
auto &input_file = input_files.front(); auto & input_file = input_files.front();
std::string path = std::string(input_file.c_str()); std::string path = std::string(input_file.c_str());
std::string name = get_file_name(path); std::string name = get_file_name(path);
@ -963,20 +1034,22 @@ bool GLGizmoEmboss::choose_svg_file()
nsvgDelete(image); nsvgDelete(image);
BoundingBox bb; BoundingBox bb;
for (const auto &p: polys) bb.merge(p.contour.points); for (const auto &p : polys) bb.merge(p.contour.points);
float scale = m_font_prop.size_in_mm / std::max(bb.max.x(), bb.max.y()); float scale = m_font_prop.size_in_mm / std::max(bb.max.x(), bb.max.y());
auto project = std::make_unique<Emboss::ProjectScale>( auto project = std::make_unique<Emboss::ProjectScale>(
std::make_unique<Emboss::ProjectZ>(m_font_prop.emboss / scale), scale); std::make_unique<Emboss::ProjectZ>(m_font_prop.emboss / scale), scale);
indexed_triangle_set its = Emboss::polygons2model(polys, *project); indexed_triangle_set its = Emboss::polygons2model(polys, *project);
// test store: // test store:
//for (auto &poly : polys) poly.scale(1e5); // for (auto &poly : polys) poly.scale(1e5);
//SVG svg("converted.svg", BoundingBox(polys.front().contour.points)); // SVG svg("converted.svg", BoundingBox(polys.front().contour.points));
//svg.draw(polys); // svg.draw(polys);
return add_volume(name, its); return add_volume(name, its);
} }
TextConfiguration GLGizmoEmboss::create_configuration() { TextConfiguration GLGizmoEmboss::create_configuration()
return TextConfiguration(m_font_list[m_font_selected], m_font_prop, m_text); {
return TextConfiguration(m_font_list[m_font_selected], m_font_prop,
m_text);
} }
bool GLGizmoEmboss::load_configuration(ModelVolume *volume) bool GLGizmoEmboss::load_configuration(ModelVolume *volume)
@ -1011,11 +1084,13 @@ bool GLGizmoEmboss::load_configuration(ModelVolume *volume)
if (!load_font()) { if (!load_font()) {
// create similar font // create similar font
auto wx_font = WxFontUtils::create_wxFont(c_font_item, configuration.font_prop); auto wx_font = WxFontUtils::create_wxFont(c_font_item,
configuration.font_prop);
if (wx_font.has_value()) { if (wx_font.has_value()) {
// fix not loadable font item // fix not loadable font item
m_font_list[m_font_selected] = WxFontUtils::get_font_item(*wx_font); m_font_list[m_font_selected] = WxFontUtils::get_font_item(
if(!load_font(*wx_font)) return false; *wx_font);
if (!load_font(*wx_font)) return false;
} else { } else {
// can't create similar font use previous // can't create similar font use previous
m_font_list.erase(m_font_list.begin() + m_font_selected); m_font_list.erase(m_font_list.begin() + m_font_selected);
@ -1035,17 +1110,22 @@ void GLGizmoEmboss::create_notification_not_valid_font(
m_exist_notification = true; m_exist_notification = true;
auto type = NotificationType::UnknownFont; auto type = NotificationType::UnknownFont;
auto level = NotificationManager::NotificationLevel::WarningNotificationLevel; auto level =
NotificationManager::NotificationLevel::WarningNotificationLevel;
const auto& origin_family = tc.font_prop.face_name; const auto &origin_family = tc.font_prop.face_name;
const auto& actual_family = m_font_prop.face_name; const auto &actual_family = m_font_prop.face_name;
const auto& fi = m_font_list[m_font_selected]; const auto &fi = m_font_list[m_font_selected];
const std::string& origin_font_name = origin_family.has_value()? *origin_family : tc.font_item.path; const std::string &origin_font_name = origin_family.has_value() ?
const std::string &actual_font_name = actual_family.has_value()? *actual_family : fi.name; *origin_family :
tc.font_item.path;
const std::string &actual_font_name = actual_family.has_value() ?
*actual_family :
fi.name;
std::string text = GUI::format(_L( std::string text =
"Can't load exactly same font(\"%1%\"), " GUI::format(_L("Can't load exactly same font(\"%1%\"), "
"Aplication select similar one(\"%2%\"). " "Aplication select similar one(\"%2%\"). "
"When you edit text, similar font will be applied."), "When you edit text, similar font will be applied."),
origin_font_name, actual_font_name); origin_font_name, actual_font_name);
@ -1053,7 +1133,8 @@ void GLGizmoEmboss::create_notification_not_valid_font(
notification_manager->push_notification(type, level, text); notification_manager->push_notification(type, level, text);
} }
void GLGizmoEmboss::remove_notification_not_valid_font() { void GLGizmoEmboss::remove_notification_not_valid_font()
{
if (!m_exist_notification) return; if (!m_exist_notification) return;
m_exist_notification = false; m_exist_notification = false;
auto type = NotificationType::UnknownFont; auto type = NotificationType::UnknownFont;
@ -1065,8 +1146,9 @@ std::string GLGizmoEmboss::create_volume_name()
{ {
const size_t &max_len = m_gui_cfg->max_count_char_in_volume_name; const size_t &max_len = m_gui_cfg->max_count_char_in_volume_name;
return _u8L("Text") + " - " + return _u8L("Text") + " - " +
((m_text.size() > max_len)? ((m_text.size() > max_len) ?
(m_text.substr(0, max_len - 3) + " ..") : m_text); (m_text.substr(0, max_len - 3) + " ..") :
m_text);
} }
bool GLGizmoEmboss::init_icons() bool GLGizmoEmboss::init_icons()
@ -1074,10 +1156,8 @@ bool GLGizmoEmboss::init_icons()
std::string path = resources_dir() + "/icons/white/"; std::string path = resources_dir() + "/icons/white/";
// icon order has to match the enum IconType // icon order has to match the enum IconType
std::vector<std::string> filenames = { std::vector<std::string> filenames = {path + "wrench.svg",
path +"wrench.svg", path + "delete.svg"};
path +"delete.svg"
};
// state order has to match the enum IconState // state order has to match the enum IconState
std::vector<std::pair<int, bool>> states; std::vector<std::pair<int, bool>> states;
@ -1089,7 +1169,10 @@ bool GLGizmoEmboss::init_icons()
// make size pair number // make size pair number
if (sprite_size_px % 2 != 0) ++sprite_size_px; if (sprite_size_px % 2 != 0) ++sprite_size_px;
bool compress = false; bool compress = false;
return m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, sprite_size_px, compress); return m_icons_texture.load_from_svg_files_as_sprites_array(filenames,
states,
sprite_size_px,
compress);
} }
void GLGizmoEmboss::draw_icon(IconType icon, IconState state) void GLGizmoEmboss::draw_icon(IconType icon, IconState state)
@ -1108,16 +1191,12 @@ void GLGizmoEmboss::draw_icon(IconType icon, IconState state)
size_t count_states = 3; // activable | hovered | disabled size_t count_states = 3; // activable | hovered | disabled
ImVec2 icon_size(tex_width / count_states, tex_height / count_icons); ImVec2 icon_size(tex_width / count_states, tex_height / count_icons);
ImVec2 start( ImVec2 start(static_cast<unsigned>(state) * icon_size.x,
static_cast<unsigned>(state)*icon_size.x, static_cast<unsigned>(icon) * icon_size.y);
static_cast<unsigned>(icon)*icon_size.y);
ImVec2 uv0( ImVec2 uv0(start.x / tex_width, start.y / tex_height);
start.x/tex_width,
start.y/tex_height);
ImVec2 uv1( ImVec2 uv1((start.x + icon_size.x) / tex_width,
(start.x + icon_size.x) / tex_width,
(start.y + icon_size.y) / tex_height); (start.y + icon_size.y) / tex_height);
ImGui::Image(tex_id, icon_size, uv0, uv1); ImGui::Image(tex_id, icon_size, uv0, uv1);
@ -1128,8 +1207,11 @@ bool GLGizmoEmboss::draw_button(IconType icon, bool disable)
float line_spacing = ImGui::GetTextLineHeightWithSpacing() - float line_spacing = ImGui::GetTextLineHeightWithSpacing() -
ImGui::GetTextLineHeight(); ImGui::GetTextLineHeight();
float cursor_pos_y = ImGui::GetCursorPosY(); float cursor_pos_y = ImGui::GetCursorPosY();
ImGui::SetCursorPosY(cursor_pos_y - line_spacing/2); ImGui::SetCursorPosY(cursor_pos_y - line_spacing / 2);
ScopeGuard sg([cursor_pos_y]() { ImGui::SetCursorPosY(cursor_pos_y); ImGui::NewLine();}); ScopeGuard sg([cursor_pos_y]() {
ImGui::SetCursorPosY(cursor_pos_y);
ImGui::NewLine();
});
if (disable) { if (disable) {
draw_icon(icon, IconState::disabled); draw_icon(icon, IconState::disabled);
@ -1144,8 +1226,12 @@ bool GLGizmoEmboss::draw_button(IconType icon, bool disable)
if (ImGui::IsItemClicked()) return true; if (ImGui::IsItemClicked()) return true;
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
switch (icon) { switch (icon) {
case IconType::rename: ImGui::SetTooltip(_u8L("rename").c_str()); break; case IconType::rename:
case IconType::erase: ImGui::SetTooltip(_u8L("delete").c_str()); break; ImGui::SetTooltip(_u8L("rename").c_str());
break;
case IconType::erase:
ImGui::SetTooltip(_u8L("delete").c_str());
break;
default: break; default: break;
} }
// redraw image over previous // redraw image over previous
@ -1203,16 +1289,20 @@ std::optional<FontItem> GLGizmoEmboss::get_font_item(
{ {
auto path_it = app_cfg_section.find(APP_CONFIG_FONT_DESCRIPTOR); auto path_it = app_cfg_section.find(APP_CONFIG_FONT_DESCRIPTOR);
if (path_it == app_cfg_section.end()) return {}; if (path_it == app_cfg_section.end()) return {};
const std::string& path = path_it->second; const std::string &path = path_it->second;
auto name_it = app_cfg_section.find(APP_CONFIG_FONT_NAME); auto name_it = app_cfg_section.find(APP_CONFIG_FONT_NAME);
static const std::string default_name = "font_name"; static const std::string default_name = "font_name";
const std::string& name = (name_it == app_cfg_section.end()) ? const std::string & name = (name_it == app_cfg_section.end()) ?
default_name : name_it->second; default_name :
name_it->second;
return FontItem(name, path, WxFontUtils::get_actual_type()); return FontItem(name, path, WxFontUtils::get_actual_type());
} }
void GLGizmoEmboss::set_font_item(AppConfig &cfg, const FontItem &fi, unsigned index) { void GLGizmoEmboss::set_font_item(AppConfig & cfg,
const FontItem &fi,
unsigned index)
{
std::string section_name = get_app_config_font_section(index); std::string section_name = get_app_config_font_section(index);
cfg.clear_section(section_name); cfg.clear_section(section_name);
cfg.set(section_name, APP_CONFIG_FONT_NAME, fi.name); cfg.set(section_name, APP_CONFIG_FONT_NAME, fi.name);
@ -1270,17 +1360,18 @@ std::optional<Emboss::Font> WxFontUtils::load_font(const wxFont &font)
#elif defined(__APPLE__) #elif defined(__APPLE__)
// use file path // use file path
const wxNativeFontInfo *info = font.GetNativeFontInfo(); const wxNativeFontInfo *info = font.GetNativeFontInfo();
if(info == nullptr) return {}; if (info == nullptr) return {};
CTFontDescriptorRef descriptor = info->GetCTFontDescriptor(); CTFontDescriptorRef descriptor = info->GetCTFontDescriptor();
CFURLRef typeref = (CFURLRef)CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute); CFURLRef typeref = (CFURLRef)
CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute);
CFStringRef url = CFURLGetString(typeref); CFStringRef url = CFURLGetString(typeref);
if(url == NULL) return {}; if (url == NULL) return {};
wxString file_uri; wxString file_uri;
wxCFTypeRef(url).GetValue(file_uri); wxCFTypeRef(url).GetValue(file_uri);
std::string file_path(wxURI::Unescape(file_uri).c_str()); std::string file_path(wxURI::Unescape(file_uri).c_str());
size_t start = std::string("file://").size(); size_t start = std::string("file://").size();
if (file_path.empty() || file_path.size() <= start) return {}; if (file_path.empty() || file_path.size() <= start) return {};
file_path = file_path.substr(start, file_path.size()-start); file_path = file_path.substr(start, file_path.size() - start);
return Emboss::load_font(file_path.c_str()); return Emboss::load_font(file_path.c_str());
#elif defined(__linux__) #elif defined(__linux__)
static FontConfigHelp help; static FontConfigHelp help;
@ -1294,7 +1385,8 @@ std::optional<Emboss::Font> WxFontUtils::load_font(const wxFont &font)
#endif #endif
} }
FontItem::Type WxFontUtils::get_actual_type() { FontItem::Type WxFontUtils::get_actual_type()
{
#ifdef _WIN32 #ifdef _WIN32
return FontItem::Type::wx_win_font_descr; return FontItem::Type::wx_win_font_descr;
#elif defined(__APPLE__) #elif defined(__APPLE__)
@ -1311,7 +1403,7 @@ 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);
FontItem::Type type = get_actual_type(); FontItem::Type type = get_actual_type();
//wxFont f = font; // copy // wxFont f = font; // copy
return FontItem(name, fontDesc, type); return FontItem(name, fontDesc, type);
} }
@ -1331,22 +1423,22 @@ std::string WxFontUtils::get_human_readable_name(const wxFont &font)
if (!font.GetFaceName().empty()) { if (!font.GetFaceName().empty()) {
return std::string(font.GetFaceName().c_str()); return std::string(font.GetFaceName().c_str());
} else { } else {
return std::string(( return std::string((font.GetFamilyString() + " " +
font.GetFamilyString() + " " +
font.GetStyleString() + " " + font.GetStyleString() + " " +
font.GetWeightString() font.GetWeightString())
).c_str()); .c_str());
} }
} }
std::string WxFontUtils::store_wxFont(const wxFont &font) std::string WxFontUtils::store_wxFont(const wxFont &font)
{ {
//wxString os = wxPlatformInfo::Get().GetOperatingSystemIdName(); // wxString os = wxPlatformInfo::Get().GetOperatingSystemIdName();
wxString font_descriptor = font.GetNativeFontInfoDesc(); wxString font_descriptor = font.GetNativeFontInfoDesc();
return std::string(font_descriptor.c_str()); return std::string(font_descriptor.c_str());
} }
std::optional<wxFont> WxFontUtils::load_wxFont(const std::string &font_descriptor) std::optional<wxFont> WxFontUtils::load_wxFont(
const std::string &font_descriptor)
{ {
wxString font_descriptor_wx(font_descriptor); wxString font_descriptor_wx(font_descriptor);
wxFont wx_font(font_descriptor_wx); wxFont wx_font(font_descriptor_wx);
@ -1411,12 +1503,12 @@ std::optional<wxFont> WxFontUtils::create_wxFont(const FontItem &fi,
} }
// Improve: load descriptor instead of store to font property to 3mf // Improve: load descriptor instead of store to font property to 3mf
//switch (fi.type) { // switch (fi.type) {
//case FontItem::Type::wx_lin_font_descr: // case FontItem::Type::wx_lin_font_descr:
//case FontItem::Type::wx_win_font_descr: // case FontItem::Type::wx_win_font_descr:
//case FontItem::Type::file_path: // case FontItem::Type::file_path:
//case FontItem::Type::undefined: // case FontItem::Type::undefined:
//default: // default:
//} //}
wxFont font(info); wxFont font(info);
@ -1424,7 +1516,8 @@ std::optional<wxFont> WxFontUtils::create_wxFont(const FontItem &fi,
return font; return font;
} }
void WxFontUtils::update_property(FontProp &font_prop, const wxFont &font) { void WxFontUtils::update_property(FontProp &font_prop, const wxFont &font)
{
// The point size is defined as 1/72 of the Anglo-Saxon inch (25.4 mm): it // 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. But it is too small, so I // is approximately 0.0139 inch or 352.8 um. But it is too small, so I
// decide use point size as mm for emboss // decide use point size as mm for emboss
@ -1502,12 +1595,10 @@ ExPolygons NSVGUtils::to_ExPolygons(NSVGimage *image,
polygon.points.emplace_back(path->pts[0], path->pts[1]); polygon.points.emplace_back(path->pts[0], path->pts[1]);
for (size_t i = 0; i < path->npts - 1; i += 3) { for (size_t i = 0; i < path->npts - 1; i += 3) {
float *p = &path->pts[i * 2]; float *p = &path->pts[i * 2];
Vec2f Vec2f p1(p[0], p[1]), p2(p[2], p[3]), p3(p[4], p[5]),
p1(p[0], p[1]),
p2(p[2], p[3]),
p3(p[4], p[5]),
p4(p[6], p[7]); p4(p[6], p[7]);
flatten_cubic_bez(polygon, tessTol, p1, p2, p3, p4, max_level); flatten_cubic_bez(polygon, tessTol, p1, p2, p3, p4,
max_level);
} }
if (path->closed) { if (path->closed) {
polygons.push_back(polygon); polygons.push_back(polygon);

View File

@ -9,6 +9,7 @@
#include "admesh/stl.h" // indexed_triangle_set #include "admesh/stl.h" // indexed_triangle_set
#include <optional> #include <optional>
#include <memory> #include <memory>
#include <mutex>
#include "libslic3r/Emboss.hpp" #include "libslic3r/Emboss.hpp"
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
@ -26,7 +27,7 @@ public:
virtual ~GLGizmoEmboss(); virtual ~GLGizmoEmboss();
void set_volume_type(ModelVolumeType volume_type); void set_volume_type(ModelVolumeType volume_type);
void set_fine_position();
protected: protected:
virtual bool on_init() override; virtual bool on_init() override;
virtual std::string on_get_name() const override; virtual std::string on_get_name() const override;
@ -91,7 +92,15 @@ private:
int min_imgui_font_size = 18; int min_imgui_font_size = 18;
int max_imgui_font_size = 60; int max_imgui_font_size = 60;
bool draw_advanced = false;
ImVec2 minimal_window_size = ImVec2(174, 202);
ImVec2 minimal_window_size_with_advance = ImVec2(174, 302);
// setted only when wanted to use - not all the time
std::optional<ImVec2> offset;
// Zero means it is calculated in init function // Zero means it is calculated in init function
float advanced_input_width = 0.f;
float combo_font_width = 0.f; float combo_font_width = 0.f;
float rename_pos_x = 0.f; float rename_pos_x = 0.f;
float delete_pos_x = 0.f; float delete_pos_x = 0.f;

View File

@ -32,6 +32,11 @@
#include "nanosvg/nanosvg.h" #include "nanosvg/nanosvg.h"
#include "nanosvg/nanosvgrast.h" #include "nanosvg/nanosvgrast.h"
// suggest location
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GUI_App.hpp"
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -957,6 +962,74 @@ bool ImGuiWrapper::want_any_input() const
return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput;
} }
ImVec2 ImGuiWrapper::suggest_location(const ImVec2 & dialog_size,
const Slic3r::Polygon &interest)
{
Plater * plater = wxGetApp().plater();
GLCanvas3D *canvas = plater->get_current_canvas3D();
// IMPROVE 1: do not select place over menu
// BoundingBox top_menu;
// GLGizmosManager &gizmo_mng = canvas->get_gizmos_manager();
// BoundingBox side_menu; // gizmo_mng.get_size();
// BoundingBox left_bottom_menu; // is permanent?
// NotificationManager *notify_mng = plater->get_notification_manager();
// BoundingBox notifications; // notify_mng->get_size();
// m_window_width, m_window_height + position
// IMPROVE 2: use polygon of interest not only bounding box
BoundingBox bb(interest.points);
Point center = bb.center(); // interest.centroid();
// area size
Size size = canvas->get_canvas_size();
Point window_center(size.get_width() / 2, size.get_height() / 2);
// mov on side
Point bb_half_size = (bb.max - bb.min) / 2;
Point diff_center = window_center - center;
Vec2d diff_norm(diff_center.x() / (double) bb_half_size.x(),
diff_center.y() / (double) bb_half_size.y());
if (diff_norm.x() > 1.) diff_norm.x() = 1.;
if (diff_norm.x() < -1.) diff_norm.x() = -1.;
if (diff_norm.y() > 1.) diff_norm.y() = 1.;
if (diff_norm.y() < -1.) diff_norm.y() = -1.;
Vec2d abs_diff(abs(diff_norm.x()), abs(diff_norm.y()));
if (abs_diff.x() < 1. && abs_diff.y() < 1.) {
if (abs_diff.x() > abs_diff.y())
diff_norm.x() = (diff_norm.x() < 0.) ? (-1.) : 1.;
else
diff_norm.y() = (diff_norm.y() < 0.) ? (-1.) : 1.;
}
Point half_dialog_size(dialog_size.x / 2., dialog_size.y / 2.);
Point move_size = bb_half_size + half_dialog_size;
Point offseted_center = center - half_dialog_size;
return ImVec2(offseted_center.x() + diff_norm.x() * move_size.x(),
offseted_center.y() + diff_norm.y() * move_size.y());
}
void ImGuiWrapper::draw(
const Polygon &polygon,
ImDrawList * draw_list /* = ImGui::GetOverlayDrawList()*/,
ImU32 color /* = ImGui::GetColorU32(COL_ORANGE_LIGHT)*/,
float thickness /* = 3.f*/)
{
// minimal one line consist of 2 points
if (polygon.size() < 2) return;
// need a place to draw
if (draw_list == nullptr) return;
const Point *prev_point = &polygon.points.back();
for (const Point &point : polygon.points) {
ImVec2 p1(prev_point->x(), prev_point->y());
ImVec2 p2(point.x(), point.y());
draw_list->AddLine(p1, p2, color, thickness);
prev_point = &point;
}
}
#ifdef __APPLE__ #ifdef __APPLE__
static const ImWchar ranges_keyboard_shortcuts[] = static const ImWchar ranges_keyboard_shortcuts[] =
{ {

View File

@ -107,6 +107,31 @@ public:
bool want_text_input() const; bool want_text_input() const;
bool want_any_input() const; bool want_any_input() const;
/// <summary>
/// Suggest loacation of dialog window,
/// dependent on actual visible thing on platter
/// like Gizmo menu size, notifications, ...
/// To be near of polygon interest and not over it.
/// And also not out of visible area.
/// </summary>
/// <param name="dialog_size">Define width and height of diaog window</param>
/// <param name="interest">Area of interest. Result should be close to it</param>
/// <returns>Suggestion for dialog offest</returns>
static ImVec2 suggest_location(const ImVec2 & dialog_size,
const Slic3r::Polygon &interest);
/// <summary>
/// Visualization of polygon
/// </summary>
/// <param name="polygon">Define what to draw</param>
/// <param name="draw_list">Define where to draw it</param>
/// <param name="color">Color of polygon</param>
/// <param name="thickness">Width of polygon line</param>
static void draw(const Polygon &polygon,
ImDrawList * draw_list = ImGui::GetOverlayDrawList(),
ImU32 color = ImGui::GetColorU32(COL_ORANGE_LIGHT),
float thickness = 3.f);
static const ImVec4 COL_GREY_DARK; static const ImVec4 COL_GREY_DARK;
static const ImVec4 COL_GREY_LIGHT; static const ImVec4 COL_GREY_LIGHT;
static const ImVec4 COL_ORANGE_DARK; static const ImVec4 COL_ORANGE_DARK;