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/BsGUIScrollBar.h" |
4 | #include "Image/BsSpriteTexture.h" |
5 | #include "GUI/BsGUIElementStyle.h" |
6 | #include "GUI/BsGUIDimensions.h" |
7 | #include "GUI/BsGUILayoutX.h" |
8 | #include "GUI/BsGUILayoutY.h" |
9 | #include "GUI/BsGUIButton.h" |
10 | #include "GUI/BsGUISliderHandle.h" |
11 | #include "GUI/BsGUISpace.h" |
12 | |
13 | using namespace std::placeholders; |
14 | |
15 | namespace bs |
16 | { |
17 | const UINT32 GUIScrollBar::ButtonScrollAmount = 10; |
18 | |
19 | const String& GUIScrollBar::getHScrollHandleType() |
20 | { |
21 | static String typeName = "UIScrollBarHHandle" ; |
22 | return typeName; |
23 | } |
24 | |
25 | const String& GUIScrollBar::getVScrollHandleType() |
26 | { |
27 | static String typeName = "UIScrollBarVHandle" ; |
28 | return typeName; |
29 | } |
30 | |
31 | GUIScrollBar::GUIScrollBar(bool horizontal, bool resizable, const String& styleName, const GUIDimensions& dimensions) |
32 | :GUIElement(styleName, dimensions), mHorizontal(horizontal) |
33 | { |
34 | mImageSprite = bs_new<ImageSprite>(); |
35 | |
36 | GUISliderHandleFlags flags; |
37 | if (resizable) |
38 | flags |= GUISliderHandleFlag::Resizeable; |
39 | |
40 | if(mHorizontal) |
41 | { |
42 | mLayout = GUILayoutX::create(); |
43 | _registerChildElement(mLayout); |
44 | |
45 | mUpBtn = GUIButton::create(HString("" ), "ScrollLeftBtn" ); |
46 | mDownBtn = GUIButton::create(HString("" ), "ScrollRightBtn" ); |
47 | |
48 | mHandleBtn = GUISliderHandle::create(flags | GUISliderHandleFlag::Horizontal, getSubStyleName(getHScrollHandleType())); |
49 | } |
50 | else |
51 | { |
52 | mLayout = GUILayoutY::create(); |
53 | _registerChildElement(mLayout); |
54 | |
55 | mUpBtn = GUIButton::create(HString("" ), "ScrollUpBtn" ); |
56 | mDownBtn = GUIButton::create(HString("" ), "ScrollDownBtn" ); |
57 | |
58 | mHandleBtn = GUISliderHandle::create(flags | GUISliderHandleFlag::Vertical, getSubStyleName(getVScrollHandleType())); |
59 | } |
60 | |
61 | GUIElementOptions scrollUpBtnOptions = mUpBtn->getOptionFlags(); |
62 | scrollUpBtnOptions.unset(GUIElementOption::AcceptsKeyFocus); |
63 | |
64 | mUpBtn->setOptionFlags(scrollUpBtnOptions); |
65 | |
66 | GUIElementOptions scrollDownBtnOptions = mDownBtn->getOptionFlags(); |
67 | scrollDownBtnOptions.unset(GUIElementOption::AcceptsKeyFocus); |
68 | |
69 | mDownBtn->setOptionFlags(scrollDownBtnOptions); |
70 | |
71 | mLayout->addNewElement<GUIFixedSpace>(2); |
72 | mLayout->addElement(mUpBtn); |
73 | mLayout->addElement(mHandleBtn); |
74 | mLayout->addElement(mDownBtn); |
75 | mLayout->addNewElement<GUIFixedSpace>(2); |
76 | |
77 | mHandleBtn->onHandleMovedOrResized.connect(std::bind(&GUIScrollBar::handleMoved, this, _1, _2)); |
78 | |
79 | mUpBtn->onClick.connect(std::bind(&GUIScrollBar::upButtonClicked, this)); |
80 | mDownBtn->onClick.connect(std::bind(&GUIScrollBar::downButtonClicked, this)); |
81 | } |
82 | |
83 | GUIScrollBar::~GUIScrollBar() |
84 | { |
85 | bs_delete(mImageSprite); |
86 | |
87 | GUIElement::destroy(mUpBtn); |
88 | GUIElement::destroy(mDownBtn); |
89 | GUIElement::destroy(mHandleBtn); |
90 | } |
91 | |
92 | UINT32 GUIScrollBar::_getNumRenderElements() const |
93 | { |
94 | return mImageSprite->getNumRenderElements(); |
95 | } |
96 | |
97 | const SpriteMaterialInfo& GUIScrollBar::_getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const |
98 | { |
99 | *material = mImageSprite->getMaterial(renderElementIdx); |
100 | return mImageSprite->getMaterialInfo(renderElementIdx); |
101 | } |
102 | |
103 | void GUIScrollBar::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const |
104 | { |
105 | UINT32 numQuads = mImageSprite->getNumQuads(renderElementIdx); |
106 | |
107 | numVertices = numQuads * 4; |
108 | numIndices = numQuads * 6; |
109 | type = GUIMeshType::Triangle; |
110 | } |
111 | |
112 | void GUIScrollBar::updateRenderElementsInternal() |
113 | { |
114 | IMAGE_SPRITE_DESC desc; |
115 | |
116 | if(_getStyle()->normal.texture != nullptr && _getStyle()->normal.texture.isLoaded()) |
117 | desc.texture = _getStyle()->normal.texture; |
118 | |
119 | desc.width = mLayoutData.area.width; |
120 | desc.height = mLayoutData.area.height; |
121 | desc.color = getTint(); |
122 | |
123 | mImageSprite->update(desc, (UINT64)_getParentWidget()); |
124 | |
125 | GUIElement::updateRenderElementsInternal(); |
126 | } |
127 | |
128 | void GUIScrollBar::updateClippedBounds() |
129 | { |
130 | mClippedBounds = Rect2I(0, 0, 0, 0); // We don't want any mouse input for this element. This is just a container. |
131 | } |
132 | |
133 | Vector2I GUIScrollBar::_getOptimalSize() const |
134 | { |
135 | return mLayout->_getOptimalSize(); |
136 | } |
137 | |
138 | UINT32 GUIScrollBar::_getRenderElementDepth(UINT32 renderElementIdx) const |
139 | { |
140 | return _getDepth() + 2; // + 2 depth because child buttons use +1 |
141 | } |
142 | |
143 | UINT32 GUIScrollBar::_getRenderElementDepthRange() const |
144 | { |
145 | return 3; |
146 | } |
147 | |
148 | void GUIScrollBar::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset, |
149 | UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const |
150 | { |
151 | UINT8* uvs = vertices + sizeof(Vector2); |
152 | UINT32 vertexStride = sizeof(Vector2) * 2; |
153 | UINT32 indexStride = sizeof(UINT32); |
154 | |
155 | Vector2I offset(mLayoutData.area.x, mLayoutData.area.y); |
156 | mImageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices, |
157 | vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect()); |
158 | } |
159 | |
160 | void GUIScrollBar::styleUpdated() |
161 | { |
162 | if (mHorizontal) |
163 | mHandleBtn->setStyle(getSubStyleName(getHScrollHandleType())); |
164 | else |
165 | mHandleBtn->setStyle(getSubStyleName(getVScrollHandleType())); |
166 | } |
167 | |
168 | void GUIScrollBar::handleMoved(float handlePct, float sizePct) |
169 | { |
170 | if(!onScrollOrResize.empty()) |
171 | onScrollOrResize(handlePct, sizePct); |
172 | } |
173 | |
174 | void GUIScrollBar::upButtonClicked() |
175 | { |
176 | float handleOffset = 0.0f; |
177 | float scrollableSize = (float)mHandleBtn->getScrollableSize(); |
178 | |
179 | if(scrollableSize > 0.0f) |
180 | handleOffset = ButtonScrollAmount / scrollableSize; |
181 | |
182 | scroll(handleOffset); |
183 | } |
184 | |
185 | void GUIScrollBar::downButtonClicked() |
186 | { |
187 | float handleOffset = 0.0f; |
188 | float scrollableSize = (float)mHandleBtn->getScrollableSize(); |
189 | |
190 | if(scrollableSize > 0.0f) |
191 | handleOffset = ButtonScrollAmount / scrollableSize; |
192 | |
193 | scroll(-handleOffset); |
194 | } |
195 | |
196 | void GUIScrollBar::scroll(float amount) |
197 | { |
198 | float newHandlePos = Math::clamp01(mHandleBtn->getHandlePos() - amount); |
199 | |
200 | float oldHandlePos = mHandleBtn->getHandlePos(); |
201 | mHandleBtn->_setHandlePos(newHandlePos); |
202 | |
203 | if (oldHandlePos != mHandleBtn->getHandlePos()) |
204 | { |
205 | mHandleBtn->_markLayoutAsDirty(); |
206 | |
207 | if (!onScrollOrResize.empty()) |
208 | onScrollOrResize(newHandlePos, mHandleBtn->_getHandleSizePct()); |
209 | } |
210 | } |
211 | |
212 | void GUIScrollBar::_setHandleSize(float pct) |
213 | { |
214 | mHandleBtn->_setHandleSize(pct); |
215 | } |
216 | |
217 | void GUIScrollBar::_setScrollPos(float pct) |
218 | { |
219 | mHandleBtn->_setHandlePos(pct); |
220 | } |
221 | |
222 | float GUIScrollBar::getScrollPos() const |
223 | { |
224 | return mHandleBtn->getHandlePos(); |
225 | } |
226 | |
227 | void GUIScrollBar::setScrollPos(float pct) |
228 | { |
229 | float oldHandlePos = mHandleBtn->getHandlePos(); |
230 | mHandleBtn->_setHandlePos(pct); |
231 | |
232 | if (oldHandlePos != mHandleBtn->getHandlePos()) |
233 | mHandleBtn->_markLayoutAsDirty(); |
234 | } |
235 | |
236 | float GUIScrollBar::getHandleSize() const |
237 | { |
238 | return mHandleBtn->_getHandleSizePct(); |
239 | } |
240 | |
241 | void GUIScrollBar::setHandleSize(float pct) |
242 | { |
243 | mHandleBtn->_setHandleSize(pct); |
244 | mHandleBtn->_markLayoutAsDirty(); |
245 | } |
246 | |
247 | UINT32 GUIScrollBar::getScrollableSize() const |
248 | { |
249 | return mHandleBtn->getScrollableSize(); |
250 | } |
251 | |
252 | void GUIScrollBar::setTint(const Color& color) |
253 | { |
254 | mUpBtn->setTint(color); |
255 | mDownBtn->setTint(color); |
256 | mHandleBtn->setTint(color); |
257 | |
258 | GUIElement::setTint(color); |
259 | } |
260 | } |