#pragma once #include "foundation/result.h" #include #include namespace pp::app { enum class InterfaceDirection { left_to_right, right_to_left, }; enum class TimelapseRecordingAction { no_op, start_recording, stop_recording, }; struct ScaleApplicationPlan { float scale = 1.0F; float display_density = 1.0F; float font_scale = 1.0F; }; struct ScaleOptionSelection { bool has_selection = false; std::size_t index = 0; }; struct InterfaceDirectionPlan { InterfaceDirection direction = InterfaceDirection::left_to_right; }; struct TimelapsePreferencePlan { bool enabled = true; TimelapseRecordingAction recording_action = TimelapseRecordingAction::no_op; }; struct StoredIntegerPreferencePlan { int value = 0; }; struct StoredBooleanPreferencePlan { 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 bool apply_vr_mode_preference(const StoredBooleanPreferencePlan& 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( float requested_scale, float display_density) noexcept { return { requested_scale, display_density, requested_scale * display_density, }; } [[nodiscard]] constexpr ScaleApplicationPlan plan_viewport_scale( float requested_scale, float display_density = 1.0F) noexcept { return { requested_scale, display_density, requested_scale * display_density, }; } [[nodiscard]] constexpr ScaleOptionSelection plan_scale_option_selection( float current_scale, std::span options) noexcept { ScaleOptionSelection selection; for (std::size_t index = 0; index < options.size(); ++index) { if (current_scale >= options[index]) { selection.has_selection = true; selection.index = index; } } return selection; } [[nodiscard]] constexpr InterfaceDirectionPlan plan_interface_direction(bool right_to_left) noexcept { return { right_to_left ? InterfaceDirection::right_to_left : InterfaceDirection::left_to_right, }; } [[nodiscard]] constexpr TimelapsePreferencePlan plan_timelapse_preference( bool enabled, bool recording_running) noexcept { if (enabled && !recording_running) { return { enabled, TimelapseRecordingAction::start_recording }; } if (!enabled && recording_running) { return { enabled, TimelapseRecordingAction::stop_recording }; } return { enabled, TimelapseRecordingAction::no_op }; } [[nodiscard]] constexpr StoredBooleanPreferencePlan plan_vr_controllers_preference( bool enabled) noexcept { return { enabled }; } [[nodiscard]] constexpr StoredBooleanPreferencePlan plan_vr_mode_preference(bool enabled) noexcept { return { enabled }; } [[nodiscard]] constexpr StoredIntegerPreferencePlan plan_canvas_cursor_mode(int mode) noexcept { 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_mode_preference( bool enabled, AppPreferenceServices& services) { if (!services.apply_vr_mode_preference(plan_vr_mode_preference(enabled))) { return pp::foundation::Status::invalid_argument("VR mode could not start"); } 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(); } }