]> git.lizzy.rs Git - irrlicht.git/blob - include/IGUIElement.h
5968430ab95b4384e1953c4042986d1336673f71
[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 "IAttributeExchangingObject.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 : public virtual io::IAttributeExchangingObject, 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         //! Writes attributes of the scene node.\r
793         /** Implement this to expose the attributes of your scene node for\r
794         scripting languages, editors, debuggers or xml serialization purposes. */\r
795         virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_\r
796         {\r
797                 out->addString("Name", Name.c_str());\r
798                 out->addInt("Id", ID );\r
799                 out->addString("Caption", getText());\r
800                 out->addString("ToolTip", getToolTipText().c_str());\r
801                 out->addRect("Rect", DesiredRect);\r
802                 out->addPosition2d("MinSize", core::position2di(MinSize.Width, MinSize.Height));\r
803                 out->addPosition2d("MaxSize", core::position2di(MaxSize.Width, MaxSize.Height));\r
804                 out->addEnum("LeftAlign", AlignLeft, GUIAlignmentNames);\r
805                 out->addEnum("RightAlign", AlignRight, GUIAlignmentNames);\r
806                 out->addEnum("TopAlign", AlignTop, GUIAlignmentNames);\r
807                 out->addEnum("BottomAlign", AlignBottom, GUIAlignmentNames);\r
808                 out->addBool("Visible", IsVisible);\r
809                 out->addBool("Enabled", IsEnabled);\r
810                 out->addBool("TabStop", IsTabStop);\r
811                 out->addBool("TabGroup", IsTabGroup);\r
812                 out->addInt("TabOrder", TabOrder);\r
813                 out->addBool("NoClip", NoClip);\r
814         }\r
815 \r
816 \r
817         //! Reads attributes of the scene node.\r
818         /** Implement this to set the attributes of your scene node for\r
819         scripting languages, editors, debuggers or xml deserialization purposes. */\r
820         virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_\r
821         {\r
822                 setName(in->getAttributeAsString("Name", Name));\r
823                 setID(in->getAttributeAsInt("Id", ID));\r
824                 setText(in->getAttributeAsStringW("Caption", Text).c_str());\r
825                 setToolTipText(in->getAttributeAsStringW("ToolTip").c_str());\r
826                 setVisible(in->getAttributeAsBool("Visible", IsVisible));\r
827                 setEnabled(in->getAttributeAsBool("Enabled", IsEnabled));\r
828                 IsTabStop = in->getAttributeAsBool("TabStop", IsTabStop);\r
829                 IsTabGroup = in->getAttributeAsBool("TabGroup", IsTabGroup);\r
830                 TabOrder = in->getAttributeAsInt("TabOrder", TabOrder);\r
831 \r
832                 core::position2di p = in->getAttributeAsPosition2d("MaxSize", core::position2di(MaxSize.Width, MaxSize.Height));\r
833                 setMaxSize(core::dimension2du(p.X,p.Y));\r
834 \r
835                 p = in->getAttributeAsPosition2d("MinSize", core::position2di(MinSize.Width, MinSize.Height));\r
836                 setMinSize(core::dimension2du(p.X,p.Y));\r
837 \r
838                 setAlignment((EGUI_ALIGNMENT) in->getAttributeAsEnumeration("LeftAlign", GUIAlignmentNames, AlignLeft),\r
839                         (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("RightAlign", GUIAlignmentNames, AlignRight),\r
840                         (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("TopAlign", GUIAlignmentNames, AlignTop),\r
841                         (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("BottomAlign", GUIAlignmentNames, AlignBottom));\r
842 \r
843                 setRelativePosition(in->getAttributeAsRect("Rect", DesiredRect));\r
844 \r
845                 setNotClipped(in->getAttributeAsBool("NoClip", NoClip));\r
846         }\r
847 \r
848 protected:\r
849         // not virtual because needed in constructor\r
850         void addChildToEnd(IGUIElement* child)\r
851         {\r
852                 if (child)\r
853                 {\r
854                         child->grab(); // prevent destruction when removed\r
855                         child->remove(); // remove from old parent\r
856                         child->LastParentRect = getAbsolutePosition();\r
857                         child->Parent = this;\r
858                         Children.push_back(child);\r
859                 }\r
860         }\r
861 \r
862         // not virtual because needed in constructor\r
863         void recalculateAbsolutePosition(bool recursive)\r
864         {\r
865                 core::rect<s32> parentAbsolute(0,0,0,0);\r
866                 core::rect<s32> parentAbsoluteClip;\r
867                 f32 fw=0.f, fh=0.f;\r
868 \r
869                 if (Parent)\r
870                 {\r
871                         parentAbsolute = Parent->AbsoluteRect;\r
872 \r
873                         if (NoClip)\r
874                         {\r
875                                 IGUIElement* p=this;\r
876                                 while (p->Parent)\r
877                                         p = p->Parent;\r
878                                 parentAbsoluteClip = p->AbsoluteClippingRect;\r
879                         }\r
880                         else\r
881                                 parentAbsoluteClip = Parent->AbsoluteClippingRect;\r
882                 }\r
883 \r
884                 const s32 diffx = parentAbsolute.getWidth() - LastParentRect.getWidth();\r
885                 const s32 diffy = parentAbsolute.getHeight() - LastParentRect.getHeight();\r
886 \r
887                 if (AlignLeft == EGUIA_SCALE || AlignRight == EGUIA_SCALE)\r
888                         fw = (f32)parentAbsolute.getWidth();\r
889 \r
890                 if (AlignTop == EGUIA_SCALE || AlignBottom == EGUIA_SCALE)\r
891                         fh = (f32)parentAbsolute.getHeight();\r
892 \r
893                 switch (AlignLeft)\r
894                 {\r
895                         case EGUIA_UPPERLEFT:\r
896                                 break;\r
897                         case EGUIA_LOWERRIGHT:\r
898                                 DesiredRect.UpperLeftCorner.X += diffx;\r
899                                 break;\r
900                         case EGUIA_CENTER:\r
901                                 DesiredRect.UpperLeftCorner.X += diffx/2;\r
902                                 break;\r
903                         case EGUIA_SCALE:\r
904                                 DesiredRect.UpperLeftCorner.X = core::round32(ScaleRect.UpperLeftCorner.X * fw);\r
905                                 break;\r
906                 }\r
907 \r
908                 switch (AlignRight)\r
909                 {\r
910                         case EGUIA_UPPERLEFT:\r
911                                 break;\r
912                         case EGUIA_LOWERRIGHT:\r
913                                 DesiredRect.LowerRightCorner.X += diffx;\r
914                                 break;\r
915                         case EGUIA_CENTER:\r
916                                 DesiredRect.LowerRightCorner.X += diffx/2;\r
917                                 break;\r
918                         case EGUIA_SCALE:\r
919                                 DesiredRect.LowerRightCorner.X = core::round32(ScaleRect.LowerRightCorner.X * fw);\r
920                                 break;\r
921                 }\r
922 \r
923                 switch (AlignTop)\r
924                 {\r
925                         case EGUIA_UPPERLEFT:\r
926                                 break;\r
927                         case EGUIA_LOWERRIGHT:\r
928                                 DesiredRect.UpperLeftCorner.Y += diffy;\r
929                                 break;\r
930                         case EGUIA_CENTER:\r
931                                 DesiredRect.UpperLeftCorner.Y += diffy/2;\r
932                                 break;\r
933                         case EGUIA_SCALE:\r
934                                 DesiredRect.UpperLeftCorner.Y = core::round32(ScaleRect.UpperLeftCorner.Y * fh);\r
935                                 break;\r
936                 }\r
937 \r
938                 switch (AlignBottom)\r
939                 {\r
940                         case EGUIA_UPPERLEFT:\r
941                                 break;\r
942                         case EGUIA_LOWERRIGHT:\r
943                                 DesiredRect.LowerRightCorner.Y += diffy;\r
944                                 break;\r
945                         case EGUIA_CENTER:\r
946                                 DesiredRect.LowerRightCorner.Y += diffy/2;\r
947                                 break;\r
948                         case EGUIA_SCALE:\r
949                                 DesiredRect.LowerRightCorner.Y = core::round32(ScaleRect.LowerRightCorner.Y * fh);\r
950                                 break;\r
951                 }\r
952 \r
953                 RelativeRect = DesiredRect;\r
954 \r
955                 const s32 w = RelativeRect.getWidth();\r
956                 const s32 h = RelativeRect.getHeight();\r
957 \r
958                 // make sure the desired rectangle is allowed\r
959                 if (w < (s32)MinSize.Width)\r
960                         RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MinSize.Width;\r
961                 if (h < (s32)MinSize.Height)\r
962                         RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MinSize.Height;\r
963                 if (MaxSize.Width && w > (s32)MaxSize.Width)\r
964                         RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MaxSize.Width;\r
965                 if (MaxSize.Height && h > (s32)MaxSize.Height)\r
966                         RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MaxSize.Height;\r
967 \r
968                 RelativeRect.repair();\r
969 \r
970                 AbsoluteRect = RelativeRect + parentAbsolute.UpperLeftCorner;\r
971 \r
972                 if (!Parent)\r
973                         parentAbsoluteClip = AbsoluteRect;\r
974 \r
975                 AbsoluteClippingRect = AbsoluteRect;\r
976                 AbsoluteClippingRect.clipAgainst(parentAbsoluteClip);\r
977 \r
978                 LastParentRect = parentAbsolute;\r
979 \r
980                 if ( recursive )\r
981                 {\r
982                         // update all children\r
983                         core::list<IGUIElement*>::Iterator it = Children.begin();\r
984                         for (; it != Children.end(); ++it)\r
985                         {\r
986                                 (*it)->recalculateAbsolutePosition(recursive);\r
987                         }\r
988                 }\r
989         }\r
990 \r
991 protected:\r
992 \r
993         //! List of all children of this element\r
994         core::list<IGUIElement*> Children;\r
995 \r
996         //! Pointer to the parent\r
997         IGUIElement* Parent;\r
998 \r
999         //! relative rect of element\r
1000         core::rect<s32> RelativeRect;\r
1001 \r
1002         //! absolute rect of element\r
1003         core::rect<s32> AbsoluteRect;\r
1004 \r
1005         //! absolute clipping rect of element\r
1006         core::rect<s32> AbsoluteClippingRect;\r
1007 \r
1008         //! the rectangle the element would prefer to be,\r
1009         //! if it was not constrained by parent or max/min size\r
1010         core::rect<s32> DesiredRect;\r
1011 \r
1012         //! for calculating the difference when resizing parent\r
1013         core::rect<s32> LastParentRect;\r
1014 \r
1015         //! relative scale of the element inside its parent\r
1016         core::rect<f32> ScaleRect;\r
1017 \r
1018         //! maximum and minimum size of the element\r
1019         core::dimension2du MaxSize, MinSize;\r
1020 \r
1021         //! is visible?\r
1022         bool IsVisible;\r
1023 \r
1024         //! is enabled?\r
1025         bool IsEnabled;\r
1026 \r
1027         //! is a part of a larger whole and should not be serialized?\r
1028         bool IsSubElement;\r
1029 \r
1030         //! does this element ignore its parent's clipping rectangle?\r
1031         bool NoClip;\r
1032 \r
1033         //! caption\r
1034         core::stringw Text;\r
1035 \r
1036         //! tooltip\r
1037         core::stringw ToolTipText;\r
1038 \r
1039         //! users can set this for identifying the element by string\r
1040         core::stringc Name;\r
1041 \r
1042         //! users can set this for identifying the element by integer\r
1043         s32 ID;\r
1044 \r
1045         //! tab stop like in windows\r
1046         bool IsTabStop;\r
1047 \r
1048         //! tab order\r
1049         s32 TabOrder;\r
1050 \r
1051         //! tab groups are containers like windows, use ctrl+tab to navigate\r
1052         bool IsTabGroup;\r
1053 \r
1054         //! tells the element how to act when its parent is resized\r
1055         EGUI_ALIGNMENT AlignLeft, AlignRight, AlignTop, AlignBottom;\r
1056 \r
1057         //! GUI Environment\r
1058         IGUIEnvironment* Environment;\r
1059 \r
1060         //! type of element\r
1061         EGUI_ELEMENT_TYPE Type;\r
1062 };\r
1063 \r
1064 \r
1065 } // end namespace gui\r
1066 } // end namespace irr\r
1067 \r
1068 #endif\r
1069 \r