Merge remote-tracking branch 'remotes/origin/vb_undo_redo'

This commit is contained in:
bubnikv 2019-07-15 11:34:18 +02:00
commit ab7ecc1819
60 changed files with 2799 additions and 578 deletions

View file

@ -1188,6 +1188,8 @@ wxDEFINE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
: m_canvas(canvas)
@ -1791,7 +1793,7 @@ std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
void GLCanvas3D::mirror_selection(Axis axis)
{
m_selection.mirror(axis);
do_mirror();
do_mirror("Mirror Object");
wxGetApp().obj_manipul()->set_dirty();
}
@ -1812,14 +1814,14 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
struct ModelVolumeState {
ModelVolumeState(const GLVolume *volume) :
model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {}
ModelVolumeState(const ModelVolume *model_volume, const ModelID &instance_id, const GLVolume::CompositeID &composite_id) :
ModelVolumeState(const ModelVolume *model_volume, const ObjectID &instance_id, const GLVolume::CompositeID &composite_id) :
model_volume(model_volume), geometry_id(std::make_pair(model_volume->id().id, instance_id.id)), composite_id(composite_id), volume_idx(-1) {}
ModelVolumeState(const ModelID &volume_id, const ModelID &instance_id) :
ModelVolumeState(const ObjectID &volume_id, const ObjectID &instance_id) :
model_volume(nullptr), geometry_id(std::make_pair(volume_id.id, instance_id.id)), volume_idx(-1) {}
bool new_geometry() const { return this->volume_idx == size_t(-1); }
const ModelVolume *model_volume;
// ModelID of ModelVolume + ModelID of ModelInstance
// or timestamp of an SLAPrintObjectStep + ModelID of ModelInstance
// ObjectID of ModelVolume + ObjectID of ModelInstance
// or timestamp of an SLAPrintObjectStep + ObjectID of ModelInstance
std::pair<size_t, size_t> geometry_id;
GLVolume::CompositeID composite_id;
// Volume index in the new GLVolume vector.
@ -2316,6 +2318,9 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
return;
}
if ((keyCode == WXK_ESCAPE) && _deactivate_undo_redo_toolbar_items())
return;
if (m_gizmos.on_char(evt, *this))
return;
@ -2348,6 +2353,25 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
#endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLTOOLBAR_PASTE));
break;
#ifdef __APPLE__
case 'y':
case 'Y':
#else /* __APPLE__ */
case WXK_CONTROL_Y:
#endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLCANVAS_REDO));
break;
#ifdef __APPLE__
case 'z':
case 'Z':
#else /* __APPLE__ */
case WXK_CONTROL_Z:
#endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLCANVAS_UNDO));
break;
#ifdef __APPLE__
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
#else /* __APPLE__ */
@ -2368,7 +2392,6 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
#endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE));
break;
case WXK_ESCAPE: { deselect_all(); break; }
case '0': { select_view("iso"); break; }
case '1': { select_view("top"); break; }
@ -2715,12 +2738,17 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
else if (evt.Leaving())
{
_deactivate_undo_redo_toolbar_items();
// to remove hover on objects when the mouse goes out of this canvas
m_mouse.position = Vec2d(-1.0, -1.0);
m_dirty = true;
}
else if (evt.LeftDown() || evt.RightDown())
else if (evt.LeftDown() || evt.RightDown() || evt.MiddleDown())
{
if (_deactivate_undo_redo_toolbar_items())
return;
// If user pressed left or right button we first check whether this happened
// on a volume or not.
m_layers_editing.state = LayersEditing::Unknown;
@ -2918,9 +2946,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
{
m_regenerate_volumes = false;
do_move();
do_move("Move Object");
wxGetApp().obj_manipul()->set_dirty();
// Let the platter know that the dragging finished, so a delayed refresh
// Let the plater know that the dragging finished, so a delayed refresh
// of the scene with the background processing data should be performed.
post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
}
@ -3077,11 +3105,14 @@ void GLCanvas3D::set_tooltip(const std::string& tooltip) const
}
void GLCanvas3D::do_move()
void GLCanvas3D::do_move(const std::string& snapshot_type)
{
if (m_model == nullptr)
return;
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
std::set<std::pair<int, int>> done; // keeps track of modified instances
bool object_moved = false;
Vec3d wipe_tower_origin = Vec3d::Zero();
@ -3132,13 +3163,18 @@ void GLCanvas3D::do_move()
if (wipe_tower_origin != Vec3d::Zero())
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin)));
m_dirty = true;
}
void GLCanvas3D::do_rotate()
void GLCanvas3D::do_rotate(const std::string& snapshot_type)
{
if (m_model == nullptr)
return;
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
std::set<std::pair<int, int>> done; // keeps track of modified instances
Selection::EMode selection_mode = m_selection.get_mode();
@ -3187,13 +3223,18 @@ void GLCanvas3D::do_rotate()
if (!done.empty())
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
m_dirty = true;
}
void GLCanvas3D::do_scale()
void GLCanvas3D::do_scale(const std::string& snapshot_type)
{
if (m_model == nullptr)
return;
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
std::set<std::pair<int, int>> done; // keeps track of modified instances
Selection::EMode selection_mode = m_selection.get_mode();
@ -3239,18 +3280,27 @@ void GLCanvas3D::do_scale()
if (!done.empty())
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
m_dirty = true;
}
void GLCanvas3D::do_flatten()
void GLCanvas3D::do_flatten(const Vec3d& normal, const std::string& snapshot_type)
{
do_rotate();
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
m_selection.flattening_rotate(normal);
do_rotate(""); // avoid taking another snapshot
}
void GLCanvas3D::do_mirror()
void GLCanvas3D::do_mirror(const std::string& snapshot_type)
{
if (m_model == nullptr)
return;
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
std::set<std::pair<int, int>> done; // keeps track of modified instances
Selection::EMode selection_mode = m_selection.get_mode();
@ -3289,6 +3339,8 @@ void GLCanvas3D::do_mirror()
}
post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
m_dirty = true;
}
void GLCanvas3D::set_camera_zoom(double zoom)
@ -3412,6 +3464,40 @@ bool GLCanvas3D::_is_shown_on_screen() const
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
}
// Getter for the const char*[]
static bool string_getter(const bool is_undo, int idx, const char** out_text)
{
return wxGetApp().plater()->undo_redo_string_getter(is_undo, idx, out_text);
}
void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x)
{
const wxString& stack_name = _(is_undo ? L("Undo") : L("Redo"));
ImGuiWrapper* imgui = wxGetApp().imgui();
const float x = pos_x * (float)get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width();
imgui->set_next_window_pos(x, m_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f);
imgui->set_next_window_bg_alpha(0.5f);
imgui->begin(wxString::Format(_(L("%s Stack")), stack_name),
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
int hovered = m_imgui_undo_redo_hovered_pos;
int selected = -1;
const float em = static_cast<float>(wxGetApp().em_unit());
if (imgui->undo_redo_list(ImVec2(12 * em, 20 * em), is_undo, &string_getter, hovered, selected))
m_imgui_undo_redo_hovered_pos = hovered;
else
m_imgui_undo_redo_hovered_pos = -1;
if (selected >= 0)
is_undo ? wxGetApp().plater()->undo_to(selected) : wxGetApp().plater()->redo_to(selected);
imgui->text(wxString::Format(_(L("%s %d Action")), stack_name, hovered + 1));
imgui->end();
}
bool GLCanvas3D::_init_toolbar()
{
if (!m_toolbar.is_enabled())
@ -3444,7 +3530,7 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "add.svg";
item.tooltip = _utf8(L("Add...")) + " [" + GUI::shortkey_ctrl_prefix() + "I]";
item.sprite_id = 0;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); };
if (!m_toolbar.add_item(item))
return false;
@ -3452,8 +3538,8 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "remove.svg";
item.tooltip = _utf8(L("Delete")) + " [Del]";
item.sprite_id = 1;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE)); };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_delete(); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete(); };
if (!m_toolbar.add_item(item))
return false;
@ -3461,8 +3547,8 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "delete_all.svg";
item.tooltip = _utf8(L("Delete all")) + " [" + GUI::shortkey_ctrl_prefix() + "Del]";
item.sprite_id = 2;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_delete_all(); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete_all(); };
if (!m_toolbar.add_item(item))
return false;
@ -3470,8 +3556,8 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "arrange.svg";
item.tooltip = _utf8(L("Arrange")) + " [A]";
item.sprite_id = 3;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_arrange(); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); };
if (!m_toolbar.add_item(item))
return false;
@ -3482,8 +3568,8 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "copy.svg";
item.tooltip = _utf8(L("Copy")) + " [" + GUI::shortkey_ctrl_prefix() + "C]";
item.sprite_id = 4;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_copy_to_clipboard(); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_copy_to_clipboard(); };
if (!m_toolbar.add_item(item))
return false;
@ -3491,8 +3577,8 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "paste.svg";
item.tooltip = _utf8(L("Paste")) + " [" + GUI::shortkey_ctrl_prefix() + "V]";
item.sprite_id = 5;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_paste_from_clipboard(); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_paste_from_clipboard(); };
if (!m_toolbar.add_item(item))
return false;
@ -3503,9 +3589,10 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "instance_add.svg";
item.tooltip = _utf8(L("Add instance")) + " [+]";
item.sprite_id = 6;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); };
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_increase_instances(); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_increase_instances(); };
if (!m_toolbar.add_item(item))
return false;
@ -3513,9 +3600,9 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "instance_remove.svg";
item.tooltip = _utf8(L("Remove instance")) + " [-]";
item.sprite_id = 7;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); };
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_decrease_instances(); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_decrease_instances(); };
if (!m_toolbar.add_item(item))
return false;
@ -3526,9 +3613,9 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "split_objects.svg";
item.tooltip = _utf8(L("Split to objects"));
item.sprite_id = 8;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); };
item.visibility_callback = GLToolbarItem::Default_Visibility_Callback;
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_split_to_objects(); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_split_to_objects(); };
if (!m_toolbar.add_item(item))
return false;
@ -3536,9 +3623,9 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "split_parts.svg";
item.tooltip = _utf8(L("Split to parts"));
item.sprite_id = 9;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); };
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); };
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_split_to_volumes(); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_split_to_volumes(); };
if (!m_toolbar.add_item(item))
return false;
@ -3549,10 +3636,42 @@ bool GLCanvas3D::_init_toolbar()
item.icon_filename = "layers_white.svg";
item.tooltip = _utf8(L("Layers editing"));
item.sprite_id = 10;
item.is_toggable = true;
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); };
item.left.toggable = true;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); };
item.visibility_callback = [this]()->bool { return m_process->current_printer_technology() == ptFFF; };
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_layers_editing(); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_layers_editing(); };
if (!m_toolbar.add_item(item))
return false;
if (!m_toolbar.add_separator())
return false;
item.name = "undo";
#if ENABLE_SVG_ICONS
item.icon_filename = "undo_toolbar.svg";
#endif // ENABLE_SVG_ICONS
item.tooltip = _utf8(L("Undo")) + " [" + GUI::shortkey_ctrl_prefix() + "Z]";
item.sprite_id = 11;
item.left.toggable = false;
item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_UNDO)); };
item.right.toggable = true;
item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; };
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(true, 0.5f * (left + right)); };
item.visibility_callback = []()->bool { return true; };
item.enabling_callback = [this]()->bool { return wxGetApp().plater()->can_undo(); };
if (!m_toolbar.add_item(item))
return false;
item.name = "redo";
#if ENABLE_SVG_ICONS
item.icon_filename = "redo_toolbar.svg";
#endif // ENABLE_SVG_ICONS
item.tooltip = _utf8(L("Redo")) + " [" + GUI::shortkey_ctrl_prefix() + "Y]";
item.sprite_id = 12;
item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_REDO)); };
item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; };
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(false, 0.5f * (left + right)); };
item.enabling_callback = [this]()->bool { return wxGetApp().plater()->can_redo(); };
if (!m_toolbar.add_item(item))
return false;
@ -5551,6 +5670,22 @@ void GLCanvas3D::_update_selection_from_hover()
m_dirty = true;
}
bool GLCanvas3D::_deactivate_undo_redo_toolbar_items()
{
if (m_toolbar.is_item_pressed("undo"))
{
m_toolbar.force_right_action(m_toolbar.get_item_id("undo"), *this);
return true;
}
else if (m_toolbar.is_item_pressed("redo"))
{
m_toolbar.force_right_action(m_toolbar.get_item_id("redo"), *this);
return true;
}
return false;
}
const Print* GLCanvas3D::fff_print() const
{
return (m_process == nullptr) ? nullptr : m_process->fff_print();