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_app_shell_services.cpp
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.h
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_ui_state.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_edit_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,
unsaved-project prompting, project-open execution, and title/layer refresh
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.
`src/app_layout_main_toolbar.cpp` no longer owns the retained main-toolbar
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
`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-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
download background execution in `src/legacy_cloud_services.cpp` now routes
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
corresponding `app_layout_*` files are thinner adapters even though retained
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
longer compiles Web platform sources directly, but broader CMake and
entrypoint cleanup are not complete.

View File

@@ -84,6 +84,23 @@ Key facts:
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.
- `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

View File

@@ -1,9 +1,9 @@
#include "pch.h"
#include "app.h"
#include "app_core/app_frame.h"
#include "app_core/app_input.h"
#include "app_core/document_platform_io.h"
#include "app_core/document_sharing.h"
#include "legacy_app_frame_services.h"
#include "platform_api/platform_services.h"
#include <functional>
@@ -14,15 +14,9 @@
#ifdef _WIN32
#include "platform_windows/windows_platform_services.h"
#endif
#include "renderer_gl/opengl_capabilities.h"
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
{
const auto action = pp::app::plan_virtual_keyboard(visible);
@@ -97,35 +91,12 @@ void App::crash_test()
void App::tick(float dt)
{
const auto tick_plan = pp::app::plan_app_frame_tick(
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);
pp::panopainter::execute_legacy_app_frame_tick(*this, dt);
}
void App::resize(float w, float h)
{
LOG("App::resize %d %d", (int)w, (int)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;
pp::panopainter::execute_legacy_app_frame_resize(*this, w, h);
}
void App::show_cursor()

View File

@@ -4,6 +4,7 @@
#include "node_panel_floating.h"
#include "app_core/brush_ui.h"
#include "app_core/document_layer.h"
#include "legacy_sidebar_color_popup_services.h"
#include "legacy_brush_ui_services.h"
#include "legacy_document_layer_services.h"
#include "legacy_ui_overlay_services.h"
@@ -297,37 +298,7 @@ void App::init_sidebar()
if (!popup_root) {
return;
}
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
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);
};
pp::panopainter::open_legacy_sidebar_color_popup(*this, *popup_root, *button, *color);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-layer"))

View File

@@ -1,161 +1,8 @@
#include "pch.h"
#include "app.h"
#include "app_core/app_preferences.h"
#include "legacy_brush_ui_services.h"
#include "legacy_ui_overlay_services.h"
#include "legacy_app_ui_state_services.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)
{
@@ -173,23 +20,11 @@ bool App::get_ui_rtl() const
void App::ui_save()
{
Serializer::Descriptor d;
d.class_id = "ui-state";
Serializer::List list_floatings;
for (auto const& c : layout[main_id]->find("floatings")->m_children)
save_floating_panel_state(list_floatings, c);
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::save_legacy_ui_panel_state(
d,
layout[main_id]->find_ref("floatings"),
layout[main_id]->find_ref("drop-left"),
layout[main_id]->find_ref("drop-right"));
pp::panopainter::set_legacy_ui_state_preferences(d, ui_rtl);
save_platform_ui_state();
@@ -210,7 +45,5 @@ void App::ui_restore()
auto drop_right = layout[main_id]->find_ref("drop-right");
auto d = preferences.state;
restore_panel_children(*this, floatings, d->get<Serializer::List>("floatings")->items, false);
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);
pp::panopainter::restore_legacy_ui_panel_state(*this, floatings, drop_left, drop_right, *d);
}

View File

@@ -1,5 +1,7 @@
#include "pch.h"
#include "legacy_app_frame_services.h"
#include "app.h"
#include "app_core/app_frame.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
@@ -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);
}
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_status.h"
#include "app_core/document_session.h"
#include "legacy_app_frame_services.h"
#include "legacy_document_session_services.h"
#include "legacy_recording_services.h"
#include "legacy_ui_gl_dispatch.h"
@@ -42,9 +43,6 @@ void apply_app_scissor_test(bool enabled)
namespace pp::panopainter {
bool process_legacy_recording_worker_iteration(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)
{
@@ -158,20 +156,10 @@ void App::draw(float dt)
void App::update(float dt)
{
const auto update_plan = pp::app::plan_app_frame_update(redraw, animate);
if (!update_plan.update_frame)
return;
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)dt;
pp::panopainter::execute_legacy_app_frame_update(
*this,
pp::app::plan_app_frame_update(redraw, animate));
}
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