Route canvas cursor visibility through app core

This commit is contained in:
2026-06-05 01:39:36 +02:00
parent e95861e9b7
commit f42a6540be
8 changed files with 447 additions and 23 deletions

View File

@@ -1628,6 +1628,42 @@ if(TARGET pano_cli)
LABELS "app;ui;integration;desktop-fast;fuzz"
WILL_FAIL TRUE)
add_test(NAME pano_cli_plan_canvas_cursor_small_brush_smoke
COMMAND pano_cli plan-canvas-cursor --mode draw --visibility small-brush --brush-size 9.5)
set_tests_properties(pano_cli_plan_canvas_cursor_small_brush_smoke PROPERTIES
LABELS "app;ui;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-cursor\".*\"mode\":\"draw\".*\"visibility\":\"small-brush\".*\"visible\":true.*\"paintMode\":true.*\"usesBrushSize\":true")
add_test(NAME pano_cli_plan_canvas_cursor_not_painting_hidden_smoke
COMMAND pano_cli plan-canvas-cursor --mode erase --visibility not-painting --drawing)
set_tests_properties(pano_cli_plan_canvas_cursor_not_painting_hidden_smoke PROPERTIES
LABELS "app;ui;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-cursor\".*\"mode\":\"erase\".*\"visibility\":\"not-painting\".*\"drawing\":true.*\"visible\":false.*\"usesPenState\":true")
add_test(NAME pano_cli_plan_canvas_cursor_alt_forces_visible_smoke
COMMAND pano_cli plan-canvas-cursor --mode draw --visibility never --alt)
set_tests_properties(pano_cli_plan_canvas_cursor_alt_forces_visible_smoke PROPERTIES
LABELS "app;ui;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-cursor\".*\"visibility\":\"never\".*\"visible\":true.*\"forcedVisibleByModifierOrTool\":true")
add_test(NAME pano_cli_plan_canvas_cursor_non_paint_smoke
COMMAND pano_cli plan-canvas-cursor --mode camera --visibility never)
set_tests_properties(pano_cli_plan_canvas_cursor_non_paint_smoke PROPERTIES
LABELS "app;ui;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-cursor\".*\"mode\":\"camera\".*\"visible\":true.*\"paintMode\":false")
add_test(NAME pano_cli_plan_canvas_cursor_rejects_missing_brush
COMMAND pano_cli plan-canvas-cursor --visibility small-brush --no-brush)
set_tests_properties(pano_cli_plan_canvas_cursor_rejects_missing_brush PROPERTIES
LABELS "app;ui;integration;desktop-fast;fuzz"
WILL_FAIL TRUE)
add_test(NAME pano_cli_plan_canvas_cursor_rejects_bad_size
COMMAND pano_cli plan-canvas-cursor --visibility small-brush --bad-size)
set_tests_properties(pano_cli_plan_canvas_cursor_rejects_bad_size PROPERTIES
LABELS "app;ui;integration;desktop-fast;fuzz"
WILL_FAIL TRUE)
add_test(NAME pano_cli_plan_grid_operation_pick_smoke
COMMAND pano_cli plan-grid-operation --kind pick)
set_tests_properties(pano_cli_plan_grid_operation_pick_smoke PROPERTIES

View File

@@ -1,6 +1,7 @@
#include "app_core/canvas_tool_ui.h"
#include "test_harness.h"
#include <cmath>
#include <string>
namespace {
@@ -128,6 +129,96 @@ void button_state_tracks_active_mode_and_toggles(pp::tests::Harness& harness)
PP_EXPECT(harness, !bucket.mask_line_active);
}
void cursor_visibility_projects_canvas_state(pp::tests::Harness& harness)
{
const auto non_paint = pp::app::plan_canvas_cursor_visibility(pp::app::CanvasCursorVisibilityInput {
.mode = pp::app::CanvasToolMode::camera,
.visibility_mode = pp::app::CanvasCursorVisibilityMode::never,
});
PP_EXPECT(harness, non_paint);
if (non_paint) {
PP_EXPECT(harness, non_paint.value().visible);
PP_EXPECT(harness, !non_paint.value().paint_mode);
}
const auto small = pp::app::plan_canvas_cursor_visibility(pp::app::CanvasCursorVisibilityInput {
.mode = pp::app::CanvasToolMode::draw,
.visibility_mode = pp::app::CanvasCursorVisibilityMode::small_brush,
.has_current_brush = true,
.brush_tip_size = 9.5F,
});
PP_EXPECT(harness, small);
if (small) {
PP_EXPECT(harness, small.value().visible);
PP_EXPECT(harness, small.value().paint_mode);
PP_EXPECT(harness, small.value().uses_brush_size);
}
const auto large = pp::app::plan_canvas_cursor_visibility(pp::app::CanvasCursorVisibilityInput {
.mode = pp::app::CanvasToolMode::erase,
.visibility_mode = pp::app::CanvasCursorVisibilityMode::small_brush,
.has_current_brush = true,
.brush_tip_size = 10.0F,
});
PP_EXPECT(harness, large);
if (large) {
PP_EXPECT(harness, !large.value().visible);
PP_EXPECT(harness, large.value().uses_brush_size);
}
const auto painting = pp::app::plan_canvas_cursor_visibility(pp::app::CanvasCursorVisibilityInput {
.mode = pp::app::CanvasToolMode::draw,
.visibility_mode = pp::app::CanvasCursorVisibilityMode::not_painting,
.pen_is_drawing = true,
});
PP_EXPECT(harness, painting);
if (painting) {
PP_EXPECT(harness, !painting.value().visible);
PP_EXPECT(harness, painting.value().uses_pen_state);
}
}
void cursor_visibility_forces_visible_for_modifier_or_tool(pp::tests::Harness& harness)
{
const auto alt = pp::app::plan_canvas_cursor_visibility(pp::app::CanvasCursorVisibilityInput {
.mode = pp::app::CanvasToolMode::draw,
.visibility_mode = pp::app::CanvasCursorVisibilityMode::never,
.alt_down = true,
});
PP_EXPECT(harness, alt);
if (alt) {
PP_EXPECT(harness, alt.value().visible);
PP_EXPECT(harness, alt.value().forced_visible_by_modifier_or_tool);
}
const auto picking = pp::app::plan_canvas_cursor_visibility(pp::app::CanvasCursorVisibilityInput {
.mode = pp::app::CanvasToolMode::erase,
.visibility_mode = pp::app::CanvasCursorVisibilityMode::not_painting,
.pen_is_drawing = true,
.pen_is_picking = true,
});
PP_EXPECT(harness, picking);
if (picking) {
PP_EXPECT(harness, picking.value().visible);
PP_EXPECT(harness, picking.value().forced_visible_by_modifier_or_tool);
}
}
void cursor_visibility_rejects_invalid_brush_state(pp::tests::Harness& harness)
{
PP_EXPECT(harness, !pp::app::plan_canvas_cursor_visibility(pp::app::CanvasCursorVisibilityInput {
.mode = pp::app::CanvasToolMode::draw,
.visibility_mode = pp::app::CanvasCursorVisibilityMode::small_brush,
.has_current_brush = false,
}));
PP_EXPECT(harness, !pp::app::plan_canvas_cursor_visibility(pp::app::CanvasCursorVisibilityInput {
.mode = pp::app::CanvasToolMode::draw,
.visibility_mode = pp::app::CanvasCursorVisibilityMode::small_brush,
.has_current_brush = true,
.brush_tip_size = std::nanf(""),
}));
}
void executor_dispatches_tool_actions(pp::tests::Harness& harness)
{
FakeCanvasToolServices services;
@@ -205,6 +296,9 @@ int main()
harness.run("transform tools plan copy and cut actions", transform_tools_plan_copy_and_cut_actions);
harness.run("pick and touch lock toggle state", pick_and_touch_lock_toggle_state);
harness.run("button state tracks active mode and toggles", button_state_tracks_active_mode_and_toggles);
harness.run("cursor visibility projects canvas state", cursor_visibility_projects_canvas_state);
harness.run("cursor visibility forces visible for modifier or tool", cursor_visibility_forces_visible_for_modifier_or_tool);
harness.run("cursor visibility rejects invalid brush state", cursor_visibility_rejects_invalid_brush_state);
harness.run("executor dispatches tool actions", executor_dispatches_tool_actions);
harness.run("executor no-ops pick when not in draw mode", executor_no_ops_pick_when_not_in_draw_mode);
harness.run("executor rejects malformed plans", executor_rejects_malformed_plans);