Inject Windows platform services

This commit is contained in:
2026-06-03 04:14:47 +02:00
parent 0e77ca6ba8
commit ead7f58285
6 changed files with 166 additions and 82 deletions

View File

@@ -10,7 +10,7 @@ Keep it updated as platform paths move to shared CMake targets.
| Platform/Target | Current Entrypoint | Notes | | Platform/Target | Current Entrypoint | Notes |
| --- | --- | --- | | --- | --- | --- |
| Windows desktop | Root `CMakeLists.txt`, preset `windows-msvc-default`; target preset `windows-vs2026-x64` retained for VS 2026 | Raw `.sln/.vcxproj` files removed on 2026-05-31; local machine currently uses Visual Studio 17 2022; `PanoPainter` now links through `pp_platform_windows` and `panopainter_app`, with Windows/vendor link dependencies owned by the platform shell, runtime payload deployment in `cmake/PanoPainterRuntime.cmake`, tested app-level document-open routing plus open/close/save session decisions owned by `pp_app_core`, SDK-free clipboard/cursor/virtual-keyboard/display/share/picker service contracts owned by `pp_platform_api`, retained third-party source dependencies contained by `pp_legacy_vendor`, retained asset/file/serialization sources contained by `pp_legacy_assets_io`, retained paint/document/canvas sources contained by `pp_legacy_paint_document`, retained OpenGL runtime sources contained by `pp_legacy_renderer_gl` and folded into `pp_legacy_engine`, retained runtime shell sources contained by `pp_legacy_engine`, retained base UI controls contained by `pp_legacy_ui_core` and folded into `pp_legacy_app`, app orchestration/version metadata owned by `panopainter_app`, and app-specific modal/dialog/panel/canvas workflow nodes owned by `pp_panopainter_ui` | | Windows desktop | Root `CMakeLists.txt`, preset `windows-msvc-default`; target preset `windows-vs2026-x64` retained for VS 2026 | Raw `.sln/.vcxproj` files removed on 2026-05-31; local machine currently uses Visual Studio 17 2022; `PanoPainter` now links through `pp_platform_windows` and `panopainter_app`, with Windows/vendor link dependencies owned by the platform shell, runtime payload deployment in `cmake/PanoPainterRuntime.cmake`, tested app-level document-open routing plus open/close/save session decisions owned by `pp_app_core`, SDK-free clipboard/cursor/virtual-keyboard/display/share/picker service contracts owned by `pp_platform_api`, and injected `WindowsPlatformServices` owned by `pp_platform_windows`; retained third-party source dependencies contained by `pp_legacy_vendor`, retained asset/file/serialization sources contained by `pp_legacy_assets_io`, retained paint/document/canvas sources contained by `pp_legacy_paint_document`, retained OpenGL runtime sources contained by `pp_legacy_renderer_gl` and folded into `pp_legacy_engine`, retained runtime shell sources contained by `pp_legacy_engine`, retained base UI controls contained by `pp_legacy_ui_core` and folded into `pp_legacy_app`, app orchestration/version metadata owned by `panopainter_app`, and app-specific modal/dialog/panel/canvas workflow nodes owned by `pp_panopainter_ui` |
| Windows AppX | `PanoPainterPackage/Package.appxmanifest`, `.wapproj` referenced by solution | Distribution packaging | | Windows AppX | `PanoPainterPackage/Package.appxmanifest`, `.wapproj` referenced by solution | Distribution packaging |
| macOS | `PanoPainter-OSX/` project files and `Info.plist` | Uses `NSOpenGLView` today | | macOS | `PanoPainter-OSX/` project files and `Info.plist` | Uses `NSOpenGLView` today |
| iOS | `PanoPainter/Info.plist`, related Apple sources | Uses OpenGL ES today | | iOS | `PanoPainter/Info.plist`, related Apple sources | Uses OpenGL ES today |
@@ -446,10 +446,12 @@ Known local toolchain state:
platform clipboard bridges. platform clipboard bridges.
- `pp_platform_api` exposes the SDK-free `PlatformServices` interface for - `pp_platform_api` exposes the SDK-free `PlatformServices` interface for
clipboard text, cursor visibility, virtual-keyboard visibility, external clipboard text, cursor visibility, virtual-keyboard visibility, external
file display, file sharing, and picker callbacks; live app execution now file display, file sharing, and picker callbacks; Windows live app execution
reaches retained platform bridges through the debt-tracked legacy adapter in now uses injected `WindowsPlatformServices` from `pp_platform_windows`, while
`app_events.cpp`. The iOS/Web save-with-writer overload remains a separate non-Windows platforms still reach retained platform bridges through the
app method until export handoff is isolated. debt-tracked legacy adapter in `app_events.cpp`. The iOS/Web
save-with-writer overload remains a separate app method until export handoff
is isolated.
- `pano_cli plan-cloud-upload` exposes `pp_app_core` cloud upload availability, - `pano_cli plan-cloud-upload` exposes `pp_app_core` cloud upload availability,
new-document warning, publish prompt, and save-before-upload planning as JSON; new-document warning, publish prompt, and save-before-upload planning as JSON;
the live cloud upload command consumes the same start contract before the live cloud upload command consumes the same start contract before

View File

@@ -33,9 +33,9 @@ agent or engineer to remove them without reconstructing context from chat.
| DEBT-0012 | Open | Modernization | `pp_ui_core` uses vcpkg tinyxml2 on `windows-msvc-vcpkg-headless`, but retains `pp_vendor_tinyxml2` for default and unproven platform presets | Mobile/AppX/Apple triplets and app packaging still need validation before removing the vendored fallback | `ctest --preset desktop-fast-vcpkg --build-config Debug`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64` | All supported presets consume vcpkg tinyxml2 or document a permanent vendored exception | | DEBT-0012 | Open | Modernization | `pp_ui_core` uses vcpkg tinyxml2 on `windows-msvc-vcpkg-headless`, but retains `pp_vendor_tinyxml2` for default and unproven platform presets | Mobile/AppX/Apple triplets and app packaging still need validation before removing the vendored fallback | `ctest --preset desktop-fast-vcpkg --build-config Debug`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64` | All supported presets consume vcpkg tinyxml2 or document a permanent vendored exception |
| DEBT-0013 | Open | Modernization | `pp_assets`, `pp_document`, `pano_cli inspect-project`, `pano_cli load-project`, and `pano_cli save-project` validate the fixed PPI header, thumbnail/body byte layout, generated multi-layer/multi-frame PPI writing with explicit layer opacity/blend/alpha-lock/visibility metadata, per-layer frame durations, metadata-only and targeted dirty-face-payload save/load round-trips, layer/frame index, dirty-face descriptors, dirty-face PNG payload metadata, asset-level RGBA PNG payload decoding, pure document-to-PPI export, CLI document export automation, file-writing document export automation, stroke-script-generated document payload export, and decoded pixel attachment to `pp_document`, but full legacy PPI round-trip parity is not yet extracted | Full PPI save parity requires staged extraction of legacy `Canvas` serialization and image/layer payload handling | `ctest --preset desktop-fast --build-config Debug`; `pp_assets_image_pixels_tests`; `pp_assets_ppi_header_tests`; `pp_document_ppi_import_tests`; `pp_document_ppi_export_tests`; `pano_cli_inspect_project_layout_smoke`; `pano_cli_load_project_metadata_smoke`; `pano_cli_save_project_roundtrip_smoke`; `pano_cli_save_project_payload_roundtrip_smoke`; `pano_cli_simulate_document_export_smoke`; `pano_cli_save_document_project_roundtrip_smoke`; `pano_cli_apply_stroke_script_roundtrip_smoke`; `pano_cli_apply_stroke_script_rejects_tiny_canvas` | Full PPI load/save fixtures cover thumbnails, decoded layer face payloads attached to documents, frames, corrupt payloads, dirty-face payload saving, arbitrary legacy canvas payload/layout combinations, and legacy app round-trip compatibility | | DEBT-0013 | Open | Modernization | `pp_assets`, `pp_document`, `pano_cli inspect-project`, `pano_cli load-project`, and `pano_cli save-project` validate the fixed PPI header, thumbnail/body byte layout, generated multi-layer/multi-frame PPI writing with explicit layer opacity/blend/alpha-lock/visibility metadata, per-layer frame durations, metadata-only and targeted dirty-face-payload save/load round-trips, layer/frame index, dirty-face descriptors, dirty-face PNG payload metadata, asset-level RGBA PNG payload decoding, pure document-to-PPI export, CLI document export automation, file-writing document export automation, stroke-script-generated document payload export, and decoded pixel attachment to `pp_document`, but full legacy PPI round-trip parity is not yet extracted | Full PPI save parity requires staged extraction of legacy `Canvas` serialization and image/layer payload handling | `ctest --preset desktop-fast --build-config Debug`; `pp_assets_image_pixels_tests`; `pp_assets_ppi_header_tests`; `pp_document_ppi_import_tests`; `pp_document_ppi_export_tests`; `pano_cli_inspect_project_layout_smoke`; `pano_cli_load_project_metadata_smoke`; `pano_cli_save_project_roundtrip_smoke`; `pano_cli_save_project_payload_roundtrip_smoke`; `pano_cli_simulate_document_export_smoke`; `pano_cli_save_document_project_roundtrip_smoke`; `pano_cli_apply_stroke_script_roundtrip_smoke`; `pano_cli_apply_stroke_script_rejects_tiny_canvas` | Full PPI load/save fixtures cover thumbnails, decoded layer face payloads attached to documents, frames, corrupt payloads, dirty-face payload saving, arbitrary legacy canvas payload/layout combinations, and legacy app round-trip compatibility |
| DEBT-0014 | Open | Modernization | `windows-clangcl-asan` now configures as a headless Ninja/clang-cl preset and uses the release MSVC runtime required by ASan, but local builds still fail because installed clang-cl 18.1.8 is paired with VS 2026-preview STL headers that require Clang 20 or newer | Sanitizer validation should be local and repeatable, but this machine's compiler/header pairing is incompatible | `cmake --fresh --preset windows-clangcl-asan`; `cmake --build --preset windows-clangcl-asan --target pp_foundation` | Install/use Clang 20+ with the VS 2026 STL, or point the preset at a compatible VS 2022 toolchain, then make `platform-build.ps1 -Presets windows-clangcl-asan` pass for the headless matrix | | DEBT-0014 | Open | Modernization | `windows-clangcl-asan` now configures as a headless Ninja/clang-cl preset and uses the release MSVC runtime required by ASan, but local builds still fail because installed clang-cl 18.1.8 is paired with VS 2026-preview STL headers that require Clang 20 or newer | Sanitizer validation should be local and repeatable, but this machine's compiler/header pairing is incompatible | `cmake --fresh --preset windows-clangcl-asan`; `cmake --build --preset windows-clangcl-asan --target pp_foundation` | Install/use Clang 20+ with the VS 2026 STL, or point the preset at a compatible VS 2022 toolchain, then make `platform-build.ps1 -Presets windows-clangcl-asan` pass for the headless matrix |
| DEBT-0015 | Open | Modernization | Cursor visibility requests now consume pure `pp_app_core` planning through `pano_cli plan-cursor-visibility`, but live cursor execution still reaches retained Win32/macOS platform bridges from `App::show_cursor` and `App::hide_cursor` | Keep canvas cursor behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-cursor-visibility --visible`; `ctest --preset desktop-fast --build-config Debug` | Cursor visibility execution is owned by `pp_platform_*` services and live app code depends on an injected platform interface instead of direct singleton/platform calls | | DEBT-0015 | Open | Modernization | Cursor visibility requests now consume pure `pp_app_core` planning through `pano_cli plan-cursor-visibility`, and Windows live execution uses injected `WindowsPlatformServices`, but macOS cursor execution still reaches the retained fallback adapter from `App::show_cursor` and `App::hide_cursor` | Keep canvas cursor behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-cursor-visibility --visible`; `ctest --preset desktop-fast --build-config Debug` | Cursor visibility execution is owned by injected `pp_platform_*` services for every supported platform |
| DEBT-0016 | Open | Modernization | Clipboard get/set requests now consume pure `pp_app_core` planning through `pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write`, but live clipboard execution still reaches retained Win32/Apple/Android platform bridges from `App::clipboard_get_text` and `App::clipboard_set_text` | Keep picker/color text clipboard behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-clipboard-write --text #ff00aa`; `ctest --preset desktop-fast --build-config Debug` | Clipboard execution is owned by `pp_platform_*` services and live app code depends on an injected platform interface instead of direct singleton/platform calls | | DEBT-0016 | Open | Modernization | Clipboard get/set requests now consume pure `pp_app_core` planning through `pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write`, and Windows live execution uses injected `WindowsPlatformServices`, but Apple/Android clipboard execution still reaches retained fallback adapter branches from `App::clipboard_get_text` and `App::clipboard_set_text` | Keep picker/color text clipboard behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-clipboard-write --text #ff00aa`; `ctest --preset desktop-fast --build-config Debug` | Clipboard execution is owned by injected `pp_platform_*` services for every supported platform |
| DEBT-0017 | Open | Modernization | `App::clipboard_get_text`, `App::clipboard_set_text`, `App::show_cursor`, `App::hide_cursor`, `App::showKeyboard`, `App::hideKeyboard`, `App::display_file`, `App::share_file`, `App::pick_image`, `App::pick_file`, the non-writer `App::pick_file_save`, and `App::pick_dir` now call the SDK-free `pp::platform::PlatformServices` interface, but the live implementation is still a legacy adapter in `app_events.cpp` that forwards to retained Win32/Apple/Android/Linux/Web bridge functions and retained no-op branches; the iOS/Web save-with-writer overload remains separate until export handoff is isolated | Preserve behavior while moving platform execution behind a testable service boundary before platform shell implementations are injected | `pp_platform_api_tests`; `pp_app_core_document_platform_io_tests`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug` | Replace the `app_events.cpp` legacy adapter with injected `pp_platform_*` service implementations owned by each platform shell | | DEBT-0017 | Open | Modernization | `App::clipboard_get_text`, `App::clipboard_set_text`, `App::show_cursor`, `App::hide_cursor`, `App::showKeyboard`, `App::hideKeyboard`, `App::display_file`, `App::share_file`, `App::pick_image`, `App::pick_file`, the non-writer `App::pick_file_save`, and `App::pick_dir` now call the SDK-free `pp::platform::PlatformServices` interface, and Windows injects `WindowsPlatformServices` from `pp_platform_windows`; non-Windows live implementations still use a legacy fallback adapter in `app_events.cpp` that forwards to retained Apple/Android/Linux/Web bridge functions and retained no-op branches; the iOS/Web save-with-writer overload remains separate until export handoff is isolated | Preserve behavior while moving platform execution behind a testable service boundary before platform shell implementations are injected | `pp_platform_api_tests`; `pp_app_core_document_platform_io_tests`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug` | Replace the `app_events.cpp` legacy adapter with injected `pp_platform_*` service implementations owned by each non-Windows platform shell |
## Closed Debt ## Closed Debt

View File

@@ -471,11 +471,12 @@ before retained platform clipboard bridges continue.
`pp_platform_api` now owns a headless `PlatformServices` interface for `pp_platform_api` now owns a headless `PlatformServices` interface for
clipboard text, cursor visibility, virtual-keyboard visibility, external file clipboard text, cursor visibility, virtual-keyboard visibility, external file
display, file sharing, image/file/save-file pickers, and directory pickers. display, file sharing, image/file/save-file pickers, and directory pickers.
Live app clipboard/cursor/keyboard/display/share/picker execution routes Windows installs an injected `WindowsPlatformServices` implementation from
through a debt-tracked legacy adapter in `app_events.cpp`, so behavior is `pp_platform_windows`; other platforms still route through the debt-tracked
preserved while later platform shell implementations can replace direct bridge legacy fallback adapter in `app_events.cpp`, so behavior is preserved while
calls. The iOS/Web save-with-writer overload remains separate because it writes their platform shell implementations are extracted. The iOS/Web
a temporary/exported file before handing control to the platform. save-with-writer overload remains separate because it writes a
temporary/exported file before handing control to the platform.
`pano_cli plan-cloud-upload` exposes the app-core cloud upload decision used by `pano_cli plan-cloud-upload` exposes the app-core cloud upload decision used by
the live cloud upload command for missing-canvas, new-document warning, publish the live cloud upload command for missing-canvas, new-document warning, publish
prompt, and dirty-document save-before-upload states before legacy UI, canvas, prompt, and dirty-document save-before-upload states before legacy UI, canvas,
@@ -990,8 +991,9 @@ Results:
interface for clipboard read/write, empty clipboard writes, cursor interface for clipboard read/write, empty clipboard writes, cursor
visibility dispatch, virtual-keyboard visibility dispatch, external file visibility dispatch, virtual-keyboard visibility dispatch, external file
display dispatch, file sharing dispatch, and picker callback dispatch. The display dispatch, file sharing dispatch, and picker callback dispatch. The
live app now consumes this interface through the legacy platform adapter for live Windows app now consumes this interface through an injected
clipboard/cursor/keyboard/display/share/picker execution. `WindowsPlatformServices` instance owned by `pp_platform_windows`; other
platforms still use the legacy fallback adapter.
- `panopainter_validate_shaders` passed, validating 25 shader programs and 7 - `panopainter_validate_shaders` passed, validating 25 shader programs and 7
shader includes for stage markers and include graph integrity. shader includes for stage markers and include graph integrity.
- `pp_renderer_gl_capabilities_tests` passed on default MSVC, vcpkg-headless, - `pp_renderer_gl_capabilities_tests` passed on default MSVC, vcpkg-headless,

View File

@@ -26,6 +26,10 @@
#include "layout.h" #include "layout.h"
#include "app_core/document_session.h" #include "app_core/document_session.h"
namespace pp::platform {
class PlatformServices;
}
#if defined(__OBJC__) && defined(__IOS__) #if defined(__OBJC__) && defined(__IOS__)
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "GameViewController.h" #import "GameViewController.h"
@@ -156,6 +160,7 @@ public:
float display_density = 1.f; float display_density = 1.f;
float zoom = 1.f; float zoom = 1.f;
int idle_ms = 100; int idle_ms = 100;
pp::platform::PlatformServices* platform_services_ = nullptr;
#if defined(__IOS__) && defined(__OBJC__) #if defined(__IOS__) && defined(__OBJC__)
GameViewController* ios_view; GameViewController* ios_view;
@@ -184,6 +189,8 @@ public:
void pick_dir(std::function<void(std::string path)> callback); void pick_dir(std::function<void(std::string path)> callback);
void display_file(std::string path); void display_file(std::string path);
void share_file(std::string path); void share_file(std::string path);
void set_platform_services(pp::platform::PlatformServices* services) noexcept;
[[nodiscard]] pp::platform::PlatformServices* platform_services() const noexcept;
void showKeyboard(); void showKeyboard();
void hideKeyboard(); void hideKeyboard();
void initLog(); void initLog();

View File

@@ -44,13 +44,6 @@ void android_pick_file(std::function<void(std::string)> callback);
void android_pick_file_save(std::function<void(std::string)> callback); void android_pick_file_save(std::function<void(std::string)> callback);
std::string android_get_clipboard(); std::string android_get_clipboard();
bool android_set_clipboard(const std::string& s); bool android_set_clipboard(const std::string& s);
#elif _WIN32
std::string win32_open_file(const char* filter);
std::string win32_save_file(const char* filter);
std::string win32_open_dir();
void win32_show_cursor(bool visible);
bool win32_clipboard_set_text(const std::string & s);
std::string win32_clipboard_get_text();
#elif __APPLE__ #elif __APPLE__
#elif __LINUX__ #elif __LINUX__
#include <tinyfiledialogs.h> #include <tinyfiledialogs.h>
@@ -63,34 +56,12 @@ void webgl_sync();
namespace { namespace {
std::string build_supported_files_filter(const std::vector<std::string>& types) // DEBT-0017: fallback for platforms that do not inject PlatformServices yet.
{
std::string filter = "Supported Files (";
bool first_type = true;
for (const auto& t : types)
{
filter.append(std::string(first_type ? "" : " ,") + "*." + t);
first_type = false;
}
filter.append(")");
filter.push_back(0);
first_type = true;
for (const auto& t : types)
{
filter.append(std::string(first_type ? "" : ";") + "*." + t);
first_type = false;
}
filter.push_back(0);
return filter;
}
class LegacyPlatformServices final : public pp::platform::PlatformServices { class LegacyPlatformServices final : public pp::platform::PlatformServices {
public: public:
[[nodiscard]] std::string clipboard_text() override [[nodiscard]] std::string clipboard_text() override
{ {
#if _WIN32 #if __IOS__
return win32_clipboard_get_text();
#elif __IOS__
return [App::I->ios_view clipboard_get_string]; return [App::I->ios_view clipboard_get_string];
#elif __OSX__ #elif __OSX__
return [App::I->osx_view clipboard_get_string]; return [App::I->osx_view clipboard_get_string];
@@ -104,9 +75,7 @@ public:
[[nodiscard]] bool set_clipboard_text(std::string_view text) override [[nodiscard]] bool set_clipboard_text(std::string_view text) override
{ {
const std::string value(text); const std::string value(text);
#if _WIN32 #if __IOS__
return win32_clipboard_set_text(value);
#elif __IOS__
return [App::I->ios_view clipboard_set_string:value]; return [App::I->ios_view clipboard_set_string:value];
#elif __OSX__ #elif __OSX__
return [App::I->osx_view clipboard_set_string:value]; return [App::I->osx_view clipboard_set_string:value];
@@ -119,9 +88,7 @@ public:
void set_cursor_visible(bool visible) override void set_cursor_visible(bool visible) override
{ {
#ifdef _WIN32 #ifdef __OSX__
win32_show_cursor(visible);
#elif __OSX__
[App::I->osx_view show_cursor:visible]; [App::I->osx_view show_cursor:visible];
#else #else
(void)visible; (void)visible;
@@ -158,9 +125,6 @@ public:
}); });
#elif __ANDROID__ #elif __ANDROID__
android_pick_file(callback); android_pick_file(callback);
#elif _WIN32
std::string path = win32_open_file("Image Files (*.jpg, *.png)\0*.jpg;*.png");
invoke_picked_path_if_selected(path, callback);
#elif __LINUX__ #elif __LINUX__
if (auto p = tinyfd_openFileDialog("Open File", "", 0, nullptr, nullptr, false)) if (auto p = tinyfd_openFileDialog("Open File", "", 0, nullptr, nullptr, false))
invoke_picked_path_if_selected(p, callback); invoke_picked_path_if_selected(p, callback);
@@ -190,10 +154,6 @@ public:
}); });
#elif __ANDROID__ #elif __ANDROID__
android_pick_file(callback); android_pick_file(callback);
#elif _WIN32
const std::string filter = build_supported_files_filter(file_types);
std::string path = win32_open_file(filter.c_str());
invoke_picked_path_if_selected(path, callback);
#elif __LINUX__ #elif __LINUX__
if (auto p = tinyfd_openFileDialog("Open File", "", 0, nullptr, nullptr, false)) if (auto p = tinyfd_openFileDialog("Open File", "", 0, nullptr, nullptr, false))
invoke_picked_path_if_selected(p, callback); invoke_picked_path_if_selected(p, callback);
@@ -217,10 +177,6 @@ public:
}); });
#elif __ANDROID__ #elif __ANDROID__
android_pick_file_save(callback); android_pick_file_save(callback);
#elif _WIN32
const std::string filter = build_supported_files_filter(file_types);
std::string path = win32_save_file(filter.c_str());
invoke_picked_path_if_selected(path, callback);
#else #else
(void)file_types; (void)file_types;
(void)callback; (void)callback;
@@ -238,9 +194,6 @@ public:
}); });
#elif __ANDROID__ #elif __ANDROID__
(void)callback; (void)callback;
#elif _WIN32
std::string path = win32_open_dir();
invoke_picked_path_if_selected(path, callback);
#else #else
(void)callback; (void)callback;
#endif #endif
@@ -283,15 +236,35 @@ public:
return services; return services;
} }
[[nodiscard]] pp::platform::PlatformServices& active_platform_services()
{
if (App::I)
{
if (auto* services = App::I->platform_services())
return *services;
}
return legacy_platform_services();
} }
}
void App::set_platform_services(pp::platform::PlatformServices* services) noexcept
{
platform_services_ = services;
}
pp::platform::PlatformServices* App::platform_services() const noexcept
{
return platform_services_;
}
std::string App::clipboard_get_text() std::string App::clipboard_get_text()
{ {
if (pp::app::plan_clipboard_read() != pp::app::ClipboardReadAction::read_text) if (pp::app::plan_clipboard_read() != pp::app::ClipboardReadAction::read_text)
return {}; return {};
return legacy_platform_services().clipboard_text(); return active_platform_services().clipboard_text();
} }
bool App::clipboard_set_text(const std::string& s) bool App::clipboard_set_text(const std::string& s)
@@ -299,7 +272,7 @@ bool App::clipboard_set_text(const std::string& s)
if (pp::app::plan_clipboard_write(s) != pp::app::ClipboardWriteAction::write_text) if (pp::app::plan_clipboard_write(s) != pp::app::ClipboardWriteAction::write_text)
return false; return false;
return legacy_platform_services().set_clipboard_text(s); return active_platform_services().set_clipboard_text(s);
} }
void App::stacktrace() void App::stacktrace()
@@ -347,9 +320,9 @@ void App::show_cursor()
return; return;
#ifdef _WIN32 #ifdef _WIN32
legacy_platform_services().set_cursor_visible(true); active_platform_services().set_cursor_visible(true);
#elif __OSX__ #elif __OSX__
legacy_platform_services().set_cursor_visible(true); active_platform_services().set_cursor_visible(true);
#endif #endif
} }
@@ -359,9 +332,9 @@ void App::hide_cursor()
return; return;
#ifdef _WIN32 #ifdef _WIN32
legacy_platform_services().set_cursor_visible(false); active_platform_services().set_cursor_visible(false);
#elif __OSX__ #elif __OSX__
legacy_platform_services().set_cursor_visible(false); active_platform_services().set_cursor_visible(false);
#endif #endif
} }
@@ -372,9 +345,9 @@ void App::showKeyboard()
if (!should_dispatch_keyboard_visibility(true)) if (!should_dispatch_keyboard_visibility(true))
return; return;
#ifdef __IOS__ #ifdef __IOS__
legacy_platform_services().set_virtual_keyboard_visible(true); active_platform_services().set_virtual_keyboard_visible(true);
#elif __ANDROID__ #elif __ANDROID__
legacy_platform_services().set_virtual_keyboard_visible(true); active_platform_services().set_virtual_keyboard_visible(true);
#endif #endif
} }
@@ -385,22 +358,22 @@ void App::hideKeyboard()
if (!should_dispatch_keyboard_visibility(false)) if (!should_dispatch_keyboard_visibility(false))
return; return;
#ifdef __IOS__ #ifdef __IOS__
legacy_platform_services().set_virtual_keyboard_visible(false); active_platform_services().set_virtual_keyboard_visible(false);
#elif __ANDROID__ #elif __ANDROID__
legacy_platform_services().set_virtual_keyboard_visible(false); active_platform_services().set_virtual_keyboard_visible(false);
#endif #endif
} }
void App::pick_image(std::function<void(std::string path)> callback) void App::pick_image(std::function<void(std::string path)> callback)
{ {
redraw = true; redraw = true;
legacy_platform_services().pick_image(std::move(callback)); active_platform_services().pick_image(std::move(callback));
} }
void App::pick_file(std::vector<std::string> types, std::function<void (std::string)> callback) void App::pick_file(std::vector<std::string> types, std::function<void (std::string)> callback)
{ {
redraw = true; redraw = true;
legacy_platform_services().pick_file(std::move(types), std::move(callback)); active_platform_services().pick_file(std::move(types), std::move(callback));
} }
#if __IOS__ #if __IOS__
@@ -432,14 +405,14 @@ void App::pick_file_save(const std::string& type, const std::string& default_nam
void App::pick_file_save(std::vector<std::string> types, std::function<void(std::string)> callback) void App::pick_file_save(std::vector<std::string> types, std::function<void(std::string)> callback)
{ {
redraw = true; redraw = true;
legacy_platform_services().pick_save_file(std::move(types), std::move(callback)); active_platform_services().pick_save_file(std::move(types), std::move(callback));
} }
#endif #endif
void App::pick_dir(std::function<void(std::string path)> callback) void App::pick_dir(std::function<void(std::string path)> callback)
{ {
redraw = true; redraw = true;
legacy_platform_services().pick_directory(std::move(callback)); active_platform_services().pick_directory(std::move(callback));
} }
void App::display_file(std::string path) void App::display_file(std::string path)
@@ -447,7 +420,7 @@ void App::display_file(std::string path)
if (pp::app::plan_display_file(path) == pp::app::DisplayFileAction::ignore_empty_path) if (pp::app::plan_display_file(path) == pp::app::DisplayFileAction::ignore_empty_path)
return; return;
legacy_platform_services().display_file(path); active_platform_services().display_file(path);
} }
void App::share_file(std::string path) void App::share_file(std::string path)
@@ -458,7 +431,7 @@ void App::share_file(std::string path)
message_box("Sharing failed", "Please save the document before sharing it."); message_box("Sharing failed", "Please save the document before sharing it.");
return; return;
} }
legacy_platform_services().share_file(path); active_platform_services().share_file(path);
} }
bool App::mouse_down(int button, float x, float y, float pressure, kEventSource source, bool eraser) bool App::mouse_down(int button, float x, float y, float pressure, kEventSource source, bool eraser)

View File

@@ -5,6 +5,7 @@
#include "texture.h" #include "texture.h"
#include "image.h" #include "image.h"
#include "app.h" #include "app.h"
#include "platform_api/platform_services.h"
#include "canvas.h" #include "canvas.h"
#include "keymap.h" #include "keymap.h"
#include "hmd.h" #include "hmd.h"
@@ -351,6 +352,104 @@ std::string win32_open_dir()
return Buffer; return Buffer;
} }
namespace {
void invoke_selected_path(
const std::string& path,
const pp::platform::PickedPathCallback& callback)
{
if (!path.empty())
callback(path);
}
std::string build_supported_files_filter(const std::vector<std::string>& types)
{
std::string filter = "Supported Files (";
bool first_type = true;
for (const auto& t : types)
{
filter.append(std::string(first_type ? "" : " ,") + "*." + t);
first_type = false;
}
filter.append(")");
filter.push_back(0);
first_type = true;
for (const auto& t : types)
{
filter.append(std::string(first_type ? "" : ";") + "*." + t);
first_type = false;
}
filter.push_back(0);
return filter;
}
class WindowsPlatformServices final : public pp::platform::PlatformServices {
public:
[[nodiscard]] std::string clipboard_text() override
{
return win32_clipboard_get_text();
}
[[nodiscard]] bool set_clipboard_text(std::string_view text) override
{
return win32_clipboard_set_text(std::string(text));
}
void set_cursor_visible(bool visible) override
{
win32_show_cursor(visible);
}
void set_virtual_keyboard_visible(bool visible) override
{
(void)visible;
}
void display_file(std::string_view path) override
{
(void)path;
}
void share_file(std::string_view path) override
{
(void)path;
}
void pick_image(pp::platform::PickedPathCallback callback) override
{
const std::string path = win32_open_file("Image Files (*.jpg, *.png)\0*.jpg;*.png");
invoke_selected_path(path, callback);
}
void pick_file(std::vector<std::string> file_types, pp::platform::PickedPathCallback callback) override
{
const std::string filter = build_supported_files_filter(file_types);
const std::string path = win32_open_file(filter.c_str());
invoke_selected_path(path, callback);
}
void pick_save_file(std::vector<std::string> file_types, pp::platform::PickedPathCallback callback) override
{
const std::string filter = build_supported_files_filter(file_types);
const std::string path = win32_save_file(filter.c_str());
invoke_selected_path(path, callback);
}
void pick_directory(pp::platform::PickedPathCallback callback) override
{
const std::string path = win32_open_dir();
invoke_selected_path(path, callback);
}
};
[[nodiscard]] WindowsPlatformServices& windows_platform_services()
{
static WindowsPlatformServices services;
return services;
}
}
int read_WMI_info() int read_WMI_info()
{ {
// see: http://win32easy.blogspot.co.uk/2011/03/wmi-in-c-query-everyting-from-your-os.html // see: http://win32easy.blogspot.co.uk/2011/03/wmi-in-c-query-everyting-from-your-os.html
@@ -841,6 +940,7 @@ int main(int argc, char** argv)
PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR pfd;
App::I = new App(); App::I = new App();
App::I->set_platform_services(&windows_platform_services());
App::I->initLog(); App::I->initLog();
init_shcore_API(); init_shcore_API();