Add UI core node lifetime handles
This commit is contained in:
127
src/ui_core/node_lifetime.h
Normal file
127
src/ui_core/node_lifetime.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace pp::ui {
|
||||
|
||||
inline constexpr std::uint32_t invalid_node_slot = 0xffffffffU;
|
||||
inline constexpr std::uint32_t invalid_connection_slot = 0xffffffffU;
|
||||
|
||||
struct NodeHandle {
|
||||
std::uint32_t slot = invalid_node_slot;
|
||||
std::uint32_t generation = 0;
|
||||
|
||||
[[nodiscard]] constexpr bool valid() const noexcept
|
||||
{
|
||||
return slot != invalid_node_slot && generation != 0U;
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(NodeHandle left, NodeHandle right) noexcept
|
||||
{
|
||||
return left.slot == right.slot && left.generation == right.generation;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator!=(NodeHandle left, NodeHandle right) noexcept
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
struct UiConnection {
|
||||
std::uint32_t slot = invalid_connection_slot;
|
||||
std::uint32_t generation = 0;
|
||||
|
||||
[[nodiscard]] constexpr bool valid() const noexcept
|
||||
{
|
||||
return slot != invalid_connection_slot && generation != 0U;
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(UiConnection left, UiConnection right) noexcept
|
||||
{
|
||||
return left.slot == right.slot && left.generation == right.generation;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator!=(UiConnection left, UiConnection right) noexcept
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
class NodeLifetimeTree;
|
||||
|
||||
class ScopedUiConnection {
|
||||
public:
|
||||
ScopedUiConnection() noexcept = default;
|
||||
ScopedUiConnection(NodeLifetimeTree& tree, UiConnection connection) noexcept;
|
||||
ScopedUiConnection(const ScopedUiConnection&) = delete;
|
||||
ScopedUiConnection& operator=(const ScopedUiConnection&) = delete;
|
||||
ScopedUiConnection(ScopedUiConnection&& other) noexcept;
|
||||
ScopedUiConnection& operator=(ScopedUiConnection&& other) noexcept;
|
||||
~ScopedUiConnection();
|
||||
|
||||
void reset() noexcept;
|
||||
|
||||
[[nodiscard]] UiConnection connection() const noexcept;
|
||||
[[nodiscard]] bool connected() const noexcept;
|
||||
|
||||
private:
|
||||
NodeLifetimeTree* tree_ = nullptr;
|
||||
UiConnection connection_ {};
|
||||
};
|
||||
|
||||
class NodeLifetimeTree {
|
||||
public:
|
||||
using Callback = std::function<void(NodeHandle)>;
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<NodeHandle> create_root();
|
||||
[[nodiscard]] pp::foundation::Result<NodeHandle> create_child(NodeHandle parent);
|
||||
|
||||
[[nodiscard]] bool contains(NodeHandle node) const noexcept;
|
||||
[[nodiscard]] pp::foundation::Result<NodeHandle> parent_of(NodeHandle node) const noexcept;
|
||||
[[nodiscard]] pp::foundation::Result<std::size_t> child_count(NodeHandle node) const noexcept;
|
||||
[[nodiscard]] pp::foundation::Result<NodeHandle> child_at(NodeHandle node, std::size_t index) const noexcept;
|
||||
[[nodiscard]] pp::foundation::Status destroy_subtree(NodeHandle node) noexcept;
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<UiConnection> connect(NodeHandle node, Callback callback);
|
||||
[[nodiscard]] pp::foundation::Result<ScopedUiConnection> scoped_connect(NodeHandle node, Callback callback);
|
||||
[[nodiscard]] pp::foundation::Status disconnect(UiConnection connection) noexcept;
|
||||
[[nodiscard]] pp::foundation::Result<std::size_t> live_connection_count(NodeHandle node) const noexcept;
|
||||
[[nodiscard]] pp::foundation::Status dispatch(NodeHandle node);
|
||||
|
||||
private:
|
||||
struct NodeSlot {
|
||||
std::uint32_t generation = 1;
|
||||
bool alive = false;
|
||||
NodeHandle parent {};
|
||||
std::vector<NodeHandle> children;
|
||||
std::vector<UiConnection> connections;
|
||||
};
|
||||
|
||||
struct ConnectionSlot {
|
||||
std::uint32_t generation = 1;
|
||||
bool alive = false;
|
||||
NodeHandle node {};
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
[[nodiscard]] NodeSlot* node_slot(NodeHandle node) noexcept;
|
||||
[[nodiscard]] const NodeSlot* node_slot(NodeHandle node) const noexcept;
|
||||
[[nodiscard]] ConnectionSlot* connection_slot(UiConnection connection) noexcept;
|
||||
[[nodiscard]] const ConnectionSlot* connection_slot(UiConnection connection) const noexcept;
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<NodeHandle> allocate_node(NodeHandle parent);
|
||||
void unlink_from_parent(NodeHandle node) noexcept;
|
||||
void release_connection(UiConnection connection) noexcept;
|
||||
|
||||
std::vector<NodeSlot> nodes_;
|
||||
std::vector<std::uint32_t> free_nodes_;
|
||||
std::vector<ConnectionSlot> connections_;
|
||||
std::vector<std::uint32_t> free_connections_;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user