230 lines
7.7 KiB
C++
230 lines
7.7 KiB
C++
#pragma once
|
|
|
|
#include "foundation/result.h"
|
|
|
|
namespace pp::app {
|
|
|
|
enum class QuickUiSlotKind {
|
|
brush,
|
|
color,
|
|
};
|
|
|
|
enum class QuickUiOperation {
|
|
select_slot,
|
|
open_slot_popup,
|
|
restore_state,
|
|
reset_state,
|
|
};
|
|
|
|
struct QuickUiPlan {
|
|
QuickUiOperation operation = QuickUiOperation::select_slot;
|
|
QuickUiSlotKind slot_kind = QuickUiSlotKind::brush;
|
|
int slot_index = 0;
|
|
int previous_index = 0;
|
|
int brush_index = 0;
|
|
int color_index = 0;
|
|
int slot_count = 0;
|
|
bool fire_event = false;
|
|
bool updates_selection = false;
|
|
bool opens_brush_popup = false;
|
|
bool opens_color_picker = false;
|
|
bool invokes_change_callback = false;
|
|
bool restores_slots = false;
|
|
bool resets_slots = false;
|
|
bool redraws_brush_previews = false;
|
|
bool mutates_quick_state = false;
|
|
};
|
|
|
|
class QuickUiServices {
|
|
public:
|
|
virtual ~QuickUiServices() = default;
|
|
|
|
virtual void select_slot(QuickUiSlotKind slot_kind, int slot_index, bool fire_event) = 0;
|
|
virtual void open_slot_popup(QuickUiSlotKind slot_kind, int slot_index) = 0;
|
|
virtual void restore_state(int brush_index, int color_index, bool fire_event) = 0;
|
|
virtual void reset_state(bool fire_event) = 0;
|
|
};
|
|
|
|
[[nodiscard]] inline pp::foundation::Status validate_quick_slot_count(int slot_count) noexcept
|
|
{
|
|
if (slot_count <= 0) {
|
|
return pp::foundation::Status::out_of_range("quick slot count must be greater than zero");
|
|
}
|
|
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
[[nodiscard]] inline pp::foundation::Status validate_quick_slot_index(int slot_index, int slot_count) noexcept
|
|
{
|
|
const auto count_status = validate_quick_slot_count(slot_count);
|
|
if (!count_status.ok()) {
|
|
return count_status;
|
|
}
|
|
|
|
if (slot_index < 0 || slot_index >= slot_count) {
|
|
return pp::foundation::Status::out_of_range("quick slot index is out of range");
|
|
}
|
|
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
[[nodiscard]] inline pp::foundation::Result<QuickUiPlan> plan_quick_slot_click(
|
|
QuickUiSlotKind slot_kind,
|
|
int current_index,
|
|
int clicked_index,
|
|
int slot_count)
|
|
{
|
|
const auto current_status = validate_quick_slot_index(current_index, slot_count);
|
|
if (!current_status.ok()) {
|
|
return pp::foundation::Result<QuickUiPlan>::failure(current_status);
|
|
}
|
|
|
|
const auto clicked_status = validate_quick_slot_index(clicked_index, slot_count);
|
|
if (!clicked_status.ok()) {
|
|
return pp::foundation::Result<QuickUiPlan>::failure(clicked_status);
|
|
}
|
|
|
|
QuickUiPlan plan;
|
|
plan.slot_kind = slot_kind;
|
|
plan.slot_index = clicked_index;
|
|
plan.previous_index = current_index;
|
|
plan.brush_index = slot_kind == QuickUiSlotKind::brush ? clicked_index : 0;
|
|
plan.color_index = slot_kind == QuickUiSlotKind::color ? clicked_index : 0;
|
|
plan.slot_count = slot_count;
|
|
if (clicked_index != current_index) {
|
|
plan.operation = QuickUiOperation::select_slot;
|
|
plan.updates_selection = true;
|
|
plan.invokes_change_callback = true;
|
|
plan.mutates_quick_state = true;
|
|
return pp::foundation::Result<QuickUiPlan>::success(plan);
|
|
}
|
|
|
|
plan.operation = QuickUiOperation::open_slot_popup;
|
|
plan.opens_brush_popup = slot_kind == QuickUiSlotKind::brush;
|
|
plan.opens_color_picker = slot_kind == QuickUiSlotKind::color;
|
|
return pp::foundation::Result<QuickUiPlan>::success(plan);
|
|
}
|
|
|
|
[[nodiscard]] inline pp::foundation::Result<QuickUiPlan> plan_quick_state_restore(
|
|
int brush_index,
|
|
int color_index,
|
|
int slot_count,
|
|
bool fire_event)
|
|
{
|
|
const auto brush_status = validate_quick_slot_index(brush_index, slot_count);
|
|
if (!brush_status.ok()) {
|
|
return pp::foundation::Result<QuickUiPlan>::failure(brush_status);
|
|
}
|
|
|
|
const auto color_status = validate_quick_slot_index(color_index, slot_count);
|
|
if (!color_status.ok()) {
|
|
return pp::foundation::Result<QuickUiPlan>::failure(color_status);
|
|
}
|
|
|
|
QuickUiPlan plan;
|
|
plan.operation = QuickUiOperation::restore_state;
|
|
plan.brush_index = brush_index;
|
|
plan.color_index = color_index;
|
|
plan.slot_count = slot_count;
|
|
plan.fire_event = fire_event;
|
|
plan.updates_selection = true;
|
|
plan.invokes_change_callback = fire_event;
|
|
plan.restores_slots = true;
|
|
plan.redraws_brush_previews = true;
|
|
plan.mutates_quick_state = true;
|
|
return pp::foundation::Result<QuickUiPlan>::success(plan);
|
|
}
|
|
|
|
[[nodiscard]] inline pp::foundation::Result<QuickUiPlan> plan_quick_state_reset(
|
|
int slot_count,
|
|
bool fire_event)
|
|
{
|
|
const auto count_status = validate_quick_slot_count(slot_count);
|
|
if (!count_status.ok()) {
|
|
return pp::foundation::Result<QuickUiPlan>::failure(count_status);
|
|
}
|
|
|
|
QuickUiPlan plan;
|
|
plan.operation = QuickUiOperation::reset_state;
|
|
plan.brush_index = 0;
|
|
plan.color_index = 0;
|
|
plan.slot_count = slot_count;
|
|
plan.fire_event = fire_event;
|
|
plan.updates_selection = true;
|
|
plan.invokes_change_callback = fire_event;
|
|
plan.resets_slots = true;
|
|
plan.redraws_brush_previews = true;
|
|
plan.mutates_quick_state = true;
|
|
return pp::foundation::Result<QuickUiPlan>::success(plan);
|
|
}
|
|
|
|
[[nodiscard]] inline pp::foundation::Status execute_quick_ui_plan(
|
|
const QuickUiPlan& plan,
|
|
QuickUiServices& services)
|
|
{
|
|
switch (plan.operation) {
|
|
case QuickUiOperation::select_slot:
|
|
if (!plan.updates_selection) {
|
|
return pp::foundation::Status::invalid_argument("quick select plan must update selection");
|
|
}
|
|
{
|
|
const auto status = validate_quick_slot_index(plan.slot_index, plan.slot_count);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
}
|
|
services.select_slot(plan.slot_kind, plan.slot_index, plan.invokes_change_callback);
|
|
return pp::foundation::Status::success();
|
|
|
|
case QuickUiOperation::open_slot_popup:
|
|
if (plan.slot_kind == QuickUiSlotKind::brush && !plan.opens_brush_popup) {
|
|
return pp::foundation::Status::invalid_argument("quick brush popup plan must open brush popup");
|
|
}
|
|
if (plan.slot_kind == QuickUiSlotKind::color && !plan.opens_color_picker) {
|
|
return pp::foundation::Status::invalid_argument("quick color popup plan must open color picker");
|
|
}
|
|
{
|
|
const auto status = validate_quick_slot_index(plan.slot_index, plan.slot_count);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
}
|
|
services.open_slot_popup(plan.slot_kind, plan.slot_index);
|
|
return pp::foundation::Status::success();
|
|
|
|
case QuickUiOperation::restore_state:
|
|
if (!plan.restores_slots) {
|
|
return pp::foundation::Status::invalid_argument("quick restore plan must restore slots");
|
|
}
|
|
{
|
|
const auto brush_status = validate_quick_slot_index(plan.brush_index, plan.slot_count);
|
|
if (!brush_status.ok()) {
|
|
return brush_status;
|
|
}
|
|
const auto color_status = validate_quick_slot_index(plan.color_index, plan.slot_count);
|
|
if (!color_status.ok()) {
|
|
return color_status;
|
|
}
|
|
}
|
|
services.restore_state(plan.brush_index, plan.color_index, plan.fire_event);
|
|
return pp::foundation::Status::success();
|
|
|
|
case QuickUiOperation::reset_state:
|
|
if (!plan.resets_slots) {
|
|
return pp::foundation::Status::invalid_argument("quick reset plan must reset slots");
|
|
}
|
|
{
|
|
const auto status = validate_quick_slot_count(plan.slot_count);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
}
|
|
services.reset_state(plan.fire_event);
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
return pp::foundation::Status::invalid_argument("unknown quick UI operation");
|
|
}
|
|
|
|
} // namespace pp::app
|