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 #ifndef __I_GUI_ELEMENT_H_INCLUDED__
\r
6 #define __I_GUI_ELEMENT_H_INCLUDED__
\r
8 #include "IAttributeExchangingObject.h"
\r
11 #include "irrString.h"
\r
12 #include "IEventReceiver.h"
\r
13 #include "EGUIElementTypes.h"
\r
14 #include "EGUIAlignment.h"
\r
15 #include "IAttributes.h"
\r
16 #include "IGUIEnvironment.h"
\r
22 //! Base class of all GUI elements.
\r
23 class IGUIElement : public virtual io::IAttributeExchangingObject, public IEventReceiver
\r
28 IGUIElement(EGUI_ELEMENT_TYPE type, IGUIEnvironment* environment, IGUIElement* parent,
\r
29 s32 id, const core::rect<s32>& rectangle)
\r
30 : Parent(0), RelativeRect(rectangle), AbsoluteRect(rectangle),
\r
31 AbsoluteClippingRect(rectangle), DesiredRect(rectangle),
\r
32 MaxSize(0,0), MinSize(1,1), IsVisible(true), IsEnabled(true),
\r
33 IsSubElement(false), NoClip(false), ID(id), IsTabStop(false), TabOrder(-1), IsTabGroup(false),
\r
34 AlignLeft(EGUIA_UPPERLEFT), AlignRight(EGUIA_UPPERLEFT), AlignTop(EGUIA_UPPERLEFT), AlignBottom(EGUIA_UPPERLEFT),
\r
35 Environment(environment), Type(type)
\r
38 setDebugName("IGUIElement");
\r
41 // if we were given a parent to attach to
\r
44 parent->addChildToEnd(this);
\r
45 recalculateAbsolutePosition(true);
\r
51 virtual ~IGUIElement()
\r
53 // delete all children
\r
54 core::list<IGUIElement*>::Iterator it = Children.begin();
\r
55 for (; it != Children.end(); ++it)
\r
63 //! Returns parent of this element.
\r
64 IGUIElement* getParent() const
\r
69 //! Returns the relative rectangle of this element.
\r
70 core::rect<s32> getRelativePosition() const
\r
72 return RelativeRect;
\r
76 //! Sets the relative rectangle of this element.
\r
77 /** \param r The absolute position to set */
\r
78 void setRelativePosition(const core::rect<s32>& r)
\r
82 const core::rect<s32>& r2 = Parent->getAbsolutePosition();
\r
84 core::dimension2df d((f32)(r2.getSize().Width), (f32)(r2.getSize().Height));
\r
86 if (AlignLeft == EGUIA_SCALE)
\r
87 ScaleRect.UpperLeftCorner.X = (f32)r.UpperLeftCorner.X / d.Width;
\r
88 if (AlignRight == EGUIA_SCALE)
\r
89 ScaleRect.LowerRightCorner.X = (f32)r.LowerRightCorner.X / d.Width;
\r
90 if (AlignTop == EGUIA_SCALE)
\r
91 ScaleRect.UpperLeftCorner.Y = (f32)r.UpperLeftCorner.Y / d.Height;
\r
92 if (AlignBottom == EGUIA_SCALE)
\r
93 ScaleRect.LowerRightCorner.Y = (f32)r.LowerRightCorner.Y / d.Height;
\r
97 updateAbsolutePosition();
\r
100 //! Sets the relative rectangle of this element, maintaining its current width and height
\r
101 /** \param position The new relative position to set. Width and height will not be changed. */
\r
102 void setRelativePosition(const core::position2di & position)
\r
104 const core::dimension2di mySize = RelativeRect.getSize();
\r
105 const core::rect<s32> rectangle(position.X, position.Y,
\r
106 position.X + mySize.Width, position.Y + mySize.Height);
\r
107 setRelativePosition(rectangle);
\r
111 //! Sets the relative rectangle of this element as a proportion of its parent's area.
\r
112 /** \note This method used to be 'void setRelativePosition(const core::rect<f32>& r)'
\r
113 \param r The rectangle to set, interpreted as a proportion of the parent's area.
\r
114 Meaningful values are in the range [0...1], unless you intend this element to spill
\r
115 outside its parent. */
\r
116 void setRelativePositionProportional(const core::rect<f32>& r)
\r
121 const core::dimension2di& d = Parent->getAbsolutePosition().getSize();
\r
123 DesiredRect = core::rect<s32>(
\r
124 core::floor32((f32)d.Width * r.UpperLeftCorner.X),
\r
125 core::floor32((f32)d.Height * r.UpperLeftCorner.Y),
\r
126 core::floor32((f32)d.Width * r.LowerRightCorner.X),
\r
127 core::floor32((f32)d.Height * r.LowerRightCorner.Y));
\r
131 updateAbsolutePosition();
\r
135 //! Gets the absolute rectangle of this element
\r
136 core::rect<s32> getAbsolutePosition() const
\r
138 return AbsoluteRect;
\r
142 //! Returns the visible area of the element.
\r
143 core::rect<s32> getAbsoluteClippingRect() const
\r
145 return AbsoluteClippingRect;
\r
149 //! Sets whether the element will ignore its parent's clipping rectangle
\r
150 /** \param noClip If true, the element will not be clipped by its parent's clipping rectangle. */
\r
151 void setNotClipped(bool noClip)
\r
154 updateAbsolutePosition();
\r
158 //! Gets whether the element will ignore its parent's clipping rectangle
\r
159 /** \return true if the element is not clipped by its parent's clipping rectangle. */
\r
160 bool isNotClipped() const
\r
166 //! Sets the maximum size allowed for this element
\r
167 /** If set to 0,0, there is no maximum size */
\r
168 void setMaxSize(core::dimension2du size)
\r
171 updateAbsolutePosition();
\r
175 //! Sets the minimum size allowed for this element
\r
176 void setMinSize(core::dimension2du size)
\r
179 if (MinSize.Width < 1)
\r
181 if (MinSize.Height < 1)
\r
182 MinSize.Height = 1;
\r
183 updateAbsolutePosition();
\r
187 //! The alignment defines how the borders of this element will be positioned when the parent element is resized.
\r
188 void setAlignment(EGUI_ALIGNMENT left, EGUI_ALIGNMENT right, EGUI_ALIGNMENT top, EGUI_ALIGNMENT bottom)
\r
191 AlignRight = right;
\r
193 AlignBottom = bottom;
\r
197 core::rect<s32> r(Parent->getAbsolutePosition());
\r
199 core::dimension2df d((f32)r.getSize().Width, (f32)r.getSize().Height);
\r
201 if (AlignLeft == EGUIA_SCALE)
\r
202 ScaleRect.UpperLeftCorner.X = (f32)DesiredRect.UpperLeftCorner.X / d.Width;
\r
203 if (AlignRight == EGUIA_SCALE)
\r
204 ScaleRect.LowerRightCorner.X = (f32)DesiredRect.LowerRightCorner.X / d.Width;
\r
205 if (AlignTop == EGUIA_SCALE)
\r
206 ScaleRect.UpperLeftCorner.Y = (f32)DesiredRect.UpperLeftCorner.Y / d.Height;
\r
207 if (AlignBottom == EGUIA_SCALE)
\r
208 ScaleRect.LowerRightCorner.Y = (f32)DesiredRect.LowerRightCorner.Y / d.Height;
\r
212 //! How left element border is aligned when parent is resized
\r
213 EGUI_ALIGNMENT getAlignLeft() const
\r
218 //! How right element border is aligned when parent is resized
\r
219 EGUI_ALIGNMENT getAlignRight() const
\r
224 //! How top element border is aligned when parent is resized
\r
225 EGUI_ALIGNMENT getAlignTop() const
\r
230 //! How bottom element border is aligned when parent is resized
\r
231 EGUI_ALIGNMENT getAlignBottom() const
\r
233 return AlignBottom;
\r
236 //! Updates the absolute position.
\r
237 virtual void updateAbsolutePosition()
\r
239 recalculateAbsolutePosition(false);
\r
241 // update all children
\r
242 core::list<IGUIElement*>::Iterator it = Children.begin();
\r
243 for (; it != Children.end(); ++it)
\r
245 (*it)->updateAbsolutePosition();
\r
250 //! Returns the topmost GUI element at the specific position.
\r
252 This will check this GUI element and all of its descendants, so it
\r
253 may return this GUI element. To check all GUI elements, call this
\r
254 function on device->getGUIEnvironment()->getRootGUIElement(). Note
\r
255 that the root element is the size of the screen, so doing so (with
\r
256 an on-screen point) will always return the root element if no other
\r
257 element is above it at that point.
\r
258 \param point: The point at which to find a GUI element.
\r
259 \return The topmost GUI element at that point, or 0 if there are
\r
260 no candidate elements at this point.
\r
262 virtual IGUIElement* getElementFromPoint(const core::position2d<s32>& point)
\r
264 IGUIElement* target = 0;
\r
266 // we have to search from back to front, because later children
\r
267 // might be drawn over the top of earlier ones.
\r
269 core::list<IGUIElement*>::ConstIterator it = Children.getLast();
\r
273 while(it != Children.end())
\r
275 target = (*it)->getElementFromPoint(point);
\r
283 if (isVisible() && isPointInside(point))
\r
290 //! Returns true if a point is within this element.
\r
291 /** Elements with a shape other than a rectangle should override this method */
\r
292 virtual bool isPointInside(const core::position2d<s32>& point) const
\r
294 return AbsoluteClippingRect.isPointInside(point);
\r
298 //! Adds a GUI element as new child of this element.
\r
299 virtual void addChild(IGUIElement* child)
\r
301 if ( child && child != this )
\r
303 addChildToEnd(child);
\r
304 child->updateAbsolutePosition();
\r
308 //! Removes a child.
\r
309 virtual void removeChild(IGUIElement* child)
\r
311 core::list<IGUIElement*>::Iterator it = Children.begin();
\r
312 for (; it != Children.end(); ++it)
\r
313 if ((*it) == child)
\r
317 Children.erase(it);
\r
323 //! Removes this element from its parent.
\r
324 virtual void remove()
\r
327 Parent->removeChild(this);
\r
331 //! Draws the element and its children.
\r
332 virtual void draw()
\r
336 core::list<IGUIElement*>::Iterator it = Children.begin();
\r
337 for (; it != Children.end(); ++it)
\r
343 //! animate the element and its children.
\r
344 virtual void OnPostRender(u32 timeMs)
\r
348 core::list<IGUIElement*>::Iterator it = Children.begin();
\r
349 for (; it != Children.end(); ++it)
\r
350 (*it)->OnPostRender( timeMs );
\r
355 //! Moves this element.
\r
356 virtual void move(core::position2d<s32> absoluteMovement)
\r
358 setRelativePosition(DesiredRect + absoluteMovement);
\r
362 //! Returns true if element is visible.
\r
363 virtual bool isVisible() const
\r
368 //! Check whether the element is truly visible, taking into accounts its parents' visibility
\r
369 /** \return true if the element and all its parents are visible,
\r
370 false if this or any parent element is invisible. */
\r
371 virtual bool isTrulyVisible() const
\r
379 return Parent->isTrulyVisible();
\r
382 //! Sets the visible state of this element.
\r
383 virtual void setVisible(bool visible)
\r
385 IsVisible = visible;
\r
389 //! Returns true if this element was created as part of its parent control
\r
390 virtual bool isSubElement() const
\r
392 return IsSubElement;
\r
396 //! Sets whether this control was created as part of its parent.
\r
397 /** For example, it is true when a scrollbar is part of a listbox.
\r
398 SubElements are not saved to disk when calling guiEnvironment->saveGUI() */
\r
399 virtual void setSubElement(bool subElement)
\r
401 IsSubElement = subElement;
\r
405 //! If set to true, the focus will visit this element when using the tab key to cycle through elements.
\r
406 /** If this element is a tab group (see isTabGroup/setTabGroup) then
\r
407 ctrl+tab will be used instead. */
\r
408 void setTabStop(bool enable)
\r
410 IsTabStop = enable;
\r
414 //! Returns true if this element can be focused by navigating with the tab key
\r
415 bool isTabStop() const
\r
421 //! Sets the priority of focus when using the tab key to navigate between a group of elements.
\r
422 /** See setTabGroup, isTabGroup and getTabGroup for information on tab groups.
\r
423 Elements with a lower number are focused first */
\r
424 void setTabOrder(s32 index)
\r
426 // negative = autonumber
\r
430 IGUIElement *el = getTabGroup();
\r
431 while (IsTabGroup && el && el->Parent)
\r
434 IGUIElement *first=0, *closest=0;
\r
437 // find the highest element number
\r
438 el->getNextElement(-1, true, IsTabGroup, first, closest, true);
\r
441 TabOrder = first->getTabOrder() + 1;
\r
451 //! Returns the number in the tab order sequence
\r
452 s32 getTabOrder() const
\r
458 //! Sets whether this element is a container for a group of elements which can be navigated using the tab key.
\r
459 /** For example, windows are tab groups.
\r
460 Groups can be navigated using ctrl+tab, providing isTabStop is true. */
\r
461 void setTabGroup(bool isGroup)
\r
463 IsTabGroup = isGroup;
\r
467 //! Returns true if this element is a tab group.
\r
468 bool isTabGroup() const
\r
474 //! Returns the container element which holds all elements in this element's tab group.
\r
475 IGUIElement* getTabGroup()
\r
477 IGUIElement *ret=this;
\r
479 while (ret && !ret->isTabGroup())
\r
480 ret = ret->getParent();
\r
486 //! Returns true if element is enabled
\r
487 /** Currently elements do _not_ care about parent-states.
\r
488 So if you want to affect children you have to enable/disable them all.
\r
489 The only exception to this are sub-elements which also check their parent.
\r
491 virtual bool isEnabled() const
\r
493 if ( isSubElement() && IsEnabled && getParent() )
\r
494 return getParent()->isEnabled();
\r
500 //! Sets the enabled state of this element.
\r
501 virtual void setEnabled(bool enabled)
\r
503 IsEnabled = enabled;
\r
507 //! Sets the new caption of this element.
\r
508 virtual void setText(const wchar_t* text)
\r
514 //! Returns caption of this element.
\r
515 virtual const wchar_t* getText() const
\r
517 return Text.c_str();
\r
521 //! Sets the new caption of this element.
\r
522 virtual void setToolTipText(const wchar_t* text)
\r
524 ToolTipText = text;
\r
528 //! Returns caption of this element.
\r
529 virtual const core::stringw& getToolTipText() const
\r
531 return ToolTipText;
\r
535 //! Returns id. Can be used to identify the element.
\r
536 virtual s32 getID() const
\r
542 //! Sets the id of this element
\r
543 virtual void setID(s32 id)
\r
549 //! Called if an event happened.
\r
550 virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_
\r
552 return Parent ? Parent->OnEvent(event) : false;
\r
556 //! Brings a child to front
\r
557 /** \return True if successful, false if not. */
\r
558 virtual bool bringToFront(IGUIElement* element)
\r
560 core::list<IGUIElement*>::Iterator it = Children.begin();
\r
561 for (; it != Children.end(); ++it)
\r
563 if (element == (*it))
\r
565 Children.erase(it);
\r
566 Children.push_back(element);
\r
575 //! Moves a child to the back, so it's siblings are drawn on top of it
\r
576 /** \return True if successful, false if not. */
\r
577 virtual bool sendToBack(IGUIElement* child)
\r
579 core::list<IGUIElement*>::Iterator it = Children.begin();
\r
580 if (child == (*it)) // already there
\r
582 for (; it != Children.end(); ++it)
\r
584 if (child == (*it))
\r
586 Children.erase(it);
\r
587 Children.push_front(child);
\r
595 //! Returns list with children of this element
\r
596 virtual const core::list<IGUIElement*>& getChildren() const
\r
602 //! Finds the first element with the given id.
\r
603 /** \param id: Id to search for.
\r
604 \param searchchildren: Set this to true, if also children of this
\r
605 element may contain the element with the searched id and they
\r
606 should be searched too.
\r
607 \return Returns the first element with the given id. If no element
\r
608 with this id was found, 0 is returned. */
\r
609 virtual IGUIElement* getElementFromId(s32 id, bool searchchildren=false) const
\r
611 IGUIElement* e = 0;
\r
613 core::list<IGUIElement*>::ConstIterator it = Children.begin();
\r
614 for (; it != Children.end(); ++it)
\r
616 if ((*it)->getID() == id)
\r
619 if (searchchildren)
\r
620 e = (*it)->getElementFromId(id, true);
\r
630 //! returns true if the given element is a child of this one.
\r
631 //! \param child: The child element to check
\r
632 bool isMyChild(IGUIElement* child) const
\r
639 child = child->Parent;
\r
641 } while (child->Parent && child != this);
\r
644 return child == this;
\r
648 //! searches elements to find the closest next element to tab to
\r
649 /** \param startOrder: The TabOrder of the current element, -1 if none
\r
650 \param reverse: true if searching for a lower number
\r
651 \param group: true if searching for a higher one
\r
652 \param first: element with the highest/lowest known tab order depending on search direction
\r
653 \param closest: the closest match, depending on tab order and direction
\r
654 \param includeInvisible: includes invisible elements in the search (default=false)
\r
655 \param includeDisabled: includes disabled elements in the search (default=false)
\r
656 \return true if successfully found an element, false to continue searching/fail */
\r
657 bool getNextElement(s32 startOrder, bool reverse, bool group,
\r
658 IGUIElement*& first, IGUIElement*& closest, bool includeInvisible=false,
\r
659 bool includeDisabled=false) const
\r
661 // we'll stop searching if we find this number
\r
662 s32 wanted = startOrder + ( reverse ? -1 : 1 );
\r
664 wanted = 1073741824; // maximum s32
\r
666 core::list<IGUIElement*>::ConstIterator it = Children.begin();
\r
668 s32 closestOrder, currentOrder;
\r
670 while(it != Children.end())
\r
672 // ignore invisible elements and their children
\r
673 if ( ( (*it)->isVisible() || includeInvisible ) &&
\r
674 (group == true || (*it)->isTabGroup() == false) )
\r
676 // ignore disabled, but children are checked (disabled is currently per element ignoring parent states)
\r
677 if ( (*it)->isEnabled() || includeDisabled )
\r
679 // only check tab stops and those with the same group status
\r
680 if ((*it)->isTabStop() && ((*it)->isTabGroup() == group))
\r
682 currentOrder = (*it)->getTabOrder();
\r
684 // is this what we're looking for?
\r
685 if (currentOrder == wanted)
\r
691 // is it closer than the current closest?
\r
694 closestOrder = closest->getTabOrder();
\r
695 if ( ( reverse && currentOrder > closestOrder && currentOrder < startOrder)
\r
696 ||(!reverse && currentOrder < closestOrder && currentOrder > startOrder))
\r
702 if ( (reverse && currentOrder < startOrder) || (!reverse && currentOrder > startOrder) )
\r
707 // is it before the current first?
\r
710 closestOrder = first->getTabOrder();
\r
712 if ( (reverse && closestOrder < currentOrder) || (!reverse && closestOrder > currentOrder) )
\r
723 // search within children
\r
724 if ((*it)->getNextElement(startOrder, reverse, group, first, closest))
\r
735 //! Returns the type of the gui element.
\r
736 /** This is needed for the .NET wrapper but will be used
\r
737 later for serializing and deserializing.
\r
738 If you wrote your own GUIElements, you need to set the type for your element as first parameter
\r
739 in the constructor of IGUIElement. For own (=unknown) elements, simply use EGUIET_ELEMENT as type */
\r
740 EGUI_ELEMENT_TYPE getType() const
\r
745 //! Returns true if the gui element supports the given type.
\r
746 /** This is mostly used to check if you can cast a gui element to the class that goes with the type.
\r
747 Most gui elements will only support their own type, but if you derive your own classes from interfaces
\r
748 you can overload this function and add a check for the type of the base-class additionally.
\r
749 This allows for checks comparable to the dynamic_cast of c++ with enabled rtti.
\r
750 Note that you can't do that by calling BaseClass::hasType(type), but you have to do an explicit
\r
751 comparison check, because otherwise the base class usually just checks for the member variable
\r
752 Type which contains the type of your derived class.
\r
754 virtual bool hasType(EGUI_ELEMENT_TYPE type) const
\r
756 return type == Type;
\r
760 //! Returns the type name of the gui element.
\r
761 /** This is needed serializing elements. For serializing your own elements, override this function
\r
762 and return your own type name which is created by your IGUIElementFactory */
\r
763 virtual const c8* getTypeName() const
\r
765 return GUIElementTypeNames[Type];
\r
768 //! Returns the name of the element.
\r
769 /** \return Name as character string. */
\r
770 virtual const c8* getName() const
\r
772 return Name.c_str();
\r
776 //! Sets the name of the element.
\r
777 /** \param name New name of the gui element. */
\r
778 virtual void setName(const c8* name)
\r
784 //! Sets the name of the element.
\r
785 /** \param name New name of the gui element. */
\r
786 virtual void setName(const core::stringc& name)
\r
792 //! Returns whether the element takes input from the IME
\r
793 virtual bool acceptsIME()
\r
799 //! Writes attributes of the scene node.
\r
800 /** Implement this to expose the attributes of your scene node for
\r
801 scripting languages, editors, debuggers or xml serialization purposes. */
\r
802 virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_
\r
804 out->addString("Name", Name.c_str());
\r
805 out->addInt("Id", ID );
\r
806 out->addString("Caption", getText());
\r
807 out->addString("ToolTip", getToolTipText().c_str());
\r
808 out->addRect("Rect", DesiredRect);
\r
809 out->addPosition2d("MinSize", core::position2di(MinSize.Width, MinSize.Height));
\r
810 out->addPosition2d("MaxSize", core::position2di(MaxSize.Width, MaxSize.Height));
\r
811 out->addEnum("LeftAlign", AlignLeft, GUIAlignmentNames);
\r
812 out->addEnum("RightAlign", AlignRight, GUIAlignmentNames);
\r
813 out->addEnum("TopAlign", AlignTop, GUIAlignmentNames);
\r
814 out->addEnum("BottomAlign", AlignBottom, GUIAlignmentNames);
\r
815 out->addBool("Visible", IsVisible);
\r
816 out->addBool("Enabled", IsEnabled);
\r
817 out->addBool("TabStop", IsTabStop);
\r
818 out->addBool("TabGroup", IsTabGroup);
\r
819 out->addInt("TabOrder", TabOrder);
\r
820 out->addBool("NoClip", NoClip);
\r
824 //! Reads attributes of the scene node.
\r
825 /** Implement this to set the attributes of your scene node for
\r
826 scripting languages, editors, debuggers or xml deserialization purposes. */
\r
827 virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_
\r
829 setName(in->getAttributeAsString("Name", Name));
\r
830 setID(in->getAttributeAsInt("Id", ID));
\r
831 setText(in->getAttributeAsStringW("Caption", Text).c_str());
\r
832 setToolTipText(in->getAttributeAsStringW("ToolTip").c_str());
\r
833 setVisible(in->getAttributeAsBool("Visible", IsVisible));
\r
834 setEnabled(in->getAttributeAsBool("Enabled", IsEnabled));
\r
835 IsTabStop = in->getAttributeAsBool("TabStop", IsTabStop);
\r
836 IsTabGroup = in->getAttributeAsBool("TabGroup", IsTabGroup);
\r
837 TabOrder = in->getAttributeAsInt("TabOrder", TabOrder);
\r
839 core::position2di p = in->getAttributeAsPosition2d("MaxSize", core::position2di(MaxSize.Width, MaxSize.Height));
\r
840 setMaxSize(core::dimension2du(p.X,p.Y));
\r
842 p = in->getAttributeAsPosition2d("MinSize", core::position2di(MinSize.Width, MinSize.Height));
\r
843 setMinSize(core::dimension2du(p.X,p.Y));
\r
845 setAlignment((EGUI_ALIGNMENT) in->getAttributeAsEnumeration("LeftAlign", GUIAlignmentNames, AlignLeft),
\r
846 (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("RightAlign", GUIAlignmentNames, AlignRight),
\r
847 (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("TopAlign", GUIAlignmentNames, AlignTop),
\r
848 (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("BottomAlign", GUIAlignmentNames, AlignBottom));
\r
850 setRelativePosition(in->getAttributeAsRect("Rect", DesiredRect));
\r
852 setNotClipped(in->getAttributeAsBool("NoClip", NoClip));
\r
856 // not virtual because needed in constructor
\r
857 void addChildToEnd(IGUIElement* child)
\r
861 child->grab(); // prevent destruction when removed
\r
862 child->remove(); // remove from old parent
\r
863 child->LastParentRect = getAbsolutePosition();
\r
864 child->Parent = this;
\r
865 Children.push_back(child);
\r
869 // not virtual because needed in constructor
\r
870 void recalculateAbsolutePosition(bool recursive)
\r
872 core::rect<s32> parentAbsolute(0,0,0,0);
\r
873 core::rect<s32> parentAbsoluteClip;
\r
874 f32 fw=0.f, fh=0.f;
\r
878 parentAbsolute = Parent->AbsoluteRect;
\r
882 IGUIElement* p=this;
\r
885 parentAbsoluteClip = p->AbsoluteClippingRect;
\r
888 parentAbsoluteClip = Parent->AbsoluteClippingRect;
\r
891 const s32 diffx = parentAbsolute.getWidth() - LastParentRect.getWidth();
\r
892 const s32 diffy = parentAbsolute.getHeight() - LastParentRect.getHeight();
\r
894 if (AlignLeft == EGUIA_SCALE || AlignRight == EGUIA_SCALE)
\r
895 fw = (f32)parentAbsolute.getWidth();
\r
897 if (AlignTop == EGUIA_SCALE || AlignBottom == EGUIA_SCALE)
\r
898 fh = (f32)parentAbsolute.getHeight();
\r
902 case EGUIA_UPPERLEFT:
\r
904 case EGUIA_LOWERRIGHT:
\r
905 DesiredRect.UpperLeftCorner.X += diffx;
\r
908 DesiredRect.UpperLeftCorner.X += diffx/2;
\r
911 DesiredRect.UpperLeftCorner.X = core::round32(ScaleRect.UpperLeftCorner.X * fw);
\r
915 switch (AlignRight)
\r
917 case EGUIA_UPPERLEFT:
\r
919 case EGUIA_LOWERRIGHT:
\r
920 DesiredRect.LowerRightCorner.X += diffx;
\r
923 DesiredRect.LowerRightCorner.X += diffx/2;
\r
926 DesiredRect.LowerRightCorner.X = core::round32(ScaleRect.LowerRightCorner.X * fw);
\r
932 case EGUIA_UPPERLEFT:
\r
934 case EGUIA_LOWERRIGHT:
\r
935 DesiredRect.UpperLeftCorner.Y += diffy;
\r
938 DesiredRect.UpperLeftCorner.Y += diffy/2;
\r
941 DesiredRect.UpperLeftCorner.Y = core::round32(ScaleRect.UpperLeftCorner.Y * fh);
\r
945 switch (AlignBottom)
\r
947 case EGUIA_UPPERLEFT:
\r
949 case EGUIA_LOWERRIGHT:
\r
950 DesiredRect.LowerRightCorner.Y += diffy;
\r
953 DesiredRect.LowerRightCorner.Y += diffy/2;
\r
956 DesiredRect.LowerRightCorner.Y = core::round32(ScaleRect.LowerRightCorner.Y * fh);
\r
960 RelativeRect = DesiredRect;
\r
962 const s32 w = RelativeRect.getWidth();
\r
963 const s32 h = RelativeRect.getHeight();
\r
965 // make sure the desired rectangle is allowed
\r
966 if (w < (s32)MinSize.Width)
\r
967 RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MinSize.Width;
\r
968 if (h < (s32)MinSize.Height)
\r
969 RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MinSize.Height;
\r
970 if (MaxSize.Width && w > (s32)MaxSize.Width)
\r
971 RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MaxSize.Width;
\r
972 if (MaxSize.Height && h > (s32)MaxSize.Height)
\r
973 RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MaxSize.Height;
\r
975 RelativeRect.repair();
\r
977 AbsoluteRect = RelativeRect + parentAbsolute.UpperLeftCorner;
\r
980 parentAbsoluteClip = AbsoluteRect;
\r
982 AbsoluteClippingRect = AbsoluteRect;
\r
983 AbsoluteClippingRect.clipAgainst(parentAbsoluteClip);
\r
985 LastParentRect = parentAbsolute;
\r
989 // update all children
\r
990 core::list<IGUIElement*>::Iterator it = Children.begin();
\r
991 for (; it != Children.end(); ++it)
\r
993 (*it)->recalculateAbsolutePosition(recursive);
\r
1000 //! List of all children of this element
\r
1001 core::list<IGUIElement*> Children;
\r
1003 //! Pointer to the parent
\r
1004 IGUIElement* Parent;
\r
1006 //! relative rect of element
\r
1007 core::rect<s32> RelativeRect;
\r
1009 //! absolute rect of element
\r
1010 core::rect<s32> AbsoluteRect;
\r
1012 //! absolute clipping rect of element
\r
1013 core::rect<s32> AbsoluteClippingRect;
\r
1015 //! the rectangle the element would prefer to be,
\r
1016 //! if it was not constrained by parent or max/min size
\r
1017 core::rect<s32> DesiredRect;
\r
1019 //! for calculating the difference when resizing parent
\r
1020 core::rect<s32> LastParentRect;
\r
1022 //! relative scale of the element inside its parent
\r
1023 core::rect<f32> ScaleRect;
\r
1025 //! maximum and minimum size of the element
\r
1026 core::dimension2du MaxSize, MinSize;
\r
1034 //! is a part of a larger whole and should not be serialized?
\r
1035 bool IsSubElement;
\r
1037 //! does this element ignore its parent's clipping rectangle?
\r
1041 core::stringw Text;
\r
1044 core::stringw ToolTipText;
\r
1046 //! users can set this for identifying the element by string
\r
1047 core::stringc Name;
\r
1049 //! users can set this for identifying the element by integer
\r
1052 //! tab stop like in windows
\r
1058 //! tab groups are containers like windows, use ctrl+tab to navigate
\r
1061 //! tells the element how to act when its parent is resized
\r
1062 EGUI_ALIGNMENT AlignLeft, AlignRight, AlignTop, AlignBottom;
\r
1064 //! GUI Environment
\r
1065 IGUIEnvironment* Environment;
\r
1067 //! type of element
\r
1068 EGUI_ELEMENT_TYPE Type;
\r
1072 } // end namespace gui
\r
1073 } // end namespace irr
\r