From e0a4ac03131feda71eb16e7d1fd330419a549f25 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Wed, 22 Mar 2023 09:11:12 +0100 Subject: [PATCH] Partialy calculated distance on the fly. --- src/libslic3r/Point.hpp | 15 + src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 371 +++++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 11 +- src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp | 7 +- src/slic3r/GUI/Jobs/EmbossJob.cpp | 8 +- src/slic3r/GUI/Jobs/EmbossJob.hpp | 4 +- src/slic3r/GUI/SurfaceDrag.cpp | 29 +- src/slic3r/Utils/EmbossStyleManager.cpp | 265 +++++++++-------- src/slic3r/Utils/EmbossStyleManager.hpp | 70 +++-- src/slic3r/Utils/WxFontUtils.cpp | 4 +- src/slic3r/Utils/WxFontUtils.hpp | 2 +- 11 files changed, 418 insertions(+), 368 deletions(-) diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index d97f1b32d0..a46422022b 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -144,6 +144,21 @@ Pointf3s transform(const Pointf3s& points, const Transform3d& t); /// Is positive determinant inline bool has_reflection(const Transform3d &transform) { return transform.matrix().determinant() < 0; } +/// +/// Getter on base of transformation matrix +/// +/// column index +/// source transformation +/// Base of transformation matrix +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 using Vec = Eigen::Matrix; class Point : public Vec2crd diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 75fe6cbfc5..f00ae83aed 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -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); } // 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(GLGizmosManager::Emboss); const GLVolume *gl_volume = get_first_hovered_gl_volume(canvas); - const FontProp &fp = styler.get_style().prop; Plater *plater = wxGetApp().plater(); 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) @@ -171,7 +170,7 @@ bool GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous // NOTE: change style manager - be carefull with order changes 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); } @@ -183,7 +182,7 @@ bool GLGizmoEmboss::create_volume(ModelVolumeType volume_type) // NOTE: change style manager - be carefull with order changes 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)); } @@ -197,9 +196,9 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event) if (mouse_event.Dragging()) { if (!m_rotate_start_angle.has_value()) { // 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 &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(); @@ -269,7 +268,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event) if (gl_volume == nullptr || !m_style_manager.is_active_font()) 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; @@ -576,7 +575,7 @@ void GLGizmoEmboss::on_stop_dragging() assert(m_style_manager.is_active_font()); assert(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(); @@ -754,15 +753,66 @@ EmbossStyles GLGizmoEmboss::create_default_styles() void GLGizmoEmboss::set_default_text(){ m_text = _u8L("Embossed text"); } +namespace { + +/// +/// Throow ray by embossing params to object and find surface point +/// +/// Define embossed volume +/// Way to cast rays to object +/// Contain model +/// Calculated distance from surface +std::optional 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 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() { const Selection &selection = m_parent.get_selection(); - const GLVolume *gl_volume = get_selected_gl_volume(selection); + const GLVolume *gl_volume = get_selected_gl_volume(selection); if (gl_volume == nullptr) return reset_volume(); 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) return reset_volume(); @@ -774,24 +824,28 @@ void GLGizmoEmboss::set_volume_by_selection() remove_notification_not_valid_font(); // Do not use focused input value when switch volume(it must swith value) - if (m_volume != nullptr && - m_volume != volume) // when update volume it changed id BUT not pointer + if (m_volume != nullptr && m_volume != volume) // when update volume it changed id BUT not pointer ImGuiWrapper::left_inputs(); // Is selected volume text volume? - const std::optional& tc_opt = volume->text_configuration; - if (!tc_opt.has_value()) + const std::optional &tc_opt = volume->text_configuration; + if (!tc_opt.has_value()) 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 EmbossStyle &style = tc.style; // Could exist OS without getter on face_name, // but it is able to restore font from descriptor // Soo default value must be TRUE - bool is_font_installed = true; - wxString face_name; - std::optional face_name_opt = style.prop.face_name; + bool is_font_installed = true; + wxString face_name; + const std::optional &face_name_opt = style.prop.face_name; if (face_name_opt.has_value()) { face_name = wxString(face_name_opt->c_str()); @@ -800,21 +854,20 @@ void GLGizmoEmboss::set_volume_by_selection() init_face_names(m_face_names); 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 &faces = m_face_names.faces; auto it = std::lower_bound(faces.begin(), faces.end(), face_name, cmp); is_font_installed = it != faces.end() && it->wx_name == face_name; if (!is_font_installed) { - const std::vector &bad = m_face_names.bad; - auto it_bad = std::lower_bound(bad.begin(), bad.end(), face_name); - if (it_bad == bad.end() || *it_bad != face_name){ + const std::vector &bad = m_face_names.bad; + auto it_bad = std::lower_bound(bad.begin(), bad.end(), face_name); + if (it_bad == bad.end() || *it_bad != face_name) { // check if wx allowed to set it up - another encoding of name wxFontEnumerator::InvalidateCache(); - wxFont wx_font_; // temporary structure - if (wx_font_.SetFaceName(face_name) && - WxFontUtils::create_font_file(wx_font_) != nullptr // can load TTF file? - ) { + wxFont wx_font_; // temporary structure + if (wx_font_.SetFaceName(face_name) && WxFontUtils::create_font_file(wx_font_) != nullptr // can load TTF file? + ) { is_font_installed = true; // QUESTION: add this name to allowed faces? // Could create twin of font face name @@ -826,8 +879,8 @@ void GLGizmoEmboss::set_volume_by_selection() wxFont wx_font; // load wxFont from same OS when font name is installed - if (style.type == WxFontUtils::get_actual_type() && is_font_installed) - wx_font = WxFontUtils::load_wxFont(style.path); + if (style.type == WxFontUtils::get_current_type() && is_font_installed) + wx_font = WxFontUtils::load_wxFont(style.path); // Flag that is selected same font bool is_exact_font = true; @@ -837,7 +890,7 @@ void GLGizmoEmboss::set_volume_by_selection() // Try create similar wx font by FontFamily wx_font = WxFontUtils::create_wxFont(style); if (is_font_installed) - is_exact_font = wx_font.SetFaceName(face_name); + is_exact_font = wx_font.SetFaceName(face_name); // Have to use some wxFont if (!wx_font.IsOk()) @@ -846,25 +899,28 @@ void GLGizmoEmboss::set_volume_by_selection() assert(wx_font.IsOk()); // Load style to style manager - const auto& styles = m_style_manager.get_styles(); - auto has_same_name = [&style](const StyleManager::Item &style_item) -> bool { - const EmbossStyle &es = style_item.style; - return es.name == style.name; - }; + const auto &styles = m_style_manager.get_styles(); + auto has_same_name = [&name = style.name](const StyleManager::Style &style_item) { return style_item.name == 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); if (it == styles.end()) { // style was not found - m_style_manager.load_style(style, wx_font); + m_style_manager.load_style(style_, wx_font); } else { // style name is in styles list size_t style_index = it - styles.begin(); if (!m_style_manager.load_style(style_index)) { // can`t load stored style m_style_manager.erase(style_index); - m_style_manager.load_style(style, wx_font); + m_style_manager.load_style(style_, wx_font); } else { // 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); } } @@ -890,11 +946,6 @@ void GLGizmoEmboss::set_volume_by_selection() m_volume = volume; 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(); } @@ -1858,14 +1909,10 @@ void GLGizmoEmboss::draw_style_rename_popup() { const std::string &old_name = m_style_manager.get_stored_style()->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()); - - bool is_unique = true; - for (const auto &item : m_style_manager.get_styles()) { - 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 is_unique = (new_name == old_name) || // could be same as before rename + m_style_manager.is_unique_style_name(new_name); + bool allow_change = false; if (new_name.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 std::string &new_name = m_volume->text_configuration->style.name; - - bool is_unique = true; - for (const auto &item : m_style_manager.get_styles()) - if (item.style.name == new_name) is_unique = false; - + bool is_unique = m_style_manager.is_unique_style_name(new_name); bool allow_change = false; if (new_name.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 can_add = true; 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; 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 -void GLGizmoEmboss::fix_transformation(const FontProp &from, - const FontProp &to) -{ +namespace { +// FIX IT: It should not change volume position before successfull change volume by process +void fix_transformation(const StyleManager::Style &from, const StyleManager::Style &to, GLCanvas3D &canvas) { // fix Z rotation when exists difference in styles const std::optional &f_angle_opt = from.angle; const std::optional &t_angle_opt = to.angle; if (!is_approx(f_angle_opt, t_angle_opt)) { // fix rotation - float f_angle = f_angle_opt.has_value() ? *f_angle_opt : .0f; - float t_angle = t_angle_opt.has_value() ? *t_angle_opt : .0f; - do_local_z_rotate(m_parent, t_angle - f_angle); + float f_angle = f_angle_opt.value_or(.0f); + float t_angle = t_angle_opt.value_or(.0f); + do_local_z_rotate(canvas, t_angle - f_angle); } // fix distance (Z move) when exists difference in styles const std::optional &f_move_opt = from.distance; const std::optional &t_move_opt = to.distance; if (!is_approx(f_move_opt, t_move_opt)) { - float f_move = f_move_opt.has_value() ? *f_move_opt : .0f; - float t_move = t_move_opt.has_value() ? *t_move_opt : .0f; - do_local_z_move(m_parent, t_move - f_move); + float f_move = f_move_opt.value_or(.0f); + float t_move = t_move_opt.value_or(.0f); + do_local_z_move(canvas, t_move - f_move); } } +} // namesapce void GLGizmoEmboss::draw_style_list() { 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(); if (is_stored) stored_style = m_style_manager.get_stored_style(); - const EmbossStyle &actual_style = m_style_manager.get_style(); - bool is_changed = (stored_style)? !(*stored_style == actual_style) : true; + const StyleManager::Style ¤t_style = m_style_manager.get_style(); + bool is_changed = (stored_style)? !(*stored_style == current_style) : true; bool is_modified = is_stored && is_changed; const float &max_style_name_width = m_gui_cfg->max_style_name_width; std::string &trunc_name = m_style_manager.get_truncated_name(); if (trunc_name.empty()) { // generate trunc name - std::string current_name = actual_style.name; + std::string current_name = current_style.name; ImGuiWrapper::escape_double_hash(current_name); 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_trunc_names(max_style_name_width); std::optional> swap_indexes; - const std::vector &styles = m_style_manager.get_styles(); - for (const auto &item : styles) { - size_t index = &item - &styles.front(); - const EmbossStyle &style = item.style; + const StyleManager::Styles &styles = m_style_manager.get_styles(); + for (const StyleManager::Style &style : styles) { + size_t index = &style - &styles.front(); const std::string &actual_style_name = style.name; ImGui::PushID(actual_style_name.c_str()); 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 - const std::optional &img = item.image; + float select_height = static_cast(m_gui_cfg->max_style_image_size.y()); + ImVec2 select_size(0.f, select_height); // 0,0 --> calculate in draw + const std::optional &img = style.image; // allow click delete button 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; } else if (ImGui::IsItemHovered()) 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 m_style_manager.free_style_images(); 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? - GUI::format(_L("Modified style \"%1%\""), actual_style.name): - GUI::format(_L("Current style is \"%1%\""), actual_style.name); + GUI::format(_L("Modified style \"%1%\""), current_style.name): + GUI::format(_L("Current style is \"%1%\""), current_style.name); ImGui::SetTooltip(" %s", tooltip.c_str()); } } @@ -2195,7 +2238,7 @@ void GLGizmoEmboss::draw_style_list() { // Check whether user wants lose actual style modification if (selected_style_index.has_value() && is_modified) { 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); MessageDialog not_loaded_style_message(nullptr, message, title, wxICON_WARNING | wxYES|wxNO); if (not_loaded_style_message.ShowModal() != wxID_YES) @@ -2204,12 +2247,12 @@ void GLGizmoEmboss::draw_style_list() { // selected style from combo box 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 - FontProp act_prop = actual_style.prop; // copy - FontProp new_prop = style.prop; // copy + StyleManager::Style cur_s = current_style; // copy + StyleManager::Style new_s = style; // copy if (m_style_manager.load_style(*selected_style_index)) { - fix_transformation(act_prop, new_prop); + ::fix_transformation(cur_s, new_s, m_parent); process(); } else { wxString title = _L("Not valid style."); @@ -2667,11 +2710,10 @@ void GLGizmoEmboss::draw_advanced() return; } - FontProp &font_prop = m_style_manager.get_style().prop; - const auto &cn = m_style_manager.get_font_prop().collection_number; - unsigned int font_index = (cn.has_value()) ? *cn : 0; - const auto &font_info = ff.font_file->infos[font_index]; - + StyleManager::Style ¤t_style = m_style_manager.get_style(); + FontProp ¤t_prop = current_style.prop; + + const FontFile::Info &font_info = ff.font_file->infos[current_prop.collection_number.value_or(0)]; #ifdef SHOW_FONT_FILE_PROPERTY ImGui::SameLine(); 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) + ", cache(" + std::to_string(cache_size) + " glyphs)"; if (font_file->infos.size() > 1) { - unsigned int collection = font_prop.collection_number.has_value() ? - *font_prop.collection_number : 0; + unsigned int collection = current_prop.collection_number.has_value() ? + *current_prop.collection_number : 0; 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); @@ -2692,26 +2734,22 @@ void GLGizmoEmboss::draw_advanced() bool exist_change = false; auto &tr = m_gui_cfg->translations; - const EmbossStyle *stored_style = nullptr; + const StyleManager::Style *stored_style = nullptr; if (m_style_manager.exist_stored_style()) stored_style = m_style_manager.get_stored_style(); - bool can_use_surface = (m_volume==nullptr)? false : - (font_prop.use_surface)? true : // already used surface must have option to uncheck - (m_volume->get_object()->volumes.size() > 1); + bool can_use_surface = (m_volume == nullptr)? false : + (m_volume->emboss_shape->projection.use_surface)? true : // already used surface must have option to uncheck + !m_volume->is_the_only_one_part(); m_imgui->disabled_begin(!can_use_surface); const bool *def_use_surface = stored_style ? - &stored_style->prop.use_surface : nullptr; - if (rev_checkbox(tr.use_surface, font_prop.use_surface, def_use_surface, + &stored_style->projection.use_surface : nullptr; + 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."))) { - if (font_prop.use_surface) { + if (use_surface) // when using surface distance is not used - font_prop.distance.reset(); - - // there should be minimal embossing depth - if (font_prop.emboss < 0.1) - font_prop.emboss = 1; - } + current_style.distance.reset(); process(); } m_imgui->disabled_end(); // !can_use_surface @@ -2724,13 +2762,14 @@ void GLGizmoEmboss::draw_advanced() &stored_style->prop.char_gap : nullptr; int half_ascent = font_info.ascent / 2; - int min_char_gap = -half_ascent, max_char_gap = half_ascent; - if (rev_slider(tr.char_gap, font_prop.char_gap, def_char_gap, _u8L("Revert gap between letters"), + int min_char_gap = -half_ascent; + 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"))){ // Condition prevent recalculation when insertint out of limits value by imgui input - if (!apply(font_prop.char_gap, priv::limits.char_gap) || - !m_volume->text_configuration->style.prop.char_gap.has_value() || - m_volume->text_configuration->style.prop.char_gap != font_prop.char_gap) { + const std::optional &volume_char_gap = m_volume->text_configuration->style.prop.char_gap; + if (!apply(current_prop.char_gap, priv::limits.char_gap) || + !volume_char_gap.has_value() || volume_char_gap != current_prop.char_gap) { // char gap is stored inside of imgui font atlas m_style_manager.clear_imgui_font(); exist_change = true; @@ -2740,13 +2779,14 @@ void GLGizmoEmboss::draw_advanced() // input gap between lines auto def_line_gap = stored_style ? &stored_style->prop.line_gap : nullptr; - int min_line_gap = -half_ascent, max_line_gap = half_ascent; - if (rev_slider(tr.line_gap, font_prop.line_gap, def_line_gap, _u8L("Revert gap between lines"), + int min_line_gap = -half_ascent; + 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"))){ // Condition prevent recalculation when insertint out of limits value by imgui input - if (!apply(font_prop.line_gap, priv::limits.line_gap) || - !m_volume->text_configuration->style.prop.line_gap.has_value() || - m_volume->text_configuration->style.prop.line_gap != font_prop.line_gap) { + const std::optional &volume_line_gap = m_volume->text_configuration->style.prop.line_gap; + if (!apply(current_prop.line_gap, priv::limits.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 m_style_manager.clear_imgui_font(); exist_change = true; @@ -2756,37 +2796,34 @@ void GLGizmoEmboss::draw_advanced() // input boldness auto def_boldness = stored_style ? &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"))){ - if (!apply(font_prop.boldness, priv::limits.boldness.values) || - !m_volume->text_configuration->style.prop.boldness.has_value() || - m_volume->text_configuration->style.prop.boldness != font_prop.boldness) + const std::optional &volume_boldness = m_volume->text_configuration->style.prop.boldness; + if (!apply(current_prop.boldness, priv::limits.boldness.values) || + !volume_boldness.has_value() || volume_boldness != current_prop.boldness) exist_change = true; } // input italic auto def_skew = stored_style ? &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"))){ - if (!apply(font_prop.skew, priv::limits.skew.values) || - !m_volume->text_configuration->style.prop.skew.has_value() || - m_volume->text_configuration->style.prop.skew != font_prop.skew) + const std::optional &volume_skew = m_volume->text_configuration->style.prop.skew; + if (!apply(current_prop.skew, priv::limits.skew.values) || + !volume_skew.has_value() ||volume_skew != current_prop.skew) exist_change = true; } // input surface distance - bool allowe_surface_distance = - !m_volume->text_configuration->style.prop.use_surface && - !m_volume->is_the_only_one_part(); - std::optional &distance = font_prop.distance; - float prev_distance = distance.has_value() ? *distance : .0f, - min_distance = -2 * font_prop.emboss, - max_distance = 2 * font_prop.emboss; + bool allowe_surface_distance = !use_surface && !m_volume->is_the_only_one_part(); + std::optional &distance = current_style.distance; + float prev_distance = distance.value_or(.0f); + float min_distance = static_cast(-2 * current_style.projection.depth); + float max_distance = static_cast(2 * current_style.projection.depth); auto def_distance = stored_style ? - &stored_style->prop.distance : nullptr; - m_imgui->disabled_begin(!allowe_surface_distance); - + &stored_style->distance : nullptr; + m_imgui->disabled_begin(!allowe_surface_distance); bool use_inch = wxGetApp().app_config->get_bool("use_inches"); const std::string undo_move_tooltip = _u8L("Undo translation"); 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; 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()) { - font_prop.distance = *distance_inch * ObjectManipulation::in_to_mm; + distance = *distance_inch * ObjectManipulation::in_to_mm; } else { - font_prop.distance.reset(); + distance.reset(); } is_moved = true; } @@ -2814,23 +2851,19 @@ void GLGizmoEmboss::draw_advanced() min_distance, max_distance, "%.2f mm", move_tooltip)) is_moved = true; } - if (is_moved){ - m_volume->text_configuration->style.prop.distance = font_prop.distance; - float act_distance = font_prop.distance.has_value() ? *font_prop.distance : .0f; - do_local_z_move(m_parent, act_distance - prev_distance); - } - m_imgui->disabled_end(); + if (is_moved) + do_local_z_move(m_parent, distance.value_or(.0f) - prev_distance); + m_imgui->disabled_end(); // allowe_surface_distance // slider for Clock-wise angle in degress // stored angle is optional CCW and in radians // Convert stored value to degress // minus create clock-wise roation from CCW - const std::optional &angle_opt = m_style_manager.get_font_prop().angle; - float angle = angle_opt.has_value() ? *angle_opt: 0.f; + float angle = current_style.angle.value_or(0.f); float angle_deg = static_cast(-angle * 180 / M_PI); float def_angle_deg_val = - (!stored_style || !stored_style->prop.angle.has_value()) ? - 0.f : (*stored_style->prop.angle * -180 / M_PI); + (!stored_style || !stored_style->angle.has_value()) ? + 0.f : (*stored_style->angle * -180 / M_PI); float* def_angle_deg = stored_style ? &def_angle_deg_val : nullptr; 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(m_style_manager.is_active_font()); 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 - if (font_prop.use_surface) + if (use_surface) process(); } ImGui::Text("%s", tr.keep_up.c_str()); ImGui::SameLine(m_gui_cfg->advanced_input_offset); - if (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; - } - } + ImGui::Checkbox("##keep_up", &m_keep_up); if (ImGui::IsItemHovered()) 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::SameLine(m_gui_cfg->advanced_input_offset); ImGui::SetNextItemWidth(m_gui_cfg->input_width); - unsigned int selected = font_prop.collection_number.has_value() ? - *font_prop.collection_number : 0; + unsigned int selected = current_prop.collection_number.has_value() ? + *current_prop.collection_number : 0; if (ImGui::BeginCombo("## Font collection", std::to_string(selected).c_str())) { for (unsigned int i = 0; i < ff.font_file->infos.size(); ++i) { ImGui::PushID(1 << (10 + i)); bool is_selected = (i == selected); if (ImGui::Selectable(std::to_string(i).c_str(), is_selected)) { - if (i == 0) font_prop.collection_number.reset(); - else font_prop.collection_number = i; + if (i == 0) current_prop.collection_number.reset(); + else current_prop.collection_number = i; exist_change = true; } ImGui::PopID(); @@ -2897,25 +2925,24 @@ void GLGizmoEmboss::draw_advanced() if (ImGui::Button(_u8L("Set text to face camera").c_str())) { assert(get_selected_volume(m_parent.get_selection()) == m_volume); - const Camera &cam = wxGetApp().plater()->get_camera(); - bool use_surface = m_style_manager.get_style().prop.use_surface; + const Camera &cam = wxGetApp().plater()->get_camera(); if (face_selected_volume_to_camera(cam, m_parent) && use_surface) process(); } else if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s", _u8L("Use camera direction for text orientation").c_str()); } #ifdef ALLOW_DEBUG_MODE - ImGui::Text("family = %s", (font_prop.family.has_value() ? - font_prop.family->c_str() : + ImGui::Text("family = %s", (current_prop.family.has_value() ? + current_prop.family->c_str() : " --- ")); - ImGui::Text("face name = %s", (font_prop.face_name.has_value() ? - font_prop.face_name->c_str() : + ImGui::Text("face name = %s", (current_prop.face_name.has_value() ? + current_prop.face_name->c_str() : " --- ")); 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() ? - font_prop.weight->c_str() : + ImGui::Text("weight = %s", (current_prop.weight.has_value() ? + current_prop.weight->c_str() : " --- ")); std::string descriptor = style.path; @@ -2961,7 +2988,7 @@ bool GLGizmoEmboss::choose_font_by_wxdialog() data.RestrictSelection(wxFONTRESTRICT_SCALABLE); // set previous selected font 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 selected_font = WxFontUtils::load_wxFont( selected_style.path); 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 const FontProp &fp = this->text_configuration.style.prop; - shape.depth = fp.emboss; - shape.use_surface = fp.use_surface; - shape.distance = fp.distance; + EmbossProjection &p = shape.projection; + p.depth = fp.emboss; + p.use_surface = fp.use_surface; const FontFile &ff = *this->font_file.font_file; 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(); // only temporary solution - volume.text_configuration->style.prop.use_surface = shape.use_surface; - volume.text_configuration->style.prop.distance = shape.distance; + volume.text_configuration->style.prop.use_surface = shape.projection.use_surface; // copy + volume.text_configuration->style.prop.emboss = static_cast(shape.projection.depth); // copy DataBase::write(volume); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index 3422039fa2..8f48628fb6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -32,7 +32,7 @@ namespace Slic3r::GUI { class GLGizmoEmboss : public GLGizmoBase { public: - GLGizmoEmboss(GLCanvas3D& parent); + explicit GLGizmoEmboss(GLCanvas3D& parent); /// /// Create new embossed text volume by type on position of mouse @@ -51,8 +51,8 @@ protected: bool on_init() override; std::string on_get_name() const override; void on_render() override; - virtual void on_register_raycasters_for_picking() override; - virtual void on_unregister_raycasters_for_picking() override; + void on_register_raycasters_for_picking() override; + void on_unregister_raycasters_for_picking() 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_selectable() const override { return false; } @@ -90,7 +90,6 @@ private: void draw_window(); void draw_text_input(); void draw_model_type(); - void fix_transformation(const FontProp &from, const FontProp &to); void draw_style_list(); void draw_delete_style_button(); void draw_style_rename_popup(); @@ -308,8 +307,8 @@ private: // Keep data about dragging only during drag&drop std::optional m_surface_drag; - // TODO: it should be accessible by other gizmo too. - // May be move to plater? + // Keep old scene triangle data in AABB trees, + // all the time it need actualize before use. RaycastManager m_raycast_manager; // For text on scaled objects diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 8c56912b5f..54ff00cbdf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -398,7 +398,7 @@ void GLGizmoSVG::on_stop_dragging() // recalculate for surface cut if (m_volume != nullptr && m_volume->emboss_shape.has_value() && - m_volume->emboss_shape->use_surface) + m_volume->emboss_shape->projection.use_surface) process(); } 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 shape; - shape.depth = 10.; - shape.distance = 0; - shape.use_surface = false; + shape.projection.depth = 10.; + shape.projection.use_surface = false; shape.svg_file_path = choose_svg_file(); if (shape.svg_file_path.empty()) diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index c1671db2d7..15f9296374 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -825,10 +825,10 @@ void update_volume(TriangleMesh &&mesh, const DataUpdate &data, const Transform3 volume->set_transformation(*tr); } else { // apply fix matrix made by store to .3mf - const auto &tc = volume->text_configuration; - assert(tc.has_value()); - if (tc.has_value() && tc->fix_3mf_tr.has_value()) - volume->set_transformation(volume->get_matrix() * tc->fix_3mf_tr->inverse()); + const std::optional &emboss_shape = volume->emboss_shape; + assert(emboss_shape.has_value()); + if (emboss_shape.has_value() && emboss_shape->fix_3mf_tr.has_value()) + volume->set_transformation(volume->get_matrix() * emboss_shape->fix_3mf_tr->inverse()); } UpdateJob::update_volume(volume, std::move(mesh), *data.base); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index 173eec399e..7a3a39b7b7 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -37,8 +37,8 @@ class DataBase public: DataBase(const std::string& volume_name, std::shared_ptr> cancel) : volume_name(volume_name), cancel(std::move(cancel)) {} DataBase(const std::string& volume_name, std::shared_ptr> 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; /// diff --git a/src/slic3r/GUI/SurfaceDrag.cpp b/src/slic3r/GUI/SurfaceDrag.cpp index b80e1fb894..a65acd452a 100644 --- a/src/slic3r/GUI/SurfaceDrag.cpp +++ b/src/slic3r/GUI/SurfaceDrag.cpp @@ -93,25 +93,28 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, // detect start text dragging if (mouse_event.LeftDown()) { // selected volume - GLVolume *gl_volume = get_selected_gl_volume(canvas); - if (gl_volume == nullptr) + GLVolume *gl_volume_ptr = get_selected_gl_volume(canvas); + if (gl_volume_ptr == nullptr) return false; + const GLVolume &gl_volume = *gl_volume_ptr; // is selected volume closest hovered? - const GLVolumePtrs &gl_volumes = canvas.get_volumes().volumes; - int hovered_idx = canvas.get_first_hover_volume_idx(); - if (hovered_idx < 0 || - hovered_idx >= gl_volumes.size() || - gl_volumes[hovered_idx] != gl_volume) + const GLVolumePtrs &gl_volumes = canvas.get_volumes().volumes; + if (int hovered_idx = canvas.get_first_hover_volume_idx(); + hovered_idx < 0) + return false; + else if (auto hovered_idx_ = static_cast(hovered_idx); + hovered_idx_ >= gl_volumes.size() || + gl_volumes[hovered_idx_] != gl_volume_ptr) 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); if (object == nullptr) return false; - const ModelInstance *instance = get_model_instance(*gl_volume, *object); - const ModelVolume *volume = get_model_volume(*gl_volume, *object); + 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 false; @@ -124,7 +127,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, std::vector allowed_volumes_id; if (volumes.size() > 1) { allowed_volumes_id.reserve(volumes.size() - 1); - for (auto &v : volumes) { + for (const ModelVolume *v : volumes) { // skip actual selected object if (v->id() == volume->id()) continue; @@ -146,7 +149,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, Vec2d mouse_pos = mouse_coord.cast(); 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()) { const TextConfiguration &tc = *volume->text_configuration; @@ -161,7 +164,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, std::optional start_angle; if (up_limit.has_value()) 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 canvas.enable_moving(false); diff --git a/src/slic3r/Utils/EmbossStyleManager.cpp b/src/slic3r/Utils/EmbossStyleManager.cpp index 32e003c6d7..af9013301b 100644 --- a/src/slic3r/Utils/EmbossStyleManager.cpp +++ b/src/slic3r/Utils/EmbossStyleManager.cpp @@ -14,13 +14,9 @@ using namespace Slic3r; using namespace Slic3r::Emboss; using namespace Slic3r::GUI::Emboss; -StyleManager::StyleManager(const ImWchar *language_glyph_range, std::function create_default_styles) - : m_imgui_init_glyph_range(language_glyph_range) - , m_create_default_styles(create_default_styles) - , m_exist_style_images(false) - , m_temp_style_images(nullptr) - , m_app_config(nullptr) - , m_last_style_index(std::numeric_limits::max()) +StyleManager::StyleManager(const ImWchar *language_glyph_range, const std::function& create_default_styles) + : m_create_default_styles(create_default_styles) + , m_imgui_init_glyph_range(language_glyph_range) {} StyleManager::~StyleManager() { @@ -32,24 +28,26 @@ StyleManager::~StyleManager() { /// For store/load emboss style to/from AppConfig /// namespace { -void store_style_index(AppConfig &cfg, unsigned index); +void store_style_index(AppConfig &cfg, size_t index); ::std::optional load_style_index(const AppConfig &cfg); -EmbossStyles load_styles(const AppConfig &cfg); -void store_styles(AppConfig &cfg, const EmbossStyles &styles); +StyleManager::Styles load_styles(const AppConfig &cfg); +void store_styles(AppConfig &cfg, const StyleManager::Styles &styles); +void make_unique_name(const StyleManager::Styles &styles, std::string &name); } // namespace void StyleManager::init(AppConfig *app_config) { m_app_config = app_config; - EmbossStyles styles = (app_config != nullptr) ? - ::load_styles(*app_config) : - EmbossStyles{}; - if (styles.empty()) - styles = m_create_default_styles(); - for (EmbossStyle &style : styles) { - make_unique_name(style.name); - m_style_items.push_back({style}); + m_styles = ::load_styles(*app_config); + + if (m_styles.empty()) { + // No styles loaded from ini file so use default + EmbossStyles styles = m_create_default_styles(); + for (EmbossStyle &style : styles) { + ::make_unique_name(m_styles, style.name); + m_styles.push_back({style}); + } } std::optional active_index_opt = (app_config != nullptr) ? @@ -58,14 +56,14 @@ void StyleManager::init(AppConfig *app_config) size_t active_index = 0; 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 if (load_style(active_index)) return; // style is 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(); } @@ -77,14 +75,14 @@ bool StyleManager::store_styles_to_app_config(bool use_modification, bool store_ if (use_modification) { if (exist_stored_style()) { // 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 { // add new into stored list 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.style_index = m_style_items.size(); - m_style_items.push_back({style}); + m_style_cache.style_index = m_styles.size(); + m_styles.push_back({style}); } 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); } - EmbossStyles 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); + store_styles(*m_app_config, m_styles); return true; } void StyleManager::add_style(const std::string &name) { EmbossStyle& style = m_style_cache.style; style.name = name; - make_unique_name(style.name); - m_style_cache.style_index = m_style_items.size(); + ::make_unique_name(m_styles, style.name); + m_style_cache.style_index = m_styles.size(); m_style_cache.stored_wx_font = m_style_cache.wx_font; 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) { - if (i1 >= m_style_items.size() || - i2 >= m_style_items.size()) return; - std::swap(m_style_items[i1], m_style_items[i2]); + if (i1 >= m_styles.size() || + i2 >= m_styles.size()) return; + std::swap(m_styles[i1], m_styles[i2]); // fix selected index if (!exist_stored_style()) return; if (m_style_cache.style_index == i1) { @@ -141,7 +136,7 @@ void StyleManager::discard_style_changes() { } void StyleManager::erase(size_t index) { - if (index >= m_style_items.size()) return; + if (index >= m_styles.size()) return; // fix selected index if (exist_stored_style()) { @@ -150,15 +145,15 @@ void StyleManager::erase(size_t index) { else if (index == i) i = std::numeric_limits::max(); } - m_style_items.erase(m_style_items.begin() + index); + m_styles.erase(m_styles.begin() + index); } void StyleManager::rename(const std::string& name) { m_style_cache.style.name = name; m_style_cache.truncated_name.clear(); if (exist_stored_style()) { - Item &it = m_style_items[m_style_cache.style_index]; - it.style.name = name; + Style &it = m_styles[m_style_cache.style_index]; + it.name = name; it.truncated_name.clear(); } } @@ -166,28 +161,28 @@ void StyleManager::rename(const std::string& name) { void StyleManager::load_valid_style() { // iterate over all known styles - while (!m_style_items.empty()) { + while (!m_styles.empty()) { if (load_style(0)) return; // 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 // set up default font list EmbossStyles def_style = m_create_default_styles(); for (EmbossStyle &style : def_style) { - make_unique_name(style.name); - m_style_items.push_back({std::move(style)}); + ::make_unique_name(m_styles, style.name); + m_styles.push_back({std::move(style)}); } // iterate over default styles // There have to be option to use build in font - while (!m_style_items.empty()) { + while (!m_styles.empty()) { if (load_style(0)) return; // 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, @@ -197,15 +192,15 @@ void StyleManager::load_valid_style() bool StyleManager::load_style(size_t style_index) { - if (style_index >= m_style_items.size()) return false; - if (!load_style(m_style_items[style_index].style)) return false; + if (style_index >= m_styles.size()) return false; + if (!load_style(m_styles[style_index])) return false; m_style_cache.style_index = style_index; m_style_cache.stored_wx_font = m_style_cache.wx_font; // copy m_last_style_index = style_index; return true; } -bool StyleManager::load_style(const EmbossStyle &style) { +bool StyleManager::load_style(const Style &style) { if (style.type == EmbossStyle::Type::file_path) { std::unique_ptr font_ptr = create_font_file(style.path.c_str()); @@ -218,13 +213,13 @@ bool StyleManager::load_style(const EmbossStyle &style) { m_style_cache.stored_wx_font = {}; return true; } - if (style.type != WxFontUtils::get_actual_type()) return false; + if (style.type != WxFontUtils::get_current_type()) return false; std::optional wx_font_opt = WxFontUtils::load_wxFont(style.path); if (!wx_font_opt.has_value()) return false; 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 @@ -275,12 +270,19 @@ bool StyleManager::is_font_changed() const 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(); } -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; - return &m_style_items[m_style_cache.style_index].style; + if (m_style_cache.style_index >= m_styles.size()) return nullptr; + return &m_styles[m_style_cache.style_index]; } void StyleManager::clear_glyphs_cache() @@ -308,44 +310,11 @@ ImFont *StyleManager::get_imgui_font() return font; } -const std::vector &StyleManager::get_styles() const{ return m_style_items; } - -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; -} - +const StyleManager::Styles &StyleManager::get_styles() const{ return m_styles; } void StyleManager::init_trunc_names(float max_width) { - for (auto &s : m_style_items) + for (auto &s : m_styles) if (s.truncated_name.empty()) { - std::string name = s.style.name; + std::string name = s.name; ImGuiWrapper::escape_double_hash(name); 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]; // find style in font list and copy to it - for (auto &it : m_style_items) { - if (it.style.name != style.text || - !(it.style.prop == style.prop)) + for (auto &it : m_styles) { + if (it.name != style.text || + !(it.prop == style.prop)) continue; it.image = image; break; @@ -397,9 +366,8 @@ void StyleManager::init_style_images(const Vec2i &max_size, // create job for init images m_temp_style_images = std::make_shared(); StyleImagesData::Items styles; - styles.reserve(m_style_items.size()); - for (const Item &item : m_style_items) { - const EmbossStyle &style = item.style; + styles.reserve(m_styles.size()); + for (const Style &style : m_styles) { std::optional wx_font_opt = WxFontUtils::load_wxFont(style.path); if (!wx_font_opt.has_value()) continue; std::unique_ptr font_file = @@ -426,7 +394,7 @@ void StyleManager::init_style_images(const Vec2i &max_size, void StyleManager::free_style_images() { if (!m_exist_style_images) return; GLuint tex_id = 0; - for (Item &it : m_style_items) { + for (Style &it : m_styles) { if (tex_id == 0 && it.image.has_value()) tex_id = (GLuint)(intptr_t) it.image->texture_id; it.image.reset(); @@ -546,7 +514,7 @@ bool StyleManager::set_wx_font(const wxFont &wx_font, std::unique_ptr FontFileWithCache(std::move(font_file)); EmbossStyle &style = m_style_cache.style; - style.type = WxFontUtils::get_actual_type(); + style.type = WxFontUtils::get_current_type(); // update string path style.path = WxFontUtils::store_wxFont(wx_font); WxFontUtils::update_property(style.prop, wx_font); @@ -664,51 +632,55 @@ bool read(const Section §ion, const std::string &key, std::optional & return true; } -std::optional load_style(const Section &app_cfg_section) +std::optional load_style(const Section &app_cfg_section) { auto path_it = app_cfg_section.find(APP_CONFIG_FONT_DESCRIPTOR); if (path_it == app_cfg_section.end()) return {}; - const std::string &path = path_it->second; - - auto name_it = app_cfg_section.find(APP_CONFIG_FONT_NAME); + + 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); 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_DEPTH, fp.emboss); - read(app_cfg_section, APP_CONFIG_FONT_USE_SURFACE, fp.use_surface); + read(app_cfg_section, APP_CONFIG_FONT_DEPTH, depth);ep.depth = depth; + 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_SKEW, fp.skew); - read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, fp.distance); - read(app_cfg_section, APP_CONFIG_FONT_ANGLE, fp.angle); + read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, s.distance); + 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_CHAR_GAP, fp.char_gap); read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap); - - EmbossStyle::Type type = WxFontUtils::get_actual_type(); - return EmbossStyle{name, path, type, fp}; + return s; } -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; - data[APP_CONFIG_FONT_NAME] = fi.name; - data[APP_CONFIG_FONT_DESCRIPTOR] = fi.path; - const FontProp &fp = fi.prop; + data[APP_CONFIG_FONT_NAME] = s.name; + data[APP_CONFIG_FONT_DESCRIPTOR] = s.path; + const FontProp &fp = s.prop; data[APP_CONFIG_FONT_LINE_HEIGHT] = std::to_string(fp.size_in_mm); - data[APP_CONFIG_FONT_DEPTH] = std::to_string(fp.emboss); - if (fp.use_surface) + data[APP_CONFIG_FONT_DEPTH] = std::to_string(ep.depth); + if (ep.use_surface) data[APP_CONFIG_FONT_USE_SURFACE] = "true"; if (fp.boldness.has_value()) data[APP_CONFIG_FONT_BOLDNESS] = std::to_string(*fp.boldness); if (fp.skew.has_value()) data[APP_CONFIG_FONT_SKEW] = std::to_string(*fp.skew); - if (fp.distance.has_value()) - data[APP_CONFIG_FONT_DISTANCE] = std::to_string(*fp.distance); - if (fp.angle.has_value()) - data[APP_CONFIG_FONT_ANGLE] = std::to_string(*fp.angle); + if (s.distance.has_value()) + data[APP_CONFIG_FONT_DISTANCE] = std::to_string(*s.distance); + if (s.angle.has_value()) + data[APP_CONFIG_FONT_ANGLE] = std::to_string(*s.angle); if (fp.collection_number.has_value()) data[APP_CONFIG_FONT_COLLECTION] = std::to_string(*fp.collection_number); 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)); } -void store_style_index(AppConfig &cfg, unsigned index) +void store_style_index(AppConfig &cfg, size_t index) { // store actual font index // active font first index is +1 to correspond with section name @@ -742,29 +714,34 @@ std::optional load_style_index(const AppConfig &cfg) 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 !! unsigned index = 1; std::string section_name = create_section_name(index); while (cfg.has_section(section_name)) { - std::optional style_opt = load_style(cfg.get_section(section_name)); - if (style_opt.has_value()) + std::optional style_opt = load_style(cfg.get_section(section_name)); + if (style_opt.has_value()) { + make_unique_name(result, style_opt->name); result.emplace_back(*style_opt); + } + section_name = create_section_name(++index); } 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 unsigned index = 1; - for (const EmbossStyle &style : styles) { + for (const StyleManager::Style &style : styles) { // skip file paths + fonts from other OS(loaded from .3mf) - assert(style.type == WxFontUtils::get_actual_type()); - // if (style_opt.type != WxFontUtils::get_actual_type()) continue; + assert(style.type == current_type); + if (style.type != current_type) + continue; store_style(cfg, style, 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 diff --git a/src/slic3r/Utils/EmbossStyleManager.hpp b/src/slic3r/Utils/EmbossStyleManager.hpp index 5bab7adce5..492d3f51c4 100644 --- a/src/slic3r/Utils/EmbossStyleManager.hpp +++ b/src/slic3r/Utils/EmbossStyleManager.hpp @@ -24,11 +24,10 @@ namespace Slic3r::GUI::Emboss { class StyleManager { friend class CreateFontStyleImagesJob; // access to StyleImagesData - public: /// Character to load for imgui when initialize imgui font /// Function to create default styles - StyleManager(const ImWchar *language_glyph_range, std::function create_default_styles); + StyleManager(const ImWchar *language_glyph_range, const std::function& create_default_styles); /// /// Release imgui font and style images from GPU @@ -59,11 +58,11 @@ public: void add_style(const std::string& name); /// - /// 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 /// - /// First index to m_style_items - /// Second index to m_style_items + /// First index to m_styles + /// Second index to m_styles void swap(size_t i1, size_t i2); /// @@ -73,7 +72,7 @@ public: void discard_style_changes(); /// - /// Remove style from m_style_items. + /// Remove style from m_styles. /// Fix selected font index when index is under m_font_selected /// /// Index of style to be removed @@ -94,13 +93,14 @@ public: /// Change active font /// When font not loaded roll back activ font /// - /// New font index(from m_style_items range) + /// New font index(from m_styles range) /// True on succes. False on fail load font bool load_style(size_t font_index); // 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 - bool load_style(const EmbossStyle &style, const wxFont &font); + bool load_style(const Style &style, const wxFont &font); // clear actual selected glyphs cache void clear_glyphs_cache(); @@ -109,10 +109,10 @@ public: void clear_imgui_font(); // 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; } - EmbossStyle &get_style() { return m_style_cache.style; } + const Style &get_style() const { 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; } std::string &get_truncated_name() { return m_style_cache.truncated_name; } const ImFontAtlas &get_atlas() const { return m_style_cache.atlas; } @@ -133,6 +133,8 @@ public: /// bool is_font_changed() const; + bool is_unique_style_name(const std::string &name) const; + /// /// Setter on wx_font when changed /// @@ -167,33 +169,28 @@ public: void init_style_images(const Vec2i& max_size, const std::string &text); void free_style_images(); - struct Item; // access to all managed font styles - const std::vector &get_styles() const; + const std::vector