]> git.lizzy.rs Git - minetest.git/blob - src/gui/guiButton.cpp
Improve a translation string
[minetest.git] / src / gui / guiButton.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "guiButton.h"\r
6 \r
7 \r
8 #include "client/guiscalingfilter.h"\r
9 #include "client/tile.h"\r
10 #include "IGUISkin.h"\r
11 #include "IGUIEnvironment.h"\r
12 #include "IVideoDriver.h"\r
13 #include "IGUIFont.h"\r
14 #include "irrlicht_changes/static_text.h"\r
15 #include "porting.h"\r
16 #include "StyleSpec.h"\r
17 #include "util/numeric.h"\r
18 \r
19 using namespace irr;\r
20 using namespace gui;\r
21 \r
22 // Multiply with a color to get the default corresponding hovered color\r
23 #define COLOR_HOVERED_MOD 1.25f\r
24 \r
25 // Multiply with a color to get the default corresponding pressed color\r
26 #define COLOR_PRESSED_MOD 0.85f\r
27 \r
28 //! constructor\r
29 GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,\r
30                         s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,\r
31                         bool noclip)\r
32 : IGUIButton(environment, parent, id, rectangle),\r
33         SpriteBank(0), OverrideFont(0),\r
34         OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),\r
35         ClickTime(0), HoverTime(0), FocusTime(0),\r
36         ClickShiftState(false), ClickControlState(false),\r
37         IsPushButton(false), Pressed(false),\r
38         UseAlphaChannel(false), DrawBorder(true), ScaleImage(false), TSrc(tsrc)\r
39 {\r
40         setNotClipped(noclip);\r
41 \r
42         // This element can be tabbed.\r
43         setTabStop(true);\r
44         setTabOrder(-1);\r
45 \r
46         // PATCH\r
47         for (size_t i = 0; i < 4; i++) {\r
48                 Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);\r
49         }\r
50         StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);\r
51         StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);\r
52         // END PATCH\r
53 }\r
54 \r
55 //! destructor\r
56 GUIButton::~GUIButton()\r
57 {\r
58         if (OverrideFont)\r
59                 OverrideFont->drop();\r
60 \r
61         if (SpriteBank)\r
62                 SpriteBank->drop();\r
63 }\r
64 \r
65 \r
66 //! Sets if the images should be scaled to fit the button\r
67 void GUIButton::setScaleImage(bool scaleImage)\r
68 {\r
69         ScaleImage = scaleImage;\r
70 }\r
71 \r
72 \r
73 //! Returns whether the button scale the used images\r
74 bool GUIButton::isScalingImage() const\r
75 {\r
76         return ScaleImage;\r
77 }\r
78 \r
79 \r
80 //! Sets if the button should use the skin to draw its border\r
81 void GUIButton::setDrawBorder(bool border)\r
82 {\r
83         DrawBorder = border;\r
84 }\r
85 \r
86 \r
87 void GUIButton::setSpriteBank(IGUISpriteBank* sprites)\r
88 {\r
89         if (sprites)\r
90                 sprites->grab();\r
91 \r
92         if (SpriteBank)\r
93                 SpriteBank->drop();\r
94 \r
95         SpriteBank = sprites;\r
96 }\r
97 \r
98 void GUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale)\r
99 {\r
100         ButtonSprites[(u32)state].Index = index;\r
101         ButtonSprites[(u32)state].Color = color;\r
102         ButtonSprites[(u32)state].Loop  = loop;\r
103         ButtonSprites[(u32)state].Scale = scale;\r
104 }\r
105 \r
106 //! Get the sprite-index for the given state or -1 when no sprite is set\r
107 s32 GUIButton::getSpriteIndex(EGUI_BUTTON_STATE state) const\r
108 {\r
109         return ButtonSprites[(u32)state].Index;\r
110 }\r
111 \r
112 //! Get the sprite color for the given state. Color is only used when a sprite is set.\r
113 video::SColor GUIButton::getSpriteColor(EGUI_BUTTON_STATE state) const\r
114 {\r
115         return ButtonSprites[(u32)state].Color;\r
116 }\r
117 \r
118 //! Returns if the sprite in the given state does loop\r
119 bool GUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const\r
120 {\r
121         return ButtonSprites[(u32)state].Loop;\r
122 }\r
123 \r
124 //! Returns if the sprite in the given state is scaled\r
125 bool GUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const\r
126 {\r
127         return ButtonSprites[(u32)state].Scale;\r
128 }\r
129 \r
130 //! called if an event happened.\r
131 bool GUIButton::OnEvent(const SEvent& event)\r
132 {\r
133         if (!isEnabled())\r
134                 return IGUIElement::OnEvent(event);\r
135 \r
136         switch(event.EventType)\r
137         {\r
138         case EET_KEY_INPUT_EVENT:\r
139                 if (event.KeyInput.PressedDown &&\r
140                         (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))\r
141                 {\r
142                         if (!IsPushButton)\r
143                                 setPressed(true);\r
144                         else\r
145                                 setPressed(!Pressed);\r
146 \r
147                         return true;\r
148                 }\r
149                 if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)\r
150                 {\r
151                         setPressed(false);\r
152                         return true;\r
153                 }\r
154                 else\r
155                 if (!event.KeyInput.PressedDown && Pressed &&\r
156                         (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))\r
157                 {\r
158 \r
159                         if (!IsPushButton)\r
160                                 setPressed(false);\r
161 \r
162                         if (Parent)\r
163                         {\r
164                                 ClickShiftState = event.KeyInput.Shift;\r
165                                 ClickControlState = event.KeyInput.Control;\r
166 \r
167                                 SEvent newEvent;\r
168                                 newEvent.EventType = EET_GUI_EVENT;\r
169                                 newEvent.GUIEvent.Caller = this;\r
170                                 newEvent.GUIEvent.Element = 0;\r
171                                 newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;\r
172                                 Parent->OnEvent(newEvent);\r
173                         }\r
174                         return true;\r
175                 }\r
176                 break;\r
177         case EET_GUI_EVENT:\r
178                 if (event.GUIEvent.Caller == this)\r
179                 {\r
180                         if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)\r
181                         {\r
182                                 if (!IsPushButton)\r
183                                         setPressed(false);\r
184                                 FocusTime = (u32)porting::getTimeMs();\r
185                         }\r
186                         else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)\r
187                         {\r
188                                 FocusTime = (u32)porting::getTimeMs();\r
189                         }\r
190                         else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)\r
191                         {\r
192                                 HoverTime = (u32)porting::getTimeMs();\r
193                         }\r
194                 }\r
195                 break;\r
196         case EET_MOUSE_INPUT_EVENT:\r
197                 if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
198                 {\r
199                         // Sometimes formspec elements can receive mouse events when the\r
200                         // mouse is outside of the formspec. Thus, we test the position here.\r
201                         if ( !IsPushButton && AbsoluteClippingRect.isPointInside(\r
202                                                 core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ))) {\r
203                                 setPressed(true);\r
204                         }\r
205 \r
206                         return true;\r
207                 }\r
208                 else\r
209                 if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
210                 {\r
211                         bool wasPressed = Pressed;\r
212 \r
213                         if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )\r
214                         {\r
215                                 if (!IsPushButton)\r
216                                         setPressed(false);\r
217                                 return true;\r
218                         }\r
219 \r
220                         if (!IsPushButton)\r
221                                 setPressed(false);\r
222                         else\r
223                         {\r
224                                 setPressed(!Pressed);\r
225                         }\r
226 \r
227                         if ((!IsPushButton && wasPressed && Parent) ||\r
228                                 (IsPushButton && wasPressed != Pressed))\r
229                         {\r
230                                 ClickShiftState = event.MouseInput.Shift;\r
231                                 ClickControlState = event.MouseInput.Control;\r
232 \r
233                                 SEvent newEvent;\r
234                                 newEvent.EventType = EET_GUI_EVENT;\r
235                                 newEvent.GUIEvent.Caller = this;\r
236                                 newEvent.GUIEvent.Element = 0;\r
237                                 newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;\r
238                                 Parent->OnEvent(newEvent);\r
239                         }\r
240 \r
241                         return true;\r
242                 }\r
243                 break;\r
244         default:\r
245                 break;\r
246         }\r
247 \r
248         return Parent ? Parent->OnEvent(event) : false;\r
249 }\r
250 \r
251 \r
252 //! draws the element and its children\r
253 void GUIButton::draw()\r
254 {\r
255         if (!IsVisible)\r
256                 return;\r
257 \r
258         // PATCH\r
259         // Track hovered state, if it has changed then we need to update the style.\r
260         bool hovered = isHovered();\r
261         if (hovered != WasHovered) {\r
262                 WasHovered = hovered;\r
263                 setFromState();\r
264         }\r
265 \r
266         GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
267         video::IVideoDriver* driver = Environment->getVideoDriver();\r
268         // END PATCH\r
269 \r
270         if (DrawBorder)\r
271         {\r
272                 if (!Pressed)\r
273                 {\r
274                         // PATCH\r
275                         skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,\r
276                                         &AbsoluteClippingRect, Colors);\r
277                         // END PATCH\r
278                 }\r
279                 else\r
280                 {\r
281                         // PATCH\r
282                         skin->drawColored3DButtonPanePressed(this, AbsoluteRect,\r
283                                         &AbsoluteClippingRect, Colors);\r
284                         // END PATCH\r
285                 }\r
286         }\r
287 \r
288         const core::position2di buttonCenter(AbsoluteRect.getCenter());\r
289         // PATCH\r
290         // The image changes based on the state, so we use the default every time.\r
291         EGUI_BUTTON_IMAGE_STATE imageState = EGBIS_IMAGE_UP;\r
292         // END PATCH\r
293         if ( ButtonImages[(u32)imageState].Texture )\r
294         {\r
295                 core::position2d<s32> pos(buttonCenter);\r
296                 core::rect<s32> sourceRect(ButtonImages[(u32)imageState].SourceRect);\r
297                 if ( sourceRect.getWidth() == 0 && sourceRect.getHeight() == 0 )\r
298                         sourceRect = core::rect<s32>(core::position2di(0,0), ButtonImages[(u32)imageState].Texture->getOriginalSize());\r
299 \r
300                 pos.X -= sourceRect.getWidth() / 2;\r
301                 pos.Y -= sourceRect.getHeight() / 2;\r
302 \r
303                 if ( Pressed )\r
304                 {\r
305                         // Create a pressed-down effect by moving the image when it looks identical to the unpressed state image\r
306                         EGUI_BUTTON_IMAGE_STATE unpressedState = getImageState(false);\r
307                         if ( unpressedState == imageState || ButtonImages[(u32)imageState] == ButtonImages[(u32)unpressedState] )\r
308                         {\r
309                                 pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);\r
310                                 pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);\r
311                         }\r
312                 }\r
313 \r
314                 // PATCH\r
315                 video::ITexture* texture = ButtonImages[(u32)imageState].Texture;\r
316                 video::SColor image_colors[] = { BgColor, BgColor, BgColor, BgColor };\r
317                 if (BgMiddle.getArea() == 0) {\r
318                         driver->draw2DImage(texture,\r
319                                         ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
320                                         sourceRect, &AbsoluteClippingRect,\r
321                                         image_colors, UseAlphaChannel);\r
322                 } else {\r
323                         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 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8\r
510 video::SColor GUIButton::getActiveColor() const\r
511 {\r
512         return video::SColor(0,0,0,0); // unused?\r
513 }\r
514 #endif\r
515 \r
516 void GUIButton::enableOverrideColor(bool enable)\r
517 {\r
518         OverrideColorEnabled = enable;\r
519 }\r
520 \r
521 bool GUIButton::isOverrideColorEnabled() const\r
522 {\r
523         return OverrideColorEnabled;\r
524 }\r
525 \r
526 void GUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect<s32>& sourceRect)\r
527 {\r
528         if ( state >= EGBIS_COUNT )\r
529                 return;\r
530 \r
531         if ( image )\r
532                 image->grab();\r
533 \r
534         u32 stateIdx = (u32)state;\r
535         if ( ButtonImages[stateIdx].Texture )\r
536                 ButtonImages[stateIdx].Texture->drop();\r
537 \r
538         ButtonImages[stateIdx].Texture = image;\r
539         ButtonImages[stateIdx].SourceRect = sourceRect;\r
540 }\r
541 \r
542 // PATCH\r
543 void GUIButton::setImage(video::ITexture* image)\r
544 {\r
545         setImage(gui::EGBIS_IMAGE_UP, image);\r
546 }\r
547 \r
548 void GUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos)\r
549 {\r
550         setImage(gui::EGBIS_IMAGE_UP, image, pos);\r
551 }\r
552 \r
553 void GUIButton::setPressedImage(video::ITexture* image)\r
554 {\r
555         setImage(gui::EGBIS_IMAGE_DOWN, image);\r
556 }\r
557 \r
558 void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos)\r
559 {\r
560         setImage(gui::EGBIS_IMAGE_DOWN, 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                 setFromState();\r
604         }\r
605 }\r
606 \r
607 \r
608 //! Returns whether the button is a push button\r
609 bool GUIButton::isPushButton() const\r
610 {\r
611         return IsPushButton;\r
612 }\r
613 \r
614 \r
615 //! Sets if the alpha channel should be used for drawing images on the button (default is false)\r
616 void GUIButton::setUseAlphaChannel(bool useAlphaChannel)\r
617 {\r
618         UseAlphaChannel = useAlphaChannel;\r
619 }\r
620 \r
621 \r
622 //! Returns if the alpha channel should be used for drawing images on the button\r
623 bool GUIButton::isAlphaChannelUsed() const\r
624 {\r
625         return UseAlphaChannel;\r
626 }\r
627 \r
628 \r
629 bool GUIButton::isDrawingBorder() const\r
630 {\r
631         return DrawBorder;\r
632 }\r
633 \r
634 \r
635 // PATCH\r
636 GUIButton* GUIButton::addButton(IGUIEnvironment *environment,\r
637                 const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,\r
638                 IGUIElement* parent, s32 id, const wchar_t* text,\r
639                 const wchar_t *tooltiptext)\r
640 {\r
641         GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);\r
642         if (text)\r
643                 button->setText(text);\r
644 \r
645         if ( tooltiptext )\r
646                 button->setToolTipText ( tooltiptext );\r
647 \r
648         button->drop();\r
649         return button;\r
650 }\r
651 \r
652 void GUIButton::setColor(video::SColor color)\r
653 {\r
654         BgColor = color;\r
655 \r
656         float d = 0.65f;\r
657         for (size_t i = 0; i < 4; i++) {\r
658                 video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
659                 Colors[i] = base.getInterpolated(color, d);\r
660         }\r
661 }\r
662 \r
663 //! Set element properties from a StyleSpec corresponding to the button state\r
664 void GUIButton::setFromState()\r
665 {\r
666         StyleSpec::State state = StyleSpec::STATE_DEFAULT;\r
667 \r
668         if (isPressed())\r
669                 state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_PRESSED);\r
670 \r
671         if (isHovered())\r
672                 state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_HOVERED);\r
673 \r
674         setFromStyle(StyleSpec::getStyleFromStatePropagation(Styles, state));\r
675 }\r
676 \r
677 //! Set element properties from a StyleSpec\r
678 void GUIButton::setFromStyle(const StyleSpec& style)\r
679 {\r
680         bool hovered = (style.getState() & StyleSpec::STATE_HOVERED) != 0;\r
681         bool pressed = (style.getState() & StyleSpec::STATE_PRESSED) != 0;\r
682 \r
683         if (style.isNotDefault(StyleSpec::BGCOLOR)) {\r
684                 setColor(style.getColor(StyleSpec::BGCOLOR));\r
685 \r
686                 // If we have a propagated hover/press color, we need to automatically\r
687                 // lighten/darken it\r
688                 if (!Styles[style.getState()].isNotDefault(StyleSpec::BGCOLOR)) {\r
689                                 if (pressed) {\r
690                                         BgColor = multiplyColorValue(BgColor, COLOR_PRESSED_MOD);\r
691 \r
692                                         for (size_t i = 0; i < 4; i++)\r
693                                                 Colors[i] = multiplyColorValue(Colors[i], COLOR_PRESSED_MOD);\r
694                                 } else if (hovered) {\r
695                                         BgColor = multiplyColorValue(BgColor, COLOR_HOVERED_MOD);\r
696 \r
697                                         for (size_t i = 0; i < 4; i++)\r
698                                                 Colors[i] = multiplyColorValue(Colors[i], COLOR_HOVERED_MOD);\r
699                                 }\r
700                 }\r
701 \r
702         } else {\r
703                 BgColor = video::SColor(255, 255, 255, 255);\r
704                 for (size_t i = 0; i < 4; i++) {\r
705                         video::SColor base =\r
706                                         Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
707                         if (pressed) {\r
708                                 Colors[i] = multiplyColorValue(base, COLOR_PRESSED_MOD);\r
709                         } else if (hovered) {\r
710                                 Colors[i] = multiplyColorValue(base, COLOR_HOVERED_MOD);\r
711                         } else {\r
712                                 Colors[i] = base;\r
713                         }\r
714                 }\r
715         }\r
716 \r
717         if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {\r
718                 setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));\r
719         } else {\r
720                 setOverrideColor(video::SColor(255,255,255,255));\r
721                 OverrideColorEnabled = false;\r
722         }\r
723         setNotClipped(style.getBool(StyleSpec::NOCLIP, false));\r
724         setDrawBorder(style.getBool(StyleSpec::BORDER, true));\r
725         setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));\r
726         setOverrideFont(style.getFont());\r
727 \r
728         if (style.isNotDefault(StyleSpec::BGIMG)) {\r
729                 video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,\r
730                                 getTextureSource());\r
731                 setImage(guiScalingImageButton(\r
732                                 Environment->getVideoDriver(), texture,\r
733                                                 AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));\r
734                 setScaleImage(true);\r
735         } else {\r
736                 setImage(nullptr);\r
737         }\r
738 \r
739         BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);\r
740 \r
741         // Child padding and offset\r
742         Padding = style.getRect(StyleSpec::PADDING, core::rect<s32>());\r
743         Padding = core::rect<s32>(\r
744                         Padding.UpperLeftCorner + BgMiddle.UpperLeftCorner,\r
745                         Padding.LowerRightCorner + BgMiddle.LowerRightCorner);\r
746 \r
747         GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
748         core::vector2d<s32> defaultPressOffset(\r
749                         skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),\r
750                         skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y));\r
751         ContentOffset = style.getVector2i(StyleSpec::CONTENT_OFFSET, isPressed()\r
752                         ? defaultPressOffset\r
753                         : core::vector2d<s32>(0));\r
754 \r
755         core::rect<s32> childBounds(\r
756                                 Padding.UpperLeftCorner.X + ContentOffset.X,\r
757                                 Padding.UpperLeftCorner.Y + ContentOffset.Y,\r
758                                 AbsoluteRect.getWidth() + Padding.LowerRightCorner.X + ContentOffset.X,\r
759                                 AbsoluteRect.getHeight() + Padding.LowerRightCorner.Y + ContentOffset.Y);\r
760 \r
761         for (IGUIElement *child : getChildren()) {\r
762                 child->setRelativePosition(childBounds);\r
763         }\r
764 }\r
765 \r
766 //! Set the styles used for each state\r
767 void GUIButton::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles)\r
768 {\r
769         Styles = styles;\r
770         setFromState();\r
771 }\r
772 // END PATCH\r