diff --git a/cmake/PanoPainterSources.cmake b/cmake/PanoPainterSources.cmake index ba1d63c9..152902dc 100644 --- a/cmake/PanoPainterSources.cmake +++ b/cmake/PanoPainterSources.cmake @@ -163,6 +163,8 @@ set(PP_PANOPAINTER_APP_SOURCES src/legacy_draw_toolbar_binding_services.h src/app_layout_ui_state.cpp src/app_layout_sidebar.cpp + src/legacy_sidebar_grid_popup_services.cpp + src/legacy_sidebar_grid_popup_services.h src/legacy_sidebar_stroke_popup_services.cpp src/legacy_sidebar_stroke_popup_services.h src/legacy_sidebar_color_popup_services.cpp diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 195da7b6..4b3e0661 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -792,26 +792,40 @@ agent or engineer to remove them without reconstructing context from chat. `bind_legacy_click_destroys_node(...)`; menu/layout-owned popup families still remain on separate retained cleanup paths. - 2026-06-17: `DEBT-0058`/`DEBT-0063` were narrowed again. The retained - usermanual, changelog, and about openers in `src/app_dialogs_info_openers.cpp` - now delegate retained dialog construction and overlay close wiring through + usermanual, changelog, about, What's New, and shortcuts openers in + `src/app_dialogs_info_openers.cpp` now delegate retained dialog construction, + overlay close wiring, and remote-page/button ownership through `src/legacy_info_dialog_services.*` with explicit `App&` plus overlay-anchor dependencies, so the app dialog shell no longer owns that info-dialog family - inline while `open_whatsnew_dialog()` still owns the retained whats-new flow inline. - 2026-06-17: `DEBT-0058`/`DEBT-0063` were narrowed again. The retained New Document and Save dialog openers in `src/app_dialogs_workflow.cpp` now delegate retained dialog construction and button wiring through `src/legacy_document_session_services.*` with explicit `App&` ownership, so the app dialog shell no longer owns that document-session dialog family - inline while browse, open, and resize flows still remain there. + inline. +- 2026-06-17: `DEBT-0058`/`DEBT-0063` were narrowed again. The retained Open, + Browse, and Resize dialog openers in `src/app_dialogs_workflow.cpp` now + delegate retained dialog construction and overlay/button wiring through + `src/legacy_document_open_services.*` and + `src/legacy_document_session_services.*`, so the app dialog shell no longer + owns those workflow dialog families inline. - 2026-06-17: `DEBT-0035` was narrowed again. `App::title_update()` and the - draw-toolbar/stroke-popup binding families now delegate through + draw-toolbar/stroke-popup/grid-popup binding families now delegate through `src/legacy_app_status_services.*`, `src/legacy_draw_toolbar_binding_services.*`, and - `src/legacy_sidebar_stroke_popup_services.*`, so + `src/legacy_sidebar_stroke_popup_services.*`, and + `src/legacy_sidebar_grid_popup_services.*`, so `src/app_layout.cpp`, `src/app_layout_draw_toolbar.cpp`, and part of `src/app_layout_sidebar.cpp` are thinner adapters while retained app-shell - execution and remaining popup families still stay open under the same debt. + execution and the remaining layer popup family still stay open under the same + debt. +- 2026-06-17: `DEBT-0030`/`DEBT-0043`/`DEBT-0044` were narrowed again. + `src/app_dialogs_export.cpp` is now a thin forwarding adapter. Retained + document export start/branching flows now live in + `src/legacy_document_export_services.*`, and the PPBR export dialog opener + now lives in `src/legacy_brush_package_export_services.*`; retained export + execution still remains behind those legacy bridges. - 2026-06-15: `DEBT-0036` was narrowed again. `NodeStrokePreview` now drops the retained pass-sequence, mix-execution, final-composite-request, background capture, and preview-copy wrapper structs/functions in favor of direct diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index bc441042..54a11b07 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -93,12 +93,13 @@ Current conclusion: app shell is down to adapter calls even though runtime draw/event/sidebar execution still remains. - New-document/save dialog session wiring, app-title rendering, draw-toolbar - binding, sidebar stroke-popup binding, and usermanual/changelog/about opener - wiring now live in dedicated `legacy_*services.*` seams, so - `src/app_dialogs_workflow.cpp`, `src/app_layout.cpp`, - `src/app_layout_draw_toolbar.cpp`, `src/app_layout_sidebar.cpp`, and - `src/app_dialogs_info_openers.cpp` are thinner adapters even though broader - retained dialog/sidebar execution still remains. + binding, sidebar stroke/grid-popup binding, export-dialog start wiring, and + the full info-opener family now live in dedicated `legacy_*services.*` seams, + so `src/app_dialogs_workflow.cpp`, `src/app_dialogs_export.cpp`, + `src/app_layout.cpp`, `src/app_layout_draw_toolbar.cpp`, + `src/app_layout_sidebar.cpp`, and `src/app_dialogs_info_openers.cpp` are + thinner adapters even though broader retained dialog/sidebar execution still + remains. - Platform extraction improved substantially and the root app source group no longer compiles Web platform sources directly, but broader CMake and entrypoint cleanup are not complete. diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 4e6ff2a6..69af6b8a 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -65,6 +65,12 @@ Key facts: - `App::dialog_browse()` no longer owns browse-dialog button wiring inline; the retained document-open bridge now owns that handoff in `src/legacy_document_open_services.*`. +- `App::dialog_open()`, `App::dialog_browse()`, and `App::dialog_resize()` now + delegate retained dialog construction and overlay/button wiring through + `src/legacy_document_open_services.*` and + `src/legacy_document_session_services.*`, so + `src/app_dialogs_workflow.cpp` is thinner while the save-before-workflow + policy seam remains local. - `App::init_toolbar_main()` now delegates retained main-toolbar button wiring through `src/legacy_main_toolbar_binding_services.*`, so `src/app_layout_main_toolbar.cpp` is down to a thin root lookup and adapter @@ -104,13 +110,13 @@ Key facts: - `App::dialog_usermanual()`, `App::dialog_changelog()`, and `App::dialog_about()` now delegate the retained info-dialog construction and overlay close wiring through `src/legacy_info_dialog_services.*` with - explicit `App&` plus overlay-anchor dependencies, so - `src/app_dialogs_info_openers.cpp` is thinner while `open_whatsnew_dialog()` - still owns the retained whats-new flow inline. + explicit `App&` plus overlay-anchor dependencies, and the remaining + What's New plus shortcuts flows now route through the same seam, so + `src/app_dialogs_info_openers.cpp` is down to thin forwarding only. - `App::dialog_newdoc()` and `App::dialog_save()` now delegate retained dialog - construction and button wiring through `src/legacy_document_session_services.*`, - so `src/app_dialogs_workflow.cpp` is thinner at the document-session seam - while browse, open, and resize retained workflows still remain there. + construction and button wiring through + `src/legacy_document_session_services.*`, so + `src/app_dialogs_workflow.cpp` is thinner at the document-session seam. - `App::title_update()` now delegates retained document-title and DPI-label rendering through `src/legacy_app_status_services.*`, so `src/app_layout.cpp` no longer owns that app-status family inline. @@ -122,8 +128,16 @@ Key facts: - `App::init_sidebar()` now delegates the retained stroke-popup open/anchor/tick wiring through `src/legacy_sidebar_stroke_popup_services.*` with explicit `App&`, popup-root, trigger-button, and panel dependencies, so - `src/app_layout_sidebar.cpp` is thinner while the retained grid and layer - popup families still remain inline. + `src/app_layout_sidebar.cpp` is thinner while the retained layer popup family + still remains inline. +- `App::init_sidebar()` now delegates the retained grid-popup + open/anchor/tick/close wiring through + `src/legacy_sidebar_grid_popup_services.*`, so the `btn-grids-panel` path in + `src/app_layout_sidebar.cpp` is down to a thin adapter. +- `src/app_dialogs_export.cpp` is now a forwarding adapter; the retained + document export start/branching flows live in + `src/legacy_document_export_services.*`, and the PPBR dialog opener now lives + in `src/legacy_brush_package_export_services.*`. ## Parallel Assignment Rules diff --git a/src/app_dialogs_export.cpp b/src/app_dialogs_export.cpp index d3fa09c4..a5953805 100644 --- a/src/app_dialogs_export.cpp +++ b/src/app_dialogs_export.cpp @@ -1,316 +1,51 @@ #include "pch.h" + #include "app.h" -#include "app_core/app_dialog.h" -#include "app_core/document_export.h" #include "legacy_brush_package_export_services.h" #include "legacy_document_export_services.h" -#include "legacy_ui_overlay_services.h" -#include "node_dialog_export_ppbr.h" - -#include -#define MP4V2_NO_STDINT_DEFS -#include #include namespace pp::panopainter { -namespace { - -[[nodiscard]] bool can_start_document_export(App& app, bool requires_license) -{ - const auto decision = pp::app::plan_document_export_start( - requires_license, - !requires_license || app.check_license(), - app.canvas != nullptr); - - switch (decision) { - case pp::app::DocumentExportStartDecision::start_now: - return true; - case pp::app::DocumentExportStartDecision::show_license_disabled: - { - const auto plan = pp::app::plan_document_export_license_disabled_dialog(); - app.message_box(plan.title, plan.message, plan.show_cancel); - return false; - } - case pp::app::DocumentExportStartDecision::unavailable_no_canvas: - return false; - } - - return false; -} - -void start_document_export_collection( - App& app, - pp::app::DocumentExportCollectionKind kind) -{ - const auto plan = pp::app::plan_document_export_collection_target( - kind, - app.uses_work_directory_document_export_collections()); - const auto success_kind = pp::app::document_export_collection_success_kind(kind); - - if (plan.destination == pp::app::DocumentExportCollectionDestination::work_directory_collection) { - const auto target = pp::app::make_document_export_collection_target( - app.work_path, - app.doc_name, - plan.suffix); - if (!target) { - const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message); - app.message_box(dialog.title, dialog.message, dialog.show_cancel); - return; - } - - const auto status = pp::panopainter::execute_legacy_document_export_collection( - app, - plan.kind, - target.value()); - if (!status.ok()) - LOG( - "%s: %s", - pp::app::document_export_execution_log_message( - kind == pp::app::DocumentExportCollectionKind::layers - ? pp::app::DocumentExportExecutionKind::layers_collection - : pp::app::DocumentExportExecutionKind::animation_frames_collection), - status.message); - return; - } - - app.pick_dir([ - &app, - kind = plan.kind, - success_kind - ](std::string path) { - const auto target = pp::app::make_document_export_stem_target(path, app.doc_name); - if (!target) { - const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message); - app.message_box(dialog.title, dialog.message, dialog.show_cancel); - return; - } - - const auto status = pp::panopainter::execute_legacy_document_export_stem( - app, - kind, - target.value()); - if (!status.ok()) - LOG( - "%s: %s", - pp::app::document_export_execution_log_message( - kind == pp::app::DocumentExportCollectionKind::layers - ? pp::app::DocumentExportExecutionKind::layers_stem - : pp::app::DocumentExportExecutionKind::animation_frames_stem), - status.message); - }); -} - -void start_document_video_export( - App& app, - pp::app::DocumentVideoExportKind kind, - pp::app::DocumentExportSuccessKind success_kind, - const char* suffix, - pp::app::DocumentExportExecutionKind execution_kind) -{ - if (!can_start_document_export(app, false)) - return; - - if (app.uses_prepared_file_writes()) - { - const auto target = pp::app::make_document_export_suggested_name(app.doc_name, suffix); - if (!target) { - const auto dialog = pp::app::plan_document_export_failure_dialog( - success_kind, - target.status().message); - app.message_box(dialog.title, dialog.message, dialog.show_cancel); - return; - } - - app.pick_file_save("mp4", target.value().name, - [&app, kind, execution_kind](std::string path) { - const auto status = pp::panopainter::execute_legacy_document_video_export( - app, - kind, - path, - false); - if (!status.ok()) - LOG( - "%s: %s", - pp::app::document_export_execution_log_message(execution_kind), - status.message); - }, - [](const std::string& path, bool saved) { - (void)path; - (void)saved; - } - ); - return; - } - - app.pick_file_save({ "mp4" }, [&app, kind, execution_kind](std::string path) { - const auto status = pp::panopainter::execute_legacy_document_video_export( - app, - kind, - path, - true); - if (!status.ok()) - LOG( - "%s: %s", - pp::app::document_export_execution_log_message(execution_kind), - status.message); - }); -} - -} // namespace - void open_document_export_dialog(App& app, std::string ext) { - if (!can_start_document_export(app, true)) - return; - - // TODO: use picker - const auto target = pp::app::make_document_export_file_target(app.work_path, app.doc_name, ext); - if (!target) { - const auto dialog = pp::app::plan_document_export_failure_dialog( - pp::app::DocumentExportSuccessKind::equirectangular, - target.status().message); - app.message_box(dialog.title, dialog.message, dialog.show_cancel); - return; - } - - const auto status = pp::panopainter::execute_legacy_document_export_file(app, target.value()); - if (!status.ok()) - LOG( - "%s: %s", - pp::app::document_export_execution_log_message( - pp::app::DocumentExportExecutionKind::equirectangular_file), - status.message); + open_legacy_document_export_dialog(app, std::move(ext)); } void open_document_export_layers_dialog(App& app) { - if (!can_start_document_export(app, true)) - return; - - start_document_export_collection( - app, - pp::app::DocumentExportCollectionKind::layers); + open_legacy_document_export_layers_dialog(app); } void open_document_export_anim_frames_dialog(App& app) { - if (!can_start_document_export(app, true)) - return; - - start_document_export_collection( - app, - pp::app::DocumentExportCollectionKind::animation_frames); + open_legacy_document_export_anim_frames_dialog(app); } void open_document_export_depth_dialog(App& app) { - if (!can_start_document_export(app, true)) - return; - - const auto status = pp::panopainter::execute_legacy_document_export_depth(app, app.doc_name); - if (!status.ok()) - LOG( - "%s: %s", - pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::depth), - status.message); + open_legacy_document_export_depth_dialog(app); } void open_document_export_cube_faces_dialog(App& app) { - if (!can_start_document_export(app, false)) - return; - - const auto status = pp::panopainter::execute_legacy_document_export_cube_faces(app, app.doc_name); - if (!status.ok()) - LOG( - "%s: %s", - pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::cube_faces), - status.message); -} - -void open_document_timelapse_export_dialog(App& app) -{ - start_document_video_export( - app, - pp::app::DocumentVideoExportKind::timelapse, - pp::app::DocumentExportSuccessKind::timelapse, - "-timelapse", - pp::app::DocumentExportExecutionKind::timelapse); -} - -void open_document_export_mp4_dialog(App& app) -{ - start_document_video_export( - app, - pp::app::DocumentVideoExportKind::animation_mp4, - pp::app::DocumentExportSuccessKind::animation_mp4, - "-animation", - pp::app::DocumentExportExecutionKind::animation_mp4); + open_legacy_document_export_cube_faces_dialog(app); } void open_ppbr_export_dialog(App& app) { - auto* overlay_anchor = app.layout[app.main_id]; - if (!overlay_anchor) { - LOG("PPBR export dialog open failed: main layout anchor is missing"); - return; - } + open_legacy_ppbr_export_dialog(app); +} - auto dialog = pp::panopainter::make_legacy_overlay_node(app); +void open_document_timelapse_export_dialog(App& app) +{ + open_legacy_document_timelapse_export_dialog(app); +} - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - LOG("PPBR export dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - - const auto close_dialog = [overlay_anchor, overlay_handle]() { - const auto close_status = pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); - (void)close_status; - }; - - dialog->btn_ok->on_click = [&app, dialog] (Node*) { - const auto request = pp::panopainter::make_legacy_brush_package_export_request(*dialog); - - if (app.uses_prepared_file_writes()) - { - app.pick_file_save("ppbr", "exported-brushes", - [&app, dialog, request] (std::string path) { - const auto status = pp::panopainter::execute_legacy_brush_package_export( - app, - *dialog, - request, - path, - pp::panopainter::LegacyBrushPackageExportMode::inline_export_only); - if (!status.ok()) - LOG("PPBR export failed: %s", status.message); - }, - [dialog] (const std::string& path, bool saved) { - (void)path; - pp::panopainter::complete_legacy_brush_package_export(*dialog, saved); - } - ); - return; - } - - app.pick_file_save({ "ppbr" }, [&app, dialog, request] (std::string path) { - const auto status = pp::panopainter::execute_legacy_brush_package_export( - app, - *dialog, - request, - path, - pp::panopainter::LegacyBrushPackageExportMode::desktop_async_close_and_message); - if (!status.ok()) - LOG("PPBR export failed: %s", status.message); - }); - }; - dialog->btn_cancel->on_click = [close_dialog](Node*) - { - close_dialog(); - }; +void open_document_export_mp4_dialog(App& app) +{ + open_legacy_document_export_mp4_dialog(app); } } // namespace pp::panopainter diff --git a/src/app_dialogs_info_openers.cpp b/src/app_dialogs_info_openers.cpp index e8224b9b..38af8907 100644 --- a/src/app_dialogs_info_openers.cpp +++ b/src/app_dialogs_info_openers.cpp @@ -1,11 +1,6 @@ #include "pch.h" #include "app.h" -#include "legacy_preference_storage.h" -#include "legacy_ui_overlay_services.h" #include "legacy_info_dialog_services.h" -#include "node_remote_page.h" -#include "node_shorcuts.h" -#include "version.h" namespace pp::panopainter { @@ -45,70 +40,12 @@ void open_about_dialog(App& app) void open_whatsnew_dialog(App& app, bool force_show) { - auto* overlay_anchor = app.layout[app.main_id]; - if (!overlay_anchor) { - LOG("What's new dialog open failed: main layout anchor is missing"); - return; - } - - const auto overlay_handle = std::make_shared(); - const auto open_overlay = [overlay_anchor, overlay_handle](const std::shared_ptr& page) { - if (overlay_handle->valid()) { - return; - } - - const auto overlay = open_legacy_overlay_node_with_handle(*overlay_anchor, page); - if (!overlay) { - return; - } - *overlay_handle = overlay.value(); - }; - const auto close_overlay = [overlay_anchor, overlay_handle]() { - if (!overlay_handle->valid()) { - return; - } - - const auto close_status = close_legacy_overlay_node(*overlay_anchor, *overlay_handle); - (void)close_status; - *overlay_handle = {}; - }; - - auto whatsnew = std::make_shared(); - whatsnew->set_manager(&app.layout); - whatsnew->init(); - std::string url = fmt::format("https://panopainter.com/app-content/whatsnew/?version={}", g_version_build); - whatsnew->load_url(url, [whatsnew, force_show, open_overlay](bool success) { - if (success) - { - int last_id = legacy_whatsnew_id_or(0); - if (force_show || (whatsnew->m_page_id <= g_version_build && whatsnew->m_page_id > last_id)) - { - whatsnew->set_title(fmt::format("What's new in version {}", g_version_number)); - if (!force_show) - open_overlay(whatsnew); - } - } - }); - whatsnew->add_button("Reload", 120, [whatsnew](Node*) { - whatsnew->reload(); - }); - whatsnew->add_button("Read Later", 120, [whatsnew, close_overlay](Node*) { - clear_legacy_whatsnew_id(); - save_legacy_preferences(); - close_overlay(); - }); - whatsnew->add_button("Close", 100, [whatsnew, close_overlay](Node*) { - set_legacy_whatsnew_id(whatsnew->m_page_id); - save_legacy_preferences(); - close_overlay(); - }); - if (force_show) - open_overlay(whatsnew); + pp::panopainter::open_legacy_whatsnew_dialog(app, force_show); } void open_shortcuts_dialog(App& app) { - (void)add_legacy_overlay_node(app); + pp::panopainter::open_legacy_shortcuts_dialog(app); } } // namespace pp::panopainter diff --git a/src/app_dialogs_workflow.cpp b/src/app_dialogs_workflow.cpp index 4b54cc03..dc7eb420 100644 --- a/src/app_dialogs_workflow.cpp +++ b/src/app_dialogs_workflow.cpp @@ -1,13 +1,7 @@ #include "pch.h" #include "app.h" -#include "app_core/document_resize.h" #include "legacy_document_open_services.h" -#include "legacy_document_canvas_services.h" #include "legacy_document_session_services.h" -#include "legacy_ui_overlay_services.h" -#include "node_dialog_browse.h" -#include "node_dialog_open.h" -#include "node_dialog_resize.h" void App::continue_document_workflow_after_optional_save(std::function action) { @@ -34,80 +28,16 @@ void App::dialog_newdoc() // DEPRECATED void App::dialog_open() { - auto show_dialog = [this] { - // load thumbnail test - auto* overlay_anchor = layout[main_id]; - if (!overlay_anchor) { - LOG("Open document dialog open failed: main layout anchor is missing"); - return; - } - - auto dialog = pp::panopainter::make_legacy_overlay_node(*this); - - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - LOG("Open document dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - - const auto close_dialog = [overlay_anchor, overlay_handle]() { - const auto close_status = - pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); - (void)close_status; - }; - - dialog->btn_ok->on_click = [this, dialog](Node*) - { -// canvas->reset_camera(); -// layers->clear(); -// doc_name = dialog->selected_name; -// canvas->m_canvas->project_open(dialog->selected_path, [this](bool success) { -// // on complete -// async_start(); -// title_update(); -// for (auto& i : canvas->m_canvas->m_order) -// layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str()); -// async_end(); -// }); -// dialog->destroy(); -// ActionManager::clear(); - }; - dialog->btn_cancel->on_click = [close_dialog](Node*) - { - close_dialog(); - }; - }; - - continue_document_workflow_after_optional_save(show_dialog); + continue_document_workflow_after_optional_save([this] { + pp::panopainter::open_legacy_document_open_dialog(*this); + }); } void App::dialog_browse() { - auto show_dialog = [this] { - auto* overlay_anchor = layout[main_id]; - if (!overlay_anchor) { - LOG("Browse document dialog open failed: main layout anchor is missing"); - return; - } - - auto dialog = pp::panopainter::make_legacy_overlay_node(*this); - dialog->search_paths = document_browse_roots(); - - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - LOG("Browse document dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - pp::panopainter::wire_legacy_document_browse_dialog_actions( - *this, - dialog, - *overlay_anchor, - overlay_handle); - }; - - continue_document_workflow_after_optional_save(show_dialog); + continue_document_workflow_after_optional_save([this] { + pp::panopainter::open_legacy_document_browse_dialog(*this); + }); } void App::dialog_save_ver() @@ -148,41 +78,5 @@ void App::dialog_save() void App::dialog_resize() { - auto* overlay_anchor = layout[main_id]; - if (!overlay_anchor) { - LOG("Resize dialog open failed: main layout anchor is missing"); - return; - } - - auto dialog = pp::panopainter::make_legacy_overlay_node(*this); - const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); - if (!overlay) { - LOG("Resize dialog open failed: %s", overlay.status().message); - return; - } - const auto overlay_handle = overlay.value(); - - const auto close_dialog = [overlay_anchor, overlay_handle]() { - const auto close_status = - pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); - (void)close_status; - }; - - dialog->btn_ok->on_click = [this, dialog, close_dialog](Node*) - { - const auto plan = pp::app::plan_document_resize( - dialog->combo ? dialog->combo->m_current_index : 0); - if (!plan) - { - close_dialog(); - return; - } - const auto status = pp::panopainter::execute_legacy_document_resize_plan(*this, plan.value()); - if (!status.ok()) - LOG("Document resize failed: %s", status.message); - close_dialog(); - }; - dialog->btn_cancel->on_click = [close_dialog](Node*) { - close_dialog(); - }; + pp::panopainter::open_legacy_document_resize_dialog(*this); } diff --git a/src/app_layout_sidebar.cpp b/src/app_layout_sidebar.cpp index a866d5d9..ce0c2f97 100644 --- a/src/app_layout_sidebar.cpp +++ b/src/app_layout_sidebar.cpp @@ -4,6 +4,7 @@ #include "node_panel_floating.h" #include "app_core/brush_ui.h" #include "app_core/document_layer.h" +#include "legacy_sidebar_grid_popup_services.h" #include "legacy_sidebar_color_popup_services.h" #include "legacy_sidebar_stroke_popup_services.h" #include "legacy_brush_ui_services.h" @@ -321,49 +322,7 @@ void App::init_sidebar() if (!popup_root) { return; } - auto screen = popup_root->m_size; - glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); - grid->find("title")->SetVisibility(true); - grid->SetSize(350, YGUndefined); - if (grid->m_parent) - { - if (auto fp = dynamic_cast(grid->m_parent->m_parent)) - { - pp::panopainter::detach_legacy_node_from_parent(*grid); - pp::panopainter::close_legacy_dialog_node(*fp); - } - } - const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, grid); - if (!popup_overlay) - { - LOG("Grid popup overlay failed: %s", popup_overlay.status().message); - return; - } - auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor(*popup_root); - tick->SetPositioning(YGPositionTypeAbsolute); - tick->SetSize(32, 16); - tick->SetPosition(pos.x - 16, pos.y); - tick->set_image("data/ui/popup-tick-up.png"); - auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick); - if (!popup_overlay || !tick_overlay) - { - close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay); - return; - } - const auto popup_handle = popup_overlay.value(); - const auto tick_handle = tick_overlay.value(); - popup_root->update(); - - grid->SetPosition(pos.x - grid->m_size.x / 2.f, pos.y + 16); - grid->SetPositioning(YGPositionTypeAbsolute); - pp::panopainter::activate_legacy_popup_overlay(*grid); - auto scroll = grid->find("scroller"); - scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 250.f)); - - grid->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle); - }; + pp::panopainter::open_legacy_sidebar_grid_popup(*popup_root, *button, *grid); }; } } diff --git a/src/legacy_brush_package_export_services.cpp b/src/legacy_brush_package_export_services.cpp index 41b65da3..4c1ca337 100644 --- a/src/legacy_brush_package_export_services.cpp +++ b/src/legacy_brush_package_export_services.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace pp::panopainter { namespace { @@ -134,4 +135,67 @@ void complete_legacy_brush_package_export(NodeDialogExportPPBR& dialog, bool sav } } +void open_legacy_ppbr_export_dialog(App& app) +{ + auto* overlay_anchor = app.layout[app.main_id]; + if (!overlay_anchor) { + LOG("PPBR export dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(app); + + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + LOG("PPBR export dialog open failed: %s", overlay.status().message); + return; + } + const auto overlay_handle = overlay.value(); + + const auto close_dialog = [overlay_anchor, overlay_handle]() { + const auto close_status = pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); + (void)close_status; + }; + + dialog->btn_ok->on_click = [&app, dialog] (Node*) { + const auto request = pp::panopainter::make_legacy_brush_package_export_request(*dialog); + + if (app.uses_prepared_file_writes()) + { + app.pick_file_save("ppbr", "exported-brushes", + [&app, dialog, request] (std::string path) { + const auto status = pp::panopainter::execute_legacy_brush_package_export( + app, + *dialog, + request, + path, + pp::panopainter::LegacyBrushPackageExportMode::inline_export_only); + if (!status.ok()) + LOG("PPBR export failed: %s", status.message); + }, + [dialog] (const std::string& path, bool saved) { + (void)path; + pp::panopainter::complete_legacy_brush_package_export(*dialog, saved); + } + ); + return; + } + + app.pick_file_save({ "ppbr" }, [&app, dialog, request] (std::string path) { + const auto status = pp::panopainter::execute_legacy_brush_package_export( + app, + *dialog, + request, + path, + pp::panopainter::LegacyBrushPackageExportMode::desktop_async_close_and_message); + if (!status.ok()) + LOG("PPBR export failed: %s", status.message); + }); + }; + dialog->btn_cancel->on_click = [close_dialog](Node*) + { + close_dialog(); + }; +} + } // namespace pp::panopainter diff --git a/src/legacy_brush_package_export_services.h b/src/legacy_brush_package_export_services.h index e97274ca..4eee8585 100644 --- a/src/legacy_brush_package_export_services.h +++ b/src/legacy_brush_package_export_services.h @@ -26,5 +26,6 @@ enum class LegacyBrushPackageExportMode { LegacyBrushPackageExportMode mode); void complete_legacy_brush_package_export(NodeDialogExportPPBR& dialog, bool saved); +void open_legacy_ppbr_export_dialog(App& app); } // namespace pp::panopainter diff --git a/src/legacy_document_export_services.cpp b/src/legacy_document_export_services.cpp index c4b9b70e..4577a084 100644 --- a/src/legacy_document_export_services.cpp +++ b/src/legacy_document_export_services.cpp @@ -13,10 +13,34 @@ #include #include #include +#include namespace pp::panopainter { namespace { +[[nodiscard]] bool can_start_legacy_document_export(App& app, bool requires_license) +{ + const auto decision = pp::app::plan_document_export_start( + requires_license, + !requires_license || app.check_license(), + app.canvas != nullptr); + + switch (decision) { + case pp::app::DocumentExportStartDecision::start_now: + return true; + case pp::app::DocumentExportStartDecision::show_license_disabled: + { + const auto plan = pp::app::plan_document_export_license_disabled_dialog(); + app.message_box(plan.title, plan.message, plan.show_cancel); + return false; + } + case pp::app::DocumentExportStartDecision::unavailable_no_canvas: + return false; + } + + return false; +} + void show_export_success_dialog( App& app, const pp::app::DocumentExportSuccessDialogPlan& plan) @@ -26,6 +50,124 @@ void show_export_success_dialog( } } +void start_legacy_document_export_collection( + App& app, + pp::app::DocumentExportCollectionKind kind) +{ + const auto plan = pp::app::plan_document_export_collection_target( + kind, + app.uses_work_directory_document_export_collections()); + const auto success_kind = pp::app::document_export_collection_success_kind(kind); + + if (plan.destination == pp::app::DocumentExportCollectionDestination::work_directory_collection) { + const auto target = pp::app::make_document_export_collection_target( + app.work_path, + app.doc_name, + plan.suffix); + if (!target) { + const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message); + app.message_box(dialog.title, dialog.message, dialog.show_cancel); + return; + } + + const auto status = pp::panopainter::execute_legacy_document_export_collection( + app, + plan.kind, + target.value()); + if (!status.ok()) + LOG( + "%s: %s", + pp::app::document_export_execution_log_message( + kind == pp::app::DocumentExportCollectionKind::layers + ? pp::app::DocumentExportExecutionKind::layers_collection + : pp::app::DocumentExportExecutionKind::animation_frames_collection), + status.message); + return; + } + + app.pick_dir([ + &app, + kind = plan.kind, + success_kind + ](std::string path) { + const auto target = pp::app::make_document_export_stem_target(path, app.doc_name); + if (!target) { + const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message); + app.message_box(dialog.title, dialog.message, dialog.show_cancel); + return; + } + + const auto status = pp::panopainter::execute_legacy_document_export_stem( + app, + kind, + target.value()); + if (!status.ok()) + LOG( + "%s: %s", + pp::app::document_export_execution_log_message( + kind == pp::app::DocumentExportCollectionKind::layers + ? pp::app::DocumentExportExecutionKind::layers_stem + : pp::app::DocumentExportExecutionKind::animation_frames_stem), + status.message); + }); +} + +void start_legacy_document_video_export( + App& app, + pp::app::DocumentVideoExportKind kind, + pp::app::DocumentExportSuccessKind success_kind, + const char* suffix, + pp::app::DocumentExportExecutionKind execution_kind) +{ + if (!can_start_legacy_document_export(app, false)) + return; + + if (app.uses_prepared_file_writes()) + { + const auto target = pp::app::make_document_export_suggested_name(app.doc_name, suffix); + if (!target) { + const auto dialog = pp::app::plan_document_export_failure_dialog( + success_kind, + target.status().message); + app.message_box(dialog.title, dialog.message, dialog.show_cancel); + return; + } + + app.pick_file_save("mp4", target.value().name, + [&app, kind, execution_kind](std::string path) { + const auto status = pp::panopainter::execute_legacy_document_video_export( + app, + kind, + path, + false); + if (!status.ok()) + LOG( + "%s: %s", + pp::app::document_export_execution_log_message(execution_kind), + status.message); + }, + [](const std::string& path, bool saved) { + (void)path; + (void)saved; + } + ); + return; + } + + app.pick_file_save({ "mp4" }, [&app, kind, execution_kind](std::string path) { + const auto status = pp::panopainter::execute_legacy_document_video_export( + app, + kind, + path, + true); + if (!status.ok()) + LOG( + "%s: %s", + pp::app::document_export_execution_log_message(execution_kind), + status.message); + }); +} + struct LegacyDocumentExportSnapshotReports { pp::app::DocumentCanvasSnapshotResult snapshot; pp::paint_renderer::DocumentFrameFacePngExportResult face_pngs; @@ -834,6 +976,96 @@ void execute_legacy_document_export_equirectangular_thread(std::string file_path execute_legacy_document_export_equirectangular_thread_impl(std::move(file_path)); } +void open_legacy_document_export_dialog(App& app, std::string ext) +{ + if (!can_start_legacy_document_export(app, true)) + return; + + // TODO: use picker + const auto target = pp::app::make_document_export_file_target(app.work_path, app.doc_name, ext); + if (!target) { + const auto dialog = pp::app::plan_document_export_failure_dialog( + pp::app::DocumentExportSuccessKind::equirectangular, + target.status().message); + app.message_box(dialog.title, dialog.message, dialog.show_cancel); + return; + } + + const auto status = pp::panopainter::execute_legacy_document_export_file(app, target.value()); + if (!status.ok()) + LOG( + "%s: %s", + pp::app::document_export_execution_log_message( + pp::app::DocumentExportExecutionKind::equirectangular_file), + status.message); +} + +void open_legacy_document_export_layers_dialog(App& app) +{ + if (!can_start_legacy_document_export(app, true)) + return; + + start_legacy_document_export_collection( + app, + pp::app::DocumentExportCollectionKind::layers); +} + +void open_legacy_document_export_anim_frames_dialog(App& app) +{ + if (!can_start_legacy_document_export(app, true)) + return; + + start_legacy_document_export_collection( + app, + pp::app::DocumentExportCollectionKind::animation_frames); +} + +void open_legacy_document_export_depth_dialog(App& app) +{ + if (!can_start_legacy_document_export(app, true)) + return; + + const auto status = pp::panopainter::execute_legacy_document_export_depth(app, app.doc_name); + if (!status.ok()) + LOG( + "%s: %s", + pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::depth), + status.message); +} + +void open_legacy_document_export_cube_faces_dialog(App& app) +{ + if (!can_start_legacy_document_export(app, false)) + return; + + const auto status = pp::panopainter::execute_legacy_document_export_cube_faces(app, app.doc_name); + if (!status.ok()) + LOG( + "%s: %s", + pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::cube_faces), + status.message); +} + +void open_legacy_document_timelapse_export_dialog(App& app) +{ + start_legacy_document_video_export( + app, + pp::app::DocumentVideoExportKind::timelapse, + pp::app::DocumentExportSuccessKind::timelapse, + "-timelapse", + pp::app::DocumentExportExecutionKind::timelapse); +} + +void open_legacy_document_export_mp4_dialog(App& app) +{ + start_legacy_document_video_export( + app, + pp::app::DocumentVideoExportKind::animation_mp4, + pp::app::DocumentExportSuccessKind::animation_mp4, + "-animation", + pp::app::DocumentExportExecutionKind::animation_mp4); +} + pp::foundation::Status execute_legacy_document_export_file( App& app, const pp::app::DocumentExportFileTarget& target) diff --git a/src/legacy_document_export_services.h b/src/legacy_document_export_services.h index 8fe6e33c..fa987c63 100644 --- a/src/legacy_document_export_services.h +++ b/src/legacy_document_export_services.h @@ -7,6 +7,7 @@ class App; #include #include +#include namespace pp::panopainter { @@ -38,6 +39,14 @@ namespace pp::panopainter { std::string_view path, bool asynchronous); +void open_legacy_document_export_dialog(App& app, std::string ext); +void open_legacy_document_export_layers_dialog(App& app); +void open_legacy_document_export_anim_frames_dialog(App& app); +void open_legacy_document_export_depth_dialog(App& app); +void open_legacy_document_export_cube_faces_dialog(App& app); +void open_legacy_document_timelapse_export_dialog(App& app); +void open_legacy_document_export_mp4_dialog(App& app); + void execute_legacy_document_export_equirectangular( std::string file_path, std::function on_complete); diff --git a/src/legacy_document_open_services.cpp b/src/legacy_document_open_services.cpp index 0a4888ba..f4dc1254 100644 --- a/src/legacy_document_open_services.cpp +++ b/src/legacy_document_open_services.cpp @@ -9,6 +9,7 @@ #include "legacy_history_services.h" #include "legacy_ui_overlay_services.h" #include "log.h" +#include "node_dialog_open.h" #include "node_dialog_browse.h" #include "node_panel_brush.h" #include "node_panel_layer.h" @@ -112,6 +113,38 @@ void prompt_discard_unsaved_project(App& app, const pp::app::DocumentOpenRoute& }; } +void open_legacy_document_open_dialog_impl(App& app) +{ + auto* overlay_anchor = app.layout[app.main_id]; + if (!overlay_anchor) { + LOG("Open document dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(app); + + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + LOG("Open document dialog open failed: %s", overlay.status().message); + return; + } + const auto overlay_handle = overlay.value(); + + const auto close_dialog = [overlay_anchor, overlay_handle]() { + const auto close_status = + pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); + (void)close_status; + }; + + dialog->btn_ok->on_click = [](Node*) + { + }; + dialog->btn_cancel->on_click = [close_dialog](Node*) + { + close_dialog(); + }; +} + class LegacyDocumentOpenServices final : public pp::app::DocumentOpenServices { public: explicit LegacyDocumentOpenServices(App& app) noexcept @@ -181,6 +214,30 @@ void wire_legacy_document_browse_dialog_actions( }; } +void open_legacy_document_browse_dialog(App& app) +{ + auto* overlay_anchor = app.layout[app.main_id]; + if (!overlay_anchor) { + LOG("Browse document dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(app); + dialog->search_paths = app.document_browse_roots(); + + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + LOG("Browse document dialog open failed: %s", overlay.status().message); + return; + } + + pp::panopainter::wire_legacy_document_browse_dialog_actions( + app, + dialog, + *overlay_anchor, + overlay.value()); +} + pp::foundation::Status execute_legacy_document_open_plan( App& app, pp::app::DocumentOpenPlanAction action, @@ -219,4 +276,9 @@ void execute_legacy_downloaded_project_open( reconcile_downloaded_project_open(app); } +void open_legacy_document_open_dialog(App& app) +{ + open_legacy_document_open_dialog_impl(app); +} + } // namespace pp::panopainter diff --git a/src/legacy_document_open_services.h b/src/legacy_document_open_services.h index 6f0fc5d9..150aab7c 100644 --- a/src/legacy_document_open_services.h +++ b/src/legacy_document_open_services.h @@ -10,6 +10,7 @@ class App; class Node; +class NodeDialogOpen; class NodeDialogBrowse; namespace pp::panopainter { @@ -18,11 +19,15 @@ namespace pp::panopainter { App& app, std::string path); +void open_legacy_document_open_dialog(App& app); + [[nodiscard]] pp::foundation::Status execute_legacy_document_open_plan( App& app, pp::app::DocumentOpenPlanAction action, const pp::app::DocumentOpenRoute& route); +void open_legacy_document_browse_dialog(App& app); + void wire_legacy_document_browse_dialog_actions( App& app, const std::shared_ptr& dialog, diff --git a/src/legacy_document_session_services.cpp b/src/legacy_document_session_services.cpp index 8a187f6f..a6f26494 100644 --- a/src/legacy_document_session_services.cpp +++ b/src/legacy_document_session_services.cpp @@ -10,6 +10,7 @@ #include "legacy_history_services.h" #include "legacy_ui_overlay_services.h" #include "node_dialog_open.h" +#include "node_dialog_resize.h" #include @@ -487,6 +488,47 @@ void open_legacy_document_file_save_dialog_impl(App& app) wire_document_file_save_dialog_buttons(app, dialog); } +void open_legacy_document_resize_dialog_impl(App& app) +{ + auto* overlay_anchor = app.layout[app.main_id]; + if (!overlay_anchor) { + LOG("Resize dialog open failed: main layout anchor is missing"); + return; + } + + auto dialog = pp::panopainter::make_legacy_overlay_node(app); + const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog); + if (!overlay) { + LOG("Resize dialog open failed: %s", overlay.status().message); + return; + } + const auto overlay_handle = overlay.value(); + + const auto close_dialog = [overlay_anchor, overlay_handle]() { + const auto close_status = + pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle); + (void)close_status; + }; + + dialog->btn_ok->on_click = [&app, dialog, close_dialog](Node*) + { + const auto plan = pp::app::plan_document_resize( + dialog->combo ? dialog->combo->m_current_index : 0); + if (!plan) + { + close_dialog(); + return; + } + const auto status = pp::panopainter::execute_legacy_document_resize_plan(app, plan.value()); + if (!status.ok()) + LOG("Document resize failed: %s", status.message); + close_dialog(); + }; + dialog->btn_cancel->on_click = [close_dialog](Node*) { + close_dialog(); + }; +} + } // namespace pp::foundation::Status execute_legacy_close_request_decision( @@ -561,6 +603,11 @@ void open_legacy_document_file_save_dialog(App& app) open_legacy_document_file_save_dialog_impl(app); } +void open_legacy_document_resize_dialog(App& app) +{ + open_legacy_document_resize_dialog_impl(app); +} + pp::foundation::Status execute_legacy_document_version_save( App& app, const pp::app::DocumentVersionTarget& target) diff --git a/src/legacy_document_session_services.h b/src/legacy_document_session_services.h index b8f0fb32..093c632a 100644 --- a/src/legacy_document_session_services.h +++ b/src/legacy_document_session_services.h @@ -9,6 +9,7 @@ class App; class NodeDialogNewDoc; class NodeDialogSave; +class NodeDialogResize; namespace pp::panopainter { @@ -44,6 +45,8 @@ void open_legacy_new_document_dialog(App& app); void open_legacy_document_file_save_dialog(App& app); +void open_legacy_document_resize_dialog(App& app); + [[nodiscard]] pp::foundation::Status execute_legacy_document_version_save( App& app, const pp::app::DocumentVersionTarget& target); diff --git a/src/legacy_info_dialog_services.cpp b/src/legacy_info_dialog_services.cpp index 03a92869..2bcfd5e6 100644 --- a/src/legacy_info_dialog_services.cpp +++ b/src/legacy_info_dialog_services.cpp @@ -3,14 +3,27 @@ #include "legacy_info_dialog_services.h" #include "app.h" +#include "legacy_preference_storage.h" #include "legacy_ui_overlay_services.h" +#include "node_remote_page.h" +#include "node_shorcuts.h" #include "node_about.h" #include "node_changelog.h" #include "node_usermanual.h" +#include "version.h" namespace pp::panopainter { namespace { +Node* get_legacy_info_dialog_overlay_anchor(App& app, const char* log_name) +{ + auto* overlay_anchor = app.layout[app.main_id]; + if (!overlay_anchor) { + LOG("%s dialog open failed: main layout anchor is missing", log_name); + } + return overlay_anchor; +} + template void open_legacy_info_dialog(App& app, Node& overlay_anchor, const char* log_name) { @@ -49,4 +62,71 @@ void open_about_dialog(App& app, Node& overlay_anchor, const char* log_name) open_legacy_info_dialog(app, overlay_anchor, log_name); } +void open_legacy_whatsnew_dialog(App& app, bool force_show) +{ + auto* overlay_anchor = get_legacy_info_dialog_overlay_anchor(app, "What's new"); + if (!overlay_anchor) { + return; + } + + const auto overlay_handle = std::make_shared(); + const auto open_overlay = [overlay_anchor, overlay_handle](const std::shared_ptr& page) { + if (overlay_handle->valid()) { + return; + } + + const auto overlay = open_legacy_overlay_node_with_handle(*overlay_anchor, page); + if (!overlay) { + return; + } + *overlay_handle = overlay.value(); + }; + const auto close_overlay = [overlay_anchor, overlay_handle]() { + if (!overlay_handle->valid()) { + return; + } + + const auto close_status = close_legacy_overlay_node(*overlay_anchor, *overlay_handle); + (void)close_status; + *overlay_handle = {}; + }; + + auto whatsnew = std::make_shared(); + whatsnew->set_manager(&app.layout); + whatsnew->init(); + const std::string url = fmt::format("https://panopainter.com/app-content/whatsnew/?version={}", g_version_build); + whatsnew->load_url(url, [whatsnew, force_show, open_overlay](bool success) { + if (success) { + const int last_id = legacy_whatsnew_id_or(0); + if (force_show || (whatsnew->m_page_id <= g_version_build && whatsnew->m_page_id > last_id)) { + whatsnew->set_title(fmt::format("What's new in version {}", g_version_number)); + if (!force_show) { + open_overlay(whatsnew); + } + } + } + }); + whatsnew->add_button("Reload", 120, [whatsnew](Node*) { + whatsnew->reload(); + }); + whatsnew->add_button("Read Later", 120, [whatsnew, close_overlay](Node*) { + clear_legacy_whatsnew_id(); + save_legacy_preferences(); + close_overlay(); + }); + whatsnew->add_button("Close", 100, [whatsnew, close_overlay](Node*) { + set_legacy_whatsnew_id(whatsnew->m_page_id); + save_legacy_preferences(); + close_overlay(); + }); + if (force_show) { + open_overlay(whatsnew); + } +} + +void open_legacy_shortcuts_dialog(App& app) +{ + (void)add_legacy_overlay_node(app); +} + } // namespace pp::panopainter diff --git a/src/legacy_info_dialog_services.h b/src/legacy_info_dialog_services.h index 42774230..427243e3 100644 --- a/src/legacy_info_dialog_services.h +++ b/src/legacy_info_dialog_services.h @@ -8,5 +8,7 @@ namespace pp::panopainter { void open_usermanual_dialog(App& app, Node& overlay_anchor, const char* log_name); void open_changelog_dialog(App& app, Node& overlay_anchor, const char* log_name); void open_about_dialog(App& app, Node& overlay_anchor, const char* log_name); +void open_legacy_whatsnew_dialog(App& app, bool force_show); +void open_legacy_shortcuts_dialog(App& app); } // namespace pp::panopainter diff --git a/src/legacy_sidebar_grid_popup_services.cpp b/src/legacy_sidebar_grid_popup_services.cpp new file mode 100644 index 00000000..5d80a3ee --- /dev/null +++ b/src/legacy_sidebar_grid_popup_services.cpp @@ -0,0 +1,73 @@ +#include "pch.h" +#include "legacy_sidebar_grid_popup_services.h" + +#include "legacy_ui_overlay_services.h" +#include "log.h" +#include "node_button_custom.h" +#include "node_image.h" +#include "node_panel_floating.h" +#include "node_panel_grid.h" +#include "node_scroll.h" + +namespace pp::panopainter { + +void open_legacy_sidebar_grid_popup( + Node& popup_root, + NodeButtonCustom& trigger_button, + NodePanelGrid& popup_panel) +{ + const glm::vec2 pos = trigger_button.m_pos + glm::vec2(trigger_button.m_size.x * 0.5f, trigger_button.m_size.y); + const auto screen = popup_root.m_size; + + popup_panel.find("title")->SetVisibility(true); + popup_panel.SetSize(350, YGUndefined); + + if (popup_panel.m_parent) + { + if (auto fp = dynamic_cast(popup_panel.m_parent->m_parent)) + { + detach_legacy_node_from_parent(popup_panel); + close_legacy_dialog_node(*fp); + } + } + + const auto popup_overlay = open_legacy_overlay_node_with_handle( + popup_root, + std::static_pointer_cast(popup_panel.shared_from_this())); + if (!popup_overlay) + { + LOG("Grid popup overlay failed: %s", popup_overlay.status().message); + return; + } + + auto tick = make_legacy_overlay_node_for_anchor(popup_root); + tick->SetPositioning(YGPositionTypeAbsolute); + tick->SetSize(32, 16); + tick->SetPosition(pos.x - 16, pos.y); + tick->set_image("data/ui/popup-tick-up.png"); + + const auto tick_overlay = open_legacy_overlay_node_with_handle(popup_root, tick); + if (!popup_overlay || !tick_overlay) + { + close_legacy_overlay_handles_if_open(popup_root, popup_overlay, tick_overlay); + return; + } + + const auto popup_handle = popup_overlay.value(); + const auto tick_handle = tick_overlay.value(); + popup_root.update(); + + popup_panel.SetPosition(pos.x - popup_panel.m_size.x / 2.f, pos.y + 16); + popup_panel.SetPositioning(YGPositionTypeAbsolute); + activate_legacy_popup_overlay(popup_panel); + + auto scroll = popup_panel.find("scroller"); + scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 250.f)); + + popup_panel.on_popup_close = [&popup_root, popup_handle, tick_handle](Node*) { + close_legacy_overlay_handle_ignoring_status(popup_root, popup_handle); + close_legacy_overlay_handle_ignoring_status(popup_root, tick_handle); + }; +} + +} // namespace pp::panopainter diff --git a/src/legacy_sidebar_grid_popup_services.h b/src/legacy_sidebar_grid_popup_services.h new file mode 100644 index 00000000..673071c8 --- /dev/null +++ b/src/legacy_sidebar_grid_popup_services.h @@ -0,0 +1,14 @@ +#pragma once + +class Node; +class NodeButtonCustom; +class NodePanelGrid; + +namespace pp::panopainter { + +void open_legacy_sidebar_grid_popup( + Node& popup_root, + NodeButtonCustom& trigger_button, + NodePanelGrid& popup_panel); + +} // namespace pp::panopainter