]> git.lizzy.rs Git - minetest.git/blob - src/gui/guiButton.cpp
be7e0c4391ec3ecf89f6b85d5d9b07e61888565b
[minetest.git] / src / gui / guiButton.cpp
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
4 \r
5 #include "guiButton.h"\r
6 \r
7 \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
18 \r
19 using namespace irr;\r
20 using namespace gui;\r
21 \r
22 // Multiply with a color to get the default corresponding hovered color\r
23 #define COLOR_HOVERED_MOD 1.25f\r
24 \r
25 // Multiply with a color to get the default corresponding pressed color\r
26 #define COLOR_PRESSED_MOD 0.85f\r
27 \r
28 //! constructor\r
29 GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,\r
30                         s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,\r
31                         bool noclip)\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
39 {\r
40         setNotClipped(noclip);\r
41 \r
42         // This element can be tabbed.\r
43         setTabStop(true);\r
44         setTabOrder(-1);\r
45 \r
46         // PATCH\r
47         for (size_t i = 0; i < 4; i++) {\r
48                 Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);\r
49         }\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
52         // END PATCH\r
53 }\r
54 \r
55 //! destructor\r
56 GUIButton::~GUIButton()\r
57 {\r
58         if (OverrideFont)\r
59                 OverrideFont->drop();\r
60 \r
61         if (SpriteBank)\r
62                 SpriteBank->drop();\r
63 }\r
64 \r
65 \r
66 //! Sets if the images should be scaled to fit the button\r
67 void GUIButton::setScaleImage(bool scaleImage)\r
68 {\r
69         ScaleImage = scaleImage;\r
70 }\r
71 \r
72 \r
73 //! Returns whether the button scale the used images\r
74 bool GUIButton::isScalingImage() const\r
75 {\r
76         return ScaleImage;\r
77 }\r
78 \r
79 \r
80 //! Sets if the button should use the skin to draw its border\r
81 void GUIButton::setDrawBorder(bool border)\r
82 {\r
83         DrawBorder = border;\r
84 }\r
85 \r
86 \r
87 void GUIButton::setSpriteBank(IGUISpriteBank* sprites)\r
88 {\r
89         if (sprites)\r
90                 sprites->grab();\r
91 \r
92         if (SpriteBank)\r
93                 SpriteBank->drop();\r
94 \r
95         SpriteBank = sprites;\r
96 }\r
97 \r
98 void GUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale)\r
99 {\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
104 }\r
105 \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
108 {\r
109         return ButtonSprites[(u32)state].Index;\r
110 }\r
111 \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
114 {\r
115         return ButtonSprites[(u32)state].Color;\r
116 }\r
117 \r
118 //! Returns if the sprite in the given state does loop\r
119 bool GUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const\r
120 {\r
121         return ButtonSprites[(u32)state].Loop;\r
122 }\r
123 \r
124 //! Returns if the sprite in the given state is scaled\r
125 bool GUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const\r
126 {\r
127         return ButtonSprites[(u32)state].Scale;\r
128 }\r
129 \r
130 //! called if an event happened.\r
131 bool GUIButton::OnEvent(const SEvent& event)\r
132 {\r
133         if (!isEnabled())\r
134                 return IGUIElement::OnEvent(event);\r
135 \r
136         switch(event.EventType)\r
137         {\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
141                 {\r
142                         if (!IsPushButton)\r
143                                 setPressed(true);\r
144                         else\r
145                                 setPressed(!Pressed);\r
146 \r
147                         return true;\r
148                 }\r
149                 if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)\r
150                 {\r
151                         setPressed(false);\r
152                         return true;\r
153                 }\r
154                 else\r
155                 if (!event.KeyInput.PressedDown && Pressed &&\r
156                         (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))\r
157                 {\r
158 \r
159                         if (!IsPushButton)\r
160                                 setPressed(false);\r
161 \r
162                         if (Parent)\r
163                         {\r
164                                 ClickShiftState = event.KeyInput.Shift;\r
165                                 ClickControlState = event.KeyInput.Control;\r
166 \r
167                                 SEvent newEvent;\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
173                         }\r
174                         return true;\r
175                 }\r
176                 break;\r
177         case EET_GUI_EVENT:\r
178                 if (event.GUIEvent.Caller == this)\r
179                 {\r
180                         if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)\r
181                         {\r
182                                 if (!IsPushButton)\r
183                                         setPressed(false);\r
184                                 FocusTime = (u32)porting::getTimeMs();\r
185                         }\r
186                         else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)\r
187                         {\r
188                                 FocusTime = (u32)porting::getTimeMs();\r
189                         }\r
190                         else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)\r
191                         {\r
192                                 HoverTime = (u32)porting::getTimeMs();\r
193                         }\r
194                 }\r
195                 break;\r
196         case EET_MOUSE_INPUT_EVENT:\r
197                 if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
198                 {\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
203                                 setPressed(true);\r
204                         }\r
205 \r
206                         return true;\r
207                 }\r
208                 else\r
209                 if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
210                 {\r
211                         bool wasPressed = Pressed;\r
212 \r
213                         if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )\r
214                         {\r
215                                 if (!IsPushButton)\r
216                                         setPressed(false);\r
217                                 return true;\r
218                         }\r
219 \r
220                         if (!IsPushButton)\r
221                                 setPressed(false);\r
222                         else\r
223                         {\r
224                                 setPressed(!Pressed);\r
225                         }\r
226 \r
227                         if ((!IsPushButton && wasPressed && Parent) ||\r
228                                 (IsPushButton && wasPressed != Pressed))\r
229                         {\r
230                                 ClickShiftState = event.MouseInput.Shift;\r
231                                 ClickControlState = event.MouseInput.Control;\r
232 \r
233                                 SEvent newEvent;\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
239                         }\r
240 \r
241                         return true;\r
242                 }\r
243                 break;\r
244         default:\r
245                 break;\r
246         }\r
247 \r
248         return Parent ? Parent->OnEvent(event) : false;\r
249 }\r
250 \r
251 \r
252 //! draws the element and its children\r
253 void GUIButton::draw()\r
254 {\r
255         if (!IsVisible)\r
256                 return;\r
257 \r
258         // PATCH\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
263                 setFromState();\r
264         }\r
265 \r
266         GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
267         video::IVideoDriver* driver = Environment->getVideoDriver();\r
268         // END PATCH\r
269 \r
270         if (DrawBorder)\r
271         {\r
272                 if (!Pressed)\r
273                 {\r
274                         // PATCH\r
275                         skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,\r
276                                         &AbsoluteClippingRect, Colors);\r
277                         // END PATCH\r
278                 }\r
279                 else\r
280                 {\r
281                         // PATCH\r
282                         skin->drawColored3DButtonPanePressed(this, AbsoluteRect,\r
283                                         &AbsoluteClippingRect, Colors);\r
284                         // END PATCH\r
285                 }\r
286         }\r
287 \r
288         const core::position2di buttonCenter(AbsoluteRect.getCenter());\r
289         // PATCH\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
292         // END PATCH\r
293         if ( ButtonImages[(u32)imageState].Texture )\r
294         {\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
299 \r
300                 pos.X -= sourceRect.getWidth() / 2;\r
301                 pos.Y -= sourceRect.getHeight() / 2;\r
302 \r
303                 if ( Pressed )\r
304                 {\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
308                         {\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
311                         }\r
312                 }\r
313 \r
314                 // PATCH\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
322                 } else {\r
323                         draw2DImage9Slice(driver, texture,\r
324                                         ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
325                                         sourceRect, BgMiddle, &AbsoluteClippingRect, image_colors);\r
326                 }\r
327                 // END PATCH\r
328         }\r
329 \r
330         if (SpriteBank)\r
331         {\r
332                 if (isEnabled())\r
333                 {\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
338 \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
342 \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
346                 }\r
347                 else\r
348                 {\r
349                         // draw disabled\r
350 //                      drawSprite(EGBS_BUTTON_DISABLED, 0, pos);\r
351                 }\r
352         }\r
353 \r
354         IGUIElement::draw();\r
355 }\r
356 \r
357 void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)\r
358 {\r
359         u32 stateIdx = (u32)state;\r
360 \r
361         if (ButtonSprites[stateIdx].Index != -1)\r
362         {\r
363                 if ( ButtonSprites[stateIdx].Scale )\r
364                 {\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
369                 }\r
370                 else\r
371                 {\r
372                         SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,\r
373                                 &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, porting::getTimeMs(),\r
374                                 ButtonSprites[stateIdx].Loop, true);\r
375                 }\r
376         }\r
377 }\r
378 \r
379 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const\r
380 {\r
381         // PATCH\r
382         return getImageState(pressed, ButtonImages);\r
383         // END PATCH\r
384 }\r
385 \r
386 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed, const ButtonImage* images) const\r
387 {\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
392         if (isEnabled())\r
393         {\r
394                 if ( pressed )\r
395                 {\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
402                         else\r
403                                 state = EGBIS_IMAGE_DOWN;\r
404                 }\r
405                 else // !pressed\r
406                 {\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
413                         else\r
414                                 state = EGBIS_IMAGE_UP;\r
415                 }\r
416         }\r
417 \r
418         // find a compatible state that has images\r
419         while ( state != EGBIS_IMAGE_UP && !images[(u32)state].Texture )\r
420         {\r
421                 // PATCH\r
422                 switch ( state )\r
423                 {\r
424                         case EGBIS_IMAGE_UP_FOCUSED:\r
425                                 state = EGBIS_IMAGE_UP;\r
426                                 break;\r
427                         case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:\r
428                                 state = EGBIS_IMAGE_UP_FOCUSED;\r
429                                 break;\r
430                         case EGBIS_IMAGE_DOWN_MOUSEOVER:\r
431                                 state = EGBIS_IMAGE_DOWN;\r
432                                 break;\r
433                         case EGBIS_IMAGE_DOWN_FOCUSED:\r
434                                 state = EGBIS_IMAGE_DOWN;\r
435                                 break;\r
436                         case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:\r
437                                 state = EGBIS_IMAGE_DOWN_FOCUSED;\r
438                                 break;\r
439                         case EGBIS_IMAGE_DISABLED:\r
440                                 if ( pressed )\r
441                                         state = EGBIS_IMAGE_DOWN;\r
442                                 else\r
443                                         state = EGBIS_IMAGE_UP;\r
444                                 break;\r
445                         default:\r
446                                 state = EGBIS_IMAGE_UP;\r
447                 }\r
448                 // END PATCH\r
449         }\r
450 \r
451         return state;\r
452 }\r
453 \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
456 {\r
457         if (OverrideFont == font)\r
458                 return;\r
459 \r
460         if (OverrideFont)\r
461                 OverrideFont->drop();\r
462 \r
463         OverrideFont = font;\r
464 \r
465         if (OverrideFont)\r
466                 OverrideFont->grab();\r
467 \r
468         StaticText->setOverrideFont(font);\r
469 }\r
470 \r
471 //! Gets the override font (if any)\r
472 IGUIFont * GUIButton::getOverrideFont() const\r
473 {\r
474         return OverrideFont;\r
475 }\r
476 \r
477 //! Get the font which is used right now for drawing\r
478 IGUIFont* GUIButton::getActiveFont() const\r
479 {\r
480         if ( OverrideFont )\r
481                 return OverrideFont;\r
482         IGUISkin* skin = Environment->getSkin();\r
483         if (skin)\r
484                 return skin->getFont(EGDF_BUTTON);\r
485         return 0;\r
486 }\r
487 \r
488 //! Sets another color for the text.\r
489 void GUIButton::setOverrideColor(video::SColor color)\r
490 {\r
491         OverrideColor = color;\r
492         OverrideColorEnabled = true;\r
493 \r
494         StaticText->setOverrideColor(color);\r
495 }\r
496 \r
497 video::SColor GUIButton::getOverrideColor() const\r
498 {\r
499         return OverrideColor;\r
500 }\r
501 \r
502 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8\r
503 video::SColor GUIButton::getActiveColor() const\r
504 {\r
505         return video::SColor(0,0,0,0); // unused?\r
506 }\r
507 #endif\r
508 \r
509 void GUIButton::enableOverrideColor(bool enable)\r
510 {\r
511         OverrideColorEnabled = enable;\r
512 }\r
513 \r
514 bool GUIButton::isOverrideColorEnabled() const\r
515 {\r
516         return OverrideColorEnabled;\r
517 }\r
518 \r
519 void GUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect<s32>& sourceRect)\r
520 {\r
521         if ( state >= EGBIS_COUNT )\r
522                 return;\r
523 \r
524         if ( image )\r
525                 image->grab();\r
526 \r
527         u32 stateIdx = (u32)state;\r
528         if ( ButtonImages[stateIdx].Texture )\r
529                 ButtonImages[stateIdx].Texture->drop();\r
530 \r
531         ButtonImages[stateIdx].Texture = image;\r
532         ButtonImages[stateIdx].SourceRect = sourceRect;\r
533 }\r
534 \r
535 // PATCH\r
536 void GUIButton::setImage(video::ITexture* image)\r
537 {\r
538         setImage(gui::EGBIS_IMAGE_UP, image);\r
539 }\r
540 \r
541 void GUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos)\r
542 {\r
543         setImage(gui::EGBIS_IMAGE_UP, image, pos);\r
544 }\r
545 \r
546 void GUIButton::setPressedImage(video::ITexture* image)\r
547 {\r
548         setImage(gui::EGBIS_IMAGE_DOWN, image);\r
549 }\r
550 \r
551 void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos)\r
552 {\r
553         setImage(gui::EGBIS_IMAGE_DOWN, image, pos);\r
554 }\r
555 \r
556 //! Sets the text displayed by the button\r
557 void GUIButton::setText(const wchar_t* text)\r
558 {\r
559         StaticText->setText(text);\r
560 \r
561         IGUIButton::setText(text);\r
562 }\r
563 // END PATCH\r
564 \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
569 {\r
570         IsPushButton = isPushButton;\r
571 }\r
572 \r
573 \r
574 //! Returns if the button is currently pressed\r
575 bool GUIButton::isPressed() const\r
576 {\r
577         return Pressed;\r
578 }\r
579 \r
580 // PATCH\r
581 //! Returns if this element (or one of its direct children) is hovered\r
582 bool GUIButton::isHovered() const\r
583 {\r
584         IGUIElement *hovered = Environment->getHovered();\r
585         return  hovered == this || (hovered != nullptr && hovered->getParent() == this);\r
586 }\r
587 // END PATCH\r
588 \r
589 //! Sets the pressed state of the button if this is a pushbutton\r
590 void GUIButton::setPressed(bool pressed)\r
591 {\r
592         if (Pressed != pressed)\r
593         {\r
594                 ClickTime = porting::getTimeMs();\r
595                 Pressed = pressed;\r
596                 setFromState();\r
597         }\r
598 }\r
599 \r
600 \r
601 //! Returns whether the button is a push button\r
602 bool GUIButton::isPushButton() const\r
603 {\r
604         return IsPushButton;\r
605 }\r
606 \r
607 \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
610 {\r
611         UseAlphaChannel = useAlphaChannel;\r
612 }\r
613 \r
614 \r
615 //! Returns if the alpha channel should be used for drawing images on the button\r
616 bool GUIButton::isAlphaChannelUsed() const\r
617 {\r
618         return UseAlphaChannel;\r
619 }\r
620 \r
621 \r
622 bool GUIButton::isDrawingBorder() const\r
623 {\r
624         return DrawBorder;\r
625 }\r
626 \r
627 \r
628 // PATCH\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
633 {\r
634         GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);\r
635         if (text)\r
636                 button->setText(text);\r
637 \r
638         if ( tooltiptext )\r
639                 button->setToolTipText ( tooltiptext );\r
640 \r
641         button->drop();\r
642         return button;\r
643 }\r
644 \r
645 void GUIButton::setColor(video::SColor color)\r
646 {\r
647         BgColor = color;\r
648 \r
649         float d = 0.65f;\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
653         }\r
654 }\r
655 \r
656 //! Set element properties from a StyleSpec corresponding to the button state\r
657 void GUIButton::setFromState()\r
658 {\r
659         StyleSpec::State state = StyleSpec::STATE_DEFAULT;\r
660 \r
661         if (isPressed())\r
662                 state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_PRESSED);\r
663 \r
664         if (isHovered())\r
665                 state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_HOVERED);\r
666 \r
667         setFromStyle(StyleSpec::getStyleFromStatePropagation(Styles, state));\r
668 }\r
669 \r
670 //! Set element properties from a StyleSpec\r
671 void GUIButton::setFromStyle(const StyleSpec& style)\r
672 {\r
673         bool hovered = (style.getState() & StyleSpec::STATE_HOVERED) != 0;\r
674         bool pressed = (style.getState() & StyleSpec::STATE_PRESSED) != 0;\r
675 \r
676         if (style.isNotDefault(StyleSpec::BGCOLOR)) {\r
677                 setColor(style.getColor(StyleSpec::BGCOLOR));\r
678 \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
682                                 if (pressed) {\r
683                                         BgColor = multiplyColorValue(BgColor, COLOR_PRESSED_MOD);\r
684 \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
689 \r
690                                         for (size_t i = 0; i < 4; i++)\r
691                                                 Colors[i] = multiplyColorValue(Colors[i], COLOR_HOVERED_MOD);\r
692                                 }\r
693                 }\r
694 \r
695         } else {\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
700                         if (pressed) {\r
701                                 Colors[i] = multiplyColorValue(base, COLOR_PRESSED_MOD);\r
702                         } else if (hovered) {\r
703                                 Colors[i] = multiplyColorValue(base, COLOR_HOVERED_MOD);\r
704                         } else {\r
705                                 Colors[i] = base;\r
706                         }\r
707                 }\r
708         }\r
709 \r
710         if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {\r
711                 setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));\r
712         } else {\r
713                 setOverrideColor(video::SColor(255,255,255,255));\r
714                 OverrideColorEnabled = false;\r
715         }\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
720 \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
728         } else {\r
729                 setImage(nullptr);\r
730         }\r
731 \r
732         BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);\r
733 \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
739 \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
747 \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
753 \r
754         for (IGUIElement *child : getChildren()) {\r
755                 child->setRelativePosition(childBounds);\r
756         }\r
757 }\r
758 \r
759 //! Set the styles used for each state\r
760 void GUIButton::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles)\r
761 {\r
762         Styles = styles;\r
763         setFromState();\r
764 }\r
765 // END PATCH\r