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_app_shell_services.cpp
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.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_info_dialog_services.cpp
src/legacy_info_dialog_services.h
src/legacy_canvas_tool_services.cpp
src/legacy_canvas_tool_services.h
src/legacy_canvas_view_services.cpp
@@ -155,8 +159,12 @@ set(PP_PANOPAINTER_APP_SOURCES
src/app_layout_bootstrap.cpp
src/app_layout_brush.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_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.h
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
`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
`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
retained pass-sequence, mix-execution, final-composite-request, background
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
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.
- 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.

View File

@@ -101,6 +101,29 @@ Key facts:
`App&`, popup-root, trigger-button, and panel dependencies, so
`src/app_layout_sidebar.cpp` is thinner while the retained stroke/grid/layer
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

View File

@@ -2,59 +2,45 @@
#include "app.h"
#include "legacy_preference_storage.h"
#include "legacy_ui_overlay_services.h"
#include "node_about.h"
#include "node_changelog.h"
#include "legacy_info_dialog_services.h"
#include "node_remote_page.h"
#include "node_shorcuts.h"
#include "node_usermanual.h"
#include "version.h"
namespace pp::panopainter {
namespace {
template <typename DialogNode>
void open_info_dialog(App& app, const char* log_name)
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;
}
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();
};
return overlay_anchor;
}
} // namespace
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)
{
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)
{
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)

View File

@@ -9,27 +9,6 @@
#include "node_dialog_open.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)
{
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()
{
auto show_dialog = [this] {
auto* overlay_anchor = layout[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>(*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();
};
pp::panopainter::open_legacy_new_document_dialog(*this);
};
continue_document_workflow_after_optional_save(show_dialog);
@@ -219,35 +143,7 @@ void App::dialog_save()
}
if (canvas)
{
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);
}
pp::panopainter::open_legacy_document_file_save_dialog(*this);
}
void App::dialog_resize()

View File

@@ -1,13 +1,12 @@
#include "pch.h"
#include "app.h"
#include "node_text.h"
#include "node_panel_floating.h"
#include "app_core/about_menu.h"
#include "app_core/app_preferences.h"
#include "app_core/document_layer.h"
#include "app_core/document_canvas.h"
#include "app_core/app_status.h"
#include "app_core/tools_menu.h"
#include "legacy_app_status_services.h"
#include "legacy_app_preference_services.h"
#include "legacy_app_shell_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()
{
if (auto docname = layout[main_id]->find<NodeText>("txt-docname"))
{
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());
}
pp::panopainter::update_legacy_app_title(*this);
}
void App::init_toolbar_main()

View File

@@ -1,68 +1,8 @@
#include "pch.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 {
[[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
#include "legacy_draw_toolbar_binding_services.h"
void App::init_toolbar_draw()
{
const auto toolbar = pp::app::plan_canvas_tool_toolbar();
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);
}
pp::panopainter::bind_legacy_draw_toolbar_buttons(*this, *layout[main_id]);
}

View File

@@ -5,6 +5,7 @@
#include "app_core/brush_ui.h"
#include "app_core/document_layer.h"
#include "legacy_sidebar_color_popup_services.h"
#include "legacy_sidebar_stroke_popup_services.h"
#include "legacy_brush_ui_services.h"
#include "legacy_document_layer_services.h"
#include "legacy_ui_overlay_services.h"
@@ -234,45 +235,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);
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;
pp::panopainter::open_legacy_sidebar_stroke_popup(*this, *popup_root, *button, *stroke);
};
}
//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_;
};
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
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);
}
void open_legacy_new_document_dialog(App& app)
{
open_legacy_new_document_dialog_impl(app);
}
pp::foundation::Status execute_legacy_new_document_plan(
App& app,
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));
}
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(
App& app,
const pp::app::DocumentVersionTarget& target)

View File

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