Extract app frame and ui state services

This commit is contained in:
2026-06-17 19:26:42 +02:00
parent 0c609b9d15
commit 52ed7ddeb0
14 changed files with 435 additions and 254 deletions

View File

@@ -94,6 +94,8 @@ 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_ui_state_services.cpp
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
@@ -155,6 +157,8 @@ set(PP_PANOPAINTER_APP_SOURCES
src/app_layout_draw_toolbar.cpp src/app_layout_draw_toolbar.cpp
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_color_popup_services.cpp
src/legacy_sidebar_color_popup_services.h
src/app_layout_main_toolbar.cpp src/app_layout_main_toolbar.cpp
src/app_layout_edit_menu.cpp src/app_layout_edit_menu.cpp
src/app_layout_about_layer_menu.cpp src/app_layout_about_layer_menu.cpp

View File

@@ -25,6 +25,24 @@ agent or engineer to remove them without reconstructing context from chat.
owns that document-open handoff inline while retained dialog creation, owns that document-open handoff inline while retained dialog creation,
unsaved-project prompting, project-open execution, and title/layer refresh unsaved-project prompting, project-open execution, and title/layer refresh
still remain. still remain.
- 2026-06-17: `DEBT-0003` was narrowed again. `App::update()` in
`src/legacy_app_runtime_shell_services.cpp` no longer owns retained
app-frame layout-update and canvas-toolbar refresh execution inline;
`src/legacy_app_frame_services.*` now owns that frame-update execution
behind an explicit `App&` plus `AppFrameUpdatePlan` seam, while draw-time
execution, UI observer walking, and broader app-frame ownership still
remain.
- 2026-06-17: `DEBT-0003` was narrowed again. `App::tick()` and
`App::resize()` in `src/app_events.cpp` no longer own retained app-frame
tick and surface-resize execution inline; `src/legacy_app_frame_services.*`
now owns the tick/resize execution against explicit `App&` plus frame plans,
while broader event dispatch and runtime/platform frame ownership still
remain.
- 2026-06-17: `DEBT-0045` was narrowed again.
`src/app_layout_ui_state.cpp` no longer owns retained floating/docked panel
save/restore serialization inline; that panel-persistence family now lives in
`src/legacy_app_ui_state_services.*`, while RTL direction execution and
broader preference/runtime ownership still remain.
- 2026-06-17: `DEBT-0035` was narrowed again. - 2026-06-17: `DEBT-0035` was narrowed again.
`src/app_layout_main_toolbar.cpp` no longer owns the retained main-toolbar `src/app_layout_main_toolbar.cpp` no longer owns the retained main-toolbar
button wiring inline; `src/legacy_main_toolbar_binding_services.*` now owns button wiring inline; `src/legacy_main_toolbar_binding_services.*` now owns
@@ -48,6 +66,12 @@ agent or engineer to remove them without reconstructing context from chat.
submenu popup flow or panel-item wiring inline; that binding now lives in submenu popup flow or panel-item wiring inline; that binding now lives in
`src/legacy_tools_menu_binding_services.*`, while retained Tools command `src/legacy_tools_menu_binding_services.*`, while retained Tools command
execution and options-menu preference wiring still remain in the app shell. execution and options-menu preference wiring still remain in the app shell.
- 2026-06-17: `DEBT-0063` was narrowed again.
`src/app_layout_sidebar.cpp` no longer owns the retained color-popup open /
close wiring inline; that binding now lives in
`src/legacy_sidebar_color_popup_services.*` with explicit `App&`,
popup-root, trigger-button, and panel dependencies, while retained
stroke/grid/layer popup families still remain on the sidebar shell.
- 2026-06-17: `DEBT-0038` was narrowed again. The retained cloud upload and - 2026-06-17: `DEBT-0038` was narrowed again. The retained cloud upload and
download background execution in `src/legacy_cloud_services.cpp` now routes download background execution in `src/legacy_cloud_services.cpp` now routes
through `AppRuntime::canvas_async_task` instead of a file-static worker through `AppRuntime::canvas_async_task` instead of a file-static worker

View File

@@ -87,6 +87,11 @@ Current conclusion:
lives in dedicated `legacy_*_binding_services.*` helpers, so the lives in dedicated `legacy_*_binding_services.*` helpers, so the
corresponding `app_layout_*` files are thinner adapters even though retained corresponding `app_layout_*` files are thinner adapters even though retained
execution still lives in the app shell. execution still lives in the app shell.
- App-frame update, tick, and resize execution now route through
`src/legacy_app_frame_services.*`, and floating/docked panel persistence now
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.
- 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

@@ -84,6 +84,23 @@ Key facts:
wiring through `src/legacy_tools_menu_binding_services.*`, so wiring through `src/legacy_tools_menu_binding_services.*`, so
`src/app_layout_tools_menu.cpp` no longer owns that floating-panel submenu `src/app_layout_tools_menu.cpp` no longer owns that floating-panel submenu
body inline while retained Tools execution and options wiring remain. body inline while retained Tools execution and options wiring remain.
- `App::update()` now delegates retained app-frame layout update and
canvas-toolbar refresh execution through `src/legacy_app_frame_services.*`,
so `src/legacy_app_runtime_shell_services.cpp` is thinner at the frame
update seam while draw-time execution still remains there.
- `App::tick()` and `App::resize()` now delegate retained app-frame tick and
surface-resize execution through `src/legacy_app_frame_services.*`, so
`src/app_events.cpp` is thinner at the frame-execution seam while broader
input/platform dispatch still remains there.
- `App::ui_save()` and `App::ui_restore()` now delegate retained floating and
docked panel persistence through `src/legacy_app_ui_state_services.*`, so
`src/app_layout_ui_state.cpp` is down to thin preference adapters while RTL
direction execution stays local.
- `App::init_sidebar()` now delegates the retained color-popup open/close
wiring through `src/legacy_sidebar_color_popup_services.*` with explicit
`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.
## Parallel Assignment Rules ## Parallel Assignment Rules

View File

@@ -1,9 +1,9 @@
#include "pch.h" #include "pch.h"
#include "app.h" #include "app.h"
#include "app_core/app_frame.h"
#include "app_core/app_input.h" #include "app_core/app_input.h"
#include "app_core/document_platform_io.h" #include "app_core/document_platform_io.h"
#include "app_core/document_sharing.h" #include "app_core/document_sharing.h"
#include "legacy_app_frame_services.h"
#include "platform_api/platform_services.h" #include "platform_api/platform_services.h"
#include <functional> #include <functional>
@@ -14,15 +14,9 @@
#ifdef _WIN32 #ifdef _WIN32
#include "platform_windows/windows_platform_services.h" #include "platform_windows/windows_platform_services.h"
#endif #endif
#include "renderer_gl/opengl_capabilities.h"
namespace { namespace {
[[nodiscard]] GLint rgba8_internal_format() noexcept
{
return static_cast<GLint>(pp::renderer::gl::rgba8_internal_format());
}
[[nodiscard]] bool should_dispatch_keyboard_visibility(bool visible) noexcept [[nodiscard]] bool should_dispatch_keyboard_visibility(bool visible) noexcept
{ {
const auto action = pp::app::plan_virtual_keyboard(visible); const auto action = pp::app::plan_virtual_keyboard(visible);
@@ -97,35 +91,12 @@ void App::crash_test()
void App::tick(float dt) void App::tick(float dt)
{ {
const auto tick_plan = pp::app::plan_app_frame_tick( pp::panopainter::execute_legacy_app_frame_tick(*this, dt);
layout_designer.get(main_id) != nullptr,
layout.get(main_id) != nullptr);
if (auto* main = layout_designer[main_id]; tick_plan.tick_designer_layout && main)
main->tick(dt);
if (auto* main = layout[main_id]; tick_plan.tick_main_layout && main)
main->tick(dt);
} }
void App::resize(float w, float h) void App::resize(float w, float h)
{ {
LOG("App::resize %d %d", (int)w, (int)h); pp::panopainter::execute_legacy_app_frame_resize(*this, w, h);
const auto resize_plan = pp::app::plan_app_resize(w, h);
if (!resize_plan) {
LOG("App resize plan failed: %s", resize_plan.status().message);
return;
}
if (resize_plan.value().recreate_ui_render_target) {
uirtt.create(
resize_plan.value().render_target_width,
resize_plan.value().render_target_height,
-1,
rgba8_internal_format(),
true);
}
redraw = resize_plan.value().request_redraw;
width = resize_plan.value().width;
height = resize_plan.value().height;
} }
void App::show_cursor() void App::show_cursor()

View File

@@ -4,6 +4,7 @@
#include "node_panel_floating.h" #include "node_panel_floating.h"
#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_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"
@@ -297,37 +298,7 @@ void App::init_sidebar()
if (!popup_root) { if (!popup_root) {
return; return;
} }
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y); pp::panopainter::open_legacy_sidebar_color_popup(*this, *popup_root, *button, *color);
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, color);
if (!popup_overlay)
{
LOG("Color popup overlay failed: %s", popup_overlay.status().message);
return;
}
color->find("title")->SetVisibility(true);
color->SetSize(350, 350);
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*layout[main_id]);
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();
color->SetPosition(pos.x - color->m_size.x / 2.f, pos.y + 16);
color->SetPositioning(YGPositionTypeAbsolute);
pp::panopainter::activate_legacy_popup_overlay(*color);
color->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) {
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle);
};
}; };
} }
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-layer")) if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-layer"))

View File

@@ -1,161 +1,8 @@
#include "pch.h" #include "pch.h"
#include "app.h" #include "app.h"
#include "app_core/app_preferences.h" #include "app_core/app_preferences.h"
#include "legacy_brush_ui_services.h" #include "legacy_app_ui_state_services.h"
#include "legacy_ui_overlay_services.h"
#include "legacy_preference_storage.h" #include "legacy_preference_storage.h"
#include "node_dialog_picker.h"
#include "node_panel_brush.h"
#include "node_panel_color.h"
#include "node_panel_grid.h"
#include "node_panel_floating.h"
#include "serializer.h"
namespace {
bool apply_brush_color_plan(App& app, glm::vec4 color, bool update_quick, bool update_color_panel)
{
return pp::panopainter::apply_legacy_brush_color_plan(app, color, update_quick, update_color_panel);
}
bool apply_brush_preset_plan(App& app, const std::shared_ptr<Brush>& brush)
{
return pp::panopainter::apply_legacy_brush_preset_plan(app, brush);
}
void save_floating_panel_state(Serializer::List& list, const std::shared_ptr<Node>& child)
{
if (auto const& f = std::dynamic_pointer_cast<NodePanelFloating>(child))
{
auto fd = list.add<Serializer::Descriptor>();
fd->class_id = "ui-flt";
fd->set("pos", Serializer::Vec2(f->GetPosition()));
fd->set("size", Serializer::Vec2(f->m_size));
fd->set("class", Serializer::Integer((int)f->m_class));
fd->set("title", Serializer::CString(f->m_title->m_text));
}
}
void save_docked_panel_state(Serializer::List& list, const std::shared_ptr<Node>& child, const char* class_id)
{
if (auto const& f = std::dynamic_pointer_cast<NodePanelFloating>(child))
{
auto fd = list.add<Serializer::Descriptor>();
fd->class_id = class_id;
fd->set("size", Serializer::Vec2(f->m_size));
fd->set("class", Serializer::Integer((int)f->m_class));
fd->set("title", Serializer::CString(f->m_title->m_text));
}
}
template <class TList>
void restore_panel_children(
App& app,
std::shared_ptr<Node> container,
const TList& items,
bool docked)
{
for (auto const& l : items)
{
auto ld = std::static_pointer_cast<Serializer::Descriptor>(l);
auto size = ld->value<Serializer::Vec2>("size");
auto cls = static_cast<NodePanelFloating::kClass>(ld->value<Serializer::Integer>("class"));
auto f = container->add_child<NodePanelFloating>();
std::string title = "Floating Panel";
ld->value<Serializer::CString>("title", title);
f->m_title->set_text(title.c_str());
switch (cls)
{
case NodePanelFloating::kClass::Presets:
{
auto floating_presets = f->m_container->add_child_ref<NodePanelBrushPreset>();
if (!docked)
app.floating_presets = floating_presets;
floating_presets->SetHeightP(100);
floating_presets->on_brush_changed = [&app](Node*, std::shared_ptr<Brush>& b) {
apply_brush_preset_plan(app, b);
};
break;
}
case NodePanelFloating::kClass::Color:
{
auto floating_color = f->m_container->add_child_ref<NodePanelColor>();
if (!docked)
app.floating_color = floating_color;
floating_color->SetHeightP(100);
if (docked)
pp::panopainter::destroy_legacy_node(*floating_color->find("title"));
else
floating_color->find("title")->SetVisibility(false);
floating_color->on_color_changed = [&app](Node*, glm::vec4 color) {
apply_brush_color_plan(app, color, false, false);
};
break;
}
case NodePanelFloating::kClass::ColorAdv:
{
app.floating_picker = f->m_container->add_child_ref<NodeColorPicker>();
app.floating_picker->m_autohide = false;
app.floating_picker->on_color_change = [&app](Node*, glm::vec3 color) {
apply_brush_color_plan(app, glm::vec4(color, 1.f), false, false);
};
break;
}
case NodePanelFloating::kClass::Layers:
f->m_container->add_child(app.layers);
if (!docked)
f->SetMinHeight(100);
if (!docked)
f->SetHeight(300);
if (!docked)
app.layers->find("title")->SetVisibility(false);
app.layers->SetPositioning(YGPositionTypeRelative);
app.layers->SetPosition(0, 0);
app.layers->SetWidthP(100);
app.layers->SetHeightP(100);
app.layers->SetFlexShrink(0);
break;
case NodePanelFloating::kClass::Brush:
f->m_container->add_child(app.stroke);
if (!docked)
app.stroke->find("title")->SetVisibility(false);
app.stroke->SetPositioning(YGPositionTypeRelative);
app.stroke->SetPosition(0, 0);
app.stroke->SetWidthP(100);
app.stroke->SetHeightP(100);
break;
case NodePanelFloating::kClass::Grids:
f->m_container->add_child(app.grid);
if (!docked)
app.grid->find("title")->SetVisibility(false);
app.grid->SetPositioning(YGPositionTypeRelative);
app.grid->SetPosition(0, 0);
app.grid->SetWidthP(100);
app.grid->SetHeightP(100);
break;
case NodePanelFloating::kClass::Animation:
f->m_container->add_child(app.animation);
f->m_droppable = false;
app.animation->SetPositioning(YGPositionTypeRelative);
app.animation->SetPosition(0, 0);
app.animation->SetWidthP(100);
app.animation->SetHeightP(100);
break;
case NodePanelFloating::kClass::Generic:
default:
f->m_container->add_child<Node>();
break;
}
f->m_class = cls;
if (docked)
f->m_dock = container;
f->SetPositioning(docked ? YGPositionTypeRelative : YGPositionTypeAbsolute);
f->SetPosition(0, 0);
f->SetSize(size);
}
}
} // namespace
void App::set_ui_rtl(bool rtl) void App::set_ui_rtl(bool rtl)
{ {
@@ -173,23 +20,11 @@ bool App::get_ui_rtl() const
void App::ui_save() void App::ui_save()
{ {
Serializer::Descriptor d; Serializer::Descriptor d;
d.class_id = "ui-state"; pp::panopainter::save_legacy_ui_panel_state(
d,
Serializer::List list_floatings; layout[main_id]->find_ref("floatings"),
for (auto const& c : layout[main_id]->find("floatings")->m_children) layout[main_id]->find_ref("drop-left"),
save_floating_panel_state(list_floatings, c); layout[main_id]->find_ref("drop-right"));
d.set("floatings", list_floatings);
Serializer::List list_drop_left;
for (auto const& c : layout[main_id]->find("drop-left")->m_children)
save_docked_panel_state(list_drop_left, c, "ui-dpl");
d.set("drop-left", list_drop_left);
Serializer::List list_drop_right;
for (auto const& c : layout[main_id]->find("drop-right")->m_children)
save_docked_panel_state(list_drop_right, c, "ui-dpr");
d.set("drop-right", list_drop_right);
pp::panopainter::set_legacy_ui_state_preferences(d, ui_rtl); pp::panopainter::set_legacy_ui_state_preferences(d, ui_rtl);
save_platform_ui_state(); save_platform_ui_state();
@@ -210,7 +45,5 @@ void App::ui_restore()
auto drop_right = layout[main_id]->find_ref("drop-right"); auto drop_right = layout[main_id]->find_ref("drop-right");
auto d = preferences.state; auto d = preferences.state;
restore_panel_children(*this, floatings, d->get<Serializer::List>("floatings")->items, false); pp::panopainter::restore_legacy_ui_panel_state(*this, floatings, drop_left, drop_right, *d);
restore_panel_children(*this, drop_left, d->get<Serializer::List>("drop-left")->items, true);
restore_panel_children(*this, drop_right, d->get<Serializer::List>("drop-right")->items, true);
} }

View File

@@ -1,5 +1,7 @@
#include "pch.h" #include "pch.h"
#include "legacy_app_frame_services.h"
#include "app.h" #include "app.h"
#include "app_core/app_frame.h" #include "app_core/app_frame.h"
#include "app_core/canvas_tool_ui.h" #include "app_core/canvas_tool_ui.h"
@@ -62,6 +64,11 @@ void watch_layout_children(LayoutManager* layout, uint16_t main_id, int start_in
} }
} }
[[nodiscard]] GLint rgba8_internal_format() noexcept
{
return static_cast<GLint>(pp::renderer::gl::rgba8_internal_format());
}
} }
namespace pp::panopainter namespace pp::panopainter
@@ -161,4 +168,56 @@ void update_legacy_canvas_toolbar(App& app)
app.layout[app.main_id]->find<NodeButtonCustom>("btn-bucket")->set_active(toolbar.flood_fill_active); app.layout[app.main_id]->find<NodeButtonCustom>("btn-bucket")->set_active(toolbar.flood_fill_active);
} }
void execute_legacy_app_frame_update(
App& app,
const pp::app::AppFrameUpdatePlan& plan)
{
if (!plan.update_frame)
return;
if (auto* main = app.layout[app.main_id]; plan.update_layouts && main)
main->update(app.width, app.height, app.zoom);
if (auto* main = app.layout_designer[app.main_id]; plan.update_layouts && main)
main->update(app.width, app.height, app.zoom);
if (!plan.refresh_canvas_toolbar)
return;
update_legacy_canvas_toolbar(app);
}
void execute_legacy_app_frame_tick(App& app, float dt)
{
const auto tick_plan = pp::app::plan_app_frame_tick(
app.layout_designer.get(app.main_id) != nullptr,
app.layout.get(app.main_id) != nullptr);
if (auto* main = app.layout_designer[app.main_id]; tick_plan.tick_designer_layout && main)
main->tick(dt);
if (auto* main = app.layout[app.main_id]; tick_plan.tick_main_layout && main)
main->tick(dt);
}
void execute_legacy_app_frame_resize(App& app, float width, float height)
{
LOG("App::resize %d %d", (int)width, (int)height);
const auto resize_plan = pp::app::plan_app_resize(width, height);
if (!resize_plan) {
LOG("App resize plan failed: %s", resize_plan.status().message);
return;
}
if (resize_plan.value().recreate_ui_render_target) {
app.uirtt.create(
resize_plan.value().render_target_width,
resize_plan.value().render_target_height,
-1,
rgba8_internal_format(),
true);
}
app.redraw = resize_plan.value().request_redraw;
app.width = resize_plan.value().width;
app.height = resize_plan.value().height;
}
} }

View File

@@ -0,0 +1,24 @@
#pragma once
#include "app_core/app_frame.h"
class App;
class Node;
#include <functional>
namespace pp::panopainter {
[[nodiscard]] bool update_legacy_app_ui_observer(App& app, Node* n);
void watch_legacy_app_ui_children(
App& app,
const std::function<bool(Node*)>& observer,
bool skip_first_main_child);
void update_legacy_canvas_toolbar(App& app);
void execute_legacy_app_frame_update(
App& app,
const pp::app::AppFrameUpdatePlan& plan);
void execute_legacy_app_frame_tick(App& app, float dt);
void execute_legacy_app_frame_resize(App& app, float width, float height);
} // namespace pp::panopainter

View File

@@ -7,6 +7,7 @@
#include "app_core/app_shutdown.h" #include "app_core/app_shutdown.h"
#include "app_core/app_status.h" #include "app_core/app_status.h"
#include "app_core/document_session.h" #include "app_core/document_session.h"
#include "legacy_app_frame_services.h"
#include "legacy_document_session_services.h" #include "legacy_document_session_services.h"
#include "legacy_recording_services.h" #include "legacy_recording_services.h"
#include "legacy_ui_gl_dispatch.h" #include "legacy_ui_gl_dispatch.h"
@@ -42,9 +43,6 @@ void apply_app_scissor_test(bool enabled)
namespace pp::panopainter { namespace pp::panopainter {
bool process_legacy_recording_worker_iteration(App& app); bool process_legacy_recording_worker_iteration(App& app);
void update_legacy_recording_frame_label(App& app); void update_legacy_recording_frame_label(App& app);
bool update_legacy_app_ui_observer(App& app, Node* n);
void watch_legacy_app_ui_children(App& app, const std::function<bool(Node*)>& observer, bool skip_first_main_child);
void update_legacy_canvas_toolbar(App& app);
bool execute_legacy_app_request_close(App& app) bool execute_legacy_app_request_close(App& app)
{ {
@@ -158,20 +156,10 @@ void App::draw(float dt)
void App::update(float dt) void App::update(float dt)
{ {
const auto update_plan = pp::app::plan_app_frame_update(redraw, animate); (void)dt;
if (!update_plan.update_frame) pp::panopainter::execute_legacy_app_frame_update(
return; *this,
pp::app::plan_app_frame_update(redraw, animate));
if (auto* main = layout[main_id]; update_plan.update_layouts && main)
main->update(width, height, zoom);
if (auto* main = layout_designer[main_id]; update_plan.update_layouts && main)
main->update(width, height, zoom);
if (!update_plan.refresh_canvas_toolbar)
return;
pp::panopainter::update_legacy_canvas_toolbar(*this);
} }
void App::clear() void App::clear()

View File

@@ -0,0 +1,187 @@
#include "pch.h"
#include "legacy_app_ui_state_services.h"
#include "app.h"
#include "legacy_brush_ui_services.h"
#include "legacy_ui_overlay_services.h"
#include "node_dialog_picker.h"
#include "node_panel_brush.h"
#include "node_panel_color.h"
#include "node_panel_grid.h"
#include "node_panel_floating.h"
namespace pp::panopainter {
namespace {
void save_floating_panel_state(Serializer::List& list, const std::shared_ptr<Node>& child)
{
if (auto const& f = std::dynamic_pointer_cast<NodePanelFloating>(child))
{
auto fd = list.add<Serializer::Descriptor>();
fd->class_id = "ui-flt";
fd->set("pos", Serializer::Vec2(f->GetPosition()));
fd->set("size", Serializer::Vec2(f->m_size));
fd->set("class", Serializer::Integer((int)f->m_class));
fd->set("title", Serializer::CString(f->m_title->m_text));
}
}
void save_docked_panel_state(Serializer::List& list, const std::shared_ptr<Node>& child, const char* class_id)
{
if (auto const& f = std::dynamic_pointer_cast<NodePanelFloating>(child))
{
auto fd = list.add<Serializer::Descriptor>();
fd->class_id = class_id;
fd->set("size", Serializer::Vec2(f->m_size));
fd->set("class", Serializer::Integer((int)f->m_class));
fd->set("title", Serializer::CString(f->m_title->m_text));
}
}
template <class TList>
void restore_panel_children(
App& app,
std::shared_ptr<Node> container,
const TList& items,
bool docked)
{
for (auto const& l : items)
{
auto ld = std::static_pointer_cast<Serializer::Descriptor>(l);
auto size = ld->value<Serializer::Vec2>("size");
auto cls = static_cast<NodePanelFloating::kClass>(ld->value<Serializer::Integer>("class"));
auto f = container->add_child<NodePanelFloating>();
std::string title = "Floating Panel";
ld->value<Serializer::CString>("title", title);
f->m_title->set_text(title.c_str());
switch (cls)
{
case NodePanelFloating::kClass::Presets:
{
auto floating_presets = f->m_container->add_child_ref<NodePanelBrushPreset>();
if (!docked)
app.floating_presets = floating_presets;
floating_presets->SetHeightP(100);
floating_presets->on_brush_changed = [&app](Node*, std::shared_ptr<Brush>& b) {
(void)apply_legacy_brush_preset_plan(app, b);
};
break;
}
case NodePanelFloating::kClass::Color:
{
auto floating_color = f->m_container->add_child_ref<NodePanelColor>();
if (!docked)
app.floating_color = floating_color;
floating_color->SetHeightP(100);
if (docked)
destroy_legacy_node(*floating_color->find("title"));
else
floating_color->find("title")->SetVisibility(false);
floating_color->on_color_changed = [&app](Node*, glm::vec4 color) {
(void)apply_legacy_brush_color_plan(app, color, false, false);
};
break;
}
case NodePanelFloating::kClass::ColorAdv:
{
app.floating_picker = f->m_container->add_child_ref<NodeColorPicker>();
app.floating_picker->m_autohide = false;
app.floating_picker->on_color_change = [&app](Node*, glm::vec3 color) {
(void)apply_legacy_brush_color_plan(app, glm::vec4(color, 1.f), false, false);
};
break;
}
case NodePanelFloating::kClass::Layers:
f->m_container->add_child(app.layers);
if (!docked)
f->SetMinHeight(100);
if (!docked)
f->SetHeight(300);
if (!docked)
app.layers->find("title")->SetVisibility(false);
app.layers->SetPositioning(YGPositionTypeRelative);
app.layers->SetPosition(0, 0);
app.layers->SetWidthP(100);
app.layers->SetHeightP(100);
app.layers->SetFlexShrink(0);
break;
case NodePanelFloating::kClass::Brush:
f->m_container->add_child(app.stroke);
if (!docked)
app.stroke->find("title")->SetVisibility(false);
app.stroke->SetPositioning(YGPositionTypeRelative);
app.stroke->SetPosition(0, 0);
app.stroke->SetWidthP(100);
app.stroke->SetHeightP(100);
break;
case NodePanelFloating::kClass::Grids:
f->m_container->add_child(app.grid);
if (!docked)
app.grid->find("title")->SetVisibility(false);
app.grid->SetPositioning(YGPositionTypeRelative);
app.grid->SetPosition(0, 0);
app.grid->SetWidthP(100);
app.grid->SetHeightP(100);
break;
case NodePanelFloating::kClass::Animation:
f->m_container->add_child(app.animation);
f->m_droppable = false;
app.animation->SetPositioning(YGPositionTypeRelative);
app.animation->SetPosition(0, 0);
app.animation->SetWidthP(100);
app.animation->SetHeightP(100);
break;
case NodePanelFloating::kClass::Generic:
default:
f->m_container->add_child<Node>();
break;
}
f->m_class = cls;
if (docked)
f->m_dock = container;
f->SetPositioning(docked ? YGPositionTypeRelative : YGPositionTypeAbsolute);
f->SetPosition(0, 0);
f->SetSize(size);
}
}
} // namespace
void save_legacy_ui_panel_state(
Serializer::Descriptor& state,
const std::shared_ptr<Node>& floatings,
const std::shared_ptr<Node>& drop_left,
const std::shared_ptr<Node>& drop_right)
{
state.class_id = "ui-state";
Serializer::List list_floatings;
for (const auto& c : floatings->m_children)
save_floating_panel_state(list_floatings, c);
state.set("floatings", list_floatings);
Serializer::List list_drop_left;
for (const auto& c : drop_left->m_children)
save_docked_panel_state(list_drop_left, c, "ui-dpl");
state.set("drop-left", list_drop_left);
Serializer::List list_drop_right;
for (const auto& c : drop_right->m_children)
save_docked_panel_state(list_drop_right, c, "ui-dpr");
state.set("drop-right", list_drop_right);
}
void restore_legacy_ui_panel_state(
App& app,
const std::shared_ptr<Node>& floatings,
const std::shared_ptr<Node>& drop_left,
const std::shared_ptr<Node>& drop_right,
const Serializer::Descriptor& state)
{
restore_panel_children(app, floatings, state.get<Serializer::List>("floatings")->items, false);
restore_panel_children(app, drop_left, state.get<Serializer::List>("drop-left")->items, true);
restore_panel_children(app, drop_right, state.get<Serializer::List>("drop-right")->items, true);
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,25 @@
#pragma once
#include "serializer.h"
#include <memory>
class App;
class Node;
namespace pp::panopainter {
void save_legacy_ui_panel_state(
Serializer::Descriptor& state,
const std::shared_ptr<Node>& floatings,
const std::shared_ptr<Node>& drop_left,
const std::shared_ptr<Node>& drop_right);
void restore_legacy_ui_panel_state(
App& app,
const std::shared_ptr<Node>& floatings,
const std::shared_ptr<Node>& drop_left,
const std::shared_ptr<Node>& drop_right,
const Serializer::Descriptor& state);
} // namespace pp::panopainter

View File

@@ -0,0 +1,57 @@
#include "pch.h"
#include "legacy_sidebar_color_popup_services.h"
#include "app.h"
#include "legacy_ui_overlay_services.h"
#include "node_button_custom.h"
#include "node_image.h"
#include "node_panel_color.h"
namespace pp::panopainter {
void open_legacy_sidebar_color_popup(
App& app,
Node& popup_root,
NodeButtonCustom& trigger_button,
NodePanelColor& popup_panel)
{
const glm::vec2 pos = trigger_button.m_pos + glm::vec2(trigger_button.m_size.x * 0.5f, trigger_button.m_size.y);
const auto popup_overlay = open_legacy_overlay_node_with_handle(
popup_root,
std::static_pointer_cast<NodePanelColor>(popup_panel.shared_from_this()));
if (!popup_overlay)
{
LOG("Color popup overlay failed: %s", popup_overlay.status().message);
return;
}
popup_panel.find("title")->SetVisibility(true);
popup_panel.SetSize(350, 350);
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)
{
pp::panopainter::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);
popup_panel.on_popup_close = [&popup_root, popup_handle, tick_handle](Node*) {
pp::panopainter::close_legacy_overlay_handle_ignoring_status(popup_root, popup_handle);
pp::panopainter::close_legacy_overlay_handle_ignoring_status(popup_root, tick_handle);
};
}
} // namespace pp::panopainter

View File

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