Extract app dialog and binding service seams

This commit is contained in:
2026-06-17 19:37:58 +02:00
parent 52ed7ddeb0
commit b505d9f727
19 changed files with 432 additions and 248 deletions

View File

@@ -94,12 +94,16 @@ set(PP_LEGACY_APP_SOURCES
src/legacy_canvas_mode_transform.cpp src/legacy_canvas_mode_transform.cpp
src/legacy_app_shell_services.cpp src/legacy_app_shell_services.cpp
src/legacy_app_shell_services.h src/legacy_app_shell_services.h
src/legacy_app_status_services.cpp
src/legacy_app_status_services.h
src/legacy_app_ui_state_services.cpp src/legacy_app_ui_state_services.cpp
src/legacy_app_ui_state_services.h src/legacy_app_ui_state_services.h
src/legacy_about_menu_binding_services.cpp src/legacy_about_menu_binding_services.cpp
src/legacy_about_menu_binding_services.h src/legacy_about_menu_binding_services.h
src/legacy_app_shell_performance_test_services.cpp src/legacy_app_shell_performance_test_services.cpp
src/legacy_app_shell_performance_test_services.h src/legacy_app_shell_performance_test_services.h
src/legacy_info_dialog_services.cpp
src/legacy_info_dialog_services.h
src/legacy_canvas_tool_services.cpp src/legacy_canvas_tool_services.cpp
src/legacy_canvas_tool_services.h src/legacy_canvas_tool_services.h
src/legacy_canvas_view_services.cpp src/legacy_canvas_view_services.cpp
@@ -155,8 +159,12 @@ set(PP_PANOPAINTER_APP_SOURCES
src/app_layout_bootstrap.cpp src/app_layout_bootstrap.cpp
src/app_layout_brush.cpp src/app_layout_brush.cpp
src/app_layout_draw_toolbar.cpp src/app_layout_draw_toolbar.cpp
src/legacy_draw_toolbar_binding_services.cpp
src/legacy_draw_toolbar_binding_services.h
src/app_layout_ui_state.cpp src/app_layout_ui_state.cpp
src/app_layout_sidebar.cpp src/app_layout_sidebar.cpp
src/legacy_sidebar_stroke_popup_services.cpp
src/legacy_sidebar_stroke_popup_services.h
src/legacy_sidebar_color_popup_services.cpp src/legacy_sidebar_color_popup_services.cpp
src/legacy_sidebar_color_popup_services.h src/legacy_sidebar_color_popup_services.h
src/app_layout_main_toolbar.cpp src/app_layout_main_toolbar.cpp

View File

@@ -791,6 +791,27 @@ agent or engineer to remove them without reconstructing context from chat.
no longer self-destroy their cancel/OK buttons through no longer self-destroy their cancel/OK buttons through
`bind_legacy_click_destroys_node(...)`; menu/layout-owned popup families still `bind_legacy_click_destroys_node(...)`; menu/layout-owned popup families still
remain on separate retained cleanup paths. 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
`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.
- 2026-06-17: `DEBT-0035` was narrowed again. `App::title_update()` and the
draw-toolbar/stroke-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/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.
- 2026-06-15: `DEBT-0036` was narrowed again. `NodeStrokePreview` now drops the - 2026-06-15: `DEBT-0036` was narrowed again. `NodeStrokePreview` now drops the
retained pass-sequence, mix-execution, final-composite-request, background retained pass-sequence, mix-execution, final-composite-request, background
capture, and preview-copy wrapper structs/functions in favor of direct capture, and preview-copy wrapper structs/functions in favor of direct

View File

@@ -92,6 +92,13 @@ Current conclusion:
routes through `src/legacy_app_ui_state_services.*`, so more of the retained routes through `src/legacy_app_ui_state_services.*`, so more of the retained
app shell is down to adapter calls even though runtime draw/event/sidebar app shell is down to adapter calls even though runtime draw/event/sidebar
execution still remains. 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.
- Platform extraction improved substantially and the root app source group no - Platform extraction improved substantially and the root app source group no
longer compiles Web platform sources directly, but broader CMake and longer compiles Web platform sources directly, but broader CMake and
entrypoint cleanup are not complete. entrypoint cleanup are not complete.

View File

@@ -101,6 +101,29 @@ Key facts:
`App&`, popup-root, trigger-button, and panel dependencies, so `App&`, popup-root, trigger-button, and panel dependencies, so
`src/app_layout_sidebar.cpp` is thinner while the retained stroke/grid/layer `src/app_layout_sidebar.cpp` is thinner while the retained stroke/grid/layer
popup families still remain inline. popup families still remain inline.
- `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.
- `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.
- `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.
- `App::init_toolbar_draw()` now delegates retained draw-toolbar button lookup,
click wiring, and default-tool application through
`src/legacy_draw_toolbar_binding_services.*`, so
`src/app_layout_draw_toolbar.cpp` is down to a thin adapter while retained
tool execution still flows through `src/legacy_canvas_tool_services.*`.
- `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.
## Parallel Assignment Rules ## Parallel Assignment Rules

View File

@@ -2,59 +2,45 @@
#include "app.h" #include "app.h"
#include "legacy_preference_storage.h" #include "legacy_preference_storage.h"
#include "legacy_ui_overlay_services.h" #include "legacy_ui_overlay_services.h"
#include "node_about.h" #include "legacy_info_dialog_services.h"
#include "node_changelog.h"
#include "node_remote_page.h" #include "node_remote_page.h"
#include "node_shorcuts.h" #include "node_shorcuts.h"
#include "node_usermanual.h"
#include "version.h" #include "version.h"
namespace pp::panopainter { namespace pp::panopainter {
namespace { namespace {
template <typename DialogNode> Node* get_legacy_info_dialog_overlay_anchor(App& app, const char* log_name)
void open_info_dialog(App& app, const char* log_name)
{ {
auto* overlay_anchor = app.layout[app.main_id]; auto* overlay_anchor = app.layout[app.main_id];
if (!overlay_anchor) { if (!overlay_anchor) {
LOG("%s dialog open failed: main layout anchor is missing", log_name); LOG("%s dialog open failed: main layout anchor is missing", log_name);
return;
} }
return overlay_anchor;
auto dialog = make_legacy_overlay_node<DialogNode>(app);
const auto overlay = open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
if (!overlay) {
LOG("%s dialog open failed: %s", log_name, overlay.status().message);
return;
}
const auto overlay_handle = overlay.value();
const auto close_dialog = [overlay_anchor, overlay_handle]() {
const auto close_status = close_legacy_overlay_node(*overlay_anchor, overlay_handle);
(void)close_status;
};
dialog->btn_ok->on_click = [close_dialog](Node*) {
close_dialog();
};
} }
} // namespace } // namespace
void open_usermanual_dialog(App& app) void open_usermanual_dialog(App& app)
{ {
open_info_dialog<NodeUserManual>(app, "User manual"); if (auto* overlay_anchor = get_legacy_info_dialog_overlay_anchor(app, "User manual")) {
pp::panopainter::open_usermanual_dialog(app, *overlay_anchor, "User manual");
}
} }
void open_changelog_dialog(App& app) void open_changelog_dialog(App& app)
{ {
open_info_dialog<NodeChangelog>(app, "Changelog"); if (auto* overlay_anchor = get_legacy_info_dialog_overlay_anchor(app, "Changelog")) {
pp::panopainter::open_changelog_dialog(app, *overlay_anchor, "Changelog");
}
} }
void open_about_dialog(App& app) void open_about_dialog(App& app)
{ {
open_info_dialog<NodeAbout>(app, "About"); if (auto* overlay_anchor = get_legacy_info_dialog_overlay_anchor(app, "About")) {
pp::panopainter::open_about_dialog(app, *overlay_anchor, "About");
}
} }
void open_whatsnew_dialog(App& app, bool force_show) void open_whatsnew_dialog(App& app, bool force_show)

View File

@@ -9,27 +9,6 @@
#include "node_dialog_open.h" #include "node_dialog_open.h"
#include "node_dialog_resize.h" #include "node_dialog_resize.h"
namespace {
void wire_document_save_dialog_buttons(
App& app,
const std::shared_ptr<NodeDialogSave>& dialog,
std::function<void()> close_dialog)
{
dialog->btn_ok->on_click = [&app, dialog](Node*)
{
const auto status = pp::panopainter::execute_legacy_document_file_save_dialog(app, dialog);
if (!status.ok())
LOG("Document file save action failed: %s", status.message);
};
dialog->btn_cancel->on_click = [close_dialog](Node*)
{
close_dialog();
};
}
} // namespace
void App::continue_document_workflow_after_optional_save(std::function<void()> action) void App::continue_document_workflow_after_optional_save(std::function<void()> action)
{ {
const bool has_canvas = canvas != nullptr; const bool has_canvas = canvas != nullptr;
@@ -46,62 +25,7 @@ void App::continue_document_workflow_after_optional_save(std::function<void()> a
void App::dialog_newdoc() void App::dialog_newdoc()
{ {
auto show_dialog = [this] { auto show_dialog = [this] {
auto* overlay_anchor = layout[main_id]; pp::panopainter::open_legacy_new_document_dialog(*this);
if (!overlay_anchor) {
LOG("New document dialog open failed: main layout anchor is missing");
return;
}
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogNewDoc>(*this);
dialog->input->set_text("name");
App::I->showKeyboard();
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
if (!overlay) {
App::I->hideKeyboard();
LOG("New document dialog open failed: %s", overlay.status().message);
return;
}
const auto overlay_handle = overlay.value();
const auto close_dialog = [this, overlay_anchor, overlay_handle]() {
const auto close_status =
pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
(void)close_status;
App::I->hideKeyboard();
};
dialog->btn_ok->on_click = [this, dialog](Node*)
{
std::string name = dialog->input->m_text;
const auto plan = pp::app::plan_new_document(
work_path,
name,
dialog->m_resolution->m_current_index,
[](const std::string& path) {
return Asset::exist(path);
});
if (!plan)
{
const bool missing_name =
plan.status().code == pp::foundation::StatusCode::invalid_argument;
message_box(
"Warning",
missing_name ? "You need to specify a name to file." : plan.status().message);
return;
}
const auto status =
pp::panopainter::execute_legacy_new_document_plan(*this, plan.value(), dialog);
if (!status.ok())
LOG("New document action failed: %s", status.message);
};
dialog->btn_cancel->on_click = [close_dialog](Node*)
{
close_dialog();
};
}; };
continue_document_workflow_after_optional_save(show_dialog); continue_document_workflow_after_optional_save(show_dialog);
@@ -219,35 +143,7 @@ void App::dialog_save()
} }
if (canvas) if (canvas)
{ pp::panopainter::open_legacy_document_file_save_dialog(*this);
auto* overlay_anchor = layout[main_id];
if (!overlay_anchor) {
LOG("Save document dialog open failed: main layout anchor is missing");
return;
}
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogSave>(*this);
dialog->input->set_text(doc_name);
App::I->showKeyboard();
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
if (!overlay) {
App::I->hideKeyboard();
LOG("Save document dialog open failed: %s", overlay.status().message);
return;
}
const auto overlay_handle = overlay.value();
const auto close_dialog = [this, overlay_anchor, overlay_handle]() {
const auto close_status =
pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
(void)close_status;
App::I->hideKeyboard();
};
wire_document_save_dialog_buttons(*this, dialog, close_dialog);
}
} }
void App::dialog_resize() void App::dialog_resize()

View File

@@ -1,13 +1,12 @@
#include "pch.h" #include "pch.h"
#include "app.h" #include "app.h"
#include "node_text.h"
#include "node_panel_floating.h" #include "node_panel_floating.h"
#include "app_core/about_menu.h" #include "app_core/about_menu.h"
#include "app_core/app_preferences.h" #include "app_core/app_preferences.h"
#include "app_core/document_layer.h" #include "app_core/document_layer.h"
#include "app_core/document_canvas.h" #include "app_core/document_canvas.h"
#include "app_core/app_status.h"
#include "app_core/tools_menu.h" #include "app_core/tools_menu.h"
#include "legacy_app_status_services.h"
#include "legacy_app_preference_services.h" #include "legacy_app_preference_services.h"
#include "legacy_app_shell_services.h" #include "legacy_app_shell_services.h"
#include "legacy_document_layer_services.h" #include "legacy_document_layer_services.h"
@@ -65,19 +64,7 @@ void execute_document_layer_merge_plan(App& app, const pp::app::DocumentLayerMer
void App::title_update() void App::title_update()
{ {
if (auto docname = layout[main_id]->find<NodeText>("txt-docname")) pp::panopainter::update_legacy_app_title(*this);
{
const auto title = pp::app::make_document_title(
doc_name,
canvas->m_canvas->m_unsaved,
canvas->m_canvas->m_width);
docname->set_text(title.c_str());
}
if (auto node = layout[main_id]->find<NodeText>("txt-dpi"))
{
const auto label = pp::app::make_dpi_label(zoom);
node->set_text(label.c_str());
}
} }
void App::init_toolbar_main() void App::init_toolbar_main()

View File

@@ -1,68 +1,8 @@
#include "pch.h" #include "pch.h"
#include "app.h" #include "app.h"
#include "app_core/canvas_tool_ui.h" #include "legacy_draw_toolbar_binding_services.h"
#include "legacy_canvas_tool_services.h"
#include "node_button.h"
#include "node_button_custom.h"
namespace {
[[nodiscard]] bool current_canvas_mode_is_draw(App& app) noexcept
{
return app.canvas && app.canvas->m_canvas && app.canvas->m_canvas->m_current_mode == kCanvasMode::Draw;
}
template<class T>
void execute_canvas_tool_toolbar_binding(
App& app,
const pp::app::CanvasToolToolbarBinding& binding,
T* button)
{
const auto plan = pp::app::plan_canvas_tool_toolbar_binding_action(
binding,
current_canvas_mode_is_draw(app));
const auto status = binding.action == pp::app::CanvasToolToolbarAction::select_mode
? pp::panopainter::execute_legacy_canvas_tool_plan(app, plan, button)
: pp::panopainter::execute_legacy_canvas_tool_plan(app, plan);
if (!status.ok())
LOG("Canvas toolbar action failed: %s", status.message);
}
template<class T>
void bind_canvas_tool_toolbar_button(
App& app,
const pp::app::CanvasToolToolbarBinding& binding,
T* button)
{
button->on_click = [&app, binding, button](Node*) {
execute_canvas_tool_toolbar_binding(app, binding, button);
};
}
} // namespace
void App::init_toolbar_draw() void App::init_toolbar_draw()
{ {
const auto toolbar = pp::app::plan_canvas_tool_toolbar(); pp::panopainter::bind_legacy_draw_toolbar_buttons(*this, *layout[main_id]);
bool apply_default_tool = false;
for (const auto& binding : toolbar.bindings) {
if (binding.custom_button) {
if (auto* button = layout[main_id]->find<NodeButtonCustom>(binding.button_id.data())) {
bind_canvas_tool_toolbar_button(*this, binding, button);
apply_default_tool = apply_default_tool || binding.applies_default_on_init;
}
} else {
if (auto* button = layout[main_id]->find<NodeButton>(binding.button_id.data())) {
bind_canvas_tool_toolbar_button(*this, binding, button);
apply_default_tool = apply_default_tool || binding.applies_default_on_init;
}
}
}
if (apply_default_tool) {
const auto default_plan = pp::app::plan_canvas_tool_select(toolbar.default_mode);
const auto status = pp::panopainter::execute_legacy_canvas_tool_plan(*this, default_plan);
if (!status.ok())
LOG("Canvas default tool action failed: %s", status.message);
}
} }

View File

@@ -5,6 +5,7 @@
#include "app_core/brush_ui.h" #include "app_core/brush_ui.h"
#include "app_core/document_layer.h" #include "app_core/document_layer.h"
#include "legacy_sidebar_color_popup_services.h" #include "legacy_sidebar_color_popup_services.h"
#include "legacy_sidebar_stroke_popup_services.h"
#include "legacy_brush_ui_services.h" #include "legacy_brush_ui_services.h"
#include "legacy_document_layer_services.h" #include "legacy_document_layer_services.h"
#include "legacy_ui_overlay_services.h" #include "legacy_ui_overlay_services.h"
@@ -234,45 +235,7 @@ void App::init_sidebar()
if (!popup_root) { if (!popup_root) {
return; return;
} }
auto screen = popup_root->m_size; pp::panopainter::open_legacy_sidebar_stroke_popup(*this, *popup_root, *button, *stroke);
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
if (stroke->m_parent)
{
if (auto fp = dynamic_cast<NodePanelFloating*>(stroke->m_parent->m_parent))
{
pp::panopainter::detach_legacy_node_from_parent(*stroke);
pp::panopainter::close_legacy_dialog_node(*fp);
}
}
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, stroke);
if (!popup_overlay) {
return;
}
stroke->SetSize(350, glm::max(100.f, screen.y - pos.y - 50.f));
stroke->find("title")->SetVisibility(true);
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*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();
stroke->SetPosition(pos.x - stroke->m_size.x / 2.f, pos.y + 16);
stroke->SetPositioning(YGPositionTypeAbsolute);
pp::panopainter::activate_legacy_popup_overlay(*stroke);
auto scroll = stroke->find<NodeScroll>("scroller");
(void)scroll;
stroke->m_popup_overlay_handle = popup_handle;
stroke->m_tick_overlay_handle = tick_handle;
}; };
} }
//if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-brush")) //if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-brush"))

View File

@@ -0,0 +1,28 @@
#include "pch.h"
#include "legacy_app_status_services.h"
#include "app.h"
#include "app_core/app_status.h"
#include "node_text.h"
namespace pp::panopainter {
void update_legacy_app_title(App& app)
{
if (auto docname = app.layout[app.main_id]->find<NodeText>("txt-docname"))
{
const auto title = pp::app::make_document_title(
app.doc_name,
app.canvas->m_canvas->m_unsaved,
app.canvas->m_canvas->m_width);
docname->set_text(title.c_str());
}
if (auto node = app.layout[app.main_id]->find<NodeText>("txt-dpi"))
{
const auto label = pp::app::make_dpi_label(app.zoom);
node->set_text(label.c_str());
}
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,9 @@
#pragma once
class App;
namespace pp::panopainter {
void update_legacy_app_title(App& app);
} // namespace pp::panopainter

View File

@@ -405,6 +405,88 @@ private:
std::function<void()> action_; std::function<void()> action_;
}; };
void open_legacy_new_document_dialog_impl(App& app)
{
auto* overlay_anchor = app.layout[app.main_id];
if (!overlay_anchor) {
LOG("New document dialog open failed: main layout anchor is missing");
return;
}
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogNewDoc>(app);
dialog->input->set_text("name");
app.showKeyboard();
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
if (!overlay) {
app.hideKeyboard();
LOG("New document dialog open failed: %s", overlay.status().message);
return;
}
dialog->btn_ok->on_click = [&app, dialog](Node*) {
const auto plan = pp::app::plan_new_document(
app.work_path,
dialog->input->m_text,
dialog->m_resolution->m_current_index,
[](const std::string& path) {
return Asset::exist(path);
});
if (!plan) {
const bool missing_name =
plan.status().code == pp::foundation::StatusCode::invalid_argument;
app.message_box(
"Warning",
missing_name ? "You need to specify a name to file." : plan.status().message);
return;
}
const auto status =
pp::panopainter::execute_legacy_new_document_plan(app, plan.value(), dialog);
if (!status.ok())
LOG("New document action failed: %s", status.message);
};
dialog->btn_cancel->on_click = [&app, dialog](Node*) {
pp::panopainter::close_legacy_dialog_and_hide_keyboard(app, *dialog);
};
}
void wire_document_file_save_dialog_buttons(App& app, const std::shared_ptr<NodeDialogSave>& dialog)
{
dialog->btn_ok->on_click = [&app, dialog](Node*) {
const auto status = pp::panopainter::execute_legacy_document_file_save_dialog(app, dialog);
if (!status.ok())
LOG("Document file save action failed: %s", status.message);
};
dialog->btn_cancel->on_click = [&app, dialog](Node*) {
pp::panopainter::close_legacy_dialog_and_hide_keyboard(app, *dialog);
};
}
void open_legacy_document_file_save_dialog_impl(App& app)
{
auto* overlay_anchor = app.layout[app.main_id];
if (!overlay_anchor) {
LOG("Save document dialog open failed: main layout anchor is missing");
return;
}
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogSave>(app);
dialog->input->set_text(app.doc_name);
app.showKeyboard();
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
if (!overlay) {
app.hideKeyboard();
LOG("Save document dialog open failed: %s", overlay.status().message);
return;
}
wire_document_file_save_dialog_buttons(app, dialog);
}
} // namespace } // namespace
pp::foundation::Status execute_legacy_close_request_decision( pp::foundation::Status execute_legacy_close_request_decision(
@@ -433,6 +515,11 @@ pp::foundation::Status execute_legacy_document_workflow_decision(
return pp::app::execute_document_workflow_decision(decision, services); return pp::app::execute_document_workflow_decision(decision, services);
} }
void open_legacy_new_document_dialog(App& app)
{
open_legacy_new_document_dialog_impl(app);
}
pp::foundation::Status execute_legacy_new_document_plan( pp::foundation::Status execute_legacy_new_document_plan(
App& app, App& app,
const pp::app::NewDocumentPlan& plan, const pp::app::NewDocumentPlan& plan,
@@ -469,6 +556,11 @@ pp::foundation::Status execute_legacy_document_file_save_dialog(
return execute_legacy_document_file_save_plan(app, plan.value(), std::move(dialog)); return execute_legacy_document_file_save_plan(app, plan.value(), std::move(dialog));
} }
void open_legacy_document_file_save_dialog(App& app)
{
open_legacy_document_file_save_dialog_impl(app);
}
pp::foundation::Status execute_legacy_document_version_save( pp::foundation::Status execute_legacy_document_version_save(
App& app, App& app,
const pp::app::DocumentVersionTarget& target) const pp::app::DocumentVersionTarget& target)

View File

@@ -26,6 +26,8 @@ namespace pp::panopainter {
pp::app::DocumentWorkflowDecision decision, pp::app::DocumentWorkflowDecision decision,
std::function<void()> action); std::function<void()> action);
void open_legacy_new_document_dialog(App& app);
[[nodiscard]] pp::foundation::Status execute_legacy_new_document_plan( [[nodiscard]] pp::foundation::Status execute_legacy_new_document_plan(
App& app, App& app,
const pp::app::NewDocumentPlan& plan, const pp::app::NewDocumentPlan& plan,
@@ -40,6 +42,8 @@ namespace pp::panopainter {
App& app, App& app,
std::shared_ptr<NodeDialogSave> dialog); std::shared_ptr<NodeDialogSave> dialog);
void open_legacy_document_file_save_dialog(App& app);
[[nodiscard]] pp::foundation::Status execute_legacy_document_version_save( [[nodiscard]] pp::foundation::Status execute_legacy_document_version_save(
App& app, App& app,
const pp::app::DocumentVersionTarget& target); const pp::app::DocumentVersionTarget& target);

View File

@@ -0,0 +1,62 @@
#include "pch.h"
#include "legacy_draw_toolbar_binding_services.h"
#include "app.h"
#include "app_core/canvas_tool_ui.h"
#include "legacy_canvas_tool_services.h"
#include "node_button.h"
#include "node_button_custom.h"
namespace pp::panopainter {
namespace {
[[nodiscard]] bool current_canvas_mode_is_draw(App& app) noexcept
{
return app.canvas && app.canvas->m_canvas && app.canvas->m_canvas->m_current_mode == kCanvasMode::Draw;
}
template <class ButtonT>
void bind_canvas_tool_toolbar_button(
App& app,
Node& toolbar_root,
const pp::app::CanvasToolToolbarBinding& binding)
{
if (auto* button = toolbar_root.find<ButtonT>(binding.button_id.data())) {
button->on_click = [&app, binding, button](Node*) {
const auto plan = pp::app::plan_canvas_tool_toolbar_binding_action(
binding,
current_canvas_mode_is_draw(app));
const auto status = binding.action == pp::app::CanvasToolToolbarAction::select_mode
? pp::panopainter::execute_legacy_canvas_tool_plan(app, plan, button)
: pp::panopainter::execute_legacy_canvas_tool_plan(app, plan);
if (!status.ok())
LOG("Canvas toolbar action failed: %s", status.message);
};
}
}
} // namespace
void bind_legacy_draw_toolbar_buttons(App& app, Node& toolbar_root)
{
const auto toolbar = pp::app::plan_canvas_tool_toolbar();
bool apply_default_tool = false;
for (const auto& binding : toolbar.bindings) {
if (binding.custom_button) {
bind_canvas_tool_toolbar_button<NodeButtonCustom>(app, toolbar_root, binding);
} else {
bind_canvas_tool_toolbar_button<NodeButton>(app, toolbar_root, binding);
}
apply_default_tool = apply_default_tool || binding.applies_default_on_init;
}
if (apply_default_tool) {
const auto default_plan = pp::app::plan_canvas_tool_select(toolbar.default_mode);
const auto status = pp::panopainter::execute_legacy_canvas_tool_plan(app, default_plan);
if (!status.ok())
LOG("Canvas default tool action failed: %s", status.message);
}
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,10 @@
#pragma once
class App;
class Node;
namespace pp::panopainter {
void bind_legacy_draw_toolbar_buttons(App& app, Node& toolbar_root);
} // namespace pp::panopainter

View File

@@ -0,0 +1,52 @@
#include "pch.h"
#include "legacy_info_dialog_services.h"
#include "app.h"
#include "legacy_ui_overlay_services.h"
#include "node_about.h"
#include "node_changelog.h"
#include "node_usermanual.h"
namespace pp::panopainter {
namespace {
template <typename DialogNode>
void open_legacy_info_dialog(App& app, Node& overlay_anchor, const char* log_name)
{
auto dialog = make_legacy_overlay_node<DialogNode>(app);
const auto overlay = open_legacy_overlay_node_with_handle(overlay_anchor, dialog);
if (!overlay) {
LOG("%s dialog open failed: %s", log_name, overlay.status().message);
return;
}
const auto overlay_handle = overlay.value();
const auto close_dialog = [&overlay_anchor, overlay_handle]() {
const auto close_status = close_legacy_overlay_node(overlay_anchor, overlay_handle);
(void)close_status;
};
dialog->btn_ok->on_click = [close_dialog](Node*) {
close_dialog();
};
}
} // namespace
void open_usermanual_dialog(App& app, Node& overlay_anchor, const char* log_name)
{
open_legacy_info_dialog<NodeUserManual>(app, overlay_anchor, log_name);
}
void open_changelog_dialog(App& app, Node& overlay_anchor, const char* log_name)
{
open_legacy_info_dialog<NodeChangelog>(app, overlay_anchor, log_name);
}
void open_about_dialog(App& app, Node& overlay_anchor, const char* log_name)
{
open_legacy_info_dialog<NodeAbout>(app, overlay_anchor, log_name);
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,12 @@
#pragma once
class App;
class Node;
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);
} // namespace pp::panopainter

View File

@@ -0,0 +1,68 @@
#include "pch.h"
#include "legacy_sidebar_stroke_popup_services.h"
#include "app.h"
#include "legacy_ui_overlay_services.h"
#include "node_button_custom.h"
#include "node_image.h"
#include "node_panel_floating.h"
#include "node_panel_stroke.h"
namespace pp::panopainter {
void open_legacy_sidebar_stroke_popup(
App& app,
Node& popup_root,
NodeButtonCustom& trigger_button,
NodePanelStroke& popup_panel)
{
(void)app;
const glm::vec2 pos = trigger_button.m_pos + glm::vec2(trigger_button.m_size.x * 0.5f, trigger_button.m_size.y);
if (popup_panel.m_parent)
{
if (auto fp = dynamic_cast<NodePanelFloating*>(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<NodePanelStroke>(popup_panel.shared_from_this()));
if (!popup_overlay) {
return;
}
popup_panel.SetSize(350, glm::max(100.f, popup_root.m_size.y - pos.y - 50.f));
popup_panel.find("title")->SetVisibility(true);
auto tick = make_legacy_overlay_node_for_anchor<NodeImage>(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<NodeScroll>("scroller");
(void)scroll;
popup_panel.m_popup_overlay_handle = popup_handle;
popup_panel.m_tick_overlay_handle = tick_handle;
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,16 @@
#pragma once
class App;
class Node;
class NodeButtonCustom;
class NodePanelStroke;
namespace pp::panopainter {
void open_legacy_sidebar_stroke_popup(
App& app,
Node& popup_root,
NodeButtonCustom& trigger_button,
NodePanelStroke& popup_panel);
} // namespace pp::panopainter