diff --git a/src/libslic3r/EmbossShape.hpp b/src/libslic3r/EmbossShape.hpp index 3e65120097..3e4a950037 100644 --- a/src/libslic3r/EmbossShape.hpp +++ b/src/libslic3r/EmbossShape.hpp @@ -105,6 +105,7 @@ struct EmbossShape // Note: image is only cache it is not neccessary to store // Store file data as plain string + // For Embossed text file_data are nullptr ar(path, path_in_3mf, (file_data != nullptr) ? *file_data : std::string("")); } template void load(Archive &ar) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index fa13dd8316..ff5b7720f2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -81,6 +81,14 @@ using namespace Slic3r::GUI; using namespace Slic3r::GUI::Emboss; namespace { +// TRN - Title in Undo/Redo stack after rotate with text around emboss axe +const std::string rotation_snapshot_name = L("Text rotate"); +// NOTE: Translation is made in "m_parent.do_rotate()" + +// TRN - Title in Undo/Redo stack after move with text along emboss axe - From surface +const std::string move_snapshot_name = L("Text move"); +// NOTE: Translation is made in "m_parent.do_translate()" + template struct Limit { // Limitation for view slider range in GUI MinMax gui; @@ -92,7 +100,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 @@ -377,7 +385,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); @@ -965,7 +973,7 @@ void GLGizmoEmboss::on_stop_dragging() m_rotate_gizmo.set_angle(PI/2); // apply rotation - m_parent.do_rotate(L("Text-Rotate")); + m_parent.do_rotate(rotation_snapshot_name); m_rotate_start_angle.reset(); volume_transformation_changed(); } @@ -1287,7 +1295,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); @@ -1301,7 +1309,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)); @@ -2129,7 +2137,9 @@ void fix_transformation(const StyleManager::Style &from, const StyleManager::Sty // fix rotation 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); + do_local_z_rotate(canvas.get_selection(), t_angle - f_angle); + std::string no_snapshot; + canvas.do_rotate(no_snapshot); } // fix distance (Z move) when exists difference in styles @@ -2138,7 +2148,9 @@ void fix_transformation(const StyleManager::Style &from, const StyleManager::Sty if (!is_approx(f_move_opt, t_move_opt)) { 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); + do_local_z_move(canvas.get_selection(), t_move - f_move); + std::string no_snapshot; + canvas.do_move(no_snapshot); } } } // namesapce @@ -2408,6 +2420,10 @@ bool GLGizmoEmboss::revertible(const std::string &name, ImGui::SameLine(undo_offset); // change cursor postion if (draw_button(m_icons, IconType::undo)) { value = *default_value; + + // !! Fix to detect change of value after revert of float-slider + m_imgui->get_last_slider_status().deactivated_after_edit = true; + return true; } else if (ImGui::IsItemHovered()) m_imgui->tooltip(undo_tooltip, m_gui_cfg->max_tooltip_width); @@ -2645,7 +2661,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; @@ -2737,6 +2752,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; @@ -2752,13 +2768,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"))){ @@ -2773,18 +2792,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 ? @@ -2796,6 +2821,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(); @@ -2835,11 +2862,19 @@ void GLGizmoEmboss::draw_advanced() if (is_moved){ if (font_prop.per_glyph){ - process(); + process(false); } else { - do_local_z_move(m_parent, distance.value_or(.0f) - prev_distance); + 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_move(move_snapshot_name); + if (font_prop.per_glyph) + process(); + } + m_imgui->disabled_end(); // allowe_surface_distance // slider for Clock-wise angle in degress @@ -2861,7 +2896,7 @@ void GLGizmoEmboss::draw_advanced() Geometry::to_range_pi_pi(angle_rad); double diff_angle = angle_rad - angle; - do_local_z_rotate(m_parent, diff_angle); + do_local_z_rotate(m_parent.get_selection(), diff_angle); // calc angle after rotation const Selection &selection = m_parent.get_selection(); @@ -2876,6 +2911,15 @@ 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(); } @@ -2912,6 +2956,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(); } @@ -2924,13 +2969,13 @@ void GLGizmoEmboss::draw_advanced() m_imgui->tooltip(tooltip, m_gui_cfg->max_tooltip_width); } - 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 6217c3f128..968dde2818 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 481888bfa8..db6a7f2f2d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -55,6 +55,14 @@ GLGizmoSVG::GLGizmoSVG(GLCanvas3D &parent) // Private functions to create emboss volume namespace{ +// TRN - Title in Undo/Redo stack after rotate with SVG around emboss axe +const std::string rotation_snapshot_name = L("SVG rotate"); +// NOTE: Translation is made in "m_parent.do_rotate()" + +// TRN - Title in Undo/Redo stack after move with SVG along emboss axe - From surface +const std::string move_snapshot_name = L("SVG move"); +// NOTE: Translation is made in "m_parent.do_translate()" + // Variable keep limits for variables const struct Limits { @@ -537,7 +545,7 @@ void GLGizmoSVG::on_stop_dragging() // apply rotation // TRN This is an item label in the undo-redo stack. - m_parent.do_rotate(L("SVG-Rotate")); + m_parent.do_rotate(rotation_snapshot_name); m_rotate_start_angle.reset(); volume_transformation_changed(); @@ -1264,8 +1272,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) @@ -1286,7 +1293,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); } @@ -1492,8 +1499,9 @@ void GLGizmoSVG::draw_filename(){ std::string new_path = choose_svg_file(); if (!new_path.empty()) { file_changed = true; - m_volume_shape.svg_file = {}; // clear data - m_volume_shape.svg_file->path = new_path; + EmbossShape::SvgFile svg_file_new; + svg_file_new.path = new_path; + m_volume_shape.svg_file = svg_file_new; // clear data } } else if (ImGui::IsItemHovered()) { tooltip = _u8L("Change to another .svg file"); @@ -1689,6 +1697,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"); @@ -1707,6 +1717,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; @@ -1726,6 +1738,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()) @@ -1739,6 +1752,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()) @@ -1760,6 +1774,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()) m_imgui->tooltip(_u8L("Reset scale"), m_gui_cfg->max_tooltip_width); } @@ -1773,20 +1788,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() @@ -1842,18 +1862,20 @@ void GLGizmoSVG::draw_distance() if (m_imgui->slider_optional_float("##distance", m_distance, min_distance, max_distance, "%.2f mm", 1.f, false, move_tooltip)) is_moved = true; } - - bool can_reset = m_distance.has_value(); - if (can_reset) { + bool is_stop_sliding = m_imgui->get_last_slider_status().deactivated_after_edit; + bool is_reseted = false; + if (m_distance.has_value()) { if (reset_button(m_icons)) { m_distance.reset(); - is_moved = true; + is_reseted = true; } else if (ImGui::IsItemHovered()) m_imgui->tooltip(_u8L("Reset distance"), m_gui_cfg->max_tooltip_width); } - if (is_moved) - do_local_z_move(m_parent, m_distance.value_or(.0f) - prev_distance); + if (is_moved || is_reseted) + do_local_z_move(m_parent.get_selection(), m_distance.value_or(.0f) - prev_distance); + if (is_stop_sliding || is_reseted) + m_parent.do_move(move_snapshot_name); } void GLGizmoSVG::draw_rotation() @@ -1876,7 +1898,7 @@ void GLGizmoSVG::draw_rotation() double diff_angle = angle_rad - angle; - do_local_z_rotate(m_parent, diff_angle); + do_local_z_rotate(m_parent.get_selection(), diff_angle); // calc angle after rotation m_angle = calc_angle(m_parent.get_selection()); @@ -1885,20 +1907,28 @@ void GLGizmoSVG::draw_rotation() if (m_volume->emboss_shape->projection.use_surface) process(); } + bool is_stop_sliding = m_imgui->get_last_slider_status().deactivated_after_edit; // Reset button + bool is_reseted = false; if (m_angle.has_value()) { if (reset_button(m_icons)) { - do_local_z_rotate(m_parent, -(*m_angle)); + do_local_z_rotate(m_parent.get_selection(), -(*m_angle)); m_angle.reset(); // recalculate for surface cut if (m_volume->emboss_shape->projection.use_surface) process(); + + is_reseted = true; } else if (ImGui::IsItemHovered()) m_imgui->tooltip(_u8L("Reset rotation"), m_gui_cfg->max_tooltip_width); } + // Apply rotation on model (backend) + if (is_stop_sliding || is_reseted) + m_parent.do_rotate(rotation_snapshot_name); + // Keep up - lock button icon if (!m_volume->is_the_only_one_part()) { ImGui::SameLine(m_gui_cfg->lock_offset); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp index 0a2dedbddd..a702395ac2 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 471f202bb3..83bdd53b31 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -102,6 +102,9 @@ struct DataCreateObject // Define which gizmo open on the success GLGizmosManager::EType gizmo; + + // additionl rotation around Z axe, given by style settings + std::optional angle = {}; }; /// @@ -330,6 +333,12 @@ void CreateObjectJob::process(Ctl &ctl) offset -= m_result.center(); Transform3d::TranslationType tt(offset.x(), offset.y(), offset.z()); m_transformation = Transform3d(tt); + + // rotate around Z by style settings + if (m_input.angle.has_value()) { + std::optional distance; // new object ignore surface distance from style settings + apply_transformation(m_input.angle, distance, m_transformation); + } } void CreateObjectJob::finalize(bool canceled, std::exception_ptr &eptr) @@ -1023,10 +1032,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 @@ -1486,8 +1498,14 @@ bool start_create_object_job(const CreateVolumeParams &input, DataBasePtr emboss { const Pointfs &bed_shape = input.build_volume.printable_area(); auto gizmo_type = static_cast(input.gizmo); - DataCreateObject data{std::move(emboss_data), coor, input.camera, bed_shape, gizmo_type}; - auto job = std::make_unique(std::move(data)); + DataCreateObject data{std::move(emboss_data), coor, input.camera, bed_shape, gizmo_type, input.angle}; + + // Fix: adding text on print bed with style containing use_surface + if (data.base->shape.projection.use_surface) + // Til the print bed is flat using surface for Object is useless + data.base->shape.projection.use_surface = false; + + auto job = std::make_unique(std::move(data)); return queue_job(input.worker, std::move(job)); } 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; }; /// diff --git a/src/slic3r/GUI/SurfaceDrag.cpp b/src/slic3r/GUI/SurfaceDrag.cpp index 8b66807800..58d6e46a58 100644 --- a/src/slic3r/GUI/SurfaceDrag.cpp +++ b/src/slic3r/GUI/SurfaceDrag.cpp @@ -198,15 +198,20 @@ std::optional calc_distance(const GLVolume &gl_volume, RaycastManager &ra if (volume->is_the_only_one_part()) return {}; + if (!volume->emboss_shape.has_value()) + return {}; + RaycastManager::AllowVolumes condition = create_condition(object->volumes, volume->id()); RaycastManager::Meshes meshes = create_meshes(canvas, condition); raycaster.actualize(*instance, &condition, &meshes); - return calc_distance(gl_volume, raycaster, &condition); + return calc_distance(gl_volume, raycaster, &condition, volume->emboss_shape->fix_3mf_tr); } -std::optional calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, const RaycastManager::ISkip *condition) -{ +std::optional calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, + const RaycastManager::ISkip *condition, const std::optional& fix) { Transform3d w = gl_volume.world_matrix(); + if (fix.has_value()) + w = w * fix->inverse(); Vec3d p = w.translation(); Vec3d dir = -get_z_base(w); auto hit_opt = raycaster.closest_hit(p, dir, condition); @@ -322,11 +327,11 @@ bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas, co return false; ModelObject &object = *object_ptr; - ModelInstance *instance_ptr = get_model_instance(gl_volume, object); + const ModelInstance *instance_ptr = get_model_instance(gl_volume, object); assert(instance_ptr != nullptr); if (instance_ptr == nullptr) return false; - ModelInstance &instance = *instance_ptr; + const ModelInstance &instance = *instance_ptr; ModelVolume *volume_ptr = get_model_volume(gl_volume, object); assert(volume_ptr != nullptr); @@ -385,10 +390,7 @@ bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas, co return true; } -void do_local_z_rotate(GLCanvas3D &canvas, double relative_angle) -{ - Selection &selection = canvas.get_selection(); - +void do_local_z_rotate(Selection &selection, double relative_angle) { assert(!selection.is_empty()); if(selection.is_empty()) return; @@ -418,17 +420,9 @@ void do_local_z_rotate(GLCanvas3D &canvas, double relative_angle) selection.rotate(Vec3d(0., 0., relative_angle), get_drag_transformation_type(selection)); }; selection_transform(selection, selection_rotate_fnc); - - std::string snapshot_name; // empty meand no store undo / redo - // NOTE: it use L instead of _L macro because prefix _ is appended - // inside function do_move - // snapshot_name = L("Set text rotation"); - canvas.do_rotate(snapshot_name); } -void do_local_z_move(GLCanvas3D &canvas, double relative_move) { - - Selection &selection = canvas.get_selection(); +void do_local_z_move(Selection &selection, double relative_move) { assert(!selection.is_empty()); if (selection.is_empty()) return; @@ -438,12 +432,6 @@ void do_local_z_move(GLCanvas3D &canvas, double relative_move) { selection.translate(translate, TransformationType::Local); }; selection_transform(selection, selection_translate_fnc); - - std::string snapshot_name; // empty mean no store undo / redo - // NOTE: it use L instead of _L macro because prefix _ is appended inside - // function do_move - // snapshot_name = L("Set surface distance"); - canvas.do_move(snapshot_name); } TransformationType get_drag_transformation_type(const Selection &selection) @@ -589,7 +577,7 @@ bool start_dragging(const Vec2d &mouse_pos, std::optional start_distance; if (!volume->emboss_shape->projection.use_surface) - start_distance = calc_distance(gl_volume, raycast_manager, &condition); + start_distance = calc_distance(gl_volume, raycast_manager, &condition, volume->emboss_shape->fix_3mf_tr); surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume_ptr, condition, start_angle, start_distance, true, mouse_offset_without_sla_shift}; diff --git a/src/slic3r/GUI/SurfaceDrag.hpp b/src/slic3r/GUI/SurfaceDrag.hpp index 9f1c0e3c07..f6bd731ae9 100644 --- a/src/slic3r/GUI/SurfaceDrag.hpp +++ b/src/slic3r/GUI/SurfaceDrag.hpp @@ -89,7 +89,8 @@ std::optional calc_surface_offset(const Selection &selection, RaycastMana /// Contain model /// Calculated distance from surface std::optional calc_distance(const GLVolume &gl_volume, RaycastManager &raycaster, GLCanvas3D &canvas); -std::optional calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, const RaycastManager::ISkip *condition); +std::optional calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, + const RaycastManager::ISkip *condition, const std::optional& fix); /// /// Calculate up vector angle @@ -136,16 +137,16 @@ bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas, co /// /// Rotation around z Axis(emboss direction) /// -/// Selected volume for rotation +/// Selected volume for rotation /// Relative angle to rotate around emboss direction -void do_local_z_rotate(GLCanvas3D &canvas, double relative_angle); +void do_local_z_rotate(Selection &selection, double relative_angle); /// /// Translation along local z Axis (emboss direction) /// -/// Selected volume for translate +/// Selected volume for translate /// Relative move along emboss direction -void do_local_z_move(GLCanvas3D &canvas, double relative_move); +void do_local_z_move(Selection &selection, double relative_move); /// /// Distiguish between object and volume diff --git a/src/slic3r/Utils/EmbossStyleManager.cpp b/src/slic3r/Utils/EmbossStyleManager.cpp index b367d44832..c8a67d8e5e 100644 --- a/src/slic3r/Utils/EmbossStyleManager.cpp +++ b/src/slic3r/Utils/EmbossStyleManager.cpp @@ -14,6 +14,9 @@ #include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" // check of font ranges +#include +#include + using namespace Slic3r; using namespace Slic3r::Emboss; using namespace Slic3r::GUI::Emboss; @@ -38,6 +41,20 @@ void store_style_index(AppConfig &cfg, size_t index); 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); + +// Enum map to string and vice versa +using HorizontalAlignToName = boost::bimap; +const HorizontalAlignToName horizontal_align_to_name = +boost::assign::list_of + (FontProp::HorizontalAlign::left, "left") + (FontProp::HorizontalAlign::center, "center") + (FontProp::HorizontalAlign::right, "right"); +using VerticalAlignToName = boost::bimap; +const VerticalAlignToName vertical_align_to_name = +boost::assign::list_of + (FontProp::VerticalAlign::top, "top") + (FontProp::VerticalAlign::center, "middle") + (FontProp::VerticalAlign::bottom, "bottom"); } // namespace void StyleManager::init(AppConfig *app_config) @@ -535,6 +552,9 @@ const std::string APP_CONFIG_FONT_DESCRIPTOR = "descriptor"; const std::string APP_CONFIG_FONT_LINE_HEIGHT = "line_height"; const std::string APP_CONFIG_FONT_DEPTH = "depth"; const std::string APP_CONFIG_FONT_USE_SURFACE = "use_surface"; +const std::string APP_CONFIG_PER_GLYPH = "per_glyph"; +const std::string APP_CONFIG_VERTICAL_ALIGN = "vertical_align"; +const std::string APP_CONFIG_HORIZONTAL_ALIGN = "horizontal_align"; const std::string APP_CONFIG_FONT_BOLDNESS = "boldness"; const std::string APP_CONFIG_FONT_SKEW = "skew"; const std::string APP_CONFIG_FONT_DISTANCE = "distance"; @@ -561,6 +581,36 @@ bool read(const Section §ion, const std::string &key, bool &value) return true; } +bool read(const Section §ion, const std::string &key, Slic3r::FontProp::HorizontalAlign &value) { + auto item = section.find(key); + if (item == section.end()) + return false; + + const std::string &data = item->second; + if (data.empty()) + return false; + + const auto& map = horizontal_align_to_name.right; + auto it = map.find(data); + value = (it != map.end()) ? it->second : Slic3r::FontProp::HorizontalAlign::center; + return true; +} + +bool read(const Section §ion, const std::string &key, Slic3r::FontProp::VerticalAlign &value) { + auto item = section.find(key); + if (item == section.end()) + return false; + + const std::string &data = item->second; + if (data.empty()) + return false; + + const auto &map = vertical_align_to_name.right; + auto it = map.find(data); + value = (it != map.end()) ? it->second : Slic3r::FontProp::VerticalAlign::center; + return true; +} + bool read(const Section §ion, const std::string &key, float &value) { auto item = section.find(key); @@ -650,6 +700,9 @@ std::optional load_style(const Section &app_cfg_section) 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_PER_GLYPH, fp.per_glyph); + read(app_cfg_section, APP_CONFIG_HORIZONTAL_ALIGN, fp.align.first); + read(app_cfg_section, APP_CONFIG_VERTICAL_ALIGN, fp.align.second); 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, s.distance); @@ -671,6 +724,12 @@ void store_style(AppConfig &cfg, const StyleManager::Style &s, unsigned index) data[APP_CONFIG_FONT_DEPTH] = std::to_string(ep.depth); if (ep.use_surface) data[APP_CONFIG_FONT_USE_SURFACE] = "true"; + if (fp.per_glyph) + data[APP_CONFIG_PER_GLYPH] = "true"; + if (fp.align.first != FontProp::HorizontalAlign::center) + data[APP_CONFIG_HORIZONTAL_ALIGN] = horizontal_align_to_name.left.find(fp.align.first)->second; + if (fp.align.second != FontProp::VerticalAlign::center) + data[APP_CONFIG_VERTICAL_ALIGN] = vertical_align_to_name.left.find(fp.align.second)->second; if (fp.boldness.has_value()) data[APP_CONFIG_FONT_BOLDNESS] = std::to_string(*fp.boldness); if (fp.skew.has_value())