mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 21:26:01 +08:00
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)
This commit is contained in:
parent
65525b0616
commit
ee3546b186
@ -96,7 +96,7 @@ static const struct Limits
|
|||||||
{
|
{
|
||||||
MinMax<double> emboss{0.01, 1e4}; // in mm
|
MinMax<double> emboss{0.01, 1e4}; // in mm
|
||||||
MinMax<float> size_in_mm{0.1f, 1000.f}; // 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
|
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> char_gap{-20000, 20000}; // in font points
|
||||||
MinMax<int> line_gap{-20000, 20000}; // in font points
|
MinMax<int> line_gap{-20000, 20000}; // in font points
|
||||||
@ -380,7 +380,7 @@ bool GLGizmoEmboss::re_emboss(const ModelVolume &text_volume, std::shared_ptr<st
|
|||||||
TextLinesModel text_lines;
|
TextLinesModel text_lines;
|
||||||
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection();
|
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);
|
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
|
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);
|
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; }
|
bool is_text_empty(std::string_view text) { return text.empty() || text.find_first_not_of(" \n\t\r") == std::string::npos; }
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool GLGizmoEmboss::process()
|
bool GLGizmoEmboss::process(bool make_snapshot)
|
||||||
{
|
{
|
||||||
// no volume is selected -> selection from right panel
|
// no volume is selected -> selection from right panel
|
||||||
assert(m_volume != nullptr);
|
assert(m_volume != nullptr);
|
||||||
@ -1330,7 +1330,7 @@ bool GLGizmoEmboss::process()
|
|||||||
|
|
||||||
const Selection& selection = m_parent.get_selection();
|
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);
|
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
|
// check valid count of text lines
|
||||||
assert(data.base->text_lines.empty() || data.base->text_lines.size() == get_count_lines(m_text));
|
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);
|
m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property);
|
||||||
#endif // SHOW_FONT_FILE_PROPERTY
|
#endif // SHOW_FONT_FILE_PROPERTY
|
||||||
|
|
||||||
bool exist_change = false;
|
|
||||||
auto &tr = m_gui_cfg->translations;
|
auto &tr = m_gui_cfg->translations;
|
||||||
|
|
||||||
const StyleManager::Style *stored_style = nullptr;
|
const StyleManager::Style *stored_style = nullptr;
|
||||||
@ -2757,6 +2756,7 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
auto def_char_gap = stored_style ?
|
auto def_char_gap = stored_style ?
|
||||||
&stored_style->prop.char_gap : nullptr;
|
&stored_style->prop.char_gap : nullptr;
|
||||||
|
|
||||||
|
bool exist_change = false;
|
||||||
int half_ascent = font_info.ascent / 2;
|
int half_ascent = font_info.ascent / 2;
|
||||||
int min_char_gap = -half_ascent;
|
int min_char_gap = -half_ascent;
|
||||||
int max_char_gap = half_ascent;
|
int max_char_gap = half_ascent;
|
||||||
@ -2772,13 +2772,16 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool last_change = false;
|
||||||
|
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
||||||
|
last_change = true;
|
||||||
|
|
||||||
// input gap between lines
|
// 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);
|
m_imgui->disabled_begin(!is_multiline);
|
||||||
auto def_line_gap = stored_style ?
|
auto def_line_gap = stored_style ?
|
||||||
&stored_style->prop.line_gap : nullptr;
|
&stored_style->prop.line_gap : nullptr;
|
||||||
int min_line_gap = -half_ascent;
|
int min_line_gap = -half_ascent;
|
||||||
int max_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"),
|
if (rev_slider(tr.line_gap, current_prop.line_gap, def_line_gap, _u8L("Revert gap between lines"),
|
||||||
min_line_gap, max_line_gap, units_fmt, _L("Distance between lines"))){
|
min_line_gap, max_line_gap, units_fmt, _L("Distance between lines"))){
|
||||||
@ -2793,18 +2796,24 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
||||||
|
last_change = true;
|
||||||
m_imgui->disabled_end(); // !is_multiline
|
m_imgui->disabled_end(); // !is_multiline
|
||||||
|
|
||||||
// input boldness
|
// input boldness
|
||||||
auto def_boldness = stored_style ?
|
auto def_boldness = stored_style ?
|
||||||
&stored_style->prop.boldness : nullptr;
|
&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"),
|
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;
|
const std::optional<float> &volume_boldness = m_volume->text_configuration->style.prop.boldness;
|
||||||
if (!apply(current_prop.boldness, limits.boldness.values) ||
|
if (!apply(current_prop.boldness, limits.boldness.values) ||
|
||||||
!volume_boldness.has_value() || volume_boldness != current_prop.boldness)
|
!volume_boldness.has_value() || volume_boldness != current_prop.boldness)
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
|
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
||||||
|
last_change = true;
|
||||||
|
|
||||||
// input italic
|
// input italic
|
||||||
auto def_skew = stored_style ?
|
auto def_skew = stored_style ?
|
||||||
@ -2816,6 +2825,8 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
!volume_skew.has_value() ||volume_skew != current_prop.skew)
|
!volume_skew.has_value() ||volume_skew != current_prop.skew)
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
}
|
}
|
||||||
|
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
||||||
|
last_change = true;
|
||||||
|
|
||||||
// input surface distance
|
// input surface distance
|
||||||
bool allowe_surface_distance = !use_surface && !m_volume->is_the_only_one_part();
|
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 (is_moved){
|
||||||
if (font_prop.per_glyph){
|
if (font_prop.per_glyph){
|
||||||
process();
|
process(false);
|
||||||
} else {
|
} else {
|
||||||
do_local_z_move(m_parent.get_selection(), 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)
|
// Apply move to model(backend)
|
||||||
if (m_imgui->get_last_slider_status().deactivated_after_edit)
|
if (m_imgui->get_last_slider_status().deactivated_after_edit) {
|
||||||
m_parent.do_rotate(move_snapshot_name);
|
m_parent.do_move(move_snapshot_name);
|
||||||
|
if (font_prop.per_glyph)
|
||||||
|
process();
|
||||||
|
}
|
||||||
|
|
||||||
m_imgui->disabled_end(); // allowe_surface_distance
|
m_imgui->disabled_end(); // allowe_surface_distance
|
||||||
|
|
||||||
@ -2901,11 +2915,17 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
|
|
||||||
// recalculate for surface cut
|
// recalculate for surface cut
|
||||||
if (use_surface || font_prop.per_glyph)
|
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();
|
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
|
// Keep up - lock button icon
|
||||||
if (!m_volume->is_the_only_one_part()) {
|
if (!m_volume->is_the_only_one_part()) {
|
||||||
@ -2937,6 +2957,7 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
if (i == 0) current_prop.collection_number.reset();
|
if (i == 0) current_prop.collection_number.reset();
|
||||||
else current_prop.collection_number = i;
|
else current_prop.collection_number = i;
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
|
last_change = true;
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
@ -2946,13 +2967,13 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exist_change) {
|
if (exist_change || last_change) {
|
||||||
m_style_manager.clear_glyphs_cache();
|
m_style_manager.clear_glyphs_cache();
|
||||||
if (m_style_manager.get_font_prop().per_glyph)
|
if (font_prop.per_glyph)
|
||||||
reinit_text_lines();
|
reinit_text_lines();
|
||||||
else
|
else
|
||||||
m_text_lines.reset();
|
m_text_lines.reset();
|
||||||
process();
|
process(last_change);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button(_u8L("Set text to face camera").c_str())) {
|
if (ImGui::Button(_u8L("Set text to face camera").c_str())) {
|
||||||
|
@ -114,7 +114,7 @@ private:
|
|||||||
void reset_volume();
|
void reset_volume();
|
||||||
|
|
||||||
// create volume from text - main functionality
|
// create volume from text - main functionality
|
||||||
bool process();
|
bool process(bool make_snapshot = true);
|
||||||
void close();
|
void close();
|
||||||
void draw_window();
|
void draw_window();
|
||||||
void draw_text_input();
|
void draw_text_input();
|
||||||
|
@ -1274,8 +1274,7 @@ void GLGizmoSVG::calculate_scale() {
|
|||||||
float GLGizmoSVG::get_scale_for_tolerance(){
|
float GLGizmoSVG::get_scale_for_tolerance(){
|
||||||
return std::max(m_scale_width.value_or(1.f), m_scale_height.value_or(1.f)); }
|
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
|
// no volume is selected -> selection from right panel
|
||||||
assert(m_volume != nullptr);
|
assert(m_volume != nullptr);
|
||||||
if (m_volume == nullptr)
|
if (m_volume == nullptr)
|
||||||
@ -1296,7 +1295,7 @@ bool GLGizmoSVG::process()
|
|||||||
EmbossShape shape = m_volume_shape; // copy
|
EmbossShape shape = m_volume_shape; // copy
|
||||||
auto base = std::make_unique<DataBase>(m_volume->name, m_job_cancel, std::move(shape));
|
auto base = std::make_unique<DataBase>(m_volume->name, m_job_cancel, std::move(shape));
|
||||||
base->is_outside = m_volume->type() == ModelVolumeType::MODEL_PART;
|
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);
|
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<Vec3d> new_relative_scale;
|
std::optional<Vec3d> new_relative_scale;
|
||||||
|
bool make_snap = false;
|
||||||
|
|
||||||
if (m_keep_ratio) {
|
if (m_keep_ratio) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::setprecision(2) << std::fixed << width << " x " << height << " " << (use_inch ? "in" : "mm");
|
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.);
|
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 {
|
} else {
|
||||||
ImGuiInputTextFlags flags = 0;
|
ImGuiInputTextFlags flags = 0;
|
||||||
|
|
||||||
@ -1727,6 +1730,7 @@ void GLGizmoSVG::draw_size()
|
|||||||
if (is_valid_scale_ratio(width_ratio)) {
|
if (is_valid_scale_ratio(width_ratio)) {
|
||||||
m_scale_width = m_scale_width.value_or(1.f) * width_ratio;
|
m_scale_width = m_scale_width.value_or(1.f) * width_ratio;
|
||||||
new_relative_scale = Vec3d(width_ratio, 1., 1.);
|
new_relative_scale = Vec3d(width_ratio, 1., 1.);
|
||||||
|
make_snap = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
@ -1740,6 +1744,7 @@ void GLGizmoSVG::draw_size()
|
|||||||
if (is_valid_scale_ratio(height_ratio)) {
|
if (is_valid_scale_ratio(height_ratio)) {
|
||||||
m_scale_height = m_scale_height.value_or(1.f) * height_ratio;
|
m_scale_height = m_scale_height.value_or(1.f) * height_ratio;
|
||||||
new_relative_scale = Vec3d(1., height_ratio, 1.);
|
new_relative_scale = Vec3d(1., height_ratio, 1.);
|
||||||
|
make_snap = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
@ -1761,6 +1766,7 @@ void GLGizmoSVG::draw_size()
|
|||||||
if (can_reset) {
|
if (can_reset) {
|
||||||
if (reset_button(m_icons)) {
|
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.);
|
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())
|
} else if (ImGui::IsItemHovered())
|
||||||
ImGui::SetTooltip("%s", _u8L("Reset scale").c_str());
|
ImGui::SetTooltip("%s", _u8L("Reset scale").c_str());
|
||||||
}
|
}
|
||||||
@ -1774,20 +1780,25 @@ void GLGizmoSVG::draw_size()
|
|||||||
};
|
};
|
||||||
selection_transform(selection, selection_scale_fnc);
|
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();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
// should be the almost same
|
// should be the almost same
|
||||||
calculate_scale();
|
calculate_scale();
|
||||||
|
|
||||||
NSVGimage *img = m_volume_shape.svg_file->image.get();
|
const NSVGimage *img = m_volume_shape.svg_file->image.get();
|
||||||
assert(img != NULL);
|
assert(img != NULL);
|
||||||
if (img != NULL){
|
if (img != NULL){
|
||||||
NSVGLineParams params{get_tesselation_tolerance(get_scale_for_tolerance())};
|
NSVGLineParams params{get_tesselation_tolerance(get_scale_for_tolerance())};
|
||||||
m_volume_shape.shapes_with_ids = create_shape_with_ids(*img, params);
|
m_volume_shape.shapes_with_ids = create_shape_with_ids(*img, params);
|
||||||
m_volume_shape.final_shape = {}; // reset cache for final shape
|
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()
|
void GLGizmoSVG::draw_use_surface()
|
||||||
|
@ -112,7 +112,7 @@ private:
|
|||||||
void reset_volume();
|
void reset_volume();
|
||||||
|
|
||||||
// create volume from text - main functionality
|
// create volume from text - main functionality
|
||||||
bool process();
|
bool process(bool make_snapshot = true);
|
||||||
void close();
|
void close();
|
||||||
void draw_window();
|
void draw_window();
|
||||||
void draw_preview();
|
void draw_preview();
|
||||||
|
@ -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 ||
|
assert(plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Emboss ||
|
||||||
plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Svg);
|
plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Svg);
|
||||||
|
|
||||||
// TRN: This is the name of the action appearing in undo/redo stack.
|
if (data.make_snapshot) {
|
||||||
std::string snap_name = _u8L("Text/SVG attribute change");
|
// TRN: This is the title of the action appearing in undo/redo stack.
|
||||||
Plater::TakeSnapshot snapshot(plater, snap_name, UndoRedo::SnapshotType::GizmoAction);
|
// 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);
|
ModelVolume *volume = get_model_volume(data.volume_id, plater->model().objects);
|
||||||
|
|
||||||
// could appear when user delete edited volume
|
// could appear when user delete edited volume
|
||||||
|
@ -113,6 +113,9 @@ struct DataUpdate
|
|||||||
|
|
||||||
// unique identifier of volume to change
|
// unique identifier of volume to change
|
||||||
ObjectID volume_id;
|
ObjectID volume_id;
|
||||||
|
|
||||||
|
// Used for prevent flooding Undo/Redo stack on slider.
|
||||||
|
bool make_snapshot;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user