]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CGUIMessageBox.cpp
57b383dbcb9306dbeed422f4c59a26ee2652e72d
[irrlicht.git] / source / Irrlicht / CGUIMessageBox.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 "CGUIMessageBox.h"\r
6 #ifdef _IRR_COMPILE_WITH_GUI_\r
7 \r
8 #include "IGUISkin.h"\r
9 #include "IGUIEnvironment.h"\r
10 #include "IGUIButton.h"\r
11 #include "IGUIFont.h"\r
12 #include "ITexture.h"\r
13 \r
14 namespace irr\r
15 {\r
16 namespace gui\r
17 {\r
18 \r
19 //! constructor\r
20 CGUIMessageBox::CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption,\r
21         const wchar_t* text, s32 flags,\r
22         IGUIElement* parent, s32 id, core::rect<s32> rectangle, video::ITexture* image)\r
23 : CGUIWindow(environment, parent, id, rectangle),\r
24         OkButton(0), CancelButton(0), YesButton(0), NoButton(0), StaticText(0),\r
25         Icon(0), IconTexture(image),\r
26         Flags(flags), MessageText(text), Pressed(false)\r
27 {\r
28         #ifdef _DEBUG\r
29         setDebugName("CGUIMessageBox");\r
30         #endif\r
31 \r
32         // set element type\r
33         Type = EGUIET_MESSAGE_BOX;\r
34 \r
35         // remove focus\r
36         Environment->setFocus(0);\r
37 \r
38         // remove buttons\r
39 \r
40         getMaximizeButton()->remove();\r
41         getMinimizeButton()->remove();\r
42 \r
43         if (caption)\r
44                 setText(caption);\r
45 \r
46         Environment->setFocus(this);\r
47 \r
48         if ( IconTexture )\r
49                 IconTexture->grab();\r
50 \r
51         refreshControls();\r
52 }\r
53 \r
54 \r
55 //! destructor\r
56 CGUIMessageBox::~CGUIMessageBox()\r
57 {\r
58         if (StaticText)\r
59                 StaticText->drop();\r
60 \r
61         if (OkButton)\r
62                 OkButton->drop();\r
63 \r
64         if (CancelButton)\r
65                 CancelButton->drop();\r
66 \r
67         if (YesButton)\r
68                 YesButton->drop();\r
69 \r
70         if (NoButton)\r
71                 NoButton->drop();\r
72 \r
73         if (Icon)\r
74                 Icon->drop();\r
75 \r
76         if ( IconTexture )\r
77                 IconTexture->drop();\r
78 }\r
79 \r
80 void CGUIMessageBox::setButton(IGUIButton*& button, bool isAvailable, const core::rect<s32> & btnRect, const wchar_t * text, IGUIElement*& focusMe)\r
81 {\r
82         // add/remove ok button\r
83         if (isAvailable)\r
84         {\r
85                 if (!button)\r
86                 {\r
87                         button = Environment->addButton(btnRect, this);\r
88                         button->setSubElement(true);\r
89                         button->grab();\r
90                 }\r
91                 else\r
92                         button->setRelativePosition(btnRect);\r
93 \r
94                 button->setText(text);\r
95 \r
96                 focusMe = button;\r
97         }\r
98         else if (button)\r
99         {\r
100                 button->drop();\r
101                 button->remove();\r
102                 button =0;\r
103         }\r
104 }\r
105 \r
106 void CGUIMessageBox::refreshControls()\r
107 {\r
108         // Layout can be seen as 4 boxes (a layoutmanager would be nice)\r
109         // One box at top over the whole width for title\r
110         // Two boxes with same height at the middle beside each other for icon and for text\r
111         // One box at the bottom for the buttons\r
112 \r
113         const IGUISkin* skin = Environment->getSkin();\r
114 \r
115         const s32 buttonHeight   = skin->getSize(EGDS_BUTTON_HEIGHT);\r
116         const s32 buttonWidth    = skin->getSize(EGDS_BUTTON_WIDTH);\r
117         const s32 titleHeight    = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH)+2;   // titlebar has no own constant\r
118         const s32 buttonDistance = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH);\r
119         const s32 borderWidth    = skin->getSize(EGDS_MESSAGE_BOX_GAP_SPACE);\r
120 \r
121         // add the static text for the message\r
122         core::rect<s32> staticRect;\r
123         staticRect.UpperLeftCorner.X = borderWidth;\r
124         staticRect.UpperLeftCorner.Y = titleHeight + borderWidth;\r
125         staticRect.LowerRightCorner.X = staticRect.UpperLeftCorner.X + skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_WIDTH);\r
126         staticRect.LowerRightCorner.Y = staticRect.UpperLeftCorner.Y + skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT);\r
127         if (!StaticText)\r
128         {\r
129                 StaticText = Environment->addStaticText(MessageText.c_str(), staticRect, false, false, this);\r
130 \r
131                 StaticText->setWordWrap(true);\r
132                 StaticText->setSubElement(true);\r
133                 StaticText->grab();\r
134         }\r
135         else\r
136         {\r
137                 StaticText->setRelativePosition(staticRect);\r
138                 StaticText->setText(MessageText.c_str());\r
139         }\r
140 \r
141         s32 textHeight  = StaticText->getTextHeight();\r
142         s32 textWidth = StaticText->getTextWidth() + 6; // +6 because the static itself needs that\r
143         const s32 iconHeight = IconTexture ? IconTexture->getOriginalSize().Height : 0;\r
144 \r
145         if ( textWidth < skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH) )\r
146                 textWidth = skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH) + 6;\r
147         // no neeed to check for max because it couldn't get larger due to statictextbox.\r
148         if ( textHeight < skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT) )\r
149                 textHeight = skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT);\r
150         if ( textHeight > skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT) )\r
151                 textHeight = skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT);\r
152 \r
153         // content is text + icons + borders (but not titlebar)\r
154         s32 contentHeight = textHeight > iconHeight ? textHeight : iconHeight;\r
155         contentHeight += borderWidth;\r
156         s32 contentWidth = 0;\r
157 \r
158         // add icon\r
159         if ( IconTexture )\r
160         {\r
161                 core::position2d<s32> iconPos;\r
162                 iconPos.Y = titleHeight + borderWidth;\r
163                 if ( iconHeight < textHeight )\r
164                         iconPos.Y += (textHeight-iconHeight) / 2;\r
165                 iconPos.X = borderWidth;\r
166 \r
167                 if (!Icon)\r
168                 {\r
169                         Icon = Environment->addImage(IconTexture, iconPos, true, this);\r
170                         Icon->setSubElement(true);\r
171                         Icon->grab();\r
172                 }\r
173                 else\r
174                 {\r
175                         core::rect<s32> iconRect( iconPos.X, iconPos.Y, iconPos.X + IconTexture->getOriginalSize().Width, iconPos.Y + IconTexture->getOriginalSize().Height );\r
176                         Icon->setRelativePosition(iconRect);\r
177                 }\r
178 \r
179                 contentWidth += borderWidth + IconTexture->getOriginalSize().Width;\r
180         }\r
181         else if ( Icon )\r
182         {\r
183                 Icon->drop();\r
184                 Icon->remove();\r
185                 Icon = 0;\r
186         }\r
187 \r
188         // position text\r
189         core::rect<s32> textRect;\r
190         textRect.UpperLeftCorner.X = contentWidth + borderWidth;\r
191         textRect.UpperLeftCorner.Y = titleHeight + borderWidth;\r
192         if ( textHeight < iconHeight )\r
193                 textRect.UpperLeftCorner.Y += (iconHeight-textHeight) / 2;\r
194         textRect.LowerRightCorner.X = textRect.UpperLeftCorner.X + textWidth;\r
195         textRect.LowerRightCorner.Y = textRect.UpperLeftCorner.Y + textHeight;\r
196         contentWidth += 2*borderWidth + textWidth;\r
197         StaticText->setRelativePosition( textRect );\r
198 \r
199         // find out button size needs\r
200         s32 countButtons = 0;\r
201         if (Flags & EMBF_OK)\r
202                 ++countButtons;\r
203         if (Flags & EMBF_CANCEL)\r
204                 ++countButtons;\r
205         if (Flags & EMBF_YES)\r
206                 ++countButtons;\r
207         if (Flags & EMBF_NO)\r
208                 ++countButtons;\r
209 \r
210         s32 buttonBoxWidth = countButtons * buttonWidth + 2 * borderWidth;\r
211         if ( countButtons > 1 )\r
212                 buttonBoxWidth += (countButtons-1) * buttonDistance;\r
213         s32 buttonBoxHeight = buttonHeight + 2 * borderWidth;\r
214 \r
215         // calc new message box sizes\r
216         core::rect<s32> tmp = getRelativePosition();\r
217         s32 msgBoxHeight = titleHeight + contentHeight + buttonBoxHeight;\r
218         s32 msgBoxWidth = contentWidth > buttonBoxWidth ? contentWidth : buttonBoxWidth;\r
219 \r
220         // adjust message box position\r
221         tmp.UpperLeftCorner.Y = (Parent->getAbsolutePosition().getHeight() - msgBoxHeight) / 2;\r
222         tmp.LowerRightCorner.Y = tmp.UpperLeftCorner.Y + msgBoxHeight;\r
223         tmp.UpperLeftCorner.X = (Parent->getAbsolutePosition().getWidth() - msgBoxWidth) / 2;\r
224         tmp.LowerRightCorner.X = tmp.UpperLeftCorner.X + msgBoxWidth;\r
225         setRelativePosition(tmp);\r
226 \r
227         // add buttons\r
228 \r
229         core::rect<s32> btnRect;\r
230         btnRect.UpperLeftCorner.Y = titleHeight + contentHeight + borderWidth;\r
231         btnRect.LowerRightCorner.Y = btnRect.UpperLeftCorner.Y + buttonHeight;\r
232         btnRect.UpperLeftCorner.X = borderWidth;\r
233         if ( contentWidth > buttonBoxWidth )\r
234                 btnRect.UpperLeftCorner.X += (contentWidth - buttonBoxWidth) / 2;       // center buttons\r
235         btnRect.LowerRightCorner.X = btnRect.UpperLeftCorner.X + buttonWidth;\r
236 \r
237         IGUIElement* focusMe = 0;\r
238         setButton(OkButton, (Flags & EMBF_OK) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_OK), focusMe);\r
239         if ( Flags & EMBF_OK )\r
240                 btnRect += core::position2d<s32>(buttonWidth + buttonDistance, 0);\r
241         setButton(CancelButton, (Flags & EMBF_CANCEL) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_CANCEL), focusMe);\r
242         if ( Flags & EMBF_CANCEL )\r
243                 btnRect += core::position2d<s32>(buttonWidth + buttonDistance, 0);\r
244         setButton(YesButton, (Flags & EMBF_YES) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_YES), focusMe);\r
245         if ( Flags & EMBF_YES )\r
246                 btnRect += core::position2d<s32>(buttonWidth + buttonDistance, 0);\r
247         setButton(NoButton, (Flags & EMBF_NO) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_NO), focusMe);\r
248 \r
249         if (Environment->hasFocus(this) && focusMe)\r
250                 Environment->setFocus(focusMe);\r
251 }\r
252 \r
253 \r
254 //! called if an event happened.\r
255 bool CGUIMessageBox::OnEvent(const SEvent& event)\r
256 {\r
257         if (isEnabled())\r
258         {\r
259                 SEvent outevent;\r
260                 outevent.EventType = EET_GUI_EVENT;\r
261                 outevent.GUIEvent.Caller = this;\r
262                 outevent.GUIEvent.Element = 0;\r
263 \r
264                 switch(event.EventType)\r
265                 {\r
266                 case EET_KEY_INPUT_EVENT:\r
267 \r
268                         if (event.KeyInput.PressedDown)\r
269                         {\r
270                                 switch (event.KeyInput.Key)\r
271                                 {\r
272                                 case KEY_RETURN:\r
273                                         if (OkButton)\r
274                                         {\r
275                                                 OkButton->setPressed(true);\r
276                                                 Pressed = true;\r
277                                         }\r
278                                         break;\r
279                                 case KEY_KEY_Y:\r
280                                         if (YesButton)\r
281                                         {\r
282                                                 YesButton->setPressed(true);\r
283                                                 Pressed = true;\r
284                                         }\r
285                                         break;\r
286                                 case KEY_KEY_N:\r
287                                         if (NoButton)\r
288                                         {\r
289                                                 NoButton->setPressed(true);\r
290                                                 Pressed = true;\r
291                                         }\r
292                                         break;\r
293                                 case KEY_ESCAPE:\r
294                                         if (Pressed)\r
295                                         {\r
296                                                 // cancel press\r
297                                                 if (OkButton) OkButton->setPressed(false);\r
298                                                 if (YesButton) YesButton->setPressed(false);\r
299                                                 if (NoButton) NoButton->setPressed(false);\r
300                                                 Pressed = false;\r
301                                         }\r
302                                         else\r
303                                         if (CancelButton)\r
304                                         {\r
305                                                 CancelButton->setPressed(true);\r
306                                                 Pressed = true;\r
307                                         }\r
308                                         else\r
309                                         if (CloseButton && CloseButton->isVisible())\r
310                                         {\r
311                                                 CloseButton->setPressed(true);\r
312                                                 Pressed = true;\r
313                                         }\r
314                                         break;\r
315                                 default: // no other key is handled here\r
316                                         break;\r
317                                 }\r
318                         }\r
319                         else\r
320                         if (Pressed)\r
321                         {\r
322                                 if (OkButton && event.KeyInput.Key == KEY_RETURN)\r
323                                 {\r
324                                         setVisible(false);      // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC\r
325                                         Environment->setFocus(0);\r
326                                         outevent.GUIEvent.EventType = EGET_MESSAGEBOX_OK;\r
327                                         Parent->OnEvent(outevent);\r
328                                         remove();\r
329                                         return true;\r
330                                 }\r
331                                 else\r
332                                 if ((CancelButton || CloseButton) && event.KeyInput.Key == KEY_ESCAPE)\r
333                                 {\r
334                                         setVisible(false);      // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC\r
335                                         Environment->setFocus(0);\r
336                                         outevent.GUIEvent.EventType = EGET_MESSAGEBOX_CANCEL;\r
337                                         Parent->OnEvent(outevent);\r
338                                         remove();\r
339                                         return true;\r
340                                 }\r
341                                 else\r
342                                 if (YesButton && event.KeyInput.Key == KEY_KEY_Y)\r
343                                 {\r
344                                         setVisible(false);      // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC\r
345                                         Environment->setFocus(0);\r
346                                         outevent.GUIEvent.EventType = EGET_MESSAGEBOX_YES;\r
347                                         Parent->OnEvent(outevent);\r
348                                         remove();\r
349                                         return true;\r
350                                 }\r
351                                 else\r
352                                 if (NoButton && event.KeyInput.Key == KEY_KEY_N)\r
353                                 {\r
354                                         setVisible(false);      // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC\r
355                                         Environment->setFocus(0);\r
356                                         outevent.GUIEvent.EventType = EGET_MESSAGEBOX_NO;\r
357                                         Parent->OnEvent(outevent);\r
358                                         remove();\r
359                                         return true;\r
360                                 }\r
361                         }\r
362                         break;\r
363                 case EET_GUI_EVENT:\r
364                         if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)\r
365                         {\r
366                                 if (event.GUIEvent.Caller == OkButton)\r
367                                 {\r
368                                         setVisible(false);      // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC\r
369                                         Environment->setFocus(0);\r
370                                         outevent.GUIEvent.EventType = EGET_MESSAGEBOX_OK;\r
371                                         Parent->OnEvent(outevent);\r
372                                         remove();\r
373                                         return true;\r
374                                 }\r
375                                 else\r
376                                 if (event.GUIEvent.Caller == CancelButton ||\r
377                                         event.GUIEvent.Caller == CloseButton)\r
378                                 {\r
379                                         setVisible(false);      // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC\r
380                                         Environment->setFocus(0);\r
381                                         outevent.GUIEvent.EventType = EGET_MESSAGEBOX_CANCEL;\r
382                                         Parent->OnEvent(outevent);\r
383                                         remove();\r
384                                         return true;\r
385                                 }\r
386                                 else\r
387                                 if (event.GUIEvent.Caller == YesButton)\r
388                                 {\r
389                                         setVisible(false);      // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC\r
390                                         Environment->setFocus(0);\r
391                                         outevent.GUIEvent.EventType = EGET_MESSAGEBOX_YES;\r
392                                         Parent->OnEvent(outevent);\r
393                                         remove();\r
394                                         return true;\r
395                                 }\r
396                                 else\r
397                                 if (event.GUIEvent.Caller == NoButton)\r
398                                 {\r
399                                         setVisible(false);      // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC\r
400                                         Environment->setFocus(0);\r
401                                         outevent.GUIEvent.EventType = EGET_MESSAGEBOX_NO;\r
402                                         Parent->OnEvent(outevent);\r
403                                         remove();\r
404                                         return true;\r
405                                 }\r
406                         }\r
407                         break;\r
408                 default:\r
409                         break;\r
410                 }\r
411         }\r
412 \r
413         return CGUIWindow::OnEvent(event);\r
414 }\r
415 \r
416 \r
417 //! Writes attributes of the element.\r
418 void CGUIMessageBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const\r
419 {\r
420         CGUIWindow::serializeAttributes(out,options);\r
421 \r
422         out->addBool    ("OkayButton",          (Flags & EMBF_OK)       != 0 );\r
423         out->addBool    ("CancelButton",        (Flags & EMBF_CANCEL)   != 0 );\r
424         out->addBool    ("YesButton",           (Flags & EMBF_YES)      != 0 );\r
425         out->addBool    ("NoButton",            (Flags & EMBF_NO)       != 0 );\r
426         out->addTexture ("Texture",                     IconTexture);\r
427 \r
428         out->addString  ("MessageText",         MessageText.c_str());\r
429 }\r
430 \r
431 \r
432 //! Reads attributes of the element\r
433 void CGUIMessageBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)\r
434 {\r
435         Flags = 0;\r
436 \r
437         Flags  = in->getAttributeAsBool("OkayButton")  ? EMBF_OK     : 0;\r
438         Flags |= in->getAttributeAsBool("CancelButton")? EMBF_CANCEL : 0;\r
439         Flags |= in->getAttributeAsBool("YesButton")   ? EMBF_YES    : 0;\r
440         Flags |= in->getAttributeAsBool("NoButton")    ? EMBF_NO     : 0;\r
441 \r
442         if ( IconTexture )\r
443         {\r
444                 IconTexture->drop();\r
445                 IconTexture = NULL;\r
446         }\r
447         IconTexture = in->getAttributeAsTexture("Texture");\r
448         if ( IconTexture )\r
449                 IconTexture->grab();\r
450 \r
451         MessageText = in->getAttributeAsStringW("MessageText").c_str();\r
452 \r
453         CGUIWindow::deserializeAttributes(in,options);\r
454 \r
455         refreshControls();\r
456 }\r
457 \r
458 \r
459 } // end namespace gui\r
460 } // end namespace irr\r
461 \r
462 #endif // _IRR_COMPILE_WITH_GUI_\r
463 \r