guiButton.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  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
  4. #include "guiButton.h"
  5. #include "client/guiscalingfilter.h"
  6. #include "client/tile.h"
  7. #include "IGUISkin.h"
  8. #include "IGUIEnvironment.h"
  9. #include "IVideoDriver.h"
  10. #include "IGUIFont.h"
  11. #include "irrlicht_changes/static_text.h"
  12. #include "porting.h"
  13. #include "StyleSpec.h"
  14. #include "util/numeric.h"
  15. using namespace irr;
  16. using namespace gui;
  17. // Multiply with a color to get the default corresponding hovered color
  18. #define COLOR_HOVERED_MOD 1.25f
  19. // Multiply with a color to get the default corresponding pressed color
  20. #define COLOR_PRESSED_MOD 0.85f
  21. //! constructor
  22. GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
  23. s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
  24. bool noclip) :
  25. IGUIButton(environment, parent, id, rectangle),
  26. TSrc(tsrc)
  27. {
  28. setNotClipped(noclip);
  29. // This element can be tabbed.
  30. setTabStop(true);
  31. setTabOrder(-1);
  32. // PATCH
  33. for (size_t i = 0; i < 4; i++) {
  34. Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
  35. }
  36. StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);
  37. StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
  38. // END PATCH
  39. }
  40. //! destructor
  41. GUIButton::~GUIButton()
  42. {
  43. if (OverrideFont)
  44. OverrideFont->drop();
  45. if (SpriteBank)
  46. SpriteBank->drop();
  47. }
  48. //! Sets if the images should be scaled to fit the button
  49. void GUIButton::setScaleImage(bool scaleImage)
  50. {
  51. ScaleImage = scaleImage;
  52. }
  53. //! Returns whether the button scale the used images
  54. bool GUIButton::isScalingImage() const
  55. {
  56. return ScaleImage;
  57. }
  58. //! Sets if the button should use the skin to draw its border
  59. void GUIButton::setDrawBorder(bool border)
  60. {
  61. DrawBorder = border;
  62. }
  63. void GUIButton::setSpriteBank(IGUISpriteBank* sprites)
  64. {
  65. if (sprites)
  66. sprites->grab();
  67. if (SpriteBank)
  68. SpriteBank->drop();
  69. SpriteBank = sprites;
  70. }
  71. void GUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale)
  72. {
  73. ButtonSprites[(u32)state].Index = index;
  74. ButtonSprites[(u32)state].Color = color;
  75. ButtonSprites[(u32)state].Loop = loop;
  76. ButtonSprites[(u32)state].Scale = scale;
  77. }
  78. //! Get the sprite-index for the given state or -1 when no sprite is set
  79. s32 GUIButton::getSpriteIndex(EGUI_BUTTON_STATE state) const
  80. {
  81. return ButtonSprites[(u32)state].Index;
  82. }
  83. //! Get the sprite color for the given state. Color is only used when a sprite is set.
  84. video::SColor GUIButton::getSpriteColor(EGUI_BUTTON_STATE state) const
  85. {
  86. return ButtonSprites[(u32)state].Color;
  87. }
  88. //! Returns if the sprite in the given state does loop
  89. bool GUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const
  90. {
  91. return ButtonSprites[(u32)state].Loop;
  92. }
  93. //! Returns if the sprite in the given state is scaled
  94. bool GUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const
  95. {
  96. return ButtonSprites[(u32)state].Scale;
  97. }
  98. //! called if an event happened.
  99. bool GUIButton::OnEvent(const SEvent& event)
  100. {
  101. if (!isEnabled())
  102. return IGUIElement::OnEvent(event);
  103. switch(event.EventType)
  104. {
  105. case EET_KEY_INPUT_EVENT:
  106. if (event.KeyInput.PressedDown &&
  107. (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
  108. {
  109. if (!IsPushButton)
  110. setPressed(true);
  111. else
  112. setPressed(!Pressed);
  113. return true;
  114. }
  115. if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
  116. {
  117. setPressed(false);
  118. return true;
  119. }
  120. else
  121. if (!event.KeyInput.PressedDown && Pressed &&
  122. (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
  123. {
  124. if (!IsPushButton)
  125. setPressed(false);
  126. if (Parent)
  127. {
  128. ClickShiftState = event.KeyInput.Shift;
  129. ClickControlState = event.KeyInput.Control;
  130. SEvent newEvent;
  131. newEvent.EventType = EET_GUI_EVENT;
  132. newEvent.GUIEvent.Caller = this;
  133. newEvent.GUIEvent.Element = 0;
  134. newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
  135. Parent->OnEvent(newEvent);
  136. }
  137. return true;
  138. }
  139. break;
  140. case EET_GUI_EVENT:
  141. if (event.GUIEvent.Caller == this)
  142. {
  143. if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
  144. {
  145. if (!IsPushButton)
  146. setPressed(false);
  147. FocusTime = (u32)porting::getTimeMs();
  148. }
  149. else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
  150. {
  151. FocusTime = (u32)porting::getTimeMs();
  152. }
  153. else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)
  154. {
  155. HoverTime = (u32)porting::getTimeMs();
  156. }
  157. }
  158. break;
  159. case EET_MOUSE_INPUT_EVENT:
  160. if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
  161. {
  162. // Sometimes formspec elements can receive mouse events when the
  163. // mouse is outside of the formspec. Thus, we test the position here.
  164. if ( !IsPushButton && AbsoluteClippingRect.isPointInside(
  165. core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ))) {
  166. Environment->setFocus(this);
  167. setPressed(true);
  168. }
  169. return true;
  170. }
  171. else
  172. if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
  173. {
  174. bool wasPressed = Pressed;
  175. if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )
  176. {
  177. if (!IsPushButton)
  178. setPressed(false);
  179. return true;
  180. }
  181. if (!IsPushButton)
  182. setPressed(false);
  183. else
  184. {
  185. setPressed(!Pressed);
  186. }
  187. if ((!IsPushButton && wasPressed && Parent) ||
  188. (IsPushButton && wasPressed != Pressed))
  189. {
  190. ClickShiftState = event.MouseInput.Shift;
  191. ClickControlState = event.MouseInput.Control;
  192. SEvent newEvent;
  193. newEvent.EventType = EET_GUI_EVENT;
  194. newEvent.GUIEvent.Caller = this;
  195. newEvent.GUIEvent.Element = 0;
  196. newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
  197. Parent->OnEvent(newEvent);
  198. }
  199. return true;
  200. }
  201. break;
  202. default:
  203. break;
  204. }
  205. return Parent ? Parent->OnEvent(event) : false;
  206. }
  207. //! draws the element and its children
  208. void GUIButton::draw()
  209. {
  210. if (!IsVisible)
  211. return;
  212. // PATCH
  213. // Track hovered state, if it has changed then we need to update the style.
  214. bool hovered = isHovered();
  215. bool focused = isFocused();
  216. if (hovered != WasHovered || focused != WasFocused) {
  217. WasHovered = hovered;
  218. WasFocused = focused;
  219. setFromState();
  220. }
  221. GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());
  222. video::IVideoDriver* driver = Environment->getVideoDriver();
  223. // END PATCH
  224. if (DrawBorder)
  225. {
  226. if (!Pressed)
  227. {
  228. // PATCH
  229. skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,
  230. &AbsoluteClippingRect, Colors);
  231. // END PATCH
  232. }
  233. else
  234. {
  235. // PATCH
  236. skin->drawColored3DButtonPanePressed(this, AbsoluteRect,
  237. &AbsoluteClippingRect, Colors);
  238. // END PATCH
  239. }
  240. }
  241. const core::position2di buttonCenter(AbsoluteRect.getCenter());
  242. // PATCH
  243. // The image changes based on the state, so we use the default every time.
  244. EGUI_BUTTON_IMAGE_STATE imageState = EGBIS_IMAGE_UP;
  245. // END PATCH
  246. if ( ButtonImages[(u32)imageState].Texture )
  247. {
  248. core::position2d<s32> pos(buttonCenter);
  249. core::rect<s32> sourceRect(ButtonImages[(u32)imageState].SourceRect);
  250. if ( sourceRect.getWidth() == 0 && sourceRect.getHeight() == 0 )
  251. sourceRect = core::rect<s32>(core::position2di(0,0), ButtonImages[(u32)imageState].Texture->getOriginalSize());
  252. pos.X -= sourceRect.getWidth() / 2;
  253. pos.Y -= sourceRect.getHeight() / 2;
  254. if ( Pressed )
  255. {
  256. // Create a pressed-down effect by moving the image when it looks identical to the unpressed state image
  257. EGUI_BUTTON_IMAGE_STATE unpressedState = getImageState(false);
  258. if ( unpressedState == imageState || ButtonImages[(u32)imageState] == ButtonImages[(u32)unpressedState] )
  259. {
  260. pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);
  261. pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);
  262. }
  263. }
  264. // PATCH
  265. video::ITexture* texture = ButtonImages[(u32)imageState].Texture;
  266. video::SColor image_colors[] = { BgColor, BgColor, BgColor, BgColor };
  267. if (BgMiddle.getArea() == 0) {
  268. driver->draw2DImage(texture,
  269. ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
  270. sourceRect, &AbsoluteClippingRect,
  271. image_colors, UseAlphaChannel);
  272. } else {
  273. draw2DImage9Slice(driver, texture,
  274. ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
  275. sourceRect, BgMiddle, &AbsoluteClippingRect, image_colors);
  276. }
  277. // END PATCH
  278. }
  279. if (SpriteBank)
  280. {
  281. if (isEnabled())
  282. {
  283. core::position2di pos(buttonCenter);
  284. // pressed / unpressed animation
  285. EGUI_BUTTON_STATE state = Pressed ? EGBS_BUTTON_DOWN : EGBS_BUTTON_UP;
  286. drawSprite(state, ClickTime, pos);
  287. // focused / unfocused animation
  288. state = Environment->hasFocus(this) ? EGBS_BUTTON_FOCUSED : EGBS_BUTTON_NOT_FOCUSED;
  289. drawSprite(state, FocusTime, pos);
  290. // mouse over / off animation
  291. state = isHovered() ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;
  292. drawSprite(state, HoverTime, pos);
  293. }
  294. else
  295. {
  296. // draw disabled
  297. // drawSprite(EGBS_BUTTON_DISABLED, 0, pos);
  298. }
  299. }
  300. IGUIElement::draw();
  301. }
  302. void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)
  303. {
  304. u32 stateIdx = (u32)state;
  305. if (ButtonSprites[stateIdx].Index != -1)
  306. {
  307. if ( ButtonSprites[stateIdx].Scale )
  308. {
  309. const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color};
  310. SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect.UpperLeftCorner,
  311. &AbsoluteClippingRect, colors[0], // FIXME: remove [0]
  312. porting::getTimeMs()-startTime, ButtonSprites[stateIdx].Loop);
  313. }
  314. else
  315. {
  316. SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,
  317. &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, porting::getTimeMs(),
  318. ButtonSprites[stateIdx].Loop, true);
  319. }
  320. }
  321. }
  322. EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const
  323. {
  324. // PATCH
  325. return getImageState(pressed, ButtonImages);
  326. // END PATCH
  327. }
  328. EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed, const ButtonImage* images) const
  329. {
  330. // figure state we should have
  331. EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED;
  332. bool focused = isFocused();
  333. bool mouseOver = isHovered();
  334. if (isEnabled())
  335. {
  336. if ( pressed )
  337. {
  338. if ( focused && mouseOver )
  339. state = EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER;
  340. else if ( focused )
  341. state = EGBIS_IMAGE_DOWN_FOCUSED;
  342. else if ( mouseOver )
  343. state = EGBIS_IMAGE_DOWN_MOUSEOVER;
  344. else
  345. state = EGBIS_IMAGE_DOWN;
  346. }
  347. else // !pressed
  348. {
  349. if ( focused && mouseOver )
  350. state = EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER;
  351. else if ( focused )
  352. state = EGBIS_IMAGE_UP_FOCUSED;
  353. else if ( mouseOver )
  354. state = EGBIS_IMAGE_UP_MOUSEOVER;
  355. else
  356. state = EGBIS_IMAGE_UP;
  357. }
  358. }
  359. // find a compatible state that has images
  360. while ( state != EGBIS_IMAGE_UP && !images[(u32)state].Texture )
  361. {
  362. // PATCH
  363. switch ( state )
  364. {
  365. case EGBIS_IMAGE_UP_FOCUSED:
  366. state = EGBIS_IMAGE_UP;
  367. break;
  368. case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:
  369. state = EGBIS_IMAGE_UP_FOCUSED;
  370. break;
  371. case EGBIS_IMAGE_DOWN_MOUSEOVER:
  372. state = EGBIS_IMAGE_DOWN;
  373. break;
  374. case EGBIS_IMAGE_DOWN_FOCUSED:
  375. state = EGBIS_IMAGE_DOWN;
  376. break;
  377. case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:
  378. state = EGBIS_IMAGE_DOWN_FOCUSED;
  379. break;
  380. case EGBIS_IMAGE_DISABLED:
  381. if ( pressed )
  382. state = EGBIS_IMAGE_DOWN;
  383. else
  384. state = EGBIS_IMAGE_UP;
  385. break;
  386. default:
  387. state = EGBIS_IMAGE_UP;
  388. }
  389. // END PATCH
  390. }
  391. return state;
  392. }
  393. //! sets another skin independent font. if this is set to zero, the button uses the font of the skin.
  394. void GUIButton::setOverrideFont(IGUIFont* font)
  395. {
  396. if (OverrideFont == font)
  397. return;
  398. if (OverrideFont)
  399. OverrideFont->drop();
  400. OverrideFont = font;
  401. if (OverrideFont)
  402. OverrideFont->grab();
  403. StaticText->setOverrideFont(font);
  404. }
  405. //! Gets the override font (if any)
  406. IGUIFont * GUIButton::getOverrideFont() const
  407. {
  408. return OverrideFont;
  409. }
  410. //! Get the font which is used right now for drawing
  411. IGUIFont* GUIButton::getActiveFont() const
  412. {
  413. if ( OverrideFont )
  414. return OverrideFont;
  415. IGUISkin* skin = Environment->getSkin();
  416. if (skin)
  417. return skin->getFont(EGDF_BUTTON);
  418. return 0;
  419. }
  420. //! Sets another color for the text.
  421. void GUIButton::setOverrideColor(video::SColor color)
  422. {
  423. OverrideColor = color;
  424. OverrideColorEnabled = true;
  425. StaticText->setOverrideColor(color);
  426. }
  427. video::SColor GUIButton::getOverrideColor() const
  428. {
  429. return OverrideColor;
  430. }
  431. video::SColor GUIButton::getActiveColor() const
  432. {
  433. return video::SColor(0,0,0,0); // unused?
  434. }
  435. void GUIButton::enableOverrideColor(bool enable)
  436. {
  437. OverrideColorEnabled = enable;
  438. }
  439. bool GUIButton::isOverrideColorEnabled() const
  440. {
  441. return OverrideColorEnabled;
  442. }
  443. void GUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect<s32>& sourceRect)
  444. {
  445. if ( state >= EGBIS_COUNT )
  446. return;
  447. if ( image )
  448. image->grab();
  449. u32 stateIdx = (u32)state;
  450. if ( ButtonImages[stateIdx].Texture )
  451. ButtonImages[stateIdx].Texture->drop();
  452. ButtonImages[stateIdx].Texture = image;
  453. ButtonImages[stateIdx].SourceRect = sourceRect;
  454. }
  455. // PATCH
  456. void GUIButton::setImage(video::ITexture* image)
  457. {
  458. setImage(gui::EGBIS_IMAGE_UP, image);
  459. }
  460. void GUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos)
  461. {
  462. setImage(gui::EGBIS_IMAGE_UP, image, pos);
  463. }
  464. void GUIButton::setPressedImage(video::ITexture* image)
  465. {
  466. setImage(gui::EGBIS_IMAGE_DOWN, image);
  467. }
  468. void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos)
  469. {
  470. setImage(gui::EGBIS_IMAGE_DOWN, image, pos);
  471. }
  472. //! Sets the text displayed by the button
  473. void GUIButton::setText(const wchar_t* text)
  474. {
  475. StaticText->setText(text);
  476. IGUIButton::setText(text);
  477. }
  478. // END PATCH
  479. //! Sets if the button should behave like a push button. Which means it
  480. //! can be in two states: Normal or Pressed. With a click on the button,
  481. //! the user can change the state of the button.
  482. void GUIButton::setIsPushButton(bool isPushButton)
  483. {
  484. IsPushButton = isPushButton;
  485. }
  486. //! Returns if the button is currently pressed
  487. bool GUIButton::isPressed() const
  488. {
  489. return Pressed;
  490. }
  491. // PATCH
  492. //! Returns if this element (or one of its direct children) is hovered
  493. bool GUIButton::isHovered() const
  494. {
  495. IGUIElement *hovered = Environment->getHovered();
  496. return hovered == this || (hovered != nullptr && hovered->getParent() == this);
  497. }
  498. //! Returns if this element (or one of its direct children) is focused
  499. bool GUIButton::isFocused() const
  500. {
  501. return Environment->hasFocus((IGUIElement*)this, true);
  502. }
  503. // END PATCH
  504. //! Sets the pressed state of the button if this is a pushbutton
  505. void GUIButton::setPressed(bool pressed)
  506. {
  507. if (Pressed != pressed)
  508. {
  509. ClickTime = porting::getTimeMs();
  510. Pressed = pressed;
  511. setFromState();
  512. }
  513. }
  514. //! Returns whether the button is a push button
  515. bool GUIButton::isPushButton() const
  516. {
  517. return IsPushButton;
  518. }
  519. //! Sets if the alpha channel should be used for drawing images on the button (default is false)
  520. void GUIButton::setUseAlphaChannel(bool useAlphaChannel)
  521. {
  522. UseAlphaChannel = useAlphaChannel;
  523. }
  524. //! Returns if the alpha channel should be used for drawing images on the button
  525. bool GUIButton::isAlphaChannelUsed() const
  526. {
  527. return UseAlphaChannel;
  528. }
  529. bool GUIButton::isDrawingBorder() const
  530. {
  531. return DrawBorder;
  532. }
  533. // PATCH
  534. GUIButton* GUIButton::addButton(IGUIEnvironment *environment,
  535. const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,
  536. IGUIElement* parent, s32 id, const wchar_t* text,
  537. const wchar_t *tooltiptext)
  538. {
  539. GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);
  540. if (text)
  541. button->setText(text);
  542. if ( tooltiptext )
  543. button->setToolTipText ( tooltiptext );
  544. button->drop();
  545. return button;
  546. }
  547. void GUIButton::setColor(video::SColor color)
  548. {
  549. BgColor = color;
  550. float d = 0.65f;
  551. for (size_t i = 0; i < 4; i++) {
  552. video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
  553. Colors[i] = base.getInterpolated(color, d);
  554. }
  555. }
  556. //! Set element properties from a StyleSpec corresponding to the button state
  557. void GUIButton::setFromState()
  558. {
  559. StyleSpec::State state = StyleSpec::STATE_DEFAULT;
  560. if (isPressed())
  561. state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_PRESSED);
  562. if (isHovered())
  563. state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_HOVERED);
  564. if (isFocused())
  565. state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_FOCUSED);
  566. setFromStyle(StyleSpec::getStyleFromStatePropagation(Styles, state));
  567. }
  568. //! Set element properties from a StyleSpec
  569. void GUIButton::setFromStyle(const StyleSpec& style)
  570. {
  571. bool hovered = (style.getState() & StyleSpec::STATE_HOVERED) != 0;
  572. bool pressed = (style.getState() & StyleSpec::STATE_PRESSED) != 0;
  573. if (style.isNotDefault(StyleSpec::BGCOLOR)) {
  574. setColor(style.getColor(StyleSpec::BGCOLOR));
  575. // If we have a propagated hover/press color, we need to automatically
  576. // lighten/darken it
  577. if (!Styles[style.getState()].isNotDefault(StyleSpec::BGCOLOR)) {
  578. if (pressed) {
  579. BgColor = multiplyColorValue(BgColor, COLOR_PRESSED_MOD);
  580. for (size_t i = 0; i < 4; i++)
  581. Colors[i] = multiplyColorValue(Colors[i], COLOR_PRESSED_MOD);
  582. } else if (hovered) {
  583. BgColor = multiplyColorValue(BgColor, COLOR_HOVERED_MOD);
  584. for (size_t i = 0; i < 4; i++)
  585. Colors[i] = multiplyColorValue(Colors[i], COLOR_HOVERED_MOD);
  586. }
  587. }
  588. } else {
  589. BgColor = video::SColor(255, 255, 255, 255);
  590. for (size_t i = 0; i < 4; i++) {
  591. video::SColor base =
  592. Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
  593. if (pressed) {
  594. Colors[i] = multiplyColorValue(base, COLOR_PRESSED_MOD);
  595. } else if (hovered) {
  596. Colors[i] = multiplyColorValue(base, COLOR_HOVERED_MOD);
  597. } else {
  598. Colors[i] = base;
  599. }
  600. }
  601. }
  602. if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {
  603. setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));
  604. } else {
  605. setOverrideColor(video::SColor(255,255,255,255));
  606. OverrideColorEnabled = false;
  607. }
  608. setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
  609. setDrawBorder(style.getBool(StyleSpec::BORDER, true));
  610. setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));
  611. setOverrideFont(style.getFont());
  612. if (style.isNotDefault(StyleSpec::BGIMG)) {
  613. video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,
  614. getTextureSource());
  615. setImage(guiScalingImageButton(
  616. Environment->getVideoDriver(), texture,
  617. AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));
  618. setScaleImage(true);
  619. } else {
  620. setImage(nullptr);
  621. }
  622. BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);
  623. // Child padding and offset
  624. Padding = style.getRect(StyleSpec::PADDING, core::rect<s32>());
  625. Padding = core::rect<s32>(
  626. Padding.UpperLeftCorner + BgMiddle.UpperLeftCorner,
  627. Padding.LowerRightCorner + BgMiddle.LowerRightCorner);
  628. GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());
  629. core::vector2d<s32> defaultPressOffset(
  630. skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),
  631. skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y));
  632. ContentOffset = style.getVector2i(StyleSpec::CONTENT_OFFSET, isPressed()
  633. ? defaultPressOffset
  634. : core::vector2d<s32>(0));
  635. core::rect<s32> childBounds(
  636. Padding.UpperLeftCorner.X + ContentOffset.X,
  637. Padding.UpperLeftCorner.Y + ContentOffset.Y,
  638. AbsoluteRect.getWidth() + Padding.LowerRightCorner.X + ContentOffset.X,
  639. AbsoluteRect.getHeight() + Padding.LowerRightCorner.Y + ContentOffset.Y);
  640. for (IGUIElement *child : getChildren()) {
  641. child->setRelativePosition(childBounds);
  642. }
  643. }
  644. //! Set the styles used for each state
  645. void GUIButton::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles)
  646. {
  647. Styles = styles;
  648. setFromState();
  649. }
  650. // END PATCH