MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Surface.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Context.hpp"
4#include "Layer.hpp"
5
6namespace MayaFlux::Core {
7class Window;
8}
9
11
12/**
13 * @class Surface
14 * @brief Named owner of a (Window, Layer, Context) triple - the Forma canvas.
15 *
16 * In Forma, three things always travel together: a Window (the rendering
17 * target and coordinate space), a Layer (the spatial registry of elements),
18 * and a Context (the event router that hit-tests against the layer). They
19 * are the three faces of one concept: the canvas. Surface names that
20 * concept and owns the triple, so that downstream construction functions
21 * accept one argument instead of three.
22 *
23 * Surface is not a widget toolkit, not a layout engine, not an event
24 * dispatcher. It does not know what an element looks like, how a buffer
25 * is built, or where bindings are routed. Construction of FormaBuffers,
26 * Mapped<T>s, and Bridge registrations is the job of the free functions
27 * in Forma.hpp, which take a Surface& as their canvas argument and read
28 * the BufferManager, Bridge, and other module-level state from the
29 * singletons established by Portal::Forma::initialize().
30 *
31 * The Layer and Context owned by Surface remain fully accessible through
32 * the layer() and ctx() accessors. Surface is a named owner, not a wall.
33 * Anything that worked against Layer or Context before continues to work
34 * against surface.layer() and surface.ctx().
35 *
36 * Surface has two constructors:
37 * 1. The default: takes Window + name. Internally creates Layer and
38 * Context. This is the path covered by Portal::Forma::create_surface
39 * in Forma.hpp.
40 * 2. The power-tinkerer: takes Window + pre-built Layer + pre-built
41 * Context. Use this when you need a custom Context subclass, want
42 * to share one Layer across multiple Contexts (split-pane editing),
43 * or are constructing in a test against a non-global EventManager.
44 *
45 * @code
46 * // Default path
47 * auto surface = Portal::Forma::create_surface(window, "plot_live");
48 *
49 * auto el = Portal::Forma::create_element<float>(surface, geom, 0.5F);
50 * surface.ctx().on_press(el.element.id, IO::MouseButtons::Left, ...);
51 *
52 * // Power-tinkerer path: pre-built layer and context
53 * auto layer = std::make_shared<Layer>();
54 * auto ctx = std::make_shared<MyCustomContext>(layer, window, em, "custom");
55 * Surface surface(window, layer, ctx);
56 * @endcode
57 */
58class MAYAFLUX_API Surface {
59public:
60 // =========================================================================
61 // Construction
62 // =========================================================================
63
64 /**
65 * @brief Construct a Surface around a pre-built Layer and Context.
66 *
67 * Surface takes shared ownership of all three components. The caller is
68 * responsible for ensuring the Layer and Context were constructed
69 * against @p window.
70 *
71 * The default factory Portal::Forma::create_surface delegates here
72 * after building a fresh Layer and Context against the global
73 * EventManager. Call this constructor directly when you need a custom
74 * Context subclass or want to share a Layer across multiple Contexts.
75 *
76 * @param window Target window. Must match the window the Context was
77 * constructed against.
78 * @param layer Pre-built Layer.
79 * @param ctx Pre-built Context, already wired to @p window.
80 */
81 Surface(std::shared_ptr<Core::Window> window,
82 std::shared_ptr<Layer> layer,
83 std::shared_ptr<Context> ctx)
84 : m_window(std::move(window))
85 , m_layer(std::move(layer))
86 , m_ctx(std::move(ctx))
87 {
88 }
89
90 ~Surface() = default;
91
92 Surface(const Surface&) = default;
93 Surface& operator=(const Surface&) = default;
94 Surface(Surface&&) noexcept = default;
95 Surface& operator=(Surface&&) noexcept = default;
96
97 // =========================================================================
98 // Accessors - the canvas is never walled off
99 // =========================================================================
100
101 /**
102 * @brief Access the spatial registry.
103 *
104 * Anything supported by Layer is reachable here: add, remove, relate,
105 * set_visible, set_bounds, set_contains, hit_test, etc.
106 */
107 [[nodiscard]] Layer& layer() noexcept { return *m_layer; }
108
109 /// @copydoc layer()
110 [[nodiscard]] const Layer& layer() const noexcept { return *m_layer; }
111
112 /**
113 * @brief Access the event router.
114 *
115 * Anything supported by Context is reachable here: on_press,
116 * on_release, on_move, on_enter, on_leave, on_scroll.
117 */
118 [[nodiscard]] Context& ctx() noexcept { return *m_ctx; }
119
120 /// @copydoc ctx()
121 [[nodiscard]] const Context& ctx() const noexcept { return *m_ctx; }
122
123 /**
124 * @brief Access the rendering target window.
125 */
126 [[nodiscard]] const std::shared_ptr<Core::Window>& window() const noexcept
127 {
128 return m_window;
129 }
130
131 /**
132 * @brief Shared handles for callers that need to keep components alive
133 * independently of the Surface (background tasks, escapes into
134 * coroutines, etc.).
135 */
136 [[nodiscard]] const std::shared_ptr<Layer>& layer_ptr() const noexcept { return m_layer; }
137
138 /// @copydoc layer_ptr()
139 [[nodiscard]] const std::shared_ptr<Context>& ctx_ptr() const noexcept { return m_ctx; }
140
141 // =========================================================================
142 // Element registration passthrough
143 // =========================================================================
144
145 /**
146 * @brief Forward an Element to layer().add() and return the Slot.
147 *
148 * Pure passthrough. Present so that existing patterns like
149 * @code
150 * const uint32_t id = layer->add(std::move(el)).relate_to(parent).id();
151 * @endcode
152 * read as
153 * @code
154 * const uint32_t id = surface.add(std::move(el)).relate_to(parent).id();
155 * @endcode
156 * without forcing the caller to reach through layer() at every step.
157 */
158 Layer::Slot add(Element element) { return m_layer->add(std::move(element)); }
159
160private:
161 std::shared_ptr<Core::Window> m_window;
162 std::shared_ptr<Layer> m_layer;
163 std::shared_ptr<Context> m_ctx;
164};
165
166} // namespace MayaFlux::Portal::Forma
Event wiring between a Layer and a window surface.
Definition Context.hpp:40
Handle returned by Layer::add, carrying the assigned element id.
Definition Layer.hpp:49
Flat registry of Elements on a surface.
Definition Layer.hpp:21
const std::shared_ptr< Layer > & layer_ptr() const noexcept
Shared handles for callers that need to keep components alive independently of the Surface (backgroun...
Definition Surface.hpp:136
const Context & ctx() const noexcept
Access the event router.
Definition Surface.hpp:121
Surface(Surface &&) noexcept=default
const Layer & layer() const noexcept
Access the spatial registry.
Definition Surface.hpp:110
Surface & operator=(const Surface &)=default
Surface(std::shared_ptr< Core::Window > window, std::shared_ptr< Layer > layer, std::shared_ptr< Context > ctx)
Construct a Surface around a pre-built Layer and Context.
Definition Surface.hpp:81
const std::shared_ptr< Context > & ctx_ptr() const noexcept
Shared handles for callers that need to keep components alive independently of the Surface (backgroun...
Definition Surface.hpp:139
const std::shared_ptr< Core::Window > & window() const noexcept
Access the rendering target window.
Definition Surface.hpp:126
std::shared_ptr< Core::Window > m_window
Definition Surface.hpp:161
Context & ctx() noexcept
Access the event router.
Definition Surface.hpp:118
Layer::Slot add(Element element)
Forward an Element to layer().add() and return the Slot.
Definition Surface.hpp:158
Surface(const Surface &)=default
std::shared_ptr< Context > m_ctx
Definition Surface.hpp:163
std::shared_ptr< Layer > m_layer
Definition Surface.hpp:162
Named owner of a (Window, Layer, Context) triple - the Forma canvas.
Definition Surface.hpp:58
A bounded, renderable region on a window surface.
Definition Element.hpp:58