From ee3546b1860c5ca87e7dc8b5408452d93aea2949 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 18 Jan 2024 13:07:35 +0100 Subject: [PATCH] SPE-2103 Make snap-shot to undo/redo stack only on release slider Connected with attributes: Text/advanced(char gap, line gap, boldness, skew ratio) SVG(size) Also change range for Boldness. VRT font-Ascent. (different font may have different slider value range) Fix line gap (it was denied when per glyph was false) --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 55 +++++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp | 23 ++++++++--- src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp | 2 +- src/slic3r/GUI/Jobs/EmbossJob.cpp | 11 +++-- src/slic3r/GUI/Jobs/EmbossJob.hpp | 3 ++ 6 files changed, 67 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 98cf7a9a88..1486c863a1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -96,7 +96,7 @@ static const struct Limits { MinMax emboss{0.01, 1e4}; // in mm MinMax size_in_mm{0.1f, 1000.f}; // in mm - Limit boldness{{-200.f, 200.f}, {-2e4f, 2e4f}}; // in font points + Limit boldness{{-.5f, .5f}, {-5e5f, 5e5f}}; // in font points Limit skew{{-1.f, 1.f}, {-100.f, 100.f}}; // ration without unit MinMax char_gap{-20000, 20000}; // in font points MinMax line_gap{-20000, 20000}; // in font points @@ -380,7 +380,7 @@ bool GLGizmoEmboss::re_emboss(const ModelVolume &text_volume, std::shared_ptrcanvas3D()->get_selection(); DataBasePtr base = create_emboss_data_base(tc.text, style_manager, text_lines, selection, text_volume.type(), job_cancel); - DataUpdate data{std::move(base), text_volume.id()}; + DataUpdate data{std::move(base), text_volume.id(), false}; RaycastManager raycast_manager; // Nothing is cached now, so It need to create raycasters return start_update_volume(std::move(data), text_volume, selection, raycast_manager); @@ -1316,7 +1316,7 @@ namespace { bool is_text_empty(std::string_view text) { return text.empty() || text.find_first_not_of(" \n\t\r") == std::string::npos; } } // namespace -bool GLGizmoEmboss::process() +bool GLGizmoEmboss::process(bool make_snapshot) { // no volume is selected -> selection from right panel assert(m_volume != nullptr); @@ -1330,7 +1330,7 @@ bool GLGizmoEmboss::process() const Selection& selection = m_parent.get_selection(); DataBasePtr base = create_emboss_data_base(m_text, m_style_manager, m_text_lines, selection, m_volume->type(), m_job_cancel); - DataUpdate data{std::move(base), m_volume->id()}; + DataUpdate data{std::move(base), m_volume->id(), make_snapshot}; // check valid count of text lines assert(data.base->text_lines.empty() || data.base->text_lines.size() == get_count_lines(m_text)); @@ -2665,7 +2665,6 @@ void GLGizmoEmboss::draw_advanced() m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property); #endif // SHOW_FONT_FILE_PROPERTY - bool exist_change = false; auto &tr = m_gui_cfg->translations; const StyleManager::Style *stored_style = nullptr; @@ -2757,6 +2756,7 @@ void GLGizmoEmboss::draw_advanced() auto def_char_gap = stored_style ? &stored_style->prop.char_gap : nullptr; + bool exist_change = false; int half_ascent = font_info.ascent / 2; int min_char_gap = -half_ascent; int max_char_gap = half_ascent; @@ -2772,13 +2772,16 @@ void GLGizmoEmboss::draw_advanced() exist_change = true; } } + bool last_change = false; + if (m_imgui->get_last_slider_status().deactivated_after_edit) + last_change = true; // input gap between lines - bool is_multiline = m_text_lines.get_lines().size() > 1; + bool is_multiline = get_count_lines(m_volume->text_configuration->text) > 1; // TODO: cache count lines m_imgui->disabled_begin(!is_multiline); auto def_line_gap = stored_style ? &stored_style->prop.line_gap : nullptr; - int min_line_gap = -half_ascent; + 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"))){ @@ -2793,18 +2796,24 @@ void GLGizmoEmboss::draw_advanced() exist_change = true; } } + if (m_imgui->get_last_slider_status().deactivated_after_edit) + last_change = true; m_imgui->disabled_end(); // !is_multiline // input boldness auto def_boldness = stored_style ? &stored_style->prop.boldness : nullptr; + int min_boldness = static_cast(font_info.ascent * limits.boldness.gui.min); + int max_boldness = static_cast(font_info.ascent * limits.boldness.gui.max); if (rev_slider(tr.boldness, current_prop.boldness, def_boldness, _u8L("Undo boldness"), - limits.boldness.gui.min, limits.boldness.gui.max, units_fmt, _L("Tiny / Wide glyphs"))){ + min_boldness, max_boldness, units_fmt, _L("Tiny / Wide glyphs"))){ const std::optional &volume_boldness = m_volume->text_configuration->style.prop.boldness; if (!apply(current_prop.boldness, limits.boldness.values) || !volume_boldness.has_value() || volume_boldness != current_prop.boldness) exist_change = true; } + if (m_imgui->get_last_slider_status().deactivated_after_edit) + last_change = true; // input italic auto def_skew = stored_style ? @@ -2816,6 +2825,8 @@ void GLGizmoEmboss::draw_advanced() !volume_skew.has_value() ||volume_skew != current_prop.skew) exist_change = true; } + if (m_imgui->get_last_slider_status().deactivated_after_edit) + last_change = true; // input surface distance bool allowe_surface_distance = !use_surface && !m_volume->is_the_only_one_part(); @@ -2855,15 +2866,18 @@ void GLGizmoEmboss::draw_advanced() if (is_moved){ if (font_prop.per_glyph){ - process(); + process(false); } else { do_local_z_move(m_parent.get_selection(), distance.value_or(.0f) - prev_distance); } } // Apply move to model(backend) - if (m_imgui->get_last_slider_status().deactivated_after_edit) - m_parent.do_rotate(move_snapshot_name); + if (m_imgui->get_last_slider_status().deactivated_after_edit) { + m_parent.do_move(move_snapshot_name); + if (font_prop.per_glyph) + process(); + } m_imgui->disabled_end(); // allowe_surface_distance @@ -2901,11 +2915,17 @@ void GLGizmoEmboss::draw_advanced() // recalculate for surface cut if (use_surface || font_prop.per_glyph) + process(false); + } + + // Apply rotation on model (backend) + if (m_imgui->get_last_slider_status().deactivated_after_edit) { + m_parent.do_rotate(rotation_snapshot_name); + + // recalculate for surface cut + if (use_surface || font_prop.per_glyph) process(); } - // Apply rotation on model (backend) - if (m_imgui->get_last_slider_status().deactivated_after_edit) - m_parent.do_rotate(rotation_snapshot_name); // Keep up - lock button icon if (!m_volume->is_the_only_one_part()) { @@ -2937,6 +2957,7 @@ void GLGizmoEmboss::draw_advanced() if (i == 0) current_prop.collection_number.reset(); else current_prop.collection_number = i; exist_change = true; + last_change = true; } ImGui::PopID(); } @@ -2946,13 +2967,13 @@ void GLGizmoEmboss::draw_advanced() } } - if (exist_change) { + if (exist_change || last_change) { m_style_manager.clear_glyphs_cache(); - if (m_style_manager.get_font_prop().per_glyph) + if (font_prop.per_glyph) reinit_text_lines(); else m_text_lines.reset(); - process(); + process(last_change); } if (ImGui::Button(_u8L("Set text to face camera").c_str())) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index aac28f1b89..f2187e46b1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -114,7 +114,7 @@ private: void reset_volume(); // create volume from text - main functionality - bool process(); + bool process(bool make_snapshot = true); void close(); void draw_window(); void draw_text_input(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 3f02201955..eedbfd4295 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -1274,8 +1274,7 @@ void GLGizmoSVG::calculate_scale() { float GLGizmoSVG::get_scale_for_tolerance(){ return std::max(m_scale_width.value_or(1.f), m_scale_height.value_or(1.f)); } -bool GLGizmoSVG::process() -{ +bool GLGizmoSVG::process(bool make_snapshot) { // no volume is selected -> selection from right panel assert(m_volume != nullptr); if (m_volume == nullptr) @@ -1296,7 +1295,7 @@ bool GLGizmoSVG::process() EmbossShape shape = m_volume_shape; // copy auto base = std::make_unique(m_volume->name, m_job_cancel, std::move(shape)); base->is_outside = m_volume->type() == ModelVolumeType::MODEL_PART; - DataUpdate data{std::move(base), m_volume_id}; + DataUpdate data{std::move(base), m_volume_id, make_snapshot}; return start_update_volume(std::move(data), *m_volume, m_parent.get_selection(), m_raycast_manager); } @@ -1690,6 +1689,8 @@ void GLGizmoSVG::draw_size() }; std::optional new_relative_scale; + bool make_snap = false; + if (m_keep_ratio) { std::stringstream ss; ss << std::setprecision(2) << std::fixed << width << " x " << height << " " << (use_inch ? "in" : "mm"); @@ -1708,6 +1709,8 @@ void GLGizmoSVG::draw_size() new_relative_scale = Vec3d(width_ratio, width_ratio, 1.); } } + if (m_imgui->get_last_slider_status().deactivated_after_edit) + make_snap = true; // only last change of slider make snap } else { ImGuiInputTextFlags flags = 0; @@ -1727,6 +1730,7 @@ void GLGizmoSVG::draw_size() if (is_valid_scale_ratio(width_ratio)) { m_scale_width = m_scale_width.value_or(1.f) * width_ratio; new_relative_scale = Vec3d(width_ratio, 1., 1.); + make_snap = true; } } if (ImGui::IsItemHovered()) @@ -1740,6 +1744,7 @@ void GLGizmoSVG::draw_size() if (is_valid_scale_ratio(height_ratio)) { m_scale_height = m_scale_height.value_or(1.f) * height_ratio; new_relative_scale = Vec3d(1., height_ratio, 1.); + make_snap = true; } } if (ImGui::IsItemHovered()) @@ -1761,6 +1766,7 @@ void GLGizmoSVG::draw_size() if (can_reset) { if (reset_button(m_icons)) { new_relative_scale = Vec3d(1./m_scale_width.value_or(1.f), 1./m_scale_height.value_or(1.f), 1.); + make_snap = true; } else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Reset scale").c_str()); } @@ -1774,20 +1780,25 @@ void GLGizmoSVG::draw_size() }; selection_transform(selection, selection_scale_fnc); - m_parent.do_scale(L("Resize")); + std::string snap_name; // Empty mean do not store on undo/redo stack + m_parent.do_scale(snap_name); wxGetApp().obj_manipul()->set_dirty(); // should be the almost same calculate_scale(); - NSVGimage *img = m_volume_shape.svg_file->image.get(); + const NSVGimage *img = m_volume_shape.svg_file->image.get(); assert(img != NULL); if (img != NULL){ NSVGLineParams params{get_tesselation_tolerance(get_scale_for_tolerance())}; m_volume_shape.shapes_with_ids = create_shape_with_ids(*img, params); m_volume_shape.final_shape = {}; // reset cache for final shape - process(); + if (!make_snap) // Be carefull: Last change may be without change of scale + process(false); } } + + if (make_snap) + process(); // make undo/redo snap-shot } void GLGizmoSVG::draw_use_surface() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp index 36b1258340..103051c0fa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp @@ -112,7 +112,7 @@ private: void reset_volume(); // create volume from text - main functionality - bool process(); + bool process(bool make_snapshot = true); void close(); void draw_window(); void draw_preview(); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 32b0effbd7..1a72cd7dfc 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -1031,10 +1031,13 @@ void update_volume(TriangleMesh &&mesh, const DataUpdate &data, const Transform3 assert(plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Emboss || plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Svg); - // TRN: This is the name of the action appearing in undo/redo stack. - std::string snap_name = _u8L("Text/SVG attribute change"); - Plater::TakeSnapshot snapshot(plater, snap_name, UndoRedo::SnapshotType::GizmoAction); - + if (data.make_snapshot) { + // TRN: This is the title of the action appearing in undo/redo stack. + // It is same for Text and SVG. + std::string snap_name = _u8L("Emboss attribute change"); + Plater::TakeSnapshot snapshot(plater, snap_name, UndoRedo::SnapshotType::GizmoAction); + } + ModelVolume *volume = get_model_volume(data.volume_id, plater->model().objects); // could appear when user delete edited volume diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index 8dec29572c..46061f3bce 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -113,6 +113,9 @@ struct DataUpdate // unique identifier of volume to change ObjectID volume_id; + + // Used for prevent flooding Undo/Redo stack on slider. + bool make_snapshot; }; ///