/* * Copyright (c) 2018-2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include #include namespace GUI { UndoStack::UndoStack() { } UndoStack::~UndoStack() { } bool UndoStack::can_undo() const { return m_stack_index > 0 || (m_stack.size() == 1 && m_stack[0].commands.size() > 0); } bool UndoStack::can_redo() const { if (m_stack.is_empty()) return false; return m_stack_index != m_stack.size() - 1; } void UndoStack::undo() { if (!can_undo()) return; finalize_current_combo(); auto& combo = m_stack[--m_stack_index]; for (auto i = static_cast(combo.commands.size()) - 1; i >= 0; i--) combo.commands[i].undo(); if (on_state_change) on_state_change(); } void UndoStack::redo() { if (!can_redo()) return; auto& commands = m_stack[m_stack_index++].commands; for (auto& command : commands) command.redo(); if (on_state_change) on_state_change(); } void UndoStack::pop() { VERIFY(!m_stack.is_empty()); m_stack.take_last(); if (m_clean_index.has_value() && m_clean_index.value() > m_stack.size()) m_clean_index = {}; } void UndoStack::push(NonnullOwnPtr&& command) { if (m_stack.is_empty()) finalize_current_combo(); // If the stack cursor is behind the top of the stack, nuke everything from here to the top. if (m_stack_index != m_stack.size() - 1) { while (m_stack.size() != m_stack_index) { pop(); } finalize_current_combo(); } if (!m_stack.last().commands.is_empty()) { bool merged = m_stack.last().commands.last().merge_with(*command); if (merged) return; } m_stack.last().commands.append(move(command)); if (on_state_change) on_state_change(); } void UndoStack::finalize_current_combo() { if (m_stack.is_empty()) { m_stack.append(make()); return; } if (!m_stack.last().commands.is_empty()) { m_stack.append(make()); m_stack_index = m_stack.size() - 1; if (on_state_change) on_state_change(); } } void UndoStack::set_current_unmodified() { finalize_current_combo(); if (m_clean_index.has_value() && m_clean_index.value() == m_stack_index) return; m_clean_index = m_stack_index; if (on_state_change) on_state_change(); } bool UndoStack::is_current_modified() const { if (!m_clean_index.has_value()) return true; if (m_stack_index != m_clean_index.value()) return true; if (m_stack.is_empty()) return false; if (m_stack_index == m_stack.size() - 1 && !m_stack[m_stack_index].commands.is_empty()) return true; return false; } void UndoStack::clear() { if (m_stack.is_empty() && m_stack_index == 0 && !m_clean_index.has_value()) return; m_stack.clear(); m_stack_index = 0; m_clean_index.clear(); if (on_state_change) on_state_change(); } }