CGUIMessageBox.cpp 14 KB

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