]> git.lizzy.rs Git - irrlicht.git/blob - include/IGUIElement.h
Fix COSOperator::getSystemMemory
[irrlicht.git] / include / IGUIElement.h
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
4 \r
5 #ifndef __I_GUI_ELEMENT_H_INCLUDED__\r
6 #define __I_GUI_ELEMENT_H_INCLUDED__\r
7 \r
8 #include "IReferenceCounted.h"\r
9 #include "irrList.h"\r
10 #include "rect.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
17 \r
18 namespace irr\r
19 {\r
20 namespace gui\r
21 {\r
22 //! Base class of all GUI elements.\r
23 class IGUIElement : virtual public IReferenceCounted, public IEventReceiver\r
24 {\r
25 public:\r
26 \r
27         //! Constructor\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
36         {\r
37                 #ifdef _DEBUG\r
38                 setDebugName("IGUIElement");\r
39                 #endif\r
40 \r
41                 // if we were given a parent to attach to\r
42                 if (parent)\r
43                 {\r
44                         parent->addChildToEnd(this);\r
45                         recalculateAbsolutePosition(true);\r
46                 }\r
47         }\r
48 \r
49 \r
50         //! Destructor\r
51         virtual ~IGUIElement()\r
52         {\r
53                 // delete all children\r
54                 core::list<IGUIElement*>::Iterator it = Children.begin();\r
55                 for (; it != Children.end(); ++it)\r
56                 {\r
57                         (*it)->Parent = 0;\r
58                         (*it)->drop();\r
59                 }\r
60         }\r
61 \r
62 \r
63         //! Returns parent of this element.\r
64         IGUIElement* getParent() const\r
65         {\r
66                 return Parent;\r
67         }\r
68 \r
69         //! Returns the relative rectangle of this element.\r
70         core::rect<s32> getRelativePosition() const\r
71         {\r
72                 return RelativeRect;\r
73         }\r
74 \r
75 \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
79         {\r
80                 if (Parent)\r
81                 {\r
82                         const core::rect<s32>& r2 = Parent->getAbsolutePosition();\r
83 \r
84                         core::dimension2df d((f32)(r2.getSize().Width), (f32)(r2.getSize().Height));\r
85 \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
94                 }\r
95 \r
96                 DesiredRect = r;\r
97                 updateAbsolutePosition();\r
98         }\r
99 \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
103         {\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
108         }\r
109 \r
110 \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
117         {\r
118                 if (!Parent)\r
119                         return;\r
120 \r
121                 const core::dimension2di& d = Parent->getAbsolutePosition().getSize();\r
122 \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
128 \r
129                 ScaleRect = r;\r
130 \r
131                 updateAbsolutePosition();\r
132         }\r
133 \r
134 \r
135         //! Gets the absolute rectangle of this element\r
136         core::rect<s32> getAbsolutePosition() const\r
137         {\r
138                 return AbsoluteRect;\r
139         }\r
140 \r
141 \r
142         //! Returns the visible area of the element.\r
143         core::rect<s32> getAbsoluteClippingRect() const\r
144         {\r
145                 return AbsoluteClippingRect;\r
146         }\r
147 \r
148 \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
152         {\r
153                 NoClip = noClip;\r
154                 updateAbsolutePosition();\r
155         }\r
156 \r
157 \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
161         {\r
162                 return NoClip;\r
163         }\r
164 \r
165 \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
169         {\r
170                 MaxSize = size;\r
171                 updateAbsolutePosition();\r
172         }\r
173 \r
174 \r
175         //! Sets the minimum size allowed for this element\r
176         void setMinSize(core::dimension2du size)\r
177         {\r
178                 MinSize = size;\r
179                 if (MinSize.Width < 1)\r
180                         MinSize.Width = 1;\r
181                 if (MinSize.Height < 1)\r
182                         MinSize.Height = 1;\r
183                 updateAbsolutePosition();\r
184         }\r
185 \r
186 \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
189         {\r
190                 AlignLeft = left;\r
191                 AlignRight = right;\r
192                 AlignTop = top;\r
193                 AlignBottom = bottom;\r
194 \r
195                 if (Parent)\r
196                 {\r
197                         core::rect<s32> r(Parent->getAbsolutePosition());\r
198 \r
199                         core::dimension2df d((f32)r.getSize().Width, (f32)r.getSize().Height);\r
200 \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
209                 }\r
210         }\r
211 \r
212         //! How left element border is aligned when parent is resized\r
213         EGUI_ALIGNMENT getAlignLeft() const\r
214         {\r
215                 return AlignLeft;\r
216         }\r
217 \r
218         //! How right element border is aligned when parent is resized\r
219         EGUI_ALIGNMENT getAlignRight() const\r
220         {\r
221                 return AlignRight;\r
222         }\r
223 \r
224         //! How top element border is aligned when parent is resized\r
225         EGUI_ALIGNMENT getAlignTop() const\r
226         {\r
227                 return AlignTop;\r
228         }\r
229 \r
230         //! How bottom element border is aligned when parent is resized\r
231         EGUI_ALIGNMENT getAlignBottom() const\r
232         {\r
233                 return AlignBottom;\r
234         }\r
235 \r
236         //! Updates the absolute position.\r
237         virtual void updateAbsolutePosition()\r
238         {\r
239                 recalculateAbsolutePosition(false);\r
240 \r
241                 // update all children\r
242                 core::list<IGUIElement*>::Iterator it = Children.begin();\r
243                 for (; it != Children.end(); ++it)\r
244                 {\r
245                         (*it)->updateAbsolutePosition();\r
246                 }\r
247         }\r
248 \r
249 \r
250         //! Returns the topmost GUI element at the specific position.\r
251         /**\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
261         */\r
262         virtual IGUIElement* getElementFromPoint(const core::position2d<s32>& point)\r
263         {\r
264                 IGUIElement* target = 0;\r
265 \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
268 \r
269                 core::list<IGUIElement*>::ConstIterator it = Children.getLast();\r
270 \r
271                 if (isVisible())\r
272                 {\r
273                         while(it != Children.end())\r
274                         {\r
275                                 target = (*it)->getElementFromPoint(point);\r
276                                 if (target)\r
277                                         return target;\r
278 \r
279                                 --it;\r
280                         }\r
281                 }\r
282 \r
283                 if (isVisible() && isPointInside(point))\r
284                         target = this;\r
285 \r
286                 return target;\r
287         }\r
288 \r
289 \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
293         {\r
294                 return AbsoluteClippingRect.isPointInside(point);\r
295         }\r
296 \r
297 \r
298         //! Adds a GUI element as new child of this element.\r
299         virtual void addChild(IGUIElement* child)\r
300         {\r
301                 if ( child && child != this )\r
302                 {\r
303                         addChildToEnd(child);\r
304                         child->updateAbsolutePosition();\r
305                 }\r
306         }\r
307 \r
308         //! Removes a child.\r
309         virtual void removeChild(IGUIElement* child)\r
310         {\r
311                 core::list<IGUIElement*>::Iterator it = Children.begin();\r
312                 for (; it != Children.end(); ++it)\r
313                         if ((*it) == child)\r
314                         {\r
315                                 (*it)->Parent = 0;\r
316                                 (*it)->drop();\r
317                                 Children.erase(it);\r
318                                 return;\r
319                         }\r
320         }\r
321 \r
322 \r
323         //! Removes this element from its parent.\r
324         virtual void remove()\r
325         {\r
326                 if (Parent)\r
327                         Parent->removeChild(this);\r
328         }\r
329 \r
330 \r
331         //! Draws the element and its children.\r
332         virtual void draw()\r
333         {\r
334                 if ( isVisible() )\r
335                 {\r
336                         core::list<IGUIElement*>::Iterator it = Children.begin();\r
337                         for (; it != Children.end(); ++it)\r
338                                 (*it)->draw();\r
339                 }\r
340         }\r
341 \r
342 \r
343         //! animate the element and its children.\r
344         virtual void OnPostRender(u32 timeMs)\r
345         {\r
346                 if ( isVisible() )\r
347                 {\r
348                         core::list<IGUIElement*>::Iterator it = Children.begin();\r
349                         for (; it != Children.end(); ++it)\r
350                                 (*it)->OnPostRender( timeMs );\r
351                 }\r
352         }\r
353 \r
354 \r
355         //! Moves this element.\r
356         virtual void move(core::position2d<s32> absoluteMovement)\r
357         {\r
358                 setRelativePosition(DesiredRect + absoluteMovement);\r
359         }\r
360 \r
361 \r
362         //! Returns true if element is visible.\r
363         virtual bool isVisible() const\r
364         {\r
365                 return IsVisible;\r
366         }\r
367 \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
372         {\r
373                 if(!IsVisible)\r
374                         return false;\r
375 \r
376                 if(!Parent)\r
377                         return true;\r
378 \r
379                 return Parent->isTrulyVisible();\r
380         }\r
381 \r
382         //! Sets the visible state of this element.\r
383         virtual void setVisible(bool visible)\r
384         {\r
385                 IsVisible = visible;\r
386         }\r
387 \r
388 \r
389         //! Returns true if this element was created as part of its parent control\r
390         virtual bool isSubElement() const\r
391         {\r
392                 return IsSubElement;\r
393         }\r
394 \r
395 \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
400         {\r
401                 IsSubElement = subElement;\r
402         }\r
403 \r
404 \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
409         {\r
410                 IsTabStop = enable;\r
411         }\r
412 \r
413 \r
414         //! Returns true if this element can be focused by navigating with the tab key\r
415         bool isTabStop() const\r
416         {\r
417                 return IsTabStop;\r
418         }\r
419 \r
420 \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
425         {\r
426                 // negative = autonumber\r
427                 if (index < 0)\r
428                 {\r
429                         TabOrder = 0;\r
430                         IGUIElement *el = getTabGroup();\r
431                         while (IsTabGroup && el && el->Parent)\r
432                                 el = el->Parent;\r
433 \r
434                         IGUIElement *first=0, *closest=0;\r
435                         if (el)\r
436                         {\r
437                                 // find the highest element number\r
438                                 el->getNextElement(-1, true, IsTabGroup, first, closest, true);\r
439                                 if (first)\r
440                                 {\r
441                                         TabOrder = first->getTabOrder() + 1;\r
442                                 }\r
443                         }\r
444 \r
445                 }\r
446                 else\r
447                         TabOrder = index;\r
448         }\r
449 \r
450 \r
451         //! Returns the number in the tab order sequence\r
452         s32 getTabOrder() const\r
453         {\r
454                 return TabOrder;\r
455         }\r
456 \r
457 \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
462         {\r
463                 IsTabGroup = isGroup;\r
464         }\r
465 \r
466 \r
467         //! Returns true if this element is a tab group.\r
468         bool isTabGroup() const\r
469         {\r
470                 return IsTabGroup;\r
471         }\r
472 \r
473 \r
474         //! Returns the container element which holds all elements in this element's tab group.\r
475         IGUIElement* getTabGroup()\r
476         {\r
477                 IGUIElement *ret=this;\r
478 \r
479                 while (ret && !ret->isTabGroup())\r
480                         ret = ret->getParent();\r
481 \r
482                 return ret;\r
483         }\r
484 \r
485 \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
490         */\r
491         virtual bool isEnabled() const\r
492         {\r
493                 if ( isSubElement() && IsEnabled && getParent() )\r
494                         return getParent()->isEnabled();\r
495 \r
496                 return IsEnabled;\r
497         }\r
498 \r
499 \r
500         //! Sets the enabled state of this element.\r
501         virtual void setEnabled(bool enabled)\r
502         {\r
503                 IsEnabled = enabled;\r
504         }\r
505 \r
506 \r
507         //! Sets the new caption of this element.\r
508         virtual void setText(const wchar_t* text)\r
509         {\r
510                 Text = text;\r
511         }\r
512 \r
513 \r
514         //! Returns caption of this element.\r
515         virtual const wchar_t* getText() const\r
516         {\r
517                 return Text.c_str();\r
518         }\r
519 \r
520 \r
521         //! Sets the new caption of this element.\r
522         virtual void setToolTipText(const wchar_t* text)\r
523         {\r
524                 ToolTipText = text;\r
525         }\r
526 \r
527 \r
528         //! Returns caption of this element.\r
529         virtual const core::stringw& getToolTipText() const\r
530         {\r
531                 return ToolTipText;\r
532         }\r
533 \r
534 \r
535         //! Returns id. Can be used to identify the element.\r
536         virtual s32 getID() const\r
537         {\r
538                 return ID;\r
539         }\r
540 \r
541 \r
542         //! Sets the id of this element\r
543         virtual void setID(s32 id)\r
544         {\r
545                 ID = id;\r
546         }\r
547 \r
548 \r
549         //! Called if an event happened.\r
550         virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_\r
551         {\r
552                 return Parent ? Parent->OnEvent(event) : false;\r
553         }\r
554 \r
555 \r
556         //! Brings a child to front\r
557         /** \return True if successful, false if not. */\r
558         virtual bool bringToFront(IGUIElement* element)\r
559         {\r
560                 core::list<IGUIElement*>::Iterator it = Children.begin();\r
561                 for (; it != Children.end(); ++it)\r
562                 {\r
563                         if (element == (*it))\r
564                         {\r
565                                 Children.erase(it);\r
566                                 Children.push_back(element);\r
567                                 return true;\r
568                         }\r
569                 }\r
570 \r
571                 return false;\r
572         }\r
573 \r
574 \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
578         {\r
579                 core::list<IGUIElement*>::Iterator it = Children.begin();\r
580                 if (child == (*it)) // already there\r
581                         return true;\r
582                 for (; it != Children.end(); ++it)\r
583                 {\r
584                         if (child == (*it))\r
585                         {\r
586                                 Children.erase(it);\r
587                                 Children.push_front(child);\r
588                                 return true;\r
589                         }\r
590                 }\r
591 \r
592                 return false;\r
593         }\r
594 \r
595         //! Returns list with children of this element\r
596         virtual const core::list<IGUIElement*>& getChildren() const\r
597         {\r
598                 return Children;\r
599         }\r
600 \r
601 \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
610         {\r
611                 IGUIElement* e = 0;\r
612 \r
613                 core::list<IGUIElement*>::ConstIterator it = Children.begin();\r
614                 for (; it != Children.end(); ++it)\r
615                 {\r
616                         if ((*it)->getID() == id)\r
617                                 return (*it);\r
618 \r
619                         if (searchchildren)\r
620                                 e = (*it)->getElementFromId(id, true);\r
621 \r
622                         if (e)\r
623                                 return e;\r
624                 }\r
625 \r
626                 return e;\r
627         }\r
628 \r
629 \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
633         {\r
634                 if (!child)\r
635                         return false;\r
636                 do\r
637                 {\r
638                         if (child->Parent)\r
639                                 child = child->Parent;\r
640 \r
641                 } while (child->Parent && child != this);\r
642 \r
643 \r
644                 return child == this;\r
645         }\r
646 \r
647 \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
660         {\r
661                 // we'll stop searching if we find this number\r
662                 s32 wanted = startOrder + ( reverse ? -1 : 1 );\r
663                 if (wanted==-2)\r
664                         wanted = 1073741824; // maximum s32\r
665 \r
666                 core::list<IGUIElement*>::ConstIterator it = Children.begin();\r
667 \r
668                 s32 closestOrder, currentOrder;\r
669 \r
670                 while(it != Children.end())\r
671                 {\r
672                         // ignore invisible elements and their children\r
673                         if ( ( (*it)->isVisible() || includeInvisible ) &&\r
674                                 (group == true || (*it)->isTabGroup() == false) )\r
675                         {\r
676                                 // ignore disabled, but children are checked (disabled is currently per element ignoring parent states)\r
677                                 if ( (*it)->isEnabled() || includeDisabled )\r
678                                 {\r
679                                         // only check tab stops and those with the same group status\r
680                                         if ((*it)->isTabStop() && ((*it)->isTabGroup() == group))\r
681                                         {\r
682                                                 currentOrder = (*it)->getTabOrder();\r
683 \r
684                                                 // is this what we're looking for?\r
685                                                 if (currentOrder == wanted)\r
686                                                 {\r
687                                                         closest = *it;\r
688                                                         return true;\r
689                                                 }\r
690 \r
691                                                 // is it closer than the current closest?\r
692                                                 if (closest)\r
693                                                 {\r
694                                                         closestOrder = closest->getTabOrder();\r
695                                                         if ( ( reverse && currentOrder > closestOrder && currentOrder < startOrder)\r
696                                                                 ||(!reverse && currentOrder < closestOrder && currentOrder > startOrder))\r
697                                                         {\r
698                                                                 closest = *it;\r
699                                                         }\r
700                                                 }\r
701                                                 else\r
702                                                 if ( (reverse && currentOrder < startOrder) || (!reverse && currentOrder > startOrder) )\r
703                                                 {\r
704                                                         closest = *it;\r
705                                                 }\r
706 \r
707                                                 // is it before the current first?\r
708                                                 if (first)\r
709                                                 {\r
710                                                         closestOrder = first->getTabOrder();\r
711 \r
712                                                         if ( (reverse && closestOrder < currentOrder) || (!reverse && closestOrder > currentOrder) )\r
713                                                         {\r
714                                                                 first = *it;\r
715                                                         }\r
716                                                 }\r
717                                                 else\r
718                                                 {\r
719                                                         first = *it;\r
720                                                 }\r
721                                         }\r
722                                 }\r
723                                 // search within children\r
724                                 if ((*it)->getNextElement(startOrder, reverse, group, first, closest))\r
725                                 {\r
726                                         return true;\r
727                                 }\r
728                         }\r
729                         ++it;\r
730                 }\r
731                 return false;\r
732         }\r
733 \r
734 \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
741         {\r
742                 return Type;\r
743         }\r
744 \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
753         */\r
754         virtual bool hasType(EGUI_ELEMENT_TYPE type) const\r
755         {\r
756                 return type == Type;\r
757         }\r
758 \r
759 \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
764         {\r
765                 return GUIElementTypeNames[Type];\r
766         }\r
767 \r
768         //! Returns the name of the element.\r
769         /** \return Name as character string. */\r
770         virtual const c8* getName() const\r
771         {\r
772                 return Name.c_str();\r
773         }\r
774 \r
775 \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
779         {\r
780                 Name = name;\r
781         }\r
782 \r
783 \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
787         {\r
788                 Name = name;\r
789         }\r
790 \r
791 \r
792         //! Returns whether the element takes input from the IME\r
793         virtual bool acceptsIME()\r
794         {\r
795                 return false;\r
796         }\r
797 \r
798 \r
799 protected:\r
800         // not virtual because needed in constructor\r
801         void addChildToEnd(IGUIElement* child)\r
802         {\r
803                 if (child)\r
804                 {\r
805                         child->grab(); // prevent destruction when removed\r
806                         child->remove(); // remove from old parent\r
807                         child->LastParentRect = getAbsolutePosition();\r
808                         child->Parent = this;\r
809                         Children.push_back(child);\r
810                 }\r
811         }\r
812 \r
813         // not virtual because needed in constructor\r
814         void recalculateAbsolutePosition(bool recursive)\r
815         {\r
816                 core::rect<s32> parentAbsolute(0,0,0,0);\r
817                 core::rect<s32> parentAbsoluteClip;\r
818                 f32 fw=0.f, fh=0.f;\r
819 \r
820                 if (Parent)\r
821                 {\r
822                         parentAbsolute = Parent->AbsoluteRect;\r
823 \r
824                         if (NoClip)\r
825                         {\r
826                                 IGUIElement* p=this;\r
827                                 while (p->Parent)\r
828                                         p = p->Parent;\r
829                                 parentAbsoluteClip = p->AbsoluteClippingRect;\r
830                         }\r
831                         else\r
832                                 parentAbsoluteClip = Parent->AbsoluteClippingRect;\r
833                 }\r
834 \r
835                 const s32 diffx = parentAbsolute.getWidth() - LastParentRect.getWidth();\r
836                 const s32 diffy = parentAbsolute.getHeight() - LastParentRect.getHeight();\r
837 \r
838                 if (AlignLeft == EGUIA_SCALE || AlignRight == EGUIA_SCALE)\r
839                         fw = (f32)parentAbsolute.getWidth();\r
840 \r
841                 if (AlignTop == EGUIA_SCALE || AlignBottom == EGUIA_SCALE)\r
842                         fh = (f32)parentAbsolute.getHeight();\r
843 \r
844                 switch (AlignLeft)\r
845                 {\r
846                         case EGUIA_UPPERLEFT:\r
847                                 break;\r
848                         case EGUIA_LOWERRIGHT:\r
849                                 DesiredRect.UpperLeftCorner.X += diffx;\r
850                                 break;\r
851                         case EGUIA_CENTER:\r
852                                 DesiredRect.UpperLeftCorner.X += diffx/2;\r
853                                 break;\r
854                         case EGUIA_SCALE:\r
855                                 DesiredRect.UpperLeftCorner.X = core::round32(ScaleRect.UpperLeftCorner.X * fw);\r
856                                 break;\r
857                 }\r
858 \r
859                 switch (AlignRight)\r
860                 {\r
861                         case EGUIA_UPPERLEFT:\r
862                                 break;\r
863                         case EGUIA_LOWERRIGHT:\r
864                                 DesiredRect.LowerRightCorner.X += diffx;\r
865                                 break;\r
866                         case EGUIA_CENTER:\r
867                                 DesiredRect.LowerRightCorner.X += diffx/2;\r
868                                 break;\r
869                         case EGUIA_SCALE:\r
870                                 DesiredRect.LowerRightCorner.X = core::round32(ScaleRect.LowerRightCorner.X * fw);\r
871                                 break;\r
872                 }\r
873 \r
874                 switch (AlignTop)\r
875                 {\r
876                         case EGUIA_UPPERLEFT:\r
877                                 break;\r
878                         case EGUIA_LOWERRIGHT:\r
879                                 DesiredRect.UpperLeftCorner.Y += diffy;\r
880                                 break;\r
881                         case EGUIA_CENTER:\r
882                                 DesiredRect.UpperLeftCorner.Y += diffy/2;\r
883                                 break;\r
884                         case EGUIA_SCALE:\r
885                                 DesiredRect.UpperLeftCorner.Y = core::round32(ScaleRect.UpperLeftCorner.Y * fh);\r
886                                 break;\r
887                 }\r
888 \r
889                 switch (AlignBottom)\r
890                 {\r
891                         case EGUIA_UPPERLEFT:\r
892                                 break;\r
893                         case EGUIA_LOWERRIGHT:\r
894                                 DesiredRect.LowerRightCorner.Y += diffy;\r
895                                 break;\r
896                         case EGUIA_CENTER:\r
897                                 DesiredRect.LowerRightCorner.Y += diffy/2;\r
898                                 break;\r
899                         case EGUIA_SCALE:\r
900                                 DesiredRect.LowerRightCorner.Y = core::round32(ScaleRect.LowerRightCorner.Y * fh);\r
901                                 break;\r
902                 }\r
903 \r
904                 RelativeRect = DesiredRect;\r
905 \r
906                 const s32 w = RelativeRect.getWidth();\r
907                 const s32 h = RelativeRect.getHeight();\r
908 \r
909                 // make sure the desired rectangle is allowed\r
910                 if (w < (s32)MinSize.Width)\r
911                         RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MinSize.Width;\r
912                 if (h < (s32)MinSize.Height)\r
913                         RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MinSize.Height;\r
914                 if (MaxSize.Width && w > (s32)MaxSize.Width)\r
915                         RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MaxSize.Width;\r
916                 if (MaxSize.Height && h > (s32)MaxSize.Height)\r
917                         RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MaxSize.Height;\r
918 \r
919                 RelativeRect.repair();\r
920 \r
921                 AbsoluteRect = RelativeRect + parentAbsolute.UpperLeftCorner;\r
922 \r
923                 if (!Parent)\r
924                         parentAbsoluteClip = AbsoluteRect;\r
925 \r
926                 AbsoluteClippingRect = AbsoluteRect;\r
927                 AbsoluteClippingRect.clipAgainst(parentAbsoluteClip);\r
928 \r
929                 LastParentRect = parentAbsolute;\r
930 \r
931                 if ( recursive )\r
932                 {\r
933                         // update all children\r
934                         core::list<IGUIElement*>::Iterator it = Children.begin();\r
935                         for (; it != Children.end(); ++it)\r
936                         {\r
937                                 (*it)->recalculateAbsolutePosition(recursive);\r
938                         }\r
939                 }\r
940         }\r
941 \r
942 protected:\r
943 \r
944         //! List of all children of this element\r
945         core::list<IGUIElement*> Children;\r
946 \r
947         //! Pointer to the parent\r
948         IGUIElement* Parent;\r
949 \r
950         //! relative rect of element\r
951         core::rect<s32> RelativeRect;\r
952 \r
953         //! absolute rect of element\r
954         core::rect<s32> AbsoluteRect;\r
955 \r
956         //! absolute clipping rect of element\r
957         core::rect<s32> AbsoluteClippingRect;\r
958 \r
959         //! the rectangle the element would prefer to be,\r
960         //! if it was not constrained by parent or max/min size\r
961         core::rect<s32> DesiredRect;\r
962 \r
963         //! for calculating the difference when resizing parent\r
964         core::rect<s32> LastParentRect;\r
965 \r
966         //! relative scale of the element inside its parent\r
967         core::rect<f32> ScaleRect;\r
968 \r
969         //! maximum and minimum size of the element\r
970         core::dimension2du MaxSize, MinSize;\r
971 \r
972         //! is visible?\r
973         bool IsVisible;\r
974 \r
975         //! is enabled?\r
976         bool IsEnabled;\r
977 \r
978         //! is a part of a larger whole and should not be serialized?\r
979         bool IsSubElement;\r
980 \r
981         //! does this element ignore its parent's clipping rectangle?\r
982         bool NoClip;\r
983 \r
984         //! caption\r
985         core::stringw Text;\r
986 \r
987         //! tooltip\r
988         core::stringw ToolTipText;\r
989 \r
990         //! users can set this for identifying the element by string\r
991         core::stringc Name;\r
992 \r
993         //! users can set this for identifying the element by integer\r
994         s32 ID;\r
995 \r
996         //! tab stop like in windows\r
997         bool IsTabStop;\r
998 \r
999         //! tab order\r
1000         s32 TabOrder;\r
1001 \r
1002         //! tab groups are containers like windows, use ctrl+tab to navigate\r
1003         bool IsTabGroup;\r
1004 \r
1005         //! tells the element how to act when its parent is resized\r
1006         EGUI_ALIGNMENT AlignLeft, AlignRight, AlignTop, AlignBottom;\r
1007 \r
1008         //! GUI Environment\r
1009         IGUIEnvironment* Environment;\r
1010 \r
1011         //! type of element\r
1012         EGUI_ELEMENT_TYPE Type;\r
1013 };\r
1014 \r
1015 \r
1016 } // end namespace gui\r
1017 } // end namespace irr\r
1018 \r
1019 #endif\r
1020 \r