Commit 1b523f68 authored by cutealien's avatar cutealien

- Fix bug that menus on IGUIWindows with titlebar got drawn too high (id: 2714400)

- Add another parameter to IGUISkin::draw3DWindowBackground to allow getting the client area without actually drawing 
- Add function getClientRect to IGUIWindow for getting the draw-able area
- Documenation updates


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@3073 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 95ea9b9b
Changes in 1.7 Changes in 1.7
- Add hasType to IGUIElement as a dynamic_cast substitute.
- Add another parameter to IGUISkin::draw3DWindowBackground to allow getting the client area without actually drawing
- Add function getClientRect to IGUIWindow for getting the draw-able area
- Fix bug that menus on IGUIWindows with titlebar got drawn too high (id: 2714400)
- Renamed OctTree to Octree - Renamed OctTree to Octree
- Allow getting a ConstIterator from a non-const core:list - Allow getting a ConstIterator from a non-const core:list
......
...@@ -683,6 +683,20 @@ public: ...@@ -683,6 +683,20 @@ public:
return Type; return Type;
} }
//! Returns true if the gui element supports the given type.
/** This is mostly used to check if you can cast a gui element to the class that goes with the type.
Most gui elements will only support their own type, but if you derive your own classes from interfaces
you can overload this function and add a check for the type of the base-class additionally.
This allows for checks comparable to the dynamic_cast of c++ with enabled rtti.
Note that you can't do that by calling BaseClass::hasType(type), but you have to do an explicit
comparison check, because otherwise the base class usually just checks for the membervariable
Type which contains the type of your derived class.
*/
virtual bool hasType(EGUI_ELEMENT_TYPE type) const
{
return type == Type;
}
//! Returns the type name of the gui element. //! Returns the type name of the gui element.
/** This is needed serializing elements. For serializing your own elements, override this function /** This is needed serializing elements. For serializing your own elements, override this function
......
...@@ -448,11 +448,16 @@ namespace gui ...@@ -448,11 +448,16 @@ namespace gui
\param drawTitleBar: True to enable title drawing. \param drawTitleBar: True to enable title drawing.
\param rect: Defining area where to draw. \param rect: Defining area where to draw.
\param clip: Clip area. \param clip: Clip area.
\return Returns rect where it would be good to draw title bar text. */ \param checkClientArea: When set to non-null the function will not draw anything,
but will instead return the clientArea which can be used for drawing by the calling window.
That is the area without borders and without titlebar.
\return Returns rect where it would be good to draw title bar text. This will
work even when checkClientArea is set to a non-null value.*/
virtual core::rect<s32> draw3DWindowBackground(IGUIElement* element, virtual core::rect<s32> draw3DWindowBackground(IGUIElement* element,
bool drawTitleBar, video::SColor titleBarColor, bool drawTitleBar, video::SColor titleBarColor,
const core::rect<s32>& rect, const core::rect<s32>& rect,
const core::rect<s32>* clip=0) = 0; const core::rect<s32>* clip=0,
core::rect<s32>* checkClientArea=0) = 0;
//! draws a standard 3d menu pane //! draws a standard 3d menu pane
/** Used for drawing for menus and context menus. /** Used for drawing for menus and context menus.
......
...@@ -53,6 +53,14 @@ namespace gui ...@@ -53,6 +53,14 @@ namespace gui
//! Get if the window titlebar will be drawn //! Get if the window titlebar will be drawn
virtual bool getDrawTitlebar() const = 0; virtual bool getDrawTitlebar() const = 0;
//! Returns the rectangle of the drawable area (without border and without titlebar)
/** The coordinates are given relative to the top-left position of the gui element.<br>
So to get absolute positions you have to add the resulting rectangle to getAbsolutePosition().UpperLeftCorner.<br>
To get it relative to the parent element you have to add the resulting rectangle to getRelativePosition().UpperLeftCorner.
Beware that adding a menu will not change the clientRect as menus are own gui elements, so in that case you might want to subtract
the menu area additionally. */
virtual core::rect<s32> getClientRect() const = 0;
}; };
......
...@@ -13,7 +13,7 @@ namespace irr ...@@ -13,7 +13,7 @@ namespace irr
namespace io namespace io
{ {
//! Interface providing write acess to a file. //! Interface providing write access to a file.
class IWriteFile : public virtual IReferenceCounted class IWriteFile : public virtual IReferenceCounted
{ {
public: public:
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "IGUIEnvironment.h" #include "IGUIEnvironment.h"
#include "IVideoDriver.h" #include "IVideoDriver.h"
#include "IGUIFont.h" #include "IGUIFont.h"
#include "IGUIWindow.h"
#include "os.h" #include "os.h"
...@@ -184,28 +185,41 @@ bool CGUIMenu::OnEvent(const SEvent& event) ...@@ -184,28 +185,41 @@ bool CGUIMenu::OnEvent(const SEvent& event)
return IGUIElement::OnEvent(event); return IGUIElement::OnEvent(event);
} }
void CGUIMenu::recalculateSize() void CGUIMenu::recalculateSize()
{ {
core::rect<s32> clientRect; // client rect of parent
if ( Parent && Parent->hasType(EGUIET_WINDOW) )
{
clientRect = static_cast<IGUIWindow*>(Parent)->getClientRect();
}
else if ( Parent )
{
clientRect = core::rect<s32>(0,0, Parent->getAbsolutePosition().getWidth(),
Parent->getAbsolutePosition().getHeight());
}
else
{
clientRect = RelativeRect;
}
IGUISkin* skin = Environment->getSkin(); IGUISkin* skin = Environment->getSkin();
IGUIFont* font = skin->getFont(EGDF_MENU); IGUIFont* font = skin->getFont(EGDF_MENU);
if (!font) if (!font)
{ {
if (Parent && skin) if (Parent && skin)
RelativeRect = core::rect<s32>(0,0, RelativeRect = core::rect<s32>(clientRect.UpperLeftCorner.X, clientRect.UpperLeftCorner.Y,
Parent->getAbsolutePosition().LowerRightCorner.X, clientRect.LowerRightCorner.X, clientRect.UpperLeftCorner.Y+skin->getSize(EGDS_MENU_HEIGHT));
skin->getSize(EGDS_MENU_HEIGHT));
return; return;
} }
core::rect<s32> rect; core::rect<s32> rect;
rect.UpperLeftCorner.X = 0; rect.UpperLeftCorner = clientRect.UpperLeftCorner;
rect.UpperLeftCorner.Y = 0;
s32 height = font->getDimension(L"A").Height + 5; s32 height = font->getDimension(L"A").Height + 5;
//if (skin && height < skin->getSize ( EGDS_MENU_HEIGHT )) //if (skin && height < skin->getSize ( EGDS_MENU_HEIGHT ))
// height = skin->getSize(EGDS_MENU_HEIGHT); // height = skin->getSize(EGDS_MENU_HEIGHT);
s32 width = 0; s32 width = rect.UpperLeftCorner.X;
s32 i; s32 i;
for (i=0; i<(s32)Items.size(); ++i) for (i=0; i<(s32)Items.size(); ++i)
...@@ -225,11 +239,10 @@ void CGUIMenu::recalculateSize() ...@@ -225,11 +239,10 @@ void CGUIMenu::recalculateSize()
width += Items[i].Dim.Width; width += Items[i].Dim.Width;
} }
if (Parent) width = clientRect.getWidth();
width = Parent->getAbsolutePosition().getWidth();
rect.LowerRightCorner.X = width; rect.LowerRightCorner.X = rect.UpperLeftCorner.X + width;
rect.LowerRightCorner.Y = height; rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + height;
setRelativePosition(rect); setRelativePosition(rect);
......
...@@ -464,56 +464,93 @@ implementations to find out how to draw the part exactly. ...@@ -464,56 +464,93 @@ implementations to find out how to draw the part exactly.
core::rect<s32> CGUISkin::draw3DWindowBackground(IGUIElement* element, core::rect<s32> CGUISkin::draw3DWindowBackground(IGUIElement* element,
bool drawTitleBar, video::SColor titleBarColor, bool drawTitleBar, video::SColor titleBarColor,
const core::rect<s32>& r, const core::rect<s32>& r,
const core::rect<s32>* cl) const core::rect<s32>* cl,
core::rect<s32>* checkClientArea)
{ {
if (!Driver) if (!Driver)
{
if ( checkClientArea )
{
*checkClientArea = r;
}
return r; return r;
}
core::rect<s32> rect = r; core::rect<s32> rect = r;
// top border
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;
if ( !checkClientArea )
{
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, cl); Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, cl);
}
// left border
rect.LowerRightCorner.Y = r.LowerRightCorner.Y; rect.LowerRightCorner.Y = r.LowerRightCorner.Y;
rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1;
if ( !checkClientArea )
{
Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, cl); Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, cl);
}
// right border dark outer line
rect.UpperLeftCorner.X = r.LowerRightCorner.X - 1; rect.UpperLeftCorner.X = r.LowerRightCorner.X - 1;
rect.LowerRightCorner.X = r.LowerRightCorner.X; rect.LowerRightCorner.X = r.LowerRightCorner.X;
rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y; rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y;
rect.LowerRightCorner.Y = r.LowerRightCorner.Y; rect.LowerRightCorner.Y = r.LowerRightCorner.Y;
if ( !checkClientArea )
{
Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, cl); Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, cl);
}
// right border bright innner line
rect.UpperLeftCorner.X -= 1; rect.UpperLeftCorner.X -= 1;
rect.LowerRightCorner.X -= 1; rect.LowerRightCorner.X -= 1;
rect.UpperLeftCorner.Y += 1; rect.UpperLeftCorner.Y += 1;
rect.LowerRightCorner.Y -= 1; rect.LowerRightCorner.Y -= 1;
if ( !checkClientArea )
{
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, cl); Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, cl);
}
// bottom border dark outer line
rect.UpperLeftCorner.X = r.UpperLeftCorner.X; rect.UpperLeftCorner.X = r.UpperLeftCorner.X;
rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1;
rect.LowerRightCorner.Y = r.LowerRightCorner.Y; rect.LowerRightCorner.Y = r.LowerRightCorner.Y;
rect.LowerRightCorner.X = r.LowerRightCorner.X; rect.LowerRightCorner.X = r.LowerRightCorner.X;
if ( !checkClientArea )
{
Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, cl); Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, cl);
}
// bottom border bright inner line
rect.UpperLeftCorner.X += 1; rect.UpperLeftCorner.X += 1;
rect.LowerRightCorner.X -= 1; rect.LowerRightCorner.X -= 1;
rect.UpperLeftCorner.Y -= 1; rect.UpperLeftCorner.Y -= 1;
rect.LowerRightCorner.Y -= 1; rect.LowerRightCorner.Y -= 1;
if ( !checkClientArea )
{
Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, cl); Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, cl);
}
// client area for background
rect = r; rect = r;
rect.UpperLeftCorner.X +=1; rect.UpperLeftCorner.X +=1;
rect.UpperLeftCorner.Y +=1; rect.UpperLeftCorner.Y +=1;
rect.LowerRightCorner.X -= 2; rect.LowerRightCorner.X -= 2;
rect.LowerRightCorner.Y -= 2; rect.LowerRightCorner.Y -= 2;
if (checkClientArea)
{
*checkClientArea = rect;
}
if ( !checkClientArea )
{
if (!UseGradient) if (!UseGradient)
{ {
Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, cl); Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, cl);
} }
else else if ( Type == EGST_BURNING_SKIN )
if ( Type == EGST_BURNING_SKIN )
{ {
const video::SColor c1 = getColor(EGDC_WINDOW).getInterpolated ( 0xFFFFFFFF, 0.9f ); const video::SColor c1 = getColor(EGDC_WINDOW).getInterpolated ( 0xFFFFFFFF, 0.9f );
const video::SColor c2 = getColor(EGDC_WINDOW).getInterpolated ( 0xFFFFFFFF, 0.8f ); const video::SColor c2 = getColor(EGDC_WINDOW).getInterpolated ( 0xFFFFFFFF, 0.8f );
...@@ -526,14 +563,22 @@ core::rect<s32> CGUISkin::draw3DWindowBackground(IGUIElement* element, ...@@ -526,14 +563,22 @@ core::rect<s32> CGUISkin::draw3DWindowBackground(IGUIElement* element,
const video::SColor c1 = getColor(EGDC_3D_FACE); const video::SColor c1 = getColor(EGDC_3D_FACE);
Driver->draw2DRectangle(rect, c1, c1, c1, c2, cl); Driver->draw2DRectangle(rect, c1, c1, c1, c2, cl);
} }
}
// title bar
rect = r; rect = r;
rect.UpperLeftCorner.X += 2; rect.UpperLeftCorner.X += 2;
rect.UpperLeftCorner.Y += 2; rect.UpperLeftCorner.Y += 2;
rect.LowerRightCorner.X -= 2; rect.LowerRightCorner.X -= 2;
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + getSize(EGDS_WINDOW_BUTTON_WIDTH) + 2; rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + getSize(EGDS_WINDOW_BUTTON_WIDTH) + 2;
if (drawTitleBar) if (drawTitleBar )
{
if (checkClientArea)
{
(*checkClientArea).UpperLeftCorner.Y = rect.LowerRightCorner.Y;
}
else
{ {
// draw title bar // draw title bar
//if (!UseGradient) //if (!UseGradient)
...@@ -550,6 +595,7 @@ core::rect<s32> CGUISkin::draw3DWindowBackground(IGUIElement* element, ...@@ -550,6 +595,7 @@ core::rect<s32> CGUISkin::draw3DWindowBackground(IGUIElement* element,
Driver->draw2DRectangle(rect, titleBarColor, c, titleBarColor, c, cl); Driver->draw2DRectangle(rect, titleBarColor, c, titleBarColor, c, cl);
} }
} }
}
return rect; return rect;
} }
......
...@@ -125,11 +125,16 @@ namespace gui ...@@ -125,11 +125,16 @@ namespace gui
\param drawTitleBar: True to enable title drawing. \param drawTitleBar: True to enable title drawing.
\param rect: Defining area where to draw. \param rect: Defining area where to draw.
\param clip: Clip area. \param clip: Clip area.
\return Returns rect where to draw title bar text. */ \param checkClientArea: When set to non-null the function will not draw anything,
but will instead return the clientArea which can be used for drawing by the calling window.
That is the area without borders and without titlebar.
\return Returns rect where it would be good to draw title bar text. This will
work even when checkClientArea is set to a non-null value.*/
virtual core::rect<s32> draw3DWindowBackground(IGUIElement* element, virtual core::rect<s32> draw3DWindowBackground(IGUIElement* element,
bool drawTitleBar, video::SColor titleBarColor, bool drawTitleBar, video::SColor titleBarColor,
const core::rect<s32>& rect, const core::rect<s32>& rect,
const core::rect<s32>* clip=0); const core::rect<s32>* clip,
core::rect<s32>* checkClientArea);
//! draws a standard 3d menu pane //! draws a standard 3d menu pane
/** Used for drawing for menus and context menus. /** Used for drawing for menus and context menus.
......
...@@ -89,6 +89,8 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id ...@@ -89,6 +89,8 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id
setTabGroup(true); setTabGroup(true);
setTabStop(true); setTabStop(true);
setTabOrder(-1); setTabOrder(-1);
updateClientRect();
} }
...@@ -221,6 +223,9 @@ void CGUIWindow::draw() ...@@ -221,6 +223,9 @@ void CGUIWindow::draw()
{ {
IGUISkin* skin = Environment->getSkin(); IGUISkin* skin = Environment->getSkin();
// update each time because the skin is allowed to change this always.
updateClientRect();
core::rect<s32> rect = AbsoluteRect; core::rect<s32> rect = AbsoluteRect;
// draw body fast // draw body fast
...@@ -310,6 +315,27 @@ bool CGUIWindow::getDrawTitlebar() const ...@@ -310,6 +315,27 @@ bool CGUIWindow::getDrawTitlebar() const
return DrawTitlebar; return DrawTitlebar;
} }
void CGUIWindow::updateClientRect()
{
if (! DrawBackground )
{
ClientRect = core::rect<s32>(0,0, AbsoluteRect.getWidth(), AbsoluteRect.getHeight());
return;
}
IGUISkin* skin = Environment->getSkin();
skin->draw3DWindowBackground(this,
DrawTitlebar,
skin->getColor(IsActive ? EGDC_ACTIVE_BORDER : EGDC_INACTIVE_BORDER),
AbsoluteRect, &AbsoluteClippingRect, &ClientRect);
ClientRect -= AbsoluteRect.UpperLeftCorner;
}
//! Returns the rectangle of the drawable area (without border, without titlebar and without scrollbars)
core::rect<s32> CGUIWindow::getClientRect() const
{
return ClientRect;
}
//! Writes attributes of the element. //! Writes attributes of the element.
void CGUIWindow::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const void CGUIWindow::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{ {
...@@ -345,6 +371,8 @@ void CGUIWindow::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWr ...@@ -345,6 +371,8 @@ void CGUIWindow::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWr
CloseButton->setVisible( in->getAttributeAsBool("IsCloseVisible") ); CloseButton->setVisible( in->getAttributeAsBool("IsCloseVisible") );
MinButton->setVisible( in->getAttributeAsBool("IsMinVisible") ); MinButton->setVisible( in->getAttributeAsBool("IsMinVisible") );
RestoreButton->setVisible( in->getAttributeAsBool("IsRestoreVisible") ); RestoreButton->setVisible( in->getAttributeAsBool("IsRestoreVisible") );
updateClientRect();
} }
} // end namespace gui } // end namespace gui
......
...@@ -63,6 +63,9 @@ namespace gui ...@@ -63,6 +63,9 @@ namespace gui
//! Get if the window titlebar will be drawn //! Get if the window titlebar will be drawn
virtual bool getDrawTitlebar() const; virtual bool getDrawTitlebar() const;
//! Returns the rectangle of the drawable area (without border and without titlebar)
virtual core::rect<s32> getClientRect() const;
//! Writes attributes of the element. //! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const; virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
...@@ -71,9 +74,12 @@ namespace gui ...@@ -71,9 +74,12 @@ namespace gui
protected: protected:
void updateClientRect();
IGUIButton* CloseButton; IGUIButton* CloseButton;
IGUIButton* MinButton; IGUIButton* MinButton;
IGUIButton* RestoreButton; IGUIButton* RestoreButton;
core::rect<s32> ClientRect;
core::position2d<s32> DragStart; core::position2d<s32> DragStart;
bool Dragging, IsDraggable; bool Dragging, IsDraggable;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment