diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index fd0456a..c6e3d4d 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -284,6 +284,13 @@ agent or engineer to remove them without reconstructing context from chat. preferences through a retained `LegacyStartupPreferenceSnapshot`, keeping the run-counter, auto-timelapse, and VR-controller preference keys inside `src/legacy_preference_storage.*`. +- 2026-06-12: DEBT-0045/0052 were narrowed again. Retained UI restore, + NodeCanvas default, and Windows placement preference keys now live behind + `LegacyUiPreferenceSnapshot`, `LegacyCanvasPreferenceSnapshot`, and + `LegacyWindowPreferenceSnapshot` in `src/legacy_preference_storage.*`. +- 2026-06-12: DEBT-0045/0052 were narrowed again. UI scale, UI-state/RTL, and + Windows placement write keys now also live behind named + `src/legacy_preference_storage.*` helpers. - 2026-06-05: DEBT-0056 was narrowed. `src/asset.h` no longer exposes Android SDK types or forward declarations; retained Android asset-manager and asset handles are stored as opaque pointers and cast only inside `src/asset.cpp`, @@ -886,14 +893,14 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0042 | Open | Modernization | Accepted Save As and Save Version planning/execution dispatch plus Save As overwrite prompt metadata now consumes pure `pp_app_core` through `App::dialog_save`, `App::dialog_save_ver`, `pano_cli plan-document-file`, `pano_cli plan-document-version`, `pano_cli plan-document-session-prompt`, `DocumentFileSaveServices`, `DocumentVersionSaveServices`, and `src/legacy_document_session_services.*`; Save As overwrite prompt creation now uses `src/legacy_app_dialog_services.*`, and accepted Save As/Save Version execution prepares a payload-bearing canvas snapshot report before retained saving, but the bridge still wires overwrite callbacks directly, delegates actual writing to legacy `Canvas::project_save`, mutates app document name/path/directory fields, marks version saves dirty before saving, updates the title, and handles keyboard/dialog cleanup directly | Preserve current Save As and Save Version behavior while document persistence moves toward app/document/storage/UI services | `pp_app_core_document_session_tests`; `pano_cli plan-document-file --work-dir D:/Paint --name demo --target-exists`; `pano_cli plan-document-session-prompt --kind file-overwrite --name demo`; `pano_cli plan-document-version --directory D:/Paint --doc-name demo.01 --existing-path D:/Paint/demo.02.ppi`; `pano_cli simulate-app-session --save-intent save-as`; `pano_cli simulate-app-session --save-intent save-version`; `ctest --preset desktop-fast --build-config Debug` | Save As overwrite prompting, project-save execution, app document metadata updates, title updates, version-save dirty-state handling, and keyboard/dialog cleanup are owned by injected app/document/storage/UI services with `App::dialog_save` and `App::dialog_save_ver` acting only as UI adapters | | DEBT-0043 | Open | Modernization | Equirectangular, layer, animation-frame, depth, and cube-face export planning/execution dispatch now consumes pure `pp_app_core` through `App::dialog_export`, `App::dialog_export_layers`, `App::dialog_export_anim_frames`, `App::dialog_export_depth`, `App::dialog_export_cube_faces`, `pano_cli plan-export-*`, `DocumentExportServices`, and `src/legacy_document_export_services.*`; layer/frame dialogs also consume `plan_document_export_collection_target` plus `PlatformServices::uses_work_directory_document_export_collections()` instead of spelling local iOS branches, export success/failure/license dialog metadata plus execution log labels now come from `pp_app_core`, equirectangular/layer/animation-frame/depth/cube-face execution prepares a payload-bearing document snapshot plus the shared `pp_paint_renderer::prepare_document_frame_export_readiness` report, document-snapshot writer-versus-retained fallback routing now comes from tested `pp_app_core` policy including current-platform support consumed by the live bridge, depth export target naming and two-payload write order are covered by tested `pp_app_core` helpers, cube-face export writes the pure face PNG bytes to `pp_app_core` planned work-directory face paths through `execute_document_cube_face_export_write` before falling back to retained Canvas execution on failure, PNG/JPEG equirectangular export writes the pure `pp_paint_renderer` equirectangular payload through `execute_document_export_file_write` before retained fallback, and payload-complete layer/animation-frame collections write pure `pp_paint_renderer` PNG sequences through `execute_document_export_collection_write` before retained fallback, but the bridge still adapts retained filesystem writes/exported-image publishing locally, still calls legacy `Canvas` export methods for Web/incomplete-readback collection exports and depth rendering, creates export directories, handles picker-selected stems, performs Web prepared-file handoff directly, and leaves depth render/readback plus the legacy `.png`/JPEG payload mismatch on the retained path | Preserve current image/collection/depth/cube export behavior while export execution moves toward document/renderer/platform/storage services | `pp_app_core_document_export_tests`; `pp_platform_api_tests`; `pano_cli plan-export-start --requires-license --demo`; `pano_cli plan-export-menu --kind layers`; `pano_cli plan-export-target --kind collection --work-dir D:/Paint --doc-name demo --suffix _layers`; `pano_cli plan-export-target --kind cube-faces --work-dir D:/Paint --doc-name demo`; `pano_cli plan-export-message --kind equirectangular --destination work --detail D:/Paint`; `pano_cli plan-export-report --kind license-disabled`; `pano_cli plan-export-snapshot-route --kind layers-collection --captured-face-payloads 3 --pending-face-payloads 6`; `pano_cli simulate-document-export`; `ctest --preset desktop-fast --build-config Debug` | File, collection, stem, depth, and remaining retained export execution, export-directory creation, Web file handoff, picker-selected stem handling, and legacy canvas export calls are owned by injected document/renderer/platform/storage services with export dialogs acting only as UI adapters | | DEBT-0044 | Open | Modernization | Timelapse and animation MP4 export execution dispatch now consumes pure `pp_app_core` through `App::dialog_timelapse_export`, `App::dialog_export_mp4`, `pano_cli plan-export-menu`, `pano_cli plan-export-target --kind name`, `pano_cli plan-export-message`, `pano_cli plan-export-report`, `DocumentVideoExportServices`, and `src/legacy_document_export_services.*`, and success/failure/license dialog metadata plus execution log labels now come from `pp_app_core`, but the bridge still launches legacy desktop timelapse worker threads, calls `App::rec_export`, calls `Canvas::export_anim_mp4`, and owns mobile/Web save callbacks | Preserve current MP4/timelapse export behavior while video export moves toward app/document/renderer/video/platform/storage services | `pp_app_core_document_export_tests`; `pano_cli plan-export-menu --kind animation-mp4`; `pano_cli plan-export-menu --kind timelapse`; `pano_cli plan-export-target --kind name --doc-name demo --suffix -animation`; `pano_cli plan-export-target --kind name --doc-name demo --suffix -timelapse`; `pano_cli plan-export-message --kind timelapse --destination success`; `pano_cli plan-export-report --kind animation-mp4 --message "video export path must not be empty"`; `ctest --preset desktop-fast --build-config Debug` | Timelapse and animation MP4 execution, desktop worker threading, frame readback/video encoding handoff, and mobile/Web save callbacks are owned by injected app/document/renderer/video/platform/storage services with export dialogs acting only as UI adapters | -| DEBT-0045 | Open | Modernization | Options-menu preference execution now consumes pure `pp_app_core` through UI scale, viewport scale, RTL direction, VR mode, VR-controller, auto-timelapse, and canvas cursor-mode callbacks plus `AppPreferenceServices` and `src/legacy_app_preference_services.*`; viewport-density and cursor-mode execution now delegate to `src/legacy_canvas_view_services.*`, and retained preference reads/writes for UI scale, UI-state/RTL, whats-new dialog state, viewport density, cursor mode, VR controllers, and auto-timelapse now route through `src/legacy_preference_storage.*` without direct `settings.h` includes in the UI/dialog/canvas call sites, but the bridges still call legacy `App::set_ui_scale`, `App::set_ui_rtl`, `App::rec_start`, `App::rec_stop`, retained canvas view mutation, and retained `Settings` storage through that adapter; VR mode callbacks now call `App` VR wrappers that dispatch to `PlatformServices`, whose desktop runtime policy prefers OpenXR while the actual Windows OpenVR SDK bridge still lives in `WindowsPlatformServices` under DEBT-0061 | Preserve current options-menu behavior while preferences move toward app/UI/platform/storage services | `pp_app_core_app_preferences_tests`; `pp_app_core_canvas_view_tests`; `pano_cli plan-app-preferences --ui-scale 1.5 --display-density 2 --current-scale 1.6 --scale-option 1 --scale-option 1.5 --rtl`; `pano_cli plan-canvas-view-density --density 1.5`; `pano_cli plan-canvas-view-cursor-mode --mode 3`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Preference persistence, UI/layout direction, viewport density, cursor mode, VR mode start/stop/failure handling, VR-controller state, and auto-timelapse recording side effects are owned by injected app/UI/platform/storage services with options-menu callbacks acting only as UI adapters | +| DEBT-0045 | Open | Modernization | Options-menu preference execution now consumes pure `pp_app_core` through UI scale, viewport scale, RTL direction, VR mode, VR-controller, auto-timelapse, and canvas cursor-mode callbacks plus `AppPreferenceServices` and `src/legacy_app_preference_services.*`; viewport-density and cursor-mode execution now delegate to `src/legacy_canvas_view_services.*`, and retained preference reads/writes for UI scale, UI-state/RTL, whats-new dialog state, viewport density, cursor mode, VR controllers, and auto-timelapse now route through `src/legacy_preference_storage.*` snapshots/helpers without direct `settings.h` includes or retained preference keys in the UI/dialog/canvas call sites, but the bridges still call legacy `App::set_ui_scale`, `App::set_ui_rtl`, `App::rec_start`, `App::rec_stop`, retained canvas view mutation, and retained `Settings` storage through that adapter; VR mode callbacks now call `App` VR wrappers that dispatch to `PlatformServices`, whose desktop runtime policy prefers OpenXR while the actual Windows OpenVR SDK bridge still lives in `WindowsPlatformServices` under DEBT-0061 | Preserve current options-menu behavior while preferences move toward app/UI/platform/storage services | `pp_app_core_app_preferences_tests`; `pp_app_core_canvas_view_tests`; `pano_cli plan-app-preferences --ui-scale 1.5 --display-density 2 --current-scale 1.6 --scale-option 1 --scale-option 1.5 --rtl`; `pano_cli plan-canvas-view-density --density 1.5`; `pano_cli plan-canvas-view-cursor-mode --mode 3`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Preference persistence, UI/layout direction, viewport density, cursor mode, VR mode start/stop/failure handling, VR-controller state, and auto-timelapse recording side effects are owned by injected app/UI/platform/storage services with options-menu callbacks acting only as UI adapters | | DEBT-0046 | Open | Modernization | Startup preference/runtime execution and startup resource sequencing now consume pure `pp_app_core` through `App::init`, `pano_cli plan-app-startup`, `pano_cli plan-app-startup-resources`, `AppStartupServices`, `AppStartupResourceServices`, and `src/legacy_app_startup_services.*`, and startup preference load/read/write now routes through `src/legacy_preference_storage.*` with retained startup keys hidden behind `LegacyStartupPreferenceSnapshot`, but the bridge still calls legacy `Settings` storage through that adapter, `App::rec_start`, app VR-controller state mutation, message-box license warning execution, shader loading, asset initialization, layout creation, title updates, and UI render-target creation directly | Preserve current startup behavior while app startup moves toward app/preferences/storage/recording/UI/renderer services | `pp_app_core_app_startup_tests`; `pano_cli plan-app-startup --run-counter 7 --vr-controllers-disabled --license-invalid`; `pano_cli plan-app-startup --run-counter -1`; `pano_cli plan-app-startup-resources --width 1280 --height 720`; `pano_cli plan-app-startup-resources --bad-size`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Startup preference persistence, auto-timelapse startup, stored VR-controller state, license validation/warning, startup resource initialization, title updates, and UI render-target allocation are owned by injected app/preferences/storage/recording/UI/renderer services with `App::init` acting only as orchestration | | DEBT-0047 | Open | Modernization | PPBR brush package export request validation, success-dialog metadata, and execution dispatch now consume pure `pp_app_core` through `App::dialog_ppbr_export`, `pano_cli plan-brush-package-export`, `BrushPackageExportServices`, and `src/legacy_brush_package_export_services.*`; PPBR header/path planning now consumes `pp_assets::brush_package`, and the macOS data-directory override now routes through `PlatformServices`, but the bridge still reads `NodeDialogExportPPBR`, carries the legacy `Image` header object outside the pure request, converts to `NodePanelBrushPreset::PPBRInfo`, calls `NodePanelBrushPreset::export_ppbr`, owns desktop worker-thread dispatch, dialog destruction, and mobile/Web completion directly | Preserve current PPBR export behavior while brush assets, PPBR serialization, picker completion, and UI lifetime move toward asset/storage/UI/platform services | `pp_assets_brush_package_tests`; `pp_app_core_brush_package_export_tests`; `pp_platform_api_tests`; `pano_cli plan-brush-package-export --path D:/Paint/clouds.ppbr --author Artist --dest-path D:/Paint/BrushPreviews --export-data --header-image`; `pano_cli plan-brush-package-export --path D:/Paint/clouds.ppbr`; `pano_cli plan-brush-package-export`; `pano_cli plan-brush-package-export --path clouds`; `pano_cli plan-brush-package-export --path D:/Paint/clouds.ppbr --dest-path D:/Paint/BrushPreviews --no-export-data`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | PPBR metadata collection, header-image ownership, serialization, picker-selected path execution, desktop threading, dialog lifetime, and mobile/Web completion are owned by injected brush asset/storage/UI/platform services with `App::dialog_ppbr_export` acting only as a UI adapter | | DEBT-0048 | Open | Modernization | ABR/PPBR brush package import execution now consumes pure `pp_app_core` through document-open confirmation callbacks, `pano_cli plan-brush-package-import`, `BrushPackageImportServices`, and `src/legacy_brush_package_import_services.*`; imported brush tip/pattern target paths now consume `pp_assets::brush_package`, but the bridge still launches detached legacy `NodePanelBrushPreset::import_abr`/`import_ppbr` worker threads and depends on the legacy preset panel as the importer/storage owner | Preserve current brush import behavior while brush package parsing, preset storage, progress/error reporting, and UI refresh move toward asset/paint/UI services | `pp_assets_brush_package_tests`; `pp_app_core_brush_package_import_tests`; `pano_cli plan-brush-package-import --kind ppbr --path D:/Paint/Brushes/clouds.ppbr`; `pano_cli plan-brush-package-import --kind abr --path D:/Paint/Brushes/clouds.abr`; `pano_cli plan-brush-package-import --kind ppbr`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | ABR/PPBR parsing, preset creation/storage, import threading/progress, duplicate asset policy, and UI refresh are owned by injected brush asset/paint/UI services with document-open callbacks only confirming user intent | | DEBT-0049 | Open | Modernization | `pp_assets::validate_ppbr_header` intentionally preserves the legacy PPBR version check from `NodePanelBrushPreset::import_ppbr`, which accepts files when either major is `0` or minor is `1` instead of requiring exactly version `0.1` | Avoid rejecting existing brush packages before compatibility fixtures prove the stricter rule is safe | `pp_assets_brush_package_tests`; `pano_cli plan-brush-package-export --path D:/Paint/clouds.ppbr`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Add PPBR compatibility fixtures for accepted/rejected historical package versions, then require canonical `0.1` or an explicit supported-version matrix and update live import accordingly | | DEBT-0050 | Open | Modernization | iOS exported-image photo-library publishing and WebGL persistent-storage flushing now dispatch through `PlatformServices`; the iOS/Web policy decision lives in tested `pp_platform_api::platform_policy`, but non-Windows execution still lives in `src/platform_legacy/legacy_platform_services.*` and forwards to retained `save_image_library`/`webgl_sync` bridges | Preserve current iOS/Web export and save behavior while the Apple/Web platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; platform package smoke once Apple/Web root builds exist | Exported-image publishing and persistent-storage flushing are owned by injected Apple/Web `pp_platform_*` services with no legacy adapter branch | | DEBT-0051 | Open | Modernization | Document browser search roots and Browse dialog working-directory picker visibility/path formatting now dispatch through `PlatformServices`; iOS Inbox roots and working-directory picker availability live in tested `pp_platform_api::platform_policy`, but macOS directory picker/display-path execution still lives in `src/platform_legacy/legacy_platform_services.*` | Preserve current iOS document import/browse and desktop browse picker behavior while Apple platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Apple package smoke once root Apple builds exist | Document browse roots and browse-directory picker/display formatting are owned by injected Apple and desktop `pp_platform_*` services with no legacy adapter branch | -| DEBT-0052 | Open | Modernization | Native UI/window state saving now dispatches through `PlatformServices`; Windows/macOS save policy lives in tested `pp_platform_api::platform_policy`, and Windows placement reads/writes now use `src/legacy_preference_storage.*`, but macOS execution still lives in `src/platform_legacy/legacy_platform_services.*` and forwards to the retained Objective-C app bridge while Windows still stores placement through retained `Settings` behind the adapter | Preserve current Windows/macOS UI persistence while platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Windows app build; Apple package smoke once root Apple builds exist | UI/window state persistence is owned by injected platform services with no legacy adapter branch | +| DEBT-0052 | Open | Modernization | Native UI/window state saving now dispatches through `PlatformServices`; Windows/macOS save policy lives in tested `pp_platform_api::platform_policy`, and Windows placement reads/writes now use `LegacyWindowPreferenceSnapshot` plus `src/legacy_preference_storage.*`, but macOS execution still lives in `src/platform_legacy/legacy_platform_services.*` and forwards to the retained Objective-C app bridge while Windows still stores placement through retained `Settings` behind the adapter | Preserve current Windows/macOS UI persistence while platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Windows app build; Apple package smoke once root Apple builds exist | UI/window state persistence is owned by injected platform services with no legacy adapter branch | | DEBT-0053 | Open | Modernization | Prepared-file writable target selection and prepared-file export-dialog policy now dispatch through `PlatformServices`; iOS temporary-file and WebGL data-path target planning live in tested `pp_platform_api::platform_policy`, but retained iOS/Web save/download handoff execution still lives in `src/platform_legacy/legacy_platform_services.*` | Preserve mobile/Web export handoff behavior while platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Windows app build; Apple/Web package smoke once root package builds exist | Prepared-file target selection, export-dialog policy, and save/download handoff are owned by injected platform services with no legacy adapter branch | | DEBT-0054 | Open | Modernization | Layout XML file read/reload decisions now consume `pp_platform_api::plan_asset_file_load`; platform-family reload behavior lives in tested `pp_platform_api::platform_policy` and pure probed planning, but the live wrapper still performs direct `stat` probing for Windows/macOS mtime reload checks until platform storage/file-watch services exist | Preserve current layout hot-reload and mobile/Web single-load behavior while removing platform guards from the shared `LayoutManager` parser | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests`; Windows app build | Layout reload decisions are owned by injected platform storage/file-watch services or an asset manager boundary with platform-specific file watching removed from compile-time helpers | | DEBT-0055 | Open | Modernization | `src/app.h` now forward-declares retained iOS/macOS/Android/Linux/Web platform handles instead of including platform SDK headers, and full SDK includes are isolated in `src/platform_legacy/legacy_platform_services.cpp`, but the `App` singleton still stores those platform handles directly | Reduce central header platform coupling incrementally without rewriting non-Windows platform entrypoints before Phase 6 | Windows app build; Apple/Android/Linux/Web package smoke once platform root builds are active | Platform handles are owned by injected `pp_platform_*` shell state or services, and `App` has no platform SDK handle fields or platform conditional members | diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 48c1bde..3cf4227 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -1107,7 +1107,9 @@ void App::init_menu_tools() if (auto btn = popup_time->find("tools-timelapse")) { NodeCheckBox* cb = btn->find("tools-timelapse-check"); - cb->set_value(pp::panopainter::legacy_boolean_preference_or("auto-timelapse", true), false); + cb->set_value( + pp::panopainter::read_legacy_startup_preferences(vr_controllers_enabled).auto_timelapse, + false); btn->on_click = [this, btn](Node* b) { @@ -1127,7 +1129,7 @@ void App::init_menu_tools() if (auto mode = popup_time->find("tools-show-cursor")) { - mode->set_index(pp::panopainter::legacy_integer_preference_or("show-cursor", 0)); + mode->set_index(pp::panopainter::read_legacy_canvas_preferences().cursor_mode); mode->on_select = [mode](Node* target, int index) { @@ -1539,7 +1541,7 @@ void App::set_ui_scale(float scale) const auto plan = pp::app::plan_ui_scale(scale, display_density); zoom = plan.scale; FontManager::change_scale(plan.font_scale); - pp::panopainter::save_legacy_float_preference("ui-scale", plan.scale); + pp::panopainter::save_legacy_ui_scale_preference(plan.scale); App::I->title_update(); } @@ -1604,8 +1606,7 @@ void App::ui_save() } d.set("drop-right", list_drop_right); - pp::panopainter::set_legacy_descriptor_preference("ui", d); - pp::panopainter::set_legacy_boolean_preference("ui-rtl", ui_rtl); + pp::panopainter::set_legacy_ui_state_preferences(d, ui_rtl); save_platform_ui_state(); pp::panopainter::save_legacy_preferences(); @@ -1613,16 +1614,17 @@ void App::ui_save() void App::ui_restore() { - if (pp::panopainter::has_legacy_preference("ui-rtl")) - set_ui_rtl(pp::panopainter::legacy_integer_preference("ui-rtl")); + const auto preferences = pp::panopainter::read_legacy_ui_preferences(); + if (preferences.has_rtl) + set_ui_rtl(preferences.rtl); - if (!pp::panopainter::has_legacy_preference("ui")) + if (!preferences.state) return; auto floatings = layout[main_id]->find_ref("floatings"); auto drop_left = layout[main_id]->find_ref("drop-left"); auto drop_right = layout[main_id]->find_ref("drop-right"); - auto d = pp::panopainter::get_legacy_descriptor_preference("ui"); + auto d = preferences.state; for (auto const& l : d->get("floatings")->items) { auto ld = std::static_pointer_cast(l); diff --git a/src/legacy_preference_storage.cpp b/src/legacy_preference_storage.cpp index 596f854..9e66f71 100644 --- a/src/legacy_preference_storage.cpp +++ b/src/legacy_preference_storage.cpp @@ -21,6 +21,38 @@ LegacyStartupPreferenceSnapshot read_legacy_startup_preferences(bool default_vr_ }; } +LegacyCanvasPreferenceSnapshot read_legacy_canvas_preferences() +{ + return { + Settings::value_or("vp-scale", 1.0F), + Settings::value_or("show-cursor", 0), + }; +} + +LegacyUiPreferenceSnapshot read_legacy_ui_preferences() +{ + LegacyUiPreferenceSnapshot snapshot; + snapshot.has_rtl = Settings::has("ui-rtl"); + if (snapshot.has_rtl) + snapshot.rtl = Settings::value("ui-rtl"); + if (Settings::has("ui")) + snapshot.state = Settings::get("ui"); + return snapshot; +} + +LegacyWindowPreferenceSnapshot read_legacy_window_preferences(int default_show_command) +{ + LegacyWindowPreferenceSnapshot snapshot; + snapshot.has_ui_scale = Settings::has("ui-scale"); + if (snapshot.has_ui_scale) + snapshot.ui_scale = Settings::value("ui-scale"); + snapshot.show_command = Settings::value_or("window-show-cmd", default_show_command); + snapshot.has_window_rect = Settings::has("window-rect"); + if (snapshot.has_window_rect) + snapshot.window_rect = Settings::value("window-rect"); + return snapshot; +} + bool has_legacy_preference(const char* key) { return Settings::has(key); @@ -86,6 +118,24 @@ void unset_legacy_preference(const char* key) Settings::unset(key); } +void save_legacy_ui_scale_preference(float scale) +{ + Settings::set("ui-scale", Serializer::Float(scale)); + Settings::save(); +} + +void set_legacy_ui_state_preferences(const Serializer::Descriptor& state, bool right_to_left) +{ + Settings::set("ui", state); + Settings::set("ui-rtl", Serializer::Boolean(right_to_left)); +} + +void set_legacy_window_preferences(int show_command, const glm::ivec4& window_rect) +{ + Settings::set("window-show-cmd", Serializer::Integer(show_command)); + Settings::set("window-rect", Serializer::IVec4(window_rect)); +} + void save_legacy_boolean_preference(const char* key, bool value) { set_legacy_boolean_preference(key, value); diff --git a/src/legacy_preference_storage.h b/src/legacy_preference_storage.h index e8a4d36..47e14aa 100644 --- a/src/legacy_preference_storage.h +++ b/src/legacy_preference_storage.h @@ -10,8 +10,30 @@ struct LegacyStartupPreferenceSnapshot { bool vr_controllers_enabled = true; }; +struct LegacyCanvasPreferenceSnapshot { + float viewport_density = 1.0F; + int cursor_mode = 0; +}; + +struct LegacyUiPreferenceSnapshot { + bool has_rtl = false; + int rtl = 0; + std::shared_ptr state; +}; + +struct LegacyWindowPreferenceSnapshot { + bool has_ui_scale = false; + float ui_scale = 1.0F; + int show_command = 0; + bool has_window_rect = false; + glm::ivec4 window_rect {}; +}; + bool load_legacy_preferences(); LegacyStartupPreferenceSnapshot read_legacy_startup_preferences(bool default_vr_controllers_enabled); +LegacyCanvasPreferenceSnapshot read_legacy_canvas_preferences(); +LegacyUiPreferenceSnapshot read_legacy_ui_preferences(); +LegacyWindowPreferenceSnapshot read_legacy_window_preferences(int default_show_command); bool has_legacy_preference(const char* key); int legacy_integer_preference(const char* key); int legacy_integer_preference_or(const char* key, int default_value); @@ -25,6 +47,9 @@ void set_legacy_ivec4_preference(const char* key, const glm::ivec4& value); void set_legacy_boolean_preference(const char* key, bool value); void set_legacy_descriptor_preference(const char* key, const Serializer::Descriptor& value); void unset_legacy_preference(const char* key); +void save_legacy_ui_scale_preference(float scale); +void set_legacy_ui_state_preferences(const Serializer::Descriptor& state, bool right_to_left); +void set_legacy_window_preferences(int show_command, const glm::ivec4& window_rect); void save_legacy_boolean_preference(const char* key, bool value); void save_legacy_float_preference(const char* key, float value); bool save_legacy_preferences(); diff --git a/src/main.cpp b/src/main.cpp index 6a436f3..5cd3519 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -617,8 +617,7 @@ void win32_save_window_state() { WINDOWPLACEMENT p; GetWindowPlacement(hWnd, &p); - pp::panopainter::set_legacy_integer_preference("window-show-cmd", p.showCmd); - pp::panopainter::set_legacy_ivec4_preference("window-rect", { + pp::panopainter::set_legacy_window_preferences(p.showCmd, { p.rcNormalPosition.left, p.rcNormalPosition.top, p.rcNormalPosition.right, @@ -801,22 +800,22 @@ int main(int argc, char** argv) GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI, &x, &y); App::I->display_density = (float)x / 96.f; - if (pp::panopainter::has_legacy_preference("ui-scale")) - App::I->zoom = pp::panopainter::legacy_float_preference("ui-scale"); + const auto window_preferences = pp::panopainter::read_legacy_window_preferences(SW_NORMAL); + if (window_preferences.has_ui_scale) + App::I->zoom = window_preferences.ui_scale; else App::I->zoom = (float)x / 96.f; - int show_cmd = SW_NORMAL; - show_cmd = pp::panopainter::legacy_integer_preference_or("window-show-cmd", show_cmd); + int show_cmd = window_preferences.show_command; DWORD wnd_style = WS_OVERLAPPEDWINDOW; //if (show_cmd == SW_MAXIMIZE) // wnd_style != WS_MAXIMIZE; RECT clientRect = { 0, 0, (int)App::I->width * App::I->zoom, (int)App::I->height * App::I->zoom }; POINT clientPos = { CW_USEDEFAULT, CW_USEDEFAULT }; - if (pp::panopainter::has_legacy_preference("window-rect")) + if (window_preferences.has_window_rect) { - auto wnd_rect = pp::panopainter::legacy_ivec4_preference("window-rect"); + auto wnd_rect = window_preferences.window_rect; App::I->width = wnd_rect.z - wnd_rect.x; App::I->height = wnd_rect.w - wnd_rect.y; clientRect = { wnd_rect.x, wnd_rect.y, wnd_rect.z, wnd_rect.w }; diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index 5f07d0d..26f1b58 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -238,8 +238,9 @@ Node* NodeCanvas::clone_instantiate() const void NodeCanvas::init() { - m_density = pp::panopainter::legacy_float_preference_or("vp-scale", 1.f); - m_cursor_visibility = (kCursorVisibility)pp::panopainter::legacy_integer_preference_or("show-cursor", 0); + const auto preferences = pp::panopainter::read_legacy_canvas_preferences(); + m_density = preferences.viewport_density; + m_cursor_visibility = (kCursorVisibility)preferences.cursor_mode; m_mouse_ignore = false; m_canvas = std::make_unique();