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