Extract sidebar, lifecycle shell, and canvas unmerged draw
This commit is contained in:
@@ -97,6 +97,7 @@ set(PP_PANOPAINTER_APP_SOURCES
|
||||
src/app_dialogs_info_openers.cpp
|
||||
src/app_events.cpp
|
||||
src/app_layout.cpp
|
||||
src/app_layout_sidebar.cpp
|
||||
src/app_layout_about_layer_menu.cpp
|
||||
src/app_layout_file_menu.cpp
|
||||
src/app_layout_tools_menu.cpp
|
||||
@@ -166,6 +167,8 @@ set(PP_PANOPAINTER_UI_SOURCES
|
||||
set(PP_WINDOWS_PLATFORM_SOURCES
|
||||
src/main.cpp
|
||||
src/platform_windows/windows_bootstrap_helpers.cpp
|
||||
src/platform_windows/windows_lifecycle_shell.cpp
|
||||
src/platform_windows/windows_lifecycle_shell.h
|
||||
src/platform_windows/windows_platform_services.cpp
|
||||
src/platform_windows/windows_platform_services.h
|
||||
src/platform_windows/windows_splash.cpp
|
||||
|
||||
@@ -80,13 +80,13 @@ What is still carrying too much live ownership:
|
||||
Current hotspot files:
|
||||
|
||||
- `src/canvas.cpp`: 2645 lines
|
||||
- `src/app_layout.cpp`: 1249 lines
|
||||
- `src/app_layout.cpp`: 785 lines
|
||||
- `src/canvas_modes.cpp`: 1798 lines
|
||||
- `src/node.cpp`: 1551 lines
|
||||
- `src/main.cpp`: 909 lines
|
||||
- `src/main.cpp`: 882 lines
|
||||
- `src/node_panel_brush.cpp`: 1197 lines
|
||||
- `src/node_stroke_preview.cpp`: 933 lines
|
||||
- `src/node_canvas.cpp`: 905 lines
|
||||
- `src/node_canvas.cpp`: 910 lines
|
||||
- `src/app.cpp`: 502 lines
|
||||
- `src/app_dialogs.cpp`: 142 lines
|
||||
|
||||
@@ -138,7 +138,9 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
live in `src/app_layout_file_menu.cpp` and `App::init_menu_file()` is now a
|
||||
thin call-through, while about-menu and layer-menu wiring now also live in
|
||||
`src/app_layout_about_layer_menu.cpp` and `App::init_menu_about()` plus
|
||||
`App::init_menu_layer()` are now thin call-throughs, while the informational
|
||||
`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
|
||||
`App::init_sidebar()` is now a thin call-through, while the 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
|
||||
@@ -177,7 +179,10 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
`src/main.cpp`, while RenderDoc startup/frame capture, SHCore DPI bootstrap,
|
||||
Win32 error-string conversion, and the GL debug pre/post callbacks now also
|
||||
live in `src/platform_windows/windows_bootstrap_helpers.cpp` instead of
|
||||
`src/main.cpp`,
|
||||
`src/main.cpp`, while Win32 lifecycle running-state, close/shutdown
|
||||
sequencing, FPS title update/wakeup posting, stylus frame update, window
|
||||
preference save, and VR lifecycle wrappers now also live in
|
||||
`src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp`,
|
||||
while `App::rec_loop()` now delegates worker-iteration orchestration into
|
||||
the retained recording bridge, `App::update_rec_frames()` now delegates
|
||||
recording label refresh through that same retained recording path, and the
|
||||
|
||||
@@ -210,6 +210,11 @@ Current slice:
|
||||
`execute_node_canvas_draw_merge_tail(...)`, which trims another live tail
|
||||
block from `NodeCanvas::draw()` even though the broader outer draw shell is
|
||||
still inline.
|
||||
- `NodeCanvas` non-`draw_merged` cache/background/layer-traversal/cache-
|
||||
composite shell now also routes through
|
||||
`execute_legacy_canvas_draw_unmerged_shell(...)`, which removes another
|
||||
coherent orchestration block from `NodeCanvas::draw()` even though the
|
||||
broader node draw loop still lives in `src/node_canvas.cpp`.
|
||||
|
||||
Write scope:
|
||||
- `src/node_stroke_preview.cpp`
|
||||
@@ -304,6 +309,10 @@ Current slice:
|
||||
`src/app_layout_about_layer_menu.cpp`, and `App::init_menu_about()` plus
|
||||
`App::init_menu_layer()` are now thin call-throughs, but edit/sidebar and
|
||||
broader layout composition are still inline in `src/app_layout.cpp`.
|
||||
- Sidebar panel binding plus popup wiring now also live in
|
||||
`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
|
||||
inline in `src/app_layout.cpp`.
|
||||
|
||||
Write scope:
|
||||
- `src/app_layout.cpp`
|
||||
@@ -460,6 +469,10 @@ Current slice:
|
||||
conversion, `UnadjustWindowRectEx`, and GL debug pre/post callbacks now also
|
||||
live in `src/platform_windows/windows_bootstrap_helpers.cpp` instead of
|
||||
`src/main.cpp`
|
||||
- Win32 lifecycle running-state, close/shutdown handling, FPS title update and
|
||||
wakeup posting, stylus frame update, window preference save, and VR
|
||||
lifecycle wrappers now also live in
|
||||
`src/platform_windows/windows_lifecycle_shell.cpp` instead of `src/main.cpp`
|
||||
- prepared-file background work now runs through an `AppRuntime`-owned worker
|
||||
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
|
||||
|
||||
@@ -74,27 +74,6 @@ std::shared_ptr<NodePopupMenu> add_menu_popup(
|
||||
return popup.value();
|
||||
}
|
||||
|
||||
void close_legacy_overlay_handle_ignoring_status(
|
||||
Node& anchor,
|
||||
pp::ui::NodeHandle overlay) noexcept
|
||||
{
|
||||
(void)pp::panopainter::close_legacy_overlay_node(anchor, overlay);
|
||||
}
|
||||
|
||||
template <typename PopupOverlay, typename TickOverlay>
|
||||
void close_legacy_overlay_handles_if_open(
|
||||
Node& anchor,
|
||||
const PopupOverlay& popup_overlay,
|
||||
const TickOverlay& tick_overlay) noexcept
|
||||
{
|
||||
if (popup_overlay) {
|
||||
close_legacy_overlay_handle_ignoring_status(anchor, popup_overlay.value());
|
||||
}
|
||||
if (tick_overlay) {
|
||||
close_legacy_overlay_handle_ignoring_status(anchor, tick_overlay.value());
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool should_open_tools_panel(const pp::app::ToolsPanelPlan& plan) noexcept
|
||||
{
|
||||
return plan.action == pp::app::ToolsPanelAction::open_floating_panel;
|
||||
@@ -135,16 +114,6 @@ void execute_document_layer_merge_plan(App& app, const pp::app::DocumentLayerMer
|
||||
LOG("Layer merge failed: %s", status.message);
|
||||
}
|
||||
|
||||
void execute_document_layer_operation_plan(
|
||||
App& app,
|
||||
const pp::app::DocumentLayerOperationPlan& plan,
|
||||
const std::shared_ptr<class Layer>& pending_layer = nullptr)
|
||||
{
|
||||
const auto status = pp::panopainter::execute_legacy_document_layer_operation_plan(app, plan, pending_layer);
|
||||
if (!status.ok())
|
||||
LOG("Layer operation failed: %s", status.message);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void App::title_update()
|
||||
@@ -263,381 +232,6 @@ void App::init_toolbar_main()
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> std::shared_ptr<T> create_panel(LayoutManager& manager)
|
||||
{
|
||||
std::shared_ptr<T> ret;
|
||||
ret = std::make_shared<T>();
|
||||
ret->set_manager(&manager);
|
||||
ret->init();
|
||||
ret->create();
|
||||
ret->loaded();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void App::init_sidebar()
|
||||
{
|
||||
sidebar = layout[main_id]->find<NodeBorder>("sidebar");
|
||||
canvas = layout[main_id]->find<NodeCanvas>("paint-canvas");
|
||||
quick = layout[main_id]->find<NodePanelQuick>("panel-quick");
|
||||
floatings_container = layout[main_id]->find<Node>("floatings");
|
||||
|
||||
//brushes = layout[main_id]->find<NodePanelBrush>("panel-brush");
|
||||
//layers = layout[main_id]->find<NodePanelLayer>("panel-layer");
|
||||
//color = layout[main_id]->find<NodePanelColor>("panel-color");
|
||||
//stroke = layout[main_id]->find<NodePanelStroke>("panel-stroke");
|
||||
|
||||
//brushes = find_or_create_panel<NodePanelBrush>(panels);
|
||||
layers = create_panel<NodePanelLayer>(layout);
|
||||
color = create_panel<NodePanelColor>(layout);
|
||||
stroke = create_panel<NodePanelStroke>(layout);
|
||||
grid = create_panel<NodePanelGrid>(layout);
|
||||
presets = create_panel<NodePanelBrushPreset>(layout);
|
||||
animation = create_panel<NodePanelAnimation>(layout);
|
||||
//presets = find_or_create_panel<NodePanelBrushPreset>(panels);
|
||||
|
||||
canvas->m_canvas->on_mode_changed = [this](kCanvasMode prev, kCanvasMode mode) {
|
||||
quick_mode_state[prev] = quick->get_state();
|
||||
if (quick_mode_state.find(mode) != quick_mode_state.end())
|
||||
quick->set_state(quick_mode_state[mode], true);
|
||||
else
|
||||
quick->reset_state(true);
|
||||
brush_update(true, true);
|
||||
};
|
||||
color->on_color_changed = [this](Node* target, glm::vec4 color) {
|
||||
apply_brush_color_plan(*this, color, true, false);
|
||||
};
|
||||
|
||||
stroke->on_brush_changed = [this](Node* target, const std::string& path, const std::string& thumb) {
|
||||
apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::tip, path, thumb);
|
||||
};
|
||||
stroke->on_pattern_changed = [this](Node*target, const std::string& path, const std::string& thumb) {
|
||||
apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::pattern, path, thumb);
|
||||
};
|
||||
stroke->on_dual_changed = [this](Node*target, const std::string& path, const std::string& thumb) {
|
||||
apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::dual, path, thumb);
|
||||
};
|
||||
stroke->on_stroke_change = [this](Node*) {
|
||||
const auto status = pp::panopainter::execute_legacy_brush_stroke_changed_plan(*this);
|
||||
if (!status.ok())
|
||||
LOG("Brush stroke settings action failed: %s", status.message);
|
||||
};
|
||||
|
||||
quick->on_color_change = [this](Node*, glm::vec3 c) {
|
||||
apply_brush_color_plan(*this, glm::vec4(c, 1.f), false, true);
|
||||
};
|
||||
quick->on_flow_change = [this](Node*, float value) {
|
||||
stroke->set_flow(value, true, true);
|
||||
};
|
||||
quick->on_size_change = [this](Node*, float value) {
|
||||
stroke->set_size(value, true, true);
|
||||
};
|
||||
quick->on_brush_change = [this](Node*, std::shared_ptr<Brush> b) {
|
||||
apply_brush_preset_plan(*this, b);
|
||||
};
|
||||
|
||||
layers->on_layer_add = [this](Node*, std::shared_ptr<class Layer> layer, int index) {
|
||||
const auto plan = pp::app::plan_document_layer_add(
|
||||
static_cast<int>(Canvas::I->m_layers.size()),
|
||||
index,
|
||||
layers->m_layers.back()->m_label_text);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value(), layer);
|
||||
};
|
||||
|
||||
layers->on_layer_duplicate = [this](Node*, int source_index) {
|
||||
const auto plan = pp::app::plan_document_layer_duplicate(
|
||||
static_cast<int>(Canvas::I->m_layers.size()),
|
||||
source_index);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_change = [this](Node*, int, int new_idx) {
|
||||
const auto plan = pp::app::plan_document_layer_select(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
new_idx);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_order = [this](Node*, int old_idx, int new_idx) {
|
||||
const auto plan = pp::app::plan_document_layer_reorder(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
old_idx,
|
||||
new_idx);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_delete = [this](Node*, int idx) {
|
||||
const auto plan = pp::app::plan_document_layer_remove(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_opacity_changed = [this](Node*, int idx, float value) {
|
||||
const auto plan = pp::app::plan_document_layer_opacity(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
value);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) {
|
||||
const auto plan = pp::app::plan_document_layer_visibility(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
visible);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) {
|
||||
const auto plan = pp::app::plan_document_layer_alpha_lock(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
locked);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) {
|
||||
const auto plan = pp::app::plan_document_layer_blend_mode(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
mode);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) {
|
||||
const auto plan = pp::app::plan_document_layer_highlight(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
highlight);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-stroke"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
auto* popup_root = layout[main_id];
|
||||
if (!popup_root) {
|
||||
return;
|
||||
}
|
||||
auto screen = popup_root->m_size;
|
||||
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
|
||||
if (stroke->m_parent)
|
||||
{
|
||||
if (auto fp = dynamic_cast<NodePanelFloating*>(stroke->m_parent->m_parent))
|
||||
{
|
||||
pp::panopainter::detach_legacy_node_from_parent(*stroke);
|
||||
pp::panopainter::close_legacy_dialog_node(*fp);
|
||||
}
|
||||
}
|
||||
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, stroke);
|
||||
if (!popup_overlay) {
|
||||
return;
|
||||
}
|
||||
stroke->SetSize(350, glm::max(100.f, screen.y - pos.y - 50.f));
|
||||
stroke->find("title")->SetVisibility(true);
|
||||
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*popup_root);
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(32, 16);
|
||||
tick->SetPosition(pos.x - 16, pos.y);
|
||||
tick->set_image("data/ui/popup-tick-up.png");
|
||||
auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick);
|
||||
if (!popup_overlay || !tick_overlay)
|
||||
{
|
||||
close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay);
|
||||
return;
|
||||
}
|
||||
const auto popup_handle = popup_overlay.value();
|
||||
const auto tick_handle = tick_overlay.value();
|
||||
popup_root->update();
|
||||
|
||||
stroke->SetPosition(pos.x - stroke->m_size.x / 2.f, pos.y + 16);
|
||||
stroke->SetPositioning(YGPositionTypeAbsolute);
|
||||
pp::panopainter::activate_legacy_popup_overlay(*stroke);
|
||||
auto scroll = stroke->find<NodeScroll>("scroller");
|
||||
//scroll->SetHeight(glm::max(100.f, screen.y - pos.y - 200.f));
|
||||
stroke->m_popup_overlay_handle = popup_handle;
|
||||
stroke->m_tick_overlay_handle = tick_handle;
|
||||
|
||||
};
|
||||
}
|
||||
//if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-brush"))
|
||||
//{
|
||||
// button->on_click = [this, button](Node*) {
|
||||
// panels->get_child_index(brushes.get()) == -1 ? panels->add_child(brushes) : panels->remove_child(brushes.get());
|
||||
// panels->fix_scroll();
|
||||
// button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight);
|
||||
// };
|
||||
//}
|
||||
//if (auto* button = layout[main_id]->find<NodeButton>("btn-brush-preset"))
|
||||
//{
|
||||
// button->on_click = [this, button](Node*) {
|
||||
// panels->get_child_index(presets.get()) == -1 ? panels->add_child(presets) : panels->remove_child(presets.get());
|
||||
// panels->fix_scroll();
|
||||
// button->set_color(panels->get_child_index(presets.get()) == -1 ? color_button_normal : color_button_hlight);
|
||||
// };
|
||||
//}
|
||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-color"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
auto* popup_root = layout[main_id];
|
||||
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);
|
||||
};
|
||||
};
|
||||
}
|
||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-layer"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
auto* popup_root = layout[main_id];
|
||||
if (!popup_root) {
|
||||
return;
|
||||
}
|
||||
auto screen = popup_root->m_size;
|
||||
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
|
||||
layers->find("title")->SetVisibility(true);
|
||||
layers->SetSize(350, YGUndefined);
|
||||
if (layers->m_parent)
|
||||
{
|
||||
if (auto fp = dynamic_cast<NodePanelFloating*>(layers->m_parent->m_parent))
|
||||
{
|
||||
pp::panopainter::detach_legacy_node_from_parent(*layers);
|
||||
pp::panopainter::close_legacy_dialog_node(*fp);
|
||||
}
|
||||
}
|
||||
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, layers);
|
||||
if (!popup_overlay) {
|
||||
return;
|
||||
}
|
||||
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*popup_root);
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(32, 16);
|
||||
tick->SetPosition(pos.x - 16, pos.y);
|
||||
tick->set_image("data/ui/popup-tick-up.png");
|
||||
auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick);
|
||||
if (!popup_overlay || !tick_overlay)
|
||||
{
|
||||
close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay);
|
||||
return;
|
||||
}
|
||||
const auto popup_handle = popup_overlay.value();
|
||||
const auto tick_handle = tick_overlay.value();
|
||||
popup_root->update();
|
||||
|
||||
layers->SetPosition(pos.x - layers->m_size.x / 2.f, pos.y + 16);
|
||||
layers->SetPositioning(YGPositionTypeAbsolute);
|
||||
pp::panopainter::activate_legacy_popup_overlay(*layers);
|
||||
auto scroll = layers->find<NodeScroll>("layers-container");
|
||||
scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 200.f));
|
||||
layers->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-grids-panel"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
auto* popup_root = layout[main_id];
|
||||
if (!popup_root) {
|
||||
return;
|
||||
}
|
||||
auto screen = popup_root->m_size;
|
||||
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
|
||||
grid->find("title")->SetVisibility(true);
|
||||
grid->SetSize(350, YGUndefined);
|
||||
if (grid->m_parent)
|
||||
{
|
||||
if (auto fp = dynamic_cast<NodePanelFloating*>(grid->m_parent->m_parent))
|
||||
{
|
||||
pp::panopainter::detach_legacy_node_from_parent(*grid);
|
||||
pp::panopainter::close_legacy_dialog_node(*fp);
|
||||
}
|
||||
}
|
||||
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, grid);
|
||||
if (!popup_overlay)
|
||||
{
|
||||
LOG("Grid popup overlay failed: %s", popup_overlay.status().message);
|
||||
return;
|
||||
}
|
||||
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*popup_root);
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(32, 16);
|
||||
tick->SetPosition(pos.x - 16, pos.y);
|
||||
tick->set_image("data/ui/popup-tick-up.png");
|
||||
auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick);
|
||||
if (!popup_overlay || !tick_overlay)
|
||||
{
|
||||
close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay);
|
||||
return;
|
||||
}
|
||||
const auto popup_handle = popup_overlay.value();
|
||||
const auto tick_handle = tick_overlay.value();
|
||||
popup_root->update();
|
||||
|
||||
grid->SetPosition(pos.x - grid->m_size.x / 2.f, pos.y + 16);
|
||||
grid->SetPositioning(YGPositionTypeAbsolute);
|
||||
pp::panopainter::activate_legacy_popup_overlay(*grid);
|
||||
auto scroll = grid->find<NodeScroll>("scroller");
|
||||
scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 250.f));
|
||||
|
||||
grid->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);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
[[nodiscard]] bool current_canvas_mode_is_draw(App& app) noexcept
|
||||
{
|
||||
return app.canvas && app.canvas->m_canvas && app.canvas->m_canvas->m_current_mode == kCanvasMode::Draw;
|
||||
|
||||
435
src/app_layout_sidebar.cpp
Normal file
435
src/app_layout_sidebar.cpp
Normal file
@@ -0,0 +1,435 @@
|
||||
#include "pch.h"
|
||||
#include "app.h"
|
||||
#include "node_panel_grid.h"
|
||||
#include "node_panel_floating.h"
|
||||
#include "app_core/brush_ui.h"
|
||||
#include "app_core/document_layer.h"
|
||||
#include "legacy_brush_ui_services.h"
|
||||
#include "legacy_document_layer_services.h"
|
||||
#include "legacy_ui_overlay_services.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_texture_plan(App& app, pp::app::BrushUiTextureSlot slot, const std::string& path, const std::string& thumb)
|
||||
{
|
||||
return pp::panopainter::apply_legacy_brush_texture_plan(app, slot, path, thumb);
|
||||
}
|
||||
|
||||
bool apply_brush_preset_plan(App& app, const std::shared_ptr<Brush>& brush)
|
||||
{
|
||||
return pp::panopainter::apply_legacy_brush_preset_plan(app, brush);
|
||||
}
|
||||
|
||||
void execute_document_layer_operation_plan(
|
||||
App& app,
|
||||
const pp::app::DocumentLayerOperationPlan& plan,
|
||||
const std::shared_ptr<class Layer>& pending_layer = nullptr)
|
||||
{
|
||||
const auto status = pp::panopainter::execute_legacy_document_layer_operation_plan(app, plan, pending_layer);
|
||||
if (!status.ok())
|
||||
LOG("Layer operation failed: %s", status.message);
|
||||
}
|
||||
|
||||
void close_legacy_overlay_handle_ignoring_status(
|
||||
Node& anchor,
|
||||
pp::ui::NodeHandle overlay) noexcept
|
||||
{
|
||||
(void)pp::panopainter::close_legacy_overlay_node(anchor, overlay);
|
||||
}
|
||||
|
||||
template <typename PopupOverlay, typename TickOverlay>
|
||||
void close_legacy_overlay_handles_if_open(
|
||||
Node& anchor,
|
||||
const PopupOverlay& popup_overlay,
|
||||
const TickOverlay& tick_overlay) noexcept
|
||||
{
|
||||
if (popup_overlay) {
|
||||
close_legacy_overlay_handle_ignoring_status(anchor, popup_overlay.value());
|
||||
}
|
||||
if (tick_overlay) {
|
||||
close_legacy_overlay_handle_ignoring_status(anchor, tick_overlay.value());
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> create_panel(LayoutManager& manager)
|
||||
{
|
||||
auto ret = std::make_shared<T>();
|
||||
ret->set_manager(&manager);
|
||||
ret->init();
|
||||
ret->create();
|
||||
ret->loaded();
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void App::init_sidebar()
|
||||
{
|
||||
sidebar = layout[main_id]->find<NodeBorder>("sidebar");
|
||||
canvas = layout[main_id]->find<NodeCanvas>("paint-canvas");
|
||||
quick = layout[main_id]->find<NodePanelQuick>("panel-quick");
|
||||
floatings_container = layout[main_id]->find<Node>("floatings");
|
||||
|
||||
//brushes = layout[main_id]->find<NodePanelBrush>("panel-brush");
|
||||
//layers = layout[main_id]->find<NodePanelLayer>("panel-layer");
|
||||
//color = layout[main_id]->find<NodePanelColor>("panel-color");
|
||||
//stroke = layout[main_id]->find<NodePanelStroke>("panel-stroke");
|
||||
|
||||
//brushes = find_or_create_panel<NodePanelBrush>(panels);
|
||||
layers = create_panel<NodePanelLayer>(layout);
|
||||
color = create_panel<NodePanelColor>(layout);
|
||||
stroke = create_panel<NodePanelStroke>(layout);
|
||||
grid = create_panel<NodePanelGrid>(layout);
|
||||
presets = create_panel<NodePanelBrushPreset>(layout);
|
||||
animation = create_panel<NodePanelAnimation>(layout);
|
||||
//presets = find_or_create_panel<NodePanelBrushPreset>(panels);
|
||||
|
||||
canvas->m_canvas->on_mode_changed = [this](kCanvasMode prev, kCanvasMode mode) {
|
||||
quick_mode_state[prev] = quick->get_state();
|
||||
if (quick_mode_state.find(mode) != quick_mode_state.end())
|
||||
quick->set_state(quick_mode_state[mode], true);
|
||||
else
|
||||
quick->reset_state(true);
|
||||
brush_update(true, true);
|
||||
};
|
||||
color->on_color_changed = [this](Node* target, glm::vec4 color) {
|
||||
apply_brush_color_plan(*this, color, true, false);
|
||||
};
|
||||
|
||||
stroke->on_brush_changed = [this](Node* target, const std::string& path, const std::string& thumb) {
|
||||
apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::tip, path, thumb);
|
||||
};
|
||||
stroke->on_pattern_changed = [this](Node* target, const std::string& path, const std::string& thumb) {
|
||||
apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::pattern, path, thumb);
|
||||
};
|
||||
stroke->on_dual_changed = [this](Node* target, const std::string& path, const std::string& thumb) {
|
||||
apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::dual, path, thumb);
|
||||
};
|
||||
stroke->on_stroke_change = [this](Node*) {
|
||||
const auto status = pp::panopainter::execute_legacy_brush_stroke_changed_plan(*this);
|
||||
if (!status.ok())
|
||||
LOG("Brush stroke settings action failed: %s", status.message);
|
||||
};
|
||||
|
||||
quick->on_color_change = [this](Node*, glm::vec3 c) {
|
||||
apply_brush_color_plan(*this, glm::vec4(c, 1.f), false, true);
|
||||
};
|
||||
quick->on_flow_change = [this](Node*, float value) {
|
||||
stroke->set_flow(value, true, true);
|
||||
};
|
||||
quick->on_size_change = [this](Node*, float value) {
|
||||
stroke->set_size(value, true, true);
|
||||
};
|
||||
quick->on_brush_change = [this](Node*, std::shared_ptr<Brush> b) {
|
||||
apply_brush_preset_plan(*this, b);
|
||||
};
|
||||
|
||||
layers->on_layer_add = [this](Node*, std::shared_ptr<class Layer> layer, int index) {
|
||||
const auto plan = pp::app::plan_document_layer_add(
|
||||
static_cast<int>(Canvas::I->m_layers.size()),
|
||||
index,
|
||||
layers->m_layers.back()->m_label_text);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value(), layer);
|
||||
};
|
||||
|
||||
layers->on_layer_duplicate = [this](Node*, int source_index) {
|
||||
const auto plan = pp::app::plan_document_layer_duplicate(
|
||||
static_cast<int>(Canvas::I->m_layers.size()),
|
||||
source_index);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_change = [this](Node*, int, int new_idx) {
|
||||
const auto plan = pp::app::plan_document_layer_select(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
new_idx);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_order = [this](Node*, int old_idx, int new_idx) {
|
||||
const auto plan = pp::app::plan_document_layer_reorder(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
old_idx,
|
||||
new_idx);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_delete = [this](Node*, int idx) {
|
||||
const auto plan = pp::app::plan_document_layer_remove(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_opacity_changed = [this](Node*, int idx, float value) {
|
||||
const auto plan = pp::app::plan_document_layer_opacity(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
value);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) {
|
||||
const auto plan = pp::app::plan_document_layer_visibility(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
visible);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) {
|
||||
const auto plan = pp::app::plan_document_layer_alpha_lock(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
locked);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) {
|
||||
const auto plan = pp::app::plan_document_layer_blend_mode(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
mode);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) {
|
||||
const auto plan = pp::app::plan_document_layer_highlight(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
idx,
|
||||
highlight);
|
||||
if (!plan)
|
||||
return;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-stroke"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
auto* popup_root = layout[main_id];
|
||||
if (!popup_root) {
|
||||
return;
|
||||
}
|
||||
auto screen = popup_root->m_size;
|
||||
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
|
||||
if (stroke->m_parent)
|
||||
{
|
||||
if (auto fp = dynamic_cast<NodePanelFloating*>(stroke->m_parent->m_parent))
|
||||
{
|
||||
pp::panopainter::detach_legacy_node_from_parent(*stroke);
|
||||
pp::panopainter::close_legacy_dialog_node(*fp);
|
||||
}
|
||||
}
|
||||
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, stroke);
|
||||
if (!popup_overlay) {
|
||||
return;
|
||||
}
|
||||
stroke->SetSize(350, glm::max(100.f, screen.y - pos.y - 50.f));
|
||||
stroke->find("title")->SetVisibility(true);
|
||||
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*popup_root);
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(32, 16);
|
||||
tick->SetPosition(pos.x - 16, pos.y);
|
||||
tick->set_image("data/ui/popup-tick-up.png");
|
||||
auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick);
|
||||
if (!popup_overlay || !tick_overlay)
|
||||
{
|
||||
close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay);
|
||||
return;
|
||||
}
|
||||
const auto popup_handle = popup_overlay.value();
|
||||
const auto tick_handle = tick_overlay.value();
|
||||
popup_root->update();
|
||||
|
||||
stroke->SetPosition(pos.x - stroke->m_size.x / 2.f, pos.y + 16);
|
||||
stroke->SetPositioning(YGPositionTypeAbsolute);
|
||||
pp::panopainter::activate_legacy_popup_overlay(*stroke);
|
||||
auto scroll = stroke->find<NodeScroll>("scroller");
|
||||
(void)scroll;
|
||||
stroke->m_popup_overlay_handle = popup_handle;
|
||||
stroke->m_tick_overlay_handle = tick_handle;
|
||||
|
||||
};
|
||||
}
|
||||
//if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-brush"))
|
||||
//{
|
||||
// button->on_click = [this, button](Node*) {
|
||||
// panels->get_child_index(brushes.get()) == -1 ? panels->add_child(brushes) : panels->remove_child(brushes.get());
|
||||
// panels->fix_scroll();
|
||||
// button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight);
|
||||
// };
|
||||
//}
|
||||
//if (auto* button = layout[main_id]->find<NodeButton>("btn-brush-preset"))
|
||||
//{
|
||||
// button->on_click = [this, button](Node*) {
|
||||
// panels->get_child_index(presets.get()) == -1 ? panels->add_child(presets) : panels->remove_child(presets.get());
|
||||
// panels->fix_scroll();
|
||||
// button->set_color(panels->get_child_index(presets.get()) == -1 ? color_button_normal : color_button_hlight);
|
||||
// };
|
||||
//}
|
||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-color"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
auto* popup_root = layout[main_id];
|
||||
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);
|
||||
};
|
||||
};
|
||||
}
|
||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-layer"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
auto* popup_root = layout[main_id];
|
||||
if (!popup_root) {
|
||||
return;
|
||||
}
|
||||
auto screen = popup_root->m_size;
|
||||
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
|
||||
layers->find("title")->SetVisibility(true);
|
||||
layers->SetSize(350, YGUndefined);
|
||||
if (layers->m_parent)
|
||||
{
|
||||
if (auto fp = dynamic_cast<NodePanelFloating*>(layers->m_parent->m_parent))
|
||||
{
|
||||
pp::panopainter::detach_legacy_node_from_parent(*layers);
|
||||
pp::panopainter::close_legacy_dialog_node(*fp);
|
||||
}
|
||||
}
|
||||
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, layers);
|
||||
if (!popup_overlay) {
|
||||
return;
|
||||
}
|
||||
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*popup_root);
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(32, 16);
|
||||
tick->SetPosition(pos.x - 16, pos.y);
|
||||
tick->set_image("data/ui/popup-tick-up.png");
|
||||
auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick);
|
||||
if (!popup_overlay || !tick_overlay)
|
||||
{
|
||||
close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay);
|
||||
return;
|
||||
}
|
||||
const auto popup_handle = popup_overlay.value();
|
||||
const auto tick_handle = tick_overlay.value();
|
||||
popup_root->update();
|
||||
|
||||
layers->SetPosition(pos.x - layers->m_size.x / 2.f, pos.y + 16);
|
||||
layers->SetPositioning(YGPositionTypeAbsolute);
|
||||
pp::panopainter::activate_legacy_popup_overlay(*layers);
|
||||
auto scroll = layers->find<NodeScroll>("layers-container");
|
||||
scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 200.f));
|
||||
layers->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-grids-panel"))
|
||||
{
|
||||
button->on_click = [this, button](Node*) {
|
||||
auto* popup_root = layout[main_id];
|
||||
if (!popup_root) {
|
||||
return;
|
||||
}
|
||||
auto screen = popup_root->m_size;
|
||||
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
|
||||
grid->find("title")->SetVisibility(true);
|
||||
grid->SetSize(350, YGUndefined);
|
||||
if (grid->m_parent)
|
||||
{
|
||||
if (auto fp = dynamic_cast<NodePanelFloating*>(grid->m_parent->m_parent))
|
||||
{
|
||||
pp::panopainter::detach_legacy_node_from_parent(*grid);
|
||||
pp::panopainter::close_legacy_dialog_node(*fp);
|
||||
}
|
||||
}
|
||||
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, grid);
|
||||
if (!popup_overlay)
|
||||
{
|
||||
LOG("Grid popup overlay failed: %s", popup_overlay.status().message);
|
||||
return;
|
||||
}
|
||||
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*popup_root);
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(32, 16);
|
||||
tick->SetPosition(pos.x - 16, pos.y);
|
||||
tick->set_image("data/ui/popup-tick-up.png");
|
||||
auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick);
|
||||
if (!popup_overlay || !tick_overlay)
|
||||
{
|
||||
close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay);
|
||||
return;
|
||||
}
|
||||
const auto popup_handle = popup_overlay.value();
|
||||
const auto tick_handle = tick_overlay.value();
|
||||
popup_root->update();
|
||||
|
||||
grid->SetPosition(pos.x - grid->m_size.x / 2.f, pos.y + 16);
|
||||
grid->SetPositioning(YGPositionTypeAbsolute);
|
||||
pp::panopainter::activate_legacy_popup_overlay(*grid);
|
||||
auto scroll = grid->find<NodeScroll>("scroller");
|
||||
scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 250.f));
|
||||
|
||||
grid->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);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -945,6 +945,49 @@ inline void execute_legacy_canvas_draw_merge_background_setup(
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename PrepareBlendCache,
|
||||
typename DrawBackground,
|
||||
typename ConfigureBlendState,
|
||||
typename DisableDepthTest,
|
||||
typename PlanOnionRange,
|
||||
typename ShouldDrawPlane,
|
||||
typename VisitLayerPlane,
|
||||
typename LogOnionRangeFailure,
|
||||
typename CompositeBlendCache>
|
||||
inline void execute_legacy_canvas_draw_unmerged_shell(
|
||||
bool use_blend,
|
||||
size_t layer_count,
|
||||
PrepareBlendCache&& prepare_blend_cache,
|
||||
DrawBackground&& draw_background,
|
||||
ConfigureBlendState&& configure_blend_state,
|
||||
DisableDepthTest&& disable_depth_test,
|
||||
PlanOnionRange&& plan_onion_range,
|
||||
ShouldDrawPlane&& should_draw_plane,
|
||||
VisitLayerPlane&& visit_layer_plane,
|
||||
LogOnionRangeFailure&& log_onion_range_failure,
|
||||
CompositeBlendCache&& composite_blend_cache)
|
||||
{
|
||||
if (use_blend) {
|
||||
prepare_blend_cache();
|
||||
}
|
||||
|
||||
draw_background();
|
||||
configure_blend_state(use_blend);
|
||||
disable_depth_test();
|
||||
|
||||
execute_legacy_canvas_draw_layer_traversal(
|
||||
layer_count,
|
||||
std::forward<PlanOnionRange>(plan_onion_range),
|
||||
std::forward<ShouldDrawPlane>(should_draw_plane),
|
||||
std::forward<VisitLayerPlane>(visit_layer_plane),
|
||||
std::forward<LogOnionRangeFailure>(log_onion_range_failure));
|
||||
|
||||
if (use_blend) {
|
||||
composite_blend_cache();
|
||||
}
|
||||
}
|
||||
|
||||
inline void execute_legacy_canvas_draw_merge_plane_setup(
|
||||
const LegacyCanvasDrawMergePlaneSetupUniforms& uniforms,
|
||||
const LegacyCanvasDrawMergePlaneSetupExecution& execution)
|
||||
|
||||
60
src/main.cpp
60
src/main.cpp
@@ -11,6 +11,7 @@
|
||||
#include "legacy_preference_storage.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
#include "platform_windows/windows_platform_services.h"
|
||||
#include "platform_windows/windows_lifecycle_shell.h"
|
||||
#include "platform_windows/windows_splash.h"
|
||||
#include "platform_windows/windows_stylus_input.h"
|
||||
#include "platform_windows/windows_vr_shell.h"
|
||||
@@ -30,10 +31,6 @@
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
#include <atomic>
|
||||
|
||||
#define WM_USER_CLOSE (WM_USER + 1)
|
||||
#define WM_USER_WAKEUP (WM_USER + 2)
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
|
||||
namespace pp::platform::windows {
|
||||
@@ -127,13 +124,10 @@ void pp_windows_enqueue_main_task(std::packaged_task<void()> task)
|
||||
enqueue_main_task_bridge(std::move(task));
|
||||
}
|
||||
|
||||
std::atomic<int> running{-1};
|
||||
|
||||
void destroy_window()
|
||||
{
|
||||
auto& state = retained_state();
|
||||
enqueue_main_task([hWnd = state.hWnd] {
|
||||
PostMessage(hWnd, WM_USER_CLOSE, 0, 0);
|
||||
enqueue_main_task([hWnd = retained_state().hWnd] {
|
||||
pp::platform::windows::request_window_close(hWnd);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -159,25 +153,15 @@ void async_unlock()
|
||||
|
||||
void win32_update_stylus(float dt)
|
||||
{
|
||||
pp::platform::windows::update_stylus_state(dt);
|
||||
pp::platform::windows::update_stylus_frame(dt);
|
||||
}
|
||||
|
||||
void win32_update_fps(int frames)
|
||||
{
|
||||
static wchar_t title_fps[512];
|
||||
auto& state = retained_state();
|
||||
const int vr_fps = pp::platform::windows::current_vr_fps(state.vr);
|
||||
if (App::I->vr_active)
|
||||
swprintf_s(title_fps, L"%s - %d fps - %d vr fps", state.window_title, frames, vr_fps);
|
||||
else
|
||||
swprintf_s(title_fps, L"%s - %d fps", state.window_title, frames);
|
||||
|
||||
{
|
||||
enqueue_main_task([hWnd = state.hWnd] {
|
||||
SetWindowText(hWnd, title_fps);
|
||||
enqueue_main_task([hWnd = state.hWnd, window_title = state.window_title, &vr = state.vr, frames] {
|
||||
pp::platform::windows::update_window_fps(hWnd, window_title, vr, frames);
|
||||
});
|
||||
}
|
||||
PostMessage(state.hWnd, WM_USER_WAKEUP, 0, 0);
|
||||
}
|
||||
|
||||
int read_WMI_info()
|
||||
@@ -455,25 +439,17 @@ void init_vk_map()
|
||||
bool win32_vr_start()
|
||||
{
|
||||
auto& state = retained_state();
|
||||
return pp::platform::windows::start_vr_shell(state.vr, state.sandboxed, running);
|
||||
return pp::platform::windows::start_window_vr(state.vr, state.sandboxed);
|
||||
}
|
||||
|
||||
void win32_vr_stop()
|
||||
{
|
||||
auto& state = retained_state();
|
||||
pp::platform::windows::stop_vr_shell(state.vr);
|
||||
pp::platform::windows::stop_window_vr(retained_state().vr);
|
||||
}
|
||||
|
||||
void win32_save_window_state()
|
||||
{
|
||||
auto& state = retained_state();
|
||||
WINDOWPLACEMENT p;
|
||||
GetWindowPlacement(state.hWnd, &p);
|
||||
pp::panopainter::set_legacy_window_preferences(p.showCmd, {
|
||||
p.rcNormalPosition.left,
|
||||
p.rcNormalPosition.top,
|
||||
p.rcNormalPosition.right,
|
||||
p.rcNormalPosition.bottom });
|
||||
pp::platform::windows::save_window_preferences(retained_state().hWnd);
|
||||
}
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
@@ -678,7 +654,7 @@ int main(int argc, char** argv)
|
||||
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
|
||||
running.store(1, std::memory_order_relaxed);
|
||||
pp::platform::windows::mark_lifecycle_running();
|
||||
App::I->runtime().render_thread_start(*App::I);
|
||||
App::I->runtime().ui_thread_start(*App::I);
|
||||
|
||||
@@ -724,14 +700,14 @@ int main(int argc, char** argv)
|
||||
|
||||
MSG msg;
|
||||
LOG("start main loop");
|
||||
while (running.load(std::memory_order_relaxed) == 1)
|
||||
while (pp::platform::windows::lifecycle_is_running())
|
||||
{
|
||||
// If there any message in the queue process it
|
||||
auto present = App::I->animate || App::I->redraw ?
|
||||
PeekMessage(&msg, 0, 0, 0, PM_REMOVE) : GetMessage(&msg, 0, 0, 0);
|
||||
|
||||
if (msg.message == WM_QUIT)
|
||||
running.store(0, std::memory_order_relaxed);
|
||||
pp::platform::windows::mark_lifecycle_stopped();
|
||||
|
||||
if (present)
|
||||
{
|
||||
@@ -762,14 +738,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_USER_CLOSE:
|
||||
running.store(0, std::memory_order_relaxed);
|
||||
pp::platform::windows::request_stop_and_join_vr_thread(state.vr);
|
||||
App::I->runtime().ui_thread_stop();
|
||||
App::I->runtime().render_thread_stop();
|
||||
App::I->terminate();
|
||||
delete App::I;
|
||||
PostQuitMessage(0);
|
||||
case pp::platform::windows::kUserCloseMessage:
|
||||
pp::platform::windows::handle_window_close_message(state.vr);
|
||||
return 0;
|
||||
case WM_PAINT:
|
||||
App::I->redraw = true;
|
||||
@@ -792,7 +762,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
{
|
||||
auto w = (float)LOWORD(lp);
|
||||
auto h = (float)HIWORD(lp);
|
||||
if (h != 0 && running.load(std::memory_order_relaxed) == 1)
|
||||
if (h != 0 && pp::platform::windows::lifecycle_is_running())
|
||||
{
|
||||
App::I->ui_task_async([=]
|
||||
{
|
||||
|
||||
@@ -668,13 +668,16 @@ void NodeCanvas::draw()
|
||||
const bool use_blend = blend_gate.shader_blend;
|
||||
const bool copy_blend_destination = use_blend && !blend_gate.reads_destination_color;
|
||||
|
||||
if (use_blend)
|
||||
{
|
||||
const auto& b = m_canvas->m_current_stroke->m_brush;
|
||||
pp::panopainter::execute_legacy_canvas_draw_unmerged_shell(
|
||||
use_blend,
|
||||
m_canvas->m_layers.size(),
|
||||
[&] {
|
||||
apply_node_canvas_viewport(0, 0, m_cache_rtt.getWidth(), m_cache_rtt.getHeight());
|
||||
m_cache_rtt.bindFramebuffer();
|
||||
m_cache_rtt.clear({ 1, 1, 1, 0 });
|
||||
}
|
||||
|
||||
},
|
||||
[&] {
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_background_setup(
|
||||
{
|
||||
.use_blend = use_blend,
|
||||
@@ -692,14 +695,14 @@ void NodeCanvas::draw()
|
||||
m_face_plane.draw_fill();
|
||||
}),
|
||||
});
|
||||
|
||||
},
|
||||
[&](bool enable_shader_blend) {
|
||||
// if not using shader blend, use gl rasterizer blend
|
||||
use_blend ? apply_node_canvas_capability(pp::renderer::gl::blend_state(), false) : apply_node_canvas_capability(pp::renderer::gl::blend_state(), true);
|
||||
apply_node_canvas_capability(pp::renderer::gl::blend_state(), !enable_shader_blend);
|
||||
},
|
||||
[&] {
|
||||
apply_node_canvas_capability(pp::renderer::gl::depth_test_state(), false);
|
||||
|
||||
const auto& b = m_canvas->m_current_stroke->m_brush;
|
||||
pp::panopainter::execute_legacy_canvas_draw_layer_traversal(
|
||||
m_canvas->m_layers.size(),
|
||||
},
|
||||
[&](size_t layer_index) {
|
||||
return pp::app::plan_animation_onion_frame_range(
|
||||
m_canvas->m_layers[layer_index]->frames_count(),
|
||||
@@ -748,9 +751,8 @@ void NodeCanvas::draw()
|
||||
},
|
||||
[&](const char* message) {
|
||||
LOG("NodeCanvas onion frame range failed: %s", message);
|
||||
});
|
||||
if (use_blend)
|
||||
{
|
||||
},
|
||||
[&] {
|
||||
m_cache_rtt.unbindFramebuffer();
|
||||
if (m_density != 1.f)
|
||||
apply_node_canvas_viewport(0, 0, m_rtt.getWidth(), m_rtt.getHeight());
|
||||
@@ -792,7 +794,7 @@ void NodeCanvas::draw()
|
||||
m_cache_rtt.unbindTexture();
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
execute_node_canvas_draw_merge_tail(*this, ortho_proj, proj, camera, c);
|
||||
|
||||
96
src/platform_windows/windows_lifecycle_shell.cpp
Normal file
96
src/platform_windows/windows_lifecycle_shell.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "platform_windows/windows_lifecycle_shell.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "legacy_preference_storage.h"
|
||||
#include "platform_windows/windows_stylus_input.h"
|
||||
|
||||
namespace pp::platform::windows {
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] std::atomic<int>& retained_running_state() noexcept
|
||||
{
|
||||
static std::atomic<int> running{-1};
|
||||
return running;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::atomic<int>& lifecycle_running_state() noexcept
|
||||
{
|
||||
return retained_running_state();
|
||||
}
|
||||
|
||||
void mark_lifecycle_running() noexcept
|
||||
{
|
||||
retained_running_state().store(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void mark_lifecycle_stopped() noexcept
|
||||
{
|
||||
retained_running_state().store(0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool lifecycle_is_running() noexcept
|
||||
{
|
||||
return retained_running_state().load(std::memory_order_relaxed) == 1;
|
||||
}
|
||||
|
||||
void request_window_close(HWND hWnd)
|
||||
{
|
||||
PostMessage(hWnd, kUserCloseMessage, 0, 0);
|
||||
}
|
||||
|
||||
void handle_window_close_message(VrShellState& vr)
|
||||
{
|
||||
mark_lifecycle_stopped();
|
||||
request_stop_and_join_vr_thread(vr);
|
||||
App::I->runtime().ui_thread_stop();
|
||||
App::I->runtime().render_thread_stop();
|
||||
App::I->terminate();
|
||||
delete App::I;
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
void update_stylus_frame(float dt)
|
||||
{
|
||||
update_stylus_state(dt);
|
||||
}
|
||||
|
||||
void update_window_fps(HWND hWnd, const wchar_t* window_title, VrShellState& vr, int frames)
|
||||
{
|
||||
static wchar_t title_fps[512];
|
||||
const int vr_fps = current_vr_fps(vr);
|
||||
if (App::I->vr_active)
|
||||
swprintf_s(title_fps, L"%s - %d fps - %d vr fps", window_title, frames, vr_fps);
|
||||
else
|
||||
swprintf_s(title_fps, L"%s - %d fps", window_title, frames);
|
||||
|
||||
SetWindowText(hWnd, title_fps);
|
||||
PostMessage(hWnd, kUserWakeupMessage, 0, 0);
|
||||
}
|
||||
|
||||
void save_window_preferences(HWND hWnd)
|
||||
{
|
||||
WINDOWPLACEMENT placement{};
|
||||
GetWindowPlacement(hWnd, &placement);
|
||||
pp::panopainter::set_legacy_window_preferences(placement.showCmd, {
|
||||
placement.rcNormalPosition.left,
|
||||
placement.rcNormalPosition.top,
|
||||
placement.rcNormalPosition.right,
|
||||
placement.rcNormalPosition.bottom });
|
||||
}
|
||||
|
||||
bool start_window_vr(VrShellState& vr, bool sandboxed)
|
||||
{
|
||||
return start_vr_shell(vr, sandboxed, retained_running_state());
|
||||
}
|
||||
|
||||
void stop_window_vr(VrShellState& vr)
|
||||
{
|
||||
stop_vr_shell(vr);
|
||||
}
|
||||
|
||||
}
|
||||
29
src/platform_windows/windows_lifecycle_shell.h
Normal file
29
src/platform_windows/windows_lifecycle_shell.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "platform_windows/windows_vr_shell.h"
|
||||
|
||||
namespace pp::platform::windows {
|
||||
|
||||
inline constexpr UINT kUserCloseMessage = WM_USER + 1;
|
||||
inline constexpr UINT kUserWakeupMessage = WM_USER + 2;
|
||||
|
||||
[[nodiscard]] std::atomic<int>& lifecycle_running_state() noexcept;
|
||||
void mark_lifecycle_running() noexcept;
|
||||
void mark_lifecycle_stopped() noexcept;
|
||||
[[nodiscard]] bool lifecycle_is_running() noexcept;
|
||||
|
||||
void request_window_close(HWND hWnd);
|
||||
void handle_window_close_message(VrShellState& vr);
|
||||
|
||||
void update_stylus_frame(float dt);
|
||||
void update_window_fps(HWND hWnd, const wchar_t* window_title, VrShellState& vr, int frames);
|
||||
void save_window_preferences(HWND hWnd);
|
||||
|
||||
[[nodiscard]] bool start_window_vr(VrShellState& vr, bool sandboxed);
|
||||
void stop_window_vr(VrShellState& vr);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user