174 lines
4.7 KiB
C++
174 lines
4.7 KiB
C++
#include "ui_core/overlay_lifetime.h"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace pp::ui {
|
|
|
|
UiOverlayLifetime::UiOverlayLifetime(NodeLifetimeTree& tree, NodeHandle root) noexcept
|
|
: tree_(tree)
|
|
, root_(root)
|
|
{
|
|
}
|
|
|
|
pp::foundation::Result<NodeHandle> UiOverlayLifetime::open_popup()
|
|
{
|
|
return open_overlay(root_, UiOverlayKind::popup, true, false);
|
|
}
|
|
|
|
pp::foundation::Result<NodeHandle> UiOverlayLifetime::open_child_popup(NodeHandle parent_popup)
|
|
{
|
|
if (!tracked_alive(parent_popup)) {
|
|
return pp::foundation::Result<NodeHandle>::failure(
|
|
pp::foundation::Status::invalid_argument("child popup requires a live tracked parent popup"));
|
|
}
|
|
|
|
return open_overlay(parent_popup, UiOverlayKind::popup, true, false);
|
|
}
|
|
|
|
pp::foundation::Result<NodeHandle> UiOverlayLifetime::open_dialog(bool modal)
|
|
{
|
|
return open_overlay(root_, UiOverlayKind::dialog, modal, modal);
|
|
}
|
|
|
|
pp::foundation::Status UiOverlayLifetime::close(NodeHandle overlay) noexcept
|
|
{
|
|
if (!tracked_alive(overlay)) {
|
|
return pp::foundation::Status::invalid_argument("overlay close requires a live tracked overlay");
|
|
}
|
|
|
|
const auto status = tree_.destroy_subtree(overlay);
|
|
if (!status.ok()) {
|
|
return status;
|
|
}
|
|
|
|
prune_dead_entries();
|
|
restore_capture(UiCaptureKind::pointer);
|
|
restore_capture(UiCaptureKind::keyboard);
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
void UiOverlayLifetime::clear_for_layout_reload() noexcept
|
|
{
|
|
tree_.clear();
|
|
entries_.clear();
|
|
}
|
|
|
|
bool UiOverlayLifetime::tracks(NodeHandle overlay) const noexcept
|
|
{
|
|
return tracked_alive(overlay);
|
|
}
|
|
|
|
std::size_t UiOverlayLifetime::overlay_count() const noexcept
|
|
{
|
|
std::size_t count = 0;
|
|
for (const auto& entry : entries_) {
|
|
if (tree_.contains(entry.node)) {
|
|
++count;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
pp::foundation::Result<NodeHandle> UiOverlayLifetime::top_overlay() const noexcept
|
|
{
|
|
for (auto index = entries_.size(); index > 0U; --index) {
|
|
const auto& entry = entries_[index - 1U];
|
|
if (tree_.contains(entry.node)) {
|
|
return pp::foundation::Result<NodeHandle>::success(entry.node);
|
|
}
|
|
}
|
|
|
|
return pp::foundation::Result<NodeHandle>::failure(
|
|
pp::foundation::Status::invalid_argument("overlay stack is empty"));
|
|
}
|
|
|
|
pp::foundation::Result<NodeHandle> UiOverlayLifetime::open_overlay(
|
|
NodeHandle parent,
|
|
UiOverlayKind kind,
|
|
bool captures_pointer,
|
|
bool captures_keyboard)
|
|
{
|
|
if (!tree_.contains(root_)) {
|
|
return pp::foundation::Result<NodeHandle>::failure(
|
|
pp::foundation::Status::invalid_argument("overlay root is not live"));
|
|
}
|
|
|
|
if (!tree_.contains(parent)) {
|
|
return pp::foundation::Result<NodeHandle>::failure(
|
|
pp::foundation::Status::invalid_argument("overlay parent is not live"));
|
|
}
|
|
|
|
auto node = tree_.create_child(parent);
|
|
if (!node) {
|
|
return node;
|
|
}
|
|
|
|
if (captures_pointer) {
|
|
const auto status = tree_.capture(UiCaptureKind::pointer, node.value());
|
|
if (!status.ok()) {
|
|
(void)tree_.destroy_subtree(node.value());
|
|
return pp::foundation::Result<NodeHandle>::failure(status);
|
|
}
|
|
}
|
|
|
|
if (captures_keyboard) {
|
|
const auto status = tree_.capture(UiCaptureKind::keyboard, node.value());
|
|
if (!status.ok()) {
|
|
(void)tree_.destroy_subtree(node.value());
|
|
return pp::foundation::Result<NodeHandle>::failure(status);
|
|
}
|
|
}
|
|
|
|
entries_.push_back(UiOverlayEntry {
|
|
.node = node.value(),
|
|
.parent = parent,
|
|
.kind = kind,
|
|
.captures_pointer = captures_pointer,
|
|
.captures_keyboard = captures_keyboard,
|
|
});
|
|
return node;
|
|
}
|
|
|
|
void UiOverlayLifetime::prune_dead_entries() noexcept
|
|
{
|
|
entries_.erase(
|
|
std::remove_if(
|
|
entries_.begin(),
|
|
entries_.end(),
|
|
[this](const UiOverlayEntry& entry) {
|
|
return !tree_.contains(entry.node);
|
|
}),
|
|
entries_.end());
|
|
}
|
|
|
|
void UiOverlayLifetime::restore_capture(UiCaptureKind kind) noexcept
|
|
{
|
|
for (auto index = entries_.size(); index > 0U; --index) {
|
|
const auto& entry = entries_[index - 1U];
|
|
const auto captures = kind == UiCaptureKind::pointer
|
|
? entry.captures_pointer
|
|
: entry.captures_keyboard;
|
|
if (captures && tree_.contains(entry.node)) {
|
|
(void)tree_.capture(kind, entry.node);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UiOverlayLifetime::tracked_alive(NodeHandle overlay) const noexcept
|
|
{
|
|
if (!tree_.contains(overlay)) {
|
|
return false;
|
|
}
|
|
|
|
return std::any_of(
|
|
entries_.begin(),
|
|
entries_.end(),
|
|
[overlay](const UiOverlayEntry& entry) {
|
|
return entry.node == overlay;
|
|
});
|
|
}
|
|
|
|
}
|