Narrow retained UI overlay lifetime debt
This commit is contained in:
@@ -7,6 +7,40 @@
|
||||
#include "node_combobox.h"
|
||||
#include "app.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void move_layer_entry(std::vector<std::shared_ptr<NodeLayer>>& layers, int old_index, int new_index)
|
||||
{
|
||||
if (old_index < 0 || new_index < 0 || old_index == new_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto size = static_cast<int>(layers.size());
|
||||
if (old_index >= size || new_index >= size) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto moved = layers[old_index];
|
||||
layers.erase(layers.begin() + old_index);
|
||||
layers.insert(layers.begin() + new_index, std::move(moved));
|
||||
}
|
||||
|
||||
int find_layer_index(const std::vector<std::shared_ptr<NodeLayer>>& layers, const NodeLayer* layer)
|
||||
{
|
||||
if (!layer) {
|
||||
return -1;
|
||||
}
|
||||
const auto it = std::find_if(
|
||||
layers.begin(),
|
||||
layers.end(),
|
||||
[layer](const auto& item) {
|
||||
return item.get() == layer;
|
||||
});
|
||||
return it == layers.end() ? -1 : static_cast<int>(std::distance(layers.begin(), it));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Node* NodeLayer::clone_instantiate() const
|
||||
{
|
||||
return new NodeLayer();
|
||||
@@ -121,6 +155,14 @@ void NodePanelLayer::init()
|
||||
btn_down = find<NodeButtonCustom>("btn-down");
|
||||
btn_duplicate = find<NodeButtonCustom>("btn-duplicate");
|
||||
btn_duplicate->on_click = [this](Node*) {
|
||||
if (!m_current_layer) {
|
||||
return;
|
||||
}
|
||||
const auto source_index = find_layer_index(m_layers, m_current_layer.get());
|
||||
if (source_index < 0) {
|
||||
m_current_layer.reset();
|
||||
return;
|
||||
}
|
||||
std::string next = m_current_layer->m_label_text + "01";
|
||||
std::regex r(R"(([^\d]*)(\d+)$)");
|
||||
std::smatch m;
|
||||
@@ -132,35 +174,65 @@ void NodePanelLayer::init()
|
||||
sprintf(tmp, "%s%0*d", m[1].str().c_str(), (int)num.length(), count);
|
||||
next = tmp;
|
||||
}
|
||||
int source_index = m_layers_container->get_child_index(m_current_layer);
|
||||
auto l = add_layer(next.c_str(), false, false, nullptr, nullptr, source_index + 1);
|
||||
if (on_layer_duplicate)
|
||||
on_layer_duplicate(this, source_index);
|
||||
if (on_layer_change)
|
||||
on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer));
|
||||
{
|
||||
const auto selected_index = find_layer_index(m_layers, m_current_layer.get());
|
||||
if (selected_index >= 0) {
|
||||
on_layer_change(this, -1, selected_index);
|
||||
}
|
||||
}
|
||||
update_attributes();
|
||||
|
||||
auto a = new ActionLayerAdd;
|
||||
a->m_panel = this;
|
||||
a->m_layer_node = l->shared_from_this();
|
||||
a->m_layer_order = m_layers_container->get_child_index(l);
|
||||
a->m_layer_id = Canvas::I->m_layers[a->m_layer_order]->id;
|
||||
const auto new_layer_order = find_layer_index(m_layers, l);
|
||||
if (new_layer_order < 0) {
|
||||
delete a;
|
||||
return;
|
||||
}
|
||||
a->m_layer_order = new_layer_order;
|
||||
a->m_layer_id = Canvas::I->m_layers[new_layer_order]->id;
|
||||
ActionManager::add(a);
|
||||
};
|
||||
btn_add->on_click = [this](Node*) {
|
||||
add_layer(true, true, m_layers_container->get_child_index(m_current_layer) + 1);
|
||||
if (!m_current_layer) {
|
||||
return;
|
||||
}
|
||||
const auto insert_index = find_layer_index(m_layers, m_current_layer.get());
|
||||
if (insert_index < 0) {
|
||||
return;
|
||||
}
|
||||
add_layer(true, true, insert_index + 1);
|
||||
};
|
||||
btn_remove->on_click = [this](Node*) {
|
||||
if (m_layers.size() == 1)
|
||||
return; // don't delete the last layer
|
||||
remove_layer(m_current_layer);
|
||||
if (m_current_layer) {
|
||||
remove_layer(m_current_layer.get());
|
||||
}
|
||||
};
|
||||
btn_up->on_click = [this](Node*) {
|
||||
int old_idx = m_layers_container->get_child_index(m_current_layer);
|
||||
m_layers_container->move_child_offset(m_current_layer, +1);
|
||||
int new_idx = m_layers_container->get_child_index(m_current_layer);
|
||||
if (!m_current_layer) {
|
||||
return;
|
||||
}
|
||||
const int old_idx = find_layer_index(m_layers, m_current_layer.get());
|
||||
if (old_idx < 0) {
|
||||
m_current_layer.reset();
|
||||
return;
|
||||
}
|
||||
m_layers_container->move_child_offset(m_current_layer.get(), +1);
|
||||
const int new_idx = m_layers_container->get_child_index(m_current_layer.get());
|
||||
if (new_idx < 0) {
|
||||
m_current_layer->m_selected = true;
|
||||
return;
|
||||
}
|
||||
if (on_layer_order && old_idx != new_idx)
|
||||
{
|
||||
move_layer_entry(m_layers, old_idx, new_idx);
|
||||
on_layer_order(this, old_idx, new_idx);
|
||||
}
|
||||
auto a = new ActionLayerMove;
|
||||
@@ -170,11 +242,23 @@ void NodePanelLayer::init()
|
||||
ActionManager::add(a);
|
||||
};
|
||||
btn_down->on_click = [this](Node*) {
|
||||
int old_idx = m_layers_container->get_child_index(m_current_layer);
|
||||
m_layers_container->move_child_offset(m_current_layer, -1);
|
||||
int new_idx = m_layers_container->get_child_index(m_current_layer);
|
||||
if (!m_current_layer) {
|
||||
return;
|
||||
}
|
||||
const int old_idx = find_layer_index(m_layers, m_current_layer.get());
|
||||
if (old_idx < 0) {
|
||||
m_current_layer.reset();
|
||||
return;
|
||||
}
|
||||
m_layers_container->move_child_offset(m_current_layer.get(), -1);
|
||||
const int new_idx = m_layers_container->get_child_index(m_current_layer.get());
|
||||
if (new_idx < 0) {
|
||||
m_current_layer->m_selected = true;
|
||||
return;
|
||||
}
|
||||
if (on_layer_order && old_idx != new_idx)
|
||||
{
|
||||
move_layer_entry(m_layers, old_idx, new_idx);
|
||||
on_layer_order(this, old_idx, new_idx);
|
||||
}
|
||||
auto a = new ActionLayerMove;
|
||||
@@ -185,15 +269,21 @@ void NodePanelLayer::init()
|
||||
};
|
||||
m_opacity = find<NodeSliderH>("opacity");
|
||||
m_opacity->on_value_changed = [this](Node*, float value) {
|
||||
handle_layer_opacity(m_current_layer, value);
|
||||
if (m_current_layer && find_layer_index(m_layers, m_current_layer.get()) >= 0) {
|
||||
handle_layer_opacity(m_current_layer.get(), value);
|
||||
}
|
||||
};
|
||||
m_alpha_lock = find<NodeCheckBox>("alpha-lock");
|
||||
m_alpha_lock->on_value_changed = [this](Node*, bool locked) {
|
||||
handle_layer_alpha_lock(m_current_layer, locked);
|
||||
if (m_current_layer && find_layer_index(m_layers, m_current_layer.get()) >= 0) {
|
||||
handle_layer_alpha_lock(m_current_layer.get(), locked);
|
||||
}
|
||||
};
|
||||
m_blend_mode = find<NodeComboBox>("blend-mode");
|
||||
m_blend_mode->on_select = [this](Node*, int index) {
|
||||
handle_layer_blend_mode(m_current_layer, index);
|
||||
if (m_current_layer && find_layer_index(m_layers, m_current_layer.get()) >= 0) {
|
||||
handle_layer_blend_mode(m_current_layer.get(), index);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -215,30 +305,45 @@ NodeLayer* NodePanelLayer::add_layer(const char* name, bool add_history /*= true
|
||||
|
||||
// reset selected state
|
||||
for (const auto& c : m_layers_container->m_children)
|
||||
((NodeLayer*)c.get())->m_selected = false;
|
||||
static_cast<NodeLayer*>(c.get())->m_selected = false;
|
||||
|
||||
if (m_current_layer)
|
||||
m_current_layer->m_selected = false;
|
||||
m_current_layer = l.get();
|
||||
m_current_layer = l;
|
||||
m_current_layer->m_selected = true;
|
||||
m_layers.push_back(l.get());
|
||||
const auto insert_index = std::clamp(index, 0, static_cast<int>(m_layers.size()));
|
||||
m_layers.insert(m_layers.begin() + insert_index, l);
|
||||
|
||||
if (add_history)
|
||||
{
|
||||
if (create_events)
|
||||
{
|
||||
if (on_layer_add)
|
||||
on_layer_add(this, nullptr, m_layers_container->get_child_index(m_current_layer));
|
||||
{
|
||||
const auto current_index = find_layer_index(m_layers, m_current_layer.get());
|
||||
if (current_index >= 0) {
|
||||
on_layer_add(this, nullptr, current_index);
|
||||
}
|
||||
}
|
||||
if (on_layer_change)
|
||||
on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer));
|
||||
{
|
||||
if (const auto current_index = find_layer_index(m_layers, m_current_layer.get()); current_index >= 0) {
|
||||
on_layer_change(this, -1, current_index);
|
||||
}
|
||||
}
|
||||
update_attributes();
|
||||
}
|
||||
|
||||
auto a = new ActionLayerAdd;
|
||||
a->m_panel = this;
|
||||
a->m_layer_node = l->shared_from_this();
|
||||
a->m_layer_order = m_layers_container->get_child_index(l.get());
|
||||
a->m_layer_id = Canvas::I->m_layers[a->m_layer_order]->id;
|
||||
const auto layer_order = find_layer_index(m_layers, l.get());
|
||||
if (layer_order < 0) {
|
||||
delete a;
|
||||
return l.get();
|
||||
}
|
||||
a->m_layer_order = layer_order;
|
||||
a->m_layer_id = Canvas::I->m_layers[layer_order]->id;
|
||||
ActionManager::add(a);
|
||||
}
|
||||
else if (create_events)
|
||||
@@ -246,7 +351,12 @@ NodeLayer* NodePanelLayer::add_layer(const char* name, bool add_history /*= true
|
||||
if (on_layer_add)
|
||||
on_layer_add(this, layer, index);
|
||||
if (on_layer_change)
|
||||
on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer));
|
||||
{
|
||||
const auto current_index = find_layer_index(m_layers, m_current_layer.get());
|
||||
if (current_index >= 0) {
|
||||
on_layer_change(this, -1, current_index);
|
||||
}
|
||||
}
|
||||
update_attributes();
|
||||
}
|
||||
|
||||
@@ -267,21 +377,38 @@ NodeLayer* NodePanelLayer::get_layer_at(int index)
|
||||
|
||||
void NodePanelLayer::remove_layer(NodeLayer* layer, bool add_history /*= true*/)
|
||||
{
|
||||
auto it = std::find(m_layers.begin(), m_layers.end(), layer);
|
||||
auto i = m_layers_container->get_child_index(layer);
|
||||
int old_idx = i;// (int)std::distance(m_layers.begin(), it);
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
const auto it = std::find_if(
|
||||
m_layers.begin(),
|
||||
m_layers.end(),
|
||||
[layer](const std::shared_ptr<NodeLayer>& l) {
|
||||
return l.get() == layer;
|
||||
});
|
||||
if (it == m_layers.end()) {
|
||||
return;
|
||||
}
|
||||
const int old_idx = static_cast<int>(std::distance(m_layers.begin(), it));
|
||||
(*it)->m_selected = false;
|
||||
auto copy = (*it)->shared_from_this();
|
||||
m_layers_container->remove_child(layer);
|
||||
m_layers.erase(it);
|
||||
i = std::min<int>(i, (int)m_layers.size() - 1);
|
||||
const int i = m_layers.empty() ? -1 : std::min<int>(old_idx, static_cast<int>(m_layers.size()) - 1);
|
||||
|
||||
// reset selected state
|
||||
for (const auto& c : m_layers_container->m_children)
|
||||
((NodeLayer*)c.get())->m_selected = false;
|
||||
static_cast<NodeLayer*>(c.get())->m_selected = false;
|
||||
|
||||
m_current_layer = (NodeLayer*)m_layers_container->get_child_at(i);
|
||||
m_current_layer->m_selected = true;
|
||||
const auto next_layer = i < 0 ? nullptr : m_layers_container->get_child_at(i);
|
||||
if (next_layer) {
|
||||
m_current_layer = std::static_pointer_cast<NodeLayer>(next_layer->shared_from_this());
|
||||
} else {
|
||||
m_current_layer.reset();
|
||||
}
|
||||
if (m_current_layer) {
|
||||
m_current_layer->m_selected = true;
|
||||
}
|
||||
|
||||
if (add_history)
|
||||
{
|
||||
@@ -302,45 +429,70 @@ void NodePanelLayer::remove_layer(NodeLayer* layer, bool add_history /*= true*/)
|
||||
|
||||
void NodePanelLayer::handle_layer_opacity(NodeLayer* target, float value)
|
||||
{
|
||||
if (on_layer_opacity_changed)
|
||||
on_layer_opacity_changed(this, m_layers_container->get_child_index(target), value);
|
||||
const auto idx = find_layer_index(m_layers, target);
|
||||
if (idx < 0 || !on_layer_opacity_changed) {
|
||||
return;
|
||||
}
|
||||
on_layer_opacity_changed(this, idx, value);
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_highlight(NodeLayer* target, bool highlight)
|
||||
{
|
||||
if (on_layer_highlight_changed)
|
||||
on_layer_highlight_changed(this, m_layers_container->get_child_index(target), highlight);
|
||||
const auto idx = find_layer_index(m_layers, target);
|
||||
if (idx < 0 || !on_layer_highlight_changed) {
|
||||
return;
|
||||
}
|
||||
on_layer_highlight_changed(this, idx, highlight);
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_visibility(NodeLayer* target, bool visible)
|
||||
{
|
||||
const auto idx = find_layer_index(m_layers, target);
|
||||
if (idx < 0) {
|
||||
return;
|
||||
}
|
||||
save_history();
|
||||
if (on_layer_visibility_changed)
|
||||
on_layer_visibility_changed(this, m_layers_container->get_child_index(target), visible);
|
||||
if (on_layer_visibility_changed) {
|
||||
on_layer_visibility_changed(this, idx, visible);
|
||||
}
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_alpha_lock(NodeLayer* target, bool locked)
|
||||
{
|
||||
const auto idx = find_layer_index(m_layers, target);
|
||||
if (idx < 0) {
|
||||
return;
|
||||
}
|
||||
save_history();
|
||||
if (on_layer_alpha_lock_changed)
|
||||
on_layer_alpha_lock_changed(this, m_layers_container->get_child_index(target), locked);
|
||||
if (on_layer_alpha_lock_changed) {
|
||||
on_layer_alpha_lock_changed(this, idx, locked);
|
||||
}
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_blend_mode(NodeLayer* target, int mode)
|
||||
{
|
||||
const auto idx = find_layer_index(m_layers, target);
|
||||
if (idx < 0) {
|
||||
return;
|
||||
}
|
||||
save_history();
|
||||
if (on_layer_blend_mode_changed)
|
||||
on_layer_blend_mode_changed(this, m_layers_container->get_child_index(target), mode);
|
||||
if (on_layer_blend_mode_changed) {
|
||||
on_layer_blend_mode_changed(this, idx, mode);
|
||||
}
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_selected(NodeLayer* target)
|
||||
{
|
||||
const auto idx = find_layer_index(m_layers, target);
|
||||
if (idx < 0) {
|
||||
return;
|
||||
}
|
||||
if (m_current_layer)
|
||||
m_current_layer->m_selected = false;
|
||||
m_current_layer = target;
|
||||
m_current_layer = std::static_pointer_cast<NodeLayer>(target->shared_from_this());
|
||||
m_current_layer->m_selected = true;
|
||||
if (on_layer_change)
|
||||
on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer));
|
||||
on_layer_change(this, -1, idx);
|
||||
update_attributes();
|
||||
}
|
||||
|
||||
@@ -411,7 +563,15 @@ kEventResult NodePanelLayer::handle_event(Event* e)
|
||||
case kEventType::MouseUpL:
|
||||
if (!m_mouse_inside)
|
||||
{
|
||||
pp::panopainter::close_legacy_popup_panel(*this, on_popup_close);
|
||||
pp::panopainter::release_legacy_mouse_capture(*this);
|
||||
if (m_parent)
|
||||
{
|
||||
pp::panopainter::detach_legacy_node_from_parent(*this);
|
||||
}
|
||||
if (on_popup_close)
|
||||
{
|
||||
on_popup_close(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -500,11 +660,25 @@ Action* ActionLayerMove::get_redo()
|
||||
|
||||
void ActionLayerMove::undo()
|
||||
{
|
||||
int old_idx = m_panel->m_layers_container->get_child_index(m_layer_node.get());
|
||||
m_panel->m_layers_container->move_child_offset(m_layer_node.get(), -m_offset);
|
||||
int new_idx = m_panel->m_layers_container->get_child_index(m_layer_node.get());
|
||||
if (!m_panel || !m_layer_node) {
|
||||
return;
|
||||
}
|
||||
auto* layer = dynamic_cast<NodeLayer*>(m_layer_node.get());
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
const int old_idx = find_layer_index(m_panel->m_layers, layer);
|
||||
if (old_idx < 0) {
|
||||
return;
|
||||
}
|
||||
m_panel->m_layers_container->move_child_offset(layer, -m_offset);
|
||||
const int new_idx = m_panel->m_layers_container->get_child_index(layer);
|
||||
if (new_idx < 0) {
|
||||
return;
|
||||
}
|
||||
if (m_panel->on_layer_order && old_idx != new_idx)
|
||||
{
|
||||
move_layer_entry(m_panel->m_layers, old_idx, new_idx);
|
||||
m_panel->on_layer_order(m_panel, old_idx, new_idx);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user