diff --git a/cmake/PanoPainterSources.cmake b/cmake/PanoPainterSources.cmake index 9e890247..d43ca0d0 100644 --- a/cmake/PanoPainterSources.cmake +++ b/cmake/PanoPainterSources.cmake @@ -94,6 +94,8 @@ set(PP_LEGACY_APP_SOURCES src/legacy_canvas_mode_transform.cpp src/legacy_app_shell_services.cpp src/legacy_app_shell_services.h + src/legacy_about_menu_binding_services.cpp + src/legacy_about_menu_binding_services.h src/legacy_app_shell_performance_test_services.cpp src/legacy_app_shell_performance_test_services.h src/legacy_canvas_tool_services.cpp @@ -157,9 +159,15 @@ set(PP_PANOPAINTER_APP_SOURCES src/app_layout_edit_menu.cpp src/app_layout_about_layer_menu.cpp src/app_layout_file_menu.cpp + src/legacy_file_menu_binding_services.cpp + src/legacy_file_menu_binding_services.h src/app_layout_tools_menu.cpp + src/legacy_tools_menu_binding_services.cpp + src/legacy_tools_menu_binding_services.h src/app_shaders.cpp src/app_vr.cpp + src/legacy_main_toolbar_binding_services.cpp + src/legacy_main_toolbar_binding_services.h src/legacy_app_runtime_shell_services.cpp src/legacy_app_frame_services.cpp src/legacy_app_dialog_services.cpp diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 776124fd..2121c921 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -25,6 +25,29 @@ agent or engineer to remove them without reconstructing context from chat. owns that document-open handoff inline while retained dialog creation, unsaved-project prompting, project-open execution, and title/layer refresh still remain. +- 2026-06-17: `DEBT-0035` was narrowed again. + `src/app_layout_main_toolbar.cpp` no longer owns the retained main-toolbar + button wiring inline; `src/legacy_main_toolbar_binding_services.*` now owns + the per-button bindings behind explicit `App&` plus toolbar-root + dependencies, while the app-layout file remains a thin layout-root adapter + and retained toolbar execution still lives in + `src/legacy_app_shell_services.*`. +- 2026-06-17: `DEBT-0031`/`DEBT-0030` were narrowed again. + `src/app_layout_file_menu.cpp` no longer owns the retained File-menu popup, + export-submenu popup, or button wiring inline; that binding now lives in + `src/legacy_file_menu_binding_services.*`, while retained file/export command + execution still lives in `src/legacy_app_shell_services.*`. +- 2026-06-17: `DEBT-0034` was narrowed again. + `src/app_layout_about_layer_menu.cpp` no longer owns the retained About-menu + popup creation, version-label setup, or button wiring inline; that binding + now lives in `src/legacy_about_menu_binding_services.*`, while retained About + command execution and diagnostics still live in + `src/legacy_app_shell_services.*`. +- 2026-06-17: `DEBT-0033` was narrowed again. + `src/app_layout_tools_menu.cpp` no longer owns the retained Tools > Panels + submenu popup flow or panel-item wiring inline; that binding now lives in + `src/legacy_tools_menu_binding_services.*`, while retained Tools command + execution and options-menu preference wiring still remain in the app shell. - 2026-06-17: `DEBT-0038` was narrowed again. The retained cloud upload and download background execution in `src/legacy_cloud_services.cpp` now routes through `AppRuntime::canvas_async_task` instead of a file-static worker diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 8d8789d6..5985206f 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -83,6 +83,10 @@ Current conclusion: `src/legacy_document_open_services.*`, and retained cloud upload/download, brush-package import, and timelapse-export async paths now use `AppRuntime::canvas_async_task` instead of file-static worker singletons. +- Main-toolbar, File-menu, About-menu, and Tools > Panels binding ownership now + lives in dedicated `legacy_*_binding_services.*` helpers, so the + corresponding `app_layout_*` files are thinner adapters even though retained + execution still lives in the app shell. - 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 c16c8544..8a876126 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -65,6 +65,25 @@ 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::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 + call while retained toolbar execution still lives in + `src/legacy_app_shell_services.*`. +- `App::init_menu_file()` now delegates retained File-menu popup and export + submenu wiring through `src/legacy_file_menu_binding_services.*`, so + `src/app_layout_file_menu.cpp` is down to a thin trigger lookup and adapter + call while retained file/export execution still lives in + `src/legacy_app_shell_services.*`. +- `App::init_menu_about()` now delegates retained About-menu popup wiring + through `src/legacy_about_menu_binding_services.*`, so + `src/app_layout_about_layer_menu.cpp` no longer owns the About callback body + inline while retained About execution still lives in + `src/legacy_app_shell_services.*`. +- `App::init_menu_tools()` now delegates the retained Tools > Panels submenu + wiring through `src/legacy_tools_menu_binding_services.*`, so + `src/app_layout_tools_menu.cpp` no longer owns that floating-panel submenu + body inline while retained Tools execution and options wiring remain. ## Parallel Assignment Rules diff --git a/src/app_layout_about_layer_menu.cpp b/src/app_layout_about_layer_menu.cpp index 8f9c5609..625b9b34 100644 --- a/src/app_layout_about_layer_menu.cpp +++ b/src/app_layout_about_layer_menu.cpp @@ -1,8 +1,7 @@ #include "pch.h" #include "app.h" -#include "app_core/about_menu.h" #include "app_core/document_layer.h" -#include "legacy_app_shell_services.h" +#include "legacy_about_menu_binding_services.h" #include "legacy_document_layer_services.h" #include "legacy_ui_overlay_services.h" #include "node_button_custom.h" @@ -70,11 +69,6 @@ pp::app::DocumentLayerMenuPlan make_layer_menu_plan( return {}; } -void execute_about_menu_plan(App& app, const pp::app::AboutMenuPlan& plan) -{ - pp::panopainter::execute_legacy_about_menu_plan(app, plan); -} - void execute_document_layer_menu_plan(App& app, const pp::app::DocumentLayerMenuPlan& plan) { const auto status = pp::panopainter::execute_legacy_document_layer_menu_plan(app, plan); @@ -92,110 +86,18 @@ void bind_legacy_about_menu(App& app) if (auto* menu_file = main->find("menu-about")) { - menu_file->on_click = [&app, menu_file](Node*) { - auto* popup_root = app.layout[app.main_id]; - if (!popup_root) { - return; - } - glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); - auto popup = add_menu_popup(app, "about-menu", pos, menu_file->m_size.x); - if (!popup) - return; - pp::panopainter::detach_legacy_node_from_parent(*popup); - auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, popup); - if (!popup_overlay) { - pp::panopainter::destroy_legacy_node(*popup); - return; - } - auto popup_handle = popup_overlay.value(); - - popup->find("about-app")->on_click = [&app, popup_root, popup_handle](Node*) { - const auto plan = pp::app::plan_about_menu_command( - pp::app::AboutMenuCommand::about_app, - g_version_major, - g_version_minor, - g_version_fix); - execute_about_menu_plan(app, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - } - }; - - popup->find("about-doc")->on_click = [&app, popup_root, popup_handle](Node*) { -// auto path = Asset::absolute("data/doc/test.pdf"); -// display_file(path); - const auto plan = pp::app::plan_about_menu_command( - pp::app::AboutMenuCommand::help_guide, - g_version_major, - g_version_minor, - g_version_fix); - execute_about_menu_plan(app, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - } - }; - - if (auto item = popup->find("about-news")) - { - if (auto text = item->find("menu-label")) - { - const auto plan = pp::app::plan_about_menu_command( - pp::app::AboutMenuCommand::whats_new, - g_version_major, - g_version_minor, - g_version_fix); - text->set_text(plan.label.c_str()); - } - item->on_click = [&app, popup_root, popup_handle](Node*) { - const auto plan = pp::app::plan_about_menu_command( - pp::app::AboutMenuCommand::whats_new, - g_version_major, - g_version_minor, - g_version_fix); - execute_about_menu_plan(app, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - } - }; - } - - if (auto b = popup->find("about-crash")) - { - b->on_click = [&app, popup_root, popup_handle](Node*) { - const auto plan = pp::app::plan_about_menu_command( - pp::app::AboutMenuCommand::induce_crash, - g_version_major, - g_version_minor, - g_version_fix); - execute_about_menu_plan(app, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - } - }; - } - - if (auto b = popup->find("about-perf")) - { - b->on_click = [&app, popup_root, popup_handle](Node*) { - const auto plan = pp::app::plan_about_menu_command( - pp::app::AboutMenuCommand::performance_test, - g_version_major, - g_version_minor, - g_version_fix, - true, - Canvas::I != nullptr); - execute_about_menu_plan(app, plan); - if (plan.closes_root_popup) - { - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - } - }; - } - }; + auto* popup_root = app.layout[app.main_id]; + if (!popup_root) { + return; + } + pp::panopainter::bind_legacy_about_menu_popup( + app, + *popup_root, + *menu_file, + g_version_major, + g_version_minor, + g_version_fix, + app.canvas && app.canvas->m_canvas); } } diff --git a/src/app_layout_file_menu.cpp b/src/app_layout_file_menu.cpp index 30097b5c..a0794859 100644 --- a/src/app_layout_file_menu.cpp +++ b/src/app_layout_file_menu.cpp @@ -1,51 +1,7 @@ #include "pch.h" #include "app.h" -#include "app_core/document_export.h" -#include "app_core/file_menu.h" -#include "legacy_app_shell_services.h" -#include "legacy_ui_overlay_services.h" +#include "legacy_file_menu_binding_services.h" #include "node_button_custom.h" -#include "node_popup_menu.h" - -namespace { - -void apply_document_export_menu_plan(App& app, pp::app::DocumentExportMenuKind kind) -{ - (void)pp::panopainter::apply_legacy_document_export_menu_plan(app, kind); -} - -void apply_file_menu_plan(App& app, pp::app::FileMenuCommand command) -{ - pp::panopainter::apply_legacy_file_menu_command(app, command); -} - -std::shared_ptr add_menu_popup( - App& app, - const char* template_id, - glm::vec2 position, - float rtl_anchor_width) -{ - const auto popup = pp::panopainter::add_legacy_popup_menu( - app, - template_id, - position.x, - position.y, - rtl_anchor_width); - if (!popup) { - LOG("Popup menu '%s' failed: %s", template_id ? template_id : "", popup.status().message); - return nullptr; - } - return popup.value(); -} - -void close_legacy_overlay_handle_ignoring_status( - Node& anchor, - pp::ui::NodeHandle overlay) noexcept -{ - (void)pp::panopainter::close_legacy_overlay_node(anchor, overlay); -} - -} // namespace namespace pp::panopainter { @@ -55,135 +11,7 @@ void bind_legacy_file_menu(App& app) if (auto* menu_file = main->find("menu-file")) { - menu_file->on_click = [&app, menu_file](Node*) { - auto* popup_root = app.layout[app.main_id]; - if (!popup_root) { - return; - } - const auto open_checked_menu_popup = [popup_root](App& app_ref, const char* id, glm::vec2 pos, float width) - -> std::pair, pp::ui::NodeHandle> - { - auto popup = add_menu_popup(app_ref, id, pos, width); - if (!popup) { - return {}; - } - pp::panopainter::detach_legacy_node_from_parent(*popup); - auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, popup); - if (!popup_overlay) { - pp::panopainter::destroy_legacy_node(*popup); - return {}; - } - return { popup, popup_overlay.value() }; - }; - - glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); - const auto [popup, popup_handle] = open_checked_menu_popup(app, "file-menu", pos, menu_file->m_size.x); - if (!popup) - return; - - if (auto b = popup->find("file-newdoc")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::new_document); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-import")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::import_image); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-open")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::open_project); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-browse")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::browse_cloud); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-save")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::save); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-save-as")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::save_as); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-save-ver")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::save_version); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-export")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::export_jpeg); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-export-tick")) - b->on_click = [&app, b, popup_root, popup_handle, open_checked_menu_popup](Node*) { - glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0); - const auto [subpopup, subpopup_handle] = open_checked_menu_popup(app, "file-submenu-export", pos, b->m_size.x); - if (!subpopup) - return; - subpopup->find("file-submenu-export-png")->on_click = [&app, popup_root, popup_handle, subpopup_handle](Node*) { - apply_document_export_menu_plan(app, pp::app::DocumentExportMenuKind::png); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, subpopup_handle); - }; - subpopup->find("file-submenu-export-layers")->on_click = [&app, popup_root, popup_handle, subpopup_handle](Node*) { - apply_document_export_menu_plan(app, pp::app::DocumentExportMenuKind::layers); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, subpopup_handle); - }; - subpopup->find("file-submenu-export-cube")->on_click = [&app, popup_root, popup_handle, subpopup_handle](Node*) { - apply_document_export_menu_plan(app, pp::app::DocumentExportMenuKind::cube_faces); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, subpopup_handle); - }; - subpopup->find("file-submenu-export-depth")->on_click = [&app, popup_root, popup_handle, subpopup_handle](Node*) { - apply_document_export_menu_plan(app, pp::app::DocumentExportMenuKind::depth); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, subpopup_handle); - }; - subpopup->find("file-submenu-export-anim")->on_click = [&app, popup_root, popup_handle, subpopup_handle](Node*) { - apply_document_export_menu_plan(app, pp::app::DocumentExportMenuKind::animation_frames); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, subpopup_handle); - }; - subpopup->find("file-submenu-export-anim-mp4")->on_click = [&app, popup_root, popup_handle, subpopup_handle](Node*) { - apply_document_export_menu_plan(app, pp::app::DocumentExportMenuKind::animation_mp4); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, subpopup_handle); - }; - subpopup->find("file-submenu-export-timelapse")->on_click = [&app, popup_root, popup_handle, subpopup_handle](Node*) { - apply_document_export_menu_plan(app, pp::app::DocumentExportMenuKind::timelapse); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - close_legacy_overlay_handle_ignoring_status(*popup_root, subpopup_handle); - }; - }; - if (auto b = popup->find("file-share")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::share); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-resize")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::resize); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-cloud-upload")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::cloud_upload); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - if (auto b = popup->find("file-cloud-browse")) - b->on_click = [&app, popup_root, popup_handle](Node*) { - apply_file_menu_plan(app, pp::app::FileMenuCommand::cloud_browse); - close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle); - }; - }; + bind_legacy_file_menu_popup(app, *menu_file, *main); } } diff --git a/src/app_layout_main_toolbar.cpp b/src/app_layout_main_toolbar.cpp index 5de148b9..0d33a509 100644 --- a/src/app_layout_main_toolbar.cpp +++ b/src/app_layout_main_toolbar.cpp @@ -1,118 +1,12 @@ #include "pch.h" #include "app.h" -#include "app_core/main_toolbar.h" -#include "legacy_app_shell_services.h" -#include "legacy_history_services.h" -#include "node_button.h" -#include "node_button_custom.h" - -namespace { - -void execute_main_toolbar_plan(App& app, const pp::app::MainToolbarPlan& plan) -{ - pp::panopainter::execute_legacy_main_toolbar_plan(app, plan); -} - -} // namespace +#include "legacy_main_toolbar_binding_services.h" namespace pp::panopainter { void bind_legacy_main_toolbar(App& app) { - if (auto* button = app.layout[app.main_id]->find("btn-anim")) - { - button->on_click = [&app, button](Node*) { - if (app.canvas) - { - //app.canvas->m_canvas->export_anim(); - } - }; - } - if (auto* button = app.layout[app.main_id]->find("btn-open")) - { - button->on_click = [&app, button](Node*) { - const auto plan = pp::app::plan_main_toolbar_command( - pp::app::MainToolbarCommand::open_document); - if (plan) - execute_main_toolbar_plan(app, plan.value()); - }; - } - if (auto* button = app.layout[app.main_id]->find("btn-save")) - { - button->on_click = [&app, button](Node*) { - const auto plan = pp::app::plan_main_toolbar_command( - pp::app::MainToolbarCommand::save_document); - if (plan) - execute_main_toolbar_plan(app, plan.value()); - }; - } - if (auto* button = app.layout[app.main_id]->find("btn-undo")) - { - button->on_click = [&app, button](Node*) { - const auto history = pp::panopainter::legacy_history_snapshot(); - const auto plan = pp::app::plan_main_toolbar_command( - pp::app::MainToolbarCommand::undo, - history.undo_count); - if (plan) - execute_main_toolbar_plan(app, plan.value()); - }; - } - if (auto* button = app.layout[app.main_id]->find("btn-redo")) - { - button->on_click = [&app, button](Node*) { - const auto history = pp::panopainter::legacy_history_snapshot(); - const auto plan = pp::app::plan_main_toolbar_command( - pp::app::MainToolbarCommand::redo, - 0, - history.redo_count); - if (plan) - execute_main_toolbar_plan(app, plan.value()); - }; - } - if (auto* button = app.layout[app.main_id]->find("btn-clean-memory")) - { - button->on_click = [&app](Node*) { - const auto history = pp::panopainter::legacy_history_snapshot(); - const auto plan = pp::app::plan_main_toolbar_command( - pp::app::MainToolbarCommand::clear_history, - history.undo_count, - history.redo_count, - history.memory_bytes); - if (plan) - execute_main_toolbar_plan(app, plan.value()); - }; - } - if (auto* button = app.layout[app.main_id]->find("btn-clear")) - { - button->on_click = [&app](Node*) { - const auto plan = pp::app::plan_main_toolbar_command( - pp::app::MainToolbarCommand::clear_canvas, - 0, - 0, - 0, - static_cast(app.canvas)); - if (plan) - execute_main_toolbar_plan(app, plan.value()); - }; - } - if (auto* button = app.layout[app.main_id]->find("btn-popup")) - { - button->on_click = [&app](Node*) { - const auto plan = pp::app::plan_main_toolbar_command( - pp::app::MainToolbarCommand::show_message_box); - if (plan) - execute_main_toolbar_plan(app, plan.value()); - }; - } - if (auto* button = app.layout[app.main_id]->find("btn-settings")) - { - button->on_click = [&app](Node*) { - const auto plan = pp::app::plan_main_toolbar_command( - pp::app::MainToolbarCommand::show_settings); - if (plan) - execute_main_toolbar_plan(app, plan.value()); - }; - } + pp::panopainter::bind_legacy_main_toolbar_buttons(app, *app.layout[app.main_id]); } } // namespace pp::panopainter diff --git a/src/app_layout_tools_menu.cpp b/src/app_layout_tools_menu.cpp index a69e37d0..8bbb27f6 100644 --- a/src/app_layout_tools_menu.cpp +++ b/src/app_layout_tools_menu.cpp @@ -1,53 +1,21 @@ #include "pch.h" #include "app.h" #include "app_core/app_preferences.h" -#include "app_core/brush_ui.h" #include "app_core/tools_menu.h" -#include "legacy_brush_ui_services.h" #include "legacy_app_preference_services.h" #include "legacy_app_shell_services.h" #include "legacy_preference_storage.h" +#include "legacy_tools_menu_binding_services.h" #include "legacy_ui_overlay_services.h" #include "node_button_custom.h" #include "node_checkbox.h" #include "node_combobox.h" -#include "node_dialog_picker.h" -#include "node_panel_animation.h" -#include "node_panel_brush.h" -#include "node_panel_color.h" -#include "node_panel_floating.h" -#include "node_panel_grid.h" -#include "node_panel_layer.h" -#include "node_panel_stroke.h" #include "node_popup_menu.h" #include namespace { -[[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept -{ - return plan.action == pp::app::ToolsPanelAction::open_floating_panel; -} - -void apply_tools_panel_chrome(NodePanelFloating& panel, const pp::app::ToolsPanelPlan& plan) -{ - if (plan.width > 0 && plan.height > 0) { - panel.SetSize(static_cast(plan.width), static_cast(plan.height)); - } else { - if (plan.width > 0) - panel.SetWidth(static_cast(plan.width)); - if (plan.height > 0) - panel.SetHeight(static_cast(plan.height)); - } - if (plan.min_width > 0) - panel.SetMinWidth(static_cast(plan.min_width)); - if (plan.min_height > 0) - panel.SetMinHeight(static_cast(plan.min_height)); - panel.m_title->set_text(plan.title.data()); - panel.m_droppable = plan.droppable; -} - std::shared_ptr add_menu_popup( App& app, const char* template_id, @@ -83,201 +51,13 @@ void bind_legacy_tools_menu(App& app) if (!popup_exp) return; - if (auto tick = popup_exp->find("tools-panels")) tick->on_click = [&app, popup_exp, main](Node* b) + if (auto tick = popup_exp->find("tools-panels")) tick->on_click = [&app, popup_exp, main, tick](Node*) { const auto menu_plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::panels); if (menu_plan.action != pp::app::ToolsMenuAction::show_panels_submenu) return; - pp::panopainter::detach_legacy_node_from_parent(*popup_exp); - const auto popup_exp_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*main, popup_exp); - if (!popup_exp_overlay) - return; - const auto popup_exp_handle = popup_exp_overlay.value(); - - glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0); - auto popup_time = add_menu_popup(app, "panels-menu", pos, b->m_size.x); - if (!popup_time) - { - close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); - return; - } - pp::panopainter::detach_legacy_node_from_parent(*popup_time); - const auto popup_time_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*main, popup_time); - if (!popup_time_overlay) - { - close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); - return; - } - const auto popup_time_handle = popup_time_overlay.value(); - - const auto close_panel_popups = [main, popup_exp_handle, popup_time_handle]() - { - close_legacy_overlay_handle_ignoring_status(*main, popup_exp_handle); - close_legacy_overlay_handle_ignoring_status(*main, popup_time_handle); - }; - - auto visible = [&app](Node* panel) { - if (!panel) - return false; - for (auto& c : app.floatings_container->m_children) - { - if (auto fp = std::static_pointer_cast(c)) - { - if (fp->m_container->is_child(panel)) - return true; - } - } - return false; - }; - - popup_time->find("panel-presets")->on_click = [&app, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::presets, - visible(app.floating_presets.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = app.floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Presets; - apply_tools_panel_chrome(*fpanel, plan); - if (!app.floating_presets) - { - app.floating_presets = fpanel->m_container->add_child_ref(); - app.floating_presets->SetHeightP(100); - app.floating_presets->on_brush_changed = [&app](Node*, std::shared_ptr& b) { - (void)pp::panopainter::apply_legacy_brush_preset_plan(app, b); - }; - } - else - { - fpanel->m_container->add_child(app.floating_presets); - } - close_panel_popups(); - }; - - popup_time->find("panel-color")->on_click = [&app, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::color, - visible(app.floating_color.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = app.floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Color; - apply_tools_panel_chrome(*fpanel, plan); - if (!app.floating_color) - { - app.floating_color = fpanel->m_container->add_child_ref(); - app.floating_color->SetHeightP(100); - if (plan.hides_embedded_title) - app.floating_color->find("title")->SetVisibility(false); - app.floating_color->on_color_changed = [&app](Node*, glm::vec4 color) { - (void)pp::panopainter::apply_legacy_brush_color_plan(app, color, false, false); - }; - } - else - { - fpanel->m_container->add_child(app.floating_color); - } - close_panel_popups(); - }; - popup_time->find("panel-color-adv")->on_click = [&app, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::color_advanced, - visible(app.floating_picker.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = app.floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::ColorAdv; - apply_tools_panel_chrome(*fpanel, plan); - if (!app.floating_picker) - { - app.floating_picker = fpanel->m_container->add_child_ref(); - app.floating_picker->m_autohide = false; - app.floating_picker->on_color_change = [&app](Node*, glm::vec3 color) { - (void)pp::panopainter::apply_legacy_brush_color_plan(app, glm::vec4(color, 1.f), false, false); - }; - } - else - { - fpanel->m_container->add_child(app.floating_picker); - } - close_panel_popups(); - }; - popup_time->find("panel-layers")->on_click = [&app, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::layers, - visible(app.layers.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = app.floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Layers; - apply_tools_panel_chrome(*fpanel, plan); - fpanel->m_container->add_child(app.layers); - app.layers->SetPositioning(YGPositionTypeRelative); - app.layers->SetPosition(0, 0); - app.layers->SetWidthP(100); - app.layers->SetHeightP(100); - app.layers->SetFlexShrink(0); - if (plan.hides_embedded_title) - app.layers->find("title")->SetVisibility(false); - - close_panel_popups(); - }; - popup_time->find("panel-brush")->on_click = [&app, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::brush, - visible(app.stroke.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = app.floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Brush; - fpanel->m_container->add_child(app.stroke); - apply_tools_panel_chrome(*fpanel, plan); - app.stroke->SetPositioning(YGPositionTypeRelative); - app.stroke->SetPosition(0, 0); - app.stroke->SetWidthP(100); - app.stroke->SetHeightP(100); - if (plan.hides_embedded_title) - app.stroke->find("title")->SetVisibility(false); - - close_panel_popups(); - }; - popup_time->find("panel-grids")->on_click = [&app, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::grids, - visible(app.grid.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = app.floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Grids; - fpanel->m_container->add_child(app.grid); - apply_tools_panel_chrome(*fpanel, plan); - app.grid->SetPositioning(YGPositionTypeRelative); - app.grid->SetPosition(0, 0); - app.grid->SetWidthP(100); - app.grid->SetHeightP(100); - if (plan.hides_embedded_title) - app.grid->find("title")->SetVisibility(false); - - close_panel_popups(); - }; - popup_time->find("panel-animation")->on_click = [&app, close_panel_popups, visible](Node*) { - const auto plan = pp::app::plan_tools_panel( - pp::app::ToolsPanel::animation, - visible(app.animation.get())); - if (!should_open_tools_panel(plan)) - return; - auto fpanel = app.floatings_container->add_child(); - fpanel->m_class = NodePanelFloating::kClass::Animation; - fpanel->m_container->add_child(app.animation); - apply_tools_panel_chrome(*fpanel, plan); - app.animation->SetPositioning(YGPositionTypeRelative); - app.animation->SetPosition(0, 0); - app.animation->SetWidthP(100); - app.animation->SetHeightP(100); - - close_panel_popups(); - }; + pp::panopainter::bind_legacy_tools_panels_submenu(app, *main, popup_exp, *tick); }; if (auto options = popup_exp->find("tools-options")) options->on_click = [&app, options, main](Node* b) diff --git a/src/legacy_about_menu_binding_services.cpp b/src/legacy_about_menu_binding_services.cpp new file mode 100644 index 00000000..05932f4c --- /dev/null +++ b/src/legacy_about_menu_binding_services.cpp @@ -0,0 +1,166 @@ +#include "pch.h" + +#include "legacy_about_menu_binding_services.h" + +#include "app.h" +#include "legacy_app_shell_services.h" +#include "legacy_ui_overlay_services.h" +#include "node_button_custom.h" +#include "node_popup_menu.h" +#include "node_text.h" + +namespace pp::panopainter { +namespace { + +std::shared_ptr add_menu_popup( + App& app, + const char* template_id, + glm::vec2 position, + float rtl_anchor_width) +{ + const auto popup = pp::panopainter::add_legacy_popup_menu( + app, + template_id, + position.x, + position.y, + rtl_anchor_width); + if (!popup) { + LOG("Popup menu '%s' failed: %s", template_id ? template_id : "", popup.status().message); + return nullptr; + } + return popup.value(); +} + +void close_legacy_overlay_handle_ignoring_status( + Node& anchor, + pp::ui::NodeHandle overlay) noexcept +{ + (void)pp::panopainter::close_legacy_overlay_node(anchor, overlay); +} + +void bind_about_menu_action( + App& app, + Node& popup_root, + pp::ui::NodeHandle popup_handle, + NodeButtonCustom& button, + pp::app::AboutMenuCommand command, + int version_major, + int version_minor, + int version_fix, + bool has_canvas) noexcept +{ + button.on_click = [&app, &popup_root, popup_handle, command, version_major, version_minor, version_fix, has_canvas](Node*) { + const auto plan = pp::app::plan_about_menu_command( + command, + version_major, + version_minor, + version_fix, + true, + has_canvas); + execute_legacy_about_menu_plan(app, plan); + if (plan.closes_root_popup) { + close_legacy_overlay_handle_ignoring_status(popup_root, popup_handle); + } + }; +} + +} // namespace + +void bind_legacy_about_menu_popup( + App& app, + Node& popup_root, + NodeButtonCustom& trigger_button, + int version_major, + int version_minor, + int version_fix, + bool has_canvas) noexcept +{ + trigger_button.on_click = [&app, &popup_root, &trigger_button, version_major, version_minor, version_fix, has_canvas](Node*) { + const glm::vec2 pos = trigger_button.m_pos + glm::vec2(0, trigger_button.m_size.y); + auto popup = add_menu_popup(app, "about-menu", pos, trigger_button.m_size.x); + if (!popup) { + return; + } + + detach_legacy_node_from_parent(*popup); + auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(popup_root, popup); + if (!popup_overlay) { + pp::panopainter::destroy_legacy_node(*popup); + return; + } + + const auto popup_handle = popup_overlay.value(); + + bind_about_menu_action( + app, + popup_root, + popup_handle, + *popup->find("about-app"), + pp::app::AboutMenuCommand::about_app, + version_major, + version_minor, + version_fix, + has_canvas); + + bind_about_menu_action( + app, + popup_root, + popup_handle, + *popup->find("about-doc"), + pp::app::AboutMenuCommand::help_guide, + version_major, + version_minor, + version_fix, + has_canvas); + + if (auto item = popup->find("about-news")) { + if (auto text = item->find("menu-label")) { + const auto plan = pp::app::plan_about_menu_command( + pp::app::AboutMenuCommand::whats_new, + version_major, + version_minor, + version_fix); + text->set_text(plan.label.c_str()); + } + + bind_about_menu_action( + app, + popup_root, + popup_handle, + *item, + pp::app::AboutMenuCommand::whats_new, + version_major, + version_minor, + version_fix, + has_canvas); + } + + if (auto b = popup->find("about-crash")) { + bind_about_menu_action( + app, + popup_root, + popup_handle, + *b, + pp::app::AboutMenuCommand::induce_crash, + version_major, + version_minor, + version_fix, + has_canvas); + } + + if (auto b = popup->find("about-perf")) { + bind_about_menu_action( + app, + popup_root, + popup_handle, + *b, + pp::app::AboutMenuCommand::performance_test, + version_major, + version_minor, + version_fix, + has_canvas); + } + }; +} + +} // namespace pp::panopainter diff --git a/src/legacy_about_menu_binding_services.h b/src/legacy_about_menu_binding_services.h new file mode 100644 index 00000000..e957ead0 --- /dev/null +++ b/src/legacy_about_menu_binding_services.h @@ -0,0 +1,20 @@ +#pragma once + +#include "app_core/about_menu.h" + +class App; +class Node; +class NodeButtonCustom; + +namespace pp::panopainter { + +void bind_legacy_about_menu_popup( + App& app, + Node& popup_root, + NodeButtonCustom& trigger_button, + int version_major, + int version_minor, + int version_fix, + bool has_canvas) noexcept; + +} // namespace pp::panopainter diff --git a/src/legacy_file_menu_binding_services.cpp b/src/legacy_file_menu_binding_services.cpp new file mode 100644 index 00000000..170c23a7 --- /dev/null +++ b/src/legacy_file_menu_binding_services.cpp @@ -0,0 +1,286 @@ +#include "pch.h" + +#include "legacy_file_menu_binding_services.h" + +#include "app.h" +#include "app_core/document_export.h" +#include "app_core/file_menu.h" +#include "legacy_app_shell_services.h" +#include "legacy_ui_overlay_services.h" +#include "node_button_custom.h" +#include "node_popup_menu.h" + +namespace { + +std::shared_ptr add_menu_popup( + App& app, + const char* template_id, + glm::vec2 position, + float rtl_anchor_width) +{ + const auto popup = pp::panopainter::add_legacy_popup_menu( + app, + template_id, + position.x, + position.y, + rtl_anchor_width); + if (!popup) { + LOG("Popup menu '%s' failed: %s", template_id ? template_id : "", popup.status().message); + return nullptr; + } + return popup.value(); +} + +void close_legacy_overlay_handle_ignoring_status( + Node& anchor, + pp::ui::NodeHandle overlay) noexcept +{ + (void)pp::panopainter::close_legacy_overlay_node(anchor, overlay); +} + +} // namespace + +namespace pp::panopainter { + +namespace { + +class LegacyFileMenuBindingServices final { +public: + LegacyFileMenuBindingServices(App& app, Node& popup_root) noexcept + : app_(app) + , popup_root_(popup_root) + { + } + + void bind_menu_button(NodeButtonCustom& menu_file) + { + menu_file.on_click = [this, &menu_file](Node*) { + open_file_menu_popup(menu_file); + }; + } + +private: + void open_file_menu_popup(NodeButtonCustom& menu_file) + { + const glm::vec2 pos = menu_file.m_pos + glm::vec2(0, menu_file.m_size.y); + const auto popup = add_menu_popup(app_, "file-menu", pos, menu_file.m_size.x); + if (!popup) { + return; + } + + pp::panopainter::detach_legacy_node_from_parent(*popup); + const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(popup_root_, popup); + if (!popup_overlay) { + pp::panopainter::destroy_legacy_node(*popup); + return; + } + + bind_popup_wiring(*popup, popup_overlay.value()); + } + + void bind_popup_wiring( + NodePopupMenu& popup, + pp::ui::NodeHandle popup_handle) + { + if (auto* b = popup.find("file-newdoc")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::new_document); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-import")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::import_image); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-open")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::open_project); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-browse")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::browse_cloud); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-save")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::save); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-save-as")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::save_as); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-save-ver")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::save_version); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-export")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::export_jpeg); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-export-tick")) { + b->on_click = [this, b, popup_handle](Node*) { + open_export_submenu(*b, popup_handle); + }; + } + if (auto* b = popup.find("file-share")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::share); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-resize")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::resize); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-cloud-upload")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::cloud_upload); + close_popup(popup_handle); + }; + } + if (auto* b = popup.find("file-cloud-browse")) { + b->on_click = [this, popup_handle](Node*) { + apply_file_menu_command(pp::app::FileMenuCommand::cloud_browse); + close_popup(popup_handle); + }; + } + } + + void open_export_submenu( + NodeButtonCustom& export_button, + pp::ui::NodeHandle popup_handle) + { + const glm::vec2 pos = export_button.m_pos + glm::vec2(export_button.m_size.x, 0); + const auto subpopup = add_menu_popup( + app_, + "file-submenu-export", + pos, + export_button.m_size.x); + if (!subpopup) { + return; + } + + pp::panopainter::detach_legacy_node_from_parent(*subpopup); + const auto subpopup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(popup_root_, subpopup); + if (!subpopup_overlay) { + pp::panopainter::destroy_legacy_node(*subpopup); + return; + } + + bind_export_submenu_wiring( + *subpopup, + popup_handle, + subpopup_overlay.value()); + } + + void bind_export_submenu_wiring( + NodePopupMenu& subpopup, + pp::ui::NodeHandle popup_handle, + pp::ui::NodeHandle subpopup_handle) + { + bind_export_submenu_button( + subpopup, + "file-submenu-export-png", + pp::app::DocumentExportMenuKind::png, + popup_handle, + subpopup_handle); + bind_export_submenu_button( + subpopup, + "file-submenu-export-layers", + pp::app::DocumentExportMenuKind::layers, + popup_handle, + subpopup_handle); + bind_export_submenu_button( + subpopup, + "file-submenu-export-cube", + pp::app::DocumentExportMenuKind::cube_faces, + popup_handle, + subpopup_handle); + bind_export_submenu_button( + subpopup, + "file-submenu-export-depth", + pp::app::DocumentExportMenuKind::depth, + popup_handle, + subpopup_handle); + bind_export_submenu_button( + subpopup, + "file-submenu-export-anim", + pp::app::DocumentExportMenuKind::animation_frames, + popup_handle, + subpopup_handle); + bind_export_submenu_button( + subpopup, + "file-submenu-export-anim-mp4", + pp::app::DocumentExportMenuKind::animation_mp4, + popup_handle, + subpopup_handle); + bind_export_submenu_button( + subpopup, + "file-submenu-export-timelapse", + pp::app::DocumentExportMenuKind::timelapse, + popup_handle, + subpopup_handle); + } + + void bind_export_submenu_button( + NodePopupMenu& subpopup, + const char* button_id, + pp::app::DocumentExportMenuKind kind, + pp::ui::NodeHandle popup_handle, + pp::ui::NodeHandle subpopup_handle) + { + if (auto* b = subpopup.find(button_id)) { + b->on_click = [this, kind, popup_handle, subpopup_handle](Node*) { + apply_document_export_menu(kind); + close_popup(popup_handle); + close_popup(subpopup_handle); + }; + } + } + + void apply_file_menu_command(pp::app::FileMenuCommand command) + { + pp::panopainter::apply_legacy_file_menu_command(app_, command); + } + + void apply_document_export_menu(pp::app::DocumentExportMenuKind kind) + { + (void)pp::panopainter::apply_legacy_document_export_menu_plan(app_, kind); + } + + void close_popup(pp::ui::NodeHandle overlay) noexcept + { + close_legacy_overlay_handle_ignoring_status(popup_root_, overlay); + } + + App& app_; + Node& popup_root_; +}; + +} // namespace + +void bind_legacy_file_menu_popup( + App& app, + NodeButtonCustom& menu_file, + Node& popup_root) +{ + LegacyFileMenuBindingServices services(app, popup_root); + services.bind_menu_button(menu_file); +} + +} // namespace pp::panopainter diff --git a/src/legacy_file_menu_binding_services.h b/src/legacy_file_menu_binding_services.h new file mode 100644 index 00000000..db90fabf --- /dev/null +++ b/src/legacy_file_menu_binding_services.h @@ -0,0 +1,14 @@ +#pragma once + +class App; +class Node; +class NodeButtonCustom; + +namespace pp::panopainter { + +void bind_legacy_file_menu_popup( + App& app, + NodeButtonCustom& menu_file, + Node& popup_root); + +} // namespace pp::panopainter diff --git a/src/legacy_main_toolbar_binding_services.cpp b/src/legacy_main_toolbar_binding_services.cpp new file mode 100644 index 00000000..f2ec9593 --- /dev/null +++ b/src/legacy_main_toolbar_binding_services.cpp @@ -0,0 +1,112 @@ +#include "pch.h" + +#include "legacy_main_toolbar_binding_services.h" + +#include "app.h" +#include "app_core/main_toolbar.h" +#include "legacy_app_shell_services.h" +#include "legacy_history_services.h" +#include "node_button.h" +#include "node_button_custom.h" + +namespace pp::panopainter { + +namespace { + +template +void bind_legacy_main_toolbar_click(Node& toolbar_root, const char* button_id, Handler&& handler) +{ + if (auto* button = toolbar_root.find(button_id)) { + button->on_click = std::forward(handler); + } +} + +void execute_main_toolbar_plan(App& app, const pp::app::MainToolbarPlan& plan) +{ + pp::panopainter::execute_legacy_main_toolbar_plan(app, plan); +} + +} // namespace + +void bind_legacy_main_toolbar_buttons(App& app, Node& toolbar_root) +{ + bind_legacy_main_toolbar_click(toolbar_root, "btn-anim", [&app](Node*) { + if (app.canvas) { + //app.canvas->m_canvas->export_anim(); + } + }); + + bind_legacy_main_toolbar_click(toolbar_root, "btn-open", [&app](Node*) { + const auto plan = pp::app::plan_main_toolbar_command( + pp::app::MainToolbarCommand::open_document); + if (plan) + execute_main_toolbar_plan(app, plan.value()); + }); + + bind_legacy_main_toolbar_click(toolbar_root, "btn-save", [&app](Node*) { + const auto plan = pp::app::plan_main_toolbar_command( + pp::app::MainToolbarCommand::save_document); + if (plan) + execute_main_toolbar_plan(app, plan.value()); + }); + + bind_legacy_main_toolbar_click(toolbar_root, "btn-undo", [&app](Node*) { + const auto history = pp::panopainter::legacy_history_snapshot(); + const auto plan = pp::app::plan_main_toolbar_command( + pp::app::MainToolbarCommand::undo, + history.undo_count); + if (plan) + execute_main_toolbar_plan(app, plan.value()); + }); + + bind_legacy_main_toolbar_click(toolbar_root, "btn-redo", [&app](Node*) { + const auto history = pp::panopainter::legacy_history_snapshot(); + const auto plan = pp::app::plan_main_toolbar_command( + pp::app::MainToolbarCommand::redo, + 0, + history.redo_count); + if (plan) + execute_main_toolbar_plan(app, plan.value()); + }); + + bind_legacy_main_toolbar_click( + toolbar_root, + "btn-clean-memory", + [&app](Node*) { + const auto history = pp::panopainter::legacy_history_snapshot(); + const auto plan = pp::app::plan_main_toolbar_command( + pp::app::MainToolbarCommand::clear_history, + history.undo_count, + history.redo_count, + history.memory_bytes); + if (plan) + execute_main_toolbar_plan(app, plan.value()); + }); + + bind_legacy_main_toolbar_click(toolbar_root, "btn-clear", [&app](Node*) { + const auto plan = pp::app::plan_main_toolbar_command( + pp::app::MainToolbarCommand::clear_canvas, + 0, + 0, + 0, + static_cast(app.canvas)); + if (plan) + execute_main_toolbar_plan(app, plan.value()); + }); + + bind_legacy_main_toolbar_click(toolbar_root, "btn-popup", [&app](Node*) { + const auto plan = pp::app::plan_main_toolbar_command( + pp::app::MainToolbarCommand::show_message_box); + if (plan) + execute_main_toolbar_plan(app, plan.value()); + }); + + bind_legacy_main_toolbar_click(toolbar_root, "btn-settings", [&app](Node*) { + const auto plan = pp::app::plan_main_toolbar_command( + pp::app::MainToolbarCommand::show_settings); + if (plan) + execute_main_toolbar_plan(app, plan.value()); + }); +} + +} // namespace pp::panopainter diff --git a/src/legacy_main_toolbar_binding_services.h b/src/legacy_main_toolbar_binding_services.h new file mode 100644 index 00000000..0c84f621 --- /dev/null +++ b/src/legacy_main_toolbar_binding_services.h @@ -0,0 +1,10 @@ +#pragma once + +class App; +class Node; + +namespace pp::panopainter { + +void bind_legacy_main_toolbar_buttons(App& app, Node& toolbar_root); + +} // namespace pp::panopainter diff --git a/src/legacy_tools_menu_binding_services.cpp b/src/legacy_tools_menu_binding_services.cpp new file mode 100644 index 00000000..8cfd3383 --- /dev/null +++ b/src/legacy_tools_menu_binding_services.cpp @@ -0,0 +1,296 @@ +#include "pch.h" + +#include "legacy_tools_menu_binding_services.h" + +#include "app.h" +#include "app_core/brush_ui.h" +#include "app_core/tools_menu.h" +#include "legacy_brush_ui_services.h" +#include "legacy_ui_overlay_services.h" +#include "node_button_custom.h" +#include "node_dialog_picker.h" +#include "node_panel_animation.h" +#include "node_panel_brush.h" +#include "node_panel_color.h" +#include "node_panel_floating.h" +#include "node_panel_grid.h" +#include "node_panel_layer.h" +#include "node_panel_stroke.h" +#include "node_popup_menu.h" + +#include +#include + +namespace { + +[[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept +{ + return plan.action == pp::app::ToolsPanelAction::open_floating_panel; +} + +void apply_tools_panel_chrome(NodePanelFloating& panel, const pp::app::ToolsPanelPlan& plan) +{ + if (plan.width > 0 && plan.height > 0) { + panel.SetSize(static_cast(plan.width), static_cast(plan.height)); + } else { + if (plan.width > 0) + panel.SetWidth(static_cast(plan.width)); + if (plan.height > 0) + panel.SetHeight(static_cast(plan.height)); + } + if (plan.min_width > 0) + panel.SetMinWidth(static_cast(plan.min_width)); + if (plan.min_height > 0) + panel.SetMinHeight(static_cast(plan.min_height)); + panel.m_title->set_text(plan.title.data()); + panel.m_droppable = plan.droppable; +} + +[[nodiscard]] std::shared_ptr add_menu_popup( + App& app, + const char* template_id, + glm::vec2 position, + float rtl_anchor_width) +{ + const auto popup = pp::panopainter::add_legacy_popup_menu( + app, + template_id, + position.x, + position.y, + rtl_anchor_width); + if (!popup) { + LOG("Popup menu '%s' failed: %s", template_id ? template_id : "", popup.status().message); + return nullptr; + } + return popup.value(); +} + +void close_legacy_overlay_handle_ignoring_status( + Node& anchor, + pp::ui::NodeHandle overlay) noexcept +{ + (void)pp::panopainter::close_legacy_overlay_node(anchor, overlay); +} + +auto make_panel_visibility_checker(App& app) +{ + return [&app](Node* panel) { + if (!panel) + return false; + for (auto& c : app.floatings_container->m_children) + { + if (auto fp = std::static_pointer_cast(c)) + { + if (fp->m_container->is_child(panel)) + return true; + } + } + return false; + }; +} + +void bind_panel_handlers( + App& app, + NodePopupMenu& panels_popup, + const std::function& close_panel_popups, + const std::function& visible) +{ + panels_popup.find("panel-presets")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::presets, + visible(app.floating_presets.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Presets; + apply_tools_panel_chrome(*fpanel, plan); + if (!app.floating_presets) + { + app.floating_presets = fpanel->m_container->add_child_ref(); + app.floating_presets->SetHeightP(100); + app.floating_presets->on_brush_changed = [&app](Node*, std::shared_ptr& b) { + (void)pp::panopainter::apply_legacy_brush_preset_plan(app, b); + }; + } + else + { + fpanel->m_container->add_child(app.floating_presets); + } + close_panel_popups(); + }; + + panels_popup.find("panel-color")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::color, + visible(app.floating_color.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Color; + apply_tools_panel_chrome(*fpanel, plan); + if (!app.floating_color) + { + app.floating_color = fpanel->m_container->add_child_ref(); + app.floating_color->SetHeightP(100); + if (plan.hides_embedded_title) + app.floating_color->find("title")->SetVisibility(false); + app.floating_color->on_color_changed = [&app](Node*, glm::vec4 color) { + (void)pp::panopainter::apply_legacy_brush_color_plan(app, color, false, false); + }; + } + else + { + fpanel->m_container->add_child(app.floating_color); + } + close_panel_popups(); + }; + + panels_popup.find("panel-color-adv")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::color_advanced, + visible(app.floating_picker.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::ColorAdv; + apply_tools_panel_chrome(*fpanel, plan); + if (!app.floating_picker) + { + app.floating_picker = fpanel->m_container->add_child_ref(); + app.floating_picker->m_autohide = false; + app.floating_picker->on_color_change = [&app](Node*, glm::vec3 color) { + (void)pp::panopainter::apply_legacy_brush_color_plan(app, glm::vec4(color, 1.f), false, false); + }; + } + else + { + fpanel->m_container->add_child(app.floating_picker); + } + close_panel_popups(); + }; + + panels_popup.find("panel-layers")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::layers, + visible(app.layers.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Layers; + apply_tools_panel_chrome(*fpanel, plan); + fpanel->m_container->add_child(app.layers); + app.layers->SetPositioning(YGPositionTypeRelative); + app.layers->SetPosition(0, 0); + app.layers->SetWidthP(100); + app.layers->SetHeightP(100); + app.layers->SetFlexShrink(0); + if (plan.hides_embedded_title) + app.layers->find("title")->SetVisibility(false); + + close_panel_popups(); + }; + + panels_popup.find("panel-brush")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::brush, + visible(app.stroke.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Brush; + fpanel->m_container->add_child(app.stroke); + apply_tools_panel_chrome(*fpanel, plan); + app.stroke->SetPositioning(YGPositionTypeRelative); + app.stroke->SetPosition(0, 0); + app.stroke->SetWidthP(100); + app.stroke->SetHeightP(100); + if (plan.hides_embedded_title) + app.stroke->find("title")->SetVisibility(false); + + close_panel_popups(); + }; + + panels_popup.find("panel-grids")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::grids, + visible(app.grid.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Grids; + fpanel->m_container->add_child(app.grid); + apply_tools_panel_chrome(*fpanel, plan); + app.grid->SetPositioning(YGPositionTypeRelative); + app.grid->SetPosition(0, 0); + app.grid->SetWidthP(100); + app.grid->SetHeightP(100); + if (plan.hides_embedded_title) + app.grid->find("title")->SetVisibility(false); + + close_panel_popups(); + }; + + panels_popup.find("panel-animation")->on_click = [&app, close_panel_popups, visible](Node*) { + const auto plan = pp::app::plan_tools_panel( + pp::app::ToolsPanel::animation, + visible(app.animation.get())); + if (!should_open_tools_panel(plan)) + return; + auto fpanel = app.floatings_container->add_child(); + fpanel->m_class = NodePanelFloating::kClass::Animation; + fpanel->m_container->add_child(app.animation); + apply_tools_panel_chrome(*fpanel, plan); + app.animation->SetPositioning(YGPositionTypeRelative); + app.animation->SetPosition(0, 0); + app.animation->SetWidthP(100); + app.animation->SetHeightP(100); + + close_panel_popups(); + }; +} + +} // namespace + +namespace pp::panopainter { + +void bind_legacy_tools_panels_submenu( + App& app, + Node& main, + std::shared_ptr root_popup, + NodeButtonCustom& panels_button) +{ + panels_button.on_click = [&app, &main, root_popup = std::move(root_popup), &panels_button](Node*) mutable { + pp::panopainter::detach_legacy_node_from_parent(*root_popup); + const auto root_popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(main, root_popup); + if (!root_popup_overlay) + return; + const auto root_popup_handle = root_popup_overlay.value(); + + glm::vec2 pos = panels_button.m_pos + glm::vec2(panels_button.m_size.x, 0); + auto panels_popup = add_menu_popup(app, "panels-menu", pos, panels_button.m_size.x); + if (!panels_popup) + { + close_legacy_overlay_handle_ignoring_status(main, root_popup_handle); + return; + } + pp::panopainter::detach_legacy_node_from_parent(*panels_popup); + const auto panels_popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(main, panels_popup); + if (!panels_popup_overlay) + { + close_legacy_overlay_handle_ignoring_status(main, root_popup_handle); + return; + } + const auto panels_popup_handle = panels_popup_overlay.value(); + + const auto close_panel_popups = [root_popup_handle, panels_popup_handle, &main]() + { + close_legacy_overlay_handle_ignoring_status(main, root_popup_handle); + close_legacy_overlay_handle_ignoring_status(main, panels_popup_handle); + }; + + const auto visible = make_panel_visibility_checker(app); + bind_panel_handlers(app, *panels_popup, close_panel_popups, visible); + }; +} + +} // namespace pp::panopainter diff --git a/src/legacy_tools_menu_binding_services.h b/src/legacy_tools_menu_binding_services.h new file mode 100644 index 00000000..a005bb6a --- /dev/null +++ b/src/legacy_tools_menu_binding_services.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +class App; +class Node; +class NodeButtonCustom; +class NodePopupMenu; + +namespace pp::panopainter { + +void bind_legacy_tools_panels_submenu( + App& app, + Node& main, + std::shared_ptr root_popup, + NodeButtonCustom& panels_button); + +} // namespace pp::panopainter