1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
5 #include "CGUIScrollBar.h"
8 #include "IGUIEnvironment.h"
9 #include "IVideoDriver.h"
10 #include "CGUIButton.h"
12 #include "IGUIFontBitmap.h"
21 CGUIScrollBar::CGUIScrollBar(bool horizontal
, IGUIEnvironment
*environment
,
22 IGUIElement
*parent
, s32 id
,
23 core::rect
<s32
> rectangle
, bool noclip
) :
24 IGUIScrollBar(environment
, parent
, id
, rectangle
),
26 DownButton(0), Dragging(false), Horizontal(horizontal
),
27 DraggedBySlider(false), TrayClick(false), Pos(0), DrawPos(0),
28 DrawHeight(0), Min(0), Max(100), SmallStep(10), LargeStep(50), DesiredPos(0),
32 setDebugName("CGUIScrollBar");
37 setNotClipped(noclip
);
39 // this element can be tabbed to
47 CGUIScrollBar::~CGUIScrollBar()
56 //! called if an event happened.
57 bool CGUIScrollBar::OnEvent(const SEvent
&event
)
61 switch (event
.EventType
) {
62 case EET_KEY_INPUT_EVENT
:
63 if (event
.KeyInput
.PressedDown
) {
64 const s32 oldPos
= Pos
;
66 switch (event
.KeyInput
.Key
) {
69 setPos(Pos
- SmallStep
);
73 setPos(Pos
+ SmallStep
);
79 setPos(Pos
- LargeStep
);
85 setPos(Pos
+ LargeStep
);
93 newEvent
.EventType
= EET_GUI_EVENT
;
94 newEvent
.GUIEvent
.Caller
= this;
95 newEvent
.GUIEvent
.Element
= 0;
96 newEvent
.GUIEvent
.EventType
= EGET_SCROLL_BAR_CHANGED
;
97 Parent
->OnEvent(newEvent
);
104 if (event
.GUIEvent
.EventType
== EGET_BUTTON_CLICKED
) {
105 if (event
.GUIEvent
.Caller
== UpButton
)
106 setPos(Pos
- SmallStep
);
107 else if (event
.GUIEvent
.Caller
== DownButton
)
108 setPos(Pos
+ SmallStep
);
111 newEvent
.EventType
= EET_GUI_EVENT
;
112 newEvent
.GUIEvent
.Caller
= this;
113 newEvent
.GUIEvent
.Element
= 0;
114 newEvent
.GUIEvent
.EventType
= EGET_SCROLL_BAR_CHANGED
;
115 Parent
->OnEvent(newEvent
);
118 } else if (event
.GUIEvent
.EventType
== EGET_ELEMENT_FOCUS_LOST
) {
119 if (event
.GUIEvent
.Caller
== this)
123 case EET_MOUSE_INPUT_EVENT
: {
124 const core::position2di
p(event
.MouseInput
.X
, event
.MouseInput
.Y
);
125 bool isInside
= isPointInside(p
);
126 switch (event
.MouseInput
.Event
) {
127 case EMIE_MOUSE_WHEEL
:
128 if (Environment
->hasFocus(this)) {
129 // thanks to a bug report by REAPER
130 // thanks to tommi by tommi for another bugfix
131 // everybody needs a little thanking. hallo niko!;-)
133 ((event
.MouseInput
.Wheel
< 0 ? -1 : 1) * SmallStep
* (Horizontal
? 1 : -1)));
136 newEvent
.EventType
= EET_GUI_EVENT
;
137 newEvent
.GUIEvent
.Caller
= this;
138 newEvent
.GUIEvent
.Element
= 0;
139 newEvent
.GUIEvent
.EventType
= EGET_SCROLL_BAR_CHANGED
;
140 Parent
->OnEvent(newEvent
);
144 case EMIE_LMOUSE_PRESSED_DOWN
: {
147 DraggedBySlider
= SliderRect
.isPointInside(p
);
148 TrayClick
= !DraggedBySlider
;
149 DesiredPos
= getPosFromMousePos(p
);
154 case EMIE_LMOUSE_LEFT_UP
:
155 case EMIE_MOUSE_MOVED
: {
156 if (!event
.MouseInput
.isLeftPressed())
160 if (event
.MouseInput
.Event
== EMIE_MOUSE_MOVED
)
165 if (event
.MouseInput
.Event
== EMIE_LMOUSE_LEFT_UP
)
168 const s32 newPos
= getPosFromMousePos(p
);
169 const s32 oldPos
= Pos
;
171 if (!DraggedBySlider
) {
173 DraggedBySlider
= SliderRect
.isPointInside(p
);
174 TrayClick
= !DraggedBySlider
;
177 if (DraggedBySlider
) {
181 if (event
.MouseInput
.Event
== EMIE_MOUSE_MOVED
)
186 if (DraggedBySlider
) {
192 if (Pos
!= oldPos
&& Parent
) {
194 newEvent
.EventType
= EET_GUI_EVENT
;
195 newEvent
.GUIEvent
.Caller
= this;
196 newEvent
.GUIEvent
.Element
= 0;
197 newEvent
.GUIEvent
.EventType
= EGET_SCROLL_BAR_CHANGED
;
198 Parent
->OnEvent(newEvent
);
212 return IGUIElement::OnEvent(event
);
215 void CGUIScrollBar::OnPostRender(u32 timeMs
)
217 if (Dragging
&& !DraggedBySlider
&& TrayClick
&& timeMs
> LastChange
+ 200) {
220 const s32 oldPos
= Pos
;
222 if (DesiredPos
>= Pos
+ LargeStep
)
223 setPos(Pos
+ LargeStep
);
224 else if (DesiredPos
<= Pos
- LargeStep
)
225 setPos(Pos
- LargeStep
);
226 else if (DesiredPos
>= Pos
- LargeStep
&& DesiredPos
<= Pos
+ LargeStep
)
229 if (Pos
!= oldPos
&& Parent
) {
231 newEvent
.EventType
= EET_GUI_EVENT
;
232 newEvent
.GUIEvent
.Caller
= this;
233 newEvent
.GUIEvent
.Element
= 0;
234 newEvent
.GUIEvent
.EventType
= EGET_SCROLL_BAR_CHANGED
;
235 Parent
->OnEvent(newEvent
);
240 //! draws the element and its children
241 void CGUIScrollBar::draw()
246 IGUISkin
*skin
= Environment
->getSkin();
250 video::SColor iconColor
= skin
->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL
: EGDC_GRAY_WINDOW_SYMBOL
);
251 if (iconColor
!= CurrentIconColor
) {
255 SliderRect
= AbsoluteRect
;
257 // draws the background
258 skin
->draw2DRectangle(this, skin
->getColor(EGDC_SCROLLBAR
), SliderRect
, &AbsoluteClippingRect
);
260 if (core::isnotzero(range())) {
261 // recalculate slider rectangle
263 SliderRect
.UpperLeftCorner
.X
= AbsoluteRect
.UpperLeftCorner
.X
+ DrawPos
+ RelativeRect
.getHeight() - DrawHeight
/ 2;
264 SliderRect
.LowerRightCorner
.X
= SliderRect
.UpperLeftCorner
.X
+ DrawHeight
;
266 SliderRect
.UpperLeftCorner
.Y
= AbsoluteRect
.UpperLeftCorner
.Y
+ DrawPos
+ RelativeRect
.getWidth() - DrawHeight
/ 2;
267 SliderRect
.LowerRightCorner
.Y
= SliderRect
.UpperLeftCorner
.Y
+ DrawHeight
;
270 skin
->draw3DButtonPaneStandard(this, SliderRect
, &AbsoluteClippingRect
);
277 void CGUIScrollBar::updateAbsolutePosition()
279 IGUIElement::updateAbsolutePosition();
280 // todo: properly resize
286 s32
CGUIScrollBar::getPosFromMousePos(const core::position2di
&pos
) const
290 w
= RelativeRect
.getWidth() - f32(RelativeRect
.getHeight()) * 3.0f
;
291 p
= pos
.X
- AbsoluteRect
.UpperLeftCorner
.X
- RelativeRect
.getHeight() * 1.5f
;
293 w
= RelativeRect
.getHeight() - f32(RelativeRect
.getWidth()) * 3.0f
;
294 p
= pos
.Y
- AbsoluteRect
.UpperLeftCorner
.Y
- RelativeRect
.getWidth() * 1.5f
;
296 return (s32
)(p
/ w
* range()) + Min
;
299 //! sets the position of the scrollbar
300 void CGUIScrollBar::setPos(s32 pos
)
302 Pos
= core::s32_clamp(pos
, Min
, Max
);
304 if (core::isnotzero(range())) {
306 f32 f
= (RelativeRect
.getWidth() - ((f32
)RelativeRect
.getHeight() * 3.0f
)) / range();
307 DrawPos
= (s32
)(((Pos
- Min
) * f
) + ((f32
)RelativeRect
.getHeight() * 0.5f
));
308 DrawHeight
= RelativeRect
.getHeight();
310 f32 f
= (RelativeRect
.getHeight() - ((f32
)RelativeRect
.getWidth() * 3.0f
)) / range();
312 DrawPos
= (s32
)(((Pos
- Min
) * f
) + ((f32
)RelativeRect
.getWidth() * 0.5f
));
313 DrawHeight
= RelativeRect
.getWidth();
318 //! gets the small step value
319 s32
CGUIScrollBar::getSmallStep() const
324 //! sets the small step value
325 void CGUIScrollBar::setSmallStep(s32 step
)
333 //! gets the small step value
334 s32
CGUIScrollBar::getLargeStep() const
339 //! sets the small step value
340 void CGUIScrollBar::setLargeStep(s32 step
)
348 //! gets the maximum value of the scrollbar.
349 s32
CGUIScrollBar::getMax() const
354 //! sets the maximum value of the scrollbar.
355 void CGUIScrollBar::setMax(s32 max
)
361 bool enable
= core::isnotzero(range());
362 UpButton
->setEnabled(enable
);
363 DownButton
->setEnabled(enable
);
367 //! gets the minimum value of the scrollbar.
368 s32
CGUIScrollBar::getMin() const
373 //! sets the minimum value of the scrollbar.
374 void CGUIScrollBar::setMin(s32 min
)
380 bool enable
= core::isnotzero(range());
381 UpButton
->setEnabled(enable
);
382 DownButton
->setEnabled(enable
);
386 //! gets the current position of the scrollbar
387 s32
CGUIScrollBar::getPos() const
392 //! refreshes the position and text on child buttons
393 void CGUIScrollBar::refreshControls()
395 CurrentIconColor
= video::SColor(255, 255, 255, 255);
397 IGUISkin
*skin
= Environment
->getSkin();
398 IGUISpriteBank
*sprites
= 0;
401 sprites
= skin
->getSpriteBank();
402 CurrentIconColor
= skin
->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL
: EGDC_GRAY_WINDOW_SYMBOL
);
406 const s32 h
= RelativeRect
.getHeight();
407 const s32 w
= (h
< RelativeRect
.getWidth() / 2) ? h
: RelativeRect
.getWidth() / 2;
409 UpButton
= new CGUIButton(Environment
, this, -1, core::rect
<s32
>(0, 0, w
, h
), NoClip
);
410 UpButton
->setSubElement(true);
411 UpButton
->setTabStop(false);
414 UpButton
->setSpriteBank(sprites
);
415 UpButton
->setSprite(EGBS_BUTTON_UP
, skin
->getIcon(EGDI_CURSOR_LEFT
), CurrentIconColor
);
416 UpButton
->setSprite(EGBS_BUTTON_DOWN
, skin
->getIcon(EGDI_CURSOR_LEFT
), CurrentIconColor
);
418 UpButton
->setRelativePosition(core::rect
<s32
>(0, 0, w
, h
));
419 UpButton
->setAlignment(EGUIA_UPPERLEFT
, EGUIA_UPPERLEFT
, EGUIA_UPPERLEFT
, EGUIA_LOWERRIGHT
);
421 DownButton
= new CGUIButton(Environment
, this, -1, core::rect
<s32
>(RelativeRect
.getWidth() - w
, 0, RelativeRect
.getWidth(), h
), NoClip
);
422 DownButton
->setSubElement(true);
423 DownButton
->setTabStop(false);
426 DownButton
->setSpriteBank(sprites
);
427 DownButton
->setSprite(EGBS_BUTTON_UP
, skin
->getIcon(EGDI_CURSOR_RIGHT
), CurrentIconColor
);
428 DownButton
->setSprite(EGBS_BUTTON_DOWN
, skin
->getIcon(EGDI_CURSOR_RIGHT
), CurrentIconColor
);
430 DownButton
->setRelativePosition(core::rect
<s32
>(RelativeRect
.getWidth() - w
, 0, RelativeRect
.getWidth(), h
));
431 DownButton
->setAlignment(EGUIA_LOWERRIGHT
, EGUIA_LOWERRIGHT
, EGUIA_UPPERLEFT
, EGUIA_LOWERRIGHT
);
433 const s32 w
= RelativeRect
.getWidth();
434 const s32 h
= (w
< RelativeRect
.getHeight() / 2) ? w
: RelativeRect
.getHeight() / 2;
436 UpButton
= new CGUIButton(Environment
, this, -1, core::rect
<s32
>(0, 0, w
, h
), NoClip
);
437 UpButton
->setSubElement(true);
438 UpButton
->setTabStop(false);
441 UpButton
->setSpriteBank(sprites
);
442 UpButton
->setSprite(EGBS_BUTTON_UP
, skin
->getIcon(EGDI_CURSOR_UP
), CurrentIconColor
);
443 UpButton
->setSprite(EGBS_BUTTON_DOWN
, skin
->getIcon(EGDI_CURSOR_UP
), CurrentIconColor
);
445 UpButton
->setRelativePosition(core::rect
<s32
>(0, 0, w
, h
));
446 UpButton
->setAlignment(EGUIA_UPPERLEFT
, EGUIA_LOWERRIGHT
, EGUIA_UPPERLEFT
, EGUIA_UPPERLEFT
);
448 DownButton
= new CGUIButton(Environment
, this, -1, core::rect
<s32
>(0, RelativeRect
.getHeight() - h
, w
, RelativeRect
.getHeight()), NoClip
);
449 DownButton
->setSubElement(true);
450 DownButton
->setTabStop(false);
453 DownButton
->setSpriteBank(sprites
);
454 DownButton
->setSprite(EGBS_BUTTON_UP
, skin
->getIcon(EGDI_CURSOR_DOWN
), CurrentIconColor
);
455 DownButton
->setSprite(EGBS_BUTTON_DOWN
, skin
->getIcon(EGDI_CURSOR_DOWN
), CurrentIconColor
);
457 DownButton
->setRelativePosition(core::rect
<s32
>(0, RelativeRect
.getHeight() - h
, w
, RelativeRect
.getHeight()));
458 DownButton
->setAlignment(EGUIA_UPPERLEFT
, EGUIA_LOWERRIGHT
, EGUIA_LOWERRIGHT
, EGUIA_LOWERRIGHT
);
462 } // end namespace gui
463 } // end namespace irr