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#include "GUI/BsGUISlider.h"
4#include "GUI/BsGUISliderHandle.h"
5#include "GUI/BsGUITexture.h"
6#include "GUI/BsGUIDimensions.h"
7#include "GUI/BsGUICommandEvent.h"
8#include "GUI/BsGUIElementStyle.h"
9
10using namespace std::placeholders;
11
12namespace bs
13{
14 GUISlider::GUISlider(bool horizontal, const String& styleName, const GUIDimensions& dimensions)
15 :GUIElementContainer(dimensions, styleName, GUIElementOption::AcceptsKeyFocus), mHorizontal(horizontal)
16 {
17 GUISliderHandleFlags flags = horizontal ? GUISliderHandleFlag::Horizontal : GUISliderHandleFlag::Vertical;
18 flags |= GUISliderHandleFlag::JumpOnClick;
19
20 mSliderHandle = GUISliderHandle::create(flags, getSubStyleName(getHandleStyleType()));
21 mBackground = GUITexture::create(getSubStyleName(getBackgroundStyleType()));
22 mFillBackground = GUITexture::create(getSubStyleName(getFillStyleType()));
23
24 mBackground->_setElementDepth(mSliderHandle->_getRenderElementDepthRange() + mFillBackground->_getRenderElementDepthRange());
25 mFillBackground->_setElementDepth(mSliderHandle->_getRenderElementDepthRange());
26
27 _registerChildElement(mSliderHandle);
28 _registerChildElement(mBackground);
29 _registerChildElement(mFillBackground);
30
31 mHandleMovedConn = mSliderHandle->onHandleMovedOrResized.connect(std::bind(&GUISlider::onHandleMoved, this, _1, _2));
32 }
33
34 GUISlider::~GUISlider()
35 {
36 mHandleMovedConn.disconnect();
37 }
38
39 const String& GUISlider::getHandleStyleType()
40 {
41 static String HANDLE_STYLE_TYPE = "SliderHandle";
42 return HANDLE_STYLE_TYPE;
43 }
44
45 const String& GUISlider::getBackgroundStyleType()
46 {
47 static String BACKGROUND_STYLE_TYPE = "SliderBackground";
48 return BACKGROUND_STYLE_TYPE;
49 }
50
51 const String& GUISlider::getFillStyleType()
52 {
53 static String FILL_STYLE_TYPE = "SliderFill";
54 return FILL_STYLE_TYPE;
55 }
56
57 Vector2I GUISlider::_getOptimalSize() const
58 {
59 Vector2I optimalSize = mSliderHandle->_getOptimalSize();
60
61 Vector2I backgroundSize = mBackground->_getOptimalSize();
62 optimalSize.x = std::max(optimalSize.x, backgroundSize.x);
63 optimalSize.y = std::max(optimalSize.y, backgroundSize.y);
64
65 return optimalSize;
66 }
67
68 void GUISlider::_updateLayoutInternal(const GUILayoutData& data)
69 {
70 GUILayoutData childData = data;
71
72 if (mHorizontal)
73 {
74 Vector2I optimalSize = mBackground->_getOptimalSize();
75 childData.area.height = optimalSize.y;
76 childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
77
78 childData.clipRect = data.area;
79 childData.clipRect.clip(data.clipRect);
80
81 mBackground->_setLayoutData(childData);
82
83 optimalSize = mSliderHandle->_getOptimalSize();
84 childData.area.height = optimalSize.y;
85 childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
86
87 childData.clipRect = data.area;
88 childData.clipRect.clip(data.clipRect);
89
90 mSliderHandle->_setLayoutData(childData);
91 UINT32 handleWidth = optimalSize.x;
92
93 optimalSize = mFillBackground->_getOptimalSize();
94 childData.area.height = optimalSize.y;
95 childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
96 childData.area.width = mSliderHandle->getHandlePosPx() + handleWidth / 2;
97
98 childData.clipRect = data.area;
99 childData.clipRect.clip(data.clipRect);
100
101 mFillBackground->_setLayoutData(childData);
102 }
103 else
104 {
105 Vector2I optimalSize = mBackground->_getOptimalSize();
106 childData.area.width = optimalSize.x;
107 childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
108
109 childData.clipRect = data.area;
110 childData.clipRect.clip(data.clipRect);
111
112 mBackground->_setLayoutData(childData);
113
114 optimalSize = mSliderHandle->_getOptimalSize();
115 childData.area.width = optimalSize.x;
116 childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
117
118 childData.clipRect = data.area;
119 childData.clipRect.clip(data.clipRect);
120
121 mSliderHandle->_setLayoutData(childData);
122 UINT32 handleHeight = optimalSize.y;
123
124 optimalSize = mFillBackground->_getOptimalSize();
125 childData.area.width = optimalSize.x;
126 childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
127 childData.area.height = mSliderHandle->getHandlePosPx() + handleHeight / 2;
128
129 childData.clipRect = data.area;
130 childData.clipRect.clip(data.clipRect);
131
132 mFillBackground->_setLayoutData(childData);
133 }
134 }
135
136 void GUISlider::styleUpdated()
137 {
138 mBackground->setStyle(getSubStyleName(getBackgroundStyleType()));
139 mFillBackground->setStyle(getSubStyleName(getFillStyleType()));
140 mSliderHandle->setStyle(getSubStyleName(getHandleStyleType()));
141
142 const GUIElementStyle* bgStyle = mBackground->_getStyle();
143 if(mHasFocus)
144 mBackground->setTexture(bgStyle->focused.texture);
145 else
146 mBackground->setTexture(bgStyle->normal.texture);
147 }
148
149 void GUISlider::setPercent(float pct)
150 {
151 float oldHandlePos = mSliderHandle->getHandlePos();
152 mSliderHandle->_setHandlePos(pct);
153
154 if (oldHandlePos != mSliderHandle->getHandlePos())
155 mSliderHandle->_markLayoutAsDirty();
156 }
157
158 float GUISlider::getPercent() const
159 {
160 return mSliderHandle->getHandlePos();
161 }
162
163 float GUISlider::getValue() const
164 {
165 float diff = mMaxRange - mMinRange;
166 return mMinRange + diff * mSliderHandle->getHandlePos();
167 }
168
169 void GUISlider::setValue(float value)
170 {
171 float diff = mMaxRange - mMinRange;
172 float pct = (value - mMinRange) / diff;
173
174 setPercent(pct);
175 }
176
177 void GUISlider::setRange(float min, float max)
178 {
179 mMinRange = min;
180 mMaxRange = max;
181 }
182
183 float GUISlider::getRangeMaximum() const
184 {
185 return mMaxRange;
186 }
187
188 float GUISlider::getRangeMinimum() const
189 {
190 return mMinRange;
191 }
192
193 void GUISlider::setStep(float step)
194 {
195 float range = mMaxRange - mMinRange;
196 if(range > 0.0f)
197 step = step / range;
198 else
199 step = 0.0f;
200
201 mSliderHandle->setStep(step);
202 }
203
204 float GUISlider::getStep() const
205 {
206 return mSliderHandle->getStep();
207 }
208
209 void GUISlider::setTint(const Color& color)
210 {
211 mBackground->setTint(color);
212 mSliderHandle->setTint(color);
213 }
214
215 void GUISlider::onHandleMoved(float newPosition, float newSize)
216 {
217 onChanged(getValue());
218 }
219
220 bool GUISlider::_commandEvent(const GUICommandEvent& ev)
221 {
222 const bool baseReturnValue = GUIElement::_commandEvent(ev);
223
224 const GUIElementStyle* bgStyle = mBackground->_getStyle();
225 if(ev.getType() == GUICommandEventType::FocusGained)
226 {
227 mHasFocus = true;
228
229 if(!_isDisabled())
230 mBackground->setTexture(bgStyle->focused.texture);
231
232 return true;
233 }
234 else if(ev.getType() == GUICommandEventType::FocusLost)
235 {
236 mHasFocus = false;
237 mBackground->setTexture(bgStyle->normal.texture);
238
239 return true;
240 }
241 else if(ev.getType() == GUICommandEventType::MoveLeft)
242 {
243 mSliderHandle->moveOneStep(false);
244 return true;
245 }
246 else if(ev.getType() == GUICommandEventType::MoveRight)
247 {
248 mSliderHandle->moveOneStep(true);
249 return true;
250 }
251
252 return baseReturnValue;
253 }
254
255 GUISliderHorz::GUISliderHorz(const String& styleName, const GUIDimensions& dimensions)
256 :GUISlider(true, styleName, dimensions)
257 {
258
259 }
260
261 GUISliderHorz* GUISliderHorz::create(const String& styleName)
262 {
263 return new (bs_alloc<GUISliderHorz>()) GUISliderHorz(getStyleName<GUISliderHorz>(styleName), GUIDimensions::create());
264 }
265
266 GUISliderHorz* GUISliderHorz::create(const GUIOptions& options, const String& styleName)
267 {
268 return new (bs_alloc<GUISliderHorz>()) GUISliderHorz(getStyleName<GUISliderHorz>(styleName), GUIDimensions::create(options));
269 }
270
271 const String& GUISliderHorz::getGUITypeName()
272 {
273 static String typeName = "SliderHorz";
274 return typeName;
275 }
276
277 GUISliderVert::GUISliderVert(const String& styleName, const GUIDimensions& dimensions)
278 :GUISlider(false, styleName, dimensions)
279 {
280
281 }
282
283 GUISliderVert* GUISliderVert::create(const String& styleName)
284 {
285 return new (bs_alloc<GUISliderVert>()) GUISliderVert(getStyleName<GUISliderVert>(styleName), GUIDimensions::create());
286 }
287
288 GUISliderVert* GUISliderVert::create(const GUIOptions& options, const String& styleName)
289 {
290 return new (bs_alloc<GUISliderVert>()) GUISliderVert(getStyleName<GUISliderVert>(styleName), GUIDimensions::create(options));
291 }
292
293 const String& GUISliderVert::getGUITypeName()
294 {
295 static String typeName = "SliderVert";
296 return typeName;
297 }
298}