Route app input dispatch through app core
This commit is contained in:
@@ -241,6 +241,7 @@ target_link_libraries(pp_platform_api
|
||||
add_library(pp_app_core STATIC
|
||||
src/app_core/about_menu.h
|
||||
src/app_core/app_frame.h
|
||||
src/app_core/app_input.h
|
||||
src/app_core/app_preferences.h
|
||||
src/app_core/app_shutdown.h
|
||||
src/app_core/app_status.h
|
||||
|
||||
@@ -840,6 +840,10 @@ Known local toolchain state:
|
||||
visibility, main UI suppression in VR-only mode, tick layout selection,
|
||||
resize render-target/redraw projection, invalid resize rejection, and redraw
|
||||
reset planning.
|
||||
- `pp_app_core_app_input_tests` covers pointer coordinate normalization,
|
||||
invalid pointer/gesture inputs, designer-first mouse routing, mouse-cancel
|
||||
routing, gesture midpoint/distance/delta math, main-layout routing, key state
|
||||
mutation intent, and VR spacebar camera-sync intent.
|
||||
- `pp_app_core_app_shutdown_tests` covers legacy shutdown cleanup staging for
|
||||
UI-state save, stroke-preview renderer shutdown, recording stop,
|
||||
texture/shader invalidation, layout unload, render-target/mesh destruction,
|
||||
|
||||
@@ -98,6 +98,13 @@ agent or engineer to remove them without reconstructing context from chat.
|
||||
`App::create`, `App::tick`, `App::resize`, `App::update`, `App::draw`, and
|
||||
`pano_cli plan-app-frame`; retained layout traversal, toolbar widget writes,
|
||||
render-target recreation, and OpenGL/UI drawing remain in the legacy app.
|
||||
- 2026-06-05: DEBT-0003 was narrowed. Pointer coordinate normalization,
|
||||
mouse designer-first routing, gesture midpoint/delta math, touch/key
|
||||
main-layout routing, and VR spacebar camera-sync intent are now tested
|
||||
`pp_app_core` input plans consumed by `App::mouse_*`, `App::gesture_*`,
|
||||
`App::touch_tap`, `App::key_*`, and `pano_cli plan-app-input`; retained
|
||||
`MouseEvent`/`GestureEvent`/`TouchEvent`/`KeyEvent` construction and legacy
|
||||
`Node` event dispatch remain in the app shell.
|
||||
- 2026-06-05: DEBT-0003 was narrowed again. Shutdown cleanup staging for
|
||||
UI-state save, stroke-preview renderer shutdown, recording stop,
|
||||
texture/shader invalidation, layout unload, UI render-target and face-plane
|
||||
|
||||
@@ -204,6 +204,12 @@ VR UI drawing, main UI drawing, and redraw reset now live in `pp_app_core`;
|
||||
`App::create`, `App::tick`, `App::resize`, `App::update`, `App::draw`, and
|
||||
`pano_cli plan-app-frame` consume those plans while retained layout traversal,
|
||||
render-target recreation, and OpenGL/UI drawing stay in the legacy app.
|
||||
App input dispatch decisions for pointer coordinate normalization, mouse
|
||||
designer-first routing, gesture midpoint/delta math, touch/key main-layout
|
||||
routing, and VR spacebar camera-sync intent now live in `pp_app_core`;
|
||||
`App::mouse_*`, `App::gesture_*`, `App::touch_tap`, `App::key_*`, and
|
||||
`pano_cli plan-app-input` consume those plans while retained event objects and
|
||||
legacy `Node` dispatch stay in the app shell.
|
||||
Shutdown lifecycle staging for UI-state save, stroke-preview renderer shutdown,
|
||||
recording stop, texture/shader invalidation, layout unload, render-target
|
||||
destruction, panel-node release, and quick-mode cleanup now lives in
|
||||
@@ -1667,6 +1673,13 @@ Results:
|
||||
`pano_cli_plan_app_frame_idle_missing_canvas_smoke`, with resize automation
|
||||
covered by `pano_cli_plan_app_frame_resize_smoke` and
|
||||
`pano_cli_plan_app_frame_rejects_bad_resize`.
|
||||
- `PanoPainter`, `pp_app_core_app_input_tests`, and `pano_cli` built after
|
||||
app input routing and normalization moved into `pp_app_core`.
|
||||
- Focused app-input CTest coverage passed for `pp_app_core_app_input_tests`,
|
||||
`pano_cli_plan_app_input_pointer_smoke`,
|
||||
`pano_cli_plan_app_input_gesture_smoke`,
|
||||
`pano_cli_plan_app_input_key_vr_smoke`, and
|
||||
`pano_cli_plan_app_input_rejects_bad_float`.
|
||||
- `PanoPainter`, `pp_app_core_app_shutdown_tests`, and `pano_cli` built after
|
||||
shutdown cleanup staging moved into `pp_app_core`.
|
||||
- Focused shutdown CTest coverage passed for `pp_app_core_app_shutdown_tests`,
|
||||
|
||||
@@ -43,6 +43,7 @@ param(
|
||||
"pp_app_core_about_menu_tests",
|
||||
"pp_app_core_app_preferences_tests",
|
||||
"pp_app_core_app_frame_tests",
|
||||
"pp_app_core_app_input_tests",
|
||||
"pp_app_core_app_shutdown_tests",
|
||||
"pp_app_core_app_startup_tests",
|
||||
"pp_app_core_app_status_tests",
|
||||
|
||||
@@ -3,7 +3,7 @@ set -u
|
||||
|
||||
presets="${1:-android-arm64 android-x64 android-quest-arm64 android-focus-arm64}"
|
||||
shift || true
|
||||
targets="${*:-pp_foundation pp_assets pp_paint pp_document pp_renderer_api pp_renderer_gl pp_paint_renderer pp_ui_core pp_platform_api pp_app_core pano_cli pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_brush_package_tests pp_assets_image_format_tests pp_assets_image_metadata_tests pp_assets_image_pixels_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_paint_stroke_script_tests pp_document_tests pp_document_ppi_import_tests pp_document_ppi_export_tests pp_renderer_api_tests pp_renderer_gl_capabilities_tests pp_renderer_gl_command_plan_tests pp_paint_renderer_compositor_tests pp_platform_api_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pp_app_core_about_menu_tests pp_app_core_app_preferences_tests pp_app_core_app_frame_tests pp_app_core_app_shutdown_tests pp_app_core_app_startup_tests pp_app_core_app_status_tests pp_app_core_command_convert_tests pp_app_core_brush_package_export_tests pp_app_core_brush_package_import_tests pp_app_core_brush_ui_tests pp_app_core_canvas_hotkey_tests pp_app_core_canvas_tool_ui_tests pp_app_core_canvas_view_tests pp_app_core_document_animation_tests pp_app_core_document_canvas_tests pp_app_core_document_cloud_tests pp_app_core_document_export_tests pp_app_core_document_import_tests pp_app_core_document_layer_tests pp_app_core_document_platform_io_tests pp_app_core_document_recording_tests pp_app_core_document_resize_tests pp_app_core_document_route_tests pp_app_core_document_sharing_tests pp_app_core_document_session_tests pp_app_core_file_menu_tests pp_app_core_grid_ui_tests pp_app_core_history_ui_tests pp_app_core_main_toolbar_tests pp_app_core_quick_ui_tests pp_app_core_tools_menu_tests}"
|
||||
targets="${*:-pp_foundation pp_assets pp_paint pp_document pp_renderer_api pp_renderer_gl pp_paint_renderer pp_ui_core pp_platform_api pp_app_core pano_cli pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_brush_package_tests pp_assets_image_format_tests pp_assets_image_metadata_tests pp_assets_image_pixels_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_paint_stroke_script_tests pp_document_tests pp_document_ppi_import_tests pp_document_ppi_export_tests pp_renderer_api_tests pp_renderer_gl_capabilities_tests pp_renderer_gl_command_plan_tests pp_paint_renderer_compositor_tests pp_platform_api_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pp_app_core_about_menu_tests pp_app_core_app_preferences_tests pp_app_core_app_frame_tests pp_app_core_app_input_tests pp_app_core_app_shutdown_tests pp_app_core_app_startup_tests pp_app_core_app_status_tests pp_app_core_command_convert_tests pp_app_core_brush_package_export_tests pp_app_core_brush_package_import_tests pp_app_core_brush_ui_tests pp_app_core_canvas_hotkey_tests pp_app_core_canvas_tool_ui_tests pp_app_core_canvas_view_tests pp_app_core_document_animation_tests pp_app_core_document_canvas_tests pp_app_core_document_cloud_tests pp_app_core_document_export_tests pp_app_core_document_import_tests pp_app_core_document_layer_tests pp_app_core_document_platform_io_tests pp_app_core_document_recording_tests pp_app_core_document_resize_tests pp_app_core_document_route_tests pp_app_core_document_sharing_tests pp_app_core_document_session_tests pp_app_core_file_menu_tests pp_app_core_grid_ui_tests pp_app_core_history_ui_tests pp_app_core_main_toolbar_tests pp_app_core_quick_ui_tests pp_app_core_tools_menu_tests}"
|
||||
start="$(date +%s)"
|
||||
|
||||
overall_exit=0
|
||||
|
||||
166
src/app_core/app_input.h
Normal file
166
src/app_core/app_input.h
Normal file
@@ -0,0 +1,166 @@
|
||||
#pragma once
|
||||
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace pp::app {
|
||||
|
||||
struct AppPointerDispatchPlan {
|
||||
bool request_redraw = true;
|
||||
bool dispatch_designer_first = false;
|
||||
bool dispatch_main_if_not_consumed = false;
|
||||
float normalized_x = 0.0F;
|
||||
float normalized_y = 0.0F;
|
||||
};
|
||||
|
||||
struct AppInputDispatchPlan {
|
||||
bool request_redraw = true;
|
||||
bool dispatch_main = false;
|
||||
};
|
||||
|
||||
struct AppGestureDispatchPlan {
|
||||
bool request_redraw = true;
|
||||
bool dispatch_main = false;
|
||||
float normalized_x = 0.0F;
|
||||
float normalized_y = 0.0F;
|
||||
float distance = 0.0F;
|
||||
float distance_delta = 0.0F;
|
||||
float position_delta_x = 0.0F;
|
||||
float position_delta_y = 0.0F;
|
||||
};
|
||||
|
||||
struct AppKeyDispatchPlan {
|
||||
bool request_redraw = true;
|
||||
bool dispatch_main = false;
|
||||
bool set_key_down = false;
|
||||
bool sync_vr_camera_rotation = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status validate_input_zoom(float zoom)
|
||||
{
|
||||
if (!std::isfinite(zoom) || zoom <= 0.0F) {
|
||||
return pp::foundation::Status::invalid_argument("input zoom must be finite and positive");
|
||||
}
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<AppPointerDispatchPlan> plan_app_pointer_dispatch(
|
||||
float x,
|
||||
float y,
|
||||
float zoom,
|
||||
bool has_designer_layout,
|
||||
bool has_main_layout)
|
||||
{
|
||||
const auto zoom_status = validate_input_zoom(zoom);
|
||||
if (!zoom_status.ok()) {
|
||||
return pp::foundation::Result<AppPointerDispatchPlan>::failure(zoom_status);
|
||||
}
|
||||
|
||||
if (!std::isfinite(x) || !std::isfinite(y)) {
|
||||
return pp::foundation::Result<AppPointerDispatchPlan>::failure(
|
||||
pp::foundation::Status::invalid_argument("input coordinates must be finite"));
|
||||
}
|
||||
|
||||
return pp::foundation::Result<AppPointerDispatchPlan>::success(AppPointerDispatchPlan {
|
||||
.request_redraw = true,
|
||||
.dispatch_designer_first = has_designer_layout,
|
||||
.dispatch_main_if_not_consumed = has_main_layout,
|
||||
.normalized_x = x / zoom,
|
||||
.normalized_y = y / zoom,
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr AppPointerDispatchPlan plan_app_mouse_cancel_dispatch(
|
||||
bool has_designer_layout,
|
||||
bool has_main_layout) noexcept
|
||||
{
|
||||
return AppPointerDispatchPlan {
|
||||
.request_redraw = true,
|
||||
.dispatch_designer_first = has_designer_layout,
|
||||
.dispatch_main_if_not_consumed = has_main_layout,
|
||||
.normalized_x = 0.0F,
|
||||
.normalized_y = 0.0F,
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr AppInputDispatchPlan plan_app_main_input_dispatch(bool has_main_layout) noexcept
|
||||
{
|
||||
return AppInputDispatchPlan {
|
||||
.request_redraw = true,
|
||||
.dispatch_main = has_main_layout,
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<AppGestureDispatchPlan> plan_app_gesture_dispatch(
|
||||
float x0,
|
||||
float y0,
|
||||
float x1,
|
||||
float y1,
|
||||
float previous_x0,
|
||||
float previous_y0,
|
||||
float previous_x1,
|
||||
float previous_y1,
|
||||
float zoom,
|
||||
bool has_main_layout)
|
||||
{
|
||||
const auto zoom_status = validate_input_zoom(zoom);
|
||||
if (!zoom_status.ok()) {
|
||||
return pp::foundation::Result<AppGestureDispatchPlan>::failure(zoom_status);
|
||||
}
|
||||
|
||||
if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(x1) || !std::isfinite(y1)
|
||||
|| !std::isfinite(previous_x0) || !std::isfinite(previous_y0)
|
||||
|| !std::isfinite(previous_x1) || !std::isfinite(previous_y1)) {
|
||||
return pp::foundation::Result<AppGestureDispatchPlan>::failure(
|
||||
pp::foundation::Status::invalid_argument("gesture coordinates must be finite"));
|
||||
}
|
||||
|
||||
const float midpoint_x = (x0 + x1) * 0.5F;
|
||||
const float midpoint_y = (y0 + y1) * 0.5F;
|
||||
const float previous_midpoint_x = (previous_x0 + previous_x1) * 0.5F;
|
||||
const float previous_midpoint_y = (previous_y0 + previous_y1) * 0.5F;
|
||||
const float dx = x1 - x0;
|
||||
const float dy = y1 - y0;
|
||||
const float previous_dx = previous_x1 - previous_x0;
|
||||
const float previous_dy = previous_y1 - previous_y0;
|
||||
const float distance = std::sqrt(dx * dx + dy * dy);
|
||||
const float previous_distance = std::sqrt(previous_dx * previous_dx + previous_dy * previous_dy);
|
||||
|
||||
return pp::foundation::Result<AppGestureDispatchPlan>::success(AppGestureDispatchPlan {
|
||||
.request_redraw = true,
|
||||
.dispatch_main = has_main_layout,
|
||||
.normalized_x = midpoint_x / zoom,
|
||||
.normalized_y = midpoint_y / zoom,
|
||||
.distance = distance,
|
||||
.distance_delta = distance - previous_distance,
|
||||
.position_delta_x = midpoint_x - previous_midpoint_x,
|
||||
.position_delta_y = midpoint_y - previous_midpoint_y,
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr AppKeyDispatchPlan plan_app_key_down_dispatch(
|
||||
bool has_main_layout,
|
||||
bool is_spacebar,
|
||||
bool vr_active) noexcept
|
||||
{
|
||||
return AppKeyDispatchPlan {
|
||||
.request_redraw = true,
|
||||
.dispatch_main = has_main_layout,
|
||||
.set_key_down = true,
|
||||
.sync_vr_camera_rotation = is_spacebar && vr_active,
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr AppKeyDispatchPlan plan_app_key_up_dispatch(bool has_main_layout) noexcept
|
||||
{
|
||||
return AppKeyDispatchPlan {
|
||||
.request_redraw = true,
|
||||
.dispatch_main = has_main_layout,
|
||||
.set_key_down = false,
|
||||
.sync_vr_camera_rotation = false,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace pp::app
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "app.h"
|
||||
#include "app_core/app_frame.h"
|
||||
#include "app_core/app_input.h"
|
||||
#include "app_core/document_platform_io.h"
|
||||
#include "app_core/document_sharing.h"
|
||||
#include "platform_api/platform_services.h"
|
||||
@@ -411,164 +412,249 @@ void App::save_prepared_file(
|
||||
|
||||
bool App::mouse_down(int button, float x, float y, float pressure, kEventSource source, bool eraser)
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_pointer_dispatch(
|
||||
x,
|
||||
y,
|
||||
zoom,
|
||||
layout_designer.get(main_id) != nullptr,
|
||||
layout.get(main_id) != nullptr);
|
||||
if (!plan) {
|
||||
LOG("Mouse down dispatch plan failed: %s", plan.status().message);
|
||||
return false;
|
||||
}
|
||||
|
||||
redraw = plan.value().request_redraw;
|
||||
MouseEvent e;
|
||||
e.m_type = button ? kEventType::MouseDownR : kEventType::MouseDownL;
|
||||
e.m_pos = { x / zoom, y / zoom };
|
||||
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
||||
e.m_pressure = pressure;
|
||||
e.m_source = source;
|
||||
e.m_eraser = eraser;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout_designer[main_id])
|
||||
if (auto* main = layout_designer[main_id]; plan.value().dispatch_designer_first && main)
|
||||
return main->on_event(&e) == kEventResult::Consumed;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.value().dispatch_main_if_not_consumed && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::mouse_move(float x, float y, float pressure, kEventSource source, bool eraser)
|
||||
{
|
||||
cursor = { x / zoom, y / zoom };
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_pointer_dispatch(
|
||||
x,
|
||||
y,
|
||||
zoom,
|
||||
layout_designer.get(main_id) != nullptr,
|
||||
layout.get(main_id) != nullptr);
|
||||
if (!plan) {
|
||||
LOG("Mouse move dispatch plan failed: %s", plan.status().message);
|
||||
return false;
|
||||
}
|
||||
|
||||
cursor = { plan.value().normalized_x, plan.value().normalized_y };
|
||||
redraw = plan.value().request_redraw;
|
||||
MouseEvent e;
|
||||
e.m_type = kEventType::MouseMove;
|
||||
e.m_pos = { x / zoom, y / zoom };
|
||||
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
||||
e.m_pressure = pressure;
|
||||
e.m_source = source;
|
||||
e.m_eraser = eraser;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout_designer[main_id])
|
||||
if (auto* main = layout_designer[main_id]; plan.value().dispatch_designer_first && main)
|
||||
return main->on_event(&e) == kEventResult::Consumed;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.value().dispatch_main_if_not_consumed && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::mouse_up(int button, float x, float y, kEventSource source, bool eraser)
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_pointer_dispatch(
|
||||
x,
|
||||
y,
|
||||
zoom,
|
||||
layout_designer.get(main_id) != nullptr,
|
||||
layout.get(main_id) != nullptr);
|
||||
if (!plan) {
|
||||
LOG("Mouse up dispatch plan failed: %s", plan.status().message);
|
||||
return false;
|
||||
}
|
||||
|
||||
redraw = plan.value().request_redraw;
|
||||
MouseEvent e;
|
||||
e.m_type = button ? kEventType::MouseUpR : kEventType::MouseUpL;
|
||||
e.m_pos = { x / zoom, y / zoom };
|
||||
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
||||
e.m_source = source;
|
||||
e.m_eraser = eraser;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout_designer[main_id])
|
||||
if (auto* main = layout_designer[main_id]; plan.value().dispatch_designer_first && main)
|
||||
return main->on_event(&e) == kEventResult::Consumed;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.value().dispatch_main_if_not_consumed && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::mouse_scroll(float x, float y, float delta)
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_pointer_dispatch(
|
||||
x,
|
||||
y,
|
||||
zoom,
|
||||
layout_designer.get(main_id) != nullptr,
|
||||
layout.get(main_id) != nullptr);
|
||||
if (!plan) {
|
||||
LOG("Mouse scroll dispatch plan failed: %s", plan.status().message);
|
||||
return false;
|
||||
}
|
||||
|
||||
redraw = plan.value().request_redraw;
|
||||
MouseEvent e;
|
||||
e.m_type = kEventType::MouseScroll;
|
||||
e.m_pos = { x / zoom, y / zoom };
|
||||
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
||||
e.m_scroll_delta = delta;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout_designer[main_id])
|
||||
if (auto* main = layout_designer[main_id]; plan.value().dispatch_designer_first && main)
|
||||
return main->on_event(&e) == kEventResult::Consumed;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.value().dispatch_main_if_not_consumed && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::mouse_cancel(int button)
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_mouse_cancel_dispatch(
|
||||
layout_designer.get(main_id) != nullptr,
|
||||
layout.get(main_id) != nullptr);
|
||||
redraw = plan.request_redraw;
|
||||
MouseEvent e;
|
||||
e.m_type = kEventType::MouseCancel;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout_designer[main_id])
|
||||
if (auto* main = layout_designer[main_id]; plan.dispatch_designer_first && main)
|
||||
return main->on_event(&e) == kEventResult::Consumed;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.dispatch_main_if_not_consumed && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::gesture_start(const glm::vec2& p0, const glm::vec2& p1)
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_gesture_dispatch(
|
||||
p0.x,
|
||||
p0.y,
|
||||
p1.x,
|
||||
p1.y,
|
||||
p0.x,
|
||||
p0.y,
|
||||
p1.x,
|
||||
p1.y,
|
||||
zoom,
|
||||
layout.get(main_id) != nullptr);
|
||||
if (!plan) {
|
||||
LOG("Gesture start dispatch plan failed: %s", plan.status().message);
|
||||
return false;
|
||||
}
|
||||
|
||||
redraw = plan.value().request_redraw;
|
||||
GestureEvent e;
|
||||
glm::vec2 p = glm::lerp(p0, p1, 0.5f);
|
||||
e.m_type = kEventType::GestureStart;
|
||||
e.m_pos = p / glm::vec2(zoom);
|
||||
e.m_distance = glm::distance(p0, p1);
|
||||
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
||||
e.m_distance = plan.value().distance;
|
||||
gesture_p0 = p0;
|
||||
gesture_p1 = p1;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.value().dispatch_main && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::gesture_move(const glm::vec2& p0, const glm::vec2& p1)
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_gesture_dispatch(
|
||||
p0.x,
|
||||
p0.y,
|
||||
p1.x,
|
||||
p1.y,
|
||||
gesture_p0.x,
|
||||
gesture_p0.y,
|
||||
gesture_p1.x,
|
||||
gesture_p1.y,
|
||||
zoom,
|
||||
layout.get(main_id) != nullptr);
|
||||
if (!plan) {
|
||||
LOG("Gesture move dispatch plan failed: %s", plan.status().message);
|
||||
return false;
|
||||
}
|
||||
|
||||
redraw = plan.value().request_redraw;
|
||||
GestureEvent e;
|
||||
glm::vec2 p = glm::lerp(p0, p1, 0.5f);
|
||||
e.m_type = kEventType::GestureMove;
|
||||
e.m_pos = p / glm::vec2(zoom);
|
||||
e.m_distance = glm::distance(p0, p1);
|
||||
e.m_distance_delta = e.m_distance - glm::distance(gesture_p0, gesture_p1);
|
||||
e.m_pos_delta = p - glm::lerp(gesture_p0, gesture_p1, 0.5f);
|
||||
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
||||
e.m_distance = plan.value().distance;
|
||||
e.m_distance_delta = plan.value().distance_delta;
|
||||
e.m_pos_delta = { plan.value().position_delta_x, plan.value().position_delta_y };
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.value().dispatch_main && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::gesture_end()
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_main_input_dispatch(layout.get(main_id) != nullptr);
|
||||
redraw = plan.request_redraw;
|
||||
GestureEvent e;
|
||||
e.m_type = kEventType::GestureEnd;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::touch_tap(const glm::vec2& pos, int fingers, int tap_count)
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_main_input_dispatch(layout.get(main_id) != nullptr);
|
||||
redraw = plan.request_redraw;
|
||||
TouchEvent e;
|
||||
e.m_type = kEventType::TouchTap;
|
||||
e.m_finger_count = fingers;
|
||||
e.m_tap_count = tap_count;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::key_down(kKey key)
|
||||
{
|
||||
if (key == kKey::KeySpacebar && vr_active)
|
||||
const auto plan = pp::app::plan_app_key_down_dispatch(
|
||||
layout.get(main_id) != nullptr,
|
||||
key == kKey::KeySpacebar,
|
||||
vr_active);
|
||||
if (plan.sync_vr_camera_rotation)
|
||||
canvas->m_canvas->m_cam_rot = vr_rot;
|
||||
redraw = true;
|
||||
keys[(int)key] = true;
|
||||
redraw = plan.request_redraw;
|
||||
keys[(int)key] = plan.set_key_down;
|
||||
KeyEvent e;
|
||||
e.m_type = kEventType::KeyDown;
|
||||
e.m_key = key;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::key_up(kKey key)
|
||||
{
|
||||
redraw = true;
|
||||
keys[(int)key] = false;
|
||||
const auto plan = pp::app::plan_app_key_up_dispatch(layout.get(main_id) != nullptr);
|
||||
redraw = plan.request_redraw;
|
||||
keys[(int)key] = plan.set_key_down;
|
||||
KeyEvent e;
|
||||
e.m_type = kEventType::KeyUp;
|
||||
e.m_key = key;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
bool App::key_char(char key)
|
||||
{
|
||||
redraw = true;
|
||||
const auto plan = pp::app::plan_app_main_input_dispatch(layout.get(main_id) != nullptr);
|
||||
redraw = plan.request_redraw;
|
||||
KeyEvent e;
|
||||
e.m_type = kEventType::KeyChar;
|
||||
e.m_char = key;
|
||||
kEventResult ret = kEventResult::Available;
|
||||
if (auto* main = layout[main_id])
|
||||
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
||||
ret = main->on_event(&e);
|
||||
return ret == kEventResult::Consumed;
|
||||
}
|
||||
|
||||
@@ -565,6 +565,16 @@ add_test(NAME pp_app_core_app_frame_tests COMMAND pp_app_core_app_frame_tests)
|
||||
set_tests_properties(pp_app_core_app_frame_tests PROPERTIES
|
||||
LABELS "app;desktop-fast;fuzz")
|
||||
|
||||
add_executable(pp_app_core_app_input_tests
|
||||
app_core/app_input_tests.cpp)
|
||||
target_link_libraries(pp_app_core_app_input_tests PRIVATE
|
||||
pp_app_core
|
||||
pp_test_harness)
|
||||
|
||||
add_test(NAME pp_app_core_app_input_tests COMMAND pp_app_core_app_input_tests)
|
||||
set_tests_properties(pp_app_core_app_input_tests PROPERTIES
|
||||
LABELS "app;desktop-fast;fuzz")
|
||||
|
||||
add_executable(pp_app_core_app_shutdown_tests
|
||||
app_core/app_shutdown_tests.cpp)
|
||||
target_link_libraries(pp_app_core_app_shutdown_tests PRIVATE
|
||||
@@ -1002,6 +1012,31 @@ if(TARGET pano_cli)
|
||||
WILL_FAIL TRUE
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-frame\".*\"message\":\"resize dimensions")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_input_pointer_smoke
|
||||
COMMAND pano_cli plan-app-input --kind pointer --x 100 --y 50 --zoom 2)
|
||||
set_tests_properties(pano_cli_plan_app_input_pointer_smoke PROPERTIES
|
||||
LABELS "app;integration;desktop-fast"
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-input\".*\"kind\":\"pointer\".*\"dispatchDesignerFirst\":true.*\"dispatchMainIfNotConsumed\":true.*\"normalizedX\":50.*\"normalizedY\":25")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_input_gesture_smoke
|
||||
COMMAND pano_cli plan-app-input --kind gesture --x 0 --y 0 --x1 6 --y1 8 --prev-x 0 --prev-y 0 --prev-x1 3 --prev-y1 4 --zoom 2)
|
||||
set_tests_properties(pano_cli_plan_app_input_gesture_smoke PROPERTIES
|
||||
LABELS "app;integration;desktop-fast"
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-input\".*\"kind\":\"gesture\".*\"dispatchMain\":true.*\"normalizedX\":1.5.*\"normalizedY\":2.*\"distance\":10.*\"distanceDelta\":5")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_input_key_vr_smoke
|
||||
COMMAND pano_cli plan-app-input --kind key --spacebar --vr-active)
|
||||
set_tests_properties(pano_cli_plan_app_input_key_vr_smoke PROPERTIES
|
||||
LABELS "app;integration;desktop-fast"
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-input\".*\"kind\":\"key\".*\"dispatchMain\":true.*\"setKeyDown\":true.*\"syncVrCameraRotation\":true")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_input_rejects_bad_float
|
||||
COMMAND pano_cli plan-app-input --kind pointer --bad-float)
|
||||
set_tests_properties(pano_cli_plan_app_input_rejects_bad_float PROPERTIES
|
||||
LABELS "app;integration;desktop-fast;fuzz"
|
||||
WILL_FAIL TRUE
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-input\".*\"message\":\"input zoom must be finite and positive\"")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_shutdown_smoke
|
||||
COMMAND pano_cli plan-app-shutdown)
|
||||
set_tests_properties(pano_cli_plan_app_shutdown_smoke PROPERTIES
|
||||
|
||||
118
tests/app_core/app_input_tests.cpp
Normal file
118
tests/app_core/app_input_tests.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#include "app_core/app_input.h"
|
||||
#include "test_harness.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
|
||||
void pointer_plan_normalizes_coordinates_and_routes_designer_first(pp::tests::Harness& harness)
|
||||
{
|
||||
const auto plan = pp::app::plan_app_pointer_dispatch(100.0F, 50.0F, 2.0F, true, true);
|
||||
|
||||
PP_EXPECT(harness, plan);
|
||||
PP_EXPECT(harness, plan.value().request_redraw);
|
||||
PP_EXPECT(harness, plan.value().dispatch_designer_first);
|
||||
PP_EXPECT(harness, plan.value().dispatch_main_if_not_consumed);
|
||||
PP_EXPECT(harness, plan.value().normalized_x == 50.0F);
|
||||
PP_EXPECT(harness, plan.value().normalized_y == 25.0F);
|
||||
}
|
||||
|
||||
void pointer_plan_rejects_invalid_zoom_or_coordinates(pp::tests::Harness& harness)
|
||||
{
|
||||
PP_EXPECT(harness, !pp::app::plan_app_pointer_dispatch(100.0F, 50.0F, 0.0F, true, true));
|
||||
PP_EXPECT(harness, !pp::app::plan_app_pointer_dispatch(std::nanf(""), 50.0F, 1.0F, true, true));
|
||||
}
|
||||
|
||||
void mouse_cancel_preserves_designer_first_routing(pp::tests::Harness& harness)
|
||||
{
|
||||
const auto designer = pp::app::plan_app_mouse_cancel_dispatch(true, true);
|
||||
const auto main = pp::app::plan_app_mouse_cancel_dispatch(false, true);
|
||||
|
||||
PP_EXPECT(harness, designer.request_redraw);
|
||||
PP_EXPECT(harness, designer.dispatch_designer_first);
|
||||
PP_EXPECT(harness, designer.dispatch_main_if_not_consumed);
|
||||
PP_EXPECT(harness, !main.dispatch_designer_first);
|
||||
PP_EXPECT(harness, main.dispatch_main_if_not_consumed);
|
||||
}
|
||||
|
||||
void gesture_plan_computes_midpoint_distance_and_delta(pp::tests::Harness& harness)
|
||||
{
|
||||
const auto plan = pp::app::plan_app_gesture_dispatch(
|
||||
0.0F,
|
||||
0.0F,
|
||||
6.0F,
|
||||
8.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
3.0F,
|
||||
4.0F,
|
||||
2.0F,
|
||||
true);
|
||||
|
||||
PP_EXPECT(harness, plan);
|
||||
PP_EXPECT(harness, plan.value().dispatch_main);
|
||||
PP_EXPECT(harness, plan.value().normalized_x == 1.5F);
|
||||
PP_EXPECT(harness, plan.value().normalized_y == 2.0F);
|
||||
PP_EXPECT(harness, plan.value().distance == 10.0F);
|
||||
PP_EXPECT(harness, plan.value().distance_delta == 5.0F);
|
||||
PP_EXPECT(harness, plan.value().position_delta_x == 1.5F);
|
||||
PP_EXPECT(harness, plan.value().position_delta_y == 2.0F);
|
||||
}
|
||||
|
||||
void gesture_plan_rejects_invalid_input(pp::tests::Harness& harness)
|
||||
{
|
||||
PP_EXPECT(
|
||||
harness,
|
||||
!pp::app::plan_app_gesture_dispatch(
|
||||
0.0F,
|
||||
0.0F,
|
||||
1.0F,
|
||||
1.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
1.0F,
|
||||
1.0F,
|
||||
-1.0F,
|
||||
true));
|
||||
}
|
||||
|
||||
void key_plan_tracks_state_and_vr_spacebar_sync(pp::tests::Harness& harness)
|
||||
{
|
||||
const auto down = pp::app::plan_app_key_down_dispatch(true, true, true);
|
||||
const auto ordinary = pp::app::plan_app_key_down_dispatch(true, false, true);
|
||||
const auto up = pp::app::plan_app_key_up_dispatch(true);
|
||||
|
||||
PP_EXPECT(harness, down.dispatch_main);
|
||||
PP_EXPECT(harness, down.set_key_down);
|
||||
PP_EXPECT(harness, down.sync_vr_camera_rotation);
|
||||
PP_EXPECT(harness, ordinary.set_key_down);
|
||||
PP_EXPECT(harness, !ordinary.sync_vr_camera_rotation);
|
||||
PP_EXPECT(harness, up.dispatch_main);
|
||||
PP_EXPECT(harness, !up.set_key_down);
|
||||
}
|
||||
|
||||
void simple_input_plan_tracks_main_layout_availability(pp::tests::Harness& harness)
|
||||
{
|
||||
const auto available = pp::app::plan_app_main_input_dispatch(true);
|
||||
const auto missing = pp::app::plan_app_main_input_dispatch(false);
|
||||
|
||||
PP_EXPECT(harness, available.request_redraw);
|
||||
PP_EXPECT(harness, available.dispatch_main);
|
||||
PP_EXPECT(harness, missing.request_redraw);
|
||||
PP_EXPECT(harness, !missing.dispatch_main);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
pp::tests::Harness harness;
|
||||
harness.run("pointer plan normalizes coordinates and routes designer first", pointer_plan_normalizes_coordinates_and_routes_designer_first);
|
||||
harness.run("pointer plan rejects invalid zoom or coordinates", pointer_plan_rejects_invalid_zoom_or_coordinates);
|
||||
harness.run("mouse cancel preserves designer first routing", mouse_cancel_preserves_designer_first_routing);
|
||||
harness.run("gesture plan computes midpoint distance and delta", gesture_plan_computes_midpoint_distance_and_delta);
|
||||
harness.run("gesture plan rejects invalid input", gesture_plan_rejects_invalid_input);
|
||||
harness.run("key plan tracks state and VR spacebar sync", key_plan_tracks_state_and_vr_spacebar_sync);
|
||||
harness.run("simple input plan tracks main layout availability", simple_input_plan_tracks_main_layout_availability);
|
||||
return harness.finish();
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "app_core/about_menu.h"
|
||||
#include "app_core/app_preferences.h"
|
||||
#include "app_core/app_frame.h"
|
||||
#include "app_core/app_input.h"
|
||||
#include "app_core/app_shutdown.h"
|
||||
#include "app_core/app_status.h"
|
||||
#include "app_core/app_startup.h"
|
||||
@@ -263,6 +264,25 @@ struct PlanAppFrameArgs {
|
||||
bool bad_resize = false;
|
||||
};
|
||||
|
||||
struct PlanAppInputArgs {
|
||||
std::string kind = "pointer";
|
||||
float x0 = 100.0F;
|
||||
float y0 = 50.0F;
|
||||
float x1 = 160.0F;
|
||||
float y1 = 130.0F;
|
||||
float previous_x0 = 100.0F;
|
||||
float previous_y0 = 50.0F;
|
||||
float previous_x1 = 130.0F;
|
||||
float previous_y1 = 90.0F;
|
||||
float zoom = 2.0F;
|
||||
bool has_designer_layout = true;
|
||||
bool has_main_layout = true;
|
||||
bool spacebar = false;
|
||||
bool vr_active = false;
|
||||
bool key_up = false;
|
||||
bool bad_float = false;
|
||||
};
|
||||
|
||||
struct PlanCommandConvertArgs {
|
||||
std::string project_path = "D:/Paint/demo.ppi";
|
||||
std::string output_path = "D:/Paint/demo.png";
|
||||
@@ -2051,6 +2071,7 @@ void print_help()
|
||||
<< " plan-app-startup [--run-counter N] [--auto-timelapse-disabled] [--vr-controllers-disabled] [--license-invalid]\n"
|
||||
<< " plan-app-startup-resources [--width N] [--height N] [--bad-size]\n"
|
||||
<< " plan-app-frame [--redraw] [--animate] [--no-designer-layout] [--no-main-layout] [--no-canvas] [--no-canvas-document] [--vr-active] [--ui-hidden] [--vr-only] [--resize-width N] [--resize-height N] [--bad-resize]\n"
|
||||
<< " plan-app-input --kind pointer|gesture|cancel|main|key [--x N] [--y N] [--x1 N] [--y1 N] [--prev-x N] [--prev-y N] [--prev-x1 N] [--prev-y1 N] [--zoom N] [--no-designer-layout] [--no-main-layout] [--spacebar] [--vr-active] [--key-up] [--bad-float]\n"
|
||||
<< " plan-app-shutdown\n"
|
||||
<< " plan-command-convert [--project FILE] [--output FILE] [--canvas-resolution N]\n"
|
||||
<< " plan-app-status [--doc-name NAME] [--unsaved] [--resolution N] [--resolution-index N] [--zoom N] [--history-bytes N] [--recording-running] [--encoder-available] [--encoded-frames N] [--framebuffer-fetch] [--float32] [--float32-linear] [--float16]\n"
|
||||
@@ -3860,6 +3881,199 @@ int plan_app_frame(int argc, char** argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pp::foundation::Status parse_plan_app_input_args(
|
||||
int argc,
|
||||
char** argv,
|
||||
PlanAppInputArgs& args)
|
||||
{
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
const std::string_view key(argv[i]);
|
||||
auto parse_next_float = [&](float& target) -> pp::foundation::Status {
|
||||
if (i + 1 >= argc) {
|
||||
return pp::foundation::Status::invalid_argument("missing value for option");
|
||||
}
|
||||
const auto value = parse_float_arg(argv[++i]);
|
||||
if (!value) {
|
||||
return value.status();
|
||||
}
|
||||
target = value.value();
|
||||
return pp::foundation::Status::success();
|
||||
};
|
||||
|
||||
if (key == "--kind") {
|
||||
if (i + 1 >= argc) {
|
||||
return pp::foundation::Status::invalid_argument("missing value for option");
|
||||
}
|
||||
args.kind = argv[++i];
|
||||
} else if (key == "--x") {
|
||||
const auto status = parse_next_float(args.x0);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--y") {
|
||||
const auto status = parse_next_float(args.y0);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--x1") {
|
||||
const auto status = parse_next_float(args.x1);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--y1") {
|
||||
const auto status = parse_next_float(args.y1);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--prev-x") {
|
||||
const auto status = parse_next_float(args.previous_x0);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--prev-y") {
|
||||
const auto status = parse_next_float(args.previous_y0);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--prev-x1") {
|
||||
const auto status = parse_next_float(args.previous_x1);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--prev-y1") {
|
||||
const auto status = parse_next_float(args.previous_y1);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--zoom") {
|
||||
const auto status = parse_next_float(args.zoom);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else if (key == "--no-designer-layout") {
|
||||
args.has_designer_layout = false;
|
||||
} else if (key == "--no-main-layout") {
|
||||
args.has_main_layout = false;
|
||||
} else if (key == "--spacebar") {
|
||||
args.spacebar = true;
|
||||
} else if (key == "--vr-active") {
|
||||
args.vr_active = true;
|
||||
} else if (key == "--key-up") {
|
||||
args.key_up = true;
|
||||
} else if (key == "--bad-float") {
|
||||
args.bad_float = true;
|
||||
} else {
|
||||
return pp::foundation::Status::invalid_argument("unknown option");
|
||||
}
|
||||
}
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
int plan_app_input(int argc, char** argv)
|
||||
{
|
||||
PlanAppInputArgs args;
|
||||
const auto status = parse_plan_app_input_args(argc, argv, args);
|
||||
if (!status.ok()) {
|
||||
print_error("plan-app-input", status.message);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (args.bad_float) {
|
||||
args.zoom = 0.0F;
|
||||
}
|
||||
|
||||
if (args.kind == "pointer") {
|
||||
const auto plan = pp::app::plan_app_pointer_dispatch(
|
||||
args.x0,
|
||||
args.y0,
|
||||
args.zoom,
|
||||
args.has_designer_layout,
|
||||
args.has_main_layout);
|
||||
if (!plan) {
|
||||
print_error("plan-app-input", plan.status().message);
|
||||
return 2;
|
||||
}
|
||||
std::cout << "{\"ok\":true,\"command\":\"plan-app-input\",\"kind\":\"pointer\""
|
||||
<< ",\"requestRedraw\":" << json_bool(plan.value().request_redraw)
|
||||
<< ",\"dispatchDesignerFirst\":" << json_bool(plan.value().dispatch_designer_first)
|
||||
<< ",\"dispatchMainIfNotConsumed\":" << json_bool(plan.value().dispatch_main_if_not_consumed)
|
||||
<< ",\"normalizedX\":" << plan.value().normalized_x
|
||||
<< ",\"normalizedY\":" << plan.value().normalized_y
|
||||
<< "}\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args.kind == "gesture") {
|
||||
const auto plan = pp::app::plan_app_gesture_dispatch(
|
||||
args.x0,
|
||||
args.y0,
|
||||
args.x1,
|
||||
args.y1,
|
||||
args.previous_x0,
|
||||
args.previous_y0,
|
||||
args.previous_x1,
|
||||
args.previous_y1,
|
||||
args.zoom,
|
||||
args.has_main_layout);
|
||||
if (!plan) {
|
||||
print_error("plan-app-input", plan.status().message);
|
||||
return 2;
|
||||
}
|
||||
std::cout << "{\"ok\":true,\"command\":\"plan-app-input\",\"kind\":\"gesture\""
|
||||
<< ",\"requestRedraw\":" << json_bool(plan.value().request_redraw)
|
||||
<< ",\"dispatchMain\":" << json_bool(plan.value().dispatch_main)
|
||||
<< ",\"normalizedX\":" << plan.value().normalized_x
|
||||
<< ",\"normalizedY\":" << plan.value().normalized_y
|
||||
<< ",\"distance\":" << plan.value().distance
|
||||
<< ",\"distanceDelta\":" << plan.value().distance_delta
|
||||
<< ",\"positionDeltaX\":" << plan.value().position_delta_x
|
||||
<< ",\"positionDeltaY\":" << plan.value().position_delta_y
|
||||
<< "}\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args.kind == "cancel") {
|
||||
const auto plan = pp::app::plan_app_mouse_cancel_dispatch(
|
||||
args.has_designer_layout,
|
||||
args.has_main_layout);
|
||||
std::cout << "{\"ok\":true,\"command\":\"plan-app-input\",\"kind\":\"cancel\""
|
||||
<< ",\"requestRedraw\":" << json_bool(plan.request_redraw)
|
||||
<< ",\"dispatchDesignerFirst\":" << json_bool(plan.dispatch_designer_first)
|
||||
<< ",\"dispatchMainIfNotConsumed\":" << json_bool(plan.dispatch_main_if_not_consumed)
|
||||
<< "}\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args.kind == "main") {
|
||||
const auto plan = pp::app::plan_app_main_input_dispatch(args.has_main_layout);
|
||||
std::cout << "{\"ok\":true,\"command\":\"plan-app-input\",\"kind\":\"main\""
|
||||
<< ",\"requestRedraw\":" << json_bool(plan.request_redraw)
|
||||
<< ",\"dispatchMain\":" << json_bool(plan.dispatch_main)
|
||||
<< "}\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args.kind == "key") {
|
||||
const auto down = pp::app::plan_app_key_down_dispatch(
|
||||
args.has_main_layout,
|
||||
args.spacebar,
|
||||
args.vr_active);
|
||||
const auto up = pp::app::plan_app_key_up_dispatch(args.has_main_layout);
|
||||
const auto& plan = args.key_up ? up : down;
|
||||
std::cout << "{\"ok\":true,\"command\":\"plan-app-input\",\"kind\":\"key\""
|
||||
<< ",\"requestRedraw\":" << json_bool(plan.request_redraw)
|
||||
<< ",\"dispatchMain\":" << json_bool(plan.dispatch_main)
|
||||
<< ",\"setKeyDown\":" << json_bool(plan.set_key_down)
|
||||
<< ",\"syncVrCameraRotation\":" << json_bool(plan.sync_vr_camera_rotation)
|
||||
<< "}\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
print_error("plan-app-input", "unknown input plan kind");
|
||||
return 2;
|
||||
}
|
||||
|
||||
int plan_app_shutdown(int argc, char** argv)
|
||||
{
|
||||
static_cast<void>(argv);
|
||||
@@ -10202,6 +10416,10 @@ int main(int argc, char** argv)
|
||||
return plan_app_frame(argc, argv);
|
||||
}
|
||||
|
||||
if (command == "plan-app-input") {
|
||||
return plan_app_input(argc, argv);
|
||||
}
|
||||
|
||||
if (command == "plan-app-shutdown") {
|
||||
return plan_app_shutdown(argc, argv);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user