Narrow retained UI overlay lifetime debt
This commit is contained in:
@@ -8,8 +8,86 @@
|
||||
#include "node_popup_menu.h"
|
||||
#include "node_progress_bar.h"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
namespace {
|
||||
|
||||
struct LegacyOverlayContext {
|
||||
pp::ui::NodeHandle root_handle {};
|
||||
pp::ui::NodeLifetimeTree tree {};
|
||||
std::unique_ptr<pp::ui::UiOverlayLifetime> overlays {};
|
||||
std::unordered_map<Node*, pp::ui::NodeHandle> overlay_handles {};
|
||||
};
|
||||
|
||||
using LegacyOverlayContextMap = std::unordered_map<Node*, LegacyOverlayContext>;
|
||||
|
||||
LegacyOverlayContextMap& overlay_contexts()
|
||||
{
|
||||
static LegacyOverlayContextMap contexts {};
|
||||
return contexts;
|
||||
}
|
||||
|
||||
pp::foundation::Result<LegacyOverlayContext*> get_overlay_context(Node& anchor, bool create_if_missing) noexcept
|
||||
{
|
||||
auto* root = anchor.root();
|
||||
if (!root) {
|
||||
return pp::foundation::Result<LegacyOverlayContext*>::failure(
|
||||
pp::foundation::Status::invalid_argument("legacy overlay root is missing"));
|
||||
}
|
||||
|
||||
auto& contexts = overlay_contexts();
|
||||
auto it = contexts.find(root);
|
||||
if (it == contexts.end()) {
|
||||
if (!create_if_missing) {
|
||||
return pp::foundation::Result<LegacyOverlayContext*>::failure(
|
||||
pp::foundation::Status::invalid_argument("legacy overlay registry is missing"));
|
||||
}
|
||||
it = contexts.try_emplace(root, LegacyOverlayContext {}).first;
|
||||
}
|
||||
|
||||
auto& context = it->second;
|
||||
if (!context.overlays) {
|
||||
const auto root_handle = context.tree.create_root();
|
||||
if (!root_handle) {
|
||||
return pp::foundation::Result<LegacyOverlayContext*>::failure(root_handle.status());
|
||||
}
|
||||
|
||||
context.root_handle = root_handle.value();
|
||||
context.overlays = std::make_unique<pp::ui::UiOverlayLifetime>(context.tree, context.root_handle);
|
||||
}
|
||||
|
||||
return pp::foundation::Result<LegacyOverlayContext*>::success(&context);
|
||||
}
|
||||
|
||||
Node* overlay_node_for_handle(
|
||||
const LegacyOverlayContext& context,
|
||||
pp::ui::NodeHandle overlay) noexcept
|
||||
{
|
||||
for (auto& entry : context.overlay_handles) {
|
||||
if (entry.second == overlay) {
|
||||
return entry.first;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void forget_overlay_by_handle(LegacyOverlayContext& context, pp::ui::NodeHandle overlay) noexcept
|
||||
{
|
||||
for (auto it = context.overlay_handles.begin(); it != context.overlay_handles.end();) {
|
||||
if (it->second == overlay) {
|
||||
it = context.overlay_handles.erase(it);
|
||||
break;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void initialize_legacy_overlay_node(App& app, Node& node)
|
||||
{
|
||||
node.set_manager(&app.layout);
|
||||
@@ -30,6 +108,17 @@ void detach_legacy_node_from_parent(Node& node)
|
||||
|
||||
void close_legacy_dialog_node(Node& node)
|
||||
{
|
||||
const auto context = get_overlay_context(node, false);
|
||||
if (context) {
|
||||
auto it = context.value()->overlay_handles.find(&node);
|
||||
if (it != context.value()->overlay_handles.end()) {
|
||||
const auto status = close_legacy_overlay_node(node, it->second);
|
||||
if (status.ok()) {
|
||||
return;
|
||||
}
|
||||
context.value()->overlay_handles.erase(it);
|
||||
}
|
||||
}
|
||||
destroy_legacy_node(node);
|
||||
}
|
||||
|
||||
@@ -57,6 +146,26 @@ void close_legacy_popup_overlay(Node& node) noexcept
|
||||
destroy_legacy_node(node);
|
||||
}
|
||||
|
||||
void close_legacy_overlay_handle_ignoring_status(
|
||||
Node& anchor,
|
||||
pp::ui::NodeHandle overlay) noexcept
|
||||
{
|
||||
(void)close_legacy_overlay_node(anchor, overlay);
|
||||
}
|
||||
|
||||
void close_legacy_overlay_handles_if_open(
|
||||
Node& anchor,
|
||||
const pp::foundation::Result<pp::ui::NodeHandle>& popup_overlay,
|
||||
const pp::foundation::Result<pp::ui::NodeHandle>& 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());
|
||||
}
|
||||
}
|
||||
|
||||
void close_legacy_dialog_and_hide_keyboard(App& app, Node& node)
|
||||
{
|
||||
close_legacy_dialog_node(node);
|
||||
@@ -110,6 +219,57 @@ pp::foundation::Status attach_legacy_overlay_node_to_root(
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Result<pp::ui::NodeHandle> open_legacy_overlay_node_with_handle(
|
||||
Node& anchor,
|
||||
const std::shared_ptr<Node>& node,
|
||||
bool modal) noexcept
|
||||
{
|
||||
if (!node) {
|
||||
return pp::foundation::Result<pp::ui::NodeHandle>::failure(
|
||||
pp::foundation::Status::invalid_argument("legacy overlay node is null"));
|
||||
}
|
||||
|
||||
const auto context = get_overlay_context(anchor, true);
|
||||
if (!context) {
|
||||
return pp::foundation::Result<pp::ui::NodeHandle>::failure(
|
||||
context.status());
|
||||
}
|
||||
|
||||
auto overlay = context.value()->overlays->open_dialog(modal);
|
||||
if (!overlay) {
|
||||
return pp::foundation::Result<pp::ui::NodeHandle>::failure(overlay.status());
|
||||
}
|
||||
|
||||
const auto status = attach_legacy_overlay_node_to_root(anchor, node);
|
||||
if (!status.ok()) {
|
||||
(void)context.value()->overlays->close(overlay.value());
|
||||
return pp::foundation::Result<pp::ui::NodeHandle>::failure(status);
|
||||
}
|
||||
|
||||
context.value()->overlay_handles[node.get()] = overlay.value();
|
||||
return pp::foundation::Result<pp::ui::NodeHandle>::success(overlay.value());
|
||||
}
|
||||
|
||||
pp::foundation::Status close_legacy_overlay_node(Node& anchor, pp::ui::NodeHandle overlay) noexcept
|
||||
{
|
||||
const auto context = get_overlay_context(anchor, false);
|
||||
if (!context) {
|
||||
return pp::foundation::Status::invalid_argument("legacy overlay registry is missing");
|
||||
}
|
||||
|
||||
const auto status = context.value()->overlays->close(overlay);
|
||||
if (!status.ok()) {
|
||||
forget_overlay_by_handle(*context.value(), overlay);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (auto* raw_overlay = overlay_node_for_handle(*context.value(), overlay)) {
|
||||
destroy_legacy_node(*raw_overlay);
|
||||
}
|
||||
forget_overlay_by_handle(*context.value(), overlay);
|
||||
return status;
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::shared_ptr<NodePopupMenu>> add_legacy_popup_menu(
|
||||
App& app,
|
||||
const char* template_id,
|
||||
|
||||
Reference in New Issue
Block a user