Files
panopainter/src/app_layout_sidebar.cpp

370 lines
15 KiB
C++

#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_sidebar_color_popup_services.h"
#include "legacy_sidebar_stroke_popup_services.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;
}
pp::panopainter::open_legacy_sidebar_stroke_popup(*this, *popup_root, *button, *stroke);
};
}
//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;
}
pp::panopainter::open_legacy_sidebar_color_popup(*this, *popup_root, *button, *color);
};
}
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);
};
};
}
}