1142 lines
52 KiB
Markdown
1142 lines
52 KiB
Markdown
# Modernization Task Tracker
|
|
|
|
Status: live
|
|
Last updated: 2026-06-16
|
|
|
|
This file now tracks only active architecture work.
|
|
Completed, blocked, and superseded task history moved to
|
|
`docs/modernization/tasks-done.md`.
|
|
|
|
## Operating Rules
|
|
|
|
- Keep this file short. If a task is done, blocked for a long time, or no
|
|
longer relevant, move it to `tasks-done.md` instead of letting the active
|
|
queue sprawl.
|
|
- Keep tasks architecture-first. Build, test, tool, planner, CLI, and
|
|
automation cleanup are secondary unless they directly unblock or accompany a
|
|
real ownership transfer in the live app.
|
|
- Prefer coherent bundles over tiny adapter nibbles. Each task here should make
|
|
visible progress in a hotspot file or a legacy target, not just add another
|
|
seam around the same code.
|
|
- Use legacy-target shrinkage and hotspot reduction as the main progress signal.
|
|
If a slice does not materially reduce a large file or move code out of
|
|
`PP_PANOPAINTER_*` or `PP_LEGACY_*`, it is probably not first-priority work.
|
|
- Do not restart Vulkan, Metal, or package-only work until the app shell,
|
|
platform split, UI split, and canvas/render split are materially thinner.
|
|
|
|
## Current Architecture Read
|
|
|
|
- The extracted pure targets are real and useful: `pp_foundation`,
|
|
`pp_assets`, `pp_paint`, `pp_document`, `pp_renderer_api`, `pp_renderer_gl`,
|
|
`pp_paint_renderer`, `pp_ui_core`, `pp_platform_api`, and `pp_app_core`.
|
|
- The remaining app still lives mostly in legacy containment or thick shell
|
|
targets:
|
|
- `pp_panopainter_ui`: 34 files, about 9102 lines
|
|
- `panopainter_app`: 29 files, about 8817 lines
|
|
- `pp_legacy_paint_document`: 7 files, about 5709 lines
|
|
- `pp_legacy_app`: 20 files, about 4368 lines
|
|
- `pp_legacy_ui_core`: 20 files, about 3770 lines
|
|
- The biggest single-file choke points are still `src/canvas.cpp`,
|
|
`src/app_layout.cpp`, `src/canvas_modes.cpp`, `src/node.cpp`,
|
|
`src/main.cpp`, `src/node_panel_brush.cpp`, `src/node_stroke_preview.cpp`,
|
|
`src/node_canvas.cpp`, `src/app.cpp`, and `src/app_dialogs.cpp`.
|
|
- The platform boundary is not finished:
|
|
- `pp_platform_api` still compiles Apple implementation files
|
|
- `platform_apple` no longer reaches `App::I` directly, and Linux FPS title
|
|
reporting now uses an injected callback, but retained Apple bridging and
|
|
broader platform-to-app singleton reach are still open in
|
|
`platform_legacy`
|
|
- `platform_legacy` is still part of the live app shell
|
|
- The app runtime boundary is not finished:
|
|
- render/UI queues are static `App` state
|
|
- app-facing detached launches are no longer the main issue; preview and
|
|
recording now use owned worker threads, but those families still rely on
|
|
retained static/global ownership and ad hoc runtime control
|
|
- canvas async import/export/save/open now run through an owned in-file
|
|
worker, but their retained progress execution is still not a clean runtime
|
|
service boundary
|
|
- thread-affinity rules are enforced by convention and asserts instead of
|
|
explicit runtime contracts
|
|
- The UI ownership boundary is not finished:
|
|
- base `Node` still carries raw parent/manager pointers beside shared handles
|
|
- callback captures still frequently close over retained nodes and `App::I`
|
|
- checked overlay/lifetime helpers exist but are not yet the default scene
|
|
graph model
|
|
- Historical score/progress claims are not useful for prioritization here.
|
|
The live app still mostly runs through the same shell and hotspot files, so
|
|
the queue is now ordered by code movement instead.
|
|
|
|
## Active Bundles
|
|
|
|
### Priority Order
|
|
|
|
- `P0`: shrink the biggest live app hotspots and legacy ownership first
|
|
- `P0`: make app runtime, UI ownership, and renderer access safe enough for
|
|
future backend work
|
|
- `P1`: finish supporting boundaries that unblock or stabilize the thinner app
|
|
- `P2`: only then clean up the remaining workflow adapters
|
|
|
|
### Bundle 1 - Break The Canvas And Preview Hotspots
|
|
|
|
Priority: `P0`
|
|
|
|
Why this bundle is first:
|
|
This is where the biggest block of real app behavior still lives.
|
|
If these files stay large and stateful, the rest of the modernization still
|
|
looks like a wrapper around the old renderer shell.
|
|
|
|
#### ARC-RND-001 - Split `canvas.cpp` Into Document State And Render Execution Shells
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
`src/canvas.cpp` is still the biggest single architectural blocker at about
|
|
429 lines, with `src/canvas_modes.cpp` now materially thinner and the next
|
|
remaining render-shell pressure shifting toward preview/canvas nodes.
|
|
|
|
Current slice:
|
|
- Canvas state-management helpers for picking, clear/clear-all, layer
|
|
add/remove/order/lookups, animation frame control, resize, and snapshot
|
|
save/restore now live in `src/legacy_canvas_state_services.cpp` instead of
|
|
staying inline in `src/canvas.cpp`, but the file still owns the larger
|
|
document-plus-render shell.
|
|
- Canvas import/export/save/open/thumbnail ownership now lives in
|
|
`src/legacy_canvas_document_io_services.cpp` instead of staying inline in
|
|
`src/canvas.cpp`, which materially reduces document IO ownership in the live
|
|
render shell.
|
|
- Canvas point-trace, unproject, project2D, face-to-shape, and camera
|
|
push/pop/get/set helpers now also live in
|
|
`src/legacy_canvas_projection_services.*` instead of staying inline in
|
|
`src/canvas.cpp`, which trims another coherent non-UI state/query pocket
|
|
from the live canvas shell.
|
|
- `Canvas::draw_objects_direct(...)` and `Canvas::draw_objects(...)` now also
|
|
live in `src/legacy_canvas_object_draw_services.*` instead of staying inline
|
|
in `src/canvas.cpp`, which trims another coherent object-draw and
|
|
viewport-state execution pocket from the live canvas shell.
|
|
- `Canvas::stroke_draw_samples(...)`, `Canvas::stroke_commit()`, and the
|
|
larger stroke sample/commit execution family now also live in
|
|
`src/legacy_canvas_stroke_commit_services.*` instead of staying inline in
|
|
`src/canvas.cpp`, which trims another large retained stroke-render pocket
|
|
from the live canvas shell.
|
|
- Shared canvas-mode GL wrappers plus the `CanvasModeBasicCamera` and
|
|
`CanvasModeCamera` input handlers now also live in
|
|
`src/legacy_canvas_mode_helpers.*` instead of staying inline in
|
|
`src/canvas_modes.cpp`, which trims another coherent retained canvas-view
|
|
interaction pocket from the broader canvas/render hotspot family.
|
|
- The `CanvasModeTransform` interaction family now also lives in
|
|
`src/legacy_canvas_mode_transform.cpp` instead of staying inline in
|
|
`src/canvas_modes.cpp`, which materially thins another retained
|
|
transform-mode pocket from the broader canvas/render hotspot family.
|
|
- The live `Canvas::stroke_draw()` orchestration now also lives in
|
|
`src/legacy_canvas_stroke_live_services.cpp` instead of staying inline in
|
|
`src/canvas.cpp`, which materially thins another large retained live
|
|
stroke-render pocket from the canvas shell.
|
|
- `Canvas::layer_merge(...)`, `Canvas::flood_fill(...)`, and
|
|
`Canvas::FloodData::apply()` now also live in
|
|
`src/legacy_canvas_layer_services.cpp` instead of staying inline in
|
|
`src/canvas.cpp`, which trims another coherent retained layer/fill workflow
|
|
pocket from the live canvas shell.
|
|
- `Canvas::stroke_end(...)`, `Canvas::stroke_cancel(...)`,
|
|
`Canvas::stroke_draw_mix(...)`, `Canvas::stroke_draw_project(...)`,
|
|
`Canvas::stroke_update(...)`, and `Canvas::stroke_start(...)` now also live
|
|
in `src/legacy_canvas_stroke_runtime_services.*` instead of staying inline in
|
|
`src/canvas.cpp`, which trims another large retained live stroke/runtime
|
|
pocket from the canvas shell.
|
|
- `Canvas::draw_merge(...)`, the temporary-paint and merge-branch
|
|
orchestration helpers, final-plane composite, timelapse commit, create,
|
|
destroy, clear-context, and camera accessors now also live in
|
|
`src/legacy_canvas_render_shell_services.*` instead of staying inline in
|
|
`src/canvas.cpp`, which trims another large retained render/context shell
|
|
from the live canvas owner.
|
|
- The `CanvasModePen` and `CanvasModeLine` interaction families now also live
|
|
in `src/legacy_canvas_mode_pen_line.cpp` instead of staying inline in
|
|
`src/canvas_modes.cpp`, which materially thins another retained pen/line
|
|
interaction pocket from the broader canvas/render hotspot family.
|
|
- The `CanvasModeMaskFree` and `CanvasModeMaskLine` interaction families now
|
|
also live in `src/legacy_canvas_mode_mask.cpp` instead of staying inline in
|
|
`src/canvas_modes.cpp`, which materially thins another retained mask-tool
|
|
interaction pocket from the broader canvas/render hotspot family.
|
|
|
|
Write scope:
|
|
- `src/canvas.cpp`
|
|
- `src/canvas_layer.cpp`
|
|
- `src/canvas_actions.cpp`
|
|
- `src/legacy_canvas_*services*.h`
|
|
- new `src/legacy_canvas_*.*` helpers if needed
|
|
|
|
Read scope:
|
|
- `src/document/*`
|
|
- `src/paint_renderer/*`
|
|
- `src/renderer_api/*`
|
|
|
|
Done when:
|
|
- `canvas.cpp` stops being the place where document state, render sequencing,
|
|
history reads, and GL-side execution all meet.
|
|
- Non-render state/query/update helpers move out first.
|
|
- The remaining file reads as a render shell with explicit helper boundaries.
|
|
- The touched slice makes a substantial reduction in inline ownership, not just
|
|
a thin wrapper extraction.
|
|
|
|
Mini-model packet:
|
|
- Do not try to delete `Canvas` in one slice.
|
|
- Prioritize ownership separation over clever abstractions.
|
|
- Aim for a visible reduction in `canvas.cpp`, on the order of hundreds of
|
|
lines, not a token helper extraction.
|
|
|
|
#### ARC-RND-002 - Isolate Preview And Canvas View Render Execution
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
`src/node_stroke_preview.cpp` and `src/node_canvas.cpp` still own a large amount
|
|
of live preview/canvas render sequencing around the renderer boundary.
|
|
|
|
Current slice:
|
|
- `NodeStrokePreview` final composite plus preview-texture copy now route
|
|
through `legacy_node_stroke_preview_execution_services.h`, but the preview
|
|
node still owns most live-pass and retained GL resource execution.
|
|
- `NodeStrokePreview` render-target setup plus immediate-pass sequence
|
|
orchestration now also route through
|
|
`legacy_node_stroke_preview_execution_services.h`, and duplicate render-
|
|
target setup was removed from `render_to_image()` and the queued worker path,
|
|
but the preview node still owns broader live-pass state and thread-facing
|
|
orchestration.
|
|
- `NodeStrokePreview` main live-pass request assembly and preview framebuffer-
|
|
copy setup now also route through
|
|
`legacy_node_stroke_preview_execution_services.h`, which trims another
|
|
coherent pass-setup block from `src/node_stroke_preview.cpp`, but broader
|
|
preview-pass orchestration is still inline.
|
|
- `NodeStrokePreview::draw_stroke_immediate()` immediate preview pass
|
|
sequencing now also routes through the private
|
|
`execute_stroke_draw_immediate_pass_sequence(...)` helper, which removes
|
|
another live orchestration block from the node even though worker/readback
|
|
flow still remains in the file.
|
|
- `NodeStrokePreview` stroke preparation, dual-brush setup, and live-pass
|
|
request assembly now also route through retained preview execution helpers,
|
|
which trims another coherent setup pocket from
|
|
`src/node_stroke_preview.cpp` even though worker/readback ownership and
|
|
broader preview flow still remain inline.
|
|
- The remaining immediate preview pass shell in
|
|
`NodeStrokePreview::draw_stroke_immediate()` now also routes through
|
|
`execute_legacy_node_stroke_preview_draw_immediate_shell(...)`, which
|
|
materially reduces the live preview-pass body even though worker/readback
|
|
ownership still remains inline.
|
|
- `NodeCanvas` merged-path per-plane merged-texture draw execution now also
|
|
routes through `execute_legacy_canvas_draw_merge_layer_texture(...)`.
|
|
- `NodeCanvas` merged-path and non-blend checkerboard background setup now also
|
|
route through `execute_legacy_canvas_draw_merge_background_setup(...)`.
|
|
- `NodeCanvas` cache-to-screen checkerboard-plane callback setup now also routes
|
|
through a retained helper in `legacy_canvas_draw_merge_services.h`.
|
|
- `NodeCanvas` display resolve plus cache-to-screen checkerboard/cache-texture
|
|
composite now route through `legacy_canvas_draw_merge_services.h`.
|
|
- `NodeCanvas` smoothing-mask overlay, smoothing-mask face pass, grid keepalive
|
|
draw, heightmap draw, and current-mode draw now also route through
|
|
`execute_legacy_canvas_draw_merge_post_draw(...)`, but broader canvas draw
|
|
orchestration is still inline.
|
|
- `NodeCanvas` heightmap draw callback setup now also routes through
|
|
`make_legacy_canvas_draw_merge_heightmap_draw(...)`, but the node still owns
|
|
current-mode traversal and broader post-draw orchestration.
|
|
- `NodeCanvas` current-mode draw callback setup now also routes through
|
|
`make_legacy_canvas_draw_merge_current_modes_draw(...)`, and grid-mode
|
|
callback setup now also routes through
|
|
`make_legacy_canvas_draw_merge_grid_modes_draw(...)`, but broader post-draw
|
|
orchestration is still inline.
|
|
- `NodeCanvas` checkerboard background plane callback setup now also routes
|
|
through `make_legacy_canvas_draw_merge_background_checkerboard_plane(...)`,
|
|
but the node still owns broader live layer traversal and renderer-state
|
|
sequencing.
|
|
- `NodeCanvas` merged-path per-plane merged-texture draw callback setup now
|
|
also routes through `make_legacy_canvas_draw_merge_layer_texture_draw(...)`,
|
|
but the node still owns broader live layer traversal and renderer-state
|
|
sequencing.
|
|
- `NodeCanvas` non-`draw_merged` per-frame layer draw callback setup now also
|
|
routes through `make_legacy_canvas_draw_merge_layer_frame_draw(...)`, but
|
|
the node still owns broader live layer traversal and renderer-state
|
|
sequencing.
|
|
- `NodeCanvas` smoothing-mask face shader setup plus per-face draw execution
|
|
now also route through
|
|
`execute_legacy_canvas_draw_merge_smask_faces(...)`, but the node still owns
|
|
the broader canvas draw flow and renderer-state sequencing around that seam.
|
|
- `NodeCanvas` non-`draw_merged` per-layer/per-plane retained draw execution
|
|
now also routes through `execute_legacy_canvas_draw_merge_layer_plane(...)`,
|
|
but the node still owns substantial live layer traversal and renderer state
|
|
orchestration.
|
|
- `NodeCanvas` post-draw callback assembly now also routes through
|
|
`execute_legacy_canvas_draw_merge_post_draw_callbacks(...)`, and the
|
|
remaining per-layer render-path orchestration now also routes through
|
|
`execute_legacy_canvas_draw_merge_layer_path(...)`, but the node still owns
|
|
broader draw-loop and renderer-state shell sequencing.
|
|
- `NodeCanvas` outer non-`draw_merged` layer/plane traversal, onion-range
|
|
failure handling, and visit payload setup now also route through
|
|
`execute_legacy_canvas_draw_layer_traversal(...)`.
|
|
- `NodeCanvas` non-`draw_merged` per-layer temporary erase/paint, layer-texture,
|
|
and blend setup now also route through
|
|
`make_legacy_canvas_draw_merge_layer_path_gl_execution(...)`, but the node
|
|
still owned the remaining draw lambdas and broader renderer-state shell.
|
|
- `NodeCanvas` now routes that remaining non-`draw_merged` per-layer blend,
|
|
composite, debug-outline, and frame callback assembly through the local
|
|
`make_node_canvas_layer_path_execution(...)` helper, which materially thins
|
|
`NodeCanvas::draw()` even though the broader draw loop still lives in
|
|
`src/node_canvas.cpp`.
|
|
- `NodeCanvas` post-draw callback assembly, smoothing-mask face execution, and
|
|
optional display resolve now also route through
|
|
`execute_node_canvas_draw_merge_tail(...)`, which trims another live tail
|
|
block from `NodeCanvas::draw()` even though the broader outer draw shell is
|
|
still inline.
|
|
- `NodeCanvas` non-`draw_merged` cache/background/layer-traversal/cache-
|
|
composite shell now also routes through
|
|
`execute_legacy_canvas_draw_unmerged_shell(...)`, which removes another
|
|
coherent orchestration block from `NodeCanvas::draw()` even though the
|
|
broader node draw loop still lives in `src/node_canvas.cpp`.
|
|
- `NodeCanvas` unmerged-path onion-range planning, plane filtering, per-layer
|
|
visit handling, and per-visit layer-path execution now also route through
|
|
`execute_legacy_canvas_draw_unmerged_node_canvas_shell(...)`, which trims
|
|
another outer draw-shell block even though the broader node draw loop still
|
|
lives in `src/node_canvas.cpp`.
|
|
- `NodeCanvas` broader unmerged cache/viewport/background/composite pass setup
|
|
now also routes through
|
|
`execute_legacy_canvas_draw_unmerged_node_canvas_pass(...)`, which removes
|
|
another coherent outer-shell block even though the broader node draw loop
|
|
still lives in `src/node_canvas.cpp`.
|
|
- `NodeCanvas::draw()` setup, merged-pass shell, and unmerged-pass shell now
|
|
also route through `prepare_legacy_node_canvas_draw_setup(...)`,
|
|
`execute_legacy_canvas_draw_node_canvas_shell(...)`,
|
|
`execute_legacy_canvas_draw_merged_pass(...)`, and
|
|
`execute_legacy_canvas_draw_node_canvas_unmerged_pass(...)`, which
|
|
materially shortens the live `NodeCanvas::draw()` body even though the file
|
|
itself is still large.
|
|
- `NodeCanvas::draw()` unmerged-pass blend-gate query, layer-orientation
|
|
assembly, and callback wiring into
|
|
`execute_legacy_canvas_draw_node_canvas_unmerged_pass(...)` now also route
|
|
through `execute_node_canvas_draw_unmerged_pass(...)`, which trims another
|
|
coherent unmerged draw-orchestration block from the live node even though
|
|
the file size remains roughly flat.
|
|
- `NodeCanvas::draw()` merged-pass callback wiring and pass setup now also
|
|
route through `execute_node_canvas_draw_merged_pass(...)`, which trims
|
|
another coherent merged draw-orchestration block from the live node even
|
|
though the broader draw loop still remains inline.
|
|
- `NodeCanvas::handle_event()` now also routes through the local
|
|
`execute_node_canvas_handle_event(...)` helper, which trims another coherent
|
|
input-routing block from `src/node_canvas.cpp` even though the node still
|
|
owns broader canvas/controller behavior.
|
|
- `NodeCanvas` restore/clear context, resize handling, camera reset, buffer
|
|
creation, cursor visibility/update, tick, and destroy ownership now also
|
|
live in `src/legacy_node_canvas_state_services.*` instead of staying inline
|
|
in `src/node_canvas.cpp`, which materially thins another retained
|
|
state/control pocket without reopening the draw path.
|
|
- `NodeStrokePreview` retained lifecycle, worker-thread shell, render-to-image,
|
|
on-screen handling, and preview texture ownership now also live in
|
|
`src/legacy_node_stroke_preview_runtime_services.cpp` instead of staying
|
|
inline in `src/node_stroke_preview.cpp`, which materially thins the preview
|
|
node around its runtime-facing shell even though live pass execution still
|
|
remains.
|
|
- The remaining live render/pass orchestration in
|
|
`NodeStrokePreview::draw_stroke_immediate()` now also lives in
|
|
`src/legacy_node_stroke_preview_draw_services.*` instead of staying inline in
|
|
`src/node_stroke_preview.cpp`, which trims another coherent preview
|
|
draw-pass pocket while preserving the current runtime-facing shell.
|
|
- `NodeCanvas::init()` plus the remaining `NodeCanvas::draw()` outer shell now
|
|
also live in `src/legacy_node_canvas_draw_services.*` instead of staying
|
|
inline in `src/node_canvas.cpp`, which materially reduces the live node to a
|
|
thinner controller surface around event routing and state wrappers.
|
|
|
|
Write scope:
|
|
- `src/node_stroke_preview.cpp`
|
|
- `src/node_canvas.cpp`
|
|
- `src/legacy_node_stroke_preview_execution_services.h`
|
|
- `src/legacy_canvas_stroke_preview_services.h`
|
|
- `src/paint_renderer/compositor.*`
|
|
|
|
Read scope:
|
|
- `src/renderer_api/*`
|
|
- `src/renderer_gl/*`
|
|
|
|
Done when:
|
|
- Preview/canvas files stop carrying large inline render-pass orchestration.
|
|
- Concrete GL texture/bind/copy work is pushed behind explicit renderer-facing
|
|
service seams.
|
|
- The next renderer backend would have one place to implement preview/canvas
|
|
execution contracts instead of reading node code.
|
|
- The touched node files are materially smaller and less stateful afterward.
|
|
|
|
Mini-model packet:
|
|
- Keep the existing `pp_paint_renderer` planner surface and extend it only when
|
|
the node files clearly need a missing renderer-owned callback contract.
|
|
- Prefer deleting inline orchestration over adding another planner layer around
|
|
the same node code.
|
|
|
|
#### ARC-RND-003 - Replace App-Facing `Texture2D`/`RTT` Use With Renderer API Contracts
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
Future Vulkan and Metal work needs the live app to stop treating retained
|
|
OpenGL resource classes as the renderer boundary.
|
|
|
|
Write scope:
|
|
- `src/node_canvas.cpp`
|
|
- `src/node_stroke_preview.cpp`
|
|
- `src/canvas.cpp`
|
|
- `src/texture.*`
|
|
- `src/rtt.*`
|
|
- `src/renderer_api/*`
|
|
- `src/paint_renderer/*`
|
|
|
|
Read scope:
|
|
- `src/renderer_gl/*`
|
|
- `src/legacy_gl_*dispatch.h`
|
|
- `src/app_shaders.cpp`
|
|
|
|
Done when:
|
|
- App/UI-facing render work talks to `pp_renderer_api` resource and command
|
|
abstractions or narrow retained renderer services, not directly to
|
|
`Texture2D`, `RTT`, or GL dispatch helpers.
|
|
- The remaining `Texture2D`/`RTT` references are contained in retained GL
|
|
backend/adapters with explicit removal conditions.
|
|
- Canvas, preview, and export paths expose the same execution contract a Vulkan
|
|
or Metal implementation would need.
|
|
- The touched slice shrinks app/UI render ownership instead of only renaming
|
|
wrappers.
|
|
|
|
Mini-model packet:
|
|
- Do not start a Vulkan or Metal backend in this task.
|
|
- Use existing `pp_renderer_api` and `pp_paint_renderer` contracts first.
|
|
- Treat direct GL classes in UI/app code as debt to move behind backend-owned
|
|
services.
|
|
|
|
### Bundle 2 - Thin The App Shell
|
|
|
|
Priority: `P0`
|
|
|
|
Why this bundle is next:
|
|
`app_layout.cpp`, `app_dialogs.cpp`, and `app.cpp` still make the modernized
|
|
targets look like helpers under one old monolith.
|
|
|
|
#### ARC-APP-001 - Split `app_layout.cpp` Into UI Binding Modules
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
`src/app_layout.cpp` is still a 125-line mixed file that builds menus,
|
|
attaches callbacks, computes planner inputs, and mutates UI state directly.
|
|
|
|
Current slice:
|
|
- Tools-menu UI binding, including the nested panels/options submenu wiring,
|
|
now lives in `src/app_layout_tools_menu.cpp`, and `App::init_menu_tools()`
|
|
is now a thin call-through, but file/about/layer/sidebar and broader layout
|
|
composition are still inline in `src/app_layout.cpp`.
|
|
- File-menu UI binding, including the export submenu wiring, now also lives in
|
|
`src/app_layout_file_menu.cpp`, and `App::init_menu_file()` is now a thin
|
|
call-through, but about/layer/sidebar and broader layout composition are
|
|
still inline in `src/app_layout.cpp`.
|
|
- About-menu and layer-menu wiring now also live in
|
|
`src/app_layout_about_layer_menu.cpp`, and `App::init_menu_about()` plus
|
|
`App::init_menu_layer()` are now thin call-throughs, but edit/sidebar and
|
|
broader layout composition are still inline in `src/app_layout.cpp`.
|
|
- Sidebar panel binding plus popup wiring now also live in
|
|
`src/app_layout_sidebar.cpp`, and `App::init_sidebar()` is now a thin
|
|
call-through, but edit-menu wiring and broader layout composition are still
|
|
inline in `src/app_layout.cpp`.
|
|
- Main-toolbar binding now also lives in `src/app_layout_main_toolbar.cpp`,
|
|
and `App::init_toolbar_main()` is now a thin call-through, but edit-menu
|
|
wiring and broader layout composition are still inline in `src/app_layout.cpp`.
|
|
- Edit-menu binding now also lives in `src/app_layout_edit_menu.cpp`, and
|
|
`App::init_menu_edit()` is now a thin call-through, but draw-toolbar,
|
|
brush-refresh, and broader layout composition are still inline in
|
|
`src/app_layout.cpp`.
|
|
- UI-direction plus persisted floating/docked panel-state ownership now also
|
|
lives in `src/app_layout_ui_state.cpp`, and `src/app_layout.cpp` is down to
|
|
the remaining draw-toolbar, brush-refresh, and layout/bootstrap composition.
|
|
- Draw-toolbar binding now also lives in `src/app_layout_draw_toolbar.cpp`, and
|
|
`src/app_layout.cpp` is down to the remaining brush-refresh and
|
|
layout/bootstrap composition.
|
|
- Brush-refresh now also lives in `src/app_layout_brush.cpp`, and
|
|
`src/app_layout.cpp` is down to the remaining layout/bootstrap composition.
|
|
- Layout bootstrap plus reload/load continuation wiring now also lives in
|
|
`src/app_layout_bootstrap.cpp`, and `src/app_layout.cpp` is down to thin
|
|
call-through entrypoints plus the remaining local helper pocket.
|
|
|
|
Write scope:
|
|
- `src/app_layout.cpp`
|
|
- `src/legacy_app_shell_services.*`
|
|
- new `src/app_layout_*.*` or `src/legacy_*_ui_services.*` files if needed
|
|
|
|
Read scope:
|
|
- `src/app_core/*menu*.h`
|
|
- `src/app_core/brush_ui.h`
|
|
- `src/app_core/document_layer.h`
|
|
- `src/app_core/main_toolbar.h`
|
|
|
|
Done when:
|
|
- `app_layout.cpp` becomes a composition/binding file instead of a giant mixed
|
|
controller.
|
|
- File-menu, toolbar, tools-menu, about-menu, and layer-menu wiring each live
|
|
in named helper modules or services.
|
|
- The split follows planner/service boundaries already present in `pp_app_core`.
|
|
- The touched slice materially shrinks the file instead of just moving a few
|
|
lambdas around.
|
|
|
|
Mini-model packet:
|
|
- Start by carving out one coherent family at a time, not by reshuffling lines.
|
|
- Preserve the current planner calls; the goal is ownership, not new behavior.
|
|
- Aim for a real file-size drop, not cosmetic decomposition.
|
|
|
|
#### ARC-APP-002 - Split `app_dialogs.cpp` Into Workflow Adapters And Widget Openers
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
`src/app_dialogs.cpp` still mixes document workflow decisions, export routing,
|
|
dialog construction, and overlay ownership in one 168-line shell.
|
|
|
|
Current slice:
|
|
- Informational overlay opener paths for user manual, changelog, about,
|
|
what's-new, and shortcuts now live in `src/app_dialogs_info_openers.cpp`,
|
|
and the corresponding `App::dialog_*` entrypoints are now thin call-throughs,
|
|
but document/export workflow and retained dialog execution are still inline in
|
|
`src/app_dialogs.cpp`.
|
|
- Export, video-export, and PPBR export entrypoints now also live in
|
|
`src/app_dialogs_export.cpp`, and the corresponding `App::dialog_*`
|
|
entrypoints are now thin call-throughs, but new/open/save/browse/resize and
|
|
retained dialog execution are still inline in `src/app_dialogs.cpp`.
|
|
- New/open/save/browse/resize workflow entrypoints now also live in
|
|
`src/app_dialogs_workflow.cpp`, and `src/app_dialogs.cpp` is down to the
|
|
remaining thin entrypoints plus layer-rename retained dialog glue.
|
|
|
|
Write scope:
|
|
- `src/app_dialogs.cpp`
|
|
- `src/legacy_app_dialog_services.*`
|
|
- `src/legacy_document_session_services.*`
|
|
- `src/legacy_document_open_services.*`
|
|
- `src/legacy_document_export_services.*`
|
|
|
|
Read scope:
|
|
- `src/app_core/app_dialog.h`
|
|
- `src/app_core/document_session.h`
|
|
- `src/app_core/document_export.h`
|
|
|
|
Done when:
|
|
- `app_dialogs.cpp` is reduced to thin entrypoints plus named helper modules.
|
|
- Dialog creation/opening is clearly separated from document/export workflow
|
|
routing.
|
|
- The remaining direct node-specific code is isolated to retained dialog
|
|
adapters.
|
|
- The slice removes a meaningful amount of mixed live ownership from
|
|
`app_dialogs.cpp`.
|
|
|
|
Mini-model packet:
|
|
- Preserve existing planner usage.
|
|
- Prefer new narrow helper files over leaving another giant dialog utility file.
|
|
- Do not spend time extending dialog planners or CLI surfaces unless the live
|
|
adapter gets thinner in the same slice.
|
|
|
|
#### ARC-APP-003 - Reduce `app.cpp` To Frame, Queue, And Composition Shell
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
`src/app.cpp` still carries startup, frame flow, queue draining, recording,
|
|
and composition logic in one 171-line file.
|
|
|
|
Current slice:
|
|
- UI observer math now routes through `src/legacy_app_frame_services.cpp`
|
|
instead of staying inline in `src/app.cpp`.
|
|
- The repeated UI child traversal in `App::draw()` now routes through the same
|
|
retained helper.
|
|
- Canvas toolbar refresh in `App::update()` now also routes through that helper
|
|
file, materially shrinking `src/app.cpp`.
|
|
- `App::draw(...)`, `App::update(...)`, `App::terminate(...)`,
|
|
`App::update_memory_usage(...)`, `App::update_rec_frames(...)`,
|
|
`App::res_from_index(...)`, `App::res_to_index(...)`,
|
|
`App::res_to_string(...)`, `App::rec_clear(...)`, `App::rec_start(...)`,
|
|
`App::rec_stop(...)`, `App::rec_export(...)`, `App::rec_loop(...)`, and
|
|
`App::render_thread_tick(...)` now also live in
|
|
`src/legacy_app_runtime_shell_services.cpp` instead of staying inline in
|
|
`src/app.cpp`, which materially thins the remaining frame/runtime shell.
|
|
- `App::create(...)`, `App::initAssets(...)`, `App::initLog(...)`, and
|
|
`App::init(...)` now also live in `src/legacy_app_startup_services.*`
|
|
instead of staying inline in `src/app.cpp`, which reduces the remaining app
|
|
file to a thinner retained composition surface around startup and runtime
|
|
delegation.
|
|
|
|
Write scope:
|
|
- `src/app.cpp`
|
|
- `src/legacy_app_startup_services.*`
|
|
- `src/legacy_recording_services.*`
|
|
- small new `src/app_runtime_*.*` helpers if needed
|
|
|
|
Read scope:
|
|
- `src/app_core/app_frame.h`
|
|
- `src/app_core/app_shutdown.h`
|
|
- `src/app_core/app_startup.h`
|
|
- `src/app_core/document_recording.h`
|
|
|
|
Done when:
|
|
- `app.cpp` reads like a shell over `pp_app_core` planners and named retained
|
|
services.
|
|
- Startup, frame/update, queue/thread, and recording glue are split into named
|
|
helpers instead of living inline.
|
|
- `App` keeps ownership of composition state only where it truly has to.
|
|
- The file becomes materially thinner in the same slice.
|
|
|
|
Mini-model packet:
|
|
- Keep thread behavior unchanged.
|
|
- Split by responsibility boundaries already present in `pp_app_core`.
|
|
- Prefer moving live ownership out over creating new planner wrappers.
|
|
|
|
#### ARC-APP-004 - Move Render/UI Queues Into An Owned App Runtime Service
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
`App` still owns static render/UI queues, mutexes, condition variables, and
|
|
thread ids. That makes thread safety hard to reason about and keeps platform
|
|
entrypoints coupled to the singleton.
|
|
|
|
Current slice:
|
|
- render/UI queues, mutexes, condition variables, and thread identity already
|
|
live in `AppRuntime`
|
|
- `AppRuntime` render/UI worker ownership now also uses `std::jthread` plus
|
|
explicit stop requests instead of raw `std::thread`
|
|
- Windows main-loop run-state and VR worker coordination flags in `main.cpp`
|
|
now use `std::atomic` ownership instead of unsynchronized globals
|
|
- `main.cpp` Win32 window handles, GL task/mutex state, splash-dialog state,
|
|
stylus timers, and VR worker state now sit behind one retained local state
|
|
object instead of separate file-scope globals
|
|
- the splash-screen dialog loop, HWND ownership, and bitmap setup now also live
|
|
in `src/platform_windows/windows_splash.cpp` instead of `src/main.cpp`, and
|
|
`main.cpp` now just owns the helper lifecycle
|
|
- Win32 async GL/context lock state now lives in
|
|
`src/platform_windows/windows_platform_services.cpp` instead of `main.cpp`
|
|
retained state, and `main.cpp` only seeds that platform-owned context handle
|
|
pair during initialization and context recreation
|
|
- `main.cpp` main-thread queued task state now lives under
|
|
`src/platform_windows/windows_platform_services.cpp` instead of staying in
|
|
the entry TU
|
|
- Win32 pointer API loading, stylus/ink timer ownership and decay, `WT_PACKET`
|
|
reset, and `WM_POINTERUPDATE` pen/touch handling now live in
|
|
`src/platform_windows/windows_stylus_input.cpp` instead of `src/main.cpp`,
|
|
but broader retained Win32 shell state is still open
|
|
- the retained Win32 VR/HMD shell, including worker start/stop and VR FPS
|
|
state, now routes through `src/platform_windows/windows_vr_shell.h` instead
|
|
of staying inline in `src/main.cpp`, but broader retained Win32 shell state
|
|
is still open
|
|
- RenderDoc startup/frame capture, SHCore DPI bootstrap, Win32 error-string
|
|
conversion, `UnadjustWindowRectEx`, and GL debug pre/post callbacks now also
|
|
live in `src/platform_windows/windows_bootstrap_helpers.cpp` instead of
|
|
`src/main.cpp`
|
|
- the WMI startup probe now also lives in
|
|
`src/platform_windows/windows_bootstrap_helpers.cpp` instead of
|
|
`src/main.cpp`
|
|
- Win32 lifecycle running-state, close/shutdown handling, FPS title update and
|
|
wakeup posting, stylus frame update, window preference save, and VR
|
|
lifecycle wrappers now also live in
|
|
`src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp`
|
|
- Win32 startup/window/bootstrap flow now also lives in
|
|
`src/platform_windows/windows_bootstrap_helpers.*` for runtime-data
|
|
discovery, startup-state initialization, window creation, pixel-format
|
|
setup, GL loader init, runtime-info logging, and core-context upgrade
|
|
sequencing
|
|
- BugTrap/SEH recovery setup now also lives in
|
|
`src/platform_windows/windows_bootstrap_helpers.cpp` instead of
|
|
`src/main.cpp`
|
|
- the Win32 window procedure and retained message-handling shell now also live
|
|
in `src/platform_windows/windows_window_shell.*` instead of `src/main.cpp`,
|
|
which materially thins the entry file even though broader runtime/entrypoint
|
|
composition is still open
|
|
- the remaining interactive Win32 runtime pocket for touch registration,
|
|
render/UI thread startup, debug GL callback hookup, Wintab init/skip, icon
|
|
setup, placement restore, optional VR start, splash dismissal, message
|
|
loop, and shutdown cleanup now also lives in
|
|
`src/platform_windows/windows_runtime_shell.*` instead of `src/main.cpp`,
|
|
which reduces the entry TU to a much smaller composition root
|
|
- prepared-file background work now runs through an `AppRuntime`-owned worker
|
|
queue instead of a retained static worker in `src/app_events.cpp`
|
|
- canvas async import/export/save/open background work now also runs through an
|
|
`AppRuntime`-owned worker queue instead of a retained static worker in
|
|
`src/canvas.cpp`
|
|
- retained `App` composition, task call sites, and platform/runtime entrypoint
|
|
coupling are still not fully reduced behind the runtime contract
|
|
|
|
Write scope:
|
|
- `src/app.h`
|
|
- `src/app.cpp`
|
|
- `src/app_events.cpp`
|
|
- `src/main.cpp`
|
|
- new `src/app_runtime_*.*` or retained runtime service files if needed
|
|
|
|
Read scope:
|
|
- `src/app_core/app_thread.h`
|
|
- `src/platform_api/platform_services.h`
|
|
- render/UI task call sites under `src/*.cpp`
|
|
|
|
Done when:
|
|
- Render and UI task queues are owned by an explicit runtime object or service
|
|
with startup, drain, stop, and thread-affinity APIs.
|
|
- `App` composes that runtime instead of exposing static global queue state.
|
|
- Platform event code and retained services post work through the runtime
|
|
contract rather than by reaching `App::I` static queues.
|
|
- Shutdown behavior remains deterministic and the touched slice reduces
|
|
singleton/thread coupling.
|
|
|
|
Mini-model packet:
|
|
- Keep public behavior and thread ordering unchanged.
|
|
- Prefer a small runtime owner over broad task-system redesign.
|
|
- Make ownership and shutdown semantics explicit before adding new features.
|
|
|
|
#### ARC-APP-005 - Replace Detached App Workers With Joinable Or Service-Owned Work
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
The biggest app-facing async families have been moved off detached launches,
|
|
but retained worker ownership and ad hoc runtime control are still not a safe
|
|
modernization foundation.
|
|
|
|
Current slice:
|
|
- app-owned render/UI runtime queues and cloud worker ownership are already
|
|
moving behind owned runtime/service objects
|
|
- Windows splash-dialog and HMD renderer worker ownership in `main.cpp` now
|
|
also use `std::jthread` with explicit stop requests instead of raw
|
|
`std::thread`
|
|
- Windows VR device ownership in `main.cpp` now also uses `std::unique_ptr`
|
|
instead of a raw `Vive*`
|
|
- `LogRemote` worker ownership in `src/log.*` now also uses `std::jthread`
|
|
with explicit stop requests instead of raw `std::thread`
|
|
- brush package import/export now use service-owned `std::jthread` workers and
|
|
UI-thread completion handoff
|
|
- prepared-file save work and grid lightmap launch now also use service-owned
|
|
workers with explicit UI-thread handoff
|
|
- canvas async import/export/save/open and timelapse export now also use owned
|
|
worker queues instead of detached threads
|
|
- `src/app_events.cpp` prepared-file worker ownership and `src/canvas.cpp`
|
|
async import/export/save/open worker ownership now also sit behind named
|
|
retained local worker-state helpers instead of bare static worker accessors
|
|
- the prepared-file worker and the broader canvas async import/export/save/open
|
|
worker have now both moved into `AppRuntime`, removing the retained static
|
|
workers from `src/app_events.cpp` and `src/canvas.cpp`
|
|
- preview background rendering, recording, and the retained
|
|
`NodePanelGrid::bake_uvs()` worker now also use `std::jthread`, but their
|
|
retained loop/control flow is still open
|
|
- `App::rec_loop()` now delegates its worker-iteration orchestration into the
|
|
retained recording bridge in `src/legacy_recording_services.cpp`, while
|
|
`App::update()` no longer carries the dead update mutex residue; retained
|
|
recording loop control, readback ownership, and MP4 execution are still open
|
|
- `App::update_rec_frames()` now delegates recording label refresh through
|
|
`src/legacy_recording_services.cpp`, but retained recording label lookup,
|
|
encoder-state reads, and MP4 execution still stay on the legacy bridge
|
|
|
|
Write scope:
|
|
- `src/canvas.cpp`
|
|
- `src/app_cloud.cpp`
|
|
- `src/app_events.cpp`
|
|
- `src/legacy_cloud_services.*`
|
|
- `src/legacy_brush_package_import_services.*`
|
|
- `src/legacy_brush_package_export_services.*`
|
|
- `src/legacy_grid_ui_services.*`
|
|
- `src/node_dialog_cloud.*`
|
|
- `src/node_stroke_preview.*`
|
|
|
|
Read scope:
|
|
- `src/app_core/app_thread.h`
|
|
- `src/foundation/task_queue.*`
|
|
- `src/legacy_recording_services.*`
|
|
|
|
Done when:
|
|
- Touched worker families are owned by joinable `std::jthread`, a scoped worker
|
|
object, or an injected task service with cancellation/shutdown semantics.
|
|
- Worker callbacks do not capture raw retained nodes or `this` across unknown
|
|
lifetime without a checked handle, weak ownership, or explicit owner.
|
|
- App shutdown can stop the touched worker family without racing UI/layout or
|
|
renderer destruction.
|
|
- Detached `std::thread` count drops materially in app-facing code.
|
|
|
|
Mini-model packet:
|
|
- Start with one coherent worker family, such as cloud or brush package import.
|
|
- Do not rewrite all threading at once.
|
|
- Preserve the existing UI/progress behavior while changing ownership.
|
|
|
|
### Bundle 3 - Finish The UI Core Split
|
|
|
|
Priority: `P0`
|
|
|
|
Why this bundle is still top priority:
|
|
Until generic `Node` and control code leaves `pp_legacy_ui_core`, the UI
|
|
architecture remains mostly the old one with a modern overlay/lifetime helper
|
|
attached to it.
|
|
|
|
#### ARC-UI-001 - Move Generic Node And Control Code Out Of `pp_legacy_ui_core`
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
`pp_ui_core` has layout, color, node lifetime, and overlay lifetime, but the
|
|
generic widget layer still sits in `pp_legacy_ui_core`.
|
|
|
|
Current slice:
|
|
- `Node::load_internal(...)` child XML loading now routes through
|
|
`src/legacy_ui_node_loader.*` instead of staying inline in `src/node.cpp`.
|
|
That trims another coherent generic node-instantiation pocket and makes the
|
|
remaining scene-graph load path easier to isolate, even though ownership has
|
|
not yet moved into `pp_ui_core`.
|
|
- The generic per-frame node execution/traversal family for
|
|
`restore_context`, `clear_context`, `update`, `update_internal`, and `tick`
|
|
now also lives in `src/legacy_ui_node_execution.cpp` instead of staying
|
|
inline in `src/node.cpp`, which materially thins the base scene-graph file
|
|
without changing its public surface.
|
|
- `Node::on_event(...)` plus mouse/key capture and release now also live in
|
|
`src/legacy_ui_node_event.*` instead of staying inline in `src/node.cpp`,
|
|
which materially thins the base scene-graph event shell without changing its
|
|
public surface.
|
|
- `Node::parse_attributes(...)` now also routes through
|
|
`src/legacy_ui_node_attributes.*` instead of staying inline in `src/node.cpp`,
|
|
which trims another coherent XML/Yoga attribute decoding pocket from the base
|
|
scene-graph shell without changing its public surface.
|
|
- `Node::destroy()`, `root()`, `set_manager(...)`, `added_to_root()`,
|
|
`handle_on_screen(...)`, template loading helpers, child add/remove/move
|
|
helpers, and child query helpers now also live in
|
|
`src/legacy_ui_node_tree_services.cpp` instead of staying inline in
|
|
`src/node.cpp`, which materially thins the remaining generic scene-graph
|
|
lifecycle/tree shell without changing the public surface.
|
|
- The generic Yoga style/visibility pocket from `Node::SetWidth(...)` through
|
|
`Node::GetRTL()` now also lives in `src/legacy_ui_node_style.*` instead of
|
|
staying inline in `src/node.cpp`, which trims another coherent generic node
|
|
shell pocket without changing the public surface.
|
|
|
|
Write scope:
|
|
- `src/node.cpp`
|
|
- `src/layout.cpp`
|
|
- generic `src/node_*` base control files from `PP_LEGACY_UI_CORE_SOURCES`
|
|
- `src/ui_core/*`
|
|
- `CMakeLists.txt`
|
|
- `cmake/PanoPainterSources.cmake`
|
|
|
|
Read scope:
|
|
- `src/node_panel_*`
|
|
- `src/node_dialog_*`
|
|
|
|
Done when:
|
|
- Generic controls and base node/layout code are clearly separated from
|
|
PanoPainter-specific panels and dialogs.
|
|
- `pp_ui_core` grows as the home of generic widgets and node behavior.
|
|
- `pp_panopainter_ui` keeps only app-specific panels, dialogs, canvas, preview,
|
|
and workflow nodes.
|
|
- The touched slice removes real file ownership from `pp_legacy_ui_core`, not
|
|
just adds wrappers around it.
|
|
|
|
Mini-model packet:
|
|
- Start with the controls that have no app-specific policy:
|
|
button, checkbox, icon, image, scroll, slider, text, text input.
|
|
- Do not mix panel/dialog rewrites into the same slice.
|
|
- Prefer target ownership moves over purely internal helper reshuffles.
|
|
|
|
#### ARC-UI-002 - Make Checked Handles The Default UI Ownership Model
|
|
|
|
Status: Ready
|
|
|
|
Why now:
|
|
`pp_ui_core` has lifetime and overlay handle helpers, but retained UI code still
|
|
mixes raw `Node*`, shared ownership, direct `add_child(...)`, and callback
|
|
captures across mutation points.
|
|
|
|
Current slice:
|
|
- `src/node.cpp` child attach/detach/reorder paths now route through named
|
|
local helpers instead of repeating raw mutation logic inline. That improves
|
|
scene-graph mutation clarity, but it does not yet change the ownership model
|
|
or move those paths behind checked handles.
|
|
|
|
Write scope:
|
|
- `src/node.*`
|
|
- `src/layout.*`
|
|
- `src/legacy_ui_overlay_services.*`
|
|
- retained `src/node_dialog_*` and `src/node_panel_*` files touched by a slice
|
|
- `src/ui_core/node_lifetime.*`
|
|
- `src/ui_core/overlay_lifetime.*`
|
|
|
|
Read scope:
|
|
- existing popup/dialog call sites found with `add_child`, `remove_child`, and
|
|
`on_*` callback captures
|
|
|
|
Done when:
|
|
- New or touched UI surfaces open, close, and dispatch callbacks through checked
|
|
handles or scoped connections by default.
|
|
- Raw `Node*` fields and callback parameters are documented or reshaped as
|
|
non-owning views, not lifetime owners.
|
|
- Destroy-during-callback and close-during-dispatch behavior is owned by
|
|
`pp_ui_core` rather than each panel/dialog.
|
|
- App-specific panels become view/controller shells over safe UI-core
|
|
lifetime primitives.
|
|
|
|
Mini-model packet:
|
|
- Convert one popup/dialog family at a time.
|
|
- Do not redesign the UI appearance in this task.
|
|
- Prefer deleting raw lifetime assumptions over adding more guard comments.
|
|
|
|
#### ARC-UI-003 - Split UI Rendering From Scene Graph And App State
|
|
|
|
Status: Ready
|
|
|
|
Why now:
|
|
The generic node layer still mixes layout, input, rendering, direct app access,
|
|
and retained OpenGL resource usage. That blocks both a cleaner UI component and
|
|
future renderer backends.
|
|
|
|
Write scope:
|
|
- `src/node.cpp`
|
|
- `src/node_canvas.cpp`
|
|
- `src/node_stroke_preview.cpp`
|
|
- generic control files moved toward `src/ui_core/*`
|
|
- `src/renderer_api/*`
|
|
- `src/paint_renderer/*`
|
|
|
|
Read scope:
|
|
- `src/font.*`
|
|
- `src/shape.*`
|
|
- `src/texture.*`
|
|
- `src/rtt.*`
|
|
|
|
Done when:
|
|
- Scene graph/layout/input code has a renderer-neutral draw contract.
|
|
- Generic controls do not need to know app singleton state or concrete GL
|
|
resource classes.
|
|
- App-specific canvas and preview rendering depends on renderer-facing services
|
|
rather than base `Node` internals.
|
|
- The touched slice makes `pp_ui_core` more reusable without hiding app policy
|
|
inside it.
|
|
|
|
Mini-model packet:
|
|
- Keep visual behavior unchanged.
|
|
- Do not move PanoPainter-specific panel policy into `pp_ui_core`.
|
|
- Use renderer-neutral contracts first; backend implementation follows later.
|
|
|
|
### Bundle 4 - Make The Platform Boundary Real
|
|
|
|
Priority: `P1`
|
|
|
|
Why this bundle is not `P0`:
|
|
It matters, but moving platform code first will not change the day-to-day shape
|
|
of the app as much as reducing `canvas.cpp`, the app shell, and the generic UI
|
|
layer.
|
|
|
|
#### ARC-PLT-001 - Split `pp_platform_api` From Concrete Platform Code
|
|
|
|
Status: Ready
|
|
|
|
Why now:
|
|
`pp_platform_api` is supposed to be the SDK-free policy and interface layer,
|
|
but it still compiles `src/platform_apple/apple_platform_services.*`.
|
|
|
|
Write scope:
|
|
- `CMakeLists.txt`
|
|
- `src/platform_api/*`
|
|
- `src/platform_apple/*`
|
|
|
|
Read scope:
|
|
- `cmake/PanoPainterSources.cmake`
|
|
- `src/platform_windows/*`
|
|
- `src/platform_linux/*`
|
|
|
|
Done when:
|
|
- `pp_platform_api` contains only platform-neutral interfaces, policies, and
|
|
shared helpers.
|
|
- Apple implementation files are built by a concrete platform target instead of
|
|
the API target.
|
|
- The dependency direction is obvious from CMake without reading debt notes.
|
|
|
|
Mini-model packet:
|
|
- Start in `CMakeLists.txt` around `pp_platform_api`.
|
|
- Keep the change structural; do not broaden into new feature work.
|
|
- Preserve current Apple service entrypoints while moving ownership.
|
|
|
|
#### ARC-PLT-002 - Remove `App::I` Reach From Apple And Linux Services
|
|
|
|
Status: In Progress
|
|
|
|
Why now:
|
|
The current Apple and Linux service files still call into the app singleton,
|
|
which means the platform layer is not a platform layer yet.
|
|
|
|
Current slice:
|
|
- Linux FPS title updates now route through an injected callback installed from
|
|
`App::set_platform_services()`
|
|
- `platform_apple` clipboard, display/share, cursor, and save-ui-state calls
|
|
now route through injected Apple bridge callbacks instead of `App::I`
|
|
- `LegacyPlatformServices::prepare_storage_paths()` now routes Apple path
|
|
preparation through a narrow local helper instead of reading `App::I`
|
|
directly in that method body
|
|
- iOS virtual-keyboard visibility and prepared-file save handoff now also route
|
|
through explicit Apple bridge callbacks instead of direct `App::I` calls in
|
|
`LegacyPlatformServices`
|
|
- Apple render-context acquire/release/present hooks and iOS
|
|
`bind_main_render_target()` now also route through explicit Apple bridge
|
|
callbacks instead of direct `App::I` calls in `LegacyPlatformServices`
|
|
- Apple crash-test, app-close, and iOS SonarPen hooks now also route through
|
|
explicit Apple bridge callbacks instead of direct `App::I` calls in
|
|
`LegacyPlatformServices`
|
|
- retained Apple ObjC handles plus storage paths now live in one local
|
|
`platform_legacy` helper, and the iOS SonarPen bridge now starts through
|
|
that retained Apple state instead of reading `App::I` inside the bridge body
|
|
- Linux/Web GLFW render-context acquire/present hooks and Linux app-close now
|
|
also route through retained local GLFW callback hooks instead of direct
|
|
method-body `App::I` access in `LegacyPlatformServices`
|
|
- retained GLFW window hooks and the non-Linux fallback storage-path return now
|
|
also route through retained local state helpers instead of reading `App::I`
|
|
directly in those method bodies
|
|
- retained Apple callback injection and broader `platform_legacy` singleton
|
|
reach are still open
|
|
|
|
Write scope:
|
|
- `src/platform_apple/*`
|
|
- `src/platform_linux/*`
|
|
- `src/app_events.cpp`
|
|
- `src/app.h`
|
|
|
|
Read scope:
|
|
- `src/platform_api/platform_services.h`
|
|
- `src/platform_legacy/legacy_platform_services.*`
|
|
|
|
Done when:
|
|
- `src/platform_apple/*` and `src/platform_linux/*` no longer call `App::I`.
|
|
- The app injects the minimum callbacks or bridge state those services need.
|
|
- Platform files stop depending on app-global state for clipboard, sharing, FPS
|
|
title updates, or native UI saves.
|
|
|
|
Mini-model packet:
|
|
- Keep the interface small. Prefer injected callbacks/bridges over passing the
|
|
whole `App`.
|
|
- Do not rewrite Windows in the same slice.
|
|
|
|
#### ARC-PLT-003 - Remove App-Owned Cross-Platform Handle Storage
|
|
|
|
Status: Ready
|
|
|
|
Why now:
|
|
`src/platform_legacy/legacy_platform_services.cpp` and `src/app.h` still keep
|
|
platform-handle state on `App`, which blocks a real `pp_platform_*` shell split.
|
|
|
|
Write scope:
|
|
- `src/platform_legacy/legacy_platform_services.*`
|
|
- `src/app.h`
|
|
- `src/app_events.cpp`
|
|
- `src/platform_windows/*`
|
|
|
|
Read scope:
|
|
- `src/main.cpp`
|
|
- Apple/Android/Web/Linux entrypoint files only as needed
|
|
|
|
Done when:
|
|
- `App` no longer owns platform-specific handle fields that belong to shells.
|
|
- The legacy platform adapter becomes thin composition or disappears for the
|
|
touched path.
|
|
- Platform setup state lives with the relevant `pp_platform_*` implementation.
|
|
|
|
Mini-model packet:
|
|
- Keep this slice about state ownership, not feature behavior.
|
|
- Prefer moving state to shell-local structs or service singletons owned by the
|
|
platform target.
|
|
|
|
### Bundle 5 - Retire The Thick Workflow Bridges
|
|
|
|
Priority: `P2`
|
|
|
|
Why this bundle is later:
|
|
These bridges still matter, but many recent slices spent too much effort
|
|
polishing adapters without changing the bulk shape of the live app. This bundle
|
|
stays active only after the main hotspots are moving.
|
|
|
|
#### ARC-WKF-001 - Thin Document Open/Save/Session Bridges To Pure Adapters
|
|
|
|
Status: Ready
|
|
|
|
Why now:
|
|
The document session/open/save planners exist, but the live bridges still own a
|
|
lot of retained dialog, metadata, title, and save execution behavior.
|
|
|
|
Write scope:
|
|
- `src/legacy_document_open_services.*`
|
|
- `src/legacy_document_session_services.*`
|
|
- `src/legacy_document_export_services.*`
|
|
- `src/legacy_history_services.*`
|
|
|
|
Read scope:
|
|
- `src/app_core/document_route.h`
|
|
- `src/app_core/document_session.h`
|
|
- `src/app_core/document_export.h`
|
|
|
|
Done when:
|
|
- The remaining bridge files are thin adapters from planner outputs to retained
|
|
execution.
|
|
- Save/open/session flows stop mutating app/document/UI state inline across
|
|
multiple bridge layers.
|
|
- Title updates, history clearing, overwrite prompts, and save routing are each
|
|
owned in one obvious place.
|
|
|
|
Mini-model packet:
|
|
- Preserve current planner contracts.
|
|
- Favor one adapter per workflow family over catch-all helper growth.
|
|
|
|
#### ARC-WKF-002 - Split Cloud And Brush Package Work Out Of Retained UI Nodes
|
|
|
|
Status: Ready
|
|
|
|
Why now:
|
|
Cloud browse/download/upload and brush package import/export still close over
|
|
retained nodes, worker threads, and direct UI ownership.
|
|
|
|
Current slice:
|
|
- `NodePanelBrush` save/restore/scan/reload/find/get-path ownership now routes
|
|
through `src/legacy_brush_panel_services.*` instead of staying inline in
|
|
`src/node_panel_brush.cpp`, which trims a coherent retained brush-workflow
|
|
pocket from the live UI node even though cloud and package-worker ownership
|
|
still remain separate follow-up work.
|
|
- `NodePanelBrushPreset` save/restore plus PPBR/ABR import/export routing now
|
|
also lives in `src/legacy_brush_preset_services.*` instead of staying inline
|
|
in `src/node_panel_brush.cpp`, which trims another large preset-workflow
|
|
pocket from the live UI node even though the broader cloud/package worker
|
|
split still remains follow-up work.
|
|
- `NodePanelBrushPreset` init/menu wiring, click handling, item construction,
|
|
and added-state update now also live in
|
|
`src/legacy_brush_preset_panel_ui.*` instead of staying inline in
|
|
`src/node_panel_brush.cpp`, which materially thins another retained preset
|
|
panel UI pocket even though cloud/package worker ownership remains the
|
|
follow-up.
|
|
- `NodePanelBrush` brush texture panel init, selection dispatch,
|
|
popup-close event handling, restore-failure prompt flow, and added-state
|
|
reset now also live in `src/legacy_brush_panel_ui.*` instead of staying
|
|
inline in `src/node_panel_brush.cpp`, which trims another retained brush UI
|
|
workflow pocket while preserving the live node as a thinner controller
|
|
surface.
|
|
|
|
Write scope:
|
|
- `src/legacy_cloud_services.*`
|
|
- `src/node_dialog_cloud.*`
|
|
- `src/legacy_brush_package_import_services.*`
|
|
- `src/legacy_brush_package_export_services.*`
|
|
- `src/node_panel_brush.cpp`
|
|
|
|
Read scope:
|
|
- `src/app_core/document_cloud.h`
|
|
- `src/app_core/brush_package_import.h`
|
|
- `src/app_core/brush_package_export.h`
|
|
- `src/assets/brush_package.*`
|
|
|
|
Done when:
|
|
- Network transfer execution, thumbnail loading, and brush package worker
|
|
ownership are isolated behind named services.
|
|
- Retained nodes become view/controller shells instead of workflow owners.
|
|
- Cloud and brush package code no longer need to be understood through panel or
|
|
dialog internals first.
|
|
|
|
Mini-model packet:
|
|
- Split worker ownership from UI ownership first.
|
|
- Do not try to redesign cloud UX or brush preset UX in the same slice.
|
|
|
|
## Deferred On Purpose
|
|
|
|
- Vulkan and Metal lab work
|
|
- package-only and automation-only cleanup
|
|
- scorekeeping tasks that do not move app architecture
|
|
|
|
These remain in history only until the app shell, platform split, UI split, and
|
|
canvas/render split are materially thinner.
|