Centralize legacy app preferences
This commit is contained in:
@@ -82,6 +82,8 @@ set(PP_PANOPAINTER_APP_SOURCES
|
|||||||
src/app_layout.cpp
|
src/app_layout.cpp
|
||||||
src/app_shaders.cpp
|
src/app_shaders.cpp
|
||||||
src/app_vr.cpp
|
src/app_vr.cpp
|
||||||
|
src/legacy_app_preference_services.cpp
|
||||||
|
src/legacy_app_preference_services.h
|
||||||
src/legacy_cloud_services.cpp
|
src/legacy_cloud_services.cpp
|
||||||
src/legacy_cloud_services.h
|
src/legacy_cloud_services.h
|
||||||
src/legacy_document_export_services.cpp
|
src/legacy_document_export_services.cpp
|
||||||
|
|||||||
@@ -167,6 +167,12 @@ Known local toolchain state:
|
|||||||
Tools, About, history, canvas-clear, and settings execution remain tracked by
|
Tools, About, history, canvas-clear, and settings execution remain tracked by
|
||||||
`DEBT-0029`, `DEBT-0030`, `DEBT-0031`, `DEBT-0033`, `DEBT-0034`, and
|
`DEBT-0029`, `DEBT-0030`, `DEBT-0031`, `DEBT-0033`, `DEBT-0034`, and
|
||||||
`DEBT-0035`.
|
`DEBT-0035`.
|
||||||
|
- `src/legacy_app_preference_services.*` is the current app-shell bridge for
|
||||||
|
options-menu preference execution. It keeps UI scale, viewport scale, RTL,
|
||||||
|
VR-controller, auto-timelapse, and canvas cursor-mode callbacks on the
|
||||||
|
`pp_app_core` `AppPreferenceServices` contract while retained settings
|
||||||
|
persistence, recording lifecycle, and legacy canvas/UI execution remain
|
||||||
|
tracked by `DEBT-0045`.
|
||||||
- `src/legacy_canvas_tool_services.*` is the current app-shell bridge for
|
- `src/legacy_canvas_tool_services.*` is the current app-shell bridge for
|
||||||
canvas toolbar tool selection, NodeCanvas stylus/input mode switching, and
|
canvas toolbar tool selection, NodeCanvas stylus/input mode switching, and
|
||||||
canvas hotkey/touch execution. It keeps those live paths on the `pp_app_core`
|
canvas hotkey/touch execution. It keeps those live paths on the `pp_app_core`
|
||||||
@@ -576,6 +582,10 @@ Known local toolchain state:
|
|||||||
show/hide planning before platform keyboard callbacks, plus cursor visibility
|
show/hide planning before platform keyboard callbacks, plus cursor visibility
|
||||||
planning before platform cursor callbacks, plus clipboard read/write
|
planning before platform cursor callbacks, plus clipboard read/write
|
||||||
planning before platform clipboard callbacks.
|
planning before platform clipboard callbacks.
|
||||||
|
- `pp_app_core_app_preferences_tests` covers UI scale/font-scale planning,
|
||||||
|
scale-option selection, viewport scale planning, RTL direction planning,
|
||||||
|
timelapse start/stop/no-op decisions, simple stored preferences, and
|
||||||
|
`AppPreferenceServices` execution dispatch for options-menu side effects.
|
||||||
- `pp_platform_api_tests` covers service dispatch for clipboard read/write,
|
- `pp_platform_api_tests` covers service dispatch for clipboard read/write,
|
||||||
empty clipboard writes, cursor visibility, virtual-keyboard visibility,
|
empty clipboard writes, cursor visibility, virtual-keyboard visibility,
|
||||||
external file display, file sharing, and picker callbacks without platform
|
external file display, file sharing, and picker callbacks without platform
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ agent or engineer to remove them without reconstructing context from chat.
|
|||||||
| DEBT-0042 | Open | Modernization | Accepted Save As and Save Version planning/execution dispatch now consumes pure `pp_app_core` through `App::dialog_save`, `App::dialog_save_ver`, `pano_cli plan-document-file`, `pano_cli plan-document-version`, `DocumentFileSaveServices`, `DocumentVersionSaveServices`, and `src/legacy_document_session_services.*`, but the bridge still opens legacy overwrite prompts, calls 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-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-0042 | Open | Modernization | Accepted Save As and Save Version planning/execution dispatch now consumes pure `pp_app_core` through `App::dialog_save`, `App::dialog_save_ver`, `pano_cli plan-document-file`, `pano_cli plan-document-version`, `DocumentFileSaveServices`, `DocumentVersionSaveServices`, and `src/legacy_document_session_services.*`, but the bridge still opens legacy overwrite prompts, calls 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-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.*`, but the bridge still calls legacy `Canvas` export methods, owns platform-specific export success messages, creates export directories, handles picker-selected stems, and performs Web prepared-file handoff directly | Preserve current image/collection/depth/cube export behavior while export execution moves toward document/renderer/platform/storage services | `pp_app_core_document_export_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 simulate-document-export`; `ctest --preset desktop-fast --build-config Debug` | File, collection, stem, depth, and cube export execution, export-directory creation, platform success reporting, Web file handoff, and legacy canvas export calls are owned by injected document/renderer/platform/storage services with export dialogs 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.*`, but the bridge still calls legacy `Canvas` export methods, owns platform-specific export success messages, creates export directories, handles picker-selected stems, and performs Web prepared-file handoff directly | Preserve current image/collection/depth/cube export behavior while export execution moves toward document/renderer/platform/storage services | `pp_app_core_document_export_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 simulate-document-export`; `ctest --preset desktop-fast --build-config Debug` | File, collection, stem, depth, and cube export execution, export-directory creation, platform success reporting, Web file handoff, 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`, `DocumentVideoExportServices`, and `src/legacy_document_export_services.*`, but the bridge still launches legacy desktop timelapse worker threads, calls `App::rec_export`, calls `Canvas::export_anim_mp4`, owns mobile/Web save callbacks, and emits success messages directly | 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`; `ctest --preset desktop-fast --build-config Debug` | Timelapse and animation MP4 execution, desktop worker threading, frame readback/video encoding handoff, mobile/Web save callbacks, and success reporting are owned by injected app/document/renderer/video/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`, `DocumentVideoExportServices`, and `src/legacy_document_export_services.*`, but the bridge still launches legacy desktop timelapse worker threads, calls `App::rec_export`, calls `Canvas::export_anim_mp4`, owns mobile/Web save callbacks, and emits success messages directly | 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`; `ctest --preset desktop-fast --build-config Debug` | Timelapse and animation MP4 execution, desktop worker threading, frame readback/video encoding handoff, mobile/Web save callbacks, and success reporting 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-controller, auto-timelapse, and canvas cursor-mode callbacks plus `AppPreferenceServices` and `src/legacy_app_preference_services.*`, but the bridge still calls legacy `App::set_ui_scale`, `App::set_ui_rtl`, `NodeCanvas::set_density`, `NodeCanvas::set_cursor_visibility`, `App::rec_start`, `App::rec_stop`, and `Settings::save` directly | Preserve current options-menu behavior while preferences move toward app/UI/platform/storage services | `pp_app_core_app_preferences_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`; `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-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 |
|
||||||
|
|
||||||
## Closed Debt
|
## Closed Debt
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,10 @@ contracts while legacy canvas/project loading remains in place.
|
|||||||
scale option selection, viewport scale, RTL layout direction, timelapse
|
scale option selection, viewport scale, RTL layout direction, timelapse
|
||||||
recording toggles, VR controller enablement, and canvas cursor mode;
|
recording toggles, VR controller enablement, and canvas cursor mode;
|
||||||
the live tools/options menu and `pano_cli plan-app-preferences` consume those
|
the live tools/options menu and `pano_cli plan-app-preferences` consume those
|
||||||
contracts while legacy widgets and settings persistence execute them.
|
contracts. Options-menu preference execution now dispatches through
|
||||||
|
`AppPreferenceServices` and `src/legacy_app_preference_services.*` before
|
||||||
|
legacy widgets, settings persistence, recording toggles, and canvas cursor
|
||||||
|
updates continue.
|
||||||
It also owns tested app status/display plans for document title text,
|
It also owns tested app status/display plans for document title text,
|
||||||
resolution mapping/labels, DPI text, history-memory text, and recording-frame
|
resolution mapping/labels, DPI text, history-memory text, and recording-frame
|
||||||
status text, plus renderer diagnostic indicator labels for framebuffer fetch
|
status text, plus renderer diagnostic indicator labels for framebuffer fetch
|
||||||
@@ -602,6 +605,11 @@ dispatch through `ToolsMenuServices` in the shared app-shell bridge before the
|
|||||||
legacy UI/panel/canvas/platform adapters continue execution. The live animation
|
legacy UI/panel/canvas/platform adapters continue execution. The live animation
|
||||||
panel route now also checks animation panel visibility and applies animation
|
panel route now also checks animation panel visibility and applies animation
|
||||||
panel layout state instead of using the grid panel by mistake.
|
panel layout state instead of using the grid panel by mistake.
|
||||||
|
Options-menu preference callbacks now dispatch UI scale, viewport scale, RTL,
|
||||||
|
VR-controller, auto-timelapse, and cursor-mode side effects through
|
||||||
|
`AppPreferenceServices` in `src/legacy_app_preference_services.*` before
|
||||||
|
retained settings writes, recording lifecycle calls, and legacy canvas/UI
|
||||||
|
adapters continue.
|
||||||
`pano_cli plan-about-menu` exposes app-core planning for About menu help,
|
`pano_cli plan-about-menu` exposes app-core planning for About menu help,
|
||||||
about, what's-new, crash-test, and performance-test commands, including
|
about, what's-new, crash-test, and performance-test commands, including
|
||||||
versioned what's-new labels, diagnostic gating, and no-canvas performance-test
|
versioned what's-new labels, diagnostic gating, and no-canvas performance-test
|
||||||
@@ -1345,6 +1353,11 @@ Results:
|
|||||||
`pp_app_core_document_export_tests`, `pano_cli_plan_export_menu_*`,
|
`pp_app_core_document_export_tests`, `pano_cli_plan_export_menu_*`,
|
||||||
`pano_cli_plan_export_target_name_smoke`, and
|
`pano_cli_plan_export_target_name_smoke`, and
|
||||||
`pano_cli_simulate_document_export_smoke`.
|
`pano_cli_simulate_document_export_smoke`.
|
||||||
|
- `PanoPainter`, `pp_app_core_app_preferences_tests`, and `pano_cli` built
|
||||||
|
after options-menu preference execution moved behind app preference services.
|
||||||
|
- Focused preference CTest coverage passed for
|
||||||
|
`pp_app_core_app_preferences_tests` and the app-preferences CLI smoke tests
|
||||||
|
after the live bridge split.
|
||||||
- `pp_app_core_document_recording_tests` passed, covering recording start/stop,
|
- `pp_app_core_document_recording_tests` passed, covering recording start/stop,
|
||||||
clear, platform recorded-file cleanup, frame-count reset, export progress
|
clear, platform recorded-file cleanup, frame-count reset, export progress
|
||||||
totals, and oversized progress-total clamping.
|
totals, and oversized progress-total clamping.
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "foundation/result.h"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
@@ -44,6 +46,18 @@ struct StoredBooleanPreferencePlan {
|
|||||||
bool value = false;
|
bool value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AppPreferenceServices {
|
||||||
|
public:
|
||||||
|
virtual ~AppPreferenceServices() = default;
|
||||||
|
|
||||||
|
virtual void apply_ui_scale(const ScaleApplicationPlan& plan) = 0;
|
||||||
|
virtual void apply_viewport_scale(const ScaleApplicationPlan& plan) = 0;
|
||||||
|
virtual void apply_interface_direction(const InterfaceDirectionPlan& plan) = 0;
|
||||||
|
virtual void apply_vr_controllers_preference(const StoredBooleanPreferencePlan& plan) = 0;
|
||||||
|
virtual void apply_timelapse_preference(const TimelapsePreferencePlan& plan) = 0;
|
||||||
|
virtual void apply_canvas_cursor_mode(const StoredIntegerPreferencePlan& plan) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]] constexpr ScaleApplicationPlan plan_ui_scale(
|
[[nodiscard]] constexpr ScaleApplicationPlan plan_ui_scale(
|
||||||
float requested_scale,
|
float requested_scale,
|
||||||
float display_density) noexcept
|
float display_density) noexcept
|
||||||
@@ -111,4 +125,55 @@ struct StoredBooleanPreferencePlan {
|
|||||||
return { mode };
|
return { mode };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Status execute_ui_scale_preference(
|
||||||
|
float requested_scale,
|
||||||
|
float display_density,
|
||||||
|
AppPreferenceServices& services)
|
||||||
|
{
|
||||||
|
services.apply_ui_scale(plan_ui_scale(requested_scale, display_density));
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Status execute_viewport_scale_preference(
|
||||||
|
float requested_scale,
|
||||||
|
float display_density,
|
||||||
|
AppPreferenceServices& services)
|
||||||
|
{
|
||||||
|
services.apply_viewport_scale(plan_viewport_scale(requested_scale, display_density));
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Status execute_interface_direction_preference(
|
||||||
|
bool right_to_left,
|
||||||
|
AppPreferenceServices& services)
|
||||||
|
{
|
||||||
|
services.apply_interface_direction(plan_interface_direction(right_to_left));
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Status execute_vr_controllers_preference(
|
||||||
|
bool enabled,
|
||||||
|
AppPreferenceServices& services)
|
||||||
|
{
|
||||||
|
services.apply_vr_controllers_preference(plan_vr_controllers_preference(enabled));
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Status execute_timelapse_preference(
|
||||||
|
bool enabled,
|
||||||
|
bool recording_running,
|
||||||
|
AppPreferenceServices& services)
|
||||||
|
{
|
||||||
|
services.apply_timelapse_preference(plan_timelapse_preference(enabled, recording_running));
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline pp::foundation::Status execute_canvas_cursor_mode_preference(
|
||||||
|
int mode,
|
||||||
|
AppPreferenceServices& services)
|
||||||
|
{
|
||||||
|
services.apply_canvas_cursor_mode(plan_canvas_cursor_mode(mode));
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "app_core/app_status.h"
|
#include "app_core/app_status.h"
|
||||||
#include "app_core/main_toolbar.h"
|
#include "app_core/main_toolbar.h"
|
||||||
#include "app_core/tools_menu.h"
|
#include "app_core/tools_menu.h"
|
||||||
|
#include "legacy_app_preference_services.h"
|
||||||
#include "legacy_app_shell_services.h"
|
#include "legacy_app_shell_services.h"
|
||||||
#include "legacy_brush_ui_services.h"
|
#include "legacy_brush_ui_services.h"
|
||||||
#include "legacy_canvas_tool_services.h"
|
#include "legacy_canvas_tool_services.h"
|
||||||
@@ -1095,7 +1096,11 @@ void App::init_menu_tools()
|
|||||||
|
|
||||||
ui_scale->on_select = [ui_scale](Node* target, int index)
|
ui_scale->on_select = [ui_scale](Node* target, int index)
|
||||||
{
|
{
|
||||||
App::I->set_ui_scale(ui_scale->get_float(index));
|
const auto status = pp::panopainter::execute_legacy_ui_scale_preference(
|
||||||
|
*App::I,
|
||||||
|
ui_scale->get_float(index));
|
||||||
|
if (!status.ok())
|
||||||
|
LOG("UI scale preference failed: %s", status.message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1112,10 +1117,11 @@ void App::init_menu_tools()
|
|||||||
|
|
||||||
vp_scale->on_select = [vp_scale](Node* target, int index)
|
vp_scale->on_select = [vp_scale](Node* target, int index)
|
||||||
{
|
{
|
||||||
const auto plan = pp::app::plan_viewport_scale(vp_scale->get_float(index));
|
const auto status = pp::panopainter::execute_legacy_viewport_scale_preference(
|
||||||
App::I->canvas->set_density(plan.scale);
|
*App::I,
|
||||||
Settings::set("vp-scale", Serializer::Float(plan.scale));
|
vp_scale->get_float(index));
|
||||||
Settings::save();
|
if (!status.ok())
|
||||||
|
LOG("Viewport scale preference failed: %s", status.message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1132,7 +1138,11 @@ void App::init_menu_tools()
|
|||||||
|
|
||||||
rtl_btn->find<NodeCheckBox>("tools-rtl-check")->on_value_changed = [this, main](Node*, bool checked)
|
rtl_btn->find<NodeCheckBox>("tools-rtl-check")->on_value_changed = [this, main](Node*, bool checked)
|
||||||
{
|
{
|
||||||
set_ui_rtl(checked);
|
const auto status = pp::panopainter::execute_legacy_interface_direction_preference(
|
||||||
|
*this,
|
||||||
|
checked);
|
||||||
|
if (!status.ok())
|
||||||
|
LOG("Interface direction preference failed: %s", status.message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1178,10 +1188,11 @@ void App::init_menu_tools()
|
|||||||
|
|
||||||
vr_btn->find<NodeCheckBox>("tools-vr-controllers-check")->on_value_changed = [this, main](Node* target, bool checked)
|
vr_btn->find<NodeCheckBox>("tools-vr-controllers-check")->on_value_changed = [this, main](Node* target, bool checked)
|
||||||
{
|
{
|
||||||
const auto plan = pp::app::plan_vr_controllers_preference(checked);
|
const auto status = pp::panopainter::execute_legacy_vr_controllers_preference(
|
||||||
vr_controllers_enabled = plan.value;
|
*this,
|
||||||
Settings::set("vr-controllers-enabled", Serializer::Boolean(plan.value));
|
checked);
|
||||||
Settings::save();
|
if (!status.ok())
|
||||||
|
LOG("VR controllers preference failed: %s", status.message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1198,13 +1209,11 @@ void App::init_menu_tools()
|
|||||||
|
|
||||||
btn->find<NodeCheckBox>("tools-timelapse-check")->on_value_changed = [this, main](Node*, bool checked)
|
btn->find<NodeCheckBox>("tools-timelapse-check")->on_value_changed = [this, main](Node*, bool checked)
|
||||||
{
|
{
|
||||||
const auto plan = pp::app::plan_timelapse_preference(checked, App::I->rec_running);
|
const auto status = pp::panopainter::execute_legacy_timelapse_preference(
|
||||||
if (plan.recording_action == pp::app::TimelapseRecordingAction::stop_recording)
|
*this,
|
||||||
App::I->rec_stop();
|
checked);
|
||||||
else if (plan.recording_action == pp::app::TimelapseRecordingAction::start_recording)
|
if (!status.ok())
|
||||||
App::I->rec_start();
|
LOG("Timelapse preference failed: %s", status.message);
|
||||||
Settings::set("auto-timelapse", Serializer::Boolean(plan.enabled));
|
|
||||||
Settings::save();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1214,10 +1223,11 @@ void App::init_menu_tools()
|
|||||||
|
|
||||||
mode->on_select = [mode](Node* target, int index)
|
mode->on_select = [mode](Node* target, int index)
|
||||||
{
|
{
|
||||||
const auto plan = pp::app::plan_canvas_cursor_mode(index);
|
const auto status = pp::panopainter::execute_legacy_canvas_cursor_mode_preference(
|
||||||
App::I->canvas->set_cursor_visibility((NodeCanvas::kCursorVisibility)plan.value);
|
*App::I,
|
||||||
Settings::set("show-cursor", Serializer::Integer(plan.value));
|
index);
|
||||||
Settings::save();
|
if (!status.ok())
|
||||||
|
LOG("Cursor mode preference failed: %s", status.message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
111
src/legacy_app_preference_services.cpp
Normal file
111
src/legacy_app_preference_services.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "legacy_app_preference_services.h"
|
||||||
|
|
||||||
|
#include "app.h"
|
||||||
|
#include "node_canvas.h"
|
||||||
|
#include "serializer.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
namespace pp::panopainter {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class LegacyAppPreferenceServices final : public pp::app::AppPreferenceServices {
|
||||||
|
public:
|
||||||
|
explicit LegacyAppPreferenceServices(App& app) noexcept
|
||||||
|
: app_(app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_ui_scale(const pp::app::ScaleApplicationPlan& plan) override
|
||||||
|
{
|
||||||
|
app_.set_ui_scale(plan.scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_viewport_scale(const pp::app::ScaleApplicationPlan& plan) override
|
||||||
|
{
|
||||||
|
if (!app_.canvas)
|
||||||
|
return;
|
||||||
|
|
||||||
|
app_.canvas->set_density(plan.scale);
|
||||||
|
Settings::set("vp-scale", Serializer::Float(plan.scale));
|
||||||
|
Settings::save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_interface_direction(const pp::app::InterfaceDirectionPlan& plan) override
|
||||||
|
{
|
||||||
|
app_.set_ui_rtl(plan.direction == pp::app::InterfaceDirection::right_to_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_vr_controllers_preference(const pp::app::StoredBooleanPreferencePlan& plan) override
|
||||||
|
{
|
||||||
|
app_.vr_controllers_enabled = plan.value;
|
||||||
|
Settings::set("vr-controllers-enabled", Serializer::Boolean(plan.value));
|
||||||
|
Settings::save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_timelapse_preference(const pp::app::TimelapsePreferencePlan& plan) override
|
||||||
|
{
|
||||||
|
if (plan.recording_action == pp::app::TimelapseRecordingAction::stop_recording) {
|
||||||
|
app_.rec_stop();
|
||||||
|
} else if (plan.recording_action == pp::app::TimelapseRecordingAction::start_recording) {
|
||||||
|
app_.rec_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings::set("auto-timelapse", Serializer::Boolean(plan.enabled));
|
||||||
|
Settings::save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_canvas_cursor_mode(const pp::app::StoredIntegerPreferencePlan& plan) override
|
||||||
|
{
|
||||||
|
if (!app_.canvas)
|
||||||
|
return;
|
||||||
|
|
||||||
|
app_.canvas->set_cursor_visibility(static_cast<NodeCanvas::kCursorVisibility>(plan.value));
|
||||||
|
Settings::set("show-cursor", Serializer::Integer(plan.value));
|
||||||
|
Settings::save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
App& app_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
pp::foundation::Status execute_legacy_ui_scale_preference(App& app, float requested_scale)
|
||||||
|
{
|
||||||
|
LegacyAppPreferenceServices services(app);
|
||||||
|
return pp::app::execute_ui_scale_preference(requested_scale, app.display_density, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status execute_legacy_viewport_scale_preference(App& app, float requested_scale)
|
||||||
|
{
|
||||||
|
LegacyAppPreferenceServices services(app);
|
||||||
|
return pp::app::execute_viewport_scale_preference(requested_scale, 1.0F, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status execute_legacy_interface_direction_preference(App& app, bool right_to_left)
|
||||||
|
{
|
||||||
|
LegacyAppPreferenceServices services(app);
|
||||||
|
return pp::app::execute_interface_direction_preference(right_to_left, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status execute_legacy_vr_controllers_preference(App& app, bool enabled)
|
||||||
|
{
|
||||||
|
LegacyAppPreferenceServices services(app);
|
||||||
|
return pp::app::execute_vr_controllers_preference(enabled, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status execute_legacy_timelapse_preference(App& app, bool enabled)
|
||||||
|
{
|
||||||
|
LegacyAppPreferenceServices services(app);
|
||||||
|
return pp::app::execute_timelapse_preference(enabled, app.rec_running, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status execute_legacy_canvas_cursor_mode_preference(App& app, int mode)
|
||||||
|
{
|
||||||
|
LegacyAppPreferenceServices services(app);
|
||||||
|
return pp::app::execute_canvas_cursor_mode_preference(mode, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pp::panopainter
|
||||||
28
src/legacy_app_preference_services.h
Normal file
28
src/legacy_app_preference_services.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "app_core/app_preferences.h"
|
||||||
|
|
||||||
|
class App;
|
||||||
|
|
||||||
|
namespace pp::panopainter {
|
||||||
|
|
||||||
|
[[nodiscard]] pp::foundation::Status execute_legacy_ui_scale_preference(
|
||||||
|
App& app,
|
||||||
|
float requested_scale);
|
||||||
|
[[nodiscard]] pp::foundation::Status execute_legacy_viewport_scale_preference(
|
||||||
|
App& app,
|
||||||
|
float requested_scale);
|
||||||
|
[[nodiscard]] pp::foundation::Status execute_legacy_interface_direction_preference(
|
||||||
|
App& app,
|
||||||
|
bool right_to_left);
|
||||||
|
[[nodiscard]] pp::foundation::Status execute_legacy_vr_controllers_preference(
|
||||||
|
App& app,
|
||||||
|
bool enabled);
|
||||||
|
[[nodiscard]] pp::foundation::Status execute_legacy_timelapse_preference(
|
||||||
|
App& app,
|
||||||
|
bool enabled);
|
||||||
|
[[nodiscard]] pp::foundation::Status execute_legacy_canvas_cursor_mode_preference(
|
||||||
|
App& app,
|
||||||
|
int mode);
|
||||||
|
|
||||||
|
} // namespace pp::panopainter
|
||||||
@@ -2,9 +2,63 @@
|
|||||||
#include "test_harness.h"
|
#include "test_harness.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class FakeAppPreferenceServices final : public pp::app::AppPreferenceServices {
|
||||||
|
public:
|
||||||
|
void apply_ui_scale(const pp::app::ScaleApplicationPlan& plan) override
|
||||||
|
{
|
||||||
|
ui_scale = plan.scale;
|
||||||
|
ui_font_scale = plan.font_scale;
|
||||||
|
call_order += "ui-scale;";
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_viewport_scale(const pp::app::ScaleApplicationPlan& plan) override
|
||||||
|
{
|
||||||
|
viewport_scale = plan.scale;
|
||||||
|
viewport_font_scale = plan.font_scale;
|
||||||
|
call_order += "viewport-scale;";
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_interface_direction(const pp::app::InterfaceDirectionPlan& plan) override
|
||||||
|
{
|
||||||
|
interface_direction = plan.direction;
|
||||||
|
call_order += "direction;";
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_vr_controllers_preference(const pp::app::StoredBooleanPreferencePlan& plan) override
|
||||||
|
{
|
||||||
|
vr_controllers = plan.value;
|
||||||
|
call_order += "vr-controllers;";
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_timelapse_preference(const pp::app::TimelapsePreferencePlan& plan) override
|
||||||
|
{
|
||||||
|
timelapse_enabled = plan.enabled;
|
||||||
|
timelapse_action = plan.recording_action;
|
||||||
|
call_order += "timelapse;";
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_canvas_cursor_mode(const pp::app::StoredIntegerPreferencePlan& plan) override
|
||||||
|
{
|
||||||
|
cursor_mode = plan.value;
|
||||||
|
call_order += "cursor;";
|
||||||
|
}
|
||||||
|
|
||||||
|
float ui_scale = 0.0F;
|
||||||
|
float ui_font_scale = 0.0F;
|
||||||
|
float viewport_scale = 0.0F;
|
||||||
|
float viewport_font_scale = 0.0F;
|
||||||
|
pp::app::InterfaceDirection interface_direction = pp::app::InterfaceDirection::left_to_right;
|
||||||
|
bool vr_controllers = false;
|
||||||
|
bool timelapse_enabled = false;
|
||||||
|
pp::app::TimelapseRecordingAction timelapse_action = pp::app::TimelapseRecordingAction::no_op;
|
||||||
|
int cursor_mode = -1;
|
||||||
|
std::string call_order;
|
||||||
|
};
|
||||||
|
|
||||||
void ui_scale_computes_font_scale_from_display_density(pp::tests::Harness& harness)
|
void ui_scale_computes_font_scale_from_display_density(pp::tests::Harness& harness)
|
||||||
{
|
{
|
||||||
const auto plan = pp::app::plan_ui_scale(1.5F, 2.0F);
|
const auto plan = pp::app::plan_ui_scale(1.5F, 2.0F);
|
||||||
@@ -71,6 +125,40 @@ void simple_preferences_preserve_values_for_storage(pp::tests::Harness& harness)
|
|||||||
PP_EXPECT(harness, pp::app::plan_canvas_cursor_mode(2).value == 2);
|
PP_EXPECT(harness, pp::app::plan_canvas_cursor_mode(2).value == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void preference_executor_dispatches_side_effect_plans(pp::tests::Harness& harness)
|
||||||
|
{
|
||||||
|
FakeAppPreferenceServices services;
|
||||||
|
|
||||||
|
PP_EXPECT(harness, pp::app::execute_ui_scale_preference(1.5F, 2.0F, services).ok());
|
||||||
|
PP_EXPECT(harness, pp::app::execute_viewport_scale_preference(1.25F, 1.0F, services).ok());
|
||||||
|
PP_EXPECT(harness, pp::app::execute_interface_direction_preference(true, services).ok());
|
||||||
|
PP_EXPECT(harness, pp::app::execute_vr_controllers_preference(true, services).ok());
|
||||||
|
PP_EXPECT(harness, pp::app::execute_timelapse_preference(true, false, services).ok());
|
||||||
|
PP_EXPECT(harness, pp::app::execute_canvas_cursor_mode_preference(2, services).ok());
|
||||||
|
|
||||||
|
PP_EXPECT(harness, services.ui_scale == 1.5F);
|
||||||
|
PP_EXPECT(harness, services.ui_font_scale == 3.0F);
|
||||||
|
PP_EXPECT(harness, services.viewport_scale == 1.25F);
|
||||||
|
PP_EXPECT(harness, services.viewport_font_scale == 1.25F);
|
||||||
|
PP_EXPECT(harness, services.interface_direction == pp::app::InterfaceDirection::right_to_left);
|
||||||
|
PP_EXPECT(harness, services.vr_controllers);
|
||||||
|
PP_EXPECT(harness, services.timelapse_enabled);
|
||||||
|
PP_EXPECT(harness, services.timelapse_action == pp::app::TimelapseRecordingAction::start_recording);
|
||||||
|
PP_EXPECT(harness, services.cursor_mode == 2);
|
||||||
|
PP_EXPECT(
|
||||||
|
harness,
|
||||||
|
services.call_order == "ui-scale;viewport-scale;direction;vr-controllers;timelapse;cursor;");
|
||||||
|
}
|
||||||
|
|
||||||
|
void preference_executor_preserves_timelapse_stop_action(pp::tests::Harness& harness)
|
||||||
|
{
|
||||||
|
FakeAppPreferenceServices services;
|
||||||
|
|
||||||
|
PP_EXPECT(harness, pp::app::execute_timelapse_preference(false, true, services).ok());
|
||||||
|
PP_EXPECT(harness, !services.timelapse_enabled);
|
||||||
|
PP_EXPECT(harness, services.timelapse_action == pp::app::TimelapseRecordingAction::stop_recording);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@@ -88,5 +176,7 @@ int main()
|
|||||||
"timelapse preference starts and stops only on state change",
|
"timelapse preference starts and stops only on state change",
|
||||||
timelapse_preference_starts_and_stops_only_on_state_change);
|
timelapse_preference_starts_and_stops_only_on_state_change);
|
||||||
harness.run("simple preferences preserve values for storage", simple_preferences_preserve_values_for_storage);
|
harness.run("simple preferences preserve values for storage", simple_preferences_preserve_values_for_storage);
|
||||||
|
harness.run("preference executor dispatches side effect plans", preference_executor_dispatches_side_effect_plans);
|
||||||
|
harness.run("preference executor preserves timelapse stop action", preference_executor_preserves_timelapse_stop_action);
|
||||||
return harness.finish();
|
return harness.finish();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user