]> git.lizzy.rs Git - dragonfireclient.git/blob - src/gui/guiButton.cpp
Use "Aux1" key name consistently everywhere
[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 #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                         core::rect<s32> middle = BgMiddle;\r
324                         // `-x` is interpreted as `w - x`\r
325                         if (middle.LowerRightCorner.X < 0)\r
326                                 middle.LowerRightCorner.X += texture->getOriginalSize().Width;\r
327                         if (middle.LowerRightCorner.Y < 0)\r
328                                 middle.LowerRightCorner.Y += texture->getOriginalSize().Height;\r
329                         draw2DImage9Slice(driver, texture,\r
330                                         ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
331                                         middle, &AbsoluteClippingRect, image_colors);\r
332                 }\r
333                 // END PATCH\r
334         }\r
335 \r
336         if (SpriteBank)\r
337         {\r
338                 core::position2di pos(buttonCenter);\r
339 \r
340                 if (isEnabled())\r
341                 {\r
342                         // pressed / unpressed animation\r
343                         EGUI_BUTTON_STATE state = Pressed ? EGBS_BUTTON_DOWN : EGBS_BUTTON_UP;\r
344                         drawSprite(state, ClickTime, pos);\r
345 \r
346                         // focused / unfocused animation\r
347                         state = Environment->hasFocus(this) ? EGBS_BUTTON_FOCUSED : EGBS_BUTTON_NOT_FOCUSED;\r
348                         drawSprite(state, FocusTime, pos);\r
349 \r
350                         // mouse over / off animation\r
351                         state = isHovered() ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;\r
352                         drawSprite(state, HoverTime, pos);\r
353                 }\r
354                 else\r
355                 {\r
356                         // draw disabled\r
357 //                      drawSprite(EGBS_BUTTON_DISABLED, 0, pos);\r
358                 }\r
359         }\r
360 \r
361         IGUIElement::draw();\r
362 }\r
363 \r
364 void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)\r
365 {\r
366         u32 stateIdx = (u32)state;\r
367 \r
368         if (ButtonSprites[stateIdx].Index != -1)\r
369         {\r
370                 if ( ButtonSprites[stateIdx].Scale )\r
371                 {\r
372                         const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color};\r
373                         SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect.UpperLeftCorner,\r
374                                         &AbsoluteClippingRect, colors[0], // FIXME: remove [0]\r
375                                         porting::getTimeMs()-startTime, ButtonSprites[stateIdx].Loop);\r
376                 }\r
377                 else\r
378                 {\r
379                         SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,\r
380                                 &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, porting::getTimeMs(),\r
381                                 ButtonSprites[stateIdx].Loop, true);\r
382                 }\r
383         }\r
384 }\r
385 \r
386 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const\r
387 {\r
388         // PATCH\r
389         return getImageState(pressed, ButtonImages);\r
390         // END PATCH\r
391 }\r
392 \r
393 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed, const ButtonImage* images) const\r
394 {\r
395         // figure state we should have\r
396         EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED;\r
397         bool focused = Environment->hasFocus((IGUIElement*)this);\r
398         bool mouseOver = isHovered();\r
399         if (isEnabled())\r
400         {\r
401                 if ( pressed )\r
402                 {\r
403                         if ( focused && mouseOver )\r
404                                 state = EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER;\r
405                         else if ( focused )\r
406                                 state = EGBIS_IMAGE_DOWN_FOCUSED;\r
407                         else if ( mouseOver )\r
408                                 state = EGBIS_IMAGE_DOWN_MOUSEOVER;\r
409                         else\r
410                                 state = EGBIS_IMAGE_DOWN;\r
411                 }\r
412                 else // !pressed\r
413                 {\r
414                         if ( focused && mouseOver )\r
415                                 state = EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER;\r
416                         else if ( focused )\r
417                                 state = EGBIS_IMAGE_UP_FOCUSED;\r
418                         else if ( mouseOver )\r
419                                 state = EGBIS_IMAGE_UP_MOUSEOVER;\r
420                         else\r
421                                 state = EGBIS_IMAGE_UP;\r
422                 }\r
423         }\r
424 \r
425         // find a compatible state that has images\r
426         while ( state != EGBIS_IMAGE_UP && !images[(u32)state].Texture )\r
427         {\r
428                 // PATCH\r
429                 switch ( state )\r
430                 {\r
431                         case EGBIS_IMAGE_UP_FOCUSED:\r
432                                 state = EGBIS_IMAGE_UP;\r
433                                 break;\r
434                         case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:\r
435                                 state = EGBIS_IMAGE_UP_FOCUSED;\r
436                                 break;\r
437                         case EGBIS_IMAGE_DOWN_MOUSEOVER:\r
438                                 state = EGBIS_IMAGE_DOWN;\r
439                                 break;\r
440                         case EGBIS_IMAGE_DOWN_FOCUSED:\r
441                                 state = EGBIS_IMAGE_DOWN;\r
442                                 break;\r
443                         case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:\r
444                                 state = EGBIS_IMAGE_DOWN_FOCUSED;\r
445                                 break;\r
446                         case EGBIS_IMAGE_DISABLED:\r
447                                 if ( pressed )\r
448                                         state = EGBIS_IMAGE_DOWN;\r
449                                 else\r
450                                         state = EGBIS_IMAGE_UP;\r
451                                 break;\r
452                         default:\r
453                                 state = EGBIS_IMAGE_UP;\r
454                 }\r
455                 // END PATCH\r
456         }\r
457 \r
458         return state;\r
459 }\r
460 \r
461 //! sets another skin independent font. if this is set to zero, the button uses the font of the skin.\r
462 void GUIButton::setOverrideFont(IGUIFont* font)\r
463 {\r
464         if (OverrideFont == font)\r
465                 return;\r
466 \r
467         if (OverrideFont)\r
468                 OverrideFont->drop();\r
469 \r
470         OverrideFont = font;\r
471 \r
472         if (OverrideFont)\r
473                 OverrideFont->grab();\r
474 \r
475         StaticText->setOverrideFont(font);\r
476 }\r
477 \r
478 //! Gets the override font (if any)\r
479 IGUIFont * GUIButton::getOverrideFont() const\r
480 {\r
481         return OverrideFont;\r
482 }\r
483 \r
484 //! Get the font which is used right now for drawing\r
485 IGUIFont* GUIButton::getActiveFont() const\r
486 {\r
487         if ( OverrideFont )\r
488                 return OverrideFont;\r
489         IGUISkin* skin = Environment->getSkin();\r
490         if (skin)\r
491                 return skin->getFont(EGDF_BUTTON);\r
492         return 0;\r
493 }\r
494 \r
495 //! Sets another color for the text.\r
496 void GUIButton::setOverrideColor(video::SColor color)\r
497 {\r
498         OverrideColor = color;\r
499         OverrideColorEnabled = true;\r
500 \r
501         StaticText->setOverrideColor(color);\r
502 }\r
503 \r
504 video::SColor GUIButton::getOverrideColor() const\r
505 {\r
506         return OverrideColor;\r
507 }\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 //! Writes attributes of the element.\r
629 void GUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const\r
630 {\r
631         IGUIButton::serializeAttributes(out,options);\r
632 \r
633         out->addBool    ("PushButton",          IsPushButton );\r
634         if (IsPushButton)\r
635                 out->addBool("Pressed",             Pressed);\r
636 \r
637         for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i )\r
638         {\r
639                 if ( ButtonImages[i].Texture )\r
640                 {\r
641                         core::stringc name( GUIButtonImageStateNames[i] );\r
642                         out->addTexture(name.c_str(), ButtonImages[i].Texture);\r
643                         name += "Rect";\r
644                         out->addRect(name.c_str(), ButtonImages[i].SourceRect);\r
645                 }\r
646         }\r
647 \r
648         out->addBool    ("UseAlphaChannel",     UseAlphaChannel);\r
649         out->addBool    ("Border",                  DrawBorder);\r
650         out->addBool    ("ScaleImage",          ScaleImage);\r
651 \r
652         for ( u32 i=0; i<(u32)EGBS_COUNT; ++i )\r
653         {\r
654                 if ( ButtonSprites[i].Index >= 0 )\r
655                 {\r
656                         core::stringc nameIndex( GUIButtonStateNames[i] );\r
657                         nameIndex += "Index";\r
658                         out->addInt(nameIndex.c_str(), ButtonSprites[i].Index );\r
659 \r
660                         core::stringc nameColor( GUIButtonStateNames[i] );\r
661                         nameColor += "Color";\r
662                         out->addColor(nameColor.c_str(), ButtonSprites[i].Color );\r
663 \r
664                         core::stringc nameLoop( GUIButtonStateNames[i] );\r
665                         nameLoop += "Loop";\r
666                         out->addBool(nameLoop.c_str(), ButtonSprites[i].Loop );\r
667 \r
668                         core::stringc nameScale( GUIButtonStateNames[i] );\r
669                         nameScale += "Scale";\r
670                         out->addBool(nameScale.c_str(), ButtonSprites[i].Scale );\r
671                 }\r
672         }\r
673 \r
674         //   out->addString  ("OverrideFont",   OverrideFont);\r
675 }\r
676 \r
677 \r
678 //! Reads attributes of the element\r
679 void GUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)\r
680 {\r
681         IGUIButton::deserializeAttributes(in,options);\r
682 \r
683         IsPushButton    = in->getAttributeAsBool("PushButton");\r
684         Pressed         = IsPushButton ? in->getAttributeAsBool("Pressed") : false;\r
685 \r
686         core::rect<s32> rec = in->getAttributeAsRect("ImageRect");\r
687         if (rec.isValid())\r
688                 setImage( in->getAttributeAsTexture("Image"), rec);\r
689         else\r
690                 setImage( in->getAttributeAsTexture("Image") );\r
691 \r
692         rec = in->getAttributeAsRect("PressedImageRect");\r
693         if (rec.isValid())\r
694                 setPressedImage( in->getAttributeAsTexture("PressedImage"), rec);\r
695         else\r
696                 setPressedImage( in->getAttributeAsTexture("PressedImage") );\r
697 \r
698         setDrawBorder(in->getAttributeAsBool("Border"));\r
699         setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel"));\r
700         setScaleImage(in->getAttributeAsBool("ScaleImage"));\r
701 \r
702         //   setOverrideFont(in->getAttributeAsString("OverrideFont"));\r
703 \r
704         updateAbsolutePosition();\r
705 }\r
706 \r
707 // PATCH\r
708 GUIButton* GUIButton::addButton(IGUIEnvironment *environment,\r
709                 const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,\r
710                 IGUIElement* parent, s32 id, const wchar_t* text,\r
711                 const wchar_t *tooltiptext)\r
712 {\r
713         GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);\r
714         if (text)\r
715                 button->setText(text);\r
716 \r
717         if ( tooltiptext )\r
718                 button->setToolTipText ( tooltiptext );\r
719 \r
720         button->drop();\r
721         return button;\r
722 }\r
723 \r
724 void GUIButton::setColor(video::SColor color)\r
725 {\r
726         BgColor = color;\r
727 \r
728         float d = 0.65f;\r
729         for (size_t i = 0; i < 4; i++) {\r
730                 video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
731                 Colors[i] = base.getInterpolated(color, d);\r
732         }\r
733 }\r
734 \r
735 //! Set element properties from a StyleSpec corresponding to the button state\r
736 void GUIButton::setFromState()\r
737 {\r
738         StyleSpec::State state = StyleSpec::STATE_DEFAULT;\r
739 \r
740         if (isPressed())\r
741                 state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_PRESSED);\r
742 \r
743         if (isHovered())\r
744                 state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_HOVERED);\r
745 \r
746         setFromStyle(StyleSpec::getStyleFromStatePropagation(Styles, state));\r
747 }\r
748 \r
749 //! Set element properties from a StyleSpec\r
750 void GUIButton::setFromStyle(const StyleSpec& style)\r
751 {\r
752         bool hovered = (style.getState() & StyleSpec::STATE_HOVERED) != 0;\r
753         bool pressed = (style.getState() & StyleSpec::STATE_PRESSED) != 0;\r
754 \r
755         if (style.isNotDefault(StyleSpec::BGCOLOR)) {\r
756                 setColor(style.getColor(StyleSpec::BGCOLOR));\r
757 \r
758                 // If we have a propagated hover/press color, we need to automatically\r
759                 // lighten/darken it\r
760                 if (!Styles[style.getState()].isNotDefault(StyleSpec::BGCOLOR)) {\r
761                                 if (pressed) {\r
762                                         BgColor = multiplyColorValue(BgColor, COLOR_PRESSED_MOD);\r
763 \r
764                                         for (size_t i = 0; i < 4; i++)\r
765                                                 Colors[i] = multiplyColorValue(Colors[i], COLOR_PRESSED_MOD);\r
766                                 } else if (hovered) {\r
767                                         BgColor = multiplyColorValue(BgColor, COLOR_HOVERED_MOD);\r
768 \r
769                                         for (size_t i = 0; i < 4; i++)\r
770                                                 Colors[i] = multiplyColorValue(Colors[i], COLOR_HOVERED_MOD);\r
771                                 }\r
772                 }\r
773 \r
774         } else {\r
775                 BgColor = video::SColor(255, 255, 255, 255);\r
776                 for (size_t i = 0; i < 4; i++) {\r
777                         video::SColor base =\r
778                                         Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
779                         if (pressed) {\r
780                                 Colors[i] = multiplyColorValue(base, COLOR_PRESSED_MOD);\r
781                         } else if (hovered) {\r
782                                 Colors[i] = multiplyColorValue(base, COLOR_HOVERED_MOD);\r
783                         } else {\r
784                                 Colors[i] = base;\r
785                         }\r
786                 }\r
787         }\r
788 \r
789         if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {\r
790                 setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));\r
791         } else {\r
792                 setOverrideColor(video::SColor(255,255,255,255));\r
793                 OverrideColorEnabled = false;\r
794         }\r
795         setNotClipped(style.getBool(StyleSpec::NOCLIP, false));\r
796         setDrawBorder(style.getBool(StyleSpec::BORDER, true));\r
797         setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));\r
798         setOverrideFont(style.getFont());\r
799 \r
800         if (style.isNotDefault(StyleSpec::BGIMG)) {\r
801                 video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,\r
802                                 getTextureSource());\r
803                 setImage(guiScalingImageButton(\r
804                                 Environment->getVideoDriver(), texture,\r
805                                                 AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));\r
806                 setScaleImage(true);\r
807         } else {\r
808                 setImage(nullptr);\r
809         }\r
810 \r
811         BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);\r
812 \r
813         // Child padding and offset\r
814         Padding = style.getRect(StyleSpec::PADDING, core::rect<s32>());\r
815         Padding = core::rect<s32>(\r
816                         Padding.UpperLeftCorner + BgMiddle.UpperLeftCorner,\r
817                         Padding.LowerRightCorner + BgMiddle.LowerRightCorner);\r
818 \r
819         GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
820         core::vector2d<s32> defaultPressOffset(\r
821                         skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),\r
822                         skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y));\r
823         ContentOffset = style.getVector2i(StyleSpec::CONTENT_OFFSET, isPressed()\r
824                         ? defaultPressOffset\r
825                         : core::vector2d<s32>(0));\r
826 \r
827         core::rect<s32> childBounds(\r
828                                 Padding.UpperLeftCorner.X + ContentOffset.X,\r
829                                 Padding.UpperLeftCorner.Y + ContentOffset.Y,\r
830                                 AbsoluteRect.getWidth() + Padding.LowerRightCorner.X + ContentOffset.X,\r
831                                 AbsoluteRect.getHeight() + Padding.LowerRightCorner.Y + ContentOffset.Y);\r
832 \r
833         for (IGUIElement *child : getChildren()) {\r
834                 child->setRelativePosition(childBounds);\r
835         }\r
836 }\r
837 \r
838 //! Set the styles used for each state\r
839 void GUIButton::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles)\r
840 {\r
841         Styles = styles;\r
842         setFromState();\r
843 }\r
844 // END PATCH\r