Extract main toolbar and thin startup/node helpers
This commit is contained in:
@@ -98,6 +98,7 @@ set(PP_PANOPAINTER_APP_SOURCES
|
|||||||
src/app_events.cpp
|
src/app_events.cpp
|
||||||
src/app_layout.cpp
|
src/app_layout.cpp
|
||||||
src/app_layout_sidebar.cpp
|
src/app_layout_sidebar.cpp
|
||||||
|
src/app_layout_main_toolbar.cpp
|
||||||
src/app_layout_about_layer_menu.cpp
|
src/app_layout_about_layer_menu.cpp
|
||||||
src/app_layout_file_menu.cpp
|
src/app_layout_file_menu.cpp
|
||||||
src/app_layout_tools_menu.cpp
|
src/app_layout_tools_menu.cpp
|
||||||
|
|||||||
@@ -80,10 +80,10 @@ What is still carrying too much live ownership:
|
|||||||
Current hotspot files:
|
Current hotspot files:
|
||||||
|
|
||||||
- `src/canvas.cpp`: 2645 lines
|
- `src/canvas.cpp`: 2645 lines
|
||||||
- `src/app_layout.cpp`: 785 lines
|
- `src/app_layout.cpp`: 743 lines
|
||||||
- `src/canvas_modes.cpp`: 1798 lines
|
- `src/canvas_modes.cpp`: 1798 lines
|
||||||
- `src/node.cpp`: 1551 lines
|
- `src/node.cpp`: 1594 lines
|
||||||
- `src/main.cpp`: 882 lines
|
- `src/main.cpp`: 1098 lines
|
||||||
- `src/node_panel_brush.cpp`: 1197 lines
|
- `src/node_panel_brush.cpp`: 1197 lines
|
||||||
- `src/node_stroke_preview.cpp`: 933 lines
|
- `src/node_stroke_preview.cpp`: 933 lines
|
||||||
- `src/node_canvas.cpp`: 910 lines
|
- `src/node_canvas.cpp`: 910 lines
|
||||||
@@ -140,10 +140,13 @@ Current architecture mismatches that must be treated as real blockers:
|
|||||||
`src/app_layout_about_layer_menu.cpp` and `App::init_menu_about()` plus
|
`src/app_layout_about_layer_menu.cpp` and `App::init_menu_about()` plus
|
||||||
`App::init_menu_layer()` are now thin call-throughs, while sidebar panel
|
`App::init_menu_layer()` are now thin call-throughs, while sidebar panel
|
||||||
binding and popup wiring now also live in `src/app_layout_sidebar.cpp` and
|
binding and popup wiring now also live in `src/app_layout_sidebar.cpp` and
|
||||||
`App::init_sidebar()` is now a thin call-through, while the informational
|
`App::init_sidebar()` is now a thin call-through, while main-toolbar binding
|
||||||
overlay opener family now also lives in `src/app_dialogs_info_openers.cpp`
|
now also lives in `src/app_layout_main_toolbar.cpp` and
|
||||||
and the corresponding `App::dialog_*` entrypoints are thinner, while the
|
`App::init_toolbar_main()` is now a thin call-through, while the
|
||||||
export/video/PPBR dialog family now also lives in
|
informational overlay opener family now also lives in
|
||||||
|
`src/app_dialogs_info_openers.cpp` and the corresponding `App::dialog_*`
|
||||||
|
entrypoints are thinner, while the export/video/PPBR dialog family now also
|
||||||
|
lives in
|
||||||
`src/app_dialogs_export.cpp` and those `App::dialog_*` entrypoints are
|
`src/app_dialogs_export.cpp` and those `App::dialog_*` entrypoints are
|
||||||
thinner too, while new/open/save/browse/resize workflow entrypoints now also
|
thinner too, while new/open/save/browse/resize workflow entrypoints now also
|
||||||
live in `src/app_dialogs_workflow.cpp` and `src/app_dialogs.cpp` is now
|
live in `src/app_dialogs_workflow.cpp` and `src/app_dialogs.cpp` is now
|
||||||
@@ -183,6 +186,12 @@ Current architecture mismatches that must be treated as real blockers:
|
|||||||
sequencing, FPS title update/wakeup posting, stylus frame update, window
|
sequencing, FPS title update/wakeup posting, stylus frame update, window
|
||||||
preference save, and VR lifecycle wrappers now also live in
|
preference save, and VR lifecycle wrappers now also live in
|
||||||
`src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp`,
|
`src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp`,
|
||||||
|
while the Win32 startup/window/bootstrap path in `src/main.cpp` now also
|
||||||
|
routes through named local helper functions for runtime-data discovery,
|
||||||
|
startup-state initialization, window creation, pixel-format setup, GL loader
|
||||||
|
init, runtime-info logging, and core-context upgrade sequencing even though
|
||||||
|
that state still needs to move into platform-owned modules for the file to
|
||||||
|
shrink materially,
|
||||||
while `App::rec_loop()` now delegates worker-iteration orchestration into
|
while `App::rec_loop()` now delegates worker-iteration orchestration into
|
||||||
the retained recording bridge, `App::update_rec_frames()` now delegates
|
the retained recording bridge, `App::update_rec_frames()` now delegates
|
||||||
recording label refresh through that same retained recording path, and the
|
recording label refresh through that same retained recording path, and the
|
||||||
@@ -198,7 +207,11 @@ Current architecture mismatches that must be treated as real blockers:
|
|||||||
document-IO cluster now lives in `src/legacy_canvas_document_io_services.cpp`
|
document-IO cluster now lives in `src/legacy_canvas_document_io_services.cpp`
|
||||||
and `NodeStrokePreview` render-target setup plus immediate-pass sequencing
|
and `NodeStrokePreview` render-target setup plus immediate-pass sequencing
|
||||||
now route through retained preview execution helpers, even though the bridge
|
now route through retained preview execution helpers, even though the bridge
|
||||||
still owns worker-side readback flow and encoder-state label reads.
|
still owns worker-side readback flow and encoder-state label reads, while
|
||||||
|
`Node` child attach/detach/reorder operations now route through named local
|
||||||
|
helpers in `src/node.cpp`, which makes the scene-graph mutation paths easier
|
||||||
|
to reason about without yet reducing the file or moving ownership into
|
||||||
|
`pp_ui_core`.
|
||||||
- Modern C++23 usage exists in extracted components, especially `std::span`,
|
- Modern C++23 usage exists in extracted components, especially `std::span`,
|
||||||
explicit result/status objects, and a few concepts, but the live app still
|
explicit result/status objects, and a few concepts, but the live app still
|
||||||
does not consistently express ownership, thread affinity, or renderer
|
does not consistently express ownership, thread affinity, or renderer
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ targets look like helpers under one old monolith.
|
|||||||
Status: In Progress
|
Status: In Progress
|
||||||
|
|
||||||
Why now:
|
Why now:
|
||||||
`src/app_layout.cpp` is still a 1249-line mixed file that builds menus,
|
`src/app_layout.cpp` is still a 743-line mixed file that builds menus,
|
||||||
attaches callbacks, computes planner inputs, and mutates UI state directly.
|
attaches callbacks, computes planner inputs, and mutates UI state directly.
|
||||||
|
|
||||||
Current slice:
|
Current slice:
|
||||||
@@ -313,6 +313,9 @@ Current slice:
|
|||||||
`src/app_layout_sidebar.cpp`, and `App::init_sidebar()` is now a thin
|
`src/app_layout_sidebar.cpp`, and `App::init_sidebar()` is now a thin
|
||||||
call-through, but edit-menu wiring and broader layout composition are still
|
call-through, but edit-menu wiring and broader layout composition are still
|
||||||
inline in `src/app_layout.cpp`.
|
inline in `src/app_layout.cpp`.
|
||||||
|
- Main-toolbar binding now also lives in `src/app_layout_main_toolbar.cpp`,
|
||||||
|
and `App::init_toolbar_main()` is now a thin call-through, but edit-menu
|
||||||
|
wiring and broader layout composition are still inline in `src/app_layout.cpp`.
|
||||||
|
|
||||||
Write scope:
|
Write scope:
|
||||||
- `src/app_layout.cpp`
|
- `src/app_layout.cpp`
|
||||||
@@ -473,6 +476,12 @@ Current slice:
|
|||||||
wakeup posting, stylus frame update, window preference save, and VR
|
wakeup posting, stylus frame update, window preference save, and VR
|
||||||
lifecycle wrappers now also live in
|
lifecycle wrappers now also live in
|
||||||
`src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp`
|
`src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp`
|
||||||
|
- `main.cpp` startup/window/bootstrap flow now also routes through named local
|
||||||
|
helpers for runtime-data discovery, startup-state initialization, window
|
||||||
|
creation, pixel-format setup, GL loader init, runtime-info logging, and
|
||||||
|
core-context upgrade sequencing, but the retained Win32 shell still needs
|
||||||
|
those helpers moved into platform-owned modules before the file materially
|
||||||
|
shrinks
|
||||||
- prepared-file background work now runs through an `AppRuntime`-owned worker
|
- prepared-file background work now runs through an `AppRuntime`-owned worker
|
||||||
queue instead of a retained static worker in `src/app_events.cpp`
|
queue instead of a retained static worker in `src/app_events.cpp`
|
||||||
- canvas async import/export/save/open background work now also runs through an
|
- canvas async import/export/save/open background work now also runs through an
|
||||||
@@ -632,6 +641,12 @@ Why now:
|
|||||||
mixes raw `Node*`, shared ownership, direct `add_child(...)`, and callback
|
mixes raw `Node*`, shared ownership, direct `add_child(...)`, and callback
|
||||||
captures across mutation points.
|
captures across mutation points.
|
||||||
|
|
||||||
|
Current slice:
|
||||||
|
- `src/node.cpp` child attach/detach/reorder paths now route through named
|
||||||
|
local helpers instead of repeating raw mutation logic inline. That improves
|
||||||
|
scene-graph mutation clarity, but it does not yet change the ownership model
|
||||||
|
or move those paths behind checked handles.
|
||||||
|
|
||||||
Write scope:
|
Write scope:
|
||||||
- `src/node.*`
|
- `src/node.*`
|
||||||
- `src/layout.*`
|
- `src/layout.*`
|
||||||
|
|||||||
@@ -14,14 +14,12 @@
|
|||||||
#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/app_status.h"
|
||||||
#include "app_core/main_toolbar.h"
|
|
||||||
#include "app_core/tools_menu.h"
|
#include "app_core/tools_menu.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_brush_ui_services.h"
|
#include "legacy_brush_ui_services.h"
|
||||||
#include "legacy_canvas_tool_services.h"
|
#include "legacy_canvas_tool_services.h"
|
||||||
#include "legacy_document_layer_services.h"
|
#include "legacy_document_layer_services.h"
|
||||||
#include "legacy_history_services.h"
|
|
||||||
#include "legacy_preference_storage.h"
|
#include "legacy_preference_storage.h"
|
||||||
#include "legacy_ui_overlay_services.h"
|
#include "legacy_ui_overlay_services.h"
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
@@ -32,6 +30,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace pp::panopainter {
|
namespace pp::panopainter {
|
||||||
|
void bind_legacy_main_toolbar(App& app);
|
||||||
void bind_legacy_file_menu(App& app);
|
void bind_legacy_file_menu(App& app);
|
||||||
void bind_legacy_about_menu(App& app);
|
void bind_legacy_about_menu(App& app);
|
||||||
void bind_legacy_layer_menu(App& app);
|
void bind_legacy_layer_menu(App& app);
|
||||||
@@ -97,11 +96,6 @@ void apply_tools_panel_chrome(NodePanelFloating& panel, const pp::app::ToolsPane
|
|||||||
panel.m_droppable = plan.droppable;
|
panel.m_droppable = plan.droppable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute_main_toolbar_plan(App& app, const pp::app::MainToolbarPlan& plan)
|
|
||||||
{
|
|
||||||
pp::panopainter::execute_legacy_main_toolbar_plan(app, plan);
|
|
||||||
}
|
|
||||||
|
|
||||||
void execute_tools_menu_plan(App& app, const pp::app::ToolsMenuPlan& plan)
|
void execute_tools_menu_plan(App& app, const pp::app::ToolsMenuPlan& plan)
|
||||||
{
|
{
|
||||||
pp::panopainter::execute_legacy_tools_menu_plan(app, plan);
|
pp::panopainter::execute_legacy_tools_menu_plan(app, plan);
|
||||||
@@ -135,101 +129,7 @@ void App::title_update()
|
|||||||
|
|
||||||
void App::init_toolbar_main()
|
void App::init_toolbar_main()
|
||||||
{
|
{
|
||||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-anim"))
|
pp::panopainter::bind_legacy_main_toolbar(*this);
|
||||||
{
|
|
||||||
button->on_click = [this, button](Node*) {
|
|
||||||
if (canvas)
|
|
||||||
{
|
|
||||||
//canvas->m_canvas->export_anim();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-open"))
|
|
||||||
{
|
|
||||||
button->on_click = [this, button](Node*) {
|
|
||||||
const auto plan = pp::app::plan_main_toolbar_command(
|
|
||||||
pp::app::MainToolbarCommand::open_document);
|
|
||||||
if (plan)
|
|
||||||
execute_main_toolbar_plan(*this, plan.value());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-save"))
|
|
||||||
{
|
|
||||||
button->on_click = [this, button](Node*) {
|
|
||||||
const auto plan = pp::app::plan_main_toolbar_command(
|
|
||||||
pp::app::MainToolbarCommand::save_document);
|
|
||||||
if (plan)
|
|
||||||
execute_main_toolbar_plan(*this, plan.value());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-undo"))
|
|
||||||
{
|
|
||||||
button->on_click = [this, button](Node*) {
|
|
||||||
const auto history = pp::panopainter::legacy_history_snapshot();
|
|
||||||
const auto plan = pp::app::plan_main_toolbar_command(
|
|
||||||
pp::app::MainToolbarCommand::undo,
|
|
||||||
history.undo_count);
|
|
||||||
if (plan)
|
|
||||||
execute_main_toolbar_plan(*this, plan.value());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-redo"))
|
|
||||||
{
|
|
||||||
button->on_click = [this, button](Node*) {
|
|
||||||
const auto history = pp::panopainter::legacy_history_snapshot();
|
|
||||||
const auto plan = pp::app::plan_main_toolbar_command(
|
|
||||||
pp::app::MainToolbarCommand::redo,
|
|
||||||
0,
|
|
||||||
history.redo_count);
|
|
||||||
if (plan)
|
|
||||||
execute_main_toolbar_plan(*this, plan.value());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-clean-memory"))
|
|
||||||
{
|
|
||||||
button->on_click = [this](Node*) {
|
|
||||||
const auto history = pp::panopainter::legacy_history_snapshot();
|
|
||||||
const auto plan = pp::app::plan_main_toolbar_command(
|
|
||||||
pp::app::MainToolbarCommand::clear_history,
|
|
||||||
history.undo_count,
|
|
||||||
history.redo_count,
|
|
||||||
history.memory_bytes);
|
|
||||||
if (plan)
|
|
||||||
execute_main_toolbar_plan(*this, plan.value());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-clear"))
|
|
||||||
{
|
|
||||||
button->on_click = [this](Node*) {
|
|
||||||
//exit(0);
|
|
||||||
const auto plan = pp::app::plan_main_toolbar_command(
|
|
||||||
pp::app::MainToolbarCommand::clear_canvas,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
static_cast<bool>(canvas));
|
|
||||||
if (plan)
|
|
||||||
execute_main_toolbar_plan(*this, plan.value());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-popup"))
|
|
||||||
{
|
|
||||||
button->on_click = [this](Node*) {
|
|
||||||
const auto plan = pp::app::plan_main_toolbar_command(
|
|
||||||
pp::app::MainToolbarCommand::show_message_box);
|
|
||||||
if (plan)
|
|
||||||
execute_main_toolbar_plan(*this, plan.value());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-settings"))
|
|
||||||
{
|
|
||||||
button->on_click = [this](Node*) {
|
|
||||||
const auto plan = pp::app::plan_main_toolbar_command(
|
|
||||||
pp::app::MainToolbarCommand::show_settings);
|
|
||||||
if (plan)
|
|
||||||
execute_main_toolbar_plan(*this, plan.value());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool current_canvas_mode_is_draw(App& app) noexcept
|
[[nodiscard]] bool current_canvas_mode_is_draw(App& app) noexcept
|
||||||
|
|||||||
118
src/app_layout_main_toolbar.cpp
Normal file
118
src/app_layout_main_toolbar.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "app.h"
|
||||||
|
#include "app_core/main_toolbar.h"
|
||||||
|
#include "legacy_app_shell_services.h"
|
||||||
|
#include "legacy_history_services.h"
|
||||||
|
#include "node_button.h"
|
||||||
|
#include "node_button_custom.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void execute_main_toolbar_plan(App& app, const pp::app::MainToolbarPlan& plan)
|
||||||
|
{
|
||||||
|
pp::panopainter::execute_legacy_main_toolbar_plan(app, plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace pp::panopainter {
|
||||||
|
|
||||||
|
void bind_legacy_main_toolbar(App& app)
|
||||||
|
{
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButton>("btn-anim"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app, button](Node*) {
|
||||||
|
if (app.canvas)
|
||||||
|
{
|
||||||
|
//app.canvas->m_canvas->export_anim();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButton>("btn-open"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app, button](Node*) {
|
||||||
|
const auto plan = pp::app::plan_main_toolbar_command(
|
||||||
|
pp::app::MainToolbarCommand::open_document);
|
||||||
|
if (plan)
|
||||||
|
execute_main_toolbar_plan(app, plan.value());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButton>("btn-save"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app, button](Node*) {
|
||||||
|
const auto plan = pp::app::plan_main_toolbar_command(
|
||||||
|
pp::app::MainToolbarCommand::save_document);
|
||||||
|
if (plan)
|
||||||
|
execute_main_toolbar_plan(app, plan.value());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButtonCustom>("btn-undo"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app, button](Node*) {
|
||||||
|
const auto history = pp::panopainter::legacy_history_snapshot();
|
||||||
|
const auto plan = pp::app::plan_main_toolbar_command(
|
||||||
|
pp::app::MainToolbarCommand::undo,
|
||||||
|
history.undo_count);
|
||||||
|
if (plan)
|
||||||
|
execute_main_toolbar_plan(app, plan.value());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButtonCustom>("btn-redo"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app, button](Node*) {
|
||||||
|
const auto history = pp::panopainter::legacy_history_snapshot();
|
||||||
|
const auto plan = pp::app::plan_main_toolbar_command(
|
||||||
|
pp::app::MainToolbarCommand::redo,
|
||||||
|
0,
|
||||||
|
history.redo_count);
|
||||||
|
if (plan)
|
||||||
|
execute_main_toolbar_plan(app, plan.value());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButtonCustom>("btn-clean-memory"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app](Node*) {
|
||||||
|
const auto history = pp::panopainter::legacy_history_snapshot();
|
||||||
|
const auto plan = pp::app::plan_main_toolbar_command(
|
||||||
|
pp::app::MainToolbarCommand::clear_history,
|
||||||
|
history.undo_count,
|
||||||
|
history.redo_count,
|
||||||
|
history.memory_bytes);
|
||||||
|
if (plan)
|
||||||
|
execute_main_toolbar_plan(app, plan.value());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButton>("btn-clear"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app](Node*) {
|
||||||
|
const auto plan = pp::app::plan_main_toolbar_command(
|
||||||
|
pp::app::MainToolbarCommand::clear_canvas,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
static_cast<bool>(app.canvas));
|
||||||
|
if (plan)
|
||||||
|
execute_main_toolbar_plan(app, plan.value());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButton>("btn-popup"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app](Node*) {
|
||||||
|
const auto plan = pp::app::plan_main_toolbar_command(
|
||||||
|
pp::app::MainToolbarCommand::show_message_box);
|
||||||
|
if (plan)
|
||||||
|
execute_main_toolbar_plan(app, plan.value());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (auto* button = app.layout[app.main_id]->find<NodeButtonCustom>("btn-settings"))
|
||||||
|
{
|
||||||
|
button->on_click = [&app](Node*) {
|
||||||
|
const auto plan = pp::app::plan_main_toolbar_command(
|
||||||
|
pp::app::MainToolbarCommand::show_settings);
|
||||||
|
if (plan)
|
||||||
|
execute_main_toolbar_plan(app, plan.value());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pp::panopainter
|
||||||
391
src/main.cpp
391
src/main.cpp
@@ -112,6 +112,239 @@ void drain_main_tasks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MainWindowStartupState
|
||||||
|
{
|
||||||
|
WNDCLASS window_class{};
|
||||||
|
PIXELFORMATDESCRIPTOR pixel_format{};
|
||||||
|
DWORD window_style = WS_OVERLAPPEDWINDOW;
|
||||||
|
RECT client_rect{ 0, 0, 0, 0 };
|
||||||
|
POINT client_pos{ CW_USEDEFAULT, CW_USEDEFAULT };
|
||||||
|
int show_command = SW_NORMAL;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlWindowContext
|
||||||
|
{
|
||||||
|
HDC device_context{};
|
||||||
|
HGLRC render_context{};
|
||||||
|
pp::renderer::gl::OpenGlRuntimeInfo runtime_info{};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MainStartupResult
|
||||||
|
{
|
||||||
|
Ok = 0,
|
||||||
|
GladLoadFailure = 1,
|
||||||
|
MissingCoreContextSupport = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
void ensure_runtime_data_directory()
|
||||||
|
{
|
||||||
|
FILE* fp_check = fopen("data\\layout.xml", "rb");
|
||||||
|
if (!fp_check)
|
||||||
|
{
|
||||||
|
LOG("data files not found");
|
||||||
|
static char path[MAX_PATH];
|
||||||
|
GetModuleFileNameA(NULL, path, MAX_PATH);
|
||||||
|
LOG("current dir %s", path);
|
||||||
|
PathRemoveFileSpecA(path);
|
||||||
|
SetCurrentDirectoryA(path);
|
||||||
|
LOG("change dir to %s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp_check);
|
||||||
|
LOG("data files ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindowStartupState initialize_main_window_startup_state()
|
||||||
|
{
|
||||||
|
auto& state = retained_state();
|
||||||
|
auto startup = MainWindowStartupState {};
|
||||||
|
|
||||||
|
state.hInst = GetModuleHandle(NULL);
|
||||||
|
state.className = L"EngineMain";
|
||||||
|
|
||||||
|
startup.window_class.hInstance = state.hInst;
|
||||||
|
startup.window_class.lpfnWndProc = (WNDPROC)WndProc;
|
||||||
|
startup.window_class.lpszClassName = state.className;
|
||||||
|
startup.window_class.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
||||||
|
startup.window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
|
||||||
|
RegisterClass(&startup.window_class);
|
||||||
|
|
||||||
|
auto monitor = MonitorFromWindow(0, MONITOR_DEFAULTTOPRIMARY);
|
||||||
|
auto x = unsigned{ 96 };
|
||||||
|
auto y = unsigned{ 96 };
|
||||||
|
if (GetDpiForMonitor_fn)
|
||||||
|
GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI, &x, &y);
|
||||||
|
App::I->display_density = (float)x / 96.f;
|
||||||
|
|
||||||
|
const auto window_preferences = pp::panopainter::read_legacy_window_preferences(SW_NORMAL);
|
||||||
|
if (window_preferences.has_ui_scale)
|
||||||
|
App::I->zoom = window_preferences.ui_scale;
|
||||||
|
else
|
||||||
|
App::I->zoom = (float)x / 96.f;
|
||||||
|
|
||||||
|
startup.show_command = window_preferences.show_command;
|
||||||
|
startup.client_rect = {
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
static_cast<LONG>(App::I->width * App::I->zoom),
|
||||||
|
static_cast<LONG>(App::I->height * App::I->zoom),
|
||||||
|
};
|
||||||
|
if (window_preferences.has_window_rect)
|
||||||
|
{
|
||||||
|
auto wnd_rect = window_preferences.window_rect;
|
||||||
|
App::I->width = wnd_rect.z - wnd_rect.x;
|
||||||
|
App::I->height = wnd_rect.w - wnd_rect.y;
|
||||||
|
startup.client_rect = { wnd_rect.x, wnd_rect.y, wnd_rect.z, wnd_rect.w };
|
||||||
|
startup.client_pos = { wnd_rect.x, wnd_rect.y };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AdjustWindowRect(&startup.client_rect, startup.window_style, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return startup;
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_main_window(const MainWindowStartupState& startup, const wchar_t* window_title)
|
||||||
|
{
|
||||||
|
auto& state = retained_state();
|
||||||
|
const int window_width = startup.client_rect.right - startup.client_rect.left;
|
||||||
|
const int window_height = startup.client_rect.bottom - startup.client_rect.top;
|
||||||
|
state.hWnd = CreateWindow(
|
||||||
|
startup.window_class.lpszClassName,
|
||||||
|
window_title,
|
||||||
|
startup.window_style,
|
||||||
|
startup.client_pos.x,
|
||||||
|
startup.client_pos.y,
|
||||||
|
window_width,
|
||||||
|
window_height,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
state.hInst,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format)
|
||||||
|
{
|
||||||
|
pixel_format.nSize = sizeof(pixel_format);
|
||||||
|
pixel_format.nVersion = 1;
|
||||||
|
pixel_format.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||||
|
pixel_format.iPixelType = PFD_TYPE_RGBA;
|
||||||
|
pixel_format.cColorBits = 32;
|
||||||
|
pixel_format.cDepthBits = 24;
|
||||||
|
pixel_format.iLayerType = PFD_MAIN_PLANE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_glad_entry_points(HDC device_context)
|
||||||
|
{
|
||||||
|
if (!gladLoadGL())
|
||||||
|
{
|
||||||
|
LOG("gladLoadGL() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!gladLoadWGL(device_context))
|
||||||
|
{
|
||||||
|
LOG("gladLoadWGL() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::renderer::gl::OpenGlRuntimeInfo log_runtime_info()
|
||||||
|
{
|
||||||
|
auto runtime_info = pp::renderer::gl::OpenGlRuntimeInfo {};
|
||||||
|
const auto runtime_info_result = pp::renderer::gl::query_opengl_runtime_info(
|
||||||
|
pp::legacy::gl_runtime::runtime_info_dispatch());
|
||||||
|
if (runtime_info_result.ok())
|
||||||
|
{
|
||||||
|
runtime_info = runtime_info_result.value();
|
||||||
|
LOG("GL version: %s", runtime_info.version);
|
||||||
|
LOG("GL vendor: %s", runtime_info.vendor);
|
||||||
|
LOG("GL renderer: %s", runtime_info.renderer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG("OpenGL runtime info query failed: %s", runtime_info_result.status().message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return runtime_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool upgrade_to_core_gl_context(const MainWindowStartupState& startup, OpenGlWindowContext& context)
|
||||||
|
{
|
||||||
|
if (!GLAD_WGL_ARB_create_context)
|
||||||
|
{
|
||||||
|
LOG("WGL_ARB_create_context not supported");
|
||||||
|
// If not supported, go fuck yourself we are not gonna support your shitty device
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto wgl_config = pp::renderer::gl::windows_wgl_core_context_3_3_config();
|
||||||
|
UINT num_format = 0;
|
||||||
|
|
||||||
|
wglMakeCurrent(NULL, NULL);
|
||||||
|
wglDeleteContext(context.render_context);
|
||||||
|
DestroyWindow(retained_state().hWnd);
|
||||||
|
|
||||||
|
create_main_window(startup, retained_state().window_title);
|
||||||
|
|
||||||
|
context.device_context = GetDC(retained_state().hWnd);
|
||||||
|
int pixel_format = 0;
|
||||||
|
wglChoosePixelFormatARB(
|
||||||
|
context.device_context,
|
||||||
|
wgl_config.pixel_format_attributes.data(),
|
||||||
|
nullptr,
|
||||||
|
1,
|
||||||
|
&pixel_format,
|
||||||
|
&num_format);
|
||||||
|
SetPixelFormat(context.device_context, pixel_format, &startup.pixel_format);
|
||||||
|
context.render_context = wglCreateContextAttribsARB(
|
||||||
|
context.device_context,
|
||||||
|
NULL,
|
||||||
|
wgl_config.context_attributes.data());
|
||||||
|
wglMakeCurrent(context.device_context, context.render_context);
|
||||||
|
pp::platform::windows::set_async_render_context(context.device_context, context.render_context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainStartupResult initialize_main_window_and_gl(MainWindowStartupState& startup, OpenGlWindowContext& context)
|
||||||
|
{
|
||||||
|
create_main_window(startup, L"PanoPainter");
|
||||||
|
initialize_pixel_format_descriptor(startup.pixel_format);
|
||||||
|
|
||||||
|
context.device_context = GetDC(retained_state().hWnd);
|
||||||
|
const int pixel_format = ChoosePixelFormat(context.device_context, &startup.pixel_format);
|
||||||
|
SetPixelFormat(context.device_context, pixel_format, &startup.pixel_format);
|
||||||
|
context.render_context = wglCreateContext(context.device_context);
|
||||||
|
wglMakeCurrent(context.device_context, context.render_context);
|
||||||
|
pp::platform::windows::set_async_render_context(context.device_context, context.render_context);
|
||||||
|
|
||||||
|
if (!load_glad_entry_points(context.device_context))
|
||||||
|
return MainStartupResult::GladLoadFailure;
|
||||||
|
|
||||||
|
context.runtime_info = log_runtime_info();
|
||||||
|
|
||||||
|
#ifdef USE_RENDERDOC
|
||||||
|
if (!win32_renderdoc_init())
|
||||||
|
LOG("Renderdoc not started");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const auto renderer_name = std::string(context.runtime_info.renderer != nullptr ? context.runtime_info.renderer : "");
|
||||||
|
swprintf_s(
|
||||||
|
retained_state().window_title,
|
||||||
|
L"PanoPainter %s (%s)",
|
||||||
|
g_version_number_w,
|
||||||
|
str2wstr(renderer_name).c_str());
|
||||||
|
|
||||||
|
if (!upgrade_to_core_gl_context(startup, context))
|
||||||
|
return MainStartupResult::MissingCoreContextSupport;
|
||||||
|
|
||||||
|
return MainStartupResult::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND pp_windows_main_window_handle()
|
HWND pp_windows_main_window_handle()
|
||||||
@@ -454,8 +687,6 @@ void win32_save_window_state()
|
|||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
auto& state = retained_state();
|
auto& state = retained_state();
|
||||||
WNDCLASS wc;
|
|
||||||
PIXELFORMATDESCRIPTOR pfd;
|
|
||||||
|
|
||||||
App::I = new App();
|
App::I = new App();
|
||||||
App::I->set_platform_services(&pp::platform::windows::platform_services());
|
App::I->set_platform_services(&pp::platform::windows::platform_services());
|
||||||
@@ -467,23 +698,7 @@ int main(int argc, char** argv)
|
|||||||
if(SetProcessDpiAwareness_fn)
|
if(SetProcessDpiAwareness_fn)
|
||||||
SetProcessDpiAwareness_fn(PROCESS_PER_MONITOR_DPI_AWARE);
|
SetProcessDpiAwareness_fn(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||||
|
|
||||||
|
ensure_runtime_data_directory();
|
||||||
FILE* fp_check = fopen("data\\layout.xml", "rb");
|
|
||||||
if (!fp_check)
|
|
||||||
{
|
|
||||||
LOG("data files not found");
|
|
||||||
static char path[MAX_PATH];
|
|
||||||
GetModuleFileNameA(NULL, path, MAX_PATH);
|
|
||||||
LOG("current dir %s", path);
|
|
||||||
PathRemoveFileSpecA(path);
|
|
||||||
SetCurrentDirectoryA(path);
|
|
||||||
LOG("change dir to %s", path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fclose(fp_check);
|
|
||||||
LOG("data files ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
pp::platform::windows::SplashScreen splash(GetModuleHandle(NULL));
|
pp::platform::windows::SplashScreen splash(GetModuleHandle(NULL));
|
||||||
|
|
||||||
@@ -496,135 +711,17 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
App::I->create();
|
App::I->create();
|
||||||
|
|
||||||
// Inizialize data structures to zero
|
|
||||||
memset(&wc, 0, sizeof(wc));
|
|
||||||
memset(&state.keys, 0, sizeof(state.keys));
|
memset(&state.keys, 0, sizeof(state.keys));
|
||||||
memset(&pfd, 0, sizeof(pfd));
|
auto startup = initialize_main_window_startup_state();
|
||||||
|
auto context = OpenGlWindowContext {};
|
||||||
// Create the main window
|
switch (initialize_main_window_and_gl(startup, context))
|
||||||
|
|
||||||
state.hInst = GetModuleHandle(NULL);
|
|
||||||
state.className = L"EngineMain";
|
|
||||||
|
|
||||||
wc.hInstance = state.hInst;
|
|
||||||
wc.lpfnWndProc = (WNDPROC)WndProc;
|
|
||||||
wc.lpszClassName = state.className;
|
|
||||||
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
|
||||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
||||||
|
|
||||||
RegisterClass(&wc);
|
|
||||||
|
|
||||||
auto monitor = MonitorFromWindow(0, MONITOR_DEFAULTTOPRIMARY);
|
|
||||||
auto x = unsigned{ 96 };
|
|
||||||
auto y = unsigned{ 96 };
|
|
||||||
if (GetDpiForMonitor_fn)
|
|
||||||
GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI, &x, &y);
|
|
||||||
App::I->display_density = (float)x / 96.f;
|
|
||||||
|
|
||||||
const auto window_preferences = pp::panopainter::read_legacy_window_preferences(SW_NORMAL);
|
|
||||||
if (window_preferences.has_ui_scale)
|
|
||||||
App::I->zoom = window_preferences.ui_scale;
|
|
||||||
else
|
|
||||||
App::I->zoom = (float)x / 96.f;
|
|
||||||
|
|
||||||
int show_cmd = window_preferences.show_command;
|
|
||||||
DWORD wnd_style = WS_OVERLAPPEDWINDOW;
|
|
||||||
//if (show_cmd == SW_MAXIMIZE)
|
|
||||||
// wnd_style != WS_MAXIMIZE;
|
|
||||||
|
|
||||||
RECT clientRect = { 0, 0, (int)App::I->width * App::I->zoom, (int)App::I->height * App::I->zoom };
|
|
||||||
POINT clientPos = { CW_USEDEFAULT, CW_USEDEFAULT };
|
|
||||||
if (window_preferences.has_window_rect)
|
|
||||||
{
|
{
|
||||||
auto wnd_rect = window_preferences.window_rect;
|
case MainStartupResult::Ok:
|
||||||
App::I->width = wnd_rect.z - wnd_rect.x;
|
break;
|
||||||
App::I->height = wnd_rect.w - wnd_rect.y;
|
case MainStartupResult::GladLoadFailure:
|
||||||
clientRect = { wnd_rect.x, wnd_rect.y, wnd_rect.z, wnd_rect.w };
|
|
||||||
clientPos = { wnd_rect.x, wnd_rect.y };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AdjustWindowRect(&clientRect, wnd_style, false);
|
|
||||||
}
|
|
||||||
state.hWnd = CreateWindow(wc.lpszClassName, L"PanoPainter", wnd_style, clientPos.x, clientPos.y,
|
|
||||||
(float)(clientRect.right - clientRect.left),
|
|
||||||
(float)(clientRect.bottom - clientRect.top), 0, 0, state.hInst, 0);
|
|
||||||
|
|
||||||
// Setup GL Rendering Context
|
|
||||||
pfd.nSize = sizeof(pfd);
|
|
||||||
pfd.nVersion = 1;
|
|
||||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
|
||||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
|
||||||
pfd.cColorBits = 32;
|
|
||||||
pfd.cDepthBits = 24;
|
|
||||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
|
||||||
|
|
||||||
HDC hDC = GetDC(state.hWnd);
|
|
||||||
int pxfmt = ChoosePixelFormat(hDC, &pfd);
|
|
||||||
SetPixelFormat(hDC, pxfmt, &pfd);
|
|
||||||
HGLRC hRC = wglCreateContext(hDC); // Create OpenGL 2.1 or less
|
|
||||||
wglMakeCurrent(hDC, hRC);
|
|
||||||
pp::platform::windows::set_async_render_context(hDC, hRC);
|
|
||||||
|
|
||||||
// Initialize extensions
|
|
||||||
if (!gladLoadGL())
|
|
||||||
{
|
|
||||||
LOG("gladLoadGL() failed");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
case MainStartupResult::MissingCoreContextSupport:
|
||||||
if (!gladLoadWGL(hDC))
|
return -1;
|
||||||
{
|
|
||||||
LOG("gladLoadWGL() failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto runtime_info = pp::renderer::gl::OpenGlRuntimeInfo {};
|
|
||||||
const auto runtime_info_result = pp::renderer::gl::query_opengl_runtime_info(
|
|
||||||
pp::legacy::gl_runtime::runtime_info_dispatch());
|
|
||||||
if (runtime_info_result.ok()) {
|
|
||||||
runtime_info = runtime_info_result.value();
|
|
||||||
LOG("GL version: %s", runtime_info.version);
|
|
||||||
LOG("GL vendor: %s", runtime_info.vendor);
|
|
||||||
LOG("GL renderer: %s", runtime_info.renderer);
|
|
||||||
} else {
|
|
||||||
LOG("OpenGL runtime info query failed: %s", runtime_info_result.status().message);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_RENDERDOC
|
|
||||||
if (!win32_renderdoc_init())
|
|
||||||
LOG("Renderdoc not started");
|
|
||||||
#endif // USE_RENDERDOC
|
|
||||||
|
|
||||||
const auto renderer_name = std::string(runtime_info.renderer != nullptr ? runtime_info.renderer : "");
|
|
||||||
swprintf_s(state.window_title, L"PanoPainter %s (%s)", g_version_number_w,
|
|
||||||
str2wstr(renderer_name).c_str());
|
|
||||||
|
|
||||||
// If supported create a 3.3 context
|
|
||||||
if (GLAD_WGL_ARB_create_context)
|
|
||||||
{
|
|
||||||
const auto wgl_config = pp::renderer::gl::windows_wgl_core_context_3_3_config();
|
|
||||||
UINT numFormat;
|
|
||||||
|
|
||||||
wglMakeCurrent(NULL, NULL);
|
|
||||||
wglDeleteContext(hRC);
|
|
||||||
DestroyWindow(state.hWnd);
|
|
||||||
|
|
||||||
state.hWnd = CreateWindow(wc.lpszClassName, state.window_title, wnd_style, clientPos.x, clientPos.y,
|
|
||||||
(float)(clientRect.right - clientRect.left),
|
|
||||||
(float)(clientRect.bottom - clientRect.top), 0, 0, state.hInst, 0);
|
|
||||||
|
|
||||||
hDC = GetDC(state.hWnd);
|
|
||||||
wglChoosePixelFormatARB(hDC, wgl_config.pixel_format_attributes.data(), nullptr, 1, &pxfmt, &numFormat);
|
|
||||||
SetPixelFormat(hDC, pxfmt, &pfd);
|
|
||||||
hRC = wglCreateContextAttribsARB(hDC, NULL, wgl_config.context_attributes.data());
|
|
||||||
wglMakeCurrent(hDC, hRC);
|
|
||||||
pp::platform::windows::set_async_render_context(hDC, hRC);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG("WGL_ARB_create_context not supported");
|
|
||||||
// If not supported, go fuck yourself we are not gonna support your shitty device
|
|
||||||
return -1; // A negative number because you are a negative one
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//wglSwapIntervalEXT(1);
|
//wglSwapIntervalEXT(1);
|
||||||
@@ -682,7 +779,7 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
WINDOWPLACEMENT wp;
|
WINDOWPLACEMENT wp;
|
||||||
GetWindowPlacement(state.hWnd, &wp);
|
GetWindowPlacement(state.hWnd, &wp);
|
||||||
wp.showCmd = show_cmd;
|
wp.showCmd = startup.show_command;
|
||||||
SetWindowPlacement(state.hWnd, &wp);
|
SetWindowPlacement(state.hWnd, &wp);
|
||||||
//GetClientRect(hWnd, &clientRect);
|
//GetClientRect(hWnd, &clientRect);
|
||||||
//App::I->width = clientRect.right - clientRect.left;
|
//App::I->width = clientRect.right - clientRect.left;
|
||||||
@@ -721,7 +818,7 @@ int main(int argc, char** argv)
|
|||||||
// Clean up
|
// Clean up
|
||||||
WacomTablet::I.terminate();
|
WacomTablet::I.terminate();
|
||||||
|
|
||||||
UnregisterClass(state.className, state.hInst);
|
UnregisterClass(startup.window_class.lpszClassName, state.hInst);
|
||||||
LogRemote::I.stop();
|
LogRemote::I.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
167
src/node.cpp
167
src/node.cpp
@@ -39,6 +39,86 @@
|
|||||||
#include "node_panel_animation.h"
|
#include "node_panel_animation.h"
|
||||||
#include "node_metadata.h"
|
#include "node_metadata.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using NodeChildren = std::vector<std::shared_ptr<Node>>;
|
||||||
|
using NodeChildIterator = NodeChildren::iterator;
|
||||||
|
|
||||||
|
NodeChildIterator find_child_iterator(Node& parent, Node* child)
|
||||||
|
{
|
||||||
|
return std::find_if(parent.m_children.begin(), parent.m_children.end(),
|
||||||
|
[child](const std::shared_ptr<Node>& candidate) { return candidate.get() == child; });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename AttachChildrenFn>
|
||||||
|
void attach_child(Node& parent, Node* child, int yoga_index, AttachChildrenFn&& attach_children)
|
||||||
|
{
|
||||||
|
if (child->m_parent)
|
||||||
|
child->m_parent->remove_child(child);
|
||||||
|
|
||||||
|
attach_children(child);
|
||||||
|
child->m_parent = &parent;
|
||||||
|
child->set_manager(parent.m_manager);
|
||||||
|
child->m_destroyed = false;
|
||||||
|
YGNodeInsertChild(parent.y_node, child->y_node, yoga_index);
|
||||||
|
child->added(&parent);
|
||||||
|
parent.on_child_added(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename AttachChildrenFn>
|
||||||
|
void attach_child(Node& parent, const std::shared_ptr<Node>& child, int yoga_index, AttachChildrenFn&& attach_children)
|
||||||
|
{
|
||||||
|
if (child->m_parent)
|
||||||
|
child->m_parent->remove_child(child.get());
|
||||||
|
|
||||||
|
attach_children(child);
|
||||||
|
child->m_parent = &parent;
|
||||||
|
child->set_manager(parent.m_manager);
|
||||||
|
child->m_destroyed = false;
|
||||||
|
YGNodeInsertChild(parent.y_node, child->y_node, yoga_index);
|
||||||
|
child->added(&parent);
|
||||||
|
parent.on_child_added(child.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void detach_child(Node& parent, NodeChildIterator child_it)
|
||||||
|
{
|
||||||
|
Node* child = child_it->get();
|
||||||
|
child->removed(&parent);
|
||||||
|
child->m_parent = nullptr;
|
||||||
|
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||||
|
parent.on_child_removed(child);
|
||||||
|
parent.m_children.erase(child_it);
|
||||||
|
if (parent.child_mouse_focus.get() == child)
|
||||||
|
parent.child_mouse_focus = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void detach_all_children(Node& parent)
|
||||||
|
{
|
||||||
|
for (auto& child : parent.m_children)
|
||||||
|
{
|
||||||
|
child->removed(&parent);
|
||||||
|
child->m_parent = nullptr;
|
||||||
|
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||||
|
parent.on_child_removed(child.get());
|
||||||
|
}
|
||||||
|
parent.m_children.clear();
|
||||||
|
parent.child_mouse_focus = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reorder_child(Node& parent, Node* child, int index)
|
||||||
|
{
|
||||||
|
int count = YGNodeGetChildCount(parent.y_node);
|
||||||
|
index = glm::clamp<int>(index, 0, count - 1);
|
||||||
|
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||||
|
YGNodeInsertChild(parent.y_node, child->y_node, index);
|
||||||
|
|
||||||
|
auto child_it = find_child_iterator(parent, child);
|
||||||
|
auto moved_child = *child_it;
|
||||||
|
parent.m_children.erase(child_it);
|
||||||
|
parent.m_children.insert(parent.m_children.begin() + index, moved_child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Node::app_redraw()
|
void Node::app_redraw()
|
||||||
{
|
{
|
||||||
App::I->redraw = true;
|
App::I->redraw = true;
|
||||||
@@ -404,15 +484,11 @@ void Node::add_child(Node* n)
|
|||||||
{
|
{
|
||||||
App::I->ui_task([&]
|
App::I->ui_task([&]
|
||||||
{
|
{
|
||||||
if (n->m_parent)
|
attach_child(*this, n, YGNodeGetChildCount(y_node),
|
||||||
n->m_parent->remove_child(n);
|
[this](Node* child)
|
||||||
m_children.emplace_back(n);
|
{
|
||||||
n->m_parent = this;
|
m_children.emplace_back(child);
|
||||||
n->set_manager(m_manager);
|
});
|
||||||
n->m_destroyed = false;
|
|
||||||
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
|
|
||||||
n->added(this);
|
|
||||||
on_child_added(n);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,15 +496,12 @@ void Node::add_child(Node* n, int index)
|
|||||||
{
|
{
|
||||||
App::I->ui_task([&]
|
App::I->ui_task([&]
|
||||||
{
|
{
|
||||||
if (n->m_parent)
|
attach_child(*this, n, index,
|
||||||
n->m_parent->remove_child(n);
|
[this](Node* child)
|
||||||
m_children.emplace_back(n);
|
{
|
||||||
n->m_parent = this;
|
// Preserve the current backing-vector behavior for raw-pointer inserts.
|
||||||
n->set_manager(m_manager);
|
m_children.emplace_back(child);
|
||||||
n->m_destroyed = false;
|
});
|
||||||
YGNodeInsertChild(y_node, n->y_node, index);
|
|
||||||
n->added(this);
|
|
||||||
on_child_added(n);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,15 +509,11 @@ void Node::add_child(std::shared_ptr<Node> n)
|
|||||||
{
|
{
|
||||||
App::I->ui_task([this,n]
|
App::I->ui_task([this,n]
|
||||||
{
|
{
|
||||||
if (n->m_parent)
|
attach_child(*this, n, YGNodeGetChildCount(y_node),
|
||||||
n->m_parent->remove_child(n.get());
|
[this](const std::shared_ptr<Node>& child)
|
||||||
m_children.push_back(n);
|
{
|
||||||
n->m_parent = this;
|
m_children.push_back(child);
|
||||||
n->set_manager(m_manager);
|
});
|
||||||
n->m_destroyed = false;
|
|
||||||
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
|
|
||||||
n->added(this);
|
|
||||||
on_child_added(n.get());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,15 +521,11 @@ void Node::add_child(std::shared_ptr<Node> n, int index)
|
|||||||
{
|
{
|
||||||
App::I->ui_task([&]
|
App::I->ui_task([&]
|
||||||
{
|
{
|
||||||
if (n->m_parent)
|
attach_child(*this, n, index,
|
||||||
n->m_parent->remove_child(n.get());
|
[this, index](const std::shared_ptr<Node>& child)
|
||||||
m_children.insert(m_children.begin() + index, n);
|
{
|
||||||
n->m_parent = this;
|
m_children.insert(m_children.begin() + index, child);
|
||||||
n->set_manager(m_manager);
|
});
|
||||||
n->m_destroyed = false;
|
|
||||||
YGNodeInsertChild(y_node, n->y_node, index);
|
|
||||||
n->added(this);
|
|
||||||
on_child_added(n.get());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,18 +537,12 @@ void Node::remove_from_parent()
|
|||||||
|
|
||||||
void Node::remove_child(Node* n)
|
void Node::remove_child(Node* n)
|
||||||
{
|
{
|
||||||
auto i = std::find_if(m_children.begin(), m_children.end(), [=](auto& ptr) { return ptr.get() == n; });
|
auto i = find_child_iterator(*this, n);
|
||||||
if (i != m_children.end())
|
if (i != m_children.end())
|
||||||
{
|
{
|
||||||
App::I->ui_task([&]
|
App::I->ui_task([&]
|
||||||
{
|
{
|
||||||
n->removed(this);
|
detach_child(*this, i);
|
||||||
n->m_parent = nullptr;
|
|
||||||
YGNodeRemoveChild(y_node, n->y_node);
|
|
||||||
on_child_removed(n);
|
|
||||||
m_children.erase(i);
|
|
||||||
if (child_mouse_focus.get() == n)
|
|
||||||
child_mouse_focus = nullptr;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,15 +551,7 @@ void Node::remove_all_children()
|
|||||||
{
|
{
|
||||||
App::I->ui_task([&]
|
App::I->ui_task([&]
|
||||||
{
|
{
|
||||||
for (auto& n : m_children)
|
detach_all_children(*this);
|
||||||
{
|
|
||||||
n->removed(this);
|
|
||||||
n->m_parent = nullptr;
|
|
||||||
YGNodeRemoveChild(y_node, n->y_node);
|
|
||||||
on_child_removed(n.get());
|
|
||||||
}
|
|
||||||
m_children.clear();
|
|
||||||
child_mouse_focus = nullptr;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,15 +559,7 @@ void Node::move_child(Node* n, int index)
|
|||||||
{
|
{
|
||||||
App::I->ui_task([&]
|
App::I->ui_task([&]
|
||||||
{
|
{
|
||||||
int count = YGNodeGetChildCount(y_node);
|
reorder_child(*this, n, index);
|
||||||
index = glm::clamp<int>(index, 0, count - 1);
|
|
||||||
YGNodeRemoveChild(y_node, n->y_node);
|
|
||||||
YGNodeInsertChild(y_node, n->y_node, index);
|
|
||||||
auto it = std::find_if(m_children.begin(), m_children.end(),
|
|
||||||
[n](const std::shared_ptr<Node>& o) { return o.get() == n; });
|
|
||||||
auto tmp = *it; // copy the ptr before removing it
|
|
||||||
m_children.erase(it);
|
|
||||||
m_children.insert(m_children.begin() + index, tmp);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user