1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "guiButton.h"
\r
8 #include "client/guiscalingfilter.h"
\r
9 #include "client/tile.h"
\r
10 #include "IGUISkin.h"
\r
11 #include "IGUIEnvironment.h"
\r
12 #include "IVideoDriver.h"
\r
13 #include "IGUIFont.h"
\r
14 #include "irrlicht_changes/static_text.h"
\r
15 #include "porting.h"
\r
16 #include "StyleSpec.h"
\r
17 #include "util/numeric.h"
\r
19 using namespace irr;
\r
20 using namespace gui;
\r
22 // Multiply with a color to get the default corresponding hovered color
\r
23 #define COLOR_HOVERED_MOD 1.25f
\r
25 // Multiply with a color to get the default corresponding pressed color
\r
26 #define COLOR_PRESSED_MOD 0.85f
\r
29 GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
\r
30 s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
\r
32 : IGUIButton(environment, parent, id, rectangle),
\r
33 SpriteBank(0), OverrideFont(0),
\r
34 OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),
\r
35 ClickTime(0), HoverTime(0), FocusTime(0),
\r
36 ClickShiftState(false), ClickControlState(false),
\r
37 IsPushButton(false), Pressed(false),
\r
38 UseAlphaChannel(false), DrawBorder(true), ScaleImage(false), TSrc(tsrc)
\r
40 setNotClipped(noclip);
\r
42 // This element can be tabbed.
\r
47 for (size_t i = 0; i < 4; i++) {
\r
48 Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
\r
50 StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);
\r
51 StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
\r
56 GUIButton::~GUIButton()
\r
59 OverrideFont->drop();
\r
66 //! Sets if the images should be scaled to fit the button
\r
67 void GUIButton::setScaleImage(bool scaleImage)
\r
69 ScaleImage = scaleImage;
\r
73 //! Returns whether the button scale the used images
\r
74 bool GUIButton::isScalingImage() const
\r
80 //! Sets if the button should use the skin to draw its border
\r
81 void GUIButton::setDrawBorder(bool border)
\r
83 DrawBorder = border;
\r
87 void GUIButton::setSpriteBank(IGUISpriteBank* sprites)
\r
95 SpriteBank = sprites;
\r
98 void GUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale)
\r
100 ButtonSprites[(u32)state].Index = index;
\r
101 ButtonSprites[(u32)state].Color = color;
\r
102 ButtonSprites[(u32)state].Loop = loop;
\r
103 ButtonSprites[(u32)state].Scale = scale;
\r
106 //! Get the sprite-index for the given state or -1 when no sprite is set
\r
107 s32 GUIButton::getSpriteIndex(EGUI_BUTTON_STATE state) const
\r
109 return ButtonSprites[(u32)state].Index;
\r
112 //! Get the sprite color for the given state. Color is only used when a sprite is set.
\r
113 video::SColor GUIButton::getSpriteColor(EGUI_BUTTON_STATE state) const
\r
115 return ButtonSprites[(u32)state].Color;
\r
118 //! Returns if the sprite in the given state does loop
\r
119 bool GUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const
\r
121 return ButtonSprites[(u32)state].Loop;
\r
124 //! Returns if the sprite in the given state is scaled
\r
125 bool GUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const
\r
127 return ButtonSprites[(u32)state].Scale;
\r
130 //! called if an event happened.
\r
131 bool GUIButton::OnEvent(const SEvent& event)
\r
134 return IGUIElement::OnEvent(event);
\r
136 switch(event.EventType)
\r
138 case EET_KEY_INPUT_EVENT:
\r
139 if (event.KeyInput.PressedDown &&
\r
140 (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
\r
145 setPressed(!Pressed);
\r
149 if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
\r
155 if (!event.KeyInput.PressedDown && Pressed &&
\r
156 (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
\r
164 ClickShiftState = event.KeyInput.Shift;
\r
165 ClickControlState = event.KeyInput.Control;
\r
168 newEvent.EventType = EET_GUI_EVENT;
\r
169 newEvent.GUIEvent.Caller = this;
\r
170 newEvent.GUIEvent.Element = 0;
\r
171 newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
\r
172 Parent->OnEvent(newEvent);
\r
177 case EET_GUI_EVENT:
\r
178 if (event.GUIEvent.Caller == this)
\r
180 if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
\r
184 FocusTime = (u32)porting::getTimeMs();
\r
186 else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
\r
188 FocusTime = (u32)porting::getTimeMs();
\r
190 else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)
\r
192 HoverTime = (u32)porting::getTimeMs();
\r
196 case EET_MOUSE_INPUT_EVENT:
\r
197 if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
\r
199 // Sometimes formspec elements can receive mouse events when the
\r
200 // mouse is outside of the formspec. Thus, we test the position here.
\r
201 if ( !IsPushButton && AbsoluteClippingRect.isPointInside(
\r
202 core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ))) {
\r
209 if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
\r
211 bool wasPressed = Pressed;
\r
213 if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )
\r
224 setPressed(!Pressed);
\r
227 if ((!IsPushButton && wasPressed && Parent) ||
\r
228 (IsPushButton && wasPressed != Pressed))
\r
230 ClickShiftState = event.MouseInput.Shift;
\r
231 ClickControlState = event.MouseInput.Control;
\r
234 newEvent.EventType = EET_GUI_EVENT;
\r
235 newEvent.GUIEvent.Caller = this;
\r
236 newEvent.GUIEvent.Element = 0;
\r
237 newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
\r
238 Parent->OnEvent(newEvent);
\r
248 return Parent ? Parent->OnEvent(event) : false;
\r
252 //! draws the element and its children
\r
253 void GUIButton::draw()
\r
259 // Track hovered state, if it has changed then we need to update the style.
\r
260 bool hovered = isHovered();
\r
261 if (hovered != WasHovered) {
\r
262 WasHovered = hovered;
\r
266 GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());
\r
267 video::IVideoDriver* driver = Environment->getVideoDriver();
\r
275 skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,
\r
276 &AbsoluteClippingRect, Colors);
\r
282 skin->drawColored3DButtonPanePressed(this, AbsoluteRect,
\r
283 &AbsoluteClippingRect, Colors);
\r
288 const core::position2di buttonCenter(AbsoluteRect.getCenter());
\r
290 // The image changes based on the state, so we use the default every time.
\r
291 EGUI_BUTTON_IMAGE_STATE imageState = EGBIS_IMAGE_UP;
\r
293 if ( ButtonImages[(u32)imageState].Texture )
\r
295 core::position2d<s32> pos(buttonCenter);
\r
296 core::rect<s32> sourceRect(ButtonImages[(u32)imageState].SourceRect);
\r
297 if ( sourceRect.getWidth() == 0 && sourceRect.getHeight() == 0 )
\r
298 sourceRect = core::rect<s32>(core::position2di(0,0), ButtonImages[(u32)imageState].Texture->getOriginalSize());
\r
300 pos.X -= sourceRect.getWidth() / 2;
\r
301 pos.Y -= sourceRect.getHeight() / 2;
\r
305 // Create a pressed-down effect by moving the image when it looks identical to the unpressed state image
\r
306 EGUI_BUTTON_IMAGE_STATE unpressedState = getImageState(false);
\r
307 if ( unpressedState == imageState || ButtonImages[(u32)imageState] == ButtonImages[(u32)unpressedState] )
\r
309 pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);
\r
310 pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);
\r
315 video::ITexture* texture = ButtonImages[(u32)imageState].Texture;
\r
316 video::SColor image_colors[] = { BgColor, BgColor, BgColor, BgColor };
\r
317 if (BgMiddle.getArea() == 0) {
\r
318 driver->draw2DImage(texture,
\r
319 ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
\r
320 sourceRect, &AbsoluteClippingRect,
\r
321 image_colors, UseAlphaChannel);
\r
323 draw2DImage9Slice(driver, texture,
\r
324 ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
\r
325 sourceRect, BgMiddle, &AbsoluteClippingRect, image_colors);
\r
334 core::position2di pos(buttonCenter);
\r
335 // pressed / unpressed animation
\r
336 EGUI_BUTTON_STATE state = Pressed ? EGBS_BUTTON_DOWN : EGBS_BUTTON_UP;
\r
337 drawSprite(state, ClickTime, pos);
\r
339 // focused / unfocused animation
\r
340 state = Environment->hasFocus(this) ? EGBS_BUTTON_FOCUSED : EGBS_BUTTON_NOT_FOCUSED;
\r
341 drawSprite(state, FocusTime, pos);
\r
343 // mouse over / off animation
\r
344 state = isHovered() ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;
\r
345 drawSprite(state, HoverTime, pos);
\r
350 // drawSprite(EGBS_BUTTON_DISABLED, 0, pos);
\r
354 IGUIElement::draw();
\r
357 void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)
\r
359 u32 stateIdx = (u32)state;
\r
361 if (ButtonSprites[stateIdx].Index != -1)
\r
363 if ( ButtonSprites[stateIdx].Scale )
\r
365 const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color};
\r
366 SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect.UpperLeftCorner,
\r
367 &AbsoluteClippingRect, colors[0], // FIXME: remove [0]
\r
368 porting::getTimeMs()-startTime, ButtonSprites[stateIdx].Loop);
\r
372 SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,
\r
373 &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, porting::getTimeMs(),
\r
374 ButtonSprites[stateIdx].Loop, true);
\r
379 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const
\r
382 return getImageState(pressed, ButtonImages);
\r
386 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed, const ButtonImage* images) const
\r
388 // figure state we should have
\r
389 EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED;
\r
390 bool focused = Environment->hasFocus((IGUIElement*)this);
\r
391 bool mouseOver = isHovered();
\r
396 if ( focused && mouseOver )
\r
397 state = EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER;
\r
398 else if ( focused )
\r
399 state = EGBIS_IMAGE_DOWN_FOCUSED;
\r
400 else if ( mouseOver )
\r
401 state = EGBIS_IMAGE_DOWN_MOUSEOVER;
\r
403 state = EGBIS_IMAGE_DOWN;
\r
407 if ( focused && mouseOver )
\r
408 state = EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER;
\r
409 else if ( focused )
\r
410 state = EGBIS_IMAGE_UP_FOCUSED;
\r
411 else if ( mouseOver )
\r
412 state = EGBIS_IMAGE_UP_MOUSEOVER;
\r
414 state = EGBIS_IMAGE_UP;
\r
418 // find a compatible state that has images
\r
419 while ( state != EGBIS_IMAGE_UP && !images[(u32)state].Texture )
\r
424 case EGBIS_IMAGE_UP_FOCUSED:
\r
425 state = EGBIS_IMAGE_UP;
\r
427 case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:
\r
428 state = EGBIS_IMAGE_UP_FOCUSED;
\r
430 case EGBIS_IMAGE_DOWN_MOUSEOVER:
\r
431 state = EGBIS_IMAGE_DOWN;
\r
433 case EGBIS_IMAGE_DOWN_FOCUSED:
\r
434 state = EGBIS_IMAGE_DOWN;
\r
436 case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:
\r
437 state = EGBIS_IMAGE_DOWN_FOCUSED;
\r
439 case EGBIS_IMAGE_DISABLED:
\r
441 state = EGBIS_IMAGE_DOWN;
\r
443 state = EGBIS_IMAGE_UP;
\r
446 state = EGBIS_IMAGE_UP;
\r
454 //! sets another skin independent font. if this is set to zero, the button uses the font of the skin.
\r
455 void GUIButton::setOverrideFont(IGUIFont* font)
\r
457 if (OverrideFont == font)
\r
461 OverrideFont->drop();
\r
463 OverrideFont = font;
\r
466 OverrideFont->grab();
\r
468 StaticText->setOverrideFont(font);
\r
471 //! Gets the override font (if any)
\r
472 IGUIFont * GUIButton::getOverrideFont() const
\r
474 return OverrideFont;
\r
477 //! Get the font which is used right now for drawing
\r
478 IGUIFont* GUIButton::getActiveFont() const
\r
480 if ( OverrideFont )
\r
481 return OverrideFont;
\r
482 IGUISkin* skin = Environment->getSkin();
\r
484 return skin->getFont(EGDF_BUTTON);
\r
488 //! Sets another color for the text.
\r
489 void GUIButton::setOverrideColor(video::SColor color)
\r
491 OverrideColor = color;
\r
492 OverrideColorEnabled = true;
\r
494 StaticText->setOverrideColor(color);
\r
497 video::SColor GUIButton::getOverrideColor() const
\r
499 return OverrideColor;
\r
502 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
\r
503 video::SColor GUIButton::getActiveColor() const
\r
505 return video::SColor(0,0,0,0); // unused?
\r
509 void GUIButton::enableOverrideColor(bool enable)
\r
511 OverrideColorEnabled = enable;
\r
514 bool GUIButton::isOverrideColorEnabled() const
\r
516 return OverrideColorEnabled;
\r
519 void GUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect<s32>& sourceRect)
\r
521 if ( state >= EGBIS_COUNT )
\r
527 u32 stateIdx = (u32)state;
\r
528 if ( ButtonImages[stateIdx].Texture )
\r
529 ButtonImages[stateIdx].Texture->drop();
\r
531 ButtonImages[stateIdx].Texture = image;
\r
532 ButtonImages[stateIdx].SourceRect = sourceRect;
\r
536 void GUIButton::setImage(video::ITexture* image)
\r
538 setImage(gui::EGBIS_IMAGE_UP, image);
\r
541 void GUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos)
\r
543 setImage(gui::EGBIS_IMAGE_UP, image, pos);
\r
546 void GUIButton::setPressedImage(video::ITexture* image)
\r
548 setImage(gui::EGBIS_IMAGE_DOWN, image);
\r
551 void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos)
\r
553 setImage(gui::EGBIS_IMAGE_DOWN, image, pos);
\r
556 //! Sets the text displayed by the button
\r
557 void GUIButton::setText(const wchar_t* text)
\r
559 StaticText->setText(text);
\r
561 IGUIButton::setText(text);
\r
565 //! Sets if the button should behave like a push button. Which means it
\r
566 //! can be in two states: Normal or Pressed. With a click on the button,
\r
567 //! the user can change the state of the button.
\r
568 void GUIButton::setIsPushButton(bool isPushButton)
\r
570 IsPushButton = isPushButton;
\r
574 //! Returns if the button is currently pressed
\r
575 bool GUIButton::isPressed() const
\r
581 //! Returns if this element (or one of its direct children) is hovered
\r
582 bool GUIButton::isHovered() const
\r
584 IGUIElement *hovered = Environment->getHovered();
\r
585 return hovered == this || (hovered != nullptr && hovered->getParent() == this);
\r
589 //! Sets the pressed state of the button if this is a pushbutton
\r
590 void GUIButton::setPressed(bool pressed)
\r
592 if (Pressed != pressed)
\r
594 ClickTime = porting::getTimeMs();
\r
601 //! Returns whether the button is a push button
\r
602 bool GUIButton::isPushButton() const
\r
604 return IsPushButton;
\r
608 //! Sets if the alpha channel should be used for drawing images on the button (default is false)
\r
609 void GUIButton::setUseAlphaChannel(bool useAlphaChannel)
\r
611 UseAlphaChannel = useAlphaChannel;
\r
615 //! Returns if the alpha channel should be used for drawing images on the button
\r
616 bool GUIButton::isAlphaChannelUsed() const
\r
618 return UseAlphaChannel;
\r
622 bool GUIButton::isDrawingBorder() const
\r
629 GUIButton* GUIButton::addButton(IGUIEnvironment *environment,
\r
630 const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,
\r
631 IGUIElement* parent, s32 id, const wchar_t* text,
\r
632 const wchar_t *tooltiptext)
\r
634 GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);
\r
636 button->setText(text);
\r
639 button->setToolTipText ( tooltiptext );
\r
645 void GUIButton::setColor(video::SColor color)
\r
650 for (size_t i = 0; i < 4; i++) {
\r
651 video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
\r
652 Colors[i] = base.getInterpolated(color, d);
\r
656 //! Set element properties from a StyleSpec corresponding to the button state
\r
657 void GUIButton::setFromState()
\r
659 StyleSpec::State state = StyleSpec::STATE_DEFAULT;
\r
662 state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_PRESSED);
\r
665 state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_HOVERED);
\r
667 setFromStyle(StyleSpec::getStyleFromStatePropagation(Styles, state));
\r
670 //! Set element properties from a StyleSpec
\r
671 void GUIButton::setFromStyle(const StyleSpec& style)
\r
673 bool hovered = (style.getState() & StyleSpec::STATE_HOVERED) != 0;
\r
674 bool pressed = (style.getState() & StyleSpec::STATE_PRESSED) != 0;
\r
676 if (style.isNotDefault(StyleSpec::BGCOLOR)) {
\r
677 setColor(style.getColor(StyleSpec::BGCOLOR));
\r
679 // If we have a propagated hover/press color, we need to automatically
\r
680 // lighten/darken it
\r
681 if (!Styles[style.getState()].isNotDefault(StyleSpec::BGCOLOR)) {
\r
683 BgColor = multiplyColorValue(BgColor, COLOR_PRESSED_MOD);
\r
685 for (size_t i = 0; i < 4; i++)
\r
686 Colors[i] = multiplyColorValue(Colors[i], COLOR_PRESSED_MOD);
\r
687 } else if (hovered) {
\r
688 BgColor = multiplyColorValue(BgColor, COLOR_HOVERED_MOD);
\r
690 for (size_t i = 0; i < 4; i++)
\r
691 Colors[i] = multiplyColorValue(Colors[i], COLOR_HOVERED_MOD);
\r
696 BgColor = video::SColor(255, 255, 255, 255);
\r
697 for (size_t i = 0; i < 4; i++) {
\r
698 video::SColor base =
\r
699 Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
\r
701 Colors[i] = multiplyColorValue(base, COLOR_PRESSED_MOD);
\r
702 } else if (hovered) {
\r
703 Colors[i] = multiplyColorValue(base, COLOR_HOVERED_MOD);
\r
710 if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {
\r
711 setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));
\r
713 setOverrideColor(video::SColor(255,255,255,255));
\r
714 OverrideColorEnabled = false;
\r
716 setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
\r
717 setDrawBorder(style.getBool(StyleSpec::BORDER, true));
\r
718 setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));
\r
719 setOverrideFont(style.getFont());
\r
721 if (style.isNotDefault(StyleSpec::BGIMG)) {
\r
722 video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,
\r
723 getTextureSource());
\r
724 setImage(guiScalingImageButton(
\r
725 Environment->getVideoDriver(), texture,
\r
726 AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));
\r
727 setScaleImage(true);
\r
732 BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);
\r
734 // Child padding and offset
\r
735 Padding = style.getRect(StyleSpec::PADDING, core::rect<s32>());
\r
736 Padding = core::rect<s32>(
\r
737 Padding.UpperLeftCorner + BgMiddle.UpperLeftCorner,
\r
738 Padding.LowerRightCorner + BgMiddle.LowerRightCorner);
\r
740 GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());
\r
741 core::vector2d<s32> defaultPressOffset(
\r
742 skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),
\r
743 skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y));
\r
744 ContentOffset = style.getVector2i(StyleSpec::CONTENT_OFFSET, isPressed()
\r
745 ? defaultPressOffset
\r
746 : core::vector2d<s32>(0));
\r
748 core::rect<s32> childBounds(
\r
749 Padding.UpperLeftCorner.X + ContentOffset.X,
\r
750 Padding.UpperLeftCorner.Y + ContentOffset.Y,
\r
751 AbsoluteRect.getWidth() + Padding.LowerRightCorner.X + ContentOffset.X,
\r
752 AbsoluteRect.getHeight() + Padding.LowerRightCorner.Y + ContentOffset.Y);
\r
754 for (IGUIElement *child : getChildren()) {
\r
755 child->setRelativePosition(childBounds);
\r
759 //! Set the styles used for each state
\r
760 void GUIButton::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles)
\r