]> git.lizzy.rs Git - dragonfireclient.git/blob - src/gui/guiButton.cpp
Formspecs: Add starting frame to `animated_image` (#9411)
[dragonfireclient.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 \r
18 using namespace irr;\r
19 using namespace gui;\r
20 \r
21 // Multiply with a color to get the default corresponding hovered color\r
22 #define COLOR_HOVERED_MOD 1.25f\r
23 \r
24 // Multiply with a color to get the default corresponding pressed color\r
25 #define COLOR_PRESSED_MOD 0.85f\r
26 \r
27 //! constructor\r
28 GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,\r
29                         s32 id, core::rect<s32> rectangle, bool noclip)\r
30 : IGUIButton(environment, parent, id, rectangle),\r
31         SpriteBank(0), OverrideFont(0),\r
32         OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),\r
33         ClickTime(0), HoverTime(0), FocusTime(0),\r
34         ClickShiftState(false), ClickControlState(false),\r
35         IsPushButton(false), Pressed(false),\r
36         UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)\r
37 {\r
38         setNotClipped(noclip);\r
39 \r
40         // This element can be tabbed.\r
41         setTabStop(true);\r
42         setTabOrder(-1);\r
43 \r
44         // PATCH\r
45         for (size_t i = 0; i < 4; i++) {\r
46                 Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);\r
47                 HoveredColors[i] = irr::video::SColor(Colors[i].getAlpha(),\r
48                         core::clamp<u32>(Colors[i].getRed() * COLOR_HOVERED_MOD, 0, 255),\r
49                         core::clamp<u32>(Colors[i].getGreen() * COLOR_HOVERED_MOD, 0, 255),\r
50                         core::clamp<u32>(Colors[i].getBlue() * COLOR_HOVERED_MOD, 0, 255));\r
51                 PressedColors[i] = irr::video::SColor(Colors[i].getAlpha(),\r
52                         core::clamp<u32>(Colors[i].getRed() * COLOR_PRESSED_MOD, 0, 255),\r
53                         core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),\r
54                         core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));\r
55         }\r
56         StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);\r
57         StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);\r
58         // END PATCH\r
59 }\r
60 \r
61 //! destructor\r
62 GUIButton::~GUIButton()\r
63 {\r
64         if (OverrideFont)\r
65                 OverrideFont->drop();\r
66 \r
67         if (SpriteBank)\r
68                 SpriteBank->drop();\r
69 }\r
70 \r
71 \r
72 //! Sets if the images should be scaled to fit the button\r
73 void GUIButton::setScaleImage(bool scaleImage)\r
74 {\r
75         ScaleImage = scaleImage;\r
76 }\r
77 \r
78 \r
79 //! Returns whether the button scale the used images\r
80 bool GUIButton::isScalingImage() const\r
81 {\r
82         return ScaleImage;\r
83 }\r
84 \r
85 \r
86 //! Sets if the button should use the skin to draw its border\r
87 void GUIButton::setDrawBorder(bool border)\r
88 {\r
89         DrawBorder = border;\r
90 }\r
91 \r
92 \r
93 void GUIButton::setSpriteBank(IGUISpriteBank* sprites)\r
94 {\r
95         if (sprites)\r
96                 sprites->grab();\r
97 \r
98         if (SpriteBank)\r
99                 SpriteBank->drop();\r
100 \r
101         SpriteBank = sprites;\r
102 }\r
103 \r
104 void GUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale)\r
105 {\r
106         ButtonSprites[(u32)state].Index = index;\r
107         ButtonSprites[(u32)state].Color = color;\r
108         ButtonSprites[(u32)state].Loop  = loop;\r
109         ButtonSprites[(u32)state].Scale = scale;\r
110 }\r
111 \r
112 //! Get the sprite-index for the given state or -1 when no sprite is set\r
113 s32 GUIButton::getSpriteIndex(EGUI_BUTTON_STATE state) const\r
114 {\r
115         return ButtonSprites[(u32)state].Index;\r
116 }\r
117 \r
118 //! Get the sprite color for the given state. Color is only used when a sprite is set.\r
119 video::SColor GUIButton::getSpriteColor(EGUI_BUTTON_STATE state) const\r
120 {\r
121         return ButtonSprites[(u32)state].Color;\r
122 }\r
123 \r
124 //! Returns if the sprite in the given state does loop\r
125 bool GUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const\r
126 {\r
127         return ButtonSprites[(u32)state].Loop;\r
128 }\r
129 \r
130 //! Returns if the sprite in the given state is scaled\r
131 bool GUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const\r
132 {\r
133         return ButtonSprites[(u32)state].Scale;\r
134 }\r
135 \r
136 //! called if an event happened.\r
137 bool GUIButton::OnEvent(const SEvent& event)\r
138 {\r
139         if (!isEnabled())\r
140                 return IGUIElement::OnEvent(event);\r
141 \r
142         switch(event.EventType)\r
143         {\r
144         case EET_KEY_INPUT_EVENT:\r
145                 if (event.KeyInput.PressedDown &&\r
146                         (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))\r
147                 {\r
148                         if (!IsPushButton)\r
149                                 setPressed(true);\r
150                         else\r
151                                 setPressed(!Pressed);\r
152 \r
153                         return true;\r
154                 }\r
155                 if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)\r
156                 {\r
157                         setPressed(false);\r
158                         return true;\r
159                 }\r
160                 else\r
161                 if (!event.KeyInput.PressedDown && Pressed &&\r
162                         (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))\r
163                 {\r
164 \r
165                         if (!IsPushButton)\r
166                                 setPressed(false);\r
167 \r
168                         if (Parent)\r
169                         {\r
170                                 ClickShiftState = event.KeyInput.Shift;\r
171                                 ClickControlState = event.KeyInput.Control;\r
172 \r
173                                 SEvent newEvent;\r
174                                 newEvent.EventType = EET_GUI_EVENT;\r
175                                 newEvent.GUIEvent.Caller = this;\r
176                                 newEvent.GUIEvent.Element = 0;\r
177                                 newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;\r
178                                 Parent->OnEvent(newEvent);\r
179                         }\r
180                         return true;\r
181                 }\r
182                 break;\r
183         case EET_GUI_EVENT:\r
184                 if (event.GUIEvent.Caller == this)\r
185                 {\r
186                         if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)\r
187                         {\r
188                                 if (!IsPushButton)\r
189                                         setPressed(false);\r
190                                 FocusTime = (u32)porting::getTimeMs();\r
191                         }\r
192                         else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)\r
193                         {\r
194                                 FocusTime = (u32)porting::getTimeMs();\r
195                         }\r
196                         else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)\r
197                         {\r
198                                 HoverTime = (u32)porting::getTimeMs();\r
199                         }\r
200                 }\r
201                 break;\r
202         case EET_MOUSE_INPUT_EVENT:\r
203                 if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
204                 {\r
205                         // Sometimes formspec elements can receive mouse events when the\r
206                         // mouse is outside of the formspec. Thus, we test the position here.\r
207                         if ( !IsPushButton && AbsoluteClippingRect.isPointInside(\r
208                                                 core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ))) {\r
209                                 setPressed(true);\r
210                         }\r
211 \r
212                         return true;\r
213                 }\r
214                 else\r
215                 if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
216                 {\r
217                         bool wasPressed = Pressed;\r
218 \r
219                         if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )\r
220                         {\r
221                                 if (!IsPushButton)\r
222                                         setPressed(false);\r
223                                 return true;\r
224                         }\r
225 \r
226                         if (!IsPushButton)\r
227                                 setPressed(false);\r
228                         else\r
229                         {\r
230                                 setPressed(!Pressed);\r
231                         }\r
232 \r
233                         if ((!IsPushButton && wasPressed && Parent) ||\r
234                                 (IsPushButton && wasPressed != Pressed))\r
235                         {\r
236                                 ClickShiftState = event.MouseInput.Shift;\r
237                                 ClickControlState = event.MouseInput.Control;\r
238 \r
239                                 SEvent newEvent;\r
240                                 newEvent.EventType = EET_GUI_EVENT;\r
241                                 newEvent.GUIEvent.Caller = this;\r
242                                 newEvent.GUIEvent.Element = 0;\r
243                                 newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;\r
244                                 Parent->OnEvent(newEvent);\r
245                         }\r
246 \r
247                         return true;\r
248                 }\r
249                 break;\r
250         default:\r
251                 break;\r
252         }\r
253 \r
254         return Parent ? Parent->OnEvent(event) : false;\r
255 }\r
256 \r
257 \r
258 //! draws the element and its children\r
259 void GUIButton::draw()\r
260 {\r
261         if (!IsVisible)\r
262                 return;\r
263 \r
264         // PATCH\r
265         GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
266         video::IVideoDriver* driver = Environment->getVideoDriver();\r
267         // END PATCH\r
268 \r
269         if (DrawBorder)\r
270         {\r
271                 if (!Pressed)\r
272                 {\r
273                         // PATCH\r
274                         skin->drawColored3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect,\r
275                                 isHovered() ? HoveredColors : Colors);\r
276                         // END PATCH\r
277                 }\r
278                 else\r
279                 {\r
280                         // PATCH\r
281                         skin->drawColored3DButtonPanePressed(this,\r
282                                         AbsoluteRect, &AbsoluteClippingRect, PressedColors);\r
283                         // END PATCH\r
284                 }\r
285         }\r
286 \r
287         const core::position2di buttonCenter(AbsoluteRect.getCenter());\r
288         EGUI_BUTTON_IMAGE_STATE imageState = getImageState(Pressed);\r
289         if ( ButtonImages[(u32)imageState].Texture )\r
290         {\r
291                 core::position2d<s32> pos(buttonCenter);\r
292                 core::rect<s32> sourceRect(ButtonImages[(u32)imageState].SourceRect);\r
293                 if ( sourceRect.getWidth() == 0 && sourceRect.getHeight() == 0 )\r
294                         sourceRect = core::rect<s32>(core::position2di(0,0), ButtonImages[(u32)imageState].Texture->getOriginalSize());\r
295 \r
296                 pos.X -= sourceRect.getWidth() / 2;\r
297                 pos.Y -= sourceRect.getHeight() / 2;\r
298 \r
299                 if ( Pressed )\r
300                 {\r
301                         // Create a pressed-down effect by moving the image when it looks identical to the unpressed state image\r
302                         EGUI_BUTTON_IMAGE_STATE unpressedState = getImageState(false);\r
303                         if ( unpressedState == imageState || ButtonImages[(u32)imageState] == ButtonImages[(u32)unpressedState] )\r
304                         {\r
305                                 pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);\r
306                                 pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);\r
307                         }\r
308                 }\r
309 \r
310                 // PATCH\r
311                 video::ITexture* texture = ButtonImages[(u32)imageState].Texture;\r
312                 if (BgMiddle.getArea() == 0) {\r
313                         driver->draw2DImage(texture,\r
314                                         ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
315                                         sourceRect, &AbsoluteClippingRect,\r
316                                         0, UseAlphaChannel);\r
317                 } else {\r
318                         core::rect<s32> middle = BgMiddle;\r
319                         // `-x` is interpreted as `w - x`\r
320                         if (middle.LowerRightCorner.X < 0)\r
321                                 middle.LowerRightCorner.X += texture->getOriginalSize().Width;\r
322                         if (middle.LowerRightCorner.Y < 0)\r
323                                 middle.LowerRightCorner.Y += texture->getOriginalSize().Height;\r
324                         draw2DImage9Slice(driver, texture,\r
325                                         ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
326                                         middle, &AbsoluteClippingRect);\r
327                 }\r
328                 // END PATCH\r
329         }\r
330 \r
331         if (SpriteBank)\r
332         {\r
333                 core::position2di pos(buttonCenter);\r
334 \r
335                 if (isEnabled())\r
336                 {\r
337                         // pressed / unpressed animation\r
338                         EGUI_BUTTON_STATE state = Pressed ? EGBS_BUTTON_DOWN : EGBS_BUTTON_UP;\r
339                         drawSprite(state, ClickTime, pos);\r
340 \r
341                         // focused / unfocused animation\r
342                         state = Environment->hasFocus(this) ? EGBS_BUTTON_FOCUSED : EGBS_BUTTON_NOT_FOCUSED;\r
343                         drawSprite(state, FocusTime, pos);\r
344 \r
345                         // mouse over / off animation\r
346                         state = isHovered() ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;\r
347                         drawSprite(state, HoverTime, pos);\r
348                 }\r
349                 else\r
350                 {\r
351                         // draw disabled\r
352 //                      drawSprite(EGBS_BUTTON_DISABLED, 0, pos);\r
353                 }\r
354         }\r
355 \r
356         IGUIElement::draw();\r
357 }\r
358 \r
359 void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)\r
360 {\r
361         u32 stateIdx = (u32)state;\r
362 \r
363         if (ButtonSprites[stateIdx].Index != -1)\r
364         {\r
365                 if ( ButtonSprites[stateIdx].Scale )\r
366                 {\r
367                         const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color};\r
368                         SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect.UpperLeftCorner,\r
369                                         &AbsoluteClippingRect, colors[0], // FIXME: remove [0]\r
370                                         porting::getTimeMs()-startTime, ButtonSprites[stateIdx].Loop);\r
371                 }\r
372                 else\r
373                 {\r
374                         SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,\r
375                                 &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, porting::getTimeMs(),\r
376                                 ButtonSprites[stateIdx].Loop, true);\r
377                 }\r
378         }\r
379 }\r
380 \r
381 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const\r
382 {\r
383         // PATCH\r
384         return getImageState(pressed, ButtonImages);\r
385         // END PATCH\r
386 }\r
387 \r
388 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed, const ButtonImage* images) const\r
389 {\r
390         // figure state we should have\r
391         EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED;\r
392         bool focused = Environment->hasFocus((IGUIElement*)this);\r
393         bool mouseOver = isHovered();\r
394         if (isEnabled())\r
395         {\r
396                 if ( pressed )\r
397                 {\r
398                         if ( focused && mouseOver )\r
399                                 state = EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER;\r
400                         else if ( focused )\r
401                                 state = EGBIS_IMAGE_DOWN_FOCUSED;\r
402                         else if ( mouseOver )\r
403                                 state = EGBIS_IMAGE_DOWN_MOUSEOVER;\r
404                         else\r
405                                 state = EGBIS_IMAGE_DOWN;\r
406                 }\r
407                 else // !pressed\r
408                 {\r
409                         if ( focused && mouseOver )\r
410                                 state = EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER;\r
411                         else if ( focused )\r
412                                 state = EGBIS_IMAGE_UP_FOCUSED;\r
413                         else if ( mouseOver )\r
414                                 state = EGBIS_IMAGE_UP_MOUSEOVER;\r
415                         else\r
416                                 state = EGBIS_IMAGE_UP;\r
417                 }\r
418         }\r
419 \r
420         // find a compatible state that has images\r
421         while ( state != EGBIS_IMAGE_UP && !images[(u32)state].Texture )\r
422         {\r
423                 // PATCH\r
424                 switch ( state )\r
425                 {\r
426                         case EGBIS_IMAGE_UP_FOCUSED:\r
427                                 state = EGBIS_IMAGE_UP;\r
428                                 break;\r
429                         case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:\r
430                                 state = EGBIS_IMAGE_UP_FOCUSED;\r
431                                 break;\r
432                         case EGBIS_IMAGE_DOWN_MOUSEOVER:\r
433                                 state = EGBIS_IMAGE_DOWN;\r
434                                 break;\r
435                         case EGBIS_IMAGE_DOWN_FOCUSED:\r
436                                 state = EGBIS_IMAGE_DOWN;\r
437                                 break;\r
438                         case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:\r
439                                 state = EGBIS_IMAGE_DOWN_FOCUSED;\r
440                                 break;\r
441                         case EGBIS_IMAGE_DISABLED:\r
442                                 if ( pressed )\r
443                                         state = EGBIS_IMAGE_DOWN;\r
444                                 else\r
445                                         state = EGBIS_IMAGE_UP;\r
446                                 break;\r
447                         default:\r
448                                 state = EGBIS_IMAGE_UP;\r
449                 }\r
450                 // END PATCH\r
451         }\r
452 \r
453         return state;\r
454 }\r
455 \r
456 //! sets another skin independent font. if this is set to zero, the button uses the font of the skin.\r
457 void GUIButton::setOverrideFont(IGUIFont* font)\r
458 {\r
459         if (OverrideFont == font)\r
460                 return;\r
461 \r
462         if (OverrideFont)\r
463                 OverrideFont->drop();\r
464 \r
465         OverrideFont = font;\r
466 \r
467         if (OverrideFont)\r
468                 OverrideFont->grab();\r
469 \r
470         StaticText->setOverrideFont(font);\r
471 }\r
472 \r
473 //! Gets the override font (if any)\r
474 IGUIFont * GUIButton::getOverrideFont() const\r
475 {\r
476         return OverrideFont;\r
477 }\r
478 \r
479 //! Get the font which is used right now for drawing\r
480 IGUIFont* GUIButton::getActiveFont() const\r
481 {\r
482         if ( OverrideFont )\r
483                 return OverrideFont;\r
484         IGUISkin* skin = Environment->getSkin();\r
485         if (skin)\r
486                 return skin->getFont(EGDF_BUTTON);\r
487         return 0;\r
488 }\r
489 \r
490 //! Sets another color for the text.\r
491 void GUIButton::setOverrideColor(video::SColor color)\r
492 {\r
493         OverrideColor = color;\r
494         OverrideColorEnabled = true;\r
495 \r
496         StaticText->setOverrideColor(color);\r
497 }\r
498 \r
499 video::SColor GUIButton::getOverrideColor() const\r
500 {\r
501         return OverrideColor;\r
502 }\r
503 \r
504 void GUIButton::enableOverrideColor(bool enable)\r
505 {\r
506         OverrideColorEnabled = enable;\r
507 }\r
508 \r
509 bool GUIButton::isOverrideColorEnabled() const\r
510 {\r
511         return OverrideColorEnabled;\r
512 }\r
513 \r
514 void GUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect<s32>& sourceRect)\r
515 {\r
516         if ( state >= EGBIS_COUNT )\r
517                 return;\r
518 \r
519         if ( image )\r
520                 image->grab();\r
521 \r
522         u32 stateIdx = (u32)state;\r
523         if ( ButtonImages[stateIdx].Texture )\r
524                 ButtonImages[stateIdx].Texture->drop();\r
525 \r
526         ButtonImages[stateIdx].Texture = image;\r
527         ButtonImages[stateIdx].SourceRect = sourceRect;\r
528 }\r
529 \r
530 // PATCH\r
531 void GUIButton::setImage(video::ITexture* image)\r
532 {\r
533         setImage(gui::EGBIS_IMAGE_UP, image);\r
534 }\r
535 \r
536 void GUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos)\r
537 {\r
538         setImage(gui::EGBIS_IMAGE_UP, image, pos);\r
539 }\r
540 \r
541 void GUIButton::setPressedImage(video::ITexture* image)\r
542 {\r
543         setImage(gui::EGBIS_IMAGE_DOWN, image);\r
544 }\r
545 \r
546 void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos)\r
547 {\r
548         setImage(gui::EGBIS_IMAGE_DOWN, image, pos);\r
549 }\r
550 \r
551 void GUIButton::setHoveredImage(video::ITexture* image)\r
552 {\r
553         setImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image);\r
554         setImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image);\r
555 }\r
556 \r
557 void GUIButton::setHoveredImage(video::ITexture* image, const core::rect<s32>& pos)\r
558 {\r
559         setImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image, pos);\r
560         setImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image, pos);\r
561 }\r
562 \r
563 //! Sets the text displayed by the button\r
564 void GUIButton::setText(const wchar_t* text)\r
565 {\r
566         StaticText->setText(text);\r
567 \r
568         IGUIButton::setText(text);\r
569 }\r
570 // END PATCH\r
571 \r
572 //! Sets if the button should behave like a push button. Which means it\r
573 //! can be in two states: Normal or Pressed. With a click on the button,\r
574 //! the user can change the state of the button.\r
575 void GUIButton::setIsPushButton(bool isPushButton)\r
576 {\r
577         IsPushButton = isPushButton;\r
578 }\r
579 \r
580 \r
581 //! Returns if the button is currently pressed\r
582 bool GUIButton::isPressed() const\r
583 {\r
584         return Pressed;\r
585 }\r
586 \r
587 // PATCH\r
588 //! Returns if this element (or one of its direct children) is hovered\r
589 bool GUIButton::isHovered() const\r
590 {\r
591         IGUIElement *hovered = Environment->getHovered();\r
592         return  hovered == this || (hovered != nullptr && hovered->getParent() == this);\r
593 }\r
594 // END PATCH\r
595 \r
596 //! Sets the pressed state of the button if this is a pushbutton\r
597 void GUIButton::setPressed(bool pressed)\r
598 {\r
599         if (Pressed != pressed)\r
600         {\r
601                 ClickTime = porting::getTimeMs();\r
602                 Pressed = pressed;\r
603 \r
604                 GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
605 \r
606                 for(IGUIElement *child : getChildren())\r
607                 {\r
608                         core::rect<s32> originalRect = child->getRelativePosition();\r
609                         if (Pressed) {\r
610                                 child->setRelativePosition(originalRect +\r
611                                                 core::dimension2d<s32>(\r
612                                                         skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),\r
613                                                         skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));\r
614                         } else {\r
615                                 child->setRelativePosition(originalRect -\r
616                                                 core::dimension2d<s32>(\r
617                                                         skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),\r
618                                                         skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));\r
619                         }\r
620                 }\r
621         }\r
622 }\r
623 \r
624 \r
625 //! Returns whether the button is a push button\r
626 bool GUIButton::isPushButton() const\r
627 {\r
628         return IsPushButton;\r
629 }\r
630 \r
631 \r
632 //! Sets if the alpha channel should be used for drawing images on the button (default is false)\r
633 void GUIButton::setUseAlphaChannel(bool useAlphaChannel)\r
634 {\r
635         UseAlphaChannel = useAlphaChannel;\r
636 }\r
637 \r
638 \r
639 //! Returns if the alpha channel should be used for drawing images on the button\r
640 bool GUIButton::isAlphaChannelUsed() const\r
641 {\r
642         return UseAlphaChannel;\r
643 }\r
644 \r
645 \r
646 bool GUIButton::isDrawingBorder() const\r
647 {\r
648         return DrawBorder;\r
649 }\r
650 \r
651 \r
652 //! Writes attributes of the element.\r
653 void GUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const\r
654 {\r
655         IGUIButton::serializeAttributes(out,options);\r
656 \r
657         out->addBool    ("PushButton",          IsPushButton );\r
658         if (IsPushButton)\r
659                 out->addBool("Pressed",             Pressed);\r
660 \r
661         for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i )\r
662         {\r
663                 if ( ButtonImages[i].Texture )\r
664                 {\r
665                         core::stringc name( GUIButtonImageStateNames[i] );\r
666                         out->addTexture(name.c_str(), ButtonImages[i].Texture);\r
667                         name += "Rect";\r
668                         out->addRect(name.c_str(), ButtonImages[i].SourceRect);\r
669                 }\r
670         }\r
671 \r
672         out->addBool    ("UseAlphaChannel",     UseAlphaChannel);\r
673         out->addBool    ("Border",                  DrawBorder);\r
674         out->addBool    ("ScaleImage",          ScaleImage);\r
675 \r
676         for ( u32 i=0; i<(u32)EGBS_COUNT; ++i )\r
677         {\r
678                 if ( ButtonSprites[i].Index >= 0 )\r
679                 {\r
680                         core::stringc nameIndex( GUIButtonStateNames[i] );\r
681                         nameIndex += "Index";\r
682                         out->addInt(nameIndex.c_str(), ButtonSprites[i].Index );\r
683 \r
684                         core::stringc nameColor( GUIButtonStateNames[i] );\r
685                         nameColor += "Color";\r
686                         out->addColor(nameColor.c_str(), ButtonSprites[i].Color );\r
687 \r
688                         core::stringc nameLoop( GUIButtonStateNames[i] );\r
689                         nameLoop += "Loop";\r
690                         out->addBool(nameLoop.c_str(), ButtonSprites[i].Loop );\r
691 \r
692                         core::stringc nameScale( GUIButtonStateNames[i] );\r
693                         nameScale += "Scale";\r
694                         out->addBool(nameScale.c_str(), ButtonSprites[i].Scale );\r
695                 }\r
696         }\r
697 \r
698         //   out->addString  ("OverrideFont",   OverrideFont);\r
699 }\r
700 \r
701 \r
702 //! Reads attributes of the element\r
703 void GUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)\r
704 {\r
705         IGUIButton::deserializeAttributes(in,options);\r
706 \r
707         IsPushButton    = in->getAttributeAsBool("PushButton");\r
708         Pressed         = IsPushButton ? in->getAttributeAsBool("Pressed") : false;\r
709 \r
710         core::rect<s32> rec = in->getAttributeAsRect("ImageRect");\r
711         if (rec.isValid())\r
712                 setImage( in->getAttributeAsTexture("Image"), rec);\r
713         else\r
714                 setImage( in->getAttributeAsTexture("Image") );\r
715 \r
716         rec = in->getAttributeAsRect("PressedImageRect");\r
717         if (rec.isValid())\r
718                 setPressedImage( in->getAttributeAsTexture("PressedImage"), rec);\r
719         else\r
720                 setPressedImage( in->getAttributeAsTexture("PressedImage") );\r
721 \r
722         setDrawBorder(in->getAttributeAsBool("Border"));\r
723         setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel"));\r
724         setScaleImage(in->getAttributeAsBool("ScaleImage"));\r
725 \r
726         //   setOverrideFont(in->getAttributeAsString("OverrideFont"));\r
727 \r
728         updateAbsolutePosition();\r
729 }\r
730 \r
731 // PATCH\r
732 GUIButton* GUIButton::addButton(IGUIEnvironment *environment, const core::rect<s32>& rectangle,\r
733                                                                 IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext)\r
734 {\r
735         GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle);\r
736         if (text)\r
737                 button->setText(text);\r
738 \r
739         if ( tooltiptext )\r
740                 button->setToolTipText ( tooltiptext );\r
741 \r
742         button->drop();\r
743         return button;\r
744 }\r
745 \r
746 void GUIButton::setColor(video::SColor color)\r
747 {\r
748         float d = 0.65f;\r
749         for (size_t i = 0; i < 4; i++) {\r
750                 video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
751                 Colors[i] = base.getInterpolated(color, d);\r
752                 HoveredColors[i] = irr::video::SColor(Colors[i].getAlpha(),\r
753                         core::clamp<u32>(Colors[i].getRed() * COLOR_HOVERED_MOD, 0, 255),\r
754                         core::clamp<u32>(Colors[i].getGreen() * COLOR_HOVERED_MOD, 0, 255),\r
755                         core::clamp<u32>(Colors[i].getBlue() * COLOR_HOVERED_MOD, 0, 255));\r
756                 PressedColors[i] = irr::video::SColor(Colors[i].getAlpha(),\r
757                         core::clamp<u32>(Colors[i].getRed() * COLOR_PRESSED_MOD, 0, 255),\r
758                         core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),\r
759                         core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));\r
760         }\r
761 }\r
762 void GUIButton::setHoveredColor(video::SColor color)\r
763 {\r
764         float d = 0.65f;\r
765         for (size_t i = 0; i < 4; i++) {\r
766                 video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
767                 HoveredColors[i] = base.getInterpolated(color, d);\r
768         }\r
769 }\r
770 void GUIButton::setPressedColor(video::SColor color)\r
771 {\r
772         float d = 0.65f;\r
773         for (size_t i = 0; i < 4; i++) {\r
774                 video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
775                 PressedColors[i] = base.getInterpolated(color, d);\r
776         }\r
777 }\r
778 \r
779 //! Set element properties from a StyleSpec\r
780 void GUIButton::setFromStyle(const StyleSpec& style, ISimpleTextureSource *tsrc)\r
781 {\r
782         if (style.isNotDefault(StyleSpec::BGCOLOR)) {\r
783                 setColor(style.getColor(StyleSpec::BGCOLOR));\r
784         }\r
785         if (style.isNotDefault(StyleSpec::BGCOLOR_HOVERED)) {\r
786                 setHoveredColor(style.getColor(StyleSpec::BGCOLOR_HOVERED));\r
787         }\r
788         if (style.isNotDefault(StyleSpec::BGCOLOR_PRESSED)) {\r
789                 setPressedColor(style.getColor(StyleSpec::BGCOLOR_PRESSED));\r
790         }\r
791 \r
792         if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {\r
793                 setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));\r
794         }\r
795         setNotClipped(style.getBool(StyleSpec::NOCLIP, isNotClipped()));\r
796         setDrawBorder(style.getBool(StyleSpec::BORDER, DrawBorder));\r
797         setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));\r
798 \r
799         const core::position2di buttonCenter(AbsoluteRect.getCenter());\r
800         core::position2d<s32> geom(buttonCenter);\r
801         if (style.isNotDefault(StyleSpec::BGIMG)) {\r
802                 video::ITexture *texture = style.getTexture(StyleSpec::BGIMG, tsrc);\r
803 \r
804                 setImage(guiScalingImageButton(\r
805                                         Environment->getVideoDriver(), texture, geom.X, geom.Y));\r
806                 setScaleImage(true);\r
807         }\r
808         if (style.isNotDefault(StyleSpec::BGIMG_HOVERED)) {\r
809                 video::ITexture *hovered_texture = style.getTexture(StyleSpec::BGIMG_HOVERED, tsrc);\r
810 \r
811                 setHoveredImage(guiScalingImageButton(\r
812                                         Environment->getVideoDriver(), hovered_texture, geom.X, geom.Y));\r
813                 setScaleImage(true);\r
814         }\r
815         if (style.isNotDefault(StyleSpec::BGIMG_PRESSED)) {\r
816                 video::ITexture *pressed_texture = style.getTexture(StyleSpec::BGIMG_PRESSED, tsrc);\r
817 \r
818                 setPressedImage(guiScalingImageButton(\r
819                                         Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y));\r
820                 setScaleImage(true);\r
821         }\r
822         BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);\r
823 }\r
824 // END PATCH\r