Route canvas hotkeys through app core

This commit is contained in:
2026-06-03 20:30:07 +02:00
parent 16a1d1e15b
commit 6945ce7e23
8 changed files with 953 additions and 52 deletions

View File

@@ -5,6 +5,7 @@
#include <memory>
#include <vector>
#include "app_core/canvas_hotkey.h"
#include "app_core/canvas_tool_ui.h"
#include "app_core/history_ui.h"
#include "app.h"
@@ -69,20 +70,6 @@ pp::paint_renderer::CanvasBlendGatePlan node_canvas_blend_gate_plan(
return fallback;
}
void run_history_undo_if_available()
{
const auto plan = pp::app::plan_history_undo(static_cast<int>(ActionManager::I.m_actions.size()));
if (plan && plan.value().invokes_undo)
ActionManager::undo();
}
void run_history_redo_if_available()
{
const auto plan = pp::app::plan_history_redo(static_cast<int>(ActionManager::I.m_redos.size()));
if (plan && plan.value().invokes_redo)
ActionManager::redo();
}
class LegacyNodeCanvasToolServices final : public pp::app::CanvasToolServices {
public:
void select_toolbar_button(pp::app::CanvasToolMode) override
@@ -116,6 +103,124 @@ public:
}
};
class LegacyNodeCanvasHistoryServices final : public pp::app::HistoryUiServices {
public:
void invoke_undo() override
{
ActionManager::undo();
}
void invoke_redo() override
{
ActionManager::redo();
}
void clear_history() override
{
ActionManager::clear();
}
};
class LegacyNodeCanvasHotkeyServices final : public pp::app::CanvasHotkeyServices {
public:
pp::foundation::Status execute_tool(const pp::app::CanvasToolPlan& plan) override
{
LegacyNodeCanvasToolServices services;
return pp::app::execute_canvas_tool_plan(plan, services);
}
pp::foundation::Status execute_history(const pp::app::HistoryUiPlan& plan) override
{
LegacyNodeCanvasHistoryServices services;
return pp::app::execute_history_ui_plan(plan, services);
}
void save_document(pp::app::DocumentSaveIntent intent) override
{
App::I->save_document(intent);
}
void toggle_ui() override
{
App::I->toggle_ui();
}
void adjust_brush_size(float delta) override
{
if (!App::I || !App::I->stroke || !App::I->stroke->m_tip_size)
return;
const float value = App::I->stroke->m_tip_size->get_value();
const float next_value = glm::clamp<float>(value + delta, 0.0F, 1.0F);
App::I->stroke->set_size(next_value, true, true);
}
void show_cursor() override
{
App::I->show_cursor();
}
};
pp::app::CanvasHotkeyKey canvas_hotkey_key(kKey key) noexcept
{
switch (key) {
case kKey::AndroidBack:
return pp::app::CanvasHotkeyKey::android_back;
case kKey::KeyAlt:
return pp::app::CanvasHotkeyKey::alt;
case kKey::KeyE:
return pp::app::CanvasHotkeyKey::e;
case kKey::KeyS:
return pp::app::CanvasHotkeyKey::s;
case kKey::KeyTab:
return pp::app::CanvasHotkeyKey::tab;
case kKey::KeyZ:
return pp::app::CanvasHotkeyKey::z;
case kKey::KeyBracketLeft:
return pp::app::CanvasHotkeyKey::bracket_left;
case kKey::KeyBracketRight:
return pp::app::CanvasHotkeyKey::bracket_right;
default:
return pp::app::CanvasHotkeyKey::other;
}
}
pp::app::CanvasHotkeyState canvas_hotkey_state(bool mouse_focused, int touch_finger_count = 0) noexcept
{
pp::app::CanvasHotkeyState state;
state.ctrl_down = App::I && App::I->keys[(int)kKey::KeyCtrl];
state.shift_down = App::I && App::I->keys[(int)kKey::KeyShift];
state.mouse_focused = mouse_focused;
state.undo_count = static_cast<int>(ActionManager::I.m_actions.size());
state.redo_count = static_cast<int>(ActionManager::I.m_redos.size());
state.touch_finger_count = touch_finger_count;
return state;
}
void execute_canvas_hotkey_plan(const pp::app::CanvasHotkeyPlan& plan)
{
LegacyNodeCanvasHotkeyServices services;
const auto status = pp::app::execute_canvas_hotkey_plan(plan, services);
if (!status.ok())
LOG("Canvas hotkey action failed: %s", status.message);
}
void run_canvas_hotkey(
pp::app::CanvasHotkeyEvent event,
kKey key,
bool mouse_focused,
int touch_finger_count = 0)
{
const auto plan = pp::app::plan_canvas_hotkey(
event,
canvas_hotkey_key(key),
canvas_hotkey_state(mouse_focused, touch_finger_count));
if (plan)
execute_canvas_hotkey_plan(plan.value());
else
LOG("Canvas hotkey planning failed: %s", plan.status().message);
}
void run_canvas_tool_mode(pp::app::CanvasToolMode mode)
{
const auto plan = pp::app::plan_canvas_tool_select(mode);
@@ -700,43 +805,19 @@ kEventResult NodeCanvas::handle_event(Event* e)
update_cursor();
break;
case kEventType::KeyDown:
if (ke->m_key == kKey::KeyE)
run_canvas_tool_mode(pp::app::CanvasToolMode::erase);
if (ke->m_key == kKey::AndroidBack)
run_history_undo_if_available();
if (ke->m_key == kKey::KeyAlt && m_mouse_focus)
App::I->show_cursor();
run_canvas_hotkey(
pp::app::CanvasHotkeyEvent::key_down,
ke->m_key,
m_mouse_focus);
for (auto& mode : *m_canvas->m_mode)
mode->on_KeyEvent(ke);
break;
case kEventType::KeyUp:
update_cursor();
if (ke->m_key == kKey::KeyE)
run_canvas_tool_mode(pp::app::CanvasToolMode::draw);
if (ke->m_key == kKey::KeyTab)
App::I->toggle_ui();
if (ke->m_key == kKey::KeyZ && App::I->keys[(int)kKey::KeyCtrl])
App::I->keys[(int)kKey::KeyShift] ? run_history_redo_if_available() : run_history_undo_if_available();
if (ke->m_key == kKey::KeyS && App::I->keys[(int)kKey::KeyCtrl] && !App::I->keys[(int)kKey::KeyShift])
{
App::I->save_document(pp::app::DocumentSaveIntent::save);
}
if (ke->m_key == kKey::KeyS && App::I->keys[(int)kKey::KeyCtrl] && App::I->keys[(int)kKey::KeyShift])
{
App::I->save_document(pp::app::DocumentSaveIntent::save_dirty_version);
}
if (ke->m_key == kKey::KeyBracketLeft)
{
float v = App::I->stroke->m_tip_size->get_value();
float nv = glm::clamp<float>(v - 0.05, 0, 1);
App::I->stroke->set_size(nv, true, true);
}
if (ke->m_key == kKey::KeyBracketRight)
{
float v = App::I->stroke->m_tip_size->get_value();
float nv = glm::clamp<float>(v + 0.05, 0, 1);
App::I->stroke->set_size(nv, true, true);
}
run_canvas_hotkey(
pp::app::CanvasHotkeyEvent::key_up,
ke->m_key,
m_mouse_focus);
for (auto& mode : *m_canvas->m_mode)
mode->on_KeyEvent(ke);
break;
@@ -755,8 +836,11 @@ kEventResult NodeCanvas::handle_event(Event* e)
mode->on_GestureEvent(ge);
break;
case kEventType::TouchTap:
if (te->m_finger_count == 2)
run_history_undo_if_available();
run_canvas_hotkey(
pp::app::CanvasHotkeyEvent::touch_tap,
kKey::Unknown,
m_mouse_focus,
te->m_finger_count);
break;
default:
return kEventResult::Available;