Extract quick UI operation planning
This commit is contained in:
143
src/app_core/quick_ui.h
Normal file
143
src/app_core/quick_ui.h
Normal file
@@ -0,0 +1,143 @@
|
||||
#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 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;
|
||||
};
|
||||
|
||||
[[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.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.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.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);
|
||||
}
|
||||
|
||||
} // namespace pp::app
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "pch.h"
|
||||
#include "app_core/quick_ui.h"
|
||||
#include "node_panel_quick.h"
|
||||
#include "node_stroke_preview.h"
|
||||
#include "node_image.h"
|
||||
@@ -31,11 +32,13 @@ void NodePanelQuick::set_color(glm::vec3 color)
|
||||
int NodePanelQuick::get_selected_brush_index() const
|
||||
{
|
||||
auto it = std::find(m_button_brushes.begin(), m_button_brushes.end(), m_button_brush_current);
|
||||
return std::distance(m_button_brushes.begin(), it);
|
||||
return static_cast<int>(std::distance(m_button_brushes.begin(), it));
|
||||
}
|
||||
|
||||
void NodePanelQuick::set_selected_brush_index(int idx, bool fire_event /*= false*/)
|
||||
{
|
||||
if (!pp::app::validate_quick_slot_index(idx, static_cast<int>(m_button_brushes.size())).ok())
|
||||
return;
|
||||
if (m_button_brush_current)
|
||||
m_button_brush_current->set_active(false);
|
||||
m_button_brush_current = m_button_brushes[idx];
|
||||
@@ -48,11 +51,13 @@ void NodePanelQuick::set_selected_brush_index(int idx, bool fire_event /*= false
|
||||
int NodePanelQuick::get_selected_color_index() const
|
||||
{
|
||||
auto it = std::find(m_button_colors.begin(), m_button_colors.end(), m_button_color_current);
|
||||
return std::distance(m_button_colors.begin(), it);
|
||||
return static_cast<int>(std::distance(m_button_colors.begin(), it));
|
||||
}
|
||||
|
||||
void NodePanelQuick::set_selected_color_index(int idx, bool fire_event /*= false*/)
|
||||
{
|
||||
if (!pp::app::validate_quick_slot_index(idx, static_cast<int>(m_button_colors.size())).ok())
|
||||
return;
|
||||
if (m_button_color_current)
|
||||
m_button_color_current->set_active(false);
|
||||
m_button_color_current = m_button_colors[idx];
|
||||
@@ -77,6 +82,14 @@ NodePanelQuick::MiniState NodePanelQuick::get_state() const
|
||||
|
||||
void NodePanelQuick::set_state(const MiniState& state, bool fire_event /*= false*/)
|
||||
{
|
||||
const auto plan = pp::app::plan_quick_state_restore(
|
||||
state.brush_index,
|
||||
state.color_index,
|
||||
static_cast<int>(m_button_brushes.size()),
|
||||
fire_event);
|
||||
if (!plan)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto b = static_cast<NodeStrokePreview*>(m_button_brushes[i]->m_children[0].get());
|
||||
@@ -91,6 +104,10 @@ void NodePanelQuick::set_state(const MiniState& state, bool fire_event /*= false
|
||||
|
||||
void NodePanelQuick::reset_state(bool fire_event /*= false*/)
|
||||
{
|
||||
const auto plan = pp::app::plan_quick_state_reset(static_cast<int>(m_button_brushes.size()), fire_event);
|
||||
if (!plan)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto b = static_cast<NodeStrokePreview*>(m_button_brushes[i]->m_children[0].get());
|
||||
@@ -179,10 +196,12 @@ NodeButtonCustom* NodePanelQuick::init_button_brush(const std::string& name, boo
|
||||
{
|
||||
LOG("init_button_brush %s", name.c_str());
|
||||
auto button = find<NodeButtonCustom>(name.c_str());
|
||||
if (!button)
|
||||
if (!button) {
|
||||
LOG("couldn't find button %s", name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
button->on_click = std::bind(&this_class::handle_button_brush_click, this, std::placeholders::_1);
|
||||
LOG("button has %d children", button->m_children.size());
|
||||
LOG("button has %d children", static_cast<int>(button->m_children.size()));
|
||||
auto pr = static_cast<NodeStrokePreview*>(button->m_children[0].get());
|
||||
pr->m_brush = std::make_shared<Brush>();
|
||||
pr->m_brush->m_tip_size_pressure = szp;
|
||||
@@ -197,8 +216,17 @@ NodeButtonCustom* NodePanelQuick::init_button_brush(const std::string& name, boo
|
||||
|
||||
void NodePanelQuick::handle_button_brush_click(Node* button)
|
||||
{
|
||||
// the first time select the box
|
||||
if (m_button_brush_current != button)
|
||||
const auto clicked = std::find(m_button_brushes.begin(), m_button_brushes.end(), button);
|
||||
const int clicked_index = static_cast<int>(std::distance(m_button_brushes.begin(), clicked));
|
||||
const auto plan = pp::app::plan_quick_slot_click(
|
||||
pp::app::QuickUiSlotKind::brush,
|
||||
get_selected_brush_index(),
|
||||
clicked_index,
|
||||
static_cast<int>(m_button_brushes.size()));
|
||||
if (!plan)
|
||||
return;
|
||||
|
||||
if (plan.value().updates_selection)
|
||||
{
|
||||
auto b = static_cast<NodeButtonCustom*>(button);
|
||||
b->set_active(true);
|
||||
@@ -210,7 +238,8 @@ void NodePanelQuick::handle_button_brush_click(Node* button)
|
||||
return;
|
||||
}
|
||||
|
||||
// if the box is already selected show the popup
|
||||
if (!plan.value().opens_brush_popup)
|
||||
return;
|
||||
|
||||
auto popup = App::I->presets;
|
||||
auto screen = root()->m_size;
|
||||
@@ -268,8 +297,17 @@ void NodePanelQuick::handle_button_brush_click(Node* button)
|
||||
|
||||
void NodePanelQuick::handle_button_color_click(Node* target)
|
||||
{
|
||||
// the first time select the box
|
||||
if (m_button_color_current != target)
|
||||
const auto clicked = std::find(m_button_colors.begin(), m_button_colors.end(), target);
|
||||
const int clicked_index = static_cast<int>(std::distance(m_button_colors.begin(), clicked));
|
||||
const auto plan = pp::app::plan_quick_slot_click(
|
||||
pp::app::QuickUiSlotKind::color,
|
||||
get_selected_color_index(),
|
||||
clicked_index,
|
||||
static_cast<int>(m_button_colors.size()));
|
||||
if (!plan)
|
||||
return;
|
||||
|
||||
if (plan.value().updates_selection)
|
||||
{
|
||||
auto button = static_cast<NodeButtonCustom*>(target);
|
||||
button->set_active(true);
|
||||
@@ -281,7 +319,9 @@ void NodePanelQuick::handle_button_color_click(Node* target)
|
||||
return;
|
||||
}
|
||||
|
||||
// if the box is already selected show the popup
|
||||
if (!plan.value().opens_color_picker)
|
||||
return;
|
||||
|
||||
auto popup = m_picker;
|
||||
auto screen = root()->m_size;
|
||||
glm::vec2 tick_sz = { 16, 32 };
|
||||
|
||||
Reference in New Issue
Block a user