diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 9ef9e18..c6cdd98 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -45,11 +45,11 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0025 | Open | Modernization | Quick brush/color slot and mini-state planning and execution dispatch now consume pure `pp_app_core` through `NodePanelQuick`, `pano_cli plan-quick-operation`, and the `QuickUiServices` boundary, but the live adapter still mutates legacy quick UI widgets, `Brush` previews, color picker popup state, and preset popup state | Preserve quick-panel behavior while quick brush/color commands move toward a brush/app command boundary with safer automation coverage | `pp_app_core_quick_ui_tests`; `pano_cli plan-quick-operation --kind brush --current-index 0 --slot-index 2`; `pano_cli plan-quick-operation --kind restore --brush-index 2 --color-index 1 --fire-event`; `ctest --preset desktop-fast --build-config Debug` | Quick-panel selection, popup, restore, reset, brush preview, and color execution are owned by injected app/brush/UI services with no legacy quick-panel adapter | | DEBT-0026 | Open | Modernization | Toolbar history command planning and execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, `NodeCanvas`, `pano_cli plan-history-operation`, and the `HistoryUiServices` boundary, but the live adapter still mutates legacy `ActionManager` stacks directly | Preserve undo/redo/clear behavior while moving action history toward document/app command services | `pp_app_core_history_ui_tests`; `pano_cli plan-history-operation --kind undo --undo-count 2`; `pano_cli plan-history-operation --kind clear --undo-count 2 --redo-count 1 --memory-bytes 4096`; `ctest --preset desktop-fast --build-config Debug` | Undo/redo/clear execution is owned by injected document/app history services with no legacy `ActionManager` adapter | | DEBT-0027 | Open | Modernization | Canvas draw-tool toolbar command, canvas input mode switching, and active-state planning/execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_draw`, `App::update`, `NodeCanvas`, `pano_cli plan-canvas-tool`, `pano_cli plan-canvas-tool-state`, and the `CanvasToolServices` boundary, but live adapters still mutate or read legacy `Canvas` mode state, pen picking state, touch-lock state, and transform copy/cut action objects | Preserve current toolbar, stylus eraser, and keyboard draw/erase behavior while canvas input/tools move toward an app/document command boundary | `pp_app_core_canvas_tool_ui_tests`; `pano_cli plan-canvas-tool --kind copy`; `pano_cli plan-canvas-tool-state --mode draw --picking --touch-lock`; `ctest --preset desktop-fast --build-config Debug` | Canvas tool selection, toolbar state refresh, picking, touch lock, stylus eraser/key mode switching, and transform action execution are owned by injected app/document/canvas services with no legacy toolbar/canvas adapter | -| DEBT-0028 | Open | Modernization | Canvas clear command planning and execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, `pano_cli plan-canvas-clear`, and the `DocumentCanvasClearServices` boundary, but the live adapter still calls legacy `Canvas::clear`, which records `ActionLayerClear`, clears the current layer/frame, and marks legacy `Canvas::I` unsaved | Preserve clear-current-layer behavior while canvas/document commands move toward document/app command services | `pp_app_core_document_canvas_tests`; `pano_cli plan-canvas-clear --r 0 --g 0.1 --b 0.2 --a 0.3`; `pano_cli plan-canvas-clear --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Canvas clear execution, undo recording, dirty-state updates, and clear color handling are owned by injected document/app services with no legacy canvas-clear adapter | +| DEBT-0028 | Open | Modernization | Canvas clear command planning and execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, Layer menu clear, `pano_cli plan-canvas-clear`, and the `DocumentCanvasClearServices` boundary, but the live adapter still calls legacy `Canvas::clear`, which records `ActionLayerClear`, clears the current layer/frame, and marks legacy `Canvas::I` unsaved | Preserve clear-current-layer behavior while canvas/document commands move toward document/app command services | `pp_app_core_document_canvas_tests`; `pano_cli plan-canvas-clear --r 0 --g 0.1 --b 0.2 --a 0.3`; `pano_cli plan-canvas-clear --no-canvas`; `pano_cli plan-layer-menu --command clear --current-index 1 --current-name Paint`; `ctest --preset desktop-fast --build-config Debug` | Canvas clear execution, undo recording, dirty-state updates, and clear color handling are owned by injected document/app services with no legacy canvas-clear adapter | | DEBT-0029 | Open | Modernization | Image import route planning and execution dispatch now consume pure `pp_app_core` through the File menu, `pano_cli plan-image-import`, and the `DocumentImageImportServices` boundary, but the live adapter still loads images with legacy `Image`, calls legacy `Canvas::import_equirectangular`, or configures legacy import transform mode directly | Preserve current File > Import behavior while image import moves toward document/app/asset command services | `pp_app_core_document_import_tests`; `pano_cli plan-image-import --width 4096 --height 2048`; `pano_cli plan-image-import --width 1024 --height 1024`; `ctest --preset desktop-fast --build-config Debug` | Image loading, equirectangular import, transform-placement import, and failure reporting are owned by injected document/app/asset services with File-menu callbacks acting only as adapters and no legacy image-import adapter | | DEBT-0030 | Open | Modernization | File export menu action planning and execution dispatch now consume pure `pp_app_core` through the File menu, `pano_cli plan-export-menu`, and the `DocumentExportMenuServices` boundary, but the live adapter still opens legacy export dialogs and then reaches legacy canvas/render/video export code | Preserve current export menu behavior while export command execution moves toward document/app/renderer/video services | `pp_app_core_document_export_tests`; `pano_cli plan-export-menu --kind png`; `pano_cli plan-export-menu --kind animation-mp4 --demo`; `pano_cli plan-export-menu --kind layers --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Export menu routing, license gating, target creation, image/layer/cube/depth/animation/timelapse execution, and error reporting are owned by injected document/app/renderer/video services with File-menu callbacks acting only as UI adapters and no legacy export adapter | | DEBT-0031 | Open | Modernization | Top-level File menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_file`, `pano_cli plan-file-menu`, and the `FileMenuServices` boundary, but the live adapter still invokes legacy dialogs, platform pickers, cloud code, share code, and canvas import/export paths directly | Preserve File menu behavior while app workflows move toward app/document/platform command services | `pp_app_core_file_menu_tests`; `pano_cli plan-file-menu --command save-as`; `pano_cli plan-file-menu --command import`; `pano_cli plan-file-menu --command cloud-upload`; `ctest --preset desktop-fast --build-config Debug` | File menu routing, picker dispatch, save/share/cloud/resize/export execution, and image/project import execution are owned by injected app/document/platform services with `App::init_menu_file` acting only as a UI adapter and no legacy File menu adapter | -| DEBT-0032 | Open | Modernization | Layer menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_layer`, `pano_cli plan-layer-menu`, and the `DocumentLayerMenuServices` boundary, but the live adapter still calls legacy `Canvas::clear`, `App::dialog_layer_rename`, `NodePanelLayer::merge`, and reads `Canvas::I` animation/layer state directly | Preserve existing Layer menu behavior while layer commands move toward document/app services | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-menu --command merge --current-index 2 --lower-name Paint`; `pano_cli plan-layer-menu --command rename --no-current-layer`; `ctest --preset desktop-fast --build-config Debug` | Layer clear, rename, merge-down execution, animation gating, and selected-layer state are owned by injected document/app services with Layer-menu callbacks acting only as UI adapters and no legacy Layer menu adapter | +| DEBT-0032 | Open | Modernization | Layer menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_layer`, `pano_cli plan-layer-menu`, and the `DocumentLayerMenuServices` boundary, and Layer menu clear now reuses the `DocumentCanvasClearServices` executor, but the live adapter still calls `App::dialog_layer_rename`, `NodePanelLayer::merge`, and reads `Canvas::I` animation/layer state directly | Preserve existing Layer menu behavior while layer commands move toward document/app services | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-menu --command clear --current-index 1 --current-name Paint`; `pano_cli plan-layer-menu --command merge --current-index 2 --lower-name Paint`; `pano_cli plan-layer-menu --command rename --no-current-layer`; `ctest --preset desktop-fast --build-config Debug` | Layer rename, merge-down execution, animation gating, and selected-layer state are owned by injected document/app services with Layer-menu callbacks acting only as UI adapters and no legacy Layer menu adapter | | DEBT-0033 | Open | Modernization | Tools menu planning and direct command execution dispatch now consume pure `pp_app_core` through `App::init_menu_tools`, `pano_cli plan-tools-menu`, `pano_cli plan-tools-panel`, and the `ToolsMenuServices` boundary, but live adapters still construct legacy `NodePanelFloating` panels, mutate legacy panel nodes, clear `CanvasModeGrid`, reset `NodeCanvas` camera state, open legacy shortcuts UI, and call the iOS SonarPen bridge directly | Preserve current Tools menu behavior while UI shell actions move toward app/UI/platform services | `pp_app_core_tools_menu_tests`; `pano_cli plan-tools-menu --command shortcuts`; `pano_cli plan-tools-panel --panel layers`; `pano_cli plan-tools-panel --panel animation --already-visible`; `ctest --preset desktop-fast --build-config Debug` | Tools panel creation, submenu routing, grid clear, camera reset, shortcuts dialog, and SonarPen dispatch are owned by injected app/UI/platform services with `App::init_menu_tools` acting only as a UI adapter and no legacy Tools adapter | | DEBT-0034 | Open | Modernization | About menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_about`, `pano_cli plan-about-menu`, and the `AboutMenuServices` boundary, but the live adapter still opens legacy About/manual/what's-new dialogs, invokes the injected crash hook, and runs the legacy Canvas stroke performance test directly | Preserve About menu behavior while dialogs and diagnostics move toward app/UI/platform services | `pp_app_core_about_menu_tests`; `pano_cli plan-about-menu --command news --version-major 2 --version-minor 5 --version-fix 7`; `pano_cli plan-about-menu --command performance --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | About/manual/what's-new dialog dispatch, crash-test dispatch, and performance-test execution are owned by injected app/UI/platform services with `App::init_menu_about` acting only as a UI adapter and no legacy About adapter | | DEBT-0035 | Open | Modernization | Main toolbar/status command planning and execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, `pano_cli plan-main-toolbar`, and the `MainToolbarServices` boundary, and history/canvas commands now hand off through `HistoryUiServices` and `DocumentCanvasClearServices`, but the live adapter still opens legacy open/save/settings/message-box dialogs and delegates to legacy history/canvas adapters | Preserve reachable toolbar/status behavior while app shell commands move toward app/document/UI services | `pp_app_core_main_toolbar_tests`; `pano_cli plan-main-toolbar --command undo --undo-count 2`; `pano_cli plan-main-toolbar --command clear-canvas --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Open/save/settings/message-box routing, undo/redo/clear-history execution, and canvas-clear execution are owned by injected app/document/UI services with `App::init_toolbar_main` acting only as a UI adapter and no legacy toolbar adapter | diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index d305444..0af18cf 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -499,7 +499,9 @@ legacy `Canvas` and UI layer adapter continues execution. `pano_cli plan-layer-menu` exposes app-core planning for Layer menu clear, rename, and merge-down labels/actions, and direct Layer menu commands now dispatch through `DocumentLayerMenuServices` before the legacy canvas/layer UI -adapter continues execution. +adapter continues execution. Layer menu clear now routes through the shared +`DocumentCanvasClearServices` executor before the legacy canvas-clear adapter +continues. `pano_cli plan-animation-operation` exposes app-core planning for animation frame add, duplicate, remove, duration adjustment, timeline moves, timeline goto/next/previous, onion-size updates, frame selection, no-reload playback @@ -1254,6 +1256,7 @@ Results: `pano_cli_plan_layer_rename_rejects_empty_name` passed and expose live layer-rename planning as JSON automation. - `pano_cli_plan_layer_menu_merge_smoke`, + `pano_cli_plan_layer_menu_clear_smoke`, `pano_cli_plan_layer_menu_merge_animated_blocked_smoke`, `pano_cli_plan_layer_menu_missing_selection_smoke`, and `pano_cli_plan_layer_menu_rejects_bad_state` passed and expose live Layer diff --git a/src/app_layout.cpp b/src/app_layout.cpp index c6acc4a..1ee0d4d 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -140,6 +140,33 @@ bool apply_brush_preset_plan(App& app, const std::shared_ptr& brush) return status.ok(); } +class LegacyDocumentCanvasClearServices final : public pp::app::DocumentCanvasClearServices { +public: + explicit LegacyDocumentCanvasClearServices(App& app) noexcept + : app_(app) + { + } + + void clear_current_canvas(float r, float g, float b, float a) override + { + if (!app_.canvas || !app_.canvas->m_canvas) + return; + + app_.canvas->m_canvas->clear({ r, g, b, a }); + } + +private: + App& app_; +}; + +void execute_document_canvas_clear_plan(App& app, const pp::app::DocumentCanvasClearPlan& plan) +{ + LegacyDocumentCanvasClearServices services(app); + const auto status = pp::app::execute_document_canvas_clear_plan(plan, services); + if (!status.ok()) + LOG("Canvas clear failed: %s", status.message); +} + bool apply_document_export_menu_plan(App& app, pp::app::DocumentExportMenuKind kind) { class LegacyDocumentExportMenuServices final : public pp::app::DocumentExportMenuServices { @@ -391,29 +418,7 @@ public: void clear_canvas(const pp::app::DocumentCanvasClearPlan& plan) override { - class LegacyDocumentCanvasClearServices final : public pp::app::DocumentCanvasClearServices { - public: - explicit LegacyDocumentCanvasClearServices(App& app) noexcept - : app_(app) - { - } - - void clear_current_canvas(float r, float g, float b, float a) override - { - if (!app_.canvas || !app_.canvas->m_canvas) - return; - - app_.canvas->m_canvas->clear({ r, g, b, a }); - } - - private: - App& app_; - }; - - LegacyDocumentCanvasClearServices services(app_); - const auto status = pp::app::execute_document_canvas_clear_plan(plan, services); - if (!status.ok()) - LOG("Canvas clear failed: %s", status.message); + execute_document_canvas_clear_plan(app_, plan); } void show_message_box() override @@ -581,8 +586,16 @@ public: void clear_current_layer() override { - if (app_.canvas && app_.canvas->m_canvas) - app_.canvas->m_canvas->clear(); + const auto plan = pp::app::plan_document_canvas_clear( + app_.canvas && app_.canvas->m_canvas, + 1.0F, + 1.0F, + 1.0F, + 0.0F); + if (!plan) + return; + + execute_document_canvas_clear_plan(app_, plan.value()); } void show_rename_dialog() override diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9693394..1f5e2ac 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -992,6 +992,12 @@ if(TARGET pano_cli) LABELS "app;document;integration;desktop-fast" PASS_REGULAR_EXPRESSION "\"command\":\"plan-layer-menu\".*\"command\":\"merge\".*\"action\":\"merge-with-lower-layer\".*\"label\":\"Merge with Paint\".*\"fromIndex\":2.*\"toIndex\":1") + add_test(NAME pano_cli_plan_layer_menu_clear_smoke + COMMAND pano_cli plan-layer-menu --command clear --current-index 1 --current-name Paint) + set_tests_properties(pano_cli_plan_layer_menu_clear_smoke PROPERTIES + LABELS "app;document;integration;desktop-fast" + PASS_REGULAR_EXPRESSION "\"command\":\"plan-layer-menu\".*\"command\":\"clear\".*\"action\":\"clear-current-layer\".*\"label\":\"Clear Layer Paint\"") + add_test(NAME pano_cli_plan_layer_menu_merge_animated_blocked_smoke COMMAND pano_cli plan-layer-menu --command merge --current-index 2 --current-name Ink --lower-name Paint --animation-duration 3) set_tests_properties(pano_cli_plan_layer_menu_merge_animated_blocked_smoke PROPERTIES