1 /// Overlay I/O exists to provide nodes with the ability to add and control arbitrarily placed content, *laid over*
2 /// the remaining content.
3 ///
4 /// Typical examples of overlay content are context and dropdown menus, such that list navigation options and controls
5 /// separately from the rest, but also popup and modal windows, which appear over other content. Overlay components
6 /// are also used to guide drag-and-drop interactions.
7 ///
8 /// In Fluid, overlays may be limited to the window or canvas, as they are in [Raylib][fluid.raylib_view]. Other
9 /// setups may allow overlays to exceed window boundaries, which is common practice to give context menus more space.
10 ///
11 /// To use Overlay I/O, an `OverlayIO` instance must be active in the tree (activated through `Node.implementIO`)
12 /// to provide space for overlay nodes. A child node can then create overlays by loading the system with `Node.use`
13 /// or `Node.require` and calling `OverlayIO.addOverlay`.
14 ///
15 /// History:
16 ///     * Introduced in Fluid 0.7.2 ([#319](https://git.samerion.com/Samerion/Fluid/issues/319))
17 module fluid.io.overlay;
18 
19 import fluid.types;
20 
21 import fluid.future.context;
22 
23 @safe:
24 
25 /// This interface defines a way to create and operate overlay content.
26 ///
27 /// Instances of `OverlayIO` keep track of content as it is created and removed, and lay it out on the screen
28 /// using available methods.
29 interface OverlayIO : IO {
30 
31     /// Defines known types of overlays. To use a type from this list, use `types`, spelled lowercase.
32     enum Types {
33 
34         /// A dialog window, often serving to ask for confirmation or warning the user.
35         dialog,
36 
37         /// A context menu, usually invoked by pressing the secondary mouse button, or the keyboard "menu" key.
38         context,
39 
40         /// Dropdown menu, often used to select one option from a list of many, or opened from the app's
41         /// [menu bar](https://en.wikipedia.org/wiki/Menu_bar), if it has one.
42         dropdown,
43 
44         /// A tooltip explaining the purpose or usage of a user interface component.
45         tooltip,
46 
47         /// A drag-and-drop object.
48         draggable,
49 
50         contextMenu = context,
51 
52     }
53 
54     /// Get an overlay type defined in `OverlayIO`.
55     ///
56     /// For example, to get an appropriate overlay type for a context menu, use `OverlayIO.types.context`.
57     ///
58     /// Returns:
59     ///     A special struct that contains methods for creating instances of `OverlayType`
60     ///     for types defined by `OverlayIO`.
61     static types() {
62 
63         struct TypeDispatcher {
64 
65             static OverlayType opDispatch(string name)()
66             if (__traits(hasMember, Types, name))
67             do {
68                 const type = __traits(getMember, Types, name);
69                 return OverlayType(ioID!OverlayIO, type);
70             }
71 
72         }
73 
74         return TypeDispatcher();
75 
76     }
77 
78     /// `types` is a shorthand that fills in the correct IO ID and type into `OverlayType`'s fields.
79     @("OverlayIO.types returns valid overlays")
80     unittest {
81 
82         assert(OverlayIO.types.context == OverlayType(ioID!OverlayIO, OverlayIO.Types.context));
83         assert(OverlayIO.types.tooltip == OverlayType(ioID!OverlayIO, OverlayIO.Types.tooltip));
84         assert(OverlayIO.types.contextMenu == OverlayType(ioID!OverlayIO, OverlayIO.Types.contextMenu));
85 
86     }
87 
88     /// Insert new overlay content.
89     ///
90     /// Overlay content should remain alive until the node specifies a `toRemove` status.
91     /// Overlays should not be added if they're not already in the node tree.
92     ///
93     /// See_Also:
94     ///     `addChildOverlay`
95     /// Params:
96     ///     node = Node containing the overlay content.
97     ///         It must be a `Node` instance that implements the `Overlayable` interface.
98     ///         Implementations should reject (through an `AssertError`) any objects that do not inherit from `Node`.
99     ///     type = Type of the overlay node, as a fallback sequence.
100     ///         This information that can be used to guide the overlay system by identifying the overlay's purpose.
101     ///         See `OverlayIO.Types` and `OverlayIO.types` for commonly used types.
102     ///
103     ///         The system should choose the first type from the list that it supports.
104     ///         If none of the types in the list are recognized, `OverlayType.init` should be assumed.
105     ///         All overlay systems must support `OverlayType.init` as a general purpose overlay.
106     void addOverlay(Overlayable node, OverlayType[] type...) nothrow;
107 
108     /// Insert overlay content as a child of another.
109     ///
110     /// A child overlay is bound to its parent overlay, so if the parent is removed, the child should be removed too.
111     ///
112     /// See_Also:
113     ///     `addOverlay`
114     /// Params:
115     ///     parent = Parent node for the new overlay.
116     ///     node   = Child node; overlay to add. Same restrictions apply as for `addOverlay`.
117     ///     type   = Type of the overlay as a fallback sequence.
118     void addChildOverlay(Overlayable parent, Overlayable node, OverlayType[] type...) nothrow;
119 
120 }
121 
122 /// Defines a node that can be used as an overlay through `OverlayIO`.
123 ///
124 /// See_Also:
125 ///     `fluid.io.overlay`, `OverlayIO`.
126 interface Overlayable {
127 
128     /// An anchor the node is bound to, used for positioning the overlay.
129     ///
130     /// The overlay should be aligned to one of the rectangle's corners or edges, so that a point in the node's
131     /// rectangle should lie in the outline of the anchor. The node's `layout` property can be used for this:
132     ///
133     /// * For a `(start, start)` alignment, the point should be in the *top-left* corner of the overlay.
134     /// * For an `(end, end)` alignment, the point should lie in the *bottom-right* corner.
135     /// * An alignment value of `center` places the point in the *center* on the specified axis.
136     /// * The special value *fill* can be used to mean automatic alignment; use an alignment that is the best fit
137     ///   for the available space.
138     ///
139     /// Even for overlays that are outside of the window's boundary, the rectangle should be in window space,
140     /// so that `(0,0)` is the window's top-left corner.
141     ///
142     /// Params:
143     ///     space = Space available for the overlay, within which the anchor should be placed.
144     ///         This may be the screen (relative to the window's position), the window itself,
145     ///         or a fragment of the window.
146     /// Returns:
147     ///     The anchor rectangle to use for positioning the node.
148     Rectangle getAnchor(Rectangle space) const nothrow;
149 
150     /// Memory safe and `const` object comparison.
151     /// Returns:
152     ///     True if this, and the other object, are the same object.
153     /// Params:
154     ///     other = Object to compare to.
155     bool opEquals(const Object other) const;
156 
157 }
158 
159 /// Overlay type is used to specify the purpose of an overlay, and act as a guide for the overlay system's operations.
160 ///
161 /// Windowing systems commonly accept a window type specification which can aid in window management.
162 /// For example, it can be used by the system to style the overlay appropriately.
163 ///
164 /// Overlay types are extensible, and each I/O system can define their own set of types. Commonly used types such as
165 /// `dropdown` or `contextMenu` are defined as a part of `OverlayIO` and can be found in `OverlayIO.types`.
166 /// The `io` field specifies the I/O system, and the `number` field is used to distinguish between different types
167 /// that the system has defined.
168 ///
169 /// The special overlay type `OverlayType.init` with `io` set to `null` and number set to `0` is used to specify
170 /// a general purpose overlay type with no extra specification.
171 struct OverlayType {
172 
173     /// ID of the I/O system defining the overlay type.
174     IOID ioID;
175 
176     /// Number representing the type of the overlay. Meaning of this field is defined by the I/O system, but usually
177     /// it corresponds to an enum member, as it does for `OverlayIO`.
178     int number;
179 
180 }