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
5 #include "CGUIMessageBox.h"
\r
6 #ifdef _IRR_COMPILE_WITH_GUI_
\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
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
29 setDebugName("CGUIMessageBox");
\r
33 Type = EGUIET_MESSAGE_BOX;
\r
36 Environment->setFocus(0);
\r
40 getMaximizeButton()->remove();
\r
41 getMinimizeButton()->remove();
\r
46 Environment->setFocus(this);
\r
49 IconTexture->grab();
\r
56 CGUIMessageBox::~CGUIMessageBox()
\r
65 CancelButton->drop();
\r
77 IconTexture->drop();
\r
80 void CGUIMessageBox::setButton(IGUIButton*& button, bool isAvailable, const core::rect<s32> & btnRect, const wchar_t * text, IGUIElement*& focusMe)
\r
82 // add/remove ok button
\r
87 button = Environment->addButton(btnRect, this);
\r
88 button->setSubElement(true);
\r
92 button->setRelativePosition(btnRect);
\r
94 button->setText(text);
\r
106 void CGUIMessageBox::refreshControls()
\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
113 const IGUISkin* skin = Environment->getSkin();
\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
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
129 StaticText = Environment->addStaticText(MessageText.c_str(), staticRect, false, false, this);
\r
131 StaticText->setWordWrap(true);
\r
132 StaticText->setSubElement(true);
\r
133 StaticText->grab();
\r
137 StaticText->setRelativePosition(staticRect);
\r
138 StaticText->setText(MessageText.c_str());
\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
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
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
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
169 Icon = Environment->addImage(IconTexture, iconPos, true, this);
\r
170 Icon->setSubElement(true);
\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
179 contentWidth += borderWidth + IconTexture->getOriginalSize().Width;
\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
199 // find out button size needs
\r
200 s32 countButtons = 0;
\r
201 if (Flags & EMBF_OK)
\r
203 if (Flags & EMBF_CANCEL)
\r
205 if (Flags & EMBF_YES)
\r
207 if (Flags & EMBF_NO)
\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
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
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
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
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
249 if (Environment->hasFocus(this) && focusMe)
\r
250 Environment->setFocus(focusMe);
\r
254 //! called if an event happened.
\r
255 bool CGUIMessageBox::OnEvent(const SEvent& event)
\r
260 outevent.EventType = EET_GUI_EVENT;
\r
261 outevent.GUIEvent.Caller = this;
\r
262 outevent.GUIEvent.Element = 0;
\r
264 switch(event.EventType)
\r
266 case EET_KEY_INPUT_EVENT:
\r
268 if (event.KeyInput.PressedDown)
\r
270 switch (event.KeyInput.Key)
\r
275 OkButton->setPressed(true);
\r
282 YesButton->setPressed(true);
\r
289 NoButton->setPressed(true);
\r
297 if (OkButton) OkButton->setPressed(false);
\r
298 if (YesButton) YesButton->setPressed(false);
\r
299 if (NoButton) NoButton->setPressed(false);
\r
305 CancelButton->setPressed(true);
\r
309 if (CloseButton && CloseButton->isVisible())
\r
311 CloseButton->setPressed(true);
\r
315 default: // no other key is handled here
\r
322 if (OkButton && event.KeyInput.Key == KEY_RETURN)
\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
332 if ((CancelButton || CloseButton) && event.KeyInput.Key == KEY_ESCAPE)
\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
342 if (YesButton && event.KeyInput.Key == KEY_KEY_Y)
\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
352 if (NoButton && event.KeyInput.Key == KEY_KEY_N)
\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
363 case EET_GUI_EVENT:
\r
364 if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED)
\r
366 if (event.GUIEvent.Caller == OkButton)
\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
376 if (event.GUIEvent.Caller == CancelButton ||
\r
377 event.GUIEvent.Caller == CloseButton)
\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
387 if (event.GUIEvent.Caller == YesButton)
\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
397 if (event.GUIEvent.Caller == NoButton)
\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
413 return CGUIWindow::OnEvent(event);
\r
417 //! Writes attributes of the element.
\r
418 void CGUIMessageBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
\r
420 CGUIWindow::serializeAttributes(out,options);
\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
428 out->addString ("MessageText", MessageText.c_str());
\r
432 //! Reads attributes of the element
\r
433 void CGUIMessageBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
\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
444 IconTexture->drop();
\r
445 IconTexture = NULL;
\r
447 IconTexture = in->getAttributeAsTexture("Texture");
\r
449 IconTexture->grab();
\r
451 MessageText = in->getAttributeAsStringW("MessageText").c_str();
\r
453 CGUIWindow::deserializeAttributes(in,options);
\r
459 } // end namespace gui
\r
460 } // end namespace irr
\r
462 #endif // _IRR_COMPILE_WITH_GUI_
\r