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/BsGUIElement.h"
7#include "2D/BsImageSprite.h"
8#include "Utility/BsEvent.h"
9
10namespace bs
11{
12 /** @addtogroup GUI-Internal
13 * @{
14 */
15
16 /** Flags that control how does a slider handle behave. */
17 enum class GUISliderHandleFlag
18 {
19 /** Slider handle will move horizontally. Cannot be used with the Vertical option. */
20 Horizontal = 1 << 0,
21 /** Slider handle will move vertically. Cannot be used with the Horizontal option. */
22 Vertical = 1 << 1,
23 /**
24 * If enabled, clicking on a specific slider position will cause the handle to jump to that position. If false the
25 * handle will only slightly move in that direction.
26 */
27 JumpOnClick = 1 << 2,
28 /** Determines should the slider handle provide additional side-handles that allow it to be resized. */
29 Resizeable = 1 << 3
30 };
31
32 typedef Flags<GUISliderHandleFlag> GUISliderHandleFlags;
33 BS_FLAGS_OPERATORS(GUISliderHandleFlag);
34
35 /** A handle that can be dragged from its predefined minimum and maximum position, either horizontally or vertically. */
36 class BS_EXPORT GUISliderHandle : public GUIElement
37 {
38 /** Visual state of the handle. */
39 enum class State
40 {
41 Normal, Hover, Active
42 };
43
44 /** State the handle can be in while user is dragging it. */
45 enum class DragState
46 {
47 Normal, LeftResize, RightResize
48 };
49
50 public:
51 /** Returns type name of the GUI element used for finding GUI element styles. */
52 static const String& getGUITypeName();
53
54 /**
55 * Creates a new handle.
56 *
57 * @param[in] flags Flags that control how does the handle behave.
58 * @param[in] styleName Optional style to use for the element. Style will be retrieved from GUISkin of the
59 * GUIWidget the element is used on. If not specified default style is used.
60 */
61 static GUISliderHandle* create(GUISliderHandleFlags flags, const String& styleName = StringUtil::BLANK);
62
63 /**
64 * Creates a new handle.
65 *
66 * @param[in] flags Flags that control how does the handle behave.
67 * @param[in] options Options that allow you to control how is the element positioned and sized.
68 * This will override any similar options set by style.
69 * @param[in] styleName Optional style to use for the element. Style will be retrieved from GUISkin of the
70 * GUIWidget the element is used on. If not specified default style is used.
71 */
72 static GUISliderHandle* create(GUISliderHandleFlags flags, const GUIOptions& options,
73 const String& styleName = StringUtil::BLANK);
74
75 /** Gets the current position of the handle, in percent ranging [0.0f, 1.0f]. */
76 float getHandlePos() const;
77
78 /** Gets the minimum percentual variation of the handle position */
79 float getStep() const;
80
81 /** Returns the position of the slider handle, in pixels. Relative to this object. */
82 INT32 getHandlePosPx() const;
83
84 /** Returns remaining length of the scrollable area not covered by the handle, in pixels. */
85 UINT32 getScrollableSize() const;
86
87 /** Returns the total length of the area the handle can move in, in pixels. */
88 UINT32 getMaxSize() const;
89
90 /**
91 * Sets a step that defines the minimal increment the value can be increased/decreased by. Set to zero to have no
92 * step. In percent.
93 */
94 void setStep(float step);
95
96 /**
97 * Moves the slider handle one step forwards or backwards. Step size is determined by step (if set) or handle size
98 * otherwise. If @p forward is true the handle is moved one step forward, otherwise one step backward.
99 */
100 void moveOneStep(bool forward);
101
102 /** Triggered when the user drags the handle. */
103 Event<void(float pos, float size)> onHandleMovedOrResized;
104
105 public: // ***** INTERNAL ******
106 /** @name Internal
107 * @{
108 */
109
110 /**
111 * Size of the handle in percent of the total draggable area, along the handle drag direction.
112 *
113 * @note Does not trigger layout update.
114 */
115 void _setHandleSize(float pct);
116
117 /**
118 * Moves the handle the the specified position in the handle area.
119 *
120 * @param[in] pct Position to move the handle to, in percent ranging [0.0f, 1.0f]
121 *
122 * @note Does not trigger layout update.
123 */
124 void _setHandlePos(float pct);
125
126 /** Returns the size of the slider handle, in percent of the total area. */
127 float _getHandleSizePct() const;
128
129 /** @copydoc GUIElement::_getOptimalSize */
130 Vector2I _getOptimalSize() const override;
131
132 /** @} */
133 protected:
134 ~GUISliderHandle();
135
136 /** @copydoc GUIElement::_getNumRenderElements() */
137 UINT32 _getNumRenderElements() const override;
138
139 /** @copydoc GUIElement::_getMaterial() */
140 const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
141
142 /** @copydoc GUIElement::_getMeshInfo() */
143 void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
144
145 /** @copydoc GUIElement::_fillBuffer() */
146 void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
147 UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
148
149 /** @copydoc GUIElement::updateRenderElementsInternal() */
150 void updateRenderElementsInternal() override;
151
152 /** @copydoc GUIElement::updateClippedBounds() */
153 void updateClippedBounds() override;
154 private:
155 GUISliderHandle(GUISliderHandleFlags flags, const String& styleName, const GUIDimensions& dimensions);
156
157 /** @copydoc GUIElement::_mouseEvent */
158 bool _mouseEvent(const GUIMouseEvent& ev) override;
159
160 /** Checks are the specified over the scroll handle. Coordinates are relative to the parent widget. */
161 bool isOnHandle(const Vector2I& pos) const;
162
163 /** Sets the position of the slider handle, in pixels. Relative to this object. */
164 void setHandlePosPx(INT32 pos);
165
166 /** Returns the size of the handle button, in pixels. */
167 UINT32 getHandleSize() const;
168
169 /** Gets the currently active texture, depending on handle state. */
170 const HSpriteTexture& getActiveTexture() const;
171
172 /** @copydoc GUIElement::styleUpdated */
173 void styleUpdated() override;
174
175 static const UINT32 RESIZE_HANDLE_SIZE;
176
177 ImageSprite* mImageSprite;
178
179 GUISliderHandleFlags mFlags;
180 UINT32 mMinHandleSize = 0;
181 float mPctHandlePos = 0.0f;
182 float mPctHandleSize = 0.0f;
183 float mStep = 0.0f;
184 INT32 mDragStartPos = 0;
185 DragState mDragState = DragState::Normal;
186 bool mMouseOverHandle = false;
187 bool mHandleDragged = false;
188 State mState = State::Normal;
189 };
190
191 /** @} */
192}