123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941 |
- // Copyright (C) 2002-2012 Nikolaus Gebhardt
- // This file is part of the "Irrlicht Engine".
- // For conditions of distribution and use, see copyright notice in irrlicht.h
- #pragma once
- #include "IReferenceCounted.h"
- #include "rect.h"
- #include "irrString.h"
- #include "IEventReceiver.h"
- #include "EGUIElementTypes.h"
- #include "EGUIAlignment.h"
- #include "IAttributes.h"
- #include "IGUIEnvironment.h"
- #include <cassert>
- #include <algorithm>
- #include <list>
- #include <vector>
- namespace irr
- {
- namespace gui
- {
- //! Base class of all GUI elements.
- class IGUIElement : virtual public IReferenceCounted, public IEventReceiver
- {
- public:
- //! Constructor
- IGUIElement(EGUI_ELEMENT_TYPE type, IGUIEnvironment *environment, IGUIElement *parent,
- s32 id, const core::rect<s32> &rectangle) :
- Parent(0),
- RelativeRect(rectangle), AbsoluteRect(rectangle),
- AbsoluteClippingRect(rectangle), DesiredRect(rectangle),
- MaxSize(0, 0), MinSize(1, 1), IsVisible(true), IsEnabled(true),
- IsSubElement(false), NoClip(false), ID(id), IsTabStop(false), TabOrder(-1), IsTabGroup(false),
- AlignLeft(EGUIA_UPPERLEFT), AlignRight(EGUIA_UPPERLEFT), AlignTop(EGUIA_UPPERLEFT), AlignBottom(EGUIA_UPPERLEFT),
- Environment(environment), Type(type)
- {
- #ifdef _DEBUG
- setDebugName("IGUIElement");
- #endif
- // if we were given a parent to attach to
- if (parent) {
- parent->addChildToEnd(this);
- recalculateAbsolutePosition(true);
- }
- }
- //! Destructor
- virtual ~IGUIElement()
- {
- for (auto child : Children) {
- child->Parent = nullptr;
- child->drop();
- }
- }
- //! Returns parent of this element.
- IGUIElement *getParent() const
- {
- return Parent;
- }
- //! Returns the relative rectangle of this element.
- core::rect<s32> getRelativePosition() const
- {
- return RelativeRect;
- }
- //! Sets the relative rectangle of this element.
- /** \param r The absolute position to set */
- void setRelativePosition(const core::rect<s32> &r)
- {
- if (Parent) {
- const core::rect<s32> &r2 = Parent->getAbsolutePosition();
- core::dimension2df d((f32)(r2.getSize().Width), (f32)(r2.getSize().Height));
- if (AlignLeft == EGUIA_SCALE)
- ScaleRect.UpperLeftCorner.X = (f32)r.UpperLeftCorner.X / d.Width;
- if (AlignRight == EGUIA_SCALE)
- ScaleRect.LowerRightCorner.X = (f32)r.LowerRightCorner.X / d.Width;
- if (AlignTop == EGUIA_SCALE)
- ScaleRect.UpperLeftCorner.Y = (f32)r.UpperLeftCorner.Y / d.Height;
- if (AlignBottom == EGUIA_SCALE)
- ScaleRect.LowerRightCorner.Y = (f32)r.LowerRightCorner.Y / d.Height;
- }
- DesiredRect = r;
- updateAbsolutePosition();
- }
- //! Sets the relative rectangle of this element, maintaining its current width and height
- /** \param position The new relative position to set. Width and height will not be changed. */
- void setRelativePosition(const core::position2di &position)
- {
- const core::dimension2di mySize = RelativeRect.getSize();
- const core::rect<s32> rectangle(position.X, position.Y,
- position.X + mySize.Width, position.Y + mySize.Height);
- setRelativePosition(rectangle);
- }
- //! Sets the relative rectangle of this element as a proportion of its parent's area.
- /** \note This method used to be 'void setRelativePosition(const core::rect<f32>& r)'
- \param r The rectangle to set, interpreted as a proportion of the parent's area.
- Meaningful values are in the range [0...1], unless you intend this element to spill
- outside its parent. */
- void setRelativePositionProportional(const core::rect<f32> &r)
- {
- if (!Parent)
- return;
- const core::dimension2di &d = Parent->getAbsolutePosition().getSize();
- DesiredRect = core::rect<s32>(
- core::floor32((f32)d.Width * r.UpperLeftCorner.X),
- core::floor32((f32)d.Height * r.UpperLeftCorner.Y),
- core::floor32((f32)d.Width * r.LowerRightCorner.X),
- core::floor32((f32)d.Height * r.LowerRightCorner.Y));
- ScaleRect = r;
- updateAbsolutePosition();
- }
- //! Gets the absolute rectangle of this element
- core::rect<s32> getAbsolutePosition() const
- {
- return AbsoluteRect;
- }
- //! Returns the visible area of the element.
- core::rect<s32> getAbsoluteClippingRect() const
- {
- return AbsoluteClippingRect;
- }
- //! Sets whether the element will ignore its parent's clipping rectangle
- /** \param noClip If true, the element will not be clipped by its parent's clipping rectangle. */
- void setNotClipped(bool noClip)
- {
- NoClip = noClip;
- updateAbsolutePosition();
- }
- //! Gets whether the element will ignore its parent's clipping rectangle
- /** \return true if the element is not clipped by its parent's clipping rectangle. */
- bool isNotClipped() const
- {
- return NoClip;
- }
- //! Sets the maximum size allowed for this element
- /** If set to 0,0, there is no maximum size */
- void setMaxSize(core::dimension2du size)
- {
- MaxSize = size;
- updateAbsolutePosition();
- }
- //! Sets the minimum size allowed for this element
- void setMinSize(core::dimension2du size)
- {
- MinSize = size;
- if (MinSize.Width < 1)
- MinSize.Width = 1;
- if (MinSize.Height < 1)
- MinSize.Height = 1;
- updateAbsolutePosition();
- }
- //! The alignment defines how the borders of this element will be positioned when the parent element is resized.
- void setAlignment(EGUI_ALIGNMENT left, EGUI_ALIGNMENT right, EGUI_ALIGNMENT top, EGUI_ALIGNMENT bottom)
- {
- AlignLeft = left;
- AlignRight = right;
- AlignTop = top;
- AlignBottom = bottom;
- if (Parent) {
- core::rect<s32> r(Parent->getAbsolutePosition());
- core::dimension2df d((f32)r.getSize().Width, (f32)r.getSize().Height);
- if (AlignLeft == EGUIA_SCALE)
- ScaleRect.UpperLeftCorner.X = (f32)DesiredRect.UpperLeftCorner.X / d.Width;
- if (AlignRight == EGUIA_SCALE)
- ScaleRect.LowerRightCorner.X = (f32)DesiredRect.LowerRightCorner.X / d.Width;
- if (AlignTop == EGUIA_SCALE)
- ScaleRect.UpperLeftCorner.Y = (f32)DesiredRect.UpperLeftCorner.Y / d.Height;
- if (AlignBottom == EGUIA_SCALE)
- ScaleRect.LowerRightCorner.Y = (f32)DesiredRect.LowerRightCorner.Y / d.Height;
- }
- }
- //! How left element border is aligned when parent is resized
- EGUI_ALIGNMENT getAlignLeft() const
- {
- return AlignLeft;
- }
- //! How right element border is aligned when parent is resized
- EGUI_ALIGNMENT getAlignRight() const
- {
- return AlignRight;
- }
- //! How top element border is aligned when parent is resized
- EGUI_ALIGNMENT getAlignTop() const
- {
- return AlignTop;
- }
- //! How bottom element border is aligned when parent is resized
- EGUI_ALIGNMENT getAlignBottom() const
- {
- return AlignBottom;
- }
- //! Updates the absolute position.
- virtual void updateAbsolutePosition()
- {
- recalculateAbsolutePosition(false);
- // update all children
- for (auto child : Children) {
- child->updateAbsolutePosition();
- }
- }
- //! Returns the topmost GUI element at the specific position.
- /**
- This will check this GUI element and all of its descendants, so it
- may return this GUI element. To check all GUI elements, call this
- function on device->getGUIEnvironment()->getRootGUIElement(). Note
- that the root element is the size of the screen, so doing so (with
- an on-screen point) will always return the root element if no other
- element is above it at that point.
- \param point: The point at which to find a GUI element.
- \return The topmost GUI element at that point, or 0 if there are
- no candidate elements at this point.
- */
- virtual IGUIElement *getElementFromPoint(const core::position2d<s32> &point)
- {
- IGUIElement *target = 0;
- if (isVisible()) {
- // we have to search from back to front, because later children
- // might be drawn over the top of earlier ones.
- auto it = Children.rbegin();
- auto ie = Children.rend();
- while (it != ie) {
- target = (*it)->getElementFromPoint(point);
- if (target)
- return target;
- ++it;
- }
- }
- if (isVisible() && isPointInside(point))
- target = this;
- return target;
- }
- //! Returns true if a point is within this element.
- /** Elements with a shape other than a rectangle should override this method */
- virtual bool isPointInside(const core::position2d<s32> &point) const
- {
- return AbsoluteClippingRect.isPointInside(point);
- }
- //! Adds a GUI element as new child of this element.
- virtual void addChild(IGUIElement *child)
- {
- if (child && child != this) {
- addChildToEnd(child);
- child->updateAbsolutePosition();
- }
- }
- //! Removes a child.
- virtual void removeChild(IGUIElement *child)
- {
- assert(child->Parent == this);
- Children.erase(child->ParentPos);
- child->Parent = nullptr;
- child->drop();
- }
- //! Removes all children.
- virtual void removeAllChildren()
- {
- while (!Children.empty()) {
- auto child = Children.back();
- child->remove();
- }
- }
- //! Removes this element from its parent.
- virtual void remove()
- {
- if (Parent)
- Parent->removeChild(this);
- }
- //! Draws the element and its children.
- virtual void draw()
- {
- if (isVisible()) {
- for (auto child : Children)
- child->draw();
- }
- }
- //! animate the element and its children.
- virtual void OnPostRender(u32 timeMs)
- {
- if (isVisible()) {
- for (auto child : Children)
- child->OnPostRender(timeMs);
- }
- }
- //! Moves this element.
- virtual void move(core::position2d<s32> absoluteMovement)
- {
- setRelativePosition(DesiredRect + absoluteMovement);
- }
- //! Returns true if element is visible.
- virtual bool isVisible() const
- {
- return IsVisible;
- }
- //! Check whether the element is truly visible, taking into accounts its parents' visibility
- /** \return true if the element and all its parents are visible,
- false if this or any parent element is invisible. */
- virtual bool isTrulyVisible() const
- {
- if (!IsVisible)
- return false;
- if (!Parent)
- return true;
- return Parent->isTrulyVisible();
- }
- //! Sets the visible state of this element.
- virtual void setVisible(bool visible)
- {
- IsVisible = visible;
- }
- //! Returns true if this element was created as part of its parent control
- virtual bool isSubElement() const
- {
- return IsSubElement;
- }
- //! Sets whether this control was created as part of its parent.
- /** For example, it is true when a scrollbar is part of a listbox.
- SubElements are not saved to disk when calling guiEnvironment->saveGUI() */
- virtual void setSubElement(bool subElement)
- {
- IsSubElement = subElement;
- }
- //! If set to true, the focus will visit this element when using the tab key to cycle through elements.
- /** If this element is a tab group (see isTabGroup/setTabGroup) then
- ctrl+tab will be used instead. */
- void setTabStop(bool enable)
- {
- IsTabStop = enable;
- }
- //! Returns true if this element can be focused by navigating with the tab key
- bool isTabStop() const
- {
- return IsTabStop;
- }
- //! Sets the priority of focus when using the tab key to navigate between a group of elements.
- /** See setTabGroup, isTabGroup and getTabGroup for information on tab groups.
- Elements with a lower number are focused first */
- void setTabOrder(s32 index)
- {
- // negative = autonumber
- if (index < 0) {
- TabOrder = 0;
- IGUIElement *el = getTabGroup();
- while (IsTabGroup && el && el->Parent)
- el = el->Parent;
- IGUIElement *first = 0, *closest = 0;
- if (el) {
- // find the highest element number
- el->getNextElement(-1, true, IsTabGroup, first, closest, true, true);
- if (first) {
- TabOrder = first->getTabOrder() + 1;
- }
- }
- } else
- TabOrder = index;
- }
- //! Returns the number in the tab order sequence
- s32 getTabOrder() const
- {
- return TabOrder;
- }
- //! Sets whether this element is a container for a group of elements which can be navigated using the tab key.
- /** For example, windows are tab groups.
- Groups can be navigated using ctrl+tab, providing isTabStop is true. */
- void setTabGroup(bool isGroup)
- {
- IsTabGroup = isGroup;
- }
- //! Returns true if this element is a tab group.
- bool isTabGroup() const
- {
- return IsTabGroup;
- }
- //! Returns the container element which holds all elements in this element's tab group.
- IGUIElement *getTabGroup()
- {
- IGUIElement *ret = this;
- while (ret && !ret->isTabGroup())
- ret = ret->getParent();
- return ret;
- }
- //! Returns true if element is enabled
- /** Currently elements do _not_ care about parent-states.
- So if you want to affect children you have to enable/disable them all.
- The only exception to this are sub-elements which also check their parent.
- */
- virtual bool isEnabled() const
- {
- if (isSubElement() && IsEnabled && getParent())
- return getParent()->isEnabled();
- return IsEnabled;
- }
- //! Sets the enabled state of this element.
- virtual void setEnabled(bool enabled)
- {
- IsEnabled = enabled;
- }
- //! Sets the new caption of this element.
- virtual void setText(const wchar_t *text)
- {
- Text = text;
- }
- //! Returns caption of this element.
- virtual const wchar_t *getText() const
- {
- return Text.c_str();
- }
- //! Sets the new caption of this element.
- virtual void setToolTipText(const wchar_t *text)
- {
- ToolTipText = text;
- }
- //! Returns caption of this element.
- virtual const core::stringw &getToolTipText() const
- {
- return ToolTipText;
- }
- //! Returns id. Can be used to identify the element.
- virtual s32 getID() const
- {
- return ID;
- }
- //! Sets the id of this element
- virtual void setID(s32 id)
- {
- ID = id;
- }
- //! Called if an event happened.
- bool OnEvent(const SEvent &event) override
- {
- return Parent ? Parent->OnEvent(event) : false;
- }
- //! Brings a child to front
- /** \return True if successful, false if not. */
- virtual bool bringToFront(IGUIElement *child)
- {
- if (child->Parent != this)
- return false;
- if (std::next(child->ParentPos) == Children.end()) // already there
- return true;
- Children.erase(child->ParentPos);
- child->ParentPos = Children.insert(Children.end(), child);
- return true;
- }
- //! Moves a child to the back, so it's siblings are drawn on top of it
- /** \return True if successful, false if not. */
- virtual bool sendToBack(IGUIElement *child)
- {
- if (child->Parent != this)
- return false;
- if (child->ParentPos == Children.begin()) // already there
- return true;
- Children.erase(child->ParentPos);
- child->ParentPos = Children.insert(Children.begin(), child);
- return true;
- }
- //! Returns list with children of this element
- virtual const std::list<IGUIElement *> &getChildren() const
- {
- return Children;
- }
- //! Finds the first element with the given id.
- /** \param id: Id to search for.
- \param searchchildren: Set this to true, if also children of this
- element may contain the element with the searched id and they
- should be searched too.
- \return Returns the first element with the given id. If no element
- with this id was found, 0 is returned. */
- virtual IGUIElement *getElementFromId(s32 id, bool searchchildren = false) const
- {
- IGUIElement *e = 0;
- for (auto child : Children) {
- if (child->getID() == id)
- return child;
- if (searchchildren)
- e = child->getElementFromId(id, true);
- if (e)
- return e;
- }
- return e;
- }
- //! returns true if the given element is a child of this one.
- //! \param child: The child element to check
- bool isMyChild(IGUIElement *child) const
- {
- if (!child)
- return false;
- do {
- if (child->Parent)
- child = child->Parent;
- } while (child->Parent && child != this);
- return child == this;
- }
- //! searches elements to find the closest next element to tab to
- /** \param startOrder: The TabOrder of the current element, -1 if none
- \param reverse: true if searching for a lower number
- \param group: true if searching for a higher one
- \param first: element with the highest/lowest known tab order depending on search direction
- \param closest: the closest match, depending on tab order and direction
- \param includeInvisible: includes invisible elements in the search (default=false)
- \param includeDisabled: includes disabled elements in the search (default=false)
- \return true if successfully found an element, false to continue searching/fail */
- bool getNextElement(s32 startOrder, bool reverse, bool group,
- IGUIElement *&first, IGUIElement *&closest, bool includeInvisible = false,
- bool includeDisabled = false) const
- {
- // we'll stop searching if we find this number
- s32 wanted = startOrder + (reverse ? -1 : 1);
- if (wanted == -2)
- wanted = 1073741824; // maximum s32
- auto it = Children.begin();
- s32 closestOrder, currentOrder;
- while (it != Children.end()) {
- // ignore invisible elements and their children
- if (((*it)->isVisible() || includeInvisible) &&
- (group == true || (*it)->isTabGroup() == false)) {
- // ignore disabled, but children are checked (disabled is currently per element ignoring parent states)
- if ((*it)->isEnabled() || includeDisabled) {
- // only check tab stops and those with the same group status
- if ((*it)->isTabStop() && ((*it)->isTabGroup() == group)) {
- currentOrder = (*it)->getTabOrder();
- // is this what we're looking for?
- if (currentOrder == wanted) {
- closest = *it;
- return true;
- }
- // is it closer than the current closest?
- if (closest) {
- closestOrder = closest->getTabOrder();
- if ((reverse && currentOrder > closestOrder && currentOrder < startOrder) || (!reverse && currentOrder < closestOrder && currentOrder > startOrder)) {
- closest = *it;
- }
- } else if ((reverse && currentOrder < startOrder) || (!reverse && currentOrder > startOrder)) {
- closest = *it;
- }
- // is it before the current first?
- if (first) {
- closestOrder = first->getTabOrder();
- if ((reverse && closestOrder < currentOrder) || (!reverse && closestOrder > currentOrder)) {
- first = *it;
- }
- } else {
- first = *it;
- }
- }
- }
- // search within children
- if ((*it)->getNextElement(startOrder, reverse, group, first, closest, includeInvisible, includeDisabled)) {
- return true;
- }
- }
- ++it;
- }
- return false;
- }
- //! Returns the type of the gui element.
- /** This is needed for the .NET wrapper but will be used
- later for serializing and deserializing.
- If you wrote your own GUIElements, you need to set the type for your element as first parameter
- in the constructor of IGUIElement. For own (=unknown) elements, simply use EGUIET_ELEMENT as type */
- EGUI_ELEMENT_TYPE getType() const
- {
- 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 member variable
- 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.
- /** This is needed serializing elements. */
- virtual const c8 *getTypeName() const
- {
- return GUIElementTypeNames[Type];
- }
- //! Returns the name of the element.
- /** \return Name as character string. */
- virtual const c8 *getName() const
- {
- return Name.c_str();
- }
- //! Sets the name of the element.
- /** \param name New name of the gui element. */
- virtual void setName(const c8 *name)
- {
- Name = name;
- }
- //! Sets the name of the element.
- /** \param name New name of the gui element. */
- virtual void setName(const core::stringc &name)
- {
- Name = name;
- }
- //! Returns whether the element takes input from the IME
- virtual bool acceptsIME()
- {
- return false;
- }
- protected:
- // not virtual because needed in constructor
- void addChildToEnd(IGUIElement *child)
- {
- if (child) {
- child->grab(); // prevent destruction when removed
- child->remove(); // remove from old parent
- child->LastParentRect = getAbsolutePosition();
- child->Parent = this;
- child->ParentPos = Children.insert(Children.end(), child);
- }
- }
- #ifndef NDEBUG
- template <typename Iterator>
- static size_t _fastSetChecksum(Iterator begin, Iterator end)
- {
- std::hash<typename Iterator::value_type> hasher;
- size_t checksum = 0;
- for (Iterator it = begin; it != end; ++it) {
- size_t h = hasher(*it);
- checksum ^= 966073049 + (h * 3432918353) + ((h >> 16) * 461845907);
- }
- return checksum;
- }
- #endif
- // Reorder children [from, to) to the order given by `neworder`
- void reorderChildren(
- std::list<IGUIElement *>::iterator from,
- std::list<IGUIElement *>::iterator to,
- const std::vector<IGUIElement *> &neworder)
- {
- assert(_fastSetChecksum(from, to) == _fastSetChecksum(neworder.begin(), neworder.end()));
- for (auto e : neworder) {
- *from = e;
- e->ParentPos = from;
- ++from;
- }
- assert(from == to);
- }
- // not virtual because needed in constructor
- void recalculateAbsolutePosition(bool recursive)
- {
- core::rect<s32> parentAbsolute(0, 0, 0, 0);
- core::rect<s32> parentAbsoluteClip;
- f32 fw = 0.f, fh = 0.f;
- if (Parent) {
- parentAbsolute = Parent->AbsoluteRect;
- if (NoClip) {
- IGUIElement *p = this;
- while (p->Parent)
- p = p->Parent;
- parentAbsoluteClip = p->AbsoluteClippingRect;
- } else
- parentAbsoluteClip = Parent->AbsoluteClippingRect;
- }
- const s32 diffx = parentAbsolute.getWidth() - LastParentRect.getWidth();
- const s32 diffy = parentAbsolute.getHeight() - LastParentRect.getHeight();
- if (AlignLeft == EGUIA_SCALE || AlignRight == EGUIA_SCALE)
- fw = (f32)parentAbsolute.getWidth();
- if (AlignTop == EGUIA_SCALE || AlignBottom == EGUIA_SCALE)
- fh = (f32)parentAbsolute.getHeight();
- switch (AlignLeft) {
- case EGUIA_UPPERLEFT:
- break;
- case EGUIA_LOWERRIGHT:
- DesiredRect.UpperLeftCorner.X += diffx;
- break;
- case EGUIA_CENTER:
- DesiredRect.UpperLeftCorner.X += diffx / 2;
- break;
- case EGUIA_SCALE:
- DesiredRect.UpperLeftCorner.X = core::round32(ScaleRect.UpperLeftCorner.X * fw);
- break;
- }
- switch (AlignRight) {
- case EGUIA_UPPERLEFT:
- break;
- case EGUIA_LOWERRIGHT:
- DesiredRect.LowerRightCorner.X += diffx;
- break;
- case EGUIA_CENTER:
- DesiredRect.LowerRightCorner.X += diffx / 2;
- break;
- case EGUIA_SCALE:
- DesiredRect.LowerRightCorner.X = core::round32(ScaleRect.LowerRightCorner.X * fw);
- break;
- }
- switch (AlignTop) {
- case EGUIA_UPPERLEFT:
- break;
- case EGUIA_LOWERRIGHT:
- DesiredRect.UpperLeftCorner.Y += diffy;
- break;
- case EGUIA_CENTER:
- DesiredRect.UpperLeftCorner.Y += diffy / 2;
- break;
- case EGUIA_SCALE:
- DesiredRect.UpperLeftCorner.Y = core::round32(ScaleRect.UpperLeftCorner.Y * fh);
- break;
- }
- switch (AlignBottom) {
- case EGUIA_UPPERLEFT:
- break;
- case EGUIA_LOWERRIGHT:
- DesiredRect.LowerRightCorner.Y += diffy;
- break;
- case EGUIA_CENTER:
- DesiredRect.LowerRightCorner.Y += diffy / 2;
- break;
- case EGUIA_SCALE:
- DesiredRect.LowerRightCorner.Y = core::round32(ScaleRect.LowerRightCorner.Y * fh);
- break;
- }
- RelativeRect = DesiredRect;
- const s32 w = RelativeRect.getWidth();
- const s32 h = RelativeRect.getHeight();
- // make sure the desired rectangle is allowed
- if (w < (s32)MinSize.Width)
- RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MinSize.Width;
- if (h < (s32)MinSize.Height)
- RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MinSize.Height;
- if (MaxSize.Width && w > (s32)MaxSize.Width)
- RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MaxSize.Width;
- if (MaxSize.Height && h > (s32)MaxSize.Height)
- RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MaxSize.Height;
- RelativeRect.repair();
- AbsoluteRect = RelativeRect + parentAbsolute.UpperLeftCorner;
- if (!Parent)
- parentAbsoluteClip = AbsoluteRect;
- AbsoluteClippingRect = AbsoluteRect;
- AbsoluteClippingRect.clipAgainst(parentAbsoluteClip);
- LastParentRect = parentAbsolute;
- if (recursive) {
- // update all children
- for (auto child : Children) {
- child->recalculateAbsolutePosition(recursive);
- }
- }
- }
- protected:
- //! List of all children of this element
- std::list<IGUIElement *> Children;
- //! Pointer to the parent
- IGUIElement *Parent;
- //! Our position in the parent list. Only valid when Parent != nullptr
- std::list<IGUIElement *>::iterator ParentPos;
- //! relative rect of element
- core::rect<s32> RelativeRect;
- //! absolute rect of element
- core::rect<s32> AbsoluteRect;
- //! absolute clipping rect of element
- core::rect<s32> AbsoluteClippingRect;
- //! the rectangle the element would prefer to be,
- //! if it was not constrained by parent or max/min size
- core::rect<s32> DesiredRect;
- //! for calculating the difference when resizing parent
- core::rect<s32> LastParentRect;
- //! relative scale of the element inside its parent
- core::rect<f32> ScaleRect;
- //! maximum and minimum size of the element
- core::dimension2du MaxSize, MinSize;
- //! is visible?
- bool IsVisible;
- //! is enabled?
- bool IsEnabled;
- //! is a part of a larger whole and should not be serialized?
- bool IsSubElement;
- //! does this element ignore its parent's clipping rectangle?
- bool NoClip;
- //! caption
- core::stringw Text;
- //! tooltip
- core::stringw ToolTipText;
- //! users can set this for identifying the element by string
- core::stringc Name;
- //! users can set this for identifying the element by integer
- s32 ID;
- //! tab stop like in windows
- bool IsTabStop;
- //! tab order
- s32 TabOrder;
- //! tab groups are containers like windows, use ctrl+tab to navigate
- bool IsTabGroup;
- //! tells the element how to act when its parent is resized
- EGUI_ALIGNMENT AlignLeft, AlignRight, AlignTop, AlignBottom;
- //! GUI Environment
- IGUIEnvironment *Environment;
- //! type of element
- EGUI_ELEMENT_TYPE Type;
- };
- } // end namespace gui
- } // end namespace irr
|