1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include "BsPrerequisites.h" |
6 | #include "GUI/BsGUIElementBase.h" |
7 | #include "GUI/BsGUIOptions.h" |
8 | #include "Math/BsRect2I.h" |
9 | #include "Math/BsVector2I.h" |
10 | #include "Image/BsColor.h" |
11 | |
12 | namespace bs |
13 | { |
14 | class GUINavGroup; |
15 | |
16 | /** @addtogroup Implementation |
17 | * @{ |
18 | */ |
19 | |
20 | enum class GUIElementOption |
21 | { |
22 | /** |
23 | * Enable this option if you want pointer events to pass through this element by default. This will allow elements |
24 | * underneath this element to receive pointer events. |
25 | */ |
26 | ClickThrough = 0x01, |
27 | |
28 | /** |
29 | * Enable this option if the element accepts keyboard/gamepad input focus. This will allow the element to be |
30 | * navigated to using keys/buttons. |
31 | */ |
32 | AcceptsKeyFocus = 0x02 |
33 | }; |
34 | |
35 | typedef Flags<GUIElementOption> GUIElementOptions; |
36 | BS_FLAGS_OPERATORS(GUIElementOption) |
37 | |
38 | /** |
39 | * Represents parent class for all visible GUI elements. Contains methods needed for positioning, rendering and |
40 | * handling input. |
41 | */ |
42 | class BS_EXPORT GUIElement : public GUIElementBase |
43 | { |
44 | public: |
45 | /** Different sub-types of GUI elements. */ |
46 | enum class ElementType |
47 | { |
48 | Label, |
49 | Button, |
50 | Toggle, |
51 | Texture, |
52 | InputBox, |
53 | ListBox, |
54 | ScrollArea, |
55 | Layout, |
56 | Undefined |
57 | }; |
58 | |
59 | public: |
60 | GUIElement(String styleName, const GUIDimensions& dimensions, GUIElementOptions options = GUIElementOptions(0)); |
61 | virtual ~GUIElement() = default; |
62 | |
63 | /** |
64 | * Change the GUI element focus state. |
65 | * |
66 | * @param[in] enabled Give the element focus or take it away. |
67 | * @param[in] clear If true the focus will be cleared from any elements currently in focus. Otherwise |
68 | * the element will just be appended to the in-focus list (if enabling focus). |
69 | */ |
70 | virtual void setFocus(bool enabled, bool clear = false); |
71 | |
72 | /** Sets the tint of the GUI element. */ |
73 | virtual void setTint(const Color& color); |
74 | |
75 | /** @copydoc GUIElementBase::resetDimensions */ |
76 | void resetDimensions() override; |
77 | |
78 | /** Sets new style to be used by the element. */ |
79 | void setStyle(const String& styleName); |
80 | |
81 | /** Returns the name of the style used by this element. */ |
82 | const String& getStyleName() const { return mStyleName; } |
83 | |
84 | /** A set of flags controlling various aspects of the GUIElement. See GUIElementOptions. */ |
85 | void setOptionFlags(GUIElementOptions options) { mOptionFlags = options; } |
86 | |
87 | /** @copydoc setOptionFlags */ |
88 | GUIElementOptions getOptionFlags() const { return mOptionFlags; } |
89 | |
90 | /** |
91 | * Assigns a new context menu that will be opened when the element is right clicked. Null is allowed in case no |
92 | * context menu is wanted. |
93 | */ |
94 | void (const SPtr<GUIContextMenu>& ) { mContextMenu = menu; } |
95 | |
96 | /** |
97 | * Sets a navigation group that determines in what order are GUI elements visited when using a keyboard or gamepad |
98 | * to switch between the elements. If you don't set a navigation group the elements will inherit the default |
99 | * navigation group from their parent GUIWidget. Also see setNavGroupIndex(). |
100 | */ |
101 | void setNavGroup(const SPtr<GUINavGroup>& navGroup); |
102 | |
103 | /** |
104 | * Sets the index that determines in what order is the element visited compared to all the other elements in the |
105 | * nav-group. Elements with lower index will be visited before elements with a higher index. Elements with index |
106 | * 0 (the default) are special and will have their visit order determines by their position compared to other |
107 | * elements. The applied index is tied to the nav-group, so if the nav-group changes the index will need to be |
108 | * re-applied. |
109 | */ |
110 | void setNavGroupIndex(INT32 index); |
111 | |
112 | /** @copydoc GUIElementBase::getVisibleBounds */ |
113 | Rect2I getVisibleBounds() override; |
114 | |
115 | /** |
116 | * Destroy the element. Removes it from parent and widget, and queues it for deletion. Element memory will be |
117 | * released delayed, next frame. |
118 | */ |
119 | static void destroy(GUIElement* element); |
120 | |
121 | /** Triggered when the element loses or gains focus. */ |
122 | Event<void(bool)> onFocusChanged; |
123 | |
124 | public: // ***** INTERNAL ****** |
125 | /** @name Internal |
126 | * @{ |
127 | */ |
128 | |
129 | /** |
130 | * Returns the number of separate render elements in the GUI element. |
131 | * |
132 | * @return The number render elements. |
133 | * |
134 | * @note |
135 | * GUI system attempts to reduce the number of GUI meshes so it will group sprites based on their material and |
136 | * textures. One render elements represents a group of such sprites that share a material/texture. |
137 | */ |
138 | virtual UINT32 _getNumRenderElements() const = 0; |
139 | |
140 | /** |
141 | * Gets a material for the specified render element index. |
142 | * |
143 | * @return Handle to the material. |
144 | * |
145 | * @see _getNumRenderElements() |
146 | */ |
147 | virtual const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const = 0; |
148 | |
149 | /** |
150 | * Returns the type of mesh and number of vertices and indices that the specified render element will use. You will |
151 | * need this value when creating the buffers before calling _fillBuffer(). |
152 | * |
153 | * @see _getNumRenderElements() |
154 | * @see _fillBuffer() |
155 | */ |
156 | virtual void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const = 0; |
157 | |
158 | /** |
159 | * Fill the pre-allocated vertex, uv and index buffers with the mesh data for the specified render element. |
160 | * |
161 | * @param[out] vertices Previously allocated buffer where to store the vertices. Output is expected |
162 | * to match the GUIMeshType as returned by _getMeshInfo. |
163 | * @param[out] indices Previously allocated buffer where to store the indices. |
164 | * @param[in] vertexOffset At which vertex should the method start filling the buffer. |
165 | * @param[in] indexOffset At which index should the method start filling the buffer. |
166 | * @param[in] maxNumVerts Total number of vertices the buffers were allocated for. Used only for memory |
167 | * safety. |
168 | * @param[in] maxNumIndices Total number of indices the buffers were allocated for. Used only for memory |
169 | * safety. |
170 | * @param[in] renderElementIdx Zero-based index of the render element. |
171 | * |
172 | * @see _getNumRenderElements() |
173 | * @see _getMeshInfo() |
174 | */ |
175 | virtual void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset, |
176 | UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const = 0; |
177 | |
178 | /** |
179 | * Recreates the internal render elements. Must be called before fillBuffer if element is dirty. Marks the element |
180 | * as non dirty. |
181 | */ |
182 | void _updateRenderElements(); |
183 | |
184 | /** Gets internal element style representing the exact type of GUI element in this object. */ |
185 | virtual ElementType _getElementType() const { return ElementType::Undefined; } |
186 | |
187 | /** |
188 | * Called when a mouse event is received on any GUI element the mouse is interacting with. Return true if you have |
189 | * processed the event and don't want other elements to process it. |
190 | */ |
191 | virtual bool _mouseEvent(const GUIMouseEvent& ev); |
192 | |
193 | /** |
194 | * Called when some text is input and the GUI element has input focus. Return true if you have processed the event |
195 | * and don't want other elements to process it. |
196 | */ |
197 | virtual bool _textInputEvent(const GUITextInputEvent& ev); |
198 | |
199 | /** |
200 | * Called when a command event is triggered. Return true if you have processed the event and don't want other |
201 | * elements to process it. |
202 | */ |
203 | virtual bool _commandEvent(const GUICommandEvent& ev); |
204 | |
205 | /** |
206 | * Called when a virtual button is pressed/released and the GUI element has input focus. Return true if you have |
207 | * processed the event and don't want other elements to process it. |
208 | */ |
209 | virtual bool _virtualButtonEvent(const GUIVirtualButtonEvent& ev); |
210 | |
211 | /** Set element part of element depth. Less significant than both widget and area depth. */ |
212 | void _setElementDepth(UINT8 depth); |
213 | |
214 | /** Retrieve element part of element depth. Less significant than both widget and area depth. */ |
215 | UINT8 _getElementDepth() const; |
216 | |
217 | /** @copydoc GUIElementBase::_setLayoutData */ |
218 | void _setLayoutData(const GUILayoutData& data) override; |
219 | |
220 | /** @copydoc GUIElementBase::_changeParentWidget */ |
221 | void _changeParentWidget(GUIWidget* widget) override; |
222 | |
223 | /** |
224 | * Returns depth for a specific render element. This contains a combination of widget depth (8 bit(, area depth |
225 | * (16 bit) and render element depth (8 bit). |
226 | * |
227 | * @see _getNumRenderElements |
228 | */ |
229 | virtual UINT32 _getRenderElementDepth(UINT32 renderElementIdx) const { return _getDepth(); } |
230 | |
231 | /** |
232 | * Returns the range of depths that the child elements can be rendered it. |
233 | * |
234 | * @note |
235 | * For example if you are rendering a button with an image and a text you will want the text to be rendered in front |
236 | * of the image at a different depth, which means the depth range is 2 (0 for text, 1 for background image). |
237 | */ |
238 | virtual UINT32 _getRenderElementDepthRange() const { return 1; } |
239 | |
240 | /** Gets internal element style representing the exact type of GUI element in this object. */ |
241 | Type _getType() const override { return GUIElementBase::Type::Element; } |
242 | |
243 | /** Checks if element has been destroyed and is queued for deletion. */ |
244 | bool _isDestroyed() const override { return mIsDestroyed; } |
245 | |
246 | /** Update element style based on active GUI skin and style name. */ |
247 | void _refreshStyle(); |
248 | |
249 | /** Gets the currently active element style. */ |
250 | const GUIElementStyle* _getStyle() const { return mStyle; } |
251 | |
252 | /** Gets GUI element bounds relative to parent widget, clipped by specified clip rect. */ |
253 | const Rect2I& _getClippedBounds() const { return mClippedBounds; } |
254 | |
255 | /** |
256 | * Returns GUI element padding. Padding is modified by changing element style and determines minimum distance |
257 | * between different GUI elements. |
258 | */ |
259 | const RectOffset& _getPadding() const override; |
260 | |
261 | /** |
262 | * Returns GUI element depth. This includes widget and area depth, but does not include specific per-render-element |
263 | * depth. |
264 | */ |
265 | UINT32 _getDepth() const { return mLayoutData.depth; } |
266 | |
267 | /** Returns the navigation group this element belongs to. See setNavGroup(). */ |
268 | SPtr<GUINavGroup> _getNavGroup() const; |
269 | |
270 | /** Checks is the specified position within GUI element bounds. Position is relative to parent GUI widget. */ |
271 | virtual bool _isInBounds(const Vector2I position) const; |
272 | |
273 | /** Checks if the GUI element has a custom cursor and outputs the cursor type if it does. */ |
274 | virtual bool _hasCustomCursor(const Vector2I position, CursorType& type) const { return false; } |
275 | |
276 | /** Checks if the GUI element accepts a drag and drop operation of the specified type. */ |
277 | virtual bool _acceptDragAndDrop(const Vector2I position, UINT32 typeId) const { return false; } |
278 | |
279 | /** Returns a context menu if a GUI element has one. Otherwise returns nullptr. */ |
280 | virtual SPtr<GUIContextMenu> () const; |
281 | |
282 | /** Returns text to display when hovering over the element. Returns empty string if no tooltip. */ |
283 | virtual String _getTooltip() const { return StringUtil::BLANK; } |
284 | |
285 | /** Returns a clip rectangle relative to the element, used for offsetting the input text. */ |
286 | virtual Vector2I _getTextInputOffset() const { return Vector2I(); } |
287 | |
288 | /** Returns a clip rectangle relative to the element, used for clipping the input text. */ |
289 | virtual Rect2I _getTextInputRect() const { return Rect2I(); } |
290 | |
291 | /** @} */ |
292 | |
293 | protected: |
294 | /** Called whenever render elements are dirty and need to be rebuilt. */ |
295 | virtual void updateRenderElementsInternal(); |
296 | |
297 | /** |
298 | * Called whenever element clipped bounds need to be recalculated. (for example when width, height or clip |
299 | * rectangles changes). |
300 | */ |
301 | virtual void updateClippedBounds(); |
302 | |
303 | /** |
304 | * Helper method that returns style name used by an element of a certain type. If override style is empty, default |
305 | * style for that type is returned. |
306 | */ |
307 | template<class T> |
308 | static const String& getStyleName(const String& overrideStyle) |
309 | { |
310 | if(overrideStyle == StringUtil::BLANK) |
311 | return T::getGUITypeName(); |
312 | |
313 | return overrideStyle; |
314 | } |
315 | |
316 | /** |
317 | * Attempts to find a sub-style for the specified type in the currently set GUI element style. If one cannot be |
318 | * found empty string is returned. |
319 | */ |
320 | const String& getSubStyleName(const String& subStyleTypeName) const; |
321 | |
322 | /** Method that gets triggered whenever element style changes. */ |
323 | virtual void styleUpdated() { } |
324 | |
325 | /** Returns clipped bounds excluding the margins. Relative to parent widget. */ |
326 | Rect2I getCachedVisibleBounds() const; |
327 | |
328 | /** Returns bounds of the content contained within the GUI element. Relative to parent widget. */ |
329 | Rect2I getCachedContentBounds() const; |
330 | |
331 | /** |
332 | * Returns a clip rectangle that can be used for clipping the contents of this GUI element. Clip rect is relative |
333 | * to GUI element origin. |
334 | */ |
335 | Rect2I getCachedContentClipRect() const; |
336 | |
337 | /** Returns the tint that is applied to the GUI element. */ |
338 | Color getTint() const; |
339 | |
340 | bool mIsDestroyed = false; |
341 | GUIElementOptions mOptionFlags; |
342 | Rect2I mClippedBounds; |
343 | |
344 | private: |
345 | static const Color DISABLED_COLOR; |
346 | |
347 | const GUIElementStyle* mStyle; |
348 | String mStyleName; |
349 | |
350 | SPtr<GUIContextMenu> ; |
351 | SPtr<GUINavGroup> mNavGroup; |
352 | Color mColor; |
353 | }; |
354 | |
355 | /** @} */ |
356 | } |