#include "pch.h" #include "legacy_document_session_services.h" #include "action.h" #include "app.h" #include "legacy_app_dialog_services.h" #include "legacy_document_canvas_services.h" #include "legacy_canvas_view_services.h" #include "legacy_ui_overlay_services.h" #include "node_dialog_open.h" #include namespace pp::panopainter { namespace { class LegacyDocumentHistoryServices final : public pp::app::HistoryUiServices { public: void invoke_undo() override { ActionManager::undo(); } void invoke_redo() override { ActionManager::redo(); } void clear_history() override { ActionManager::clear(); } }; pp::foundation::Status apply_document_history(const pp::app::HistoryUiPlan& plan) { LegacyDocumentHistoryServices services; return pp::app::execute_history_ui_plan(plan, services); } void log_legacy_document_save_snapshot( const char* context, const pp::app::DocumentCanvasSaveSnapshotReport& report) { LOG( "%s document snapshot: %ux%u layers=%zu frames=%zu capturedFaces=%zu pendingFaces=%zu ppiReady=%s", context, report.width, report.height, report.layer_count, report.frame_count, report.captured_face_payloads, report.pending_face_payloads, report.can_export_ppi ? "true" : "false"); } pp::foundation::Status prepare_legacy_document_save_snapshot(App& app, const char* context) { auto snapshot = capture_legacy_canvas_document_payload_snapshot(app); if (!snapshot) { LOG("%s document snapshot failed: %s", context, snapshot.status().message); return snapshot.status(); } const auto report = pp::app::make_document_canvas_save_snapshot_report(snapshot.value()); log_legacy_document_save_snapshot(context, report); const auto route = pp::app::plan_document_canvas_save_writer_route(report); if (!route.uses_document_ppi_writer) { LOG( "%s document save writer retained legacy save: %.*s", context, static_cast(route.fallback_reason.size()), route.fallback_reason.data()); return pp::foundation::Status::success(); } const auto exported = pp::app::export_document_canvas_save_snapshot_to_ppi(snapshot.value()); if (!exported) { LOG( "%s document save writer retained legacy save after PPI export failure: %s", context, exported.status().message); return exported.status(); } LOG( "%s document save writer route: document-ppi payloadComplete=%s bytes=%llu capturedFaces=%zu pendingFaces=%zu", context, exported.value().report.payload_complete ? "true" : "false", static_cast(exported.value().bytes.size()), exported.value().report.captured_face_payloads, exported.value().report.pending_face_payloads); return pp::foundation::Status::success(); } void project_save_after_snapshot(App& app, const std::string& path) { const auto status = prepare_legacy_document_save_snapshot(app, "project-save"); if (!status.ok()) LOG("project save snapshot bridge retained legacy save after failure: %s", status.message); app.canvas->m_canvas->project_save(path); } void project_save_after_snapshot(App& app) { const auto status = prepare_legacy_document_save_snapshot(app, "project-save"); if (!status.ok()) LOG("project save snapshot bridge retained legacy save after failure: %s", status.message); app.canvas->m_canvas->project_save(); } void project_save_after_snapshot(App& app, std::function on_complete) { const auto status = prepare_legacy_document_save_snapshot(app, "project-save-before-workflow"); if (!status.ok()) LOG("project save snapshot bridge retained legacy save after failure: %s", status.message); app.canvas->m_canvas->project_save(std::move(on_complete)); } void wire_unsaved_close_prompt_buttons( App& app, bool& dialog_already_opened, const std::shared_ptr& dialog) { dialog->btn_ok->on_click = [&app](Node*) { app.request_app_close(); Canvas::I->m_unsaved = false; }; dialog->btn_cancel->on_click = [&dialog_already_opened, dialog](Node*) { pp::panopainter::close_legacy_dialog_node(*dialog); dialog_already_opened = false; }; } void create_legacy_new_document( App& app, const pp::app::NewDocumentPlan& plan, const std::shared_ptr& dialog) { app.doc_name = plan.target.name; app.doc_path = plan.target.path; app.doc_filename = plan.target.name + ".ppi"; app.doc_dir = plan.target.directory; app.layers->clear(); app.canvas->m_canvas->m_layers.clear(); app.canvas->m_canvas->resize(plan.resolution, plan.resolution); const auto reset_status = execute_legacy_canvas_camera_reset(app); if (!reset_status.ok()) LOG("New document camera reset failed: %s", reset_status.message); const auto history_status = apply_document_history(pp::app::plan_new_document_history(plan)); if (!history_status.ok()) { LOG("New document history effect failed: %s", history_status.message); } app.layers->add_layer("Default", false, true); app.canvas->m_canvas->m_unsaved = true; app.canvas->m_canvas->m_newdoc = false; app.title_update(); pp::panopainter::close_legacy_dialog_and_hide_keyboard(app, *dialog); } template void wire_legacy_overwrite_prompt_ok( App& app, const std::shared_ptr& msgbox, const std::shared_ptr& dialog, const Plan& plan, AcceptAction&& accept_action) { auto* app_ptr = &app; auto msgbox_ptr = msgbox; auto dialog_ptr = dialog; msgbox->btn_ok->on_click = [app_ptr, msgbox_ptr, dialog_ptr, plan, accept_action = std::forward(accept_action)](Node*) { accept_action(*app_ptr, plan, dialog_ptr); pp::panopainter::close_legacy_dialog_node(*msgbox_ptr); }; } class LegacyNewDocumentServices final : public pp::app::NewDocumentServices { public: LegacyNewDocumentServices(App& app, std::shared_ptr dialog) noexcept : app_(app) , dialog_(std::move(dialog)) { } void create_new_document(const pp::app::NewDocumentPlan& plan) override { create_legacy_new_document(app_, plan, dialog_); } void prompt_overwrite_new_document(const pp::app::NewDocumentPlan& plan) override { auto msgbox = pp::panopainter::create_legacy_app_message_dialog( app_, pp::app::plan_document_session_prompt( pp::app::DocumentSessionPromptKind::new_document_overwrite)); wire_legacy_overwrite_prompt_ok(app_, msgbox, dialog_, plan, create_legacy_new_document); } private: App& app_; std::shared_ptr dialog_; }; void save_legacy_document_file( App& app, const pp::app::DocumentFileSavePlan& plan, const std::shared_ptr& dialog) { const auto history_status = apply_document_history(pp::app::plan_document_file_save_history(plan)); if (!history_status.ok()) { LOG("Document file save history effect failed: %s", history_status.message); } project_save_after_snapshot(app, plan.target.path); app.doc_name = plan.target.name; app.doc_path = plan.target.path; app.doc_dir = plan.target.directory; app.title_update(); pp::panopainter::close_legacy_dialog_and_hide_keyboard(app, *dialog); } class LegacyDocumentFileSaveServices final : public pp::app::DocumentFileSaveServices { public: LegacyDocumentFileSaveServices(App& app, std::shared_ptr dialog) noexcept : app_(app) , dialog_(std::move(dialog)) { } void save_document_file(const pp::app::DocumentFileSavePlan& plan) override { save_legacy_document_file(app_, plan, dialog_); } void prompt_overwrite_document_file(const pp::app::DocumentFileSavePlan& plan) override { auto msgbox = pp::panopainter::create_legacy_app_message_dialog( app_, pp::app::plan_document_session_prompt( pp::app::DocumentSessionPromptKind::document_file_overwrite, plan.target.name)); wire_legacy_overwrite_prompt_ok(app_, msgbox, dialog_, plan, save_legacy_document_file); } private: App& app_; std::shared_ptr dialog_; }; void save_document_version(App& app, const pp::app::DocumentVersionTarget& target); class LegacyDocumentVersionSaveServices final : public pp::app::DocumentVersionSaveServices { public: explicit LegacyDocumentVersionSaveServices(App& app) noexcept : app_(app) { } void save_document_version(const pp::app::DocumentVersionTarget& target) override { save_document_version(app_, target); } private: App& app_; }; void save_document_version(App& app, const pp::app::DocumentVersionTarget& target) { const auto history_status = apply_document_history(pp::app::plan_document_version_save_history(target)); if (!history_status.ok()) { LOG("Document version history effect failed: %s", history_status.message); } app.doc_name = target.name; app.doc_path = target.path; app.canvas->m_canvas->m_unsaved = true; app.title_update(); project_save_after_snapshot(app, app.doc_path); } class LegacyCloseRequestServices final : public pp::app::CloseRequestServices { public: LegacyCloseRequestServices(App& app, bool& dialog_already_opened) noexcept : app_(app) , dialog_already_opened_(dialog_already_opened) { } void request_close_now() override { const auto history_status = apply_document_history( pp::app::plan_close_request_history(pp::app::CloseRequestDecision::close_now)); if (!history_status.ok()) { LOG("Close request history effect failed: %s", history_status.message); } } void show_unsaved_close_prompt() override { const auto history_status = apply_document_history( pp::app::plan_close_request_history(pp::app::CloseRequestDecision::show_unsaved_prompt)); if (!history_status.ok()) { LOG("Close prompt history effect failed: %s", history_status.message); } auto m = pp::panopainter::create_legacy_app_message_dialog( app_, pp::app::plan_document_session_prompt( pp::app::DocumentSessionPromptKind::close_unsaved_document)); wire_unsaved_close_prompt_buttons(app_, dialog_already_opened_, m); dialog_already_opened_ = true; } private: App& app_; bool& dialog_already_opened_; }; class LegacyDocumentSaveServices final : public pp::app::DocumentSaveServices { public: explicit LegacyDocumentSaveServices(App& app) noexcept : app_(app) { } void show_save_dialog() override { const auto history_status = apply_document_history( pp::app::plan_document_save_history(pp::app::DocumentSaveDecision::show_save_dialog)); if (!history_status.ok()) { LOG("Save dialog history effect failed: %s", history_status.message); } app_.dialog_save(); } void save_existing_document() override { const auto history_status = apply_document_history( pp::app::plan_document_save_history(pp::app::DocumentSaveDecision::save_existing)); if (!history_status.ok()) { LOG("Save existing history effect failed: %s", history_status.message); } project_save_after_snapshot(app_); } void save_document_version() override { const auto history_status = apply_document_history( pp::app::plan_document_save_history(pp::app::DocumentSaveDecision::save_version)); if (!history_status.ok()) { LOG("Save version history effect failed: %s", history_status.message); } app_.dialog_save_ver(); } private: App& app_; }; void wire_prompt_save_before_continue_buttons( App& app, const std::shared_ptr& dialog, std::function action) { auto* app_ptr = &app; dialog->btn_ok->on_click = [app_ptr, dialog, action](Node*) { project_save_after_snapshot(*app_ptr, [app_ptr, dialog, action](bool success) { if (success) action(); else { const auto plan = pp::app::plan_document_session_prompt( pp::app::DocumentSessionPromptKind::document_save_error); app_ptr->message_box(plan.title, plan.message, plan.show_cancel); } }); pp::panopainter::close_legacy_dialog_node(*dialog); }; dialog->btn_cancel->on_click = [dialog, action](Node*) { action(); pp::panopainter::close_legacy_dialog_node(*dialog); }; } class LegacyDocumentWorkflowServices final : public pp::app::DocumentWorkflowServices { public: LegacyDocumentWorkflowServices(App& app, std::function action) noexcept : app_(app) , action_(std::move(action)) { } void continue_workflow_now() override { const auto history_status = apply_document_history( pp::app::plan_document_workflow_history( pp::app::DocumentWorkflowDecision::continue_now)); if (!history_status.ok()) { LOG("Workflow continue history effect failed: %s", history_status.message); } action_(); } void prompt_save_before_continue() override { const auto history_status = apply_document_history( pp::app::plan_document_workflow_history( pp::app::DocumentWorkflowDecision::prompt_save_before_continue)); if (!history_status.ok()) { LOG("Workflow prompt history effect failed: %s", history_status.message); } auto m = pp::panopainter::create_legacy_app_message_dialog( app_, pp::app::plan_document_session_prompt( pp::app::DocumentSessionPromptKind::save_before_workflow_continue)); wire_prompt_save_before_continue_buttons(app_, m, action_); } private: App& app_; std::function action_; }; } // namespace pp::foundation::Status execute_legacy_close_request_decision( App& app, pp::app::CloseRequestDecision decision, bool& dialog_already_opened) { LegacyCloseRequestServices services(app, dialog_already_opened); return pp::app::execute_close_request_decision(decision, services); } pp::foundation::Status execute_legacy_document_save_decision( App& app, pp::app::DocumentSaveDecision decision) { LegacyDocumentSaveServices services(app); return pp::app::execute_document_save_decision(decision, services); } pp::foundation::Status execute_legacy_document_workflow_decision( App& app, pp::app::DocumentWorkflowDecision decision, std::function action) { LegacyDocumentWorkflowServices services(app, std::move(action)); return pp::app::execute_document_workflow_decision(decision, services); } pp::foundation::Status execute_legacy_new_document_plan( App& app, const pp::app::NewDocumentPlan& plan, std::shared_ptr dialog) { LegacyNewDocumentServices services(app, std::move(dialog)); return pp::app::execute_new_document_plan(plan, services); } pp::foundation::Status execute_legacy_document_file_save_plan( App& app, const pp::app::DocumentFileSavePlan& plan, std::shared_ptr dialog) { LegacyDocumentFileSaveServices services(app, std::move(dialog)); return pp::app::execute_document_file_save_plan(plan, services); } pp::foundation::Status execute_legacy_document_version_save( App& app, const pp::app::DocumentVersionTarget& target) { LegacyDocumentVersionSaveServices services(app); return pp::app::execute_document_version_save(target, services); } void execute_legacy_document_save_before_cloud_upload(App& app) { Canvas::I->project_save_thread(app.doc_path, true); } } // namespace pp::panopainter