Extract sidebar, lifecycle shell, and canvas unmerged draw
This commit is contained in:
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);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user