Partialy calculated distance on the fly.

This commit is contained in:
Filip Sykala - NTB T15p 2023-03-22 09:11:12 +01:00
parent 1b34b1970c
commit e0a4ac0313
11 changed files with 418 additions and 368 deletions

View File

@ -144,6 +144,21 @@ Pointf3s transform(const Pointf3s& points, const Transform3d& t);
/// <returns>Is positive determinant</returns> /// <returns>Is positive determinant</returns>
inline bool has_reflection(const Transform3d &transform) { return transform.matrix().determinant() < 0; } inline bool has_reflection(const Transform3d &transform) { return transform.matrix().determinant() < 0; }
/// <summary>
/// Getter on base of transformation matrix
/// </summary>
/// <param name="index">column index</param>
/// <param name="transform">source transformation</param>
/// <returns>Base of transformation matrix</returns>
inline const Vec3d &get_base(unsigned index, const Transform3d &transform) { return transform.linear().col(index); }
inline const Vec3d &get_base(unsigned index, const Transform3d::LinearPart &transform) { return transform.col(index); }
inline const Vec3d& get_x_base(const Transform3d &transform) { return get_base(0, transform); }
inline const Vec3d& get_y_base(const Transform3d &transform) { return get_base(1, transform); }
inline const Vec3d& get_z_base(const Transform3d &transform) { return get_base(2, transform); }
inline const Vec3d &get_x_base(const Transform3d::LinearPart &transform) { return get_base(0, transform); }
inline const Vec3d &get_y_base(const Transform3d::LinearPart &transform) { return get_base(1, transform); }
inline const Vec3d &get_z_base(const Transform3d::LinearPart &transform) { return get_base(2, transform); }
template<int N, class T> using Vec = Eigen::Matrix<T, N, 1, Eigen::DontAlign, N, 1>; template<int N, class T> using Vec = Eigen::Matrix<T, N, 1, Eigen::DontAlign, N, 1>;
class Point : public Vec2crd class Point : public Vec2crd

View File

@ -154,14 +154,13 @@ const IconManager::Icon &get_icon(const IconManager::VIcons& icons, IconType typ
static bool draw_button(const IconManager::VIcons& icons, IconType type, bool disable = false); static bool draw_button(const IconManager::VIcons& icons, IconType type, bool disable = false);
} // namespace priv } // namespace priv
CreateVolumeParams create_input(GLCanvas3D &canvas, StyleManager &styler, RaycastManager& raycaster, ModelVolumeType volume_type) CreateVolumeParams create_input(GLCanvas3D &canvas, const StyleManager::Style &style, RaycastManager& raycaster, ModelVolumeType volume_type)
{ {
auto gizmo = static_cast<unsigned char>(GLGizmosManager::Emboss); auto gizmo = static_cast<unsigned char>(GLGizmosManager::Emboss);
const GLVolume *gl_volume = get_first_hovered_gl_volume(canvas); const GLVolume *gl_volume = get_first_hovered_gl_volume(canvas);
const FontProp &fp = styler.get_style().prop;
Plater *plater = wxGetApp().plater(); Plater *plater = wxGetApp().plater();
return CreateVolumeParams{canvas, plater->get_camera(), plater->build_volume(), return CreateVolumeParams{canvas, plater->get_camera(), plater->build_volume(),
plater->get_ui_job_worker(), volume_type, raycaster, gizmo, gl_volume, fp.distance, fp.angle}; plater->get_ui_job_worker(), volume_type, raycaster, gizmo, gl_volume, style.distance, style.angle};
} }
bool GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mouse_pos) bool GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mouse_pos)
@ -171,7 +170,7 @@ bool GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
// NOTE: change style manager - be carefull with order changes // NOTE: change style manager - be carefull with order changes
DataBasePtr base = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel); DataBasePtr base = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
CreateVolumeParams input = create_input(m_parent, m_style_manager, m_raycast_manager, volume_type); CreateVolumeParams input = create_input(m_parent, m_style_manager.get_style(), m_raycast_manager, volume_type);
return start_create_volume(input, std::move(base), mouse_pos); return start_create_volume(input, std::move(base), mouse_pos);
} }
@ -183,7 +182,7 @@ bool GLGizmoEmboss::create_volume(ModelVolumeType volume_type)
// NOTE: change style manager - be carefull with order changes // NOTE: change style manager - be carefull with order changes
DataBasePtr base = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel); DataBasePtr base = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
CreateVolumeParams input = create_input(m_parent, m_style_manager, m_raycast_manager, volume_type); CreateVolumeParams input = create_input(m_parent, m_style_manager.get_style(), m_raycast_manager, volume_type);
return start_create_volume_without_position(input, std::move(base)); return start_create_volume_without_position(input, std::move(base));
} }
@ -197,9 +196,9 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
if (mouse_event.Dragging()) { if (mouse_event.Dragging()) {
if (!m_rotate_start_angle.has_value()) { if (!m_rotate_start_angle.has_value()) {
// when m_rotate_start_angle is not set mean it is not Dragging // when m_rotate_start_angle is not set mean it is not Dragging
// when angle_opt is not set mean angle is Zero // when angle_opt is not set than angle is Zero
const std::optional<float> &angle_opt = m_style_manager.get_font_prop().angle; const std::optional<float> &angle_opt = m_style_manager.get_font_prop().angle;
m_rotate_start_angle = angle_opt.has_value() ? *angle_opt : 0.f; m_rotate_start_angle = angle_opt.value_or(0.f);
} }
double angle = m_rotate_gizmo.get_angle(); double angle = m_rotate_gizmo.get_angle();
@ -269,7 +268,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
if (gl_volume == nullptr || !m_style_manager.is_active_font()) if (gl_volume == nullptr || !m_style_manager.is_active_font())
return res; return res;
m_style_manager.get_style().prop.angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit); m_style_manager.get_style().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
} }
} }
return res; return res;
@ -576,7 +575,7 @@ void GLGizmoEmboss::on_stop_dragging()
assert(m_style_manager.is_active_font()); assert(m_style_manager.is_active_font());
assert(gl_volume != nullptr); assert(gl_volume != nullptr);
if (m_style_manager.is_active_font() && gl_volume != nullptr) if (m_style_manager.is_active_font() && gl_volume != nullptr)
m_style_manager.get_font_prop().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit); m_style_manager.get_style().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
m_rotate_start_angle.reset(); m_rotate_start_angle.reset();
@ -754,6 +753,57 @@ EmbossStyles GLGizmoEmboss::create_default_styles()
void GLGizmoEmboss::set_default_text(){ m_text = _u8L("Embossed text"); } void GLGizmoEmboss::set_default_text(){ m_text = _u8L("Embossed text"); }
namespace {
/// <summary>
/// Throow ray by embossing params to object and find surface point
/// </summary>
/// <param name="gl_volume">Define embossed volume</param>
/// <param name="raycaster">Way to cast rays to object</param>
/// <param name="canvas">Contain model</param>
/// <returns>Calculated distance from surface</returns>
std::optional<float> calc_distance(const GLVolume &gl_volume, RaycastManager &raycaster, GLCanvas3D& canvas)
{
const ModelObject *object = get_model_object(gl_volume, canvas.get_model()->objects);
assert(object != nullptr);
if (object == nullptr)
return {};
const ModelInstance *instance = get_model_instance(gl_volume, *object);
const ModelVolume *volume = get_model_volume(gl_volume, *object);
assert(instance != nullptr && volume != nullptr);
if (object == nullptr || instance == nullptr || volume == nullptr)
return {};
if (volume->is_the_only_one_part())
return {};
const ModelVolumePtrs &volumes = object->volumes;
std::vector<size_t> allowed_volumes_id;
allowed_volumes_id.reserve(volumes.size() - 1);
for (const ModelVolume *v : volumes) {
// skip actual selected object
if (v->id() == volume->id())
continue;
// collect hit only from object parts not modifiers neither negative
if (!v->is_model_part())
continue;
allowed_volumes_id.emplace_back(v->id().id);
}
RaycastManager::AllowVolumes condition(std::move(allowed_volumes_id));
RaycastManager::Meshes meshes = create_meshes(canvas, condition);
raycaster.actualize(*instance, &condition, &meshes);
Transform3d w = gl_volume.world_matrix();
Vec3d p = w.translation();
const Vec3d& dir = get_z_base(w);
auto hit_opt = raycaster.first_hit(p, dir, &condition);
if (!hit_opt.has_value())
return {};
}
} // namespace
void GLGizmoEmboss::set_volume_by_selection() void GLGizmoEmboss::set_volume_by_selection()
{ {
const Selection &selection = m_parent.get_selection(); const Selection &selection = m_parent.get_selection();
@ -762,7 +812,7 @@ void GLGizmoEmboss::set_volume_by_selection()
return reset_volume(); return reset_volume();
const ModelObjectPtrs &objects = selection.get_model()->objects; const ModelObjectPtrs &objects = selection.get_model()->objects;
ModelVolume *volume =get_model_volume(*gl_volume, objects); ModelVolume *volume = get_model_volume(*gl_volume, objects);
if (volume == nullptr) if (volume == nullptr)
return reset_volume(); return reset_volume();
@ -774,15 +824,19 @@ void GLGizmoEmboss::set_volume_by_selection()
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 && m_volume != volume) // when update volume it changed id BUT not pointer
m_volume != volume) // when update volume it changed id BUT not pointer
ImGuiWrapper::left_inputs(); ImGuiWrapper::left_inputs();
// Is selected volume text volume? // Is selected volume text volume?
const std::optional<TextConfiguration>& tc_opt = volume->text_configuration; const std::optional<TextConfiguration> &tc_opt = volume->text_configuration;
if (!tc_opt.has_value()) if (!tc_opt.has_value())
return reset_volume(); return reset_volume();
// Emboss shape must be setted
assert(volume->emboss_shape.has_value());
if (!volume->emboss_shape.has_value())
return;
const TextConfiguration &tc = *tc_opt; const TextConfiguration &tc = *tc_opt;
const EmbossStyle &style = tc.style; const EmbossStyle &style = tc.style;
@ -791,7 +845,7 @@ void GLGizmoEmboss::set_volume_by_selection()
// Soo default value must be TRUE // Soo default value must be TRUE
bool is_font_installed = true; bool is_font_installed = true;
wxString face_name; wxString face_name;
std::optional<std::string> face_name_opt = style.prop.face_name; const std::optional<std::string> &face_name_opt = style.prop.face_name;
if (face_name_opt.has_value()) { if (face_name_opt.has_value()) {
face_name = wxString(face_name_opt->c_str()); face_name = wxString(face_name_opt->c_str());
@ -800,7 +854,7 @@ void GLGizmoEmboss::set_volume_by_selection()
init_face_names(m_face_names); init_face_names(m_face_names);
m_face_names.is_init = false; m_face_names.is_init = false;
auto cmp = [](const FaceName &fn, const wxString& face_name)->bool { return fn.wx_name < face_name; }; auto cmp = [](const FaceName &fn, const wxString &face_name) -> bool { return fn.wx_name < face_name; };
const std::vector<FaceName> &faces = m_face_names.faces; const std::vector<FaceName> &faces = m_face_names.faces;
auto it = std::lower_bound(faces.begin(), faces.end(), face_name, cmp); auto it = std::lower_bound(faces.begin(), faces.end(), face_name, cmp);
is_font_installed = it != faces.end() && it->wx_name == face_name; is_font_installed = it != faces.end() && it->wx_name == face_name;
@ -808,12 +862,11 @@ void GLGizmoEmboss::set_volume_by_selection()
if (!is_font_installed) { if (!is_font_installed) {
const std::vector<wxString> &bad = m_face_names.bad; const std::vector<wxString> &bad = m_face_names.bad;
auto it_bad = std::lower_bound(bad.begin(), bad.end(), face_name); auto it_bad = std::lower_bound(bad.begin(), bad.end(), face_name);
if (it_bad == bad.end() || *it_bad != face_name){ if (it_bad == bad.end() || *it_bad != face_name) {
// check if wx allowed to set it up - another encoding of name // check if wx allowed to set it up - another encoding of name
wxFontEnumerator::InvalidateCache(); wxFontEnumerator::InvalidateCache();
wxFont wx_font_; // temporary structure wxFont wx_font_; // temporary structure
if (wx_font_.SetFaceName(face_name) && if (wx_font_.SetFaceName(face_name) && WxFontUtils::create_font_file(wx_font_) != nullptr // can load TTF file?
WxFontUtils::create_font_file(wx_font_) != nullptr // can load TTF file?
) { ) {
is_font_installed = true; is_font_installed = true;
// QUESTION: add this name to allowed faces? // QUESTION: add this name to allowed faces?
@ -826,7 +879,7 @@ void GLGizmoEmboss::set_volume_by_selection()
wxFont wx_font; wxFont wx_font;
// load wxFont from same OS when font name is installed // load wxFont from same OS when font name is installed
if (style.type == WxFontUtils::get_actual_type() && is_font_installed) if (style.type == WxFontUtils::get_current_type() && is_font_installed)
wx_font = WxFontUtils::load_wxFont(style.path); wx_font = WxFontUtils::load_wxFont(style.path);
// Flag that is selected same font // Flag that is selected same font
@ -846,25 +899,28 @@ void GLGizmoEmboss::set_volume_by_selection()
assert(wx_font.IsOk()); assert(wx_font.IsOk());
// Load style to style manager // Load style to style manager
const auto& styles = m_style_manager.get_styles(); const auto &styles = m_style_manager.get_styles();
auto has_same_name = [&style](const StyleManager::Item &style_item) -> bool { auto has_same_name = [&name = style.name](const StyleManager::Style &style_item) { return style_item.name == name; };
const EmbossStyle &es = style_item.style;
return es.name == style.name; StyleManager::Style style_{style};
}; style_.projection = volume->emboss_shape->projection;
style_.angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
style_.distance = calc_distance(*gl_volume, m_raycast_manager, m_parent);
auto it = std::find_if(styles.begin(), styles.end(), has_same_name); auto it = std::find_if(styles.begin(), styles.end(), has_same_name);
if (it == styles.end()) { if (it == styles.end()) {
// style was not found // style was not found
m_style_manager.load_style(style, wx_font); m_style_manager.load_style(style_, wx_font);
} else { } else {
// style name is in styles list // style name is in styles list
size_t style_index = it - styles.begin(); size_t style_index = it - styles.begin();
if (!m_style_manager.load_style(style_index)) { if (!m_style_manager.load_style(style_index)) {
// can`t load stored style // can`t load stored style
m_style_manager.erase(style_index); m_style_manager.erase(style_index);
m_style_manager.load_style(style, wx_font); m_style_manager.load_style(style_, wx_font);
} else { } else {
// stored style is loaded, now set modification of style // stored style is loaded, now set modification of style
m_style_manager.get_style() = style; m_style_manager.get_style() = style_;
m_style_manager.set_wx_font(wx_font); m_style_manager.set_wx_font(wx_font);
} }
} }
@ -890,11 +946,6 @@ void GLGizmoEmboss::set_volume_by_selection()
m_volume = volume; m_volume = volume;
m_volume_id = volume->id(); m_volume_id = volume->id();
// Calculate current angle of up vector
assert(m_style_manager.is_active_font());
if (m_style_manager.is_active_font())
m_style_manager.get_font_prop().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
// calculate scale for height and depth inside of scaled object instance // calculate scale for height and depth inside of scaled object instance
calculate_scale(); calculate_scale();
} }
@ -1859,13 +1910,9 @@ void GLGizmoEmboss::draw_style_rename_popup() {
std::string text_in_popup = GUI::format(_L("Rename style(%1%) for embossing text: "), old_name); std::string text_in_popup = GUI::format(_L("Rename style(%1%) for embossing text: "), old_name);
ImGui::Text("%s", text_in_popup.c_str()); ImGui::Text("%s", text_in_popup.c_str());
bool is_unique = true; bool is_unique = (new_name == old_name) || // could be same as before rename
for (const auto &item : m_style_manager.get_styles()) { m_style_manager.is_unique_style_name(new_name);
const EmbossStyle &style = item.style;
if (&style == &m_style_manager.get_style())
continue; // could be same as original name
if (style.name == new_name) is_unique = false;
}
bool allow_change = false; bool allow_change = false;
if (new_name.empty()) { if (new_name.empty()) {
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_DARK, _u8L("Name can't be empty.")); m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_DARK, _u8L("Name can't be empty."));
@ -1946,11 +1993,7 @@ void GLGizmoEmboss::draw_style_save_as_popup() {
// use name inside of volume configuration as temporary new name // use name inside of volume configuration as temporary new name
std::string &new_name = m_volume->text_configuration->style.name; std::string &new_name = m_volume->text_configuration->style.name;
bool is_unique = m_style_manager.is_unique_style_name(new_name);
bool is_unique = true;
for (const auto &item : m_style_manager.get_styles())
if (item.style.name == new_name) is_unique = false;
bool allow_change = false; bool allow_change = false;
if (new_name.empty()) { if (new_name.empty()) {
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_DARK, _u8L("Name can't be empty.")); m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_DARK, _u8L("Name can't be empty."));
@ -1988,7 +2031,7 @@ void GLGizmoEmboss::draw_style_add_button()
bool only_add_style = !m_style_manager.exist_stored_style(); bool only_add_style = !m_style_manager.exist_stored_style();
bool can_add = true; bool can_add = true;
if (only_add_style && if (only_add_style &&
m_volume->text_configuration->style.type != WxFontUtils::get_actual_type()) m_volume->text_configuration->style.type != WxFontUtils::get_current_type())
can_add = false; can_add = false;
std::string title = _u8L("Save as new style"); std::string title = _u8L("Save as new style");
@ -2080,46 +2123,46 @@ void GLGizmoEmboss::draw_delete_style_button() {
} }
} }
// FIX IT: it should not change volume position before successfull change namespace {
void GLGizmoEmboss::fix_transformation(const FontProp &from, // FIX IT: It should not change volume position before successfull change volume by process
const FontProp &to) void fix_transformation(const StyleManager::Style &from, const StyleManager::Style &to, GLCanvas3D &canvas) {
{
// fix Z rotation when exists difference in styles // fix Z rotation when exists difference in styles
const std::optional<float> &f_angle_opt = from.angle; const std::optional<float> &f_angle_opt = from.angle;
const std::optional<float> &t_angle_opt = to.angle; const std::optional<float> &t_angle_opt = to.angle;
if (!is_approx(f_angle_opt, t_angle_opt)) { if (!is_approx(f_angle_opt, t_angle_opt)) {
// fix rotation // fix rotation
float f_angle = f_angle_opt.has_value() ? *f_angle_opt : .0f; float f_angle = f_angle_opt.value_or(.0f);
float t_angle = t_angle_opt.has_value() ? *t_angle_opt : .0f; float t_angle = t_angle_opt.value_or(.0f);
do_local_z_rotate(m_parent, t_angle - f_angle); do_local_z_rotate(canvas, t_angle - f_angle);
} }
// fix distance (Z move) when exists difference in styles // fix distance (Z move) when exists difference in styles
const std::optional<float> &f_move_opt = from.distance; const std::optional<float> &f_move_opt = from.distance;
const std::optional<float> &t_move_opt = to.distance; const std::optional<float> &t_move_opt = to.distance;
if (!is_approx(f_move_opt, t_move_opt)) { if (!is_approx(f_move_opt, t_move_opt)) {
float f_move = f_move_opt.has_value() ? *f_move_opt : .0f; float f_move = f_move_opt.value_or(.0f);
float t_move = t_move_opt.has_value() ? *t_move_opt : .0f; float t_move = t_move_opt.value_or(.0f);
do_local_z_move(m_parent, t_move - f_move); do_local_z_move(canvas, t_move - f_move);
} }
} }
} // namesapce
void GLGizmoEmboss::draw_style_list() { void GLGizmoEmboss::draw_style_list() {
if (!m_style_manager.is_active_font()) return; if (!m_style_manager.is_active_font()) return;
const EmbossStyle *stored_style = nullptr; const StyleManager::Style *stored_style = nullptr;
bool is_stored = m_style_manager.exist_stored_style(); bool is_stored = m_style_manager.exist_stored_style();
if (is_stored) if (is_stored)
stored_style = m_style_manager.get_stored_style(); stored_style = m_style_manager.get_stored_style();
const EmbossStyle &actual_style = m_style_manager.get_style(); const StyleManager::Style &current_style = m_style_manager.get_style();
bool is_changed = (stored_style)? !(*stored_style == actual_style) : true; bool is_changed = (stored_style)? !(*stored_style == current_style) : true;
bool is_modified = is_stored && is_changed; bool is_modified = is_stored && is_changed;
const float &max_style_name_width = m_gui_cfg->max_style_name_width; const float &max_style_name_width = m_gui_cfg->max_style_name_width;
std::string &trunc_name = m_style_manager.get_truncated_name(); std::string &trunc_name = m_style_manager.get_truncated_name();
if (trunc_name.empty()) { if (trunc_name.empty()) {
// generate trunc name // generate trunc name
std::string current_name = actual_style.name; std::string current_name = current_style.name;
ImGuiWrapper::escape_double_hash(current_name); ImGuiWrapper::escape_double_hash(current_name);
trunc_name = ImGuiWrapper::trunc(current_name, max_style_name_width); trunc_name = ImGuiWrapper::trunc(current_name, max_style_name_width);
} }
@ -2140,19 +2183,19 @@ void GLGizmoEmboss::draw_style_list() {
m_style_manager.init_style_images(m_gui_cfg->max_style_image_size, m_text); m_style_manager.init_style_images(m_gui_cfg->max_style_image_size, m_text);
m_style_manager.init_trunc_names(max_style_name_width); m_style_manager.init_trunc_names(max_style_name_width);
std::optional<std::pair<size_t,size_t>> swap_indexes; std::optional<std::pair<size_t,size_t>> swap_indexes;
const std::vector<StyleManager::Item> &styles = m_style_manager.get_styles(); const StyleManager::Styles &styles = m_style_manager.get_styles();
for (const auto &item : styles) { for (const StyleManager::Style &style : styles) {
size_t index = &item - &styles.front(); size_t index = &style - &styles.front();
const EmbossStyle &style = item.style;
const std::string &actual_style_name = style.name; const std::string &actual_style_name = style.name;
ImGui::PushID(actual_style_name.c_str()); ImGui::PushID(actual_style_name.c_str());
bool is_selected = (index == m_style_manager.get_style_index()); bool is_selected = (index == m_style_manager.get_style_index());
ImVec2 select_size(0,m_gui_cfg->max_style_image_size.y()); // 0,0 --> calculate in draw float select_height = static_cast<float>(m_gui_cfg->max_style_image_size.y());
const std::optional<StyleManager::StyleImage> &img = item.image; ImVec2 select_size(0.f, select_height); // 0,0 --> calculate in draw
const std::optional<StyleManager::StyleImage> &img = style.image;
// allow click delete button // allow click delete button
ImGuiSelectableFlags_ flags = ImGuiSelectableFlags_AllowItemOverlap; ImGuiSelectableFlags_ flags = ImGuiSelectableFlags_AllowItemOverlap;
if (ImGui::Selectable(item.truncated_name.c_str(), is_selected, flags, select_size)) { if (ImGui::Selectable(style.truncated_name.c_str(), is_selected, flags, select_size)) {
selected_style_index = index; selected_style_index = index;
} else if (ImGui::IsItemHovered()) } else if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", actual_style_name.c_str()); ImGui::SetTooltip("%s", actual_style_name.c_str());
@ -2184,10 +2227,10 @@ void GLGizmoEmboss::draw_style_list() {
// do not keep in memory style images when no combo box open // do not keep in memory style images when no combo box open
m_style_manager.free_style_images(); m_style_manager.free_style_images();
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
std::string style_name = add_text_modify(actual_style.name); std::string style_name = add_text_modify(current_style.name);
std::string tooltip = is_modified? std::string tooltip = is_modified?
GUI::format(_L("Modified style \"%1%\""), actual_style.name): GUI::format(_L("Modified style \"%1%\""), current_style.name):
GUI::format(_L("Current style is \"%1%\""), actual_style.name); GUI::format(_L("Current style is \"%1%\""), current_style.name);
ImGui::SetTooltip(" %s", tooltip.c_str()); ImGui::SetTooltip(" %s", tooltip.c_str());
} }
} }
@ -2195,7 +2238,7 @@ void GLGizmoEmboss::draw_style_list() {
// Check whether user wants lose actual style modification // Check whether user wants lose actual style modification
if (selected_style_index.has_value() && is_modified) { if (selected_style_index.has_value() && is_modified) {
wxString title = _L("Style modification will be lost."); wxString title = _L("Style modification will be lost.");
const EmbossStyle &style = m_style_manager.get_styles()[*selected_style_index].style; const EmbossStyle &style = m_style_manager.get_styles()[*selected_style_index];
wxString message = GUI::format_wxstr(_L("Changing style to '%1%' will discard current style modification.\n\n Would you like to continue anyway?"), style.name); wxString message = GUI::format_wxstr(_L("Changing style to '%1%' will discard current style modification.\n\n Would you like to continue anyway?"), style.name);
MessageDialog not_loaded_style_message(nullptr, message, title, wxICON_WARNING | wxYES|wxNO); MessageDialog not_loaded_style_message(nullptr, message, title, wxICON_WARNING | wxYES|wxNO);
if (not_loaded_style_message.ShowModal() != wxID_YES) if (not_loaded_style_message.ShowModal() != wxID_YES)
@ -2204,12 +2247,12 @@ void GLGizmoEmboss::draw_style_list() {
// selected style from combo box // selected style from combo box
if (selected_style_index.has_value()) { if (selected_style_index.has_value()) {
const EmbossStyle &style = m_style_manager.get_styles()[*selected_style_index].style; const StyleManager::Style &style = m_style_manager.get_styles()[*selected_style_index];
// create copy to be able do fix transformation only when successfully load style // create copy to be able do fix transformation only when successfully load style
FontProp act_prop = actual_style.prop; // copy StyleManager::Style cur_s = current_style; // copy
FontProp new_prop = style.prop; // copy StyleManager::Style new_s = style; // copy
if (m_style_manager.load_style(*selected_style_index)) { if (m_style_manager.load_style(*selected_style_index)) {
fix_transformation(act_prop, new_prop); ::fix_transformation(cur_s, new_s, m_parent);
process(); process();
} else { } else {
wxString title = _L("Not valid style."); wxString title = _L("Not valid style.");
@ -2667,11 +2710,10 @@ void GLGizmoEmboss::draw_advanced()
return; return;
} }
FontProp &font_prop = m_style_manager.get_style().prop; StyleManager::Style &current_style = m_style_manager.get_style();
const auto &cn = m_style_manager.get_font_prop().collection_number; FontProp &current_prop = current_style.prop;
unsigned int font_index = (cn.has_value()) ? *cn : 0;
const auto &font_info = ff.font_file->infos[font_index];
const FontFile::Info &font_info = ff.font_file->infos[current_prop.collection_number.value_or(0)];
#ifdef SHOW_FONT_FILE_PROPERTY #ifdef SHOW_FONT_FILE_PROPERTY
ImGui::SameLine(); ImGui::SameLine();
int cache_size = ff.has_value()? (int)ff.cache->size() : 0; int cache_size = ff.has_value()? (int)ff.cache->size() : 0;
@ -2682,8 +2724,8 @@ void GLGizmoEmboss::draw_advanced()
", unitPerEm=" + std::to_string(font_info.unit_per_em) + ", unitPerEm=" + std::to_string(font_info.unit_per_em) +
", cache(" + std::to_string(cache_size) + " glyphs)"; ", cache(" + std::to_string(cache_size) + " glyphs)";
if (font_file->infos.size() > 1) { if (font_file->infos.size() > 1) {
unsigned int collection = font_prop.collection_number.has_value() ? unsigned int collection = current_prop.collection_number.has_value() ?
*font_prop.collection_number : 0; *current_prop.collection_number : 0;
ff_property += ", collect=" + std::to_string(collection+1) + "/" + std::to_string(font_file->infos.size()); ff_property += ", collect=" + std::to_string(collection+1) + "/" + std::to_string(font_file->infos.size());
} }
m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property); m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property);
@ -2692,26 +2734,22 @@ void GLGizmoEmboss::draw_advanced()
bool exist_change = false; bool exist_change = false;
auto &tr = m_gui_cfg->translations; auto &tr = m_gui_cfg->translations;
const EmbossStyle *stored_style = nullptr; const StyleManager::Style *stored_style = nullptr;
if (m_style_manager.exist_stored_style()) if (m_style_manager.exist_stored_style())
stored_style = m_style_manager.get_stored_style(); stored_style = m_style_manager.get_stored_style();
bool can_use_surface = (m_volume==nullptr)? false : bool can_use_surface = (m_volume == nullptr)? false :
(font_prop.use_surface)? true : // already used surface must have option to uncheck (m_volume->emboss_shape->projection.use_surface)? true : // already used surface must have option to uncheck
(m_volume->get_object()->volumes.size() > 1); !m_volume->is_the_only_one_part();
m_imgui->disabled_begin(!can_use_surface); m_imgui->disabled_begin(!can_use_surface);
const bool *def_use_surface = stored_style ? const bool *def_use_surface = stored_style ?
&stored_style->prop.use_surface : nullptr; &stored_style->projection.use_surface : nullptr;
if (rev_checkbox(tr.use_surface, font_prop.use_surface, def_use_surface, bool &use_surface = current_style.projection.use_surface;
if (rev_checkbox(tr.use_surface, use_surface, def_use_surface,
_u8L("Revert using of model surface."))) { _u8L("Revert using of model surface."))) {
if (font_prop.use_surface) { if (use_surface)
// when using surface distance is not used // when using surface distance is not used
font_prop.distance.reset(); current_style.distance.reset();
// there should be minimal embossing depth
if (font_prop.emboss < 0.1)
font_prop.emboss = 1;
}
process(); process();
} }
m_imgui->disabled_end(); // !can_use_surface m_imgui->disabled_end(); // !can_use_surface
@ -2724,13 +2762,14 @@ void GLGizmoEmboss::draw_advanced()
&stored_style->prop.char_gap : nullptr; &stored_style->prop.char_gap : nullptr;
int half_ascent = font_info.ascent / 2; int half_ascent = font_info.ascent / 2;
int min_char_gap = -half_ascent, max_char_gap = half_ascent; int min_char_gap = -half_ascent;
if (rev_slider(tr.char_gap, font_prop.char_gap, def_char_gap, _u8L("Revert gap between letters"), int max_char_gap = half_ascent;
if (rev_slider(tr.char_gap, current_prop.char_gap, def_char_gap, _u8L("Revert gap between letters"),
min_char_gap, max_char_gap, units_fmt, _L("Distance between letters"))){ min_char_gap, max_char_gap, units_fmt, _L("Distance between letters"))){
// Condition prevent recalculation when insertint out of limits value by imgui input // Condition prevent recalculation when insertint out of limits value by imgui input
if (!apply(font_prop.char_gap, priv::limits.char_gap) || const std::optional<int> &volume_char_gap = m_volume->text_configuration->style.prop.char_gap;
!m_volume->text_configuration->style.prop.char_gap.has_value() || if (!apply(current_prop.char_gap, priv::limits.char_gap) ||
m_volume->text_configuration->style.prop.char_gap != font_prop.char_gap) { !volume_char_gap.has_value() || volume_char_gap != current_prop.char_gap) {
// char gap is stored inside of imgui font atlas // char gap is stored inside of imgui font atlas
m_style_manager.clear_imgui_font(); m_style_manager.clear_imgui_font();
exist_change = true; exist_change = true;
@ -2740,13 +2779,14 @@ void GLGizmoEmboss::draw_advanced()
// input gap between lines // input gap between lines
auto def_line_gap = stored_style ? auto def_line_gap = stored_style ?
&stored_style->prop.line_gap : nullptr; &stored_style->prop.line_gap : nullptr;
int min_line_gap = -half_ascent, max_line_gap = half_ascent; int min_line_gap = -half_ascent;
if (rev_slider(tr.line_gap, font_prop.line_gap, def_line_gap, _u8L("Revert gap between lines"), int max_line_gap = half_ascent;
if (rev_slider(tr.line_gap, current_prop.line_gap, def_line_gap, _u8L("Revert gap between lines"),
min_line_gap, max_line_gap, units_fmt, _L("Distance between lines"))){ min_line_gap, max_line_gap, units_fmt, _L("Distance between lines"))){
// Condition prevent recalculation when insertint out of limits value by imgui input // Condition prevent recalculation when insertint out of limits value by imgui input
if (!apply(font_prop.line_gap, priv::limits.line_gap) || const std::optional<int> &volume_line_gap = m_volume->text_configuration->style.prop.line_gap;
!m_volume->text_configuration->style.prop.line_gap.has_value() || if (!apply(current_prop.line_gap, priv::limits.line_gap) ||
m_volume->text_configuration->style.prop.line_gap != font_prop.line_gap) { !volume_line_gap.has_value() || volume_line_gap != current_prop.line_gap) {
// line gap is planed to be stored inside of imgui font atlas // line gap is planed to be stored inside of imgui font atlas
m_style_manager.clear_imgui_font(); m_style_manager.clear_imgui_font();
exist_change = true; exist_change = true;
@ -2756,37 +2796,34 @@ void GLGizmoEmboss::draw_advanced()
// input boldness // input boldness
auto def_boldness = stored_style ? auto def_boldness = stored_style ?
&stored_style->prop.boldness : nullptr; &stored_style->prop.boldness : nullptr;
if (rev_slider(tr.boldness, font_prop.boldness, def_boldness, _u8L("Undo boldness"), if (rev_slider(tr.boldness, current_prop.boldness, def_boldness, _u8L("Undo boldness"),
priv::limits.boldness.gui.min, priv::limits.boldness.gui.max, units_fmt, _L("Tiny / Wide glyphs"))){ priv::limits.boldness.gui.min, priv::limits.boldness.gui.max, units_fmt, _L("Tiny / Wide glyphs"))){
if (!apply(font_prop.boldness, priv::limits.boldness.values) || const std::optional<float> &volume_boldness = m_volume->text_configuration->style.prop.boldness;
!m_volume->text_configuration->style.prop.boldness.has_value() || if (!apply(current_prop.boldness, priv::limits.boldness.values) ||
m_volume->text_configuration->style.prop.boldness != font_prop.boldness) !volume_boldness.has_value() || volume_boldness != current_prop.boldness)
exist_change = true; exist_change = true;
} }
// input italic // input italic
auto def_skew = stored_style ? auto def_skew = stored_style ?
&stored_style->prop.skew : nullptr; &stored_style->prop.skew : nullptr;
if (rev_slider(tr.skew_ration, font_prop.skew, def_skew, _u8L("Undo letter's skew"), if (rev_slider(tr.skew_ration, current_prop.skew, def_skew, _u8L("Undo letter's skew"),
priv::limits.skew.gui.min, priv::limits.skew.gui.max, "%.2f", _L("Italic strength ratio"))){ priv::limits.skew.gui.min, priv::limits.skew.gui.max, "%.2f", _L("Italic strength ratio"))){
if (!apply(font_prop.skew, priv::limits.skew.values) || const std::optional<float> &volume_skew = m_volume->text_configuration->style.prop.skew;
!m_volume->text_configuration->style.prop.skew.has_value() || if (!apply(current_prop.skew, priv::limits.skew.values) ||
m_volume->text_configuration->style.prop.skew != font_prop.skew) !volume_skew.has_value() ||volume_skew != current_prop.skew)
exist_change = true; exist_change = true;
} }
// input surface distance // input surface distance
bool allowe_surface_distance = bool allowe_surface_distance = !use_surface && !m_volume->is_the_only_one_part();
!m_volume->text_configuration->style.prop.use_surface && std::optional<float> &distance = current_style.distance;
!m_volume->is_the_only_one_part(); float prev_distance = distance.value_or(.0f);
std::optional<float> &distance = font_prop.distance; float min_distance = static_cast<float>(-2 * current_style.projection.depth);
float prev_distance = distance.has_value() ? *distance : .0f, float max_distance = static_cast<float>(2 * current_style.projection.depth);
min_distance = -2 * font_prop.emboss,
max_distance = 2 * font_prop.emboss;
auto def_distance = stored_style ? auto def_distance = stored_style ?
&stored_style->prop.distance : nullptr; &stored_style->distance : nullptr;
m_imgui->disabled_begin(!allowe_surface_distance); m_imgui->disabled_begin(!allowe_surface_distance);
bool use_inch = wxGetApp().app_config->get_bool("use_inches"); bool use_inch = wxGetApp().app_config->get_bool("use_inches");
const std::string undo_move_tooltip = _u8L("Undo translation"); const std::string undo_move_tooltip = _u8L("Undo translation");
const wxString move_tooltip = _L("Distance of the center of text from model surface"); const wxString move_tooltip = _L("Distance of the center of text from model surface");
@ -2803,9 +2840,9 @@ void GLGizmoEmboss::draw_advanced()
max_distance *= ObjectManipulation::mm_to_in; max_distance *= ObjectManipulation::mm_to_in;
if (rev_slider(tr.from_surface, distance_inch, def_distance, undo_move_tooltip, min_distance, max_distance, "%.3f in", move_tooltip)) { if (rev_slider(tr.from_surface, distance_inch, def_distance, undo_move_tooltip, min_distance, max_distance, "%.3f in", move_tooltip)) {
if (distance_inch.has_value()) { if (distance_inch.has_value()) {
font_prop.distance = *distance_inch * ObjectManipulation::in_to_mm; distance = *distance_inch * ObjectManipulation::in_to_mm;
} else { } else {
font_prop.distance.reset(); distance.reset();
} }
is_moved = true; is_moved = true;
} }
@ -2814,23 +2851,19 @@ void GLGizmoEmboss::draw_advanced()
min_distance, max_distance, "%.2f mm", move_tooltip)) is_moved = true; min_distance, max_distance, "%.2f mm", move_tooltip)) is_moved = true;
} }
if (is_moved){ if (is_moved)
m_volume->text_configuration->style.prop.distance = font_prop.distance; do_local_z_move(m_parent, distance.value_or(.0f) - prev_distance);
float act_distance = font_prop.distance.has_value() ? *font_prop.distance : .0f; m_imgui->disabled_end(); // allowe_surface_distance
do_local_z_move(m_parent, act_distance - prev_distance);
}
m_imgui->disabled_end();
// slider for Clock-wise angle in degress // slider for Clock-wise angle in degress
// stored angle is optional CCW and in radians // stored angle is optional CCW and in radians
// Convert stored value to degress // Convert stored value to degress
// minus create clock-wise roation from CCW // minus create clock-wise roation from CCW
const std::optional<float> &angle_opt = m_style_manager.get_font_prop().angle; float angle = current_style.angle.value_or(0.f);
float angle = angle_opt.has_value() ? *angle_opt: 0.f;
float angle_deg = static_cast<float>(-angle * 180 / M_PI); float angle_deg = static_cast<float>(-angle * 180 / M_PI);
float def_angle_deg_val = float def_angle_deg_val =
(!stored_style || !stored_style->prop.angle.has_value()) ? (!stored_style || !stored_style->angle.has_value()) ?
0.f : (*stored_style->prop.angle * -180 / M_PI); 0.f : (*stored_style->angle * -180 / M_PI);
float* def_angle_deg = stored_style ? float* def_angle_deg = stored_style ?
&def_angle_deg_val : nullptr; &def_angle_deg_val : nullptr;
if (rev_slider(tr.rotation, angle_deg, def_angle_deg, _u8L("Undo rotation"), if (rev_slider(tr.rotation, angle_deg, def_angle_deg, _u8L("Undo rotation"),
@ -2848,21 +2881,16 @@ void GLGizmoEmboss::draw_advanced()
assert(gl_volume != nullptr); assert(gl_volume != nullptr);
assert(m_style_manager.is_active_font()); assert(m_style_manager.is_active_font());
if (m_style_manager.is_active_font() && gl_volume != nullptr) if (m_style_manager.is_active_font() && gl_volume != nullptr)
m_style_manager.get_font_prop().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit); m_style_manager.get_style().angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
// recalculate for surface cut // recalculate for surface cut
if (font_prop.use_surface) if (use_surface)
process(); process();
} }
ImGui::Text("%s", tr.keep_up.c_str()); ImGui::Text("%s", tr.keep_up.c_str());
ImGui::SameLine(m_gui_cfg->advanced_input_offset); ImGui::SameLine(m_gui_cfg->advanced_input_offset);
if (ImGui::Checkbox("##keep_up", &m_keep_up)) { ImGui::Checkbox("##keep_up", &m_keep_up);
if (m_keep_up) {
// copy angle to volume
m_volume->text_configuration->style.prop.angle = font_prop.angle;
}
}
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", _u8L("Keep text orientation during surface dragging.\nNot stable between horizontal and vertical alignment.").c_str()); ImGui::SetTooltip("%s", _u8L("Keep text orientation during surface dragging.\nNot stable between horizontal and vertical alignment.").c_str());
@ -2871,15 +2899,15 @@ void GLGizmoEmboss::draw_advanced()
ImGui::Text("%s", tr.collection.c_str()); ImGui::Text("%s", tr.collection.c_str());
ImGui::SameLine(m_gui_cfg->advanced_input_offset); ImGui::SameLine(m_gui_cfg->advanced_input_offset);
ImGui::SetNextItemWidth(m_gui_cfg->input_width); ImGui::SetNextItemWidth(m_gui_cfg->input_width);
unsigned int selected = font_prop.collection_number.has_value() ? unsigned int selected = current_prop.collection_number.has_value() ?
*font_prop.collection_number : 0; *current_prop.collection_number : 0;
if (ImGui::BeginCombo("## Font collection", std::to_string(selected).c_str())) { if (ImGui::BeginCombo("## Font collection", std::to_string(selected).c_str())) {
for (unsigned int i = 0; i < ff.font_file->infos.size(); ++i) { for (unsigned int i = 0; i < ff.font_file->infos.size(); ++i) {
ImGui::PushID(1 << (10 + i)); ImGui::PushID(1 << (10 + i));
bool is_selected = (i == selected); bool is_selected = (i == selected);
if (ImGui::Selectable(std::to_string(i).c_str(), is_selected)) { if (ImGui::Selectable(std::to_string(i).c_str(), is_selected)) {
if (i == 0) font_prop.collection_number.reset(); if (i == 0) current_prop.collection_number.reset();
else font_prop.collection_number = i; else current_prop.collection_number = i;
exist_change = true; exist_change = true;
} }
ImGui::PopID(); ImGui::PopID();
@ -2898,24 +2926,23 @@ void GLGizmoEmboss::draw_advanced()
if (ImGui::Button(_u8L("Set text to face camera").c_str())) { if (ImGui::Button(_u8L("Set text to face camera").c_str())) {
assert(get_selected_volume(m_parent.get_selection()) == m_volume); assert(get_selected_volume(m_parent.get_selection()) == m_volume);
const Camera &cam = wxGetApp().plater()->get_camera(); const Camera &cam = wxGetApp().plater()->get_camera();
bool use_surface = m_style_manager.get_style().prop.use_surface;
if (face_selected_volume_to_camera(cam, m_parent) && use_surface) if (face_selected_volume_to_camera(cam, m_parent) && use_surface)
process(); process();
} else if (ImGui::IsItemHovered()) { } else if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", _u8L("Use camera direction for text orientation").c_str()); ImGui::SetTooltip("%s", _u8L("Use camera direction for text orientation").c_str());
} }
#ifdef ALLOW_DEBUG_MODE #ifdef ALLOW_DEBUG_MODE
ImGui::Text("family = %s", (font_prop.family.has_value() ? ImGui::Text("family = %s", (current_prop.family.has_value() ?
font_prop.family->c_str() : current_prop.family->c_str() :
" --- ")); " --- "));
ImGui::Text("face name = %s", (font_prop.face_name.has_value() ? ImGui::Text("face name = %s", (current_prop.face_name.has_value() ?
font_prop.face_name->c_str() : current_prop.face_name->c_str() :
" --- ")); " --- "));
ImGui::Text("style = %s", ImGui::Text("style = %s",
(font_prop.style.has_value() ? font_prop.style->c_str() : (current_prop.style.has_value() ? current_prop.style->c_str() :
" --- ")); " --- "));
ImGui::Text("weight = %s", (font_prop.weight.has_value() ? ImGui::Text("weight = %s", (current_prop.weight.has_value() ?
font_prop.weight->c_str() : current_prop.weight->c_str() :
" --- ")); " --- "));
std::string descriptor = style.path; std::string descriptor = style.path;
@ -2961,7 +2988,7 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
data.RestrictSelection(wxFONTRESTRICT_SCALABLE); data.RestrictSelection(wxFONTRESTRICT_SCALABLE);
// set previous selected font // set previous selected font
EmbossStyle &selected_style = m_style_manager.get_style(); EmbossStyle &selected_style = m_style_manager.get_style();
if (selected_style.type == WxFontUtils::get_actual_type()) { if (selected_style.type == WxFontUtils::get_current_type()) {
std::optional<wxFont> selected_font = WxFontUtils::load_wxFont( std::optional<wxFont> selected_font = WxFontUtils::load_wxFont(
selected_style.path); selected_style.path);
if (selected_font.has_value()) data.SetInitialFont(*selected_font); if (selected_font.has_value()) data.SetInitialFont(*selected_font);
@ -3179,9 +3206,9 @@ priv::TextDataBase::TextDataBase(DataBase &&parent, const FontFileWithCache &fon
// partialy fill shape from text configuration // partialy fill shape from text configuration
const FontProp &fp = this->text_configuration.style.prop; const FontProp &fp = this->text_configuration.style.prop;
shape.depth = fp.emboss; EmbossProjection &p = shape.projection;
shape.use_surface = fp.use_surface; p.depth = fp.emboss;
shape.distance = fp.distance; p.use_surface = fp.use_surface;
const FontFile &ff = *this->font_file.font_file; const FontFile &ff = *this->font_file.font_file;
shape.scale = get_text_shape_scale(fp, ff); shape.scale = get_text_shape_scale(fp, ff);
@ -3219,8 +3246,8 @@ void priv::TextDataBase::write(ModelVolume &volume) const
volume.text_configuration->style.prop.angle.reset(); volume.text_configuration->style.prop.angle.reset();
// only temporary solution // only temporary solution
volume.text_configuration->style.prop.use_surface = shape.use_surface; volume.text_configuration->style.prop.use_surface = shape.projection.use_surface; // copy
volume.text_configuration->style.prop.distance = shape.distance; volume.text_configuration->style.prop.emboss = static_cast<float>(shape.projection.depth); // copy
DataBase::write(volume); DataBase::write(volume);
} }

View File

@ -32,7 +32,7 @@ namespace Slic3r::GUI {
class GLGizmoEmboss : public GLGizmoBase class GLGizmoEmboss : public GLGizmoBase
{ {
public: public:
GLGizmoEmboss(GLCanvas3D& parent); explicit GLGizmoEmboss(GLCanvas3D& parent);
/// <summary> /// <summary>
/// Create new embossed text volume by type on position of mouse /// Create new embossed text volume by type on position of mouse
@ -51,8 +51,8 @@ protected:
bool on_init() override; bool on_init() override;
std::string on_get_name() const override; std::string on_get_name() const override;
void on_render() override; void on_render() override;
virtual void on_register_raycasters_for_picking() override; void on_register_raycasters_for_picking() override;
virtual void on_unregister_raycasters_for_picking() override; void on_unregister_raycasters_for_picking() override;
void on_render_input_window(float x, float y, float bottom_limit) override; void on_render_input_window(float x, float y, float bottom_limit) override;
bool on_is_activable() const override { return true; } bool on_is_activable() const override { return true; }
bool on_is_selectable() const override { return false; } bool on_is_selectable() const override { return false; }
@ -90,7 +90,6 @@ private:
void draw_window(); void draw_window();
void draw_text_input(); void draw_text_input();
void draw_model_type(); void draw_model_type();
void fix_transformation(const FontProp &from, const FontProp &to);
void draw_style_list(); void draw_style_list();
void draw_delete_style_button(); void draw_delete_style_button();
void draw_style_rename_popup(); void draw_style_rename_popup();
@ -308,8 +307,8 @@ private:
// Keep data about dragging only during drag&drop // Keep data about dragging only during drag&drop
std::optional<SurfaceDrag> m_surface_drag; std::optional<SurfaceDrag> m_surface_drag;
// TODO: it should be accessible by other gizmo too. // Keep old scene triangle data in AABB trees,
// May be move to plater? // all the time it need actualize before use.
RaycastManager m_raycast_manager; RaycastManager m_raycast_manager;
// For text on scaled objects // For text on scaled objects

View File

@ -398,7 +398,7 @@ void GLGizmoSVG::on_stop_dragging()
// recalculate for surface cut // recalculate for surface cut
if (m_volume != nullptr && if (m_volume != nullptr &&
m_volume->emboss_shape.has_value() && m_volume->emboss_shape.has_value() &&
m_volume->emboss_shape->use_surface) m_volume->emboss_shape->projection.use_surface)
process(); process();
} }
void GLGizmoSVG::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(data); } void GLGizmoSVG::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(data); }
@ -710,9 +710,8 @@ ExPolygons priv::default_shape() {
EmbossShape priv::select_shape() { EmbossShape priv::select_shape() {
EmbossShape shape; EmbossShape shape;
shape.depth = 10.; shape.projection.depth = 10.;
shape.distance = 0; shape.projection.use_surface = false;
shape.use_surface = false;
shape.svg_file_path = choose_svg_file(); shape.svg_file_path = choose_svg_file();
if (shape.svg_file_path.empty()) if (shape.svg_file_path.empty())

View File

@ -825,10 +825,10 @@ void update_volume(TriangleMesh &&mesh, const DataUpdate &data, const Transform3
volume->set_transformation(*tr); volume->set_transformation(*tr);
} else { } else {
// apply fix matrix made by store to .3mf // apply fix matrix made by store to .3mf
const auto &tc = volume->text_configuration; const std::optional<EmbossShape> &emboss_shape = volume->emboss_shape;
assert(tc.has_value()); assert(emboss_shape.has_value());
if (tc.has_value() && tc->fix_3mf_tr.has_value()) if (emboss_shape.has_value() && emboss_shape->fix_3mf_tr.has_value())
volume->set_transformation(volume->get_matrix() * tc->fix_3mf_tr->inverse()); volume->set_transformation(volume->get_matrix() * emboss_shape->fix_3mf_tr->inverse());
} }
UpdateJob::update_volume(volume, std::move(mesh), *data.base); UpdateJob::update_volume(volume, std::move(mesh), *data.base);

View File

@ -37,8 +37,8 @@ class DataBase
public: public:
DataBase(const std::string& volume_name, std::shared_ptr<std::atomic<bool>> cancel) : volume_name(volume_name), cancel(std::move(cancel)) {} DataBase(const std::string& volume_name, std::shared_ptr<std::atomic<bool>> cancel) : volume_name(volume_name), cancel(std::move(cancel)) {}
DataBase(const std::string& volume_name, std::shared_ptr<std::atomic<bool>> cancel, EmbossShape&& shape) DataBase(const std::string& volume_name, std::shared_ptr<std::atomic<bool>> cancel, EmbossShape&& shape)
: volume_name(volume_name), cancel(std::move(cancel)), shape(std::move(shape)) : volume_name(volume_name), cancel(std::move(cancel)), shape(std::move(shape)){}
{} DataBase(DataBase &&) = default;
virtual ~DataBase() = default; virtual ~DataBase() = default;
/// <summary> /// <summary>

View File

@ -93,25 +93,28 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
// detect start text dragging // detect start text dragging
if (mouse_event.LeftDown()) { if (mouse_event.LeftDown()) {
// selected volume // selected volume
GLVolume *gl_volume = get_selected_gl_volume(canvas); GLVolume *gl_volume_ptr = get_selected_gl_volume(canvas);
if (gl_volume == nullptr) if (gl_volume_ptr == nullptr)
return false; return false;
const GLVolume &gl_volume = *gl_volume_ptr;
// is selected volume closest hovered? // is selected volume closest hovered?
const GLVolumePtrs &gl_volumes = canvas.get_volumes().volumes; const GLVolumePtrs &gl_volumes = canvas.get_volumes().volumes;
int hovered_idx = canvas.get_first_hover_volume_idx(); if (int hovered_idx = canvas.get_first_hover_volume_idx();
if (hovered_idx < 0 || hovered_idx < 0)
hovered_idx >= gl_volumes.size() || return false;
gl_volumes[hovered_idx] != gl_volume) else if (auto hovered_idx_ = static_cast<size_t>(hovered_idx);
hovered_idx_ >= gl_volumes.size() ||
gl_volumes[hovered_idx_] != gl_volume_ptr)
return false; return false;
const ModelObject *object = get_model_object(*gl_volume, canvas.get_model()->objects); const ModelObject *object = get_model_object(gl_volume, canvas.get_model()->objects);
assert(object != nullptr); assert(object != nullptr);
if (object == nullptr) if (object == nullptr)
return false; return false;
const ModelInstance *instance = get_model_instance(*gl_volume, *object); const ModelInstance *instance = get_model_instance(gl_volume, *object);
const ModelVolume *volume = get_model_volume(*gl_volume, *object); const ModelVolume *volume = get_model_volume(gl_volume, *object);
assert(instance != nullptr && volume != nullptr); assert(instance != nullptr && volume != nullptr);
if (object == nullptr || instance == nullptr || volume == nullptr) if (object == nullptr || instance == nullptr || volume == nullptr)
return false; return false;
@ -124,7 +127,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
std::vector<size_t> allowed_volumes_id; std::vector<size_t> allowed_volumes_id;
if (volumes.size() > 1) { if (volumes.size() > 1) {
allowed_volumes_id.reserve(volumes.size() - 1); allowed_volumes_id.reserve(volumes.size() - 1);
for (auto &v : volumes) { for (const ModelVolume *v : volumes) {
// skip actual selected object // skip actual selected object
if (v->id() == volume->id()) if (v->id() == volume->id())
continue; continue;
@ -146,7 +149,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
Vec2d mouse_pos = mouse_coord.cast<double>(); Vec2d mouse_pos = mouse_coord.cast<double>();
Vec2d mouse_offset = calc_screen_offset_to_volume_center(mouse_pos, *volume, camera); Vec2d mouse_offset = calc_screen_offset_to_volume_center(mouse_pos, *volume, camera);
Transform3d volume_tr = gl_volume->get_volume_transformation().get_matrix(); Transform3d volume_tr = gl_volume.get_volume_transformation().get_matrix();
if (volume->text_configuration.has_value()) { if (volume->text_configuration.has_value()) {
const TextConfiguration &tc = *volume->text_configuration; const TextConfiguration &tc = *volume->text_configuration;
@ -161,7 +164,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
std::optional<float> start_angle; std::optional<float> start_angle;
if (up_limit.has_value()) if (up_limit.has_value())
start_angle = Emboss::calc_up(world_tr, *up_limit); start_angle = Emboss::calc_up(world_tr, *up_limit);
surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume, condition, start_angle}; surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume_ptr, condition, start_angle};
// disable moving with object by mouse // disable moving with object by mouse
canvas.enable_moving(false); canvas.enable_moving(false);

View File

@ -14,13 +14,9 @@ using namespace Slic3r;
using namespace Slic3r::Emboss; using namespace Slic3r::Emboss;
using namespace Slic3r::GUI::Emboss; using namespace Slic3r::GUI::Emboss;
StyleManager::StyleManager(const ImWchar *language_glyph_range, std::function<EmbossStyles()> create_default_styles) StyleManager::StyleManager(const ImWchar *language_glyph_range, const std::function<EmbossStyles()>& create_default_styles)
: m_imgui_init_glyph_range(language_glyph_range) : m_create_default_styles(create_default_styles)
, m_create_default_styles(create_default_styles) , m_imgui_init_glyph_range(language_glyph_range)
, m_exist_style_images(false)
, m_temp_style_images(nullptr)
, m_app_config(nullptr)
, m_last_style_index(std::numeric_limits<size_t>::max())
{} {}
StyleManager::~StyleManager() { StyleManager::~StyleManager() {
@ -32,24 +28,26 @@ StyleManager::~StyleManager() {
/// For store/load emboss style to/from AppConfig /// For store/load emboss style to/from AppConfig
/// </summary> /// </summary>
namespace { namespace {
void store_style_index(AppConfig &cfg, unsigned index); void store_style_index(AppConfig &cfg, size_t index);
::std::optional<size_t> load_style_index(const AppConfig &cfg); ::std::optional<size_t> load_style_index(const AppConfig &cfg);
EmbossStyles load_styles(const AppConfig &cfg); StyleManager::Styles load_styles(const AppConfig &cfg);
void store_styles(AppConfig &cfg, const EmbossStyles &styles); void store_styles(AppConfig &cfg, const StyleManager::Styles &styles);
void make_unique_name(const StyleManager::Styles &styles, std::string &name);
} // namespace } // namespace
void StyleManager::init(AppConfig *app_config) void StyleManager::init(AppConfig *app_config)
{ {
m_app_config = app_config; m_app_config = app_config;
EmbossStyles styles = (app_config != nullptr) ? m_styles = ::load_styles(*app_config);
::load_styles(*app_config) :
EmbossStyles{}; if (m_styles.empty()) {
if (styles.empty()) // No styles loaded from ini file so use default
styles = m_create_default_styles(); EmbossStyles styles = m_create_default_styles();
for (EmbossStyle &style : styles) { for (EmbossStyle &style : styles) {
make_unique_name(style.name); ::make_unique_name(m_styles, style.name);
m_style_items.push_back({style}); m_styles.push_back({style});
}
} }
std::optional<size_t> active_index_opt = (app_config != nullptr) ? std::optional<size_t> active_index_opt = (app_config != nullptr) ?
@ -58,14 +56,14 @@ void StyleManager::init(AppConfig *app_config)
size_t active_index = 0; size_t active_index = 0;
if (active_index_opt.has_value()) active_index = *active_index_opt; if (active_index_opt.has_value()) active_index = *active_index_opt;
if (active_index >= m_style_items.size()) active_index = 0; if (active_index >= m_styles.size()) active_index = 0;
// find valid font item // find valid font item
if (load_style(active_index)) if (load_style(active_index))
return; // style is loaded return; // style is loaded
// Try to fix that style can't be loaded // Try to fix that style can't be loaded
m_style_items.erase(m_style_items.begin() + active_index); m_styles.erase(m_styles.begin() + active_index);
load_valid_style(); load_valid_style();
} }
@ -77,14 +75,14 @@ bool StyleManager::store_styles_to_app_config(bool use_modification, bool store_
if (use_modification) { if (use_modification) {
if (exist_stored_style()) { if (exist_stored_style()) {
// update stored item // update stored item
m_style_items[m_style_cache.style_index].style = m_style_cache.style; m_styles[m_style_cache.style_index] = m_style_cache.style;
} else { } else {
// add new into stored list // add new into stored list
EmbossStyle &style = m_style_cache.style; EmbossStyle &style = m_style_cache.style;
make_unique_name(style.name); ::make_unique_name(m_styles, style.name);
m_style_cache.truncated_name.clear(); m_style_cache.truncated_name.clear();
m_style_cache.style_index = m_style_items.size(); m_style_cache.style_index = m_styles.size();
m_style_items.push_back({style}); m_styles.push_back({style});
} }
m_style_cache.stored_wx_font = m_style_cache.wx_font; m_style_cache.stored_wx_font = m_style_cache.wx_font;
} }
@ -97,27 +95,24 @@ bool StyleManager::store_styles_to_app_config(bool use_modification, bool store_
store_style_index(*m_app_config, style_index); store_style_index(*m_app_config, style_index);
} }
EmbossStyles styles; store_styles(*m_app_config, m_styles);
styles.reserve(m_style_items.size());
for (const Item &item : m_style_items) styles.push_back(item.style);
store_styles(*m_app_config, styles);
return true; return true;
} }
void StyleManager::add_style(const std::string &name) { void StyleManager::add_style(const std::string &name) {
EmbossStyle& style = m_style_cache.style; EmbossStyle& style = m_style_cache.style;
style.name = name; style.name = name;
make_unique_name(style.name); ::make_unique_name(m_styles, style.name);
m_style_cache.style_index = m_style_items.size(); m_style_cache.style_index = m_styles.size();
m_style_cache.stored_wx_font = m_style_cache.wx_font; m_style_cache.stored_wx_font = m_style_cache.wx_font;
m_style_cache.truncated_name.clear(); m_style_cache.truncated_name.clear();
m_style_items.push_back({style}); m_styles.push_back({style});
} }
void StyleManager::swap(size_t i1, size_t i2) { void StyleManager::swap(size_t i1, size_t i2) {
if (i1 >= m_style_items.size() || if (i1 >= m_styles.size() ||
i2 >= m_style_items.size()) return; i2 >= m_styles.size()) return;
std::swap(m_style_items[i1], m_style_items[i2]); std::swap(m_styles[i1], m_styles[i2]);
// fix selected index // fix selected index
if (!exist_stored_style()) return; if (!exist_stored_style()) return;
if (m_style_cache.style_index == i1) { if (m_style_cache.style_index == i1) {
@ -141,7 +136,7 @@ void StyleManager::discard_style_changes() {
} }
void StyleManager::erase(size_t index) { void StyleManager::erase(size_t index) {
if (index >= m_style_items.size()) return; if (index >= m_styles.size()) return;
// fix selected index // fix selected index
if (exist_stored_style()) { if (exist_stored_style()) {
@ -150,15 +145,15 @@ void StyleManager::erase(size_t index) {
else if (index == i) i = std::numeric_limits<size_t>::max(); else if (index == i) i = std::numeric_limits<size_t>::max();
} }
m_style_items.erase(m_style_items.begin() + index); m_styles.erase(m_styles.begin() + index);
} }
void StyleManager::rename(const std::string& name) { void StyleManager::rename(const std::string& name) {
m_style_cache.style.name = name; m_style_cache.style.name = name;
m_style_cache.truncated_name.clear(); m_style_cache.truncated_name.clear();
if (exist_stored_style()) { if (exist_stored_style()) {
Item &it = m_style_items[m_style_cache.style_index]; Style &it = m_styles[m_style_cache.style_index];
it.style.name = name; it.name = name;
it.truncated_name.clear(); it.truncated_name.clear();
} }
} }
@ -166,28 +161,28 @@ void StyleManager::rename(const std::string& name) {
void StyleManager::load_valid_style() void StyleManager::load_valid_style()
{ {
// iterate over all known styles // iterate over all known styles
while (!m_style_items.empty()) { while (!m_styles.empty()) {
if (load_style(0)) if (load_style(0))
return; return;
// can't load so erase it from list // can't load so erase it from list
m_style_items.erase(m_style_items.begin()); m_styles.erase(m_styles.begin());
} }
// no one style is loadable // no one style is loadable
// set up default font list // set up default font list
EmbossStyles def_style = m_create_default_styles(); EmbossStyles def_style = m_create_default_styles();
for (EmbossStyle &style : def_style) { for (EmbossStyle &style : def_style) {
make_unique_name(style.name); ::make_unique_name(m_styles, style.name);
m_style_items.push_back({std::move(style)}); m_styles.push_back({std::move(style)});
} }
// iterate over default styles // iterate over default styles
// There have to be option to use build in font // There have to be option to use build in font
while (!m_style_items.empty()) { while (!m_styles.empty()) {
if (load_style(0)) if (load_style(0))
return; return;
// can't load so erase it from list // can't load so erase it from list
m_style_items.erase(m_style_items.begin()); m_styles.erase(m_styles.begin());
} }
// This OS doesn't have TTF as default font, // This OS doesn't have TTF as default font,
@ -197,15 +192,15 @@ void StyleManager::load_valid_style()
bool StyleManager::load_style(size_t style_index) bool StyleManager::load_style(size_t style_index)
{ {
if (style_index >= m_style_items.size()) return false; if (style_index >= m_styles.size()) return false;
if (!load_style(m_style_items[style_index].style)) return false; if (!load_style(m_styles[style_index])) return false;
m_style_cache.style_index = style_index; m_style_cache.style_index = style_index;
m_style_cache.stored_wx_font = m_style_cache.wx_font; // copy m_style_cache.stored_wx_font = m_style_cache.wx_font; // copy
m_last_style_index = style_index; m_last_style_index = style_index;
return true; return true;
} }
bool StyleManager::load_style(const EmbossStyle &style) { bool StyleManager::load_style(const Style &style) {
if (style.type == EmbossStyle::Type::file_path) { if (style.type == EmbossStyle::Type::file_path) {
std::unique_ptr<FontFile> font_ptr = std::unique_ptr<FontFile> font_ptr =
create_font_file(style.path.c_str()); create_font_file(style.path.c_str());
@ -218,13 +213,13 @@ bool StyleManager::load_style(const EmbossStyle &style) {
m_style_cache.stored_wx_font = {}; m_style_cache.stored_wx_font = {};
return true; return true;
} }
if (style.type != WxFontUtils::get_actual_type()) return false; if (style.type != WxFontUtils::get_current_type()) return false;
std::optional<wxFont> wx_font_opt = WxFontUtils::load_wxFont(style.path); std::optional<wxFont> wx_font_opt = WxFontUtils::load_wxFont(style.path);
if (!wx_font_opt.has_value()) return false; if (!wx_font_opt.has_value()) return false;
return load_style(style, *wx_font_opt); return load_style(style, *wx_font_opt);
} }
bool StyleManager::load_style(const EmbossStyle &style, const wxFont &font) bool StyleManager::load_style(const Style &style, const wxFont &font)
{ {
m_style_cache.style = style; // copy m_style_cache.style = style; // copy
@ -275,12 +270,19 @@ bool StyleManager::is_font_changed() const
return is_bold != is_stored_bold; return is_bold != is_stored_bold;
} }
bool StyleManager::is_unique_style_name(const std::string &name) const {
for (const StyleManager::Style &style : m_styles)
if (style.name == name)
return false;
return true;
}
bool StyleManager::is_active_font() { return m_style_cache.font_file.has_value(); } bool StyleManager::is_active_font() { return m_style_cache.font_file.has_value(); }
const EmbossStyle* StyleManager::get_stored_style() const const StyleManager::Style *StyleManager::get_stored_style() const
{ {
if (m_style_cache.style_index >= m_style_items.size()) return nullptr; if (m_style_cache.style_index >= m_styles.size()) return nullptr;
return &m_style_items[m_style_cache.style_index].style; return &m_styles[m_style_cache.style_index];
} }
void StyleManager::clear_glyphs_cache() void StyleManager::clear_glyphs_cache()
@ -308,44 +310,11 @@ ImFont *StyleManager::get_imgui_font()
return font; return font;
} }
const std::vector<StyleManager::Item> &StyleManager::get_styles() const{ return m_style_items; } const StyleManager::Styles &StyleManager::get_styles() const{ return m_styles; }
void StyleManager::make_unique_name(std::string &name)
{
auto is_unique = [&](const std::string &name) -> bool {
for (const Item &it : m_style_items)
if (it.style.name == name) return false;
return true;
};
// Style name can't be empty so default name is set
if (name.empty()) name = "Text style";
// When name is already unique, nothing need to be changed
if (is_unique(name)) return;
// when there is previous version of style name only find number
const char *prefix = " (";
const char suffix = ')';
auto pos = name.find_last_of(prefix);
if (name.c_str()[name.size() - 1] == suffix &&
pos != std::string::npos) {
// short name by ord number
name = name.substr(0, pos);
}
int order = 1; // start with value 2 to represents same font name
std::string new_name;
do {
new_name = name + prefix + std::to_string(++order) + suffix;
} while (!is_unique(new_name));
name = new_name;
}
void StyleManager::init_trunc_names(float max_width) { void StyleManager::init_trunc_names(float max_width) {
for (auto &s : m_style_items) for (auto &s : m_styles)
if (s.truncated_name.empty()) { if (s.truncated_name.empty()) {
std::string name = s.style.name; std::string name = s.name;
ImGuiWrapper::escape_double_hash(name); ImGuiWrapper::escape_double_hash(name);
s.truncated_name = ImGuiWrapper::trunc(name, max_width); s.truncated_name = ImGuiWrapper::trunc(name, max_width);
} }
@ -378,9 +347,9 @@ void StyleManager::init_style_images(const Vec2i &max_size,
StyleImagesData::Item &style = m_temp_style_images->styles[index]; StyleImagesData::Item &style = m_temp_style_images->styles[index];
// find style in font list and copy to it // find style in font list and copy to it
for (auto &it : m_style_items) { for (auto &it : m_styles) {
if (it.style.name != style.text || if (it.name != style.text ||
!(it.style.prop == style.prop)) !(it.prop == style.prop))
continue; continue;
it.image = image; it.image = image;
break; break;
@ -397,9 +366,8 @@ void StyleManager::init_style_images(const Vec2i &max_size,
// create job for init images // create job for init images
m_temp_style_images = std::make_shared<StyleImagesData::StyleImages>(); m_temp_style_images = std::make_shared<StyleImagesData::StyleImages>();
StyleImagesData::Items styles; StyleImagesData::Items styles;
styles.reserve(m_style_items.size()); styles.reserve(m_styles.size());
for (const Item &item : m_style_items) { for (const Style &style : m_styles) {
const EmbossStyle &style = item.style;
std::optional<wxFont> wx_font_opt = WxFontUtils::load_wxFont(style.path); std::optional<wxFont> wx_font_opt = WxFontUtils::load_wxFont(style.path);
if (!wx_font_opt.has_value()) continue; if (!wx_font_opt.has_value()) continue;
std::unique_ptr<FontFile> font_file = std::unique_ptr<FontFile> font_file =
@ -426,7 +394,7 @@ void StyleManager::init_style_images(const Vec2i &max_size,
void StyleManager::free_style_images() { void StyleManager::free_style_images() {
if (!m_exist_style_images) return; if (!m_exist_style_images) return;
GLuint tex_id = 0; GLuint tex_id = 0;
for (Item &it : m_style_items) { for (Style &it : m_styles) {
if (tex_id == 0 && it.image.has_value()) if (tex_id == 0 && it.image.has_value())
tex_id = (GLuint)(intptr_t) it.image->texture_id; tex_id = (GLuint)(intptr_t) it.image->texture_id;
it.image.reset(); it.image.reset();
@ -546,7 +514,7 @@ bool StyleManager::set_wx_font(const wxFont &wx_font, std::unique_ptr<FontFile>
FontFileWithCache(std::move(font_file)); FontFileWithCache(std::move(font_file));
EmbossStyle &style = m_style_cache.style; EmbossStyle &style = m_style_cache.style;
style.type = WxFontUtils::get_actual_type(); style.type = WxFontUtils::get_current_type();
// update string path // update string path
style.path = WxFontUtils::store_wxFont(wx_font); style.path = WxFontUtils::store_wxFont(wx_font);
WxFontUtils::update_property(style.prop, wx_font); WxFontUtils::update_property(style.prop, wx_font);
@ -664,51 +632,55 @@ bool read(const Section &section, const std::string &key, std::optional<float> &
return true; return true;
} }
std::optional<EmbossStyle> load_style(const Section &app_cfg_section) std::optional<StyleManager::Style> load_style(const Section &app_cfg_section)
{ {
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()) if (path_it == app_cfg_section.end())
return {}; return {};
const std::string &path = path_it->second;
StyleManager::Style s;
EmbossProjection& ep = s.projection;
FontProp& fp = s.prop;
s.path = path_it->second;
s.type = WxFontUtils::get_current_type();
auto name_it = app_cfg_section.find(APP_CONFIG_FONT_NAME); auto name_it = app_cfg_section.find(APP_CONFIG_FONT_NAME);
const std::string default_name = "font_name"; const std::string default_name = "font_name";
const std::string &name = (name_it == app_cfg_section.end()) ? default_name : name_it->second; s.name = (name_it == app_cfg_section.end()) ? default_name : name_it->second;
FontProp fp; float depth;
read(app_cfg_section, APP_CONFIG_FONT_LINE_HEIGHT, fp.size_in_mm); read(app_cfg_section, APP_CONFIG_FONT_LINE_HEIGHT, fp.size_in_mm);
read(app_cfg_section, APP_CONFIG_FONT_DEPTH, fp.emboss); read(app_cfg_section, APP_CONFIG_FONT_DEPTH, depth);ep.depth = depth;
read(app_cfg_section, APP_CONFIG_FONT_USE_SURFACE, fp.use_surface); read(app_cfg_section, APP_CONFIG_FONT_USE_SURFACE, ep.use_surface);
read(app_cfg_section, APP_CONFIG_FONT_BOLDNESS, fp.boldness); read(app_cfg_section, APP_CONFIG_FONT_BOLDNESS, fp.boldness);
read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew); read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew);
read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, fp.distance); read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, s.distance);
read(app_cfg_section, APP_CONFIG_FONT_ANGLE, fp.angle); read(app_cfg_section, APP_CONFIG_FONT_ANGLE, s.angle);
read(app_cfg_section, APP_CONFIG_FONT_COLLECTION, fp.collection_number); read(app_cfg_section, APP_CONFIG_FONT_COLLECTION, fp.collection_number);
read(app_cfg_section, APP_CONFIG_FONT_CHAR_GAP, fp.char_gap); read(app_cfg_section, APP_CONFIG_FONT_CHAR_GAP, fp.char_gap);
read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap); read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap);
return s;
EmbossStyle::Type type = WxFontUtils::get_actual_type();
return EmbossStyle{name, path, type, fp};
} }
void store_style(AppConfig &cfg, const EmbossStyle &fi, unsigned index) void store_style(AppConfig &cfg, const StyleManager::Style &s, unsigned index)
{ {
const EmbossProjection &ep = s.projection;
Section data; Section data;
data[APP_CONFIG_FONT_NAME] = fi.name; data[APP_CONFIG_FONT_NAME] = s.name;
data[APP_CONFIG_FONT_DESCRIPTOR] = fi.path; data[APP_CONFIG_FONT_DESCRIPTOR] = s.path;
const FontProp &fp = fi.prop; const FontProp &fp = s.prop;
data[APP_CONFIG_FONT_LINE_HEIGHT] = std::to_string(fp.size_in_mm); data[APP_CONFIG_FONT_LINE_HEIGHT] = std::to_string(fp.size_in_mm);
data[APP_CONFIG_FONT_DEPTH] = std::to_string(fp.emboss); data[APP_CONFIG_FONT_DEPTH] = std::to_string(ep.depth);
if (fp.use_surface) if (ep.use_surface)
data[APP_CONFIG_FONT_USE_SURFACE] = "true"; data[APP_CONFIG_FONT_USE_SURFACE] = "true";
if (fp.boldness.has_value()) if (fp.boldness.has_value())
data[APP_CONFIG_FONT_BOLDNESS] = std::to_string(*fp.boldness); data[APP_CONFIG_FONT_BOLDNESS] = std::to_string(*fp.boldness);
if (fp.skew.has_value()) if (fp.skew.has_value())
data[APP_CONFIG_FONT_SKEW] = std::to_string(*fp.skew); data[APP_CONFIG_FONT_SKEW] = std::to_string(*fp.skew);
if (fp.distance.has_value()) if (s.distance.has_value())
data[APP_CONFIG_FONT_DISTANCE] = std::to_string(*fp.distance); data[APP_CONFIG_FONT_DISTANCE] = std::to_string(*s.distance);
if (fp.angle.has_value()) if (s.angle.has_value())
data[APP_CONFIG_FONT_ANGLE] = std::to_string(*fp.angle); data[APP_CONFIG_FONT_ANGLE] = std::to_string(*s.angle);
if (fp.collection_number.has_value()) if (fp.collection_number.has_value())
data[APP_CONFIG_FONT_COLLECTION] = std::to_string(*fp.collection_number); data[APP_CONFIG_FONT_COLLECTION] = std::to_string(*fp.collection_number);
if (fp.char_gap.has_value()) if (fp.char_gap.has_value())
@ -718,7 +690,7 @@ void store_style(AppConfig &cfg, const EmbossStyle &fi, unsigned index)
cfg.set_section(create_section_name(index), std::move(data)); cfg.set_section(create_section_name(index), std::move(data));
} }
void store_style_index(AppConfig &cfg, unsigned index) void store_style_index(AppConfig &cfg, size_t index)
{ {
// store actual font index // store actual font index
// active font first index is +1 to correspond with section name // active font first index is +1 to correspond with section name
@ -742,29 +714,34 @@ std::optional<size_t> load_style_index(const AppConfig &cfg)
return active_font - 1; return active_font - 1;
} }
EmbossStyles load_styles(const AppConfig &cfg) ::StyleManager::Styles load_styles(const AppConfig &cfg)
{ {
EmbossStyles result; StyleManager::Styles result;
// human readable index inside of config starts from 1 !! // human readable index inside of config starts from 1 !!
unsigned index = 1; unsigned index = 1;
std::string section_name = create_section_name(index); std::string section_name = create_section_name(index);
while (cfg.has_section(section_name)) { while (cfg.has_section(section_name)) {
std::optional<EmbossStyle> style_opt = load_style(cfg.get_section(section_name)); std::optional<StyleManager::Style> style_opt = load_style(cfg.get_section(section_name));
if (style_opt.has_value()) if (style_opt.has_value()) {
make_unique_name(result, style_opt->name);
result.emplace_back(*style_opt); result.emplace_back(*style_opt);
}
section_name = create_section_name(++index); section_name = create_section_name(++index);
} }
return result; return result;
} }
void store_styles(AppConfig &cfg, const EmbossStyles &styles) void store_styles(AppConfig &cfg, const StyleManager::Styles &styles)
{ {
EmbossStyle::Type current_type = WxFontUtils::get_current_type();
// store styles // store styles
unsigned index = 1; unsigned index = 1;
for (const EmbossStyle &style : styles) { for (const StyleManager::Style &style : styles) {
// skip file paths + fonts from other OS(loaded from .3mf) // skip file paths + fonts from other OS(loaded from .3mf)
assert(style.type == WxFontUtils::get_actual_type()); assert(style.type == current_type);
// if (style_opt.type != WxFontUtils::get_actual_type()) continue; if (style.type != current_type)
continue;
store_style(cfg, style, index); store_style(cfg, style, index);
++index; ++index;
} }
@ -778,4 +755,36 @@ void store_styles(AppConfig &cfg, const EmbossStyles &styles)
} }
} }
void make_unique_name(const StyleManager::Styles& styles, std::string &name)
{
auto is_unique = [&styles](const std::string &name){
for (const StyleManager::Style &it : styles)
if (it.name == name) return false;
return true;
};
// Style name can't be empty so default name is set
if (name.empty()) name = "Text style";
// When name is already unique, nothing need to be changed
if (is_unique(name)) return;
// when there is previous version of style name only find number
const char *prefix = " (";
const char suffix = ')';
auto pos = name.find_last_of(prefix);
if (name.c_str()[name.size() - 1] == suffix &&
pos != std::string::npos) {
// short name by ord number
name = name.substr(0, pos);
}
int order = 1; // start with value 2 to represents same font name
std::string new_name;
do {
new_name = name + prefix + std::to_string(++order) + suffix;
} while (!is_unique(new_name));
name = new_name;
}
} // namespace } // namespace

View File

@ -24,11 +24,10 @@ namespace Slic3r::GUI::Emboss {
class StyleManager class StyleManager
{ {
friend class CreateFontStyleImagesJob; // access to StyleImagesData friend class CreateFontStyleImagesJob; // access to StyleImagesData
public: public:
/// <param name="language_glyph_range">Character to load for imgui when initialize imgui font</param> /// <param name="language_glyph_range">Character to load for imgui when initialize imgui font</param>
/// <param name="create_default_styles">Function to create default styles</param> /// <param name="create_default_styles">Function to create default styles</param>
StyleManager(const ImWchar *language_glyph_range, std::function<EmbossStyles()> create_default_styles); StyleManager(const ImWchar *language_glyph_range, const std::function<EmbossStyles()>& create_default_styles);
/// <summary> /// <summary>
/// Release imgui font and style images from GPU /// Release imgui font and style images from GPU
@ -59,11 +58,11 @@ public:
void add_style(const std::string& name); void add_style(const std::string& name);
/// <summary> /// <summary>
/// Change order of style item in m_style_items. /// Change order of style item in m_styles.
/// Fix selected font index when (i1 || i2) == m_font_selected /// Fix selected font index when (i1 || i2) == m_font_selected
/// </summary> /// </summary>
/// <param name="i1">First index to m_style_items</param> /// <param name="i1">First index to m_styles</param>
/// <param name="i2">Second index to m_style_items</param> /// <param name="i2">Second index to m_styles</param>
void swap(size_t i1, size_t i2); void swap(size_t i1, size_t i2);
/// <summary> /// <summary>
@ -73,7 +72,7 @@ public:
void discard_style_changes(); void discard_style_changes();
/// <summary> /// <summary>
/// Remove style from m_style_items. /// Remove style from m_styles.
/// Fix selected font index when index is under m_font_selected /// Fix selected font index when index is under m_font_selected
/// </summary> /// </summary>
/// <param name="index">Index of style to be removed</param> /// <param name="index">Index of style to be removed</param>
@ -94,13 +93,14 @@ public:
/// Change active font /// Change active font
/// When font not loaded roll back activ font /// When font not loaded roll back activ font
/// </summary> /// </summary>
/// <param name="font_index">New font index(from m_style_items range)</param> /// <param name="font_index">New font index(from m_styles range)</param>
/// <returns>True on succes. False on fail load font</returns> /// <returns>True on succes. False on fail load font</returns>
bool load_style(size_t font_index); bool load_style(size_t font_index);
// load font style not stored in list // load font style not stored in list
bool load_style(const EmbossStyle &style); struct Style;
bool load_style(const Style &style);
// fastering load font on index by wxFont, ignore type and descriptor // fastering load font on index by wxFont, ignore type and descriptor
bool load_style(const EmbossStyle &style, const wxFont &font); bool load_style(const Style &style, const wxFont &font);
// clear actual selected glyphs cache // clear actual selected glyphs cache
void clear_glyphs_cache(); void clear_glyphs_cache();
@ -109,10 +109,10 @@ public:
void clear_imgui_font(); void clear_imgui_font();
// getters for private data // getters for private data
const EmbossStyle *get_stored_style() const; const Style *get_stored_style() const;
const EmbossStyle &get_style() const { return m_style_cache.style; } const Style &get_style() const { return m_style_cache.style; }
EmbossStyle &get_style() { return m_style_cache.style; } Style &get_style() { return m_style_cache.style; }
size_t get_style_index() const { return m_style_cache.style_index; } size_t get_style_index() const { return m_style_cache.style_index; }
std::string &get_truncated_name() { return m_style_cache.truncated_name; } std::string &get_truncated_name() { return m_style_cache.truncated_name; }
const ImFontAtlas &get_atlas() const { return m_style_cache.atlas; } const ImFontAtlas &get_atlas() const { return m_style_cache.atlas; }
@ -133,6 +133,8 @@ public:
/// <returns></returns> /// <returns></returns>
bool is_font_changed() const; bool is_font_changed() const;
bool is_unique_style_name(const std::string &name) const;
/// <summary> /// <summary>
/// Setter on wx_font when changed /// Setter on wx_font when changed
/// </summary> /// </summary>
@ -167,33 +169,28 @@ public:
void init_style_images(const Vec2i& max_size, const std::string &text); void init_style_images(const Vec2i& max_size, const std::string &text);
void free_style_images(); void free_style_images();
struct Item;
// access to all managed font styles // access to all managed font styles
const std::vector<Item> &get_styles() const; const std::vector<Style> &get_styles() const;
/// <summary> /// <summary>
/// Describe image in GPU to show settings of style /// Describe image in GPU to show settings of style
/// </summary> /// </summary>
struct StyleImage struct StyleImage
{ {
void* texture_id = 0; // GLuint void* texture_id = nullptr; // GLuint
BoundingBox bounding_box; BoundingBox bounding_box;
ImVec2 tex_size; ImVec2 tex_size;
ImVec2 uv0; ImVec2 uv0;
ImVec2 uv1; ImVec2 uv1;
Point offset = Point(0, 0); Point offset = Point(0, 0);
StyleImage() = default;
}; };
/// <summary> /// <summary>
/// All connected with one style /// All connected with one style
/// keep temporary data and caches for style /// keep temporary data and caches for style
/// </summary> /// </summary>
struct Item struct Style : public EmbossStyle
{ {
// parent Text style
EmbossStyle style;
// Define how to emboss shape // Define how to emboss shape
EmbossProjection projection; EmbossProjection projection;
@ -208,9 +205,12 @@ public:
// When not set value is zero and is not stored // When not set value is zero and is not stored
std::optional<float> angle; // [in radians] form -Pi to Pi std::optional<float> angle; // [in radians] form -Pi to Pi
bool operator==(const Item &other) const bool operator==(const Style &other) const
{ {
return style == other.style && projection == other.projection && distance == other.distance && angle == other.angle; return EmbossStyle::operator==(other) &&
projection == other.projection &&
distance == other.distance &&
angle == other.angle;
} }
// cache for view font name with maximal width in imgui // cache for view font name with maximal width in imgui
@ -219,6 +219,7 @@ public:
// visualization of style // visualization of style
std::optional<StyleImage> image; std::optional<StyleImage> image;
}; };
using Styles = std::vector<Style>;
// check if exist selected font style in manager // check if exist selected font style in manager
bool is_active_font(); bool is_active_font();
@ -230,7 +231,10 @@ public:
static float get_imgui_font_size(const FontProp &prop, const Slic3r::Emboss::FontFile &file, double scale); static float get_imgui_font_size(const FontProp &prop, const Slic3r::Emboss::FontFile &file, double scale);
private: private:
// function to create default style list
std::function<EmbossStyles()> m_create_default_styles; std::function<EmbossStyles()> m_create_default_styles;
// keep language dependent glyph range
const ImWchar *m_imgui_init_glyph_range;
/// <summary> /// <summary>
/// Cache data from style to reduce amount of: /// Cache data from style to reduce amount of:
@ -256,22 +260,20 @@ private:
std::string truncated_name; std::string truncated_name;
// actual used font item // actual used font item
EmbossStyle style = {}; Style style = {};
// cache for stored wx font to not create every frame // cache for stored wx font to not create every frame
wxFont stored_wx_font = {}; wxFont stored_wx_font = {};
// index into m_style_items // index into m_styles
size_t style_index = std::numeric_limits<size_t>::max(); size_t style_index = std::numeric_limits<size_t>::max();
} m_style_cache; } m_style_cache;
void make_unique_name(std::string &name);
// Privat member // Privat member
std::vector<Item> m_style_items; Styles m_styles;
AppConfig *m_app_config; AppConfig *m_app_config = nullptr;
size_t m_last_style_index; size_t m_last_style_index = std::numeric_limits<size_t>::max();
/// <summary> /// <summary>
/// Keep data needed to create Font Style Images in Job /// Keep data needed to create Font Style Images in Job
@ -310,12 +312,8 @@ private:
// pixel per milimeter (scaled DPI) // pixel per milimeter (scaled DPI)
double ppm; double ppm;
}; };
std::shared_ptr<StyleImagesData::StyleImages> m_temp_style_images; std::shared_ptr<StyleImagesData::StyleImages> m_temp_style_images = nullptr;
bool m_exist_style_images; bool m_exist_style_images = false;
// store all font GLImages
//ImFontAtlas m_imgui_font_atlas;
const ImWchar *m_imgui_init_glyph_range;
}; };
} // namespace Slic3r } // namespace Slic3r

View File

@ -108,7 +108,7 @@ std::unique_ptr<Emboss::FontFile> WxFontUtils::create_font_file(const wxFont &fo
#endif #endif
} }
EmbossStyle::Type WxFontUtils::get_actual_type() EmbossStyle::Type WxFontUtils::get_current_type()
{ {
#ifdef _WIN32 #ifdef _WIN32
return EmbossStyle::Type::wx_win_font_descr; return EmbossStyle::Type::wx_win_font_descr;
@ -125,7 +125,7 @@ EmbossStyle WxFontUtils::create_emboss_style(const wxFont &font, const std::stri
{ {
std::string name_item = name.empty()? get_human_readable_name(font) : name; std::string name_item = name.empty()? get_human_readable_name(font) : name;
std::string fontDesc = store_wxFont(font); std::string fontDesc = store_wxFont(font);
EmbossStyle::Type type = get_actual_type(); EmbossStyle::Type type = get_current_type();
// synchronize font property with actual font // synchronize font property with actual font
FontProp font_prop; FontProp font_prop;

View File

@ -24,7 +24,7 @@ public:
// os specific load of wxFont // os specific load of wxFont
static std::unique_ptr<Slic3r::Emboss::FontFile> create_font_file(const wxFont &font); static std::unique_ptr<Slic3r::Emboss::FontFile> create_font_file(const wxFont &font);
static EmbossStyle::Type get_actual_type(); static EmbossStyle::Type get_current_type();
static EmbossStyle create_emboss_style(const wxFont &font, const std::string& name = ""); static EmbossStyle create_emboss_style(const wxFont &font, const std::string& name = "");
static std::string get_human_readable_name(const wxFont &font); static std::string get_human_readable_name(const wxFont &font);