diff --git a/include/IGUIEnvironment.h b/include/IGUIEnvironment.h index 50acb29a..5fe3b5c8 100644 --- a/include/IGUIEnvironment.h +++ b/include/IGUIEnvironment.h @@ -240,11 +240,12 @@ public: to (EMBF_OK | EMBF_CANCEL). \param parent Parent gui element of the message box. \param id Id with which the gui element can be identified. + \param image Optional texture which will be displayed beside the text as an image \return Pointer to the created message box. Returns 0 if an error occured. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IGUIWindow* addMessageBox(const wchar_t* caption, const wchar_t* text=0, - bool modal = true, s32 flags = EMBF_OK, IGUIElement* parent=0, s32 id=-1) = 0; + bool modal = true, s32 flags = EMBF_OK, IGUIElement* parent=0, s32 id=-1, video::ITexture* image=0) = 0; //! Adds a scrollbar. /** \param horizontal Specifies if the scroll bar is drawn horizontal diff --git a/include/IGUISkin.h b/include/IGUISkin.h index d0ce8658..e0047f91 100644 --- a/include/IGUISkin.h +++ b/include/IGUISkin.h @@ -139,9 +139,9 @@ namespace gui EGDS_WINDOW_BUTTON_WIDTH, //! width of a checkbox check EGDS_CHECK_BOX_WIDTH, - //! width of a messagebox + //! deprecated EGDS_MESSAGE_BOX_WIDTH, - //! height of a messagebox + //! deprecated EGDS_MESSAGE_BOX_HEIGHT, //! width of a default button EGDS_BUTTON_WIDTH, @@ -155,6 +155,17 @@ namespace gui EGDS_TITLEBARTEXT_DISTANCE_X, //! distance for text in the title bar, from the top of the window rect EGDS_TITLEBARTEXT_DISTANCE_Y, + //! free space in a messagebox between borders and contents on all sides + EGDS_MESSAGE_BOX_GAP_SPACE, + //! minimal space to reserve for messagebox text-width + EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH, + //! maximal space to reserve for messagebox text-width + EGDS_MESSAGE_BOX_MAX_TEST_WIDTH, + //! minimal space to reserve for messagebox text-height + EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT, + //! maximal space to reserve for messagebox text-height + EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT, + //! this value is not used, it only specifies the amount of default sizes //! available. EGDS_COUNT @@ -174,6 +185,13 @@ namespace gui "ButtonHeight", "TextDistanceX", "TextDistanceY", + "TitleBarTextX", + "TitleBarTextY", + "MessageBoxGapSpace", + "MessageBoxMinTextWidth", + "MessageBoxMaxTextWidth", + "MessageBoxMinTextHeight", + "MessageBoxMaxTextHeight", 0, }; diff --git a/source/Irrlicht/CGUIEnvironment.cpp b/source/Irrlicht/CGUIEnvironment.cpp index 1d61e4a0..97e43b92 100644 --- a/source/Irrlicht/CGUIEnvironment.cpp +++ b/source/Irrlicht/CGUIEnvironment.cpp @@ -978,7 +978,7 @@ IGUIElement* CGUIEnvironment::addModalScreen(IGUIElement* parent) //! Adds a message box. IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t* text, - bool modal, s32 flag, IGUIElement* parent, s32 id) + bool modal, s32 flag, IGUIElement* parent, s32 id, video::ITexture* image) { if (!CurrentSkin) return 0; @@ -990,8 +990,8 @@ IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t screenDim.Width = parent->getAbsolutePosition().getWidth(); screenDim.Height = parent->getAbsolutePosition().getHeight(); - msgBoxDim.Width = CurrentSkin->getSize(gui::EGDS_MESSAGE_BOX_WIDTH); - msgBoxDim.Height = CurrentSkin->getSize(gui::EGDS_MESSAGE_BOX_HEIGHT); + msgBoxDim.Width = 2; + msgBoxDim.Height = 2; rect.UpperLeftCorner.X = (screenDim.Width - msgBoxDim.Width) / 2; rect.UpperLeftCorner.Y = (screenDim.Height - msgBoxDim.Height) / 2; @@ -1005,7 +1005,7 @@ IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t } IGUIWindow* win = new CGUIMessageBox(this, caption, text, flag, - parent, id, rect); + parent, id, rect, image); win->drop(); return win; diff --git a/source/Irrlicht/CGUIEnvironment.h b/source/Irrlicht/CGUIEnvironment.h index ba0deab4..c307ac98 100644 --- a/source/Irrlicht/CGUIEnvironment.h +++ b/source/Irrlicht/CGUIEnvironment.h @@ -96,7 +96,7 @@ public: //! Adds a message box. virtual IGUIWindow* addMessageBox(const wchar_t* caption, const wchar_t* text=0, - bool modal = true, s32 flag = EMBF_OK, IGUIElement* parent=0, s32 id=-1); + bool modal = true, s32 flag = EMBF_OK, IGUIElement* parent=0, s32 id=-1, video::ITexture* image=0); //! adds a scrollbar. The returned pointer must not be dropped. virtual IGUIScrollBar* addScrollBar(bool horizontal, const core::rect& rectangle, diff --git a/source/Irrlicht/CGUIMessageBox.cpp b/source/Irrlicht/CGUIMessageBox.cpp index 4f76a26a..6938ce94 100644 --- a/source/Irrlicht/CGUIMessageBox.cpp +++ b/source/Irrlicht/CGUIMessageBox.cpp @@ -9,6 +9,7 @@ #include "IGUIEnvironment.h" #include "IGUIButton.h" #include "IGUIFont.h" +#include "ITexture.h" namespace irr { @@ -18,9 +19,10 @@ namespace gui //! constructor CGUIMessageBox::CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption, const wchar_t* text, s32 flags, - IGUIElement* parent, s32 id, core::rect rectangle) + IGUIElement* parent, s32 id, core::rect rectangle, video::ITexture* image) : CGUIWindow(environment, parent, id, rectangle), OkButton(0), CancelButton(0), YesButton(0), NoButton(0), StaticText(0), + Icon(0), IconTexture(image), Flags(flags), MessageText(text), Pressed(false) { #ifdef _DEBUG @@ -43,6 +45,9 @@ CGUIMessageBox::CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* capt Environment->setFocus(this); + if ( IconTexture ) + IconTexture->grab(); + refreshControls(); } @@ -64,62 +69,134 @@ CGUIMessageBox::~CGUIMessageBox() if (NoButton) NoButton->drop(); + + if (Icon) + Icon->drop(); + + if ( IconTexture ) + IconTexture->drop(); } +void CGUIMessageBox::setButton(IGUIButton*& button, bool isAvailable, const core::rect & btnRect, const wchar_t * text, IGUIElement*& focusMe) +{ + // add/remove ok button + if (isAvailable) + { + if (!button) + { + button = Environment->addButton(btnRect, this); + button->setSubElement(true); + button->grab(); + } + else + button->setRelativePosition(btnRect); + + button->setText(text); + + focusMe = button; + } + else if (button) + { + button->drop(); + button->remove(); + button =0; + } +} void CGUIMessageBox::refreshControls() { + // Layout can be seen as 4 boxes (a layoutmanager would be nice) + // One box at top over the whole width for title + // Two boxes with same height at the middle beside each other for icon and for text + // One box at the bottom for the buttons + const IGUISkin* skin = Environment->getSkin(); - IGUIElement* focusMe = 0; const s32 buttonHeight = skin->getSize(EGDS_BUTTON_HEIGHT); const s32 buttonWidth = skin->getSize(EGDS_BUTTON_WIDTH); - const s32 titleHeight = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH)+2; + const s32 titleHeight = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH)+2; // titlebar has no own constant const s32 buttonDistance = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH); + const s32 borderWidth = skin->getSize(EGDS_MESSAGE_BOX_GAP_SPACE); - // add static multiline text - - core::dimension2d dim(AbsoluteClippingRect.getWidth() - buttonWidth, - AbsoluteClippingRect.getHeight() - (buttonHeight * 2)); - const core::position2d pos((AbsoluteClippingRect.getWidth() - dim.Width) / 2, - buttonHeight / 2 + titleHeight); - + // add the static text for the message + core::rect staticRect; + staticRect.UpperLeftCorner.X = borderWidth; + staticRect.UpperLeftCorner.Y = titleHeight + borderWidth; + staticRect.LowerRightCorner.X = staticRect.UpperLeftCorner.X + skin->getSize(EGDS_MESSAGE_BOX_MAX_TEST_WIDTH); + staticRect.LowerRightCorner.Y = staticRect.UpperLeftCorner.Y + skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT); if (!StaticText) { - StaticText = Environment->addStaticText(MessageText.c_str(), - core::rect(pos, dim), false, false, this); + StaticText = Environment->addStaticText(MessageText.c_str(), staticRect, false, false, this); + StaticText->setWordWrap(true); StaticText->setSubElement(true); StaticText->grab(); } else { - StaticText->setRelativePosition(core::rect(pos, dim)); + StaticText->setRelativePosition(staticRect); StaticText->setText(MessageText.c_str()); } - // adjust static text height + s32 textHeight = StaticText->getTextHeight(); + s32 textWidth = StaticText->getTextWidth() + 6; // +6 because the static itself needs that + const s32 iconHeight = IconTexture ? IconTexture->getOriginalSize().Height : 0; - const s32 textHeight = StaticText->getTextHeight(); - core::rect tmp = StaticText->getRelativePosition(); - tmp.LowerRightCorner.Y = tmp.UpperLeftCorner.Y + textHeight; - StaticText->setRelativePosition(tmp); - dim.Height = dim.Height - buttonHeight < tmp.getHeight() ? tmp.getHeight() : dim.Height - buttonHeight; + if ( textWidth < skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH) ) + textWidth = skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH) + 6; + // no neeed to check for max because it couldn't get larger due to statictextbox. + if ( textHeight < skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT) ) + textHeight = skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT); + if ( textHeight > skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT) ) + textHeight = skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT); - // adjust message box height if required + // content is text + icons + borders (but not titlebar) + s32 contentHeight = textHeight > iconHeight ? textHeight : iconHeight; + contentHeight += borderWidth; + s32 contentWidth = 0; - tmp = getRelativePosition(); - s32 msgBoxHeight = textHeight + core::floor32(2.5f * buttonHeight) + titleHeight; - msgBoxHeight = tmp.getHeight() < msgBoxHeight ? msgBoxHeight : tmp.getHeight(); + // add icon + if ( IconTexture ) + { + core::position2d iconPos; + iconPos.Y = titleHeight + borderWidth; + if ( iconHeight < textHeight ) + iconPos.Y += (textHeight-iconHeight) / 2; + iconPos.X = borderWidth; - // adjust message box position + if (!Icon) + { + Icon = Environment->addImage(IconTexture, iconPos, true, this); + Icon->setSubElement(true); + Icon->grab(); + } + else + { + core::rect iconRect( iconPos.X, iconPos.Y, iconPos.X + IconTexture->getOriginalSize().Width, iconPos.Y + IconTexture->getOriginalSize().Height ); + Icon->setRelativePosition(iconRect); + } - tmp.UpperLeftCorner.Y = (Parent->getAbsolutePosition().getHeight() - msgBoxHeight) / 2; - tmp.LowerRightCorner.Y = tmp.UpperLeftCorner.Y + msgBoxHeight; - setRelativePosition(tmp); + contentWidth += borderWidth + IconTexture->getOriginalSize().Width; + } + else if ( Icon ) + { + Icon->drop(); + Icon->remove(); + Icon = 0; + } - // add buttons + // position text + core::rect textRect; + textRect.UpperLeftCorner.X = contentWidth + borderWidth; + textRect.UpperLeftCorner.Y = titleHeight + borderWidth; + if ( textHeight < iconHeight ) + textRect.UpperLeftCorner.Y += (iconHeight-textHeight) / 2; + textRect.LowerRightCorner.X = textRect.UpperLeftCorner.X + textWidth; + textRect.LowerRightCorner.Y = textRect.UpperLeftCorner.Y + textHeight; + contentWidth += 2*borderWidth + textWidth; + StaticText->setRelativePosition( textRect ); + // find out button size needs s32 countButtons = 0; if (Flags & EMBF_OK) ++countButtons; @@ -130,123 +207,44 @@ void CGUIMessageBox::refreshControls() if (Flags & EMBF_NO) ++countButtons; + s32 buttonBoxWidth = countButtons * buttonWidth + 2 * borderWidth; + if ( countButtons > 1 ) + buttonBoxWidth += (countButtons-1) * buttonDistance; + s32 buttonBoxHeight = buttonHeight + 2 * borderWidth; + + // calc new message box sizes + core::rect tmp = getRelativePosition(); + s32 msgBoxHeight = titleHeight + contentHeight + buttonBoxHeight; + s32 msgBoxWidth = contentWidth > buttonBoxWidth ? contentWidth : buttonBoxWidth; + + // adjust message box position + tmp.UpperLeftCorner.Y = (Parent->getAbsolutePosition().getHeight() - msgBoxHeight) / 2; + tmp.LowerRightCorner.Y = tmp.UpperLeftCorner.Y + msgBoxHeight; + tmp.UpperLeftCorner.X = (Parent->getAbsolutePosition().getWidth() - msgBoxWidth) / 2; + tmp.LowerRightCorner.X = tmp.UpperLeftCorner.X + msgBoxWidth; + setRelativePosition(tmp); + + // add buttons + core::rect btnRect; - btnRect.UpperLeftCorner.Y = pos.Y + dim.Height + buttonHeight / 2; + btnRect.UpperLeftCorner.Y = titleHeight + contentHeight + borderWidth; btnRect.LowerRightCorner.Y = btnRect.UpperLeftCorner.Y + buttonHeight; - btnRect.UpperLeftCorner.X = (AbsoluteClippingRect.getWidth() - - (buttonWidth*countButtons + (buttonDistance*countButtons+1))) / 2 + - buttonDistance / 2; + btnRect.UpperLeftCorner.X = borderWidth; + if ( contentWidth > buttonBoxWidth ) + btnRect.UpperLeftCorner.X += (contentWidth - buttonBoxWidth) / 2; // center buttons btnRect.LowerRightCorner.X = btnRect.UpperLeftCorner.X + buttonWidth; - // add/remove ok button - if (Flags & EMBF_OK) - { - if (!OkButton) - { - OkButton = Environment->addButton(btnRect, this); - OkButton->setSubElement(true); - OkButton->grab(); - } - else - OkButton->setRelativePosition(btnRect); - - OkButton->setText(skin->getDefaultText(EGDT_MSG_BOX_OK)); - - btnRect.LowerRightCorner.X += buttonWidth + buttonDistance; - btnRect.UpperLeftCorner.X += buttonWidth + buttonDistance; - - focusMe = OkButton; - } - else if (OkButton) - { - OkButton->drop(); - OkButton->remove(); - OkButton = 0; - } - - // add cancel button - if (Flags & EMBF_CANCEL) - { - if (!CancelButton) - { - CancelButton = Environment->addButton(btnRect, this); - CancelButton->setSubElement(true); - CancelButton->grab(); - } - else - CancelButton->setRelativePosition(btnRect); - - CancelButton->setText(skin->getDefaultText(EGDT_MSG_BOX_CANCEL)); - - btnRect.LowerRightCorner.X += buttonWidth + buttonDistance; - btnRect.UpperLeftCorner.X += buttonWidth + buttonDistance; - - if (!focusMe) - focusMe = CancelButton; - - } - else if (CancelButton) - { - CancelButton->drop(); - CancelButton->remove(); - CancelButton = 0; - } - - - // add/remove yes button - if (Flags & EMBF_YES) - { - if (!YesButton) - { - YesButton = Environment->addButton(btnRect, this); - YesButton->setSubElement(true); - YesButton->grab(); - } - else - YesButton->setRelativePosition(btnRect); - - YesButton->setText(skin->getDefaultText(EGDT_MSG_BOX_YES)); - - btnRect.LowerRightCorner.X += buttonWidth + buttonDistance; - btnRect.UpperLeftCorner.X += buttonWidth + buttonDistance; - - if (!focusMe) - focusMe = YesButton; - } - else if (YesButton) - { - YesButton->drop(); - YesButton->remove(); - YesButton = 0; - } - - // add no button - if (Flags & EMBF_NO) - { - if (!NoButton) - { - NoButton = Environment->addButton(btnRect, this); - NoButton->setSubElement(true); - NoButton->grab(); - } - else - NoButton->setRelativePosition(btnRect); - - NoButton->setText(skin->getDefaultText(EGDT_MSG_BOX_NO)); - - btnRect.LowerRightCorner.X += buttonWidth + buttonDistance; - btnRect.UpperLeftCorner.X += buttonWidth + buttonDistance; - - if (!focusMe) - focusMe = NoButton; - - } - else if (NoButton) - { - NoButton->drop(); - NoButton->remove(); - NoButton = 0; - } + IGUIElement* focusMe = 0; + setButton(OkButton, Flags & EMBF_OK, btnRect, skin->getDefaultText(EGDT_MSG_BOX_OK), focusMe); + if ( Flags & EMBF_OK ) + btnRect += core::position2d(buttonWidth + buttonDistance, 0); + setButton(CancelButton, Flags & EMBF_CANCEL, btnRect, skin->getDefaultText(EGDT_MSG_BOX_CANCEL), focusMe); + if ( Flags & EMBF_CANCEL ) + btnRect += core::position2d(buttonWidth + buttonDistance, 0); + setButton(YesButton, Flags & EMBF_YES, btnRect, skin->getDefaultText(EGDT_MSG_BOX_YES), focusMe); + if ( Flags & EMBF_YES ) + btnRect += core::position2d(buttonWidth + buttonDistance, 0); + setButton(NoButton, Flags & EMBF_NO, btnRect, skin->getDefaultText(EGDT_MSG_BOX_NO), focusMe); if (Environment->hasFocus(this) && focusMe) Environment->setFocus(focusMe); @@ -409,6 +407,7 @@ void CGUIMessageBox::serializeAttributes(io::IAttributes* out, io::SAttributeRea out->addBool ("CancelButton", (Flags & EMBF_CANCEL) != 0 ); out->addBool ("YesButton", (Flags & EMBF_YES) != 0 ); out->addBool ("NoButton", (Flags & EMBF_NO) != 0 ); + out->addTexture ("Texture", IconTexture); out->addString ("MessageText", MessageText.c_str()); } @@ -424,6 +423,15 @@ void CGUIMessageBox::deserializeAttributes(io::IAttributes* in, io::SAttributeRe Flags |= in->getAttributeAsBool("YesButton") ? EMBF_YES : 0; Flags |= in->getAttributeAsBool("NoButton") ? EMBF_NO : 0; + if ( IconTexture ) + { + IconTexture->drop(); + IconTexture = NULL; + } + IconTexture = in->getAttributeAsTexture("Texture"); + if ( IconTexture ) + IconTexture->grab(); + MessageText = in->getAttributeAsStringW("MessageText").c_str(); CGUIWindow::deserializeAttributes(in,options); diff --git a/source/Irrlicht/CGUIMessageBox.h b/source/Irrlicht/CGUIMessageBox.h index 5686e028..3885c8c8 100644 --- a/source/Irrlicht/CGUIMessageBox.h +++ b/source/Irrlicht/CGUIMessageBox.h @@ -10,6 +10,7 @@ #include "CGUIWindow.h" #include "IGUIStaticText.h" +#include "IGUIImage.h" #include "irrArray.h" namespace irr @@ -23,7 +24,7 @@ namespace gui //! constructor CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption, const wchar_t* text, s32 flag, - IGUIElement* parent, s32 id, core::rect rectangle); + IGUIElement* parent, s32 id, core::rect rectangle, video::ITexture* image=0); //! destructor virtual ~CGUIMessageBox(); @@ -40,12 +41,15 @@ namespace gui private: void refreshControls(); + void setButton(IGUIButton*& button, bool isAvailable, const core::rect & btnRect, const wchar_t * text, IGUIElement*& focusMe); IGUIButton* OkButton; IGUIButton* CancelButton; IGUIButton* YesButton; IGUIButton* NoButton; IGUIStaticText* StaticText; + IGUIImage * Icon; + video::ITexture * IconTexture; s32 Flags; core::stringw MessageText; diff --git a/source/Irrlicht/CGUISkin.cpp b/source/Irrlicht/CGUISkin.cpp index 0a700db4..024b472c 100644 --- a/source/Irrlicht/CGUISkin.cpp +++ b/source/Irrlicht/CGUISkin.cpp @@ -104,6 +104,12 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) Sizes[EGDS_TITLEBARTEXT_DISTANCE_Y] = 2; } + Sizes[EGDS_MESSAGE_BOX_GAP_SPACE] = 15; + Sizes[EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH] = 0; + Sizes[EGDS_MESSAGE_BOX_MAX_TEST_WIDTH] = 500; + Sizes[EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT] = 0; + Sizes[EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT] = 99999; + Texts[EGDT_MSG_BOX_OK] = L"OK"; Texts[EGDT_MSG_BOX_CANCEL] = L"Cancel"; Texts[EGDT_MSG_BOX_YES] = L"Yes";