diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0ea20bd5e..5ffd4e51c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6190,6 +6190,9 @@ bool Plater::can_mirror() const { return p->can_mirror(); } bool Plater::can_split(bool to_objects) const { return p->can_split(to_objects); } const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); } void Plater::clear_undo_redo_stack_main() { p->undo_redo_stack_main().clear(); } +#if ENABLE_PROJECT_DIRTY_STATE +const UndoRedo::Stack& Plater::undo_redo_stack_active() const { return p->undo_redo_stack(); } +#endif // ENABLE_PROJECT_DIRTY_STATE void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); } void Plater::leave_gizmos_stack() { p->leave_gizmos_stack(); } bool Plater::inside_snapshot_capture() { return p->inside_snapshot_capture(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 9b42863ec..8d228e68f 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -242,6 +242,9 @@ public: // For the memory statistics. const Slic3r::UndoRedo::Stack& undo_redo_stack_main() const; void clear_undo_redo_stack_main(); +#if ENABLE_PROJECT_DIRTY_STATE + const Slic3r::UndoRedo::Stack& undo_redo_stack_active() const; +#endif // ENABLE_PROJECT_DIRTY_STATE // Enter / leave the Gizmos specific Undo / Redo stack. To be used by the SLA support point editing gizmo. void enter_gizmos_stack(); void leave_gizmos_stack(); diff --git a/src/slic3r/GUI/ProjectDirtyStateManager.cpp b/src/slic3r/GUI/ProjectDirtyStateManager.cpp index 5fc45ccec..5d4cd8605 100644 --- a/src/slic3r/GUI/ProjectDirtyStateManager.cpp +++ b/src/slic3r/GUI/ProjectDirtyStateManager.cpp @@ -1,19 +1,68 @@ #include "libslic3r/libslic3r.h" + #include "ProjectDirtyStateManager.hpp" #include "ImGuiWrapper.hpp" #include "GUI_App.hpp" #include "MainFrame.hpp" +#include "I18N.hpp" +#include "Plater.hpp" +#include "../Utils/UndoRedo.hpp" + +#include + +#include +#include #if ENABLE_PROJECT_DIRTY_STATE namespace Slic3r { namespace GUI { +enum class EStackType +{ + Main, + Gizmo +}; + +static const UndoRedo::Snapshot* get_active_snapshot(const UndoRedo::Stack& stack) { + const std::vector& snapshots = stack.snapshots(); + const size_t active_snapshot_time = stack.active_snapshot_time(); + const auto it = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(active_snapshot_time)); + const int idx = it - snapshots.begin() - 1; + const Slic3r::UndoRedo::Snapshot* ret = (0 < idx && (size_t)idx < snapshots.size() - 1) ? + &snapshots[idx] : nullptr; + + assert(ret != nullptr); + + return ret; +} + +static const UndoRedo::Snapshot* get_last_valid_snapshot(EStackType type, const UndoRedo::Stack& stack) { + auto skip_main = [](const UndoRedo::Snapshot& snapshot) { + return boost::starts_with(snapshot.name, _utf8("Selection")); + }; + + const UndoRedo::Snapshot* snapshot = get_active_snapshot(stack); + + const UndoRedo::Snapshot* curr = snapshot; + const std::vector& snapshots = stack.snapshots(); + while (type == EStackType::Main && skip_main(*curr)) { + curr = &(*std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(curr->timestamp - 1))); + } + + return curr; +} + void ProjectDirtyStateManager::update_from_undo_redo_stack(const Slic3r::UndoRedo::Stack& main_stack, const Slic3r::UndoRedo::Stack& active_stack) { if (!wxGetApp().initialized()) return; + if (&main_stack == &active_stack) + update_from_undo_redo_main_stack(main_stack); + else + update_from_undo_redo_gizmo_stack(active_stack); + wxGetApp().mainframe->update_title(); } @@ -31,8 +80,27 @@ void ProjectDirtyStateManager::update_from_presets() void ProjectDirtyStateManager::reset_after_save() { reset_initial_presets(); - m_state.reset(); + + const Plater* plater = wxGetApp().plater(); + const UndoRedo::Stack& main_stack = plater->undo_redo_stack_main(); + const UndoRedo::Stack& active_stack = plater->undo_redo_stack_active(); + + if (&main_stack == &active_stack) { + const UndoRedo::Snapshot* active_snapshot = get_active_snapshot(main_stack); + const UndoRedo::Snapshot* valid_snapshot = get_last_valid_snapshot(EStackType::Main, main_stack); + +// std::cout << "SAVE - active: " << active_snapshot->timestamp << " - " << active_snapshot->name << "\n"; +// std::cout << "SAVE - valid: " << valid_snapshot->timestamp << " - " << valid_snapshot->name << "\n"; + + m_last_save.main = valid_snapshot->timestamp; + } + else { + const UndoRedo::Snapshot* active_snapshot = get_active_snapshot(active_stack); + +// std::cout << "SAVE - active: " << active_snapshot->timestamp << " - " << active_snapshot->name << "\n"; + } + wxGetApp().mainframe->update_title(); } @@ -48,35 +116,66 @@ void ProjectDirtyStateManager::reset_initial_presets() #if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW void ProjectDirtyStateManager::render_debug_window() const { + ImGuiWrapper& imgui = *wxGetApp().imgui(); + auto color = [](bool value) { return value ? ImVec4(1.0f, 0.49f, 0.216f, 1.0f) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); }; auto text = [](bool value) { return value ? "true" : "false"; }; + auto append_item = [color, text, &imgui](const std::string& name, bool value) { + imgui.text_colored(color(value), name); + ImGui::SameLine(); + imgui.text_colored(color(value), text(value)); + }; - std::string title = "Project dirty state statistics"; - ImGuiWrapper& imgui = *wxGetApp().imgui(); - imgui.begin(title, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - - bool dirty = is_dirty(); - imgui.text_colored(color(dirty), "State:"); - ImGui::SameLine(); - imgui.text_colored(color(dirty), text(dirty)); + imgui.begin(std::string( "Project dirty state statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + append_item("State:", is_dirty()); ImGui::Separator(); - imgui.text_colored(color(m_state.plater), "Plater:"); - ImGui::SameLine(); - imgui.text_colored(color(m_state.plater), text(m_state.plater)); - - imgui.text_colored(color(m_state.presets), "Presets:"); - ImGui::SameLine(); - imgui.text_colored(color(m_state.presets), text(m_state.presets)); + append_item("Plater:", m_state.plater); + append_item("Presets:", m_state.presets); + append_item("Current gizmo:", m_state.current_gizmo); imgui.end(); } #endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW +void ProjectDirtyStateManager::update_from_undo_redo_main_stack(const Slic3r::UndoRedo::Stack& stack) +{ + m_state.plater = false; + + const UndoRedo::Snapshot* active_snapshot = get_active_snapshot(stack); + +// std::cout << "UPDATE - active: " << active_snapshot->timestamp << " - " << active_snapshot->name << "\n"; + + if (active_snapshot->name == _utf8("New Project") || + active_snapshot->name == _utf8("Reset Project") || + boost::starts_with(active_snapshot->name, _utf8("Load Project:"))) + return; + + const UndoRedo::Snapshot* valid_snapshot = get_last_valid_snapshot(EStackType::Main, stack); + +// std::cout << "UPDATE - valid: " << valid_snapshot->timestamp << " - " << valid_snapshot->name << "\n"; + + m_state.plater = valid_snapshot->timestamp != m_last_save.main; +} + +void ProjectDirtyStateManager::update_from_undo_redo_gizmo_stack(const Slic3r::UndoRedo::Stack& stack) +{ + m_state.current_gizmo = false; + + const UndoRedo::Snapshot* active_snapshot = get_active_snapshot(stack); + +// std::cout << "UPDATE - active: " << active_snapshot->timestamp << " - " << active_snapshot->name << "\n"; + + if (active_snapshot->name == "Gizmos-Initial") + return; + + m_state.current_gizmo = true; +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/ProjectDirtyStateManager.hpp b/src/slic3r/GUI/ProjectDirtyStateManager.hpp index 2aa6680c6..2eac4ba92 100644 --- a/src/slic3r/GUI/ProjectDirtyStateManager.hpp +++ b/src/slic3r/GUI/ProjectDirtyStateManager.hpp @@ -17,15 +17,29 @@ class ProjectDirtyStateManager { bool plater{ false }; bool presets{ false }; + bool current_gizmo{ false }; - bool is_dirty() const { return plater || presets; } + bool is_dirty() const { return plater || presets || current_gizmo; } void reset() { plater = false; presets = false; + current_gizmo = false; + } + }; + + struct Timestamps + { + size_t main{ 0 }; + size_t gizmo{ 0 }; + + void reset() { + main = 0; + gizmo = 0; } }; DirtyState m_state; + Timestamps m_last_save; // keeps track of initial selected presets std::array m_initial_presets; @@ -39,6 +53,10 @@ public: #if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW void render_debug_window() const; #endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW + +private: + void update_from_undo_redo_main_stack(const Slic3r::UndoRedo::Stack& stack); + void update_from_undo_redo_gizmo_stack(const Slic3r::UndoRedo::Stack& stack); }; } // namespace GUI diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 0a11e838a..c1806cfcd 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -387,8 +387,8 @@ class TabPrint : public Tab { public: TabPrint(wxNotebook* parent) : -// Tab(parent, _(L("Print Settings")), L("print")) {} - Tab(parent, _(L("Print Settings")), Slic3r::Preset::TYPE_PRINT) {} +// Tab(parent, _L("Print Settings"), L("print")) {} + Tab(parent, _L("Print Settings"), Slic3r::Preset::TYPE_PRINT) {} ~TabPrint() {} void build() override; @@ -421,8 +421,8 @@ private: std::map m_overrides_options; public: TabFilament(wxNotebook* parent) : -// Tab(parent, _(L("Filament Settings")), L("filament")) {} - Tab(parent, _(L("Filament Settings")), Slic3r::Preset::TYPE_FILAMENT) {} +// Tab(parent, _L("Filament Settings"), L("filament")) {} + Tab(parent, _L("Filament Settings"), Slic3r::Preset::TYPE_FILAMENT) {} ~TabFilament() {} void build() override; @@ -467,7 +467,7 @@ public: // TabPrinter(wxNotebook* parent) : Tab(parent, _(L("Printer Settings")), L("printer")) {} TabPrinter(wxNotebook* parent) : - Tab(parent, _(L("Printer Settings")), Slic3r::Preset::TYPE_PRINTER) {} + Tab(parent, _L("Printer Settings"), Slic3r::Preset::TYPE_PRINTER) {} ~TabPrinter() {} void build() override; @@ -504,8 +504,8 @@ class TabSLAMaterial : public Tab { public: TabSLAMaterial(wxNotebook* parent) : -// Tab(parent, _(L("Material Settings")), L("sla_material")) {} - Tab(parent, _(L("Material Settings")), Slic3r::Preset::TYPE_SLA_MATERIAL) {} +// Tab(parent, _L("Material Settings"), L("sla_material")) {} + Tab(parent, _L("Material Settings"), Slic3r::Preset::TYPE_SLA_MATERIAL) {} ~TabSLAMaterial() {} void build() override; @@ -524,8 +524,8 @@ class TabSLAPrint : public Tab { public: TabSLAPrint(wxNotebook* parent) : -// Tab(parent, _(L("Print Settings")), L("sla_print")) {} - Tab(parent, _(L("Print Settings")), Slic3r::Preset::TYPE_SLA_PRINT) {} +// Tab(parent, _L("Print Settings"), L("sla_print")) {} + Tab(parent, _L("Print Settings"), Slic3r::Preset::TYPE_SLA_PRINT) {} ~TabSLAPrint() {} ogStaticText* m_support_object_elevation_description_line = nullptr;