UndoStack.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibGUI/Command.h>
  8. #include <LibGUI/UndoStack.h>
  9. namespace GUI {
  10. bool UndoStack::can_undo() const
  11. {
  12. return m_stack_index > 0;
  13. }
  14. bool UndoStack::can_redo() const
  15. {
  16. if (m_stack.is_empty())
  17. return false;
  18. return m_stack_index != m_stack.size();
  19. }
  20. void UndoStack::undo()
  21. {
  22. if (!can_undo())
  23. return;
  24. auto& command = m_stack[--m_stack_index];
  25. command.undo();
  26. if (on_state_change)
  27. on_state_change();
  28. }
  29. void UndoStack::redo()
  30. {
  31. if (!can_redo())
  32. return;
  33. auto& command = m_stack[m_stack_index++];
  34. command.redo();
  35. if (on_state_change)
  36. on_state_change();
  37. }
  38. void UndoStack::push(NonnullOwnPtr<Command> command)
  39. {
  40. // If the stack cursor is behind the top of the stack, nuke everything from here to the top.
  41. while (m_stack.size() != m_stack_index)
  42. (void)m_stack.take_last();
  43. if (m_clean_index.has_value() && m_clean_index.value() > m_stack.size())
  44. m_clean_index = {};
  45. if (!m_stack.is_empty() && is_current_modified()) {
  46. if (m_stack.last().merge_with(*command))
  47. return;
  48. }
  49. m_stack.append(move(command));
  50. m_stack_index = m_stack.size();
  51. if (on_state_change)
  52. on_state_change();
  53. }
  54. void UndoStack::set_current_unmodified()
  55. {
  56. if (m_clean_index.has_value() && m_clean_index.value() == m_stack_index)
  57. return;
  58. m_clean_index = m_stack_index;
  59. m_last_unmodified_timestamp = Time::now_monotonic();
  60. if (on_state_change)
  61. on_state_change();
  62. }
  63. bool UndoStack::is_current_modified() const
  64. {
  65. if (m_stack.is_empty())
  66. return false;
  67. if (!m_clean_index.has_value())
  68. return true;
  69. if (m_stack_index != m_clean_index.value())
  70. return true;
  71. return false;
  72. }
  73. void UndoStack::clear()
  74. {
  75. if (m_stack.is_empty() && m_stack_index == 0 && !m_clean_index.has_value())
  76. return;
  77. m_stack.clear();
  78. m_stack_index = 0;
  79. m_clean_index.clear();
  80. if (on_state_change)
  81. on_state_change();
  82. }
  83. Optional<String> UndoStack::undo_action_text() const
  84. {
  85. if (!can_undo())
  86. return {};
  87. return m_stack[m_stack_index - 1].action_text();
  88. }
  89. Optional<String> UndoStack::redo_action_text() const
  90. {
  91. if (!can_redo())
  92. return {};
  93. return m_stack[m_stack_index].action_text();
  94. }
  95. }