#pragma once #include "foundation/result.h" namespace pp::app { enum class HistoryUiOperation { undo, redo, clear, }; struct HistoryUiPlan { HistoryUiOperation operation = HistoryUiOperation::undo; int undo_count = 0; int redo_count = 0; int memory_bytes = 0; bool invokes_undo = false; bool invokes_redo = false; bool clears_history = false; bool updates_memory_label = false; bool updates_title = false; bool no_op = false; }; class HistoryUiServices { public: virtual ~HistoryUiServices() = default; virtual void invoke_undo() = 0; virtual void invoke_redo() = 0; virtual void clear_history() = 0; }; [[nodiscard]] inline pp::foundation::Status validate_history_metric(int value, const char* message) noexcept { if (value < 0) { return pp::foundation::Status::out_of_range(message); } return pp::foundation::Status::success(); } [[nodiscard]] inline pp::foundation::Result plan_history_undo(int undo_count) { const auto count_status = validate_history_metric(undo_count, "undo action count must not be negative"); if (!count_status.ok()) { return pp::foundation::Result::failure(count_status); } HistoryUiPlan plan; plan.operation = HistoryUiOperation::undo; plan.undo_count = undo_count; if (undo_count == 0) { plan.no_op = true; return pp::foundation::Result::success(plan); } plan.invokes_undo = true; plan.updates_memory_label = true; plan.updates_title = true; return pp::foundation::Result::success(plan); } [[nodiscard]] inline pp::foundation::Result plan_history_redo(int redo_count) { const auto count_status = validate_history_metric(redo_count, "redo action count must not be negative"); if (!count_status.ok()) { return pp::foundation::Result::failure(count_status); } HistoryUiPlan plan; plan.operation = HistoryUiOperation::redo; plan.redo_count = redo_count; if (redo_count == 0) { plan.no_op = true; return pp::foundation::Result::success(plan); } plan.invokes_redo = true; plan.updates_memory_label = true; plan.updates_title = true; return pp::foundation::Result::success(plan); } [[nodiscard]] inline pp::foundation::Result plan_history_clear( int undo_count, int redo_count, int memory_bytes) { const auto undo_status = validate_history_metric(undo_count, "undo action count must not be negative"); if (!undo_status.ok()) { return pp::foundation::Result::failure(undo_status); } const auto redo_status = validate_history_metric(redo_count, "redo action count must not be negative"); if (!redo_status.ok()) { return pp::foundation::Result::failure(redo_status); } const auto memory_status = validate_history_metric(memory_bytes, "history memory bytes must not be negative"); if (!memory_status.ok()) { return pp::foundation::Result::failure(memory_status); } HistoryUiPlan plan; plan.operation = HistoryUiOperation::clear; plan.undo_count = undo_count; plan.redo_count = redo_count; plan.memory_bytes = memory_bytes; if (undo_count == 0 && redo_count == 0 && memory_bytes == 0) { plan.no_op = true; return pp::foundation::Result::success(plan); } plan.clears_history = true; plan.updates_memory_label = true; return pp::foundation::Result::success(plan); } [[nodiscard]] inline pp::foundation::Status execute_history_ui_plan( const HistoryUiPlan& plan, HistoryUiServices& services) { const auto undo_status = validate_history_metric(plan.undo_count, "undo action count must not be negative"); if (!undo_status.ok()) { return undo_status; } const auto redo_status = validate_history_metric(plan.redo_count, "redo action count must not be negative"); if (!redo_status.ok()) { return redo_status; } const auto memory_status = validate_history_metric(plan.memory_bytes, "history memory bytes must not be negative"); if (!memory_status.ok()) { return memory_status; } if (plan.no_op) { return pp::foundation::Status::success(); } switch (plan.operation) { case HistoryUiOperation::undo: if (plan.invokes_undo) { services.invoke_undo(); } return pp::foundation::Status::success(); case HistoryUiOperation::redo: if (plan.invokes_redo) { services.invoke_redo(); } return pp::foundation::Status::success(); case HistoryUiOperation::clear: if (plan.clears_history) { services.clear_history(); } return pp::foundation::Status::success(); } return pp::foundation::Status::invalid_argument("unknown history operation"); } } // namespace pp::app