mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-02-03 01:18:44 +03:00
Prusa 2.7.2
This commit is contained in:
@@ -5,12 +5,15 @@
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <wx/progdlg.h>
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#include "slic3r/GUI/GUI_Factories.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "slic3r/Utils/FixModelByWin10.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||
|
||||
@@ -3255,6 +3258,8 @@ void update_object_cut_id(CutObjectBase& cut_id, ModelObjectCutAttributes attrib
|
||||
static void check_objects_after_cut(const ModelObjectPtrs& objects)
|
||||
{
|
||||
std::vector<std::string> err_objects_names;
|
||||
std::vector<int> err_objects_idxs;
|
||||
int obj_idx{ 0 };
|
||||
for (const ModelObject* object : objects) {
|
||||
std::vector<std::string> connectors_names;
|
||||
connectors_names.reserve(object->volumes.size());
|
||||
@@ -3265,17 +3270,86 @@ static void check_objects_after_cut(const ModelObjectPtrs& objects)
|
||||
sort_remove_duplicates(connectors_names);
|
||||
if (connectors_count != connectors_names.size())
|
||||
err_objects_names.push_back(object->name);
|
||||
// check manifol/repairs
|
||||
auto stats = object->get_object_stl_stats();
|
||||
if (!stats.manifold() || stats.repaired())
|
||||
err_objects_idxs.push_back(obj_idx);
|
||||
obj_idx++;
|
||||
}
|
||||
if (err_objects_names.empty())
|
||||
return;
|
||||
auto plater = wxGetApp().plater();
|
||||
|
||||
if (!err_objects_names.empty()) {
|
||||
wxString names = from_u8(err_objects_names[0]);
|
||||
for (size_t i = 1; i < err_objects_names.size(); i++)
|
||||
names += ", " + from_u8(err_objects_names[i]);
|
||||
WarningDialog(wxGetApp().plater(), format_wxstr("Objects(%1%) have duplicated connectors. "
|
||||
WarningDialog(plater, format_wxstr("Objects(%1%) have duplicated connectors. "
|
||||
"Some connectors may be missing in slicing result.\n"
|
||||
"Please report to QIDISlicer team in which scenario this issue happened.\n"
|
||||
"Thank you.", names)).ShowModal();
|
||||
}
|
||||
if (is_windows10() && !err_objects_idxs.empty()) {
|
||||
auto dlg = WarningDialog(plater, _L("Open edges or errors were detected after the cut.\n"
|
||||
"Do you want to fix them by Windows repair algorithm?"),
|
||||
_L("Errors detected after cut operation"), wxYES_NO);
|
||||
if (dlg.ShowModal() == wxID_YES) {
|
||||
// model_name
|
||||
std::vector<std::string> succes_models;
|
||||
// model_name failing reason
|
||||
std::vector<std::pair<std::string, std::string>> failed_models;
|
||||
|
||||
std::vector<std::string> model_names;
|
||||
|
||||
for (int obj_idx : err_objects_idxs)
|
||||
model_names.push_back(objects[obj_idx]->name);
|
||||
|
||||
auto fix_and_update_progress = [model_names, &objects](const int obj_idx, int model_idx,
|
||||
wxProgressDialog& progress_dlg,
|
||||
std::vector<std::string>& succes_models,
|
||||
std::vector<std::pair<std::string, std::string>>& failed_models) -> bool
|
||||
{
|
||||
const std::string& model_name = model_names[model_idx];
|
||||
wxString msg;
|
||||
if (model_names.size() == 1)
|
||||
msg = GUI::format(_L("Repairing object %1%"), model_name) + "\n";
|
||||
else {
|
||||
// TRN: This is followed by a list of object which are to be repaired.
|
||||
msg = _L("Repairing objects:") + "\n";
|
||||
for (int i = 0; i < int(model_names.size()); ++i)
|
||||
msg += (i == model_idx ? " > " : " ") + from_u8(model_names[i]) + "\n";
|
||||
msg += "\n";
|
||||
}
|
||||
|
||||
std::string res;
|
||||
if (!fix_model_by_win10_sdk_gui(*objects[obj_idx], -1, progress_dlg, msg, res))
|
||||
return false;
|
||||
|
||||
if (res.empty())
|
||||
succes_models.push_back(model_name);
|
||||
else
|
||||
failed_models.push_back({ model_name, res });
|
||||
return true;
|
||||
};
|
||||
|
||||
// Open a progress dialog.
|
||||
// TRN: This shows in a progress dialog while the operation is in progress.
|
||||
wxProgressDialog progress_dlg(_L("Fixing by Windows repair algorithm"), "", 100, find_toplevel_parent(plater),
|
||||
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||
int model_idx{ 0 };
|
||||
for (int obj_idx : err_objects_idxs) {
|
||||
if (!fix_and_update_progress(obj_idx, model_idx, progress_dlg, succes_models, failed_models))
|
||||
break;
|
||||
model_idx++;
|
||||
}
|
||||
|
||||
// Close the progress dialog
|
||||
progress_dlg.Update(100, "");
|
||||
|
||||
// Show info dialog
|
||||
wxString msg = MenuFactory::get_repaire_result_message(succes_models, failed_models);
|
||||
// TRN: Title of a dialog informing the user about the result of the model repair operation.
|
||||
InfoDialog(plater, _L("Repair operation finished"), msg).ShowModal();
|
||||
}
|
||||
}
|
||||
}
|
||||
void synchronize_model_after_cut(Model& model, const CutObjectBase& cut_id)
|
||||
{
|
||||
|
||||
@@ -73,6 +73,13 @@ 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<typename T> struct Limit {
|
||||
// Limitation for view slider range in GUI
|
||||
MinMax<T> gui;
|
||||
@@ -85,7 +92,7 @@ static const struct Limits
|
||||
{
|
||||
MinMax<double> emboss{0.01, 1e4}; // in mm
|
||||
MinMax<float> size_in_mm{0.1f, 1000.f}; // in mm
|
||||
Limit<float> boldness{{-200.f, 200.f}, {-2e4f, 2e4f}}; // in font points
|
||||
Limit<float> boldness{{-.5f, .5f}, {-5e5f, 5e5f}}; // in font points
|
||||
Limit<float> skew{{-1.f, 1.f}, {-100.f, 100.f}}; // ration without unit
|
||||
MinMax<int> char_gap{-20000, 20000}; // in font points
|
||||
MinMax<int> line_gap{-20000, 20000}; // in font points
|
||||
@@ -399,7 +406,7 @@ bool GLGizmoEmboss::re_emboss(const ModelVolume &text_volume, std::shared_ptr<st
|
||||
TextLinesModel text_lines;
|
||||
const Selection &selection = wxGetApp().plater()->canvas3D()->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);
|
||||
@@ -1005,7 +1012,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();
|
||||
@@ -1337,7 +1344,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);
|
||||
@@ -1351,7 +1358,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));
|
||||
@@ -2176,7 +2183,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
|
||||
@@ -2185,7 +2194,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
|
||||
@@ -2451,6 +2462,8 @@ 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())
|
||||
ImGui::SetTooltip("%s", undo_tooltip.c_str());
|
||||
@@ -2691,7 +2704,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;
|
||||
@@ -2783,6 +2795,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;
|
||||
@@ -2798,9 +2811,12 @@ 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;
|
||||
@@ -2819,18 +2835,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<int>(font_info.ascent * limits.boldness.gui.min);
|
||||
int max_boldness = static_cast<int>(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<float> &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 ?
|
||||
@@ -2842,6 +2864,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();
|
||||
@@ -2882,11 +2906,17 @@ 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
|
||||
@@ -2909,7 +2939,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
|
||||
|
||||
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();
|
||||
@@ -2924,6 +2954,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();
|
||||
}
|
||||
|
||||
@@ -2956,6 +2995,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();
|
||||
}
|
||||
@@ -2965,13 +3005,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())) {
|
||||
@@ -3622,7 +3662,7 @@ GuiCfg create_gui_configuration()
|
||||
float space = line_height_with_spacing - line_height;
|
||||
const ImGuiStyle &style = ImGui::GetStyle();
|
||||
|
||||
cfg.max_style_name_width = ImGui::CalcTextSize("Maximal font name, extended").x;
|
||||
cfg.max_style_name_width = ImGui::CalcTextSize("Maximal style name..").x;
|
||||
|
||||
cfg.icon_width = static_cast<unsigned int>(std::ceil(line_height));
|
||||
// make size pair number
|
||||
@@ -3741,11 +3781,11 @@ GuiCfg create_gui_configuration()
|
||||
ImVec2(cfg.minimal_window_size_with_advance.x,
|
||||
cfg.minimal_window_size_with_advance.y + input_height);
|
||||
|
||||
int max_style_image_width = static_cast<int>(std::round(cfg.max_style_name_width/2 - 2 * style.FramePadding.x));
|
||||
int max_style_image_width = static_cast<int>(std::round(cfg.max_style_name_width - 2 * style.FramePadding.x));
|
||||
int max_style_image_height = static_cast<int>(std::round(1.5 * input_height));
|
||||
cfg.max_style_image_size = Vec2i(max_style_image_width, max_style_image_height);
|
||||
cfg.face_name_size = Vec2i(cfg.input_width, line_height_with_spacing);
|
||||
cfg.face_name_texture_offset_x = cfg.face_name_size.x() + space;
|
||||
cfg.face_name_texture_offset_x = cfg.face_name_size.x() + style.WindowPadding.x + space;
|
||||
return cfg;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -111,7 +111,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();
|
||||
|
||||
@@ -512,7 +512,7 @@ void GLGizmoMmuSegmentation::update_model_object() const
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
++idx;
|
||||
updated |= mv->mmu_segmentation_facets.set(*m_triangle_selectors[idx].get());
|
||||
updated |= mv->mm_segmentation_facets.set(*m_triangle_selectors[idx].get());
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
@@ -542,7 +542,7 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors()
|
||||
size_t extruder_idx = get_extruder_color_idx(*mv, extruders_count);
|
||||
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorMmGui>(*mesh, m_modified_extruders_colors, m_original_extruders_colors[extruder_idx]));
|
||||
// Reset of TriangleSelector is done inside TriangleSelectorMmGUI's constructor, so we don't need it to perform it again in deserialize().
|
||||
m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data(), false);
|
||||
m_triangle_selectors.back()->deserialize(mv->mm_segmentation_facets.get_data(), false);
|
||||
m_triangle_selectors.back()->request_update_render_data();
|
||||
}
|
||||
m_original_volumes_extruder_idxs = get_extruder_id_for_volumes(*mo);
|
||||
|
||||
@@ -51,6 +51,13 @@ 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
|
||||
{
|
||||
@@ -539,7 +546,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();
|
||||
|
||||
@@ -1266,8 +1273,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)
|
||||
@@ -1288,7 +1294,7 @@ bool GLGizmoSVG::process()
|
||||
EmbossShape shape = m_volume_shape; // copy
|
||||
auto base = std::make_unique<DataBase>(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);
|
||||
}
|
||||
|
||||
@@ -1490,8 +1496,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()) {
|
||||
ImGui::SetTooltip("%s", _u8L("Change to another .svg file").c_str());
|
||||
@@ -1681,6 +1688,7 @@ void GLGizmoSVG::draw_size()
|
||||
};
|
||||
|
||||
std::optional<Vec3d> 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");
|
||||
@@ -1699,6 +1707,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;
|
||||
|
||||
@@ -1718,6 +1728,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())
|
||||
@@ -1731,6 +1742,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())
|
||||
@@ -1752,6 +1764,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());
|
||||
}
|
||||
@@ -1765,20 +1778,24 @@ 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()
|
||||
@@ -1833,17 +1850,20 @@ void GLGizmoSVG::draw_distance()
|
||||
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())
|
||||
ImGui::SetTooltip("%s", _u8L("Reset distance").c_str());
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -1865,7 +1885,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());
|
||||
@@ -1874,20 +1894,26 @@ 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())
|
||||
ImGui::SetTooltip("%s", _u8L("Reset rotation").c_str());
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user