Extract menu, stylus, and canvas draw helpers

This commit is contained in:
2026-06-16 11:25:09 +02:00
parent d135835787
commit 18665bdffc
10 changed files with 510 additions and 361 deletions

View File

@@ -33,6 +33,8 @@
namespace pp::panopainter {
void bind_legacy_file_menu(App& app);
void bind_legacy_about_menu(App& app);
void bind_legacy_layer_menu(App& app);
void bind_legacy_tools_menu(App& app);
}
@@ -93,39 +95,6 @@ void close_legacy_overlay_handles_if_open(
}
}
pp::app::DocumentLayerMenuPlan make_layer_menu_plan(
pp::app::DocumentLayerMenuCommand command,
App& app)
{
const bool has_current_layer = app.layers && app.layers->m_current_layer;
const int current_index = app.canvas && app.canvas->m_canvas
? app.canvas->m_canvas->m_current_layer_idx
: 0;
const int animation_duration = Canvas::I
? Canvas::I->anim_duration()
: 0;
const std::string current_name = has_current_layer
? app.layers->m_current_layer->m_label_text
: std::string {};
std::string lower_name;
if (app.canvas && app.canvas->m_canvas && current_index > 0
&& current_index - 1 < static_cast<int>(app.canvas->m_canvas->m_layers.size()))
{
lower_name = app.canvas->m_canvas->m_layers[current_index - 1]->m_name;
}
const auto plan = pp::app::plan_document_layer_menu(
command,
has_current_layer,
current_index,
animation_duration,
current_name,
lower_name);
if (plan)
return plan.value();
return {};
}
[[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept
{
return plan.action == pp::app::ToolsPanelAction::open_floating_panel;
@@ -154,23 +123,11 @@ void execute_main_toolbar_plan(App& app, const pp::app::MainToolbarPlan& plan)
pp::panopainter::execute_legacy_main_toolbar_plan(app, plan);
}
void execute_about_menu_plan(App& app, const pp::app::AboutMenuPlan& plan)
{
pp::panopainter::execute_legacy_about_menu_plan(app, plan);
}
void execute_tools_menu_plan(App& app, const pp::app::ToolsMenuPlan& plan)
{
pp::panopainter::execute_legacy_tools_menu_plan(app, plan);
}
void execute_document_layer_menu_plan(App& app, const pp::app::DocumentLayerMenuPlan& plan)
{
const auto status = pp::panopainter::execute_legacy_document_layer_menu_plan(app, plan);
if (!status.ok())
LOG("Layer menu action failed: %s", status.message);
}
void execute_document_layer_merge_plan(App& app, const pp::app::DocumentLayerMergePlan& plan)
{
const auto status = pp::panopainter::execute_legacy_document_layer_merge_plan(app, plan);
@@ -764,113 +721,7 @@ void App::init_menu_tools()
void App::init_menu_about()
{
if (auto* menu_file = layout[main_id]->find<NodeButtonCustom>("menu-about"))
{
menu_file->on_click = [=](Node*) {
auto* popup_root = layout[main_id];
if (!popup_root) {
return;
}
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
auto popup = add_menu_popup(*this, "about-menu", pos, menu_file->m_size.x);
if (!popup)
return;
pp::panopainter::detach_legacy_node_from_parent(*popup);
auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, popup);
if (!popup_overlay) {
pp::panopainter::destroy_legacy_node(*popup);
return;
}
auto popup_handle = popup_overlay.value();
popup->find<NodeButtonCustom>("about-app")->on_click = [this, popup_root, popup_handle](Node*) {
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::about_app,
g_version_major,
g_version_minor,
g_version_fix);
execute_about_menu_plan(*this, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
popup->find<NodeButtonCustom>("about-doc")->on_click = [this, popup_root, popup_handle](Node*) {
// auto path = Asset::absolute("data/doc/test.pdf");
// display_file(path);
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::help_guide,
g_version_major,
g_version_minor,
g_version_fix);
execute_about_menu_plan(*this, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
if (auto item = popup->find<NodeButtonCustom>("about-news"))
{
if (auto text = item->find<NodeText>("menu-label"))
{
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::whats_new,
g_version_major,
g_version_minor,
g_version_fix);
text->set_text(plan.label.c_str());
}
item->on_click = [this, popup_root, popup_handle](Node*) {
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::whats_new,
g_version_major,
g_version_minor,
g_version_fix);
execute_about_menu_plan(*this, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
}
if (auto b = popup->find<NodeButtonCustom>("about-crash"))
{
b->on_click = [this, popup_root, popup_handle](Node*) {
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::induce_crash,
g_version_major,
g_version_minor,
g_version_fix);
execute_about_menu_plan(*this, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
}
if (auto b = popup->find<NodeButtonCustom>("about-perf"))
{
b->on_click = [this, popup_root, popup_handle](Node*) {
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::performance_test,
g_version_major,
g_version_minor,
g_version_fix,
true,
Canvas::I != nullptr);
execute_about_menu_plan(*this, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
}
};
}
pp::panopainter::bind_legacy_about_menu(*this);
}
void App::brush_update(bool update_color, bool update_brush)
@@ -933,63 +784,7 @@ void App::brush_update(bool update_color, bool update_brush)
void App::init_menu_layer()
{
if (auto* menu_file = layout[main_id]->find<NodeButtonCustom>("menu-layers"))
{
menu_file->on_click = [=](Node*) {
auto* popup_root = layout[main_id];
if (!popup_root) {
return;
}
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
auto popup = add_menu_popup(*this, "layers-menu", pos, menu_file->m_size.x);
if (!popup)
return;
pp::panopainter::detach_legacy_node_from_parent(*popup);
auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, popup);
if (!popup_overlay) {
pp::panopainter::destroy_legacy_node(*popup);
return;
}
auto popup_handle = popup_overlay.value();
popup->find<NodeButtonCustom>("layer-clear")->on_click = [this, popup_root, popup_handle](Node*) {
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::clear, *this);
execute_document_layer_menu_plan(*this, plan);
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
};
{
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::clear, *this);
popup->find<NodeButtonCustom>("layer-clear")->
find<NodeText>("menu-label")->
set_text(plan.label.c_str());
}
popup->find<NodeButtonCustom>("layer-rename")->on_click = [this, popup_root, popup_handle](Node*) {
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::rename, *this);
execute_document_layer_menu_plan(*this, plan);
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
};
{
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::rename, *this);
popup->find<NodeButtonCustom>("layer-rename")->
find<NodeText>("menu-label")->
set_text(plan.label.c_str());
}
popup->find<NodeButtonCustom>("layer-merge")->on_click = [this, popup_root, popup_handle](Node*) {
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::merge_down, *this);
execute_document_layer_menu_plan(*this, plan);
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
};
{
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::merge_down, *this);
popup->find<NodeButtonCustom>("layer-merge")->
find<NodeText>("menu-label")->
set_text(plan.label.c_str());
}
};
}
pp::panopainter::bind_legacy_layer_menu(*this);
}
void App::initLayout()

View File

@@ -0,0 +1,264 @@
#include "pch.h"
#include "app.h"
#include "app_core/about_menu.h"
#include "app_core/document_layer.h"
#include "legacy_app_shell_services.h"
#include "legacy_document_layer_services.h"
#include "legacy_ui_overlay_services.h"
#include "node_button_custom.h"
#include "node_popup_menu.h"
#include "node_text.h"
namespace {
std::shared_ptr<NodePopupMenu> add_menu_popup(
App& app,
const char* template_id,
glm::vec2 position,
float rtl_anchor_width)
{
const auto popup = pp::panopainter::add_legacy_popup_menu(
app,
template_id,
position.x,
position.y,
rtl_anchor_width);
if (!popup) {
LOG("Popup menu '%s' failed: %s", template_id ? template_id : "<null>", popup.status().message);
return nullptr;
}
return popup.value();
}
void close_legacy_overlay_handle_ignoring_status(
Node& anchor,
pp::ui::NodeHandle overlay) noexcept
{
(void)pp::panopainter::close_legacy_overlay_node(anchor, overlay);
}
pp::app::DocumentLayerMenuPlan make_layer_menu_plan(
pp::app::DocumentLayerMenuCommand command,
App& app)
{
const bool has_current_layer = app.layers && app.layers->m_current_layer;
const int current_index = app.canvas && app.canvas->m_canvas
? app.canvas->m_canvas->m_current_layer_idx
: 0;
const int animation_duration = Canvas::I
? Canvas::I->anim_duration()
: 0;
const std::string current_name = has_current_layer
? app.layers->m_current_layer->m_label_text
: std::string {};
std::string lower_name;
if (app.canvas && app.canvas->m_canvas && current_index > 0
&& current_index - 1 < static_cast<int>(app.canvas->m_canvas->m_layers.size()))
{
lower_name = app.canvas->m_canvas->m_layers[current_index - 1]->m_name;
}
const auto plan = pp::app::plan_document_layer_menu(
command,
has_current_layer,
current_index,
animation_duration,
current_name,
lower_name);
if (plan)
return plan.value();
return {};
}
void execute_about_menu_plan(App& app, const pp::app::AboutMenuPlan& plan)
{
pp::panopainter::execute_legacy_about_menu_plan(app, plan);
}
void execute_document_layer_menu_plan(App& app, const pp::app::DocumentLayerMenuPlan& plan)
{
const auto status = pp::panopainter::execute_legacy_document_layer_menu_plan(app, plan);
if (!status.ok())
LOG("Layer menu action failed: %s", status.message);
}
} // namespace
namespace pp::panopainter {
void bind_legacy_about_menu(App& app)
{
auto main = app.layout[app.main_id];
if (auto* menu_file = main->find<NodeButtonCustom>("menu-about"))
{
menu_file->on_click = [&app, menu_file](Node*) {
auto* popup_root = app.layout[app.main_id];
if (!popup_root) {
return;
}
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
auto popup = add_menu_popup(app, "about-menu", pos, menu_file->m_size.x);
if (!popup)
return;
pp::panopainter::detach_legacy_node_from_parent(*popup);
auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, popup);
if (!popup_overlay) {
pp::panopainter::destroy_legacy_node(*popup);
return;
}
auto popup_handle = popup_overlay.value();
popup->find<NodeButtonCustom>("about-app")->on_click = [&app, popup_root, popup_handle](Node*) {
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::about_app,
g_version_major,
g_version_minor,
g_version_fix);
execute_about_menu_plan(app, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
popup->find<NodeButtonCustom>("about-doc")->on_click = [&app, popup_root, popup_handle](Node*) {
// auto path = Asset::absolute("data/doc/test.pdf");
// display_file(path);
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::help_guide,
g_version_major,
g_version_minor,
g_version_fix);
execute_about_menu_plan(app, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
if (auto item = popup->find<NodeButtonCustom>("about-news"))
{
if (auto text = item->find<NodeText>("menu-label"))
{
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::whats_new,
g_version_major,
g_version_minor,
g_version_fix);
text->set_text(plan.label.c_str());
}
item->on_click = [&app, popup_root, popup_handle](Node*) {
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::whats_new,
g_version_major,
g_version_minor,
g_version_fix);
execute_about_menu_plan(app, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
}
if (auto b = popup->find<NodeButtonCustom>("about-crash"))
{
b->on_click = [&app, popup_root, popup_handle](Node*) {
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::induce_crash,
g_version_major,
g_version_minor,
g_version_fix);
execute_about_menu_plan(app, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
}
if (auto b = popup->find<NodeButtonCustom>("about-perf"))
{
b->on_click = [&app, popup_root, popup_handle](Node*) {
const auto plan = pp::app::plan_about_menu_command(
pp::app::AboutMenuCommand::performance_test,
g_version_major,
g_version_minor,
g_version_fix,
true,
Canvas::I != nullptr);
execute_about_menu_plan(app, plan);
if (plan.closes_root_popup)
{
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
}
};
}
};
}
}
void bind_legacy_layer_menu(App& app)
{
auto main = app.layout[app.main_id];
if (auto* menu_file = main->find<NodeButtonCustom>("menu-layers"))
{
menu_file->on_click = [&app, menu_file](Node*) {
auto* popup_root = app.layout[app.main_id];
if (!popup_root) {
return;
}
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
auto popup = add_menu_popup(app, "layers-menu", pos, menu_file->m_size.x);
if (!popup)
return;
pp::panopainter::detach_legacy_node_from_parent(*popup);
auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, popup);
if (!popup_overlay) {
pp::panopainter::destroy_legacy_node(*popup);
return;
}
auto popup_handle = popup_overlay.value();
popup->find<NodeButtonCustom>("layer-clear")->on_click = [&app, popup_root, popup_handle](Node*) {
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::clear, app);
execute_document_layer_menu_plan(app, plan);
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
};
{
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::clear, app);
popup->find<NodeButtonCustom>("layer-clear")->
find<NodeText>("menu-label")->
set_text(plan.label.c_str());
}
popup->find<NodeButtonCustom>("layer-rename")->on_click = [&app, popup_root, popup_handle](Node*) {
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::rename, app);
execute_document_layer_menu_plan(app, plan);
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
};
{
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::rename, app);
popup->find<NodeButtonCustom>("layer-rename")->
find<NodeText>("menu-label")->
set_text(plan.label.c_str());
}
popup->find<NodeButtonCustom>("layer-merge")->on_click = [&app, popup_root, popup_handle](Node*) {
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::merge_down, app);
execute_document_layer_menu_plan(app, plan);
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
};
{
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::merge_down, app);
popup->find<NodeButtonCustom>("layer-merge")->
find<NodeText>("menu-label")->
set_text(plan.label.c_str());
}
};
}
}
} // namespace pp::panopainter

View File

@@ -130,6 +130,14 @@ struct LegacyCanvasDrawMergeLayerPathExecution {
std::function<void(int, float)> draw_frame;
};
struct LegacyCanvasDrawLayerVisit {
size_t layer_index = 0;
int plane_index = 0;
int z = 0;
int first_frame = 0;
int last_frame = 0;
};
struct LegacyCanvasDrawMergeTemporaryCompositeExecution {
std::function<void()> setup;
std::function<void()> bind_samplers;
@@ -671,6 +679,39 @@ inline void execute_legacy_canvas_draw_merge_layer_path(
execution.draw_debug_outline();
}
template <typename PlanOnionRange, typename ShouldDrawPlane, typename VisitLayerPlane, typename LogOnionRangeFailure>
inline void execute_legacy_canvas_draw_layer_traversal(
size_t layer_count,
PlanOnionRange&& plan_onion_range,
ShouldDrawPlane&& should_draw_plane,
VisitLayerPlane&& visit_layer_plane,
LogOnionRangeFailure&& log_onion_range_failure)
{
for (size_t i = 0; i < layer_count; ++i) {
const auto layer_index = i;
const auto onion_range_result = plan_onion_range(layer_index);
if (!onion_range_result) {
log_onion_range_failure(onion_range_result.status().message);
continue;
}
const auto onion_range = onion_range_result.value();
for (int plane_index = 0; plane_index < 6; ++plane_index) {
if (!should_draw_plane(layer_index, plane_index, onion_range.first_frame, onion_range.last_frame)) {
continue;
}
visit_layer_plane(LegacyCanvasDrawLayerVisit {
.layer_index = layer_index,
.plane_index = plane_index,
.z = static_cast<int>(layer_count - i),
.first_frame = onion_range.first_frame,
.last_frame = onion_range.last_frame,
}, onion_range);
}
}
}
inline void execute_legacy_canvas_draw_merge_temporary_composite(
const LegacyCanvasDrawMergeTemporaryCompositeExecution& execution)
{

View File

@@ -13,6 +13,7 @@
#include "renderer_gl/opengl_capabilities.h"
#include "platform_windows/windows_platform_services.h"
#include "platform_windows/windows_splash.h"
#include "platform_windows/windows_stylus_input.h"
#include "../resource.h"
#include <shellscalingapi.h>
@@ -55,9 +56,6 @@ struct RetainedState
std::map<kKey, int> vkey_map;
wchar_t window_title[512]{};
std::jthread hmd_renderer;
float timer_stylus = 0;
float timer_ink_touch = 0;
float timer_ink_pen = 0;
bool sandboxed = false;
std::mutex hmd_render_mutex;
std::condition_variable hmd_render_cv;
@@ -176,25 +174,6 @@ void init_shcore_API()
SetProcessDpiAwareness_fn = (decltype(SetProcessDpiAwareness_fn))GetProcAddress(dll, "SetProcessDpiAwareness");
}
BOOL(*GetPointerInfo_fn)(UINT32 pointerId, POINTER_INFO* pointerInfo);
BOOL(*GetPointerType_fn)(UINT32 pointerId, POINTER_INPUT_TYPE* pointerType);
BOOL(*GetPointerTouchInfo_fn)(UINT32 pointerId, POINTER_TOUCH_INFO* touchInfo);
BOOL(*GetPointerPenInfo_fn)(UINT32 pointerId, POINTER_PEN_INFO* penInfo);
void init_ink_API()
{
HMODULE dll = LoadLibrary(L"User32.dll");
if (!dll)
{
LOG("cannot load User32.dll");
return;
}
LOG("loaded User32.dll");
GetPointerInfo_fn = (decltype(GetPointerInfo_fn))GetProcAddress(dll, "GetPointerInfo");
GetPointerType_fn = (decltype(GetPointerType_fn))GetProcAddress(dll, "GetPointerType");
GetPointerTouchInfo_fn = (decltype(GetPointerTouchInfo_fn))GetProcAddress(dll, "GetPointerTouchInfo");
GetPointerPenInfo_fn = (decltype(GetPointerPenInfo_fn))GetProcAddress(dll, "GetPointerPenInfo");
}
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
std::string GetLastErrorAsString()
{
@@ -245,27 +224,7 @@ void async_unlock()
void win32_update_stylus(float dt)
{
auto& state = retained_state();
state.timer_stylus += dt;
state.timer_ink_touch += dt;
state.timer_ink_pen += dt;
if (state.timer_stylus > 0.1 && (WacomTablet::I.m_stylus || WacomTablet::I.m_eraser))
{
WacomTablet::I.m_stylus = false;
WacomTablet::I.m_eraser = false;
App::I->redraw = true;
}
if (state.timer_ink_pen > 0.1 && WacomTablet::I.m_ink_pen)
{
WacomTablet::I.m_ink_pen = false;
App::I->redraw = true;
}
if (state.timer_ink_touch > 0.1 && WacomTablet::I.m_ink_touch)
{
WacomTablet::I.m_ink_touch = false;
App::I->redraw = true;
}
pp::platform::windows::update_stylus_state(dt);
}
void win32_update_fps(int frames)
@@ -710,7 +669,7 @@ int main(int argc, char** argv)
App::I->initLog();
init_shcore_API();
init_ink_API();
pp::platform::windows::initialize_stylus_input();
if(SetProcessDpiAwareness_fn)
SetProcessDpiAwareness_fn(PROCESS_PER_MONITOR_DPI_AWARE);
@@ -1064,8 +1023,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
// }
case WT_PACKET:
{
App::I->set_stylus();
state.timer_stylus = 0;
pp::platform::windows::note_wintab_packet();
App::I->ui_task_async([=] {
WacomTablet::I.handle_message(hWnd, msg, wp, lp);
});
@@ -1229,79 +1187,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
}
case WM_POINTERUPDATE:
{
POINTER_TOUCH_INFO touchInfo;
POINTER_PEN_INFO penInfo;
POINTER_INFO pointerInfo;
UINT32 pointerId = GET_POINTERID_WPARAM(wp);
POINTER_INPUT_TYPE pointerType = PT_POINTER;
if(!GetPointerInfo_fn)
break;
// Retrieve common pointer information
if (!GetPointerInfo_fn(pointerId, &pointerInfo))
{
// failure, call GetLastError()
}
else
{
// success, process pointerInfo
if (!GetPointerType_fn(pointerId, &pointerType))
{
// failure, call GetLastError()
// set PT_POINTER to fall to default case below
pointerType = PT_POINTER;
}
switch (pointerType)
{
case PT_TOUCH:
// Retrieve touch information
if (!GetPointerTouchInfo_fn(pointerId, &touchInfo))
{
// failure, call GetLastError()
}
else
{
// success, process touchInfo
// mark as handled to skip call to DefWindowProc
//fHandled = TRUE;
state.timer_ink_touch = 0;
WacomTablet::I.m_ink_touch = true;
WacomTablet::I.m_pen_pres = 1;
}
break;
case PT_PEN:
// Retrieve pen information
if (!GetPointerPenInfo_fn(pointerId, &penInfo))
{
// failure, call GetLastError()
}
else
{
// success, process penInfo
// mark as handled to skip call to DefWindowProc
//fHandled = TRUE;
//penInfo.pressure
state.timer_ink_pen = 0;
WacomTablet::I.m_ink_pen = true;
WacomTablet::I.m_pen_pres = (float)penInfo.pressure / 1024.f;
App::I->set_stylus();
}
break;
default:
if (!GetPointerInfo_fn(pointerId, &pointerInfo))
{
// failure.
}
else
{
// success, proceed with pointerInfo.
//fHandled = HandleGenericPointerInfo(&pointerInfo);
}
break;
}
}
pp::platform::windows::handle_pointer_update_message(wp);
break;
}
}

View File

@@ -439,34 +439,33 @@ void NodeCanvas::draw()
apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false);
const auto& b = m_canvas->m_current_stroke->m_brush;
for (size_t i = 0; i < m_canvas->m_layers.size(); i++)
{
auto layer_index = i;
for (int plane_index = 0; plane_index < 6; plane_index++)
{
const auto onion_range_result = pp::app::plan_animation_onion_frame_range(
pp::panopainter::execute_legacy_canvas_draw_layer_traversal(
m_canvas->m_layers.size(),
[&](size_t layer_index) {
return pp::app::plan_animation_onion_frame_range(
m_canvas->m_layers[layer_index]->frames_count(),
m_canvas->m_layers[layer_index]->m_frame_index,
App::I->animation->get_onion_size());
if (!onion_range_result) {
LOG("NodeCanvas onion frame range failed: %s", onion_range_result.status().message);
continue;
}
const auto onion_range = onion_range_result.value();
},
[&](size_t layer_index, int plane_index, int first_frame, int last_frame) {
bool faces = false;
for (int frame = onion_range.first_frame; frame <= onion_range.last_frame; frame++)
for (int frame = first_frame; frame <= last_frame; ++frame)
faces |= m_canvas->m_layers[layer_index]->face(plane_index, frame);
if (!(m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) &&
(!m_canvas->m_layers[layer_index]->m_visible ||
m_canvas->m_layers[layer_index]->m_opacity == .0f || !faces))
continue;
int z = (int)(m_canvas->m_layers.size() - i);
auto plane_mvp_z = proj * camera *
glm::scale(glm::vec3(z + 1)) *
if (m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)
return true;
return m_canvas->m_layers[layer_index]->m_visible &&
m_canvas->m_layers[layer_index]->m_opacity != .0f &&
faces;
},
[&](const pp::panopainter::LegacyCanvasDrawLayerVisit& visit, const auto& onion_range) {
const auto layer_index = visit.layer_index;
const auto plane_index = visit.plane_index;
const auto plane_mvp_z = proj * camera *
glm::scale(glm::vec3(visit.z + 1)) *
glm::eulerAngleYXZ(yaw, pitch, roll) *
m_canvas->m_plane_transform[plane_index] *
m_canvas->m_plane_transform[plane_index] *
glm::translate(glm::vec3(0, 0, -1));
const auto draw_layer_frame = pp::panopainter::make_legacy_canvas_draw_merge_layer_frame_draw(
@@ -480,8 +479,8 @@ void NodeCanvas::draw()
m_canvas->m_current_stroke && m_canvas->m_current_mode == kCanvasMode::Erase && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index,
m_canvas->m_current_stroke && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index,
use_blend,
onion_range.first_frame,
onion_range.last_frame,
visit.first_frame,
visit.last_frame,
[&](int frame) {
return pp::app::animation_onion_frame_alpha(onion_range, frame);
},
@@ -649,9 +648,10 @@ void NodeCanvas::draw()
#endif
.draw_frame = draw_layer_frame,
});
}
}
},
[&](const char* message) {
LOG("NodeCanvas onion frame range failed: %s", message);
});
if (use_blend)
{
m_cache_rtt.unbindFramebuffer();

View File

@@ -0,0 +1,129 @@
#include "pch.h"
#include "platform_windows/windows_stylus_input.h"
#include "app.h"
#include "log.h"
#include "wacom.h"
namespace pp::platform::windows {
namespace {
struct StylusInputState final
{
float timer_stylus = 0.0f;
float timer_ink_touch = 0.0f;
float timer_ink_pen = 0.0f;
BOOL (*get_pointer_info)(UINT32, POINTER_INFO*) = nullptr;
BOOL (*get_pointer_type)(UINT32, POINTER_INPUT_TYPE*) = nullptr;
BOOL (*get_pointer_touch_info)(UINT32, POINTER_TOUCH_INFO*) = nullptr;
BOOL (*get_pointer_pen_info)(UINT32, POINTER_PEN_INFO*) = nullptr;
};
StylusInputState& stylus_input_state()
{
static StylusInputState state;
return state;
}
}
void initialize_stylus_input()
{
auto& state = stylus_input_state();
HMODULE dll = LoadLibrary(L"User32.dll");
if (!dll)
{
LOG("cannot load User32.dll");
return;
}
LOG("loaded User32.dll");
state.get_pointer_info =
reinterpret_cast<decltype(state.get_pointer_info)>(GetProcAddress(dll, "GetPointerInfo"));
state.get_pointer_type =
reinterpret_cast<decltype(state.get_pointer_type)>(GetProcAddress(dll, "GetPointerType"));
state.get_pointer_touch_info =
reinterpret_cast<decltype(state.get_pointer_touch_info)>(GetProcAddress(dll, "GetPointerTouchInfo"));
state.get_pointer_pen_info =
reinterpret_cast<decltype(state.get_pointer_pen_info)>(GetProcAddress(dll, "GetPointerPenInfo"));
}
void update_stylus_state(float dt)
{
auto& state = stylus_input_state();
state.timer_stylus += dt;
state.timer_ink_touch += dt;
state.timer_ink_pen += dt;
if (state.timer_stylus > 0.1f && (WacomTablet::I.m_stylus || WacomTablet::I.m_eraser))
{
WacomTablet::I.m_stylus = false;
WacomTablet::I.m_eraser = false;
App::I->redraw = true;
}
if (state.timer_ink_pen > 0.1f && WacomTablet::I.m_ink_pen)
{
WacomTablet::I.m_ink_pen = false;
App::I->redraw = true;
}
if (state.timer_ink_touch > 0.1f && WacomTablet::I.m_ink_touch)
{
WacomTablet::I.m_ink_touch = false;
App::I->redraw = true;
}
}
void note_wintab_packet()
{
auto& state = stylus_input_state();
App::I->set_stylus();
state.timer_stylus = 0.0f;
}
void handle_pointer_update_message(WPARAM wp)
{
auto& state = stylus_input_state();
if (!state.get_pointer_info)
return;
POINTER_TOUCH_INFO touch_info {};
POINTER_PEN_INFO pen_info {};
POINTER_INFO pointer_info {};
const UINT32 pointer_id = GET_POINTERID_WPARAM(wp);
POINTER_INPUT_TYPE pointer_type = PT_POINTER;
if (!state.get_pointer_info(pointer_id, &pointer_info))
return;
if (!state.get_pointer_type(pointer_id, &pointer_type))
pointer_type = PT_POINTER;
switch (pointer_type)
{
case PT_TOUCH:
if (!state.get_pointer_touch_info(pointer_id, &touch_info))
return;
state.timer_ink_touch = 0.0f;
WacomTablet::I.m_ink_touch = true;
WacomTablet::I.m_pen_pres = 1.0f;
return;
case PT_PEN:
if (!state.get_pointer_pen_info(pointer_id, &pen_info))
return;
state.timer_ink_pen = 0.0f;
WacomTablet::I.m_ink_pen = true;
WacomTablet::I.m_pen_pres = static_cast<float>(pen_info.pressure) / 1024.0f;
App::I->set_stylus();
return;
default:
return;
}
}
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <windows.h>
namespace pp::platform::windows {
void initialize_stylus_input();
void update_stylus_state(float dt);
void note_wintab_packet();
void handle_pointer_update_message(WPARAM wp);
}