Extract canvas tool UI planning

This commit is contained in:
2026-06-03 11:20:56 +02:00
parent 58afa672c7
commit 2087505921
8 changed files with 456 additions and 29 deletions

View File

@@ -0,0 +1,86 @@
#pragma once
#include "foundation/result.h"
namespace pp::app {
enum class CanvasToolOperation {
select_mode,
toggle_picking,
toggle_touch_lock,
};
enum class CanvasToolMode {
draw,
erase,
line,
camera,
grid,
copy,
cut,
fill,
mask_free,
mask_line,
flood_fill,
};
enum class CanvasToolTransformAction {
none,
copy,
cut,
};
struct CanvasToolPlan {
CanvasToolOperation operation = CanvasToolOperation::select_mode;
CanvasToolMode mode = CanvasToolMode::draw;
CanvasToolTransformAction transform_action = CanvasToolTransformAction::none;
bool selects_toolbar_button = false;
bool updates_canvas_mode = false;
bool toggles_picking = false;
bool toggles_touch_lock = false;
bool requires_draw_mode = false;
bool no_op = false;
};
[[nodiscard]] inline constexpr CanvasToolTransformAction transform_action_for_mode(CanvasToolMode mode) noexcept
{
if (mode == CanvasToolMode::copy) {
return CanvasToolTransformAction::copy;
}
if (mode == CanvasToolMode::cut) {
return CanvasToolTransformAction::cut;
}
return CanvasToolTransformAction::none;
}
[[nodiscard]] inline constexpr CanvasToolPlan plan_canvas_tool_select(CanvasToolMode mode) noexcept
{
CanvasToolPlan plan;
plan.operation = CanvasToolOperation::select_mode;
plan.mode = mode;
plan.transform_action = transform_action_for_mode(mode);
plan.selects_toolbar_button = true;
plan.updates_canvas_mode = true;
return plan;
}
[[nodiscard]] inline constexpr CanvasToolPlan plan_canvas_tool_pick_toggle(bool current_mode_is_draw) noexcept
{
CanvasToolPlan plan;
plan.operation = CanvasToolOperation::toggle_picking;
plan.mode = CanvasToolMode::draw;
plan.requires_draw_mode = true;
plan.toggles_picking = current_mode_is_draw;
plan.no_op = !current_mode_is_draw;
return plan;
}
[[nodiscard]] inline constexpr CanvasToolPlan plan_canvas_tool_touch_lock_toggle() noexcept
{
CanvasToolPlan plan;
plan.operation = CanvasToolOperation::toggle_touch_lock;
plan.toggles_touch_lock = true;
return plan;
}
} // namespace pp::app

View File

@@ -8,6 +8,7 @@
#include "node_panel_floating.h"
#include "app_core/app_preferences.h"
#include "app_core/brush_ui.h"
#include "app_core/canvas_tool_ui.h"
#include "app_core/document_layer.h"
#include "app_core/app_status.h"
#include "app_core/history_ui.h"
@@ -569,22 +570,75 @@ void select_button(Node* main, T* button) {
button->set_active(false);
};
kCanvasMode canvas_mode_from_tool(pp::app::CanvasToolMode mode)
{
switch (mode) {
case pp::app::CanvasToolMode::draw:
return kCanvasMode::Draw;
case pp::app::CanvasToolMode::erase:
return kCanvasMode::Erase;
case pp::app::CanvasToolMode::line:
return kCanvasMode::Line;
case pp::app::CanvasToolMode::camera:
return kCanvasMode::Camera;
case pp::app::CanvasToolMode::grid:
return kCanvasMode::Grid;
case pp::app::CanvasToolMode::copy:
return kCanvasMode::Copy;
case pp::app::CanvasToolMode::cut:
return kCanvasMode::Cut;
case pp::app::CanvasToolMode::fill:
return kCanvasMode::Fill;
case pp::app::CanvasToolMode::mask_free:
return kCanvasMode::MaskFree;
case pp::app::CanvasToolMode::mask_line:
return kCanvasMode::MaskLine;
case pp::app::CanvasToolMode::flood_fill:
return kCanvasMode::FloodFill;
}
return kCanvasMode::Draw;
}
template<class T>
void apply_canvas_tool_select(App& app, T* button, pp::app::CanvasToolMode mode)
{
const auto plan = pp::app::plan_canvas_tool_select(mode);
if (plan.selects_toolbar_button)
select_button(app.layout[app.main_id], button);
if (plan.transform_action == pp::app::CanvasToolTransformAction::copy) {
auto* transform = static_cast<CanvasModeTransform*>(
app.canvas->m_canvas->modes[(int)kCanvasMode::Copy][0]);
transform->m_action = CanvasModeTransform::ActionType::Copy;
} else if (plan.transform_action == pp::app::CanvasToolTransformAction::cut) {
auto* transform = static_cast<CanvasModeTransform*>(
app.canvas->m_canvas->modes[(int)kCanvasMode::Cut][0]);
transform->m_action = CanvasModeTransform::ActionType::Cut;
}
if (plan.updates_canvas_mode)
Canvas::set_mode(canvas_mode_from_tool(plan.mode));
}
void App::init_toolbar_draw()
{
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-pen"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::Draw);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::draw);
};
//button->set_active(true);
Canvas::set_mode(kCanvasMode::Draw);
const auto plan = pp::app::plan_canvas_tool_select(pp::app::CanvasToolMode::draw);
if (plan.updates_canvas_mode)
Canvas::set_mode(canvas_mode_from_tool(plan.mode));
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-pick"))
{
button->on_click = [this](Node*) {
CanvasModePen* mode = (CanvasModePen*)canvas->m_canvas->modes[(int)kCanvasMode::Draw][0];
if (mode && canvas->m_canvas->m_current_mode == kCanvasMode::Draw)
const auto plan = pp::app::plan_canvas_tool_pick_toggle(
canvas->m_canvas->m_current_mode == kCanvasMode::Draw);
if (mode && plan.toggles_picking)
{
mode->m_picking = !mode->m_picking;
}
@@ -593,82 +647,70 @@ void App::init_toolbar_draw()
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-touchlock"))
{
button->on_click = [this](Node*) {
canvas->m_canvas->m_touch_lock = !canvas->m_canvas->m_touch_lock;
const auto plan = pp::app::plan_canvas_tool_touch_lock_toggle();
if (plan.toggles_touch_lock)
canvas->m_canvas->m_touch_lock = !canvas->m_canvas->m_touch_lock;
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-erase"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::Erase);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::erase);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-line"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::Line);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::line);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-cam"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::Camera);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::camera);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-grid"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::Grid);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::grid);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-copy"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
auto m = static_cast<CanvasModeTransform*>(canvas->m_canvas->modes[(int)kCanvasMode::Copy][0]);
m->m_action = CanvasModeTransform::ActionType::Copy;
Canvas::set_mode(kCanvasMode::Copy);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::copy);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-cut"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
auto m = static_cast<CanvasModeTransform*>(canvas->m_canvas->modes[(int)kCanvasMode::Cut][0]);
m->m_action = CanvasModeTransform::ActionType::Cut;
Canvas::set_mode(kCanvasMode::Cut);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::cut);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-fill"))
{
// polygon fill
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::Fill);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::fill);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-mask-free"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::MaskFree);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::mask_free);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-mask-line"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::MaskLine);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::mask_line);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-bucket"))
{
button->on_click = [this, button](Node*) {
select_button(layout[main_id], button);
Canvas::set_mode(kCanvasMode::FloodFill);
apply_canvas_tool_select(*this, button, pp::app::CanvasToolMode::flood_fill);
};
}
}