Centralize retained menu popup attachment

This commit is contained in:
2026-06-06 10:37:14 +02:00
parent 65c7716d62
commit 5ff2992c0e
7 changed files with 128 additions and 63 deletions

View File

@@ -24,6 +24,7 @@
#include "legacy_canvas_tool_services.h"
#include "legacy_document_layer_services.h"
#include "legacy_history_services.h"
#include "legacy_ui_overlay_services.h"
#include "settings.h"
#include "serializer.h"
#include "font.h"
@@ -59,6 +60,25 @@ void apply_file_menu_plan(App& app, pp::app::FileMenuCommand command)
pp::panopainter::apply_legacy_file_menu_command(app, command);
}
std::shared_ptr<NodePopupMenu> add_menu_popup(
App& app,
const char* template_id,
glm::vec2 position,
float rtl_anchor_width)
{
const auto popup = pp::panopainter::add_legacy_popup_menu(
app,
template_id,
position.x,
position.y,
rtl_anchor_width);
if (!popup) {
LOG("Popup menu '%s' failed: %s", template_id ? template_id : "<null>", popup.status().message);
return nullptr;
}
return popup.value();
}
pp::app::DocumentLayerMenuPlan make_layer_menu_plan(
pp::app::DocumentLayerMenuCommand command,
App& app)
@@ -655,13 +675,9 @@ void App::init_menu_file()
{
menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
auto popup = layout[const_hash("file-menu")]->m_children[0]->clone<NodePopupMenu>();
popup->update();
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
pos.x = pos.x - popup->m_size.x + menu_file->m_size.x;
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
auto popup = add_menu_popup(*this, "file-menu", pos, menu_file->m_size.x);
if (!popup)
return;
if (auto b = popup->find<NodeButtonCustom>("file-newdoc"))
b->on_click = [this, popup](Node*) {
@@ -714,13 +730,9 @@ void App::init_menu_file()
if (auto b = popup->find<NodeButtonCustom>("file-export-tick"))
b->on_click = [this, b, popup](Node*) {
glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0);
auto subpopup = layout[const_hash("file-submenu-export")]->m_children[0]->clone<NodePopupMenu>();
subpopup->update();
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
pos.x = pos.x - subpopup->m_size.x + b->m_size.x;
subpopup->SetPositioning(YGPositionTypeAbsolute);
subpopup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(subpopup);
auto subpopup = add_menu_popup(*this, "file-submenu-export", pos, b->m_size.x);
if (!subpopup)
return;
subpopup->find<NodeButtonCustom>("file-submenu-export-png")->on_click = [this, subpopup, popup](Node*) {
apply_document_export_menu_plan(*this, pp::app::DocumentExportMenuKind::png);
popup->mouse_release();
@@ -805,13 +817,9 @@ void App::init_menu_edit()
{
menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
auto popup = layout[const_hash("edit-menu")]->m_children[0]->clone<NodePopupMenu>();
popup->update();
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
pos.x = pos.x - popup->m_size.x + menu_file->m_size.x;
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
auto popup = add_menu_popup(*this, "edit-menu", pos, menu_file->m_size.x);
if (!popup)
return;
};
}
}
@@ -824,13 +832,9 @@ void App::init_menu_tools()
{
menu_exp->on_click = [this, menu_exp, main](Node*) {
glm::vec2 pos = menu_exp->m_pos + glm::vec2(0, menu_exp->m_size.y);
auto popup_exp = layout[const_hash("tools-menu")]->m_children[0]->clone<NodePopupMenu>();
popup_exp->update();
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
pos.x = pos.x - popup_exp->m_size.x + menu_exp->m_size.x;
popup_exp->SetPositioning(YGPositionTypeAbsolute);
popup_exp->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup_exp);
auto popup_exp = add_menu_popup(*this, "tools-menu", pos, menu_exp->m_size.x);
if (!popup_exp)
return;
if (auto tick = popup_exp->find<NodeButtonCustom>("tools-panels")) tick->on_click = [this, popup_exp](Node* b)
{
@@ -839,13 +843,9 @@ void App::init_menu_tools()
return;
glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0);
auto popup_time = layout[const_hash("panels-menu")]->m_children[0]->clone<NodePopupMenu>();
popup_time->update();
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
pos.x = pos.x - popup_time->m_size.x + b->m_size.x;
popup_time->SetPositioning(YGPositionTypeAbsolute);
popup_time->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup_time);
auto popup_time = add_menu_popup(*this, "panels-menu", pos, b->m_size.x);
if (!popup_time)
return;
auto visible = [this](Node* panel) {
if (!panel)
@@ -1030,13 +1030,9 @@ void App::init_menu_tools()
return;
glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0);
auto popup_time = layout[const_hash("options-menu")]->m_children[0]->clone<NodePopupMenu>();
popup_time->update();
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
pos.x = pos.x - popup_time->m_size.x + b->m_size.x;
popup_time->SetPositioning(YGPositionTypeAbsolute);
popup_time->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup_time);
auto popup_time = add_menu_popup(*this, "options-menu", pos, b->m_size.x);
if (!popup_time)
return;
if (auto ui_scale = popup_time->find<NodeComboBox>("tools-ui-scale"))
{
@@ -1244,13 +1240,9 @@ void App::init_menu_about()
{
menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
auto popup = layout[const_hash("about-menu")]->m_children[0]->clone<NodePopupMenu>();
popup->update();
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
pos.x = pos.x - popup->m_size.x + menu_file->m_size.x;
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
auto popup = add_menu_popup(*this, "about-menu", pos, menu_file->m_size.x);
if (!popup)
return;
popup->find<NodeButtonCustom>("about-app")->on_click = [this, popup](Node*) {
const auto plan = pp::app::plan_about_menu_command(
@@ -1411,13 +1403,9 @@ void App::init_menu_layer()
{
menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
auto popup = layout[const_hash("layers-menu")]->m_children[0]->clone<NodePopupMenu>();
popup->update();
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
pos.x = pos.x - popup->m_size.x + menu_file->m_size.x;
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
auto popup = add_menu_popup(*this, "layers-menu", pos, menu_file->m_size.x);
if (!popup)
return;
popup->find<NodeButtonCustom>("layer-clear")->on_click = [this, popup](Node*) {
const auto plan = make_layer_menu_plan(pp::app::DocumentLayerMenuCommand::clear, *this);

View File

@@ -3,6 +3,7 @@
#include "app.h"
#include "node.h"
#include "node_popup_menu.h"
namespace pp::panopainter {
@@ -31,4 +32,45 @@ pp::foundation::Status attach_legacy_overlay_node(
return pp::foundation::Status::success();
}
pp::foundation::Result<std::shared_ptr<NodePopupMenu>> add_legacy_popup_menu(
App& app,
const char* template_id,
float x,
float y,
float rtl_anchor_width) noexcept
{
if (!template_id) {
return pp::foundation::Result<std::shared_ptr<NodePopupMenu>>::failure(
pp::foundation::Status::invalid_argument("legacy popup template id is null"));
}
auto* template_root = app.layout[const_hash(template_id)];
if (!template_root || template_root->m_children.empty()) {
return pp::foundation::Result<std::shared_ptr<NodePopupMenu>>::failure(
pp::foundation::Status::invalid_argument("legacy popup template is missing"));
}
auto popup = template_root->m_children[0]->clone<NodePopupMenu>();
if (!popup) {
return pp::foundation::Result<std::shared_ptr<NodePopupMenu>>::failure(
pp::foundation::Status::invalid_argument("legacy popup clone failed"));
}
popup->update();
if (auto* root = app.layout[app.main_id]) {
if (YGNodeStyleGetDirection(root->y_node) == YGDirectionRTL) {
x = x - popup->m_size.x + rtl_anchor_width;
}
}
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(x, y);
const auto status = attach_legacy_overlay_node(app, popup);
if (!status.ok()) {
return pp::foundation::Result<std::shared_ptr<NodePopupMenu>>::failure(status);
}
return pp::foundation::Result<std::shared_ptr<NodePopupMenu>>::success(popup);
}
} // namespace pp::panopainter

View File

@@ -6,6 +6,7 @@
class App;
class Node;
class NodePopupMenu;
namespace pp::panopainter {
@@ -15,6 +16,13 @@ void initialize_legacy_overlay_node(App& app, Node& node);
App& app,
const std::shared_ptr<Node>& node) noexcept;
[[nodiscard]] pp::foundation::Result<std::shared_ptr<NodePopupMenu>> add_legacy_popup_menu(
App& app,
const char* template_id,
float x,
float y,
float rtl_anchor_width) noexcept;
template <class T>
std::shared_ptr<T> make_legacy_overlay_node(App& app)
{