382 lines
12 KiB
C++
382 lines
12 KiB
C++
#include "pch.h"
|
|
|
|
#include "legacy_canvas_tool_services.h"
|
|
|
|
#include "app.h"
|
|
#include "legacy_history_services.h"
|
|
#include "legacy_ui_overlay_services.h"
|
|
#include "node_canvas.h"
|
|
|
|
namespace pp::panopainter {
|
|
namespace {
|
|
|
|
void set_canvas_tool_button_active(Node* button, bool active)
|
|
{
|
|
if (auto* custom = dynamic_cast<NodeButtonCustom*>(button)) {
|
|
custom->set_active(active);
|
|
return;
|
|
}
|
|
if (auto* regular = dynamic_cast<NodeButton*>(button)) {
|
|
regular->set_active(active);
|
|
}
|
|
}
|
|
|
|
void select_canvas_tool_button(Node* main, Node* button)
|
|
{
|
|
main->find<NodeButtonCustom>("btn-pen")->set_active(false);
|
|
main->find<NodeButtonCustom>("btn-erase")->set_active(false);
|
|
main->find<NodeButtonCustom>("btn-line")->set_active(false);
|
|
main->find<NodeButton>("btn-cam")->set_active(false);
|
|
main->find<NodeButton>("btn-grid")->set_active(false);
|
|
main->find<NodeButton>("btn-copy")->set_active(false);
|
|
main->find<NodeButton>("btn-cut")->set_active(false);
|
|
main->find<NodeButtonCustom>("btn-mask-free")->set_active(false);
|
|
main->find<NodeButtonCustom>("btn-mask-line")->set_active(false);
|
|
main->find<NodeButtonCustom>("btn-bucket")->set_active(false);
|
|
set_canvas_tool_button_active(button, 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;
|
|
}
|
|
|
|
class LegacyCanvasToolServices final : public pp::app::CanvasToolServices {
|
|
public:
|
|
LegacyCanvasToolServices(App* app, Node* toolbar_button = nullptr) noexcept
|
|
: app_(app)
|
|
, toolbar_button_(toolbar_button)
|
|
{
|
|
}
|
|
|
|
void select_toolbar_button(pp::app::CanvasToolMode) override
|
|
{
|
|
if (app_ && toolbar_button_)
|
|
select_canvas_tool_button(app_->layout[app_->main_id], toolbar_button_);
|
|
}
|
|
|
|
void set_transform_action(pp::app::CanvasToolTransformAction action) override
|
|
{
|
|
if (!app_ || !app_->canvas || !app_->canvas->m_canvas)
|
|
return;
|
|
|
|
if (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 (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;
|
|
}
|
|
}
|
|
|
|
void set_canvas_mode(pp::app::CanvasToolMode mode) override
|
|
{
|
|
Canvas::set_mode(canvas_mode_from_tool(mode));
|
|
}
|
|
|
|
void toggle_picking() override
|
|
{
|
|
if (!app_ || !app_->canvas || !app_->canvas->m_canvas)
|
|
return;
|
|
|
|
auto* mode = static_cast<CanvasModePen*>(
|
|
app_->canvas->m_canvas->modes[(int)kCanvasMode::Draw][0]);
|
|
if (mode)
|
|
mode->m_picking = !mode->m_picking;
|
|
}
|
|
|
|
void toggle_touch_lock() override
|
|
{
|
|
if (!app_ || !app_->canvas || !app_->canvas->m_canvas)
|
|
return;
|
|
|
|
app_->canvas->m_canvas->m_touch_lock = !app_->canvas->m_canvas->m_touch_lock;
|
|
}
|
|
|
|
private:
|
|
App* app_ = nullptr;
|
|
Node* toolbar_button_ = nullptr;
|
|
};
|
|
|
|
class LegacyCanvasInputToolServices final : public pp::app::CanvasToolServices {
|
|
public:
|
|
void select_toolbar_button(pp::app::CanvasToolMode) override
|
|
{
|
|
}
|
|
|
|
void set_transform_action(pp::app::CanvasToolTransformAction) override
|
|
{
|
|
}
|
|
|
|
void set_canvas_mode(pp::app::CanvasToolMode mode) override
|
|
{
|
|
switch (mode) {
|
|
case pp::app::CanvasToolMode::draw:
|
|
Canvas::set_mode(kCanvasMode::Draw);
|
|
return;
|
|
case pp::app::CanvasToolMode::erase:
|
|
Canvas::set_mode(kCanvasMode::Erase);
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void toggle_picking() override
|
|
{
|
|
}
|
|
|
|
void toggle_touch_lock() override
|
|
{
|
|
}
|
|
};
|
|
|
|
class LegacyCanvasHotkeyServices final : public pp::app::CanvasHotkeyServices {
|
|
public:
|
|
pp::foundation::Status execute_tool(const pp::app::CanvasToolPlan& plan) override
|
|
{
|
|
return execute_legacy_canvas_input_tool_plan(plan);
|
|
}
|
|
|
|
pp::foundation::Status execute_history(const pp::app::HistoryUiPlan& plan) override
|
|
{
|
|
return execute_legacy_history_plan(plan);
|
|
}
|
|
|
|
void save_document(pp::app::DocumentSaveIntent intent) override
|
|
{
|
|
if (App::I)
|
|
App::I->save_document(intent);
|
|
}
|
|
|
|
void toggle_ui() override
|
|
{
|
|
if (App::I)
|
|
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
|
|
{
|
|
if (App::I)
|
|
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;
|
|
const auto history = pp::panopainter::legacy_history_snapshot();
|
|
state.undo_count = history.undo_count;
|
|
state.redo_count = history.redo_count;
|
|
state.touch_finger_count = touch_finger_count;
|
|
return state;
|
|
}
|
|
|
|
void execute_canvas_hotkey_plan(const pp::app::CanvasHotkeyPlan& plan)
|
|
{
|
|
const auto status = pp::panopainter::execute_legacy_canvas_hotkey_plan(plan);
|
|
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);
|
|
const auto status = pp::panopainter::execute_legacy_canvas_input_tool_plan(plan);
|
|
if (!status.ok())
|
|
LOG("Canvas input tool action failed: %s", status.message);
|
|
}
|
|
|
|
[[nodiscard]] kEventResult execute_node_canvas_handle_event(NodeCanvas& node_canvas, Event* e)
|
|
{
|
|
static bool stylus_eraser = false;
|
|
MouseEvent* me = static_cast<MouseEvent*>(e);
|
|
KeyEvent* ke = static_cast<KeyEvent*>(e);
|
|
GestureEvent* ge = static_cast<GestureEvent*>(e);
|
|
TouchEvent* te = static_cast<TouchEvent*>(e);
|
|
auto loc = (me->m_pos - node_canvas.m_pos) * node_canvas.root()->m_zoom;
|
|
|
|
switch (e->m_type)
|
|
{
|
|
case kEventType::MouseMove:
|
|
if (stylus_eraser != me->m_eraser)
|
|
{
|
|
run_canvas_tool_mode(me->m_eraser ?
|
|
pp::app::CanvasToolMode::erase :
|
|
pp::app::CanvasToolMode::draw);
|
|
stylus_eraser = me->m_eraser;
|
|
}
|
|
case kEventType::MouseScroll:
|
|
case kEventType::MouseDownL:
|
|
case kEventType::MouseUpL:
|
|
case kEventType::MouseDownR:
|
|
case kEventType::MouseUpR:
|
|
case kEventType::MouseCancel:
|
|
node_canvas.m_canvas->m_cur_pos = loc;
|
|
node_canvas.update_cursor();
|
|
for (auto& mode : *node_canvas.m_canvas->m_mode)
|
|
mode->on_MouseEvent(me, loc);
|
|
break;
|
|
case kEventType::MouseUnfocus:
|
|
(*node_canvas.m_canvas->m_mode)[0]->m_draw_tip = false;
|
|
App::I->show_cursor();
|
|
break;
|
|
case kEventType::MouseFocus:
|
|
node_canvas.update_cursor();
|
|
break;
|
|
case kEventType::KeyDown:
|
|
run_canvas_hotkey(
|
|
pp::app::CanvasHotkeyEvent::key_down,
|
|
ke->m_key,
|
|
node_canvas.m_mouse_focus);
|
|
for (auto& mode : *node_canvas.m_canvas->m_mode)
|
|
mode->on_KeyEvent(ke);
|
|
break;
|
|
case kEventType::KeyUp:
|
|
node_canvas.update_cursor();
|
|
run_canvas_hotkey(
|
|
pp::app::CanvasHotkeyEvent::key_up,
|
|
ke->m_key,
|
|
node_canvas.m_mouse_focus);
|
|
for (auto& mode : *node_canvas.m_canvas->m_mode)
|
|
mode->on_KeyEvent(ke);
|
|
break;
|
|
case kEventType::GestureStart:
|
|
node_canvas.mouse_capture();
|
|
for (auto& mode : *node_canvas.m_canvas->m_mode)
|
|
mode->on_GestureEvent(ge);
|
|
break;
|
|
case kEventType::GestureMove:
|
|
for (auto& mode : *node_canvas.m_canvas->m_mode)
|
|
mode->on_GestureEvent(ge);
|
|
break;
|
|
case kEventType::GestureEnd:
|
|
pp::panopainter::release_legacy_mouse_capture(node_canvas);
|
|
for (auto& mode : *node_canvas.m_canvas->m_mode)
|
|
mode->on_GestureEvent(ge);
|
|
break;
|
|
case kEventType::TouchTap:
|
|
run_canvas_hotkey(
|
|
pp::app::CanvasHotkeyEvent::touch_tap,
|
|
kKey::Unknown,
|
|
node_canvas.m_mouse_focus,
|
|
te->m_finger_count);
|
|
break;
|
|
default:
|
|
return kEventResult::Available;
|
|
break;
|
|
}
|
|
return kEventResult::Consumed;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
pp::foundation::Status execute_legacy_canvas_tool_plan(
|
|
App& app,
|
|
const pp::app::CanvasToolPlan& plan,
|
|
Node* toolbar_button)
|
|
{
|
|
LegacyCanvasToolServices services(&app, toolbar_button);
|
|
return pp::app::execute_canvas_tool_plan(plan, services);
|
|
}
|
|
|
|
pp::foundation::Status execute_legacy_canvas_input_tool_plan(
|
|
const pp::app::CanvasToolPlan& plan)
|
|
{
|
|
LegacyCanvasInputToolServices services;
|
|
return pp::app::execute_canvas_tool_plan(plan, services);
|
|
}
|
|
|
|
pp::foundation::Status execute_legacy_canvas_hotkey_plan(
|
|
const pp::app::CanvasHotkeyPlan& plan)
|
|
{
|
|
LegacyCanvasHotkeyServices services;
|
|
return pp::app::execute_canvas_hotkey_plan(plan, services);
|
|
}
|
|
|
|
kEventResult handle_legacy_node_canvas_event(NodeCanvas& node_canvas, Event* e)
|
|
{
|
|
return execute_node_canvas_handle_event(node_canvas, e);
|
|
}
|
|
|
|
} // namespace pp::panopainter
|