Extract app document session decisions

This commit is contained in:
2026-06-02 22:21:08 +02:00
parent 9dd53f9212
commit 76808d60e3
11 changed files with 225 additions and 17 deletions

View File

@@ -211,7 +211,8 @@ target_link_libraries(pp_ui_core
pp_project_warnings) pp_project_warnings)
add_library(pp_app_core STATIC add_library(pp_app_core STATIC
src/app_core/document_route.cpp) src/app_core/document_route.cpp
src/app_core/document_session.cpp)
target_include_directories(pp_app_core target_include_directories(pp_app_core
PUBLIC PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/src") "${CMAKE_CURRENT_SOURCE_DIR}/src")

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 owned by `pp_app_core`, 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 and unsaved-document session decisions owned by `pp_app_core`, 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 |
@@ -394,10 +394,15 @@ Known local toolchain state:
- `pano_cli classify-open` exposes the `pp_app_core` document-open route - `pano_cli classify-open` exposes the `pp_app_core` document-open route
contract as JSON and is covered for project files, ABR imports, PPBR contract as JSON and is covered for project files, ABR imports, PPBR
imports, and malformed path rejection. imports, and malformed path rejection.
- `pano_cli simulate-app-session` exposes `pp_app_core` unsaved-document
decisions for project-open and app-close flows as JSON and is covered for
clean, dirty, and already-prompting states.
- `pp_app_core_document_route_tests` covers the app document-open route - `pp_app_core_document_route_tests` covers the app document-open route
contract for PPI/project files, ABR imports, PPBR imports, inner-dot names, contract for PPI/project files, ABR imports, PPBR imports, inner-dot names,
and malformed paths before the live `App::open_document` performs UI or and malformed paths before the live `App::open_document` performs UI or
legacy canvas work. legacy canvas work.
- `pp_app_core_document_session_tests` covers clean and dirty app session
decisions without requiring a window, canvas, or message box.
- `pp_ui_core` consumes vcpkg tinyxml2 only when `PP_USE_VCPKG_TINYXML2=ON` - `pp_ui_core` consumes vcpkg tinyxml2 only when `PP_USE_VCPKG_TINYXML2=ON`
through the vcpkg preset; default and Android validation still use the through the vcpkg preset; default and Android validation still use the
retained vendored fallback tracked by DEBT-0012. retained vendored fallback tracked by DEBT-0012.

View File

@@ -13,6 +13,7 @@ and validation command.
| --- | --- | --- | --- | | --- | --- | --- | --- |
| PPI open/save | `Canvas`, serializer, dialogs | `pp_document`, `pp_assets`, `pano_cli` | Round-trip tiny project, old-version fixture, corrupt/truncated fixture | | PPI open/save | `Canvas`, serializer, dialogs | `pp_document`, `pp_assets`, `pano_cli` | Round-trip tiny project, old-version fixture, corrupt/truncated fixture |
| Open-document routing | `App::open_document` | `pp_app_core`, `pano_cli`, `pp_panopainter_ui`, `pp_document`, `pp_assets` | Project/ABR/PPBR route tests, malformed path tests, CLI route smoke, app open smoke | | Open-document routing | `App::open_document` | `pp_app_core`, `pano_cli`, `pp_panopainter_ui`, `pp_document`, `pp_assets` | Project/ABR/PPBR route tests, malformed path tests, CLI route smoke, app open smoke |
| Unsaved document decisions | `App::open_document`, `App::request_close`, dialogs | `pp_app_core`, `pano_cli`, `pp_panopainter_ui` | Clean/dirty/prompt-open decision tests, CLI session smoke, app close/open smoke |
| Version metadata | `scripts/pre-build.py`, `version.*` | build system, `pp_foundation` | Generated header smoke test, missing-tag behavior | | Version metadata | `scripts/pre-build.py`, `version.*` | build system, `pp_foundation` | Generated header smoke test, missing-tag behavior |
| Thumbnail generation/read | `Canvas`, `Image` | `pp_assets`, `pp_paint_renderer` | Golden thumbnail, corrupt input | | Thumbnail generation/read | `Canvas`, `Image` | `pp_assets`, `pp_paint_renderer` | Golden thumbnail, corrupt input |
| Save-as, overwrite prompts | App/dialogs | `pp_panopainter_ui`, `pp_platform_*` | UI automation and platform smoke | | Save-as, overwrite prompts | App/dialogs | `pp_panopainter_ui`, `pp_platform_*` | UI automation and platform smoke |

View File

@@ -22,7 +22,7 @@ agent or engineer to remove them without reconstructing context from chat.
| --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- |
| DEBT-0001 | Open | Modernization | Existing platform build files remain alongside new CMake | Required for incremental migration without losing platform coverage | Existing platform builds plus new CMake configure | Remove after all platform builds consume shared CMake targets | | DEBT-0001 | Open | Modernization | Existing platform build files remain alongside new CMake | Required for incremental migration without losing platform coverage | Existing platform builds plus new CMake configure | Remove after all platform builds consume shared CMake targets |
| DEBT-0002 | Open | Modernization | Vendored SDK and patched libraries retained initially | Some dependencies are SDK-only, patched, or have platform-specific binaries | Dependency inventory and platform build smoke tests | Replace with vcpkg packages or document permanent vendored status after triplet evaluation | | DEBT-0002 | Open | Modernization | Vendored SDK and patched libraries retained initially | Some dependencies are SDK-only, patched, or have platform-specific binaries | Dependency inventory and platform build smoke tests | Replace with vcpkg packages or document permanent vendored status after triplet evaluation |
| DEBT-0003 | Open | Modernization | Existing singletons remain during initial split; `App::open_document` and `pano_cli classify-open` now consume a pure `pp_app_core` route contract, but document loading still reaches legacy `Canvas::I` and UI singletons | Avoid behavior changes while introducing component boundaries | App launch and component tests; `pp_app_core_document_route_tests`; `pano_cli classify-open --path D:/Paint/demo.ppi`; `ctest --preset desktop-fast --build-config Debug` | Replace singleton reaches with context/service injection at component boundaries | | DEBT-0003 | Open | Modernization | Existing singletons remain during initial split; `App::open_document`, `App::request_close`, `pano_cli classify-open`, and `pano_cli simulate-app-session` now consume pure `pp_app_core` route/session contracts, but document loading still reaches legacy `Canvas::I` and UI singletons | Avoid behavior changes while introducing component boundaries | App launch and component tests; `pp_app_core_document_route_tests`; `pp_app_core_document_session_tests`; `pano_cli classify-open --path D:/Paint/demo.ppi`; `pano_cli simulate-app-session --unsaved`; `ctest --preset desktop-fast --build-config Debug` | Replace singleton reaches with context/service injection at component boundaries |
| DEBT-0004 | Open | Modernization | Android, Linux, WebGL, Apple, and AppX build files remain platform-specific until root CMake alignment reaches them | Prevent platform regressions during incremental migration; raw Windows `.sln/.vcxproj` files were removed on 2026-05-31 by user decision | `cmake --preset windows-msvc-default`; platform-specific configure/build smoke checks as each platform is migrated | Root CMake owns every platform source list and package path | | DEBT-0004 | Open | Modernization | Android, Linux, WebGL, Apple, and AppX build files remain platform-specific until root CMake alignment reaches them | Prevent platform regressions during incremental migration; raw Windows `.sln/.vcxproj` files were removed on 2026-05-31 by user decision | `cmake --preset windows-msvc-default`; platform-specific configure/build smoke checks as each platform is migrated | Root CMake owns every platform source list and package path |
| DEBT-0005 | Open | Modernization | Temporary local CTest harness is used before Catch2 is wired through vcpkg | `vcpkg` is not currently on PATH, but headless tests need to run now | `ctest --preset desktop-fast --build-config Debug` | Replace `tests/test_harness.h` tests with Catch2 tests once vcpkg toolchain/presets are validated | | DEBT-0005 | Open | Modernization | Temporary local CTest harness is used before Catch2 is wired through vcpkg | `vcpkg` is not currently on PATH, but headless tests need to run now | `ctest --preset desktop-fast --build-config Debug` | Replace `tests/test_harness.h` tests with Catch2 tests once vcpkg toolchain/presets are validated |
| DEBT-0007 | Open | Modernization | `vcpkg.json` and `windows-msvc-vcpkg-headless` are validated for the headless Windows component matrix, but app targets still use vendored libraries and Android/Apple triplets are not proven | Dependency migration must stay incremental while SDK/patched/vendor dependencies remain in use | `$env:VCPKG_ROOT="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg"; cmake --preset windows-msvc-vcpkg-headless`; `ctest --preset desktop-fast-vcpkg --build-config Debug` | Component targets consume vcpkg packages where reliable and desktop app, Android, and Apple triplets are validated or explicitly documented as permanent vendor exceptions | | DEBT-0007 | Open | Modernization | `vcpkg.json` and `windows-msvc-vcpkg-headless` are validated for the headless Windows component matrix, but app targets still use vendored libraries and Android/Apple triplets are not proven | Dependency migration must stay incremental while SDK/patched/vendor dependencies remain in use | `$env:VCPKG_ROOT="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg"; cmake --preset windows-msvc-vcpkg-headless`; `ctest --preset desktop-fast-vcpkg --build-config Debug` | Component targets consume vcpkg packages where reliable and desktop app, Android, and Apple triplets are validated or explicitly documented as permanent vendor exceptions |

View File

@@ -168,9 +168,12 @@ targets.
`pp_app_core` now owns tested app-level document-open routing for project `pp_app_core` now owns tested app-level document-open routing for project
files, ABR imports, and PPBR imports without UI, filesystem, platform, or files, ABR imports, and PPBR imports without UI, filesystem, platform, or
renderer dependencies; `App::open_document` and `pano_cli classify-open` renderer dependencies; `App::open_document` and `pano_cli classify-open`
consume this route contract while legacy canvas/project loading remains in consume this route contract. It also owns tested unsaved-document decisions for
place. `panopainter_app` is now a real static target that owns app project-open and app-close flows; `App::open_document`, `App::request_close`,
orchestration sources, app version metadata, and version-header generation. and `pano_cli simulate-app-session` consume those contracts while legacy
canvas/project loading remains in place. `panopainter_app` is now a real
static target that owns app orchestration sources, app version metadata, and
version-header generation.
`pp_panopainter_ui` now owns app-specific modal, dialog, panel, canvas, `pp_panopainter_ui` now owns app-specific modal, dialog, panel, canvas,
viewport, color-picker, stroke-preview, and tool UI workflow nodes outside viewport, color-picker, stroke-preview, and tool UI workflow nodes outside
`pp_legacy_app`; base `Node` controls and layout plumbing remain in the legacy `pp_legacy_app`; base `Node` controls and layout plumbing remain in the legacy
@@ -283,11 +286,11 @@ Status: in progress. `tests/` exists, `desktop-fast`, `fuzz`, and `stress`
CTest presets run headlessly, and CTest presets run headlessly, and
PowerShell/bash wrappers exist for PowerShell/bash wrappers exist for
configure/build/test/analyze/platform-build/package-smoke. `pano_cli` exists configure/build/test/analyze/platform-build/package-smoke. `pano_cli` exists
with JSON automation commands for app document-open routing, creating a with JSON automation commands for app document-open routing, app session
`pp_document` model, metadata-only PPI project loading, and inspecting image dirty-state decisions, creating a `pp_document` model, metadata-only PPI
signatures, PPI headers, and layout XML; full document/app integration is project loading, and inspecting image signatures, PPI headers, and layout XML;
debt-tracked as DEBT-0010 and full PPI body parsing is debt-tracked as full document/app integration is debt-tracked as DEBT-0010 and full PPI body
DEBT-0013. parsing is debt-tracked as DEBT-0013.
Implementation tasks: Implementation tasks:
@@ -419,9 +422,11 @@ the applied stroke payload survives inspect/load round-trip automation, with a
rejection smoke test for unsafe tiny canvas dimensions. rejection smoke test for unsafe tiny canvas dimensions.
`pano_cli classify-open` exposes the pure `pp_app_core` document-open route `pano_cli classify-open` exposes the pure `pp_app_core` document-open route
contract for project files, ABR imports, PPBR imports, and malformed path contract for project files, ABR imports, PPBR imports, and malformed path
rejection. `pano_cli parse-layout` exercises the XML layout path. Continue rejection. `pano_cli simulate-app-session` exposes the pure `pp_app_core`
expanding document behavior toward legacy Canvas parity and then port OpenGL unsaved-document decisions used by project-open and app-close flows.
classes behind the renderer boundary. `pano_cli parse-layout` exercises the XML layout path. Continue expanding
document behavior toward legacy Canvas parity and then port OpenGL classes
behind the renderer boundary.
Implementation tasks: Implementation tasks:

View File

@@ -6,6 +6,7 @@
#include "node_progress_bar.h" #include "node_progress_bar.h"
#include "mp4enc.h" #include "mp4enc.h"
#include "app_core/document_route.h" #include "app_core/document_route.h"
#include "app_core/document_session.h"
#include "renderer_gl/opengl_capabilities.h" #include "renderer_gl/opengl_capabilities.h"
#ifdef __APPLE__ #ifdef __APPLE__
@@ -238,7 +239,8 @@ void App::open_document(std::string path)
}); });
ActionManager::clear(); ActionManager::clear();
}; };
if (!Canvas::I->m_unsaved) const auto open_decision = pp::app::plan_project_open(Canvas::I->m_unsaved);
if (open_decision == pp::app::ProjectOpenDecision::open_now)
{ {
open_action(); open_action();
} }
@@ -256,9 +258,12 @@ void App::open_document(std::string path)
bool App::request_close() bool App::request_close()
{ {
static bool dialog_already_opened = false; static bool dialog_already_opened = false;
if (!Canvas::I->m_unsaved) const auto close_decision = pp::app::plan_close_request(
Canvas::I->m_unsaved,
dialog_already_opened);
if (close_decision == pp::app::CloseRequestDecision::close_now)
return true; return true;
if (!dialog_already_opened) if (close_decision == pp::app::CloseRequestDecision::show_unsaved_prompt)
{ {
auto* m = layout[main_id]->add_child<NodeMessageBox>(); auto* m = layout[main_id]->add_child<NodeMessageBox>();
m->m_title->set_text("Unsaved document"); m->m_title->set_text("Unsaved document");

View File

@@ -0,0 +1 @@
#include "app_core/document_session.h"

View File

@@ -0,0 +1,36 @@
#pragma once
namespace pp::app {
enum class ProjectOpenDecision {
open_now,
prompt_discard_unsaved,
};
enum class CloseRequestDecision {
close_now,
show_unsaved_prompt,
wait_for_existing_prompt,
};
[[nodiscard]] constexpr ProjectOpenDecision plan_project_open(bool has_unsaved_changes) noexcept
{
return has_unsaved_changes
? ProjectOpenDecision::prompt_discard_unsaved
: ProjectOpenDecision::open_now;
}
[[nodiscard]] constexpr CloseRequestDecision plan_close_request(
bool has_unsaved_changes,
bool close_prompt_already_open) noexcept
{
if (!has_unsaved_changes) {
return CloseRequestDecision::close_now;
}
return close_prompt_already_open
? CloseRequestDecision::wait_for_existing_prompt
: CloseRequestDecision::show_unsaved_prompt;
}
}

View File

@@ -268,6 +268,16 @@ add_test(NAME pp_app_core_document_route_tests COMMAND pp_app_core_document_rout
set_tests_properties(pp_app_core_document_route_tests PROPERTIES set_tests_properties(pp_app_core_document_route_tests PROPERTIES
LABELS "app;desktop-fast;fuzz") LABELS "app;desktop-fast;fuzz")
add_executable(pp_app_core_document_session_tests
app_core/document_session_tests.cpp)
target_link_libraries(pp_app_core_document_session_tests PRIVATE
pp_app_core
pp_test_harness)
add_test(NAME pp_app_core_document_session_tests COMMAND pp_app_core_document_session_tests)
set_tests_properties(pp_app_core_document_session_tests PROPERTIES
LABELS "app;desktop-fast")
if(TARGET pano_cli) if(TARGET pano_cli)
add_test(NAME pano_cli_create_document_smoke add_test(NAME pano_cli_create_document_smoke
COMMAND pano_cli create-document --width 64 --height 32 --layers 2) COMMAND pano_cli create-document --width 64 --height 32 --layers 2)
@@ -361,6 +371,24 @@ if(TARGET pano_cli)
LABELS "app;integration;desktop-fast;fuzz" LABELS "app;integration;desktop-fast;fuzz"
) )
add_test(NAME pano_cli_simulate_app_session_clean_smoke
COMMAND pano_cli simulate-app-session)
set_tests_properties(pano_cli_simulate_app_session_clean_smoke PROPERTIES
LABELS "app;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"simulate-app-session\".*\"unsaved\":false.*\"closePromptOpen\":false.*\"projectOpen\":\"open-now\".*\"closeRequest\":\"close-now\"")
add_test(NAME pano_cli_simulate_app_session_unsaved_smoke
COMMAND pano_cli simulate-app-session --unsaved)
set_tests_properties(pano_cli_simulate_app_session_unsaved_smoke PROPERTIES
LABELS "app;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"simulate-app-session\".*\"unsaved\":true.*\"closePromptOpen\":false.*\"projectOpen\":\"prompt-discard-unsaved\".*\"closeRequest\":\"show-unsaved-prompt\"")
add_test(NAME pano_cli_simulate_app_session_existing_prompt_smoke
COMMAND pano_cli simulate-app-session --unsaved --close-prompt-open)
set_tests_properties(pano_cli_simulate_app_session_existing_prompt_smoke PROPERTIES
LABELS "app;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"simulate-app-session\".*\"unsaved\":true.*\"closePromptOpen\":true.*\"projectOpen\":\"prompt-discard-unsaved\".*\"closeRequest\":\"wait-for-existing-prompt\"")
add_test(NAME pano_cli_save_project_roundtrip_smoke add_test(NAME pano_cli_save_project_roundtrip_smoke
COMMAND "${CMAKE_COMMAND}" COMMAND "${CMAKE_COMMAND}"
-DPANO_CLI=$<TARGET_FILE:pano_cli> -DPANO_CLI=$<TARGET_FILE:pano_cli>

View File

@@ -0,0 +1,48 @@
#include "app_core/document_session.h"
#include "test_harness.h"
namespace {
void project_open_clean_document_executes_immediately(pp::tests::Harness& harness)
{
PP_EXPECT(harness, pp::app::plan_project_open(false) == pp::app::ProjectOpenDecision::open_now);
}
void project_open_dirty_document_prompts_for_discard(pp::tests::Harness& harness)
{
PP_EXPECT(
harness,
pp::app::plan_project_open(true) == pp::app::ProjectOpenDecision::prompt_discard_unsaved);
}
void close_clean_document_executes_immediately(pp::tests::Harness& harness)
{
PP_EXPECT(
harness,
pp::app::plan_close_request(false, false) == pp::app::CloseRequestDecision::close_now);
PP_EXPECT(
harness,
pp::app::plan_close_request(false, true) == pp::app::CloseRequestDecision::close_now);
}
void close_dirty_document_opens_one_prompt(pp::tests::Harness& harness)
{
PP_EXPECT(
harness,
pp::app::plan_close_request(true, false) == pp::app::CloseRequestDecision::show_unsaved_prompt);
PP_EXPECT(
harness,
pp::app::plan_close_request(true, true) == pp::app::CloseRequestDecision::wait_for_existing_prompt);
}
}
int main()
{
pp::tests::Harness harness;
harness.run("project open clean document executes immediately", project_open_clean_document_executes_immediately);
harness.run("project open dirty document prompts for discard", project_open_dirty_document_prompts_for_discard);
harness.run("close clean document executes immediately", close_clean_document_executes_immediately);
harness.run("close dirty document opens one prompt", close_dirty_document_opens_one_prompt);
return harness.finish();
}

View File

@@ -1,4 +1,5 @@
#include "app_core/document_route.h" #include "app_core/document_route.h"
#include "app_core/document_session.h"
#include "assets/image_format.h" #include "assets/image_format.h"
#include "assets/image_metadata.h" #include "assets/image_metadata.h"
#include "assets/image_pixels.h" #include "assets/image_pixels.h"
@@ -95,6 +96,11 @@ struct ClassifyOpenArgs {
std::string path; std::string path;
}; };
struct SimulateAppSessionArgs {
bool unsaved = false;
bool close_prompt_open = false;
};
struct SimulateStrokeArgs { struct SimulateStrokeArgs {
std::uint32_t x1 = 0; std::uint32_t x1 = 0;
std::uint32_t y1 = 0; std::uint32_t y1 = 0;
@@ -232,6 +238,32 @@ const char* document_open_kind_name(pp::app::DocumentOpenKind kind) noexcept
return "open-project"; return "open-project";
} }
const char* project_open_decision_name(pp::app::ProjectOpenDecision decision) noexcept
{
switch (decision) {
case pp::app::ProjectOpenDecision::open_now:
return "open-now";
case pp::app::ProjectOpenDecision::prompt_discard_unsaved:
return "prompt-discard-unsaved";
}
return "open-now";
}
const char* close_request_decision_name(pp::app::CloseRequestDecision decision) noexcept
{
switch (decision) {
case pp::app::CloseRequestDecision::close_now:
return "close-now";
case pp::app::CloseRequestDecision::show_unsaved_prompt:
return "show-unsaved-prompt";
case pp::app::CloseRequestDecision::wait_for_existing_prompt:
return "wait-for-existing-prompt";
}
return "close-now";
}
pp::foundation::Result<float> parse_float_arg(std::string_view text) pp::foundation::Result<float> parse_float_arg(std::string_view text)
{ {
float value = 0.0F; float value = 0.0F;
@@ -270,6 +302,7 @@ void print_help()
<< " simulate-document-edits [--width N] [--height N]\n" << " simulate-document-edits [--width N] [--height N]\n"
<< " simulate-document-export [--width N] [--height N]\n" << " simulate-document-export [--width N] [--height N]\n"
<< " simulate-document-history [--width N] [--height N] [--history N]\n" << " simulate-document-history [--width N] [--height N] [--history N]\n"
<< " simulate-app-session [--unsaved] [--close-prompt-open]\n"
<< " simulate-blend\n" << " simulate-blend\n"
<< " simulate-image-import [--width N] [--height N]\n" << " simulate-image-import [--width N] [--height N]\n"
<< " simulate-stroke --x1 N --y1 N --x2 N --y2 N [--spacing N]\n" << " simulate-stroke --x1 N --y1 N --x2 N --y2 N [--spacing N]\n"
@@ -1102,6 +1135,47 @@ int classify_open(int argc, char** argv)
return 0; return 0;
} }
pp::foundation::Status parse_simulate_app_session_args(
int argc,
char** argv,
SimulateAppSessionArgs& args)
{
for (int i = 2; i < argc; ++i) {
const std::string_view key(argv[i]);
if (key == "--unsaved") {
args.unsaved = true;
} else if (key == "--close-prompt-open") {
args.close_prompt_open = true;
} else {
return pp::foundation::Status::invalid_argument("unknown option");
}
}
return pp::foundation::Status::success();
}
int simulate_app_session(int argc, char** argv)
{
SimulateAppSessionArgs args;
const auto status = parse_simulate_app_session_args(argc, argv, args);
if (!status.ok()) {
print_error("simulate-app-session", status.message);
return 2;
}
const auto open_decision = pp::app::plan_project_open(args.unsaved);
const auto close_decision = pp::app::plan_close_request(args.unsaved, args.close_prompt_open);
std::cout << "{\"ok\":true,\"command\":\"simulate-app-session\""
<< ",\"state\":{\"unsaved\":" << json_bool(args.unsaved)
<< ",\"closePromptOpen\":" << json_bool(args.close_prompt_open)
<< "},\"decisions\":{\"projectOpen\":\""
<< project_open_decision_name(open_decision)
<< "\",\"closeRequest\":\""
<< close_request_decision_name(close_decision)
<< "\"}}\n";
return 0;
}
int inspect_project(int argc, char** argv) int inspect_project(int argc, char** argv)
{ {
InspectProjectArgs args; InspectProjectArgs args;
@@ -3038,6 +3112,10 @@ int main(int argc, char** argv)
return simulate_document_history(argc, argv); return simulate_document_history(argc, argv);
} }
if (command == "simulate-app-session") {
return simulate_app_session(argc, argv);
}
if (command == "simulate-image-import") { if (command == "simulate-image-import") {
return simulate_image_import(argc, argv); return simulate_image_import(argc, argv);
} }