diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/include/IGUIElement.h | 1037 |
1 files changed, 1037 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/include/IGUIElement.h b/libraries/irrlicht-1.8/include/IGUIElement.h new file mode 100644 index 0000000..40df446 --- /dev/null +++ b/libraries/irrlicht-1.8/include/IGUIElement.h | |||
@@ -0,0 +1,1037 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #ifndef __I_GUI_ELEMENT_H_INCLUDED__ | ||
6 | #define __I_GUI_ELEMENT_H_INCLUDED__ | ||
7 | |||
8 | #include "IAttributeExchangingObject.h" | ||
9 | #include "irrList.h" | ||
10 | #include "rect.h" | ||
11 | #include "irrString.h" | ||
12 | #include "IEventReceiver.h" | ||
13 | #include "EGUIElementTypes.h" | ||
14 | #include "EGUIAlignment.h" | ||
15 | #include "IAttributes.h" | ||
16 | |||
17 | namespace irr | ||
18 | { | ||
19 | namespace gui | ||
20 | { | ||
21 | |||
22 | class IGUIEnvironment; | ||
23 | |||
24 | //! Base class of all GUI elements. | ||
25 | class IGUIElement : public virtual io::IAttributeExchangingObject, public IEventReceiver | ||
26 | { | ||
27 | public: | ||
28 | |||
29 | //! Constructor | ||
30 | IGUIElement(EGUI_ELEMENT_TYPE type, IGUIEnvironment* environment, IGUIElement* parent, | ||
31 | s32 id, const core::rect<s32>& rectangle) | ||
32 | : Parent(0), RelativeRect(rectangle), AbsoluteRect(rectangle), | ||
33 | AbsoluteClippingRect(rectangle), DesiredRect(rectangle), | ||
34 | MaxSize(0,0), MinSize(1,1), IsVisible(true), IsEnabled(true), | ||
35 | IsSubElement(false), NoClip(false), ID(id), IsTabStop(false), TabOrder(-1), IsTabGroup(false), | ||
36 | AlignLeft(EGUIA_UPPERLEFT), AlignRight(EGUIA_UPPERLEFT), AlignTop(EGUIA_UPPERLEFT), AlignBottom(EGUIA_UPPERLEFT), | ||
37 | Environment(environment), Type(type) | ||
38 | { | ||
39 | #ifdef _DEBUG | ||
40 | setDebugName("IGUIElement"); | ||
41 | #endif | ||
42 | |||
43 | // if we were given a parent to attach to | ||
44 | if (parent) | ||
45 | { | ||
46 | parent->addChildToEnd(this); | ||
47 | recalculateAbsolutePosition(true); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | |||
52 | //! Destructor | ||
53 | virtual ~IGUIElement() | ||
54 | { | ||
55 | // delete all children | ||
56 | core::list<IGUIElement*>::Iterator it = Children.begin(); | ||
57 | for (; it != Children.end(); ++it) | ||
58 | { | ||
59 | (*it)->Parent = 0; | ||
60 | (*it)->drop(); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | |||
65 | //! Returns parent of this element. | ||
66 | IGUIElement* getParent() const | ||
67 | { | ||
68 | return Parent; | ||
69 | } | ||
70 | |||
71 | |||
72 | //! Returns the relative rectangle of this element. | ||
73 | core::rect<s32> getRelativePosition() const | ||
74 | { | ||
75 | return RelativeRect; | ||
76 | } | ||
77 | |||
78 | |||
79 | //! Sets the relative rectangle of this element. | ||
80 | /** \param r The absolute position to set */ | ||
81 | void setRelativePosition(const core::rect<s32>& r) | ||
82 | { | ||
83 | if (Parent) | ||
84 | { | ||
85 | const core::rect<s32>& r2 = Parent->getAbsolutePosition(); | ||
86 | |||
87 | core::dimension2df d((f32)(r2.getSize().Width), (f32)(r2.getSize().Height)); | ||
88 | |||
89 | if (AlignLeft == EGUIA_SCALE) | ||
90 | ScaleRect.UpperLeftCorner.X = (f32)r.UpperLeftCorner.X / d.Width; | ||
91 | if (AlignRight == EGUIA_SCALE) | ||
92 | ScaleRect.LowerRightCorner.X = (f32)r.LowerRightCorner.X / d.Width; | ||
93 | if (AlignTop == EGUIA_SCALE) | ||
94 | ScaleRect.UpperLeftCorner.Y = (f32)r.UpperLeftCorner.Y / d.Height; | ||
95 | if (AlignBottom == EGUIA_SCALE) | ||
96 | ScaleRect.LowerRightCorner.Y = (f32)r.LowerRightCorner.Y / d.Height; | ||
97 | } | ||
98 | |||
99 | DesiredRect = r; | ||
100 | updateAbsolutePosition(); | ||
101 | } | ||
102 | |||
103 | //! Sets the relative rectangle of this element, maintaining its current width and height | ||
104 | /** \param position The new relative position to set. Width and height will not be changed. */ | ||
105 | void setRelativePosition(const core::position2di & position) | ||
106 | { | ||
107 | const core::dimension2di mySize = RelativeRect.getSize(); | ||
108 | const core::rect<s32> rectangle(position.X, position.Y, | ||
109 | position.X + mySize.Width, position.Y + mySize.Height); | ||
110 | setRelativePosition(rectangle); | ||
111 | } | ||
112 | |||
113 | |||
114 | //! Sets the relative rectangle of this element as a proportion of its parent's area. | ||
115 | /** \note This method used to be 'void setRelativePosition(const core::rect<f32>& r)' | ||
116 | \param r The rectangle to set, interpreted as a proportion of the parent's area. | ||
117 | Meaningful values are in the range [0...1], unless you intend this element to spill | ||
118 | outside its parent. */ | ||
119 | void setRelativePositionProportional(const core::rect<f32>& r) | ||
120 | { | ||
121 | if (!Parent) | ||
122 | return; | ||
123 | |||
124 | const core::dimension2di& d = Parent->getAbsolutePosition().getSize(); | ||
125 | |||
126 | DesiredRect = core::rect<s32>( | ||
127 | core::floor32((f32)d.Width * r.UpperLeftCorner.X), | ||
128 | core::floor32((f32)d.Height * r.UpperLeftCorner.Y), | ||
129 | core::floor32((f32)d.Width * r.LowerRightCorner.X), | ||
130 | core::floor32((f32)d.Height * r.LowerRightCorner.Y)); | ||
131 | |||
132 | ScaleRect = r; | ||
133 | |||
134 | updateAbsolutePosition(); | ||
135 | } | ||
136 | |||
137 | |||
138 | //! Gets the absolute rectangle of this element | ||
139 | core::rect<s32> getAbsolutePosition() const | ||
140 | { | ||
141 | return AbsoluteRect; | ||
142 | } | ||
143 | |||
144 | |||
145 | //! Returns the visible area of the element. | ||
146 | core::rect<s32> getAbsoluteClippingRect() const | ||
147 | { | ||
148 | return AbsoluteClippingRect; | ||
149 | } | ||
150 | |||
151 | |||
152 | //! Sets whether the element will ignore its parent's clipping rectangle | ||
153 | /** \param noClip If true, the element will not be clipped by its parent's clipping rectangle. */ | ||
154 | void setNotClipped(bool noClip) | ||
155 | { | ||
156 | NoClip = noClip; | ||
157 | updateAbsolutePosition(); | ||
158 | } | ||
159 | |||
160 | |||
161 | //! Gets whether the element will ignore its parent's clipping rectangle | ||
162 | /** \return true if the element is not clipped by its parent's clipping rectangle. */ | ||
163 | bool isNotClipped() const | ||
164 | { | ||
165 | return NoClip; | ||
166 | } | ||
167 | |||
168 | |||
169 | //! Sets the maximum size allowed for this element | ||
170 | /** If set to 0,0, there is no maximum size */ | ||
171 | void setMaxSize(core::dimension2du size) | ||
172 | { | ||
173 | MaxSize = size; | ||
174 | updateAbsolutePosition(); | ||
175 | } | ||
176 | |||
177 | |||
178 | //! Sets the minimum size allowed for this element | ||
179 | void setMinSize(core::dimension2du size) | ||
180 | { | ||
181 | MinSize = size; | ||
182 | if (MinSize.Width < 1) | ||
183 | MinSize.Width = 1; | ||
184 | if (MinSize.Height < 1) | ||
185 | MinSize.Height = 1; | ||
186 | updateAbsolutePosition(); | ||
187 | } | ||
188 | |||
189 | |||
190 | //! The alignment defines how the borders of this element will be positioned when the parent element is resized. | ||
191 | void setAlignment(EGUI_ALIGNMENT left, EGUI_ALIGNMENT right, EGUI_ALIGNMENT top, EGUI_ALIGNMENT bottom) | ||
192 | { | ||
193 | AlignLeft = left; | ||
194 | AlignRight = right; | ||
195 | AlignTop = top; | ||
196 | AlignBottom = bottom; | ||
197 | |||
198 | if (Parent) | ||
199 | { | ||
200 | core::rect<s32> r(Parent->getAbsolutePosition()); | ||
201 | |||
202 | core::dimension2df d((f32)r.getSize().Width, (f32)r.getSize().Height); | ||
203 | |||
204 | if (AlignLeft == EGUIA_SCALE) | ||
205 | ScaleRect.UpperLeftCorner.X = (f32)DesiredRect.UpperLeftCorner.X / d.Width; | ||
206 | if (AlignRight == EGUIA_SCALE) | ||
207 | ScaleRect.LowerRightCorner.X = (f32)DesiredRect.LowerRightCorner.X / d.Width; | ||
208 | if (AlignTop == EGUIA_SCALE) | ||
209 | ScaleRect.UpperLeftCorner.Y = (f32)DesiredRect.UpperLeftCorner.Y / d.Height; | ||
210 | if (AlignBottom == EGUIA_SCALE) | ||
211 | ScaleRect.LowerRightCorner.Y = (f32)DesiredRect.LowerRightCorner.Y / d.Height; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | |||
216 | //! Updates the absolute position. | ||
217 | virtual void updateAbsolutePosition() | ||
218 | { | ||
219 | recalculateAbsolutePosition(false); | ||
220 | |||
221 | // update all children | ||
222 | core::list<IGUIElement*>::Iterator it = Children.begin(); | ||
223 | for (; it != Children.end(); ++it) | ||
224 | { | ||
225 | (*it)->updateAbsolutePosition(); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | |||
230 | //! Returns the topmost GUI element at the specific position. | ||
231 | /** | ||
232 | This will check this GUI element and all of its descendants, so it | ||
233 | may return this GUI element. To check all GUI elements, call this | ||
234 | function on device->getGUIEnvironment()->getRootGUIElement(). Note | ||
235 | that the root element is the size of the screen, so doing so (with | ||
236 | an on-screen point) will always return the root element if no other | ||
237 | element is above it at that point. | ||
238 | \param point: The point at which to find a GUI element. | ||
239 | \return The topmost GUI element at that point, or 0 if there are | ||
240 | no candidate elements at this point. | ||
241 | */ | ||
242 | IGUIElement* getElementFromPoint(const core::position2d<s32>& point) | ||
243 | { | ||
244 | IGUIElement* target = 0; | ||
245 | |||
246 | // we have to search from back to front, because later children | ||
247 | // might be drawn over the top of earlier ones. | ||
248 | |||
249 | core::list<IGUIElement*>::Iterator it = Children.getLast(); | ||
250 | |||
251 | if (isVisible()) | ||
252 | { | ||
253 | while(it != Children.end()) | ||
254 | { | ||
255 | target = (*it)->getElementFromPoint(point); | ||
256 | if (target) | ||
257 | return target; | ||
258 | |||
259 | --it; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | if (isVisible() && isPointInside(point)) | ||
264 | target = this; | ||
265 | |||
266 | return target; | ||
267 | } | ||
268 | |||
269 | |||
270 | //! Returns true if a point is within this element. | ||
271 | /** Elements with a shape other than a rectangle should override this method */ | ||
272 | virtual bool isPointInside(const core::position2d<s32>& point) const | ||
273 | { | ||
274 | return AbsoluteClippingRect.isPointInside(point); | ||
275 | } | ||
276 | |||
277 | |||
278 | //! Adds a GUI element as new child of this element. | ||
279 | virtual void addChild(IGUIElement* child) | ||
280 | { | ||
281 | addChildToEnd(child); | ||
282 | if (child) | ||
283 | { | ||
284 | child->updateAbsolutePosition(); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | //! Removes a child. | ||
289 | virtual void removeChild(IGUIElement* child) | ||
290 | { | ||
291 | core::list<IGUIElement*>::Iterator it = Children.begin(); | ||
292 | for (; it != Children.end(); ++it) | ||
293 | if ((*it) == child) | ||
294 | { | ||
295 | (*it)->Parent = 0; | ||
296 | (*it)->drop(); | ||
297 | Children.erase(it); | ||
298 | return; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | |||
303 | //! Removes this element from its parent. | ||
304 | virtual void remove() | ||
305 | { | ||
306 | if (Parent) | ||
307 | Parent->removeChild(this); | ||
308 | } | ||
309 | |||
310 | |||
311 | //! Draws the element and its children. | ||
312 | virtual void draw() | ||
313 | { | ||
314 | if ( isVisible() ) | ||
315 | { | ||
316 | core::list<IGUIElement*>::Iterator it = Children.begin(); | ||
317 | for (; it != Children.end(); ++it) | ||
318 | (*it)->draw(); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | |||
323 | //! animate the element and its children. | ||
324 | virtual void OnPostRender(u32 timeMs) | ||
325 | { | ||
326 | if ( isVisible() ) | ||
327 | { | ||
328 | core::list<IGUIElement*>::Iterator it = Children.begin(); | ||
329 | for (; it != Children.end(); ++it) | ||
330 | (*it)->OnPostRender( timeMs ); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | |||
335 | //! Moves this element. | ||
336 | virtual void move(core::position2d<s32> absoluteMovement) | ||
337 | { | ||
338 | setRelativePosition(DesiredRect + absoluteMovement); | ||
339 | } | ||
340 | |||
341 | |||
342 | //! Returns true if element is visible. | ||
343 | virtual bool isVisible() const | ||
344 | { | ||
345 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
346 | return IsVisible; | ||
347 | } | ||
348 | |||
349 | |||
350 | //! Sets the visible state of this element. | ||
351 | virtual void setVisible(bool visible) | ||
352 | { | ||
353 | IsVisible = visible; | ||
354 | } | ||
355 | |||
356 | |||
357 | //! Returns true if this element was created as part of its parent control | ||
358 | virtual bool isSubElement() const | ||
359 | { | ||
360 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
361 | return IsSubElement; | ||
362 | } | ||
363 | |||
364 | |||
365 | //! Sets whether this control was created as part of its parent. | ||
366 | /** For example, it is true when a scrollbar is part of a listbox. | ||
367 | SubElements are not saved to disk when calling guiEnvironment->saveGUI() */ | ||
368 | virtual void setSubElement(bool subElement) | ||
369 | { | ||
370 | IsSubElement = subElement; | ||
371 | } | ||
372 | |||
373 | |||
374 | //! If set to true, the focus will visit this element when using the tab key to cycle through elements. | ||
375 | /** If this element is a tab group (see isTabGroup/setTabGroup) then | ||
376 | ctrl+tab will be used instead. */ | ||
377 | void setTabStop(bool enable) | ||
378 | { | ||
379 | IsTabStop = enable; | ||
380 | } | ||
381 | |||
382 | |||
383 | //! Returns true if this element can be focused by navigating with the tab key | ||
384 | bool isTabStop() const | ||
385 | { | ||
386 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
387 | return IsTabStop; | ||
388 | } | ||
389 | |||
390 | |||
391 | //! Sets the priority of focus when using the tab key to navigate between a group of elements. | ||
392 | /** See setTabGroup, isTabGroup and getTabGroup for information on tab groups. | ||
393 | Elements with a lower number are focused first */ | ||
394 | void setTabOrder(s32 index) | ||
395 | { | ||
396 | // negative = autonumber | ||
397 | if (index < 0) | ||
398 | { | ||
399 | TabOrder = 0; | ||
400 | IGUIElement *el = getTabGroup(); | ||
401 | while (IsTabGroup && el && el->Parent) | ||
402 | el = el->Parent; | ||
403 | |||
404 | IGUIElement *first=0, *closest=0; | ||
405 | if (el) | ||
406 | { | ||
407 | // find the highest element number | ||
408 | el->getNextElement(-1, true, IsTabGroup, first, closest, true); | ||
409 | if (first) | ||
410 | { | ||
411 | TabOrder = first->getTabOrder() + 1; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | } | ||
416 | else | ||
417 | TabOrder = index; | ||
418 | } | ||
419 | |||
420 | |||
421 | //! Returns the number in the tab order sequence | ||
422 | s32 getTabOrder() const | ||
423 | { | ||
424 | return TabOrder; | ||
425 | } | ||
426 | |||
427 | |||
428 | //! Sets whether this element is a container for a group of elements which can be navigated using the tab key. | ||
429 | /** For example, windows are tab groups. | ||
430 | Groups can be navigated using ctrl+tab, providing isTabStop is true. */ | ||
431 | void setTabGroup(bool isGroup) | ||
432 | { | ||
433 | IsTabGroup = isGroup; | ||
434 | } | ||
435 | |||
436 | |||
437 | //! Returns true if this element is a tab group. | ||
438 | bool isTabGroup() const | ||
439 | { | ||
440 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
441 | return IsTabGroup; | ||
442 | } | ||
443 | |||
444 | |||
445 | //! Returns the container element which holds all elements in this element's tab group. | ||
446 | IGUIElement* getTabGroup() | ||
447 | { | ||
448 | IGUIElement *ret=this; | ||
449 | |||
450 | while (ret && !ret->isTabGroup()) | ||
451 | ret = ret->getParent(); | ||
452 | |||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | |||
457 | //! Returns true if element is enabled | ||
458 | /** Currently elements do _not_ care about parent-states. | ||
459 | So if you want to affect childs you have to enable/disable them all. | ||
460 | The only exception to this are sub-elements which also check their parent. | ||
461 | */ | ||
462 | virtual bool isEnabled() const | ||
463 | { | ||
464 | if ( isSubElement() && IsEnabled && getParent() ) | ||
465 | return getParent()->isEnabled(); | ||
466 | |||
467 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
468 | return IsEnabled; | ||
469 | } | ||
470 | |||
471 | |||
472 | //! Sets the enabled state of this element. | ||
473 | virtual void setEnabled(bool enabled) | ||
474 | { | ||
475 | IsEnabled = enabled; | ||
476 | } | ||
477 | |||
478 | |||
479 | //! Sets the new caption of this element. | ||
480 | virtual void setText(const wchar_t* text) | ||
481 | { | ||
482 | Text = text; | ||
483 | } | ||
484 | |||
485 | |||
486 | //! Returns caption of this element. | ||
487 | virtual const wchar_t* getText() const | ||
488 | { | ||
489 | return Text.c_str(); | ||
490 | } | ||
491 | |||
492 | |||
493 | //! Sets the new caption of this element. | ||
494 | virtual void setToolTipText(const wchar_t* text) | ||
495 | { | ||
496 | ToolTipText = text; | ||
497 | } | ||
498 | |||
499 | |||
500 | //! Returns caption of this element. | ||
501 | virtual const core::stringw& getToolTipText() const | ||
502 | { | ||
503 | return ToolTipText; | ||
504 | } | ||
505 | |||
506 | |||
507 | //! Returns id. Can be used to identify the element. | ||
508 | virtual s32 getID() const | ||
509 | { | ||
510 | return ID; | ||
511 | } | ||
512 | |||
513 | |||
514 | //! Sets the id of this element | ||
515 | virtual void setID(s32 id) | ||
516 | { | ||
517 | ID = id; | ||
518 | } | ||
519 | |||
520 | |||
521 | //! Called if an event happened. | ||
522 | virtual bool OnEvent(const SEvent& event) | ||
523 | { | ||
524 | return Parent ? Parent->OnEvent(event) : false; | ||
525 | } | ||
526 | |||
527 | |||
528 | //! Brings a child to front | ||
529 | /** \return True if successful, false if not. */ | ||
530 | virtual bool bringToFront(IGUIElement* element) | ||
531 | { | ||
532 | core::list<IGUIElement*>::Iterator it = Children.begin(); | ||
533 | for (; it != Children.end(); ++it) | ||
534 | { | ||
535 | if (element == (*it)) | ||
536 | { | ||
537 | Children.erase(it); | ||
538 | Children.push_back(element); | ||
539 | return true; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
544 | return false; | ||
545 | } | ||
546 | |||
547 | |||
548 | //! Moves a child to the back, so it's siblings are drawn on top of it | ||
549 | /** \return True if successful, false if not. */ | ||
550 | virtual bool sendToBack(IGUIElement* child) | ||
551 | { | ||
552 | core::list<IGUIElement*>::Iterator it = Children.begin(); | ||
553 | if (child == (*it)) // already there | ||
554 | return true; | ||
555 | for (; it != Children.end(); ++it) | ||
556 | { | ||
557 | if (child == (*it)) | ||
558 | { | ||
559 | Children.erase(it); | ||
560 | Children.push_front(child); | ||
561 | return true; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
566 | return false; | ||
567 | } | ||
568 | |||
569 | //! Returns list with children of this element | ||
570 | virtual const core::list<IGUIElement*>& getChildren() const | ||
571 | { | ||
572 | return Children; | ||
573 | } | ||
574 | |||
575 | |||
576 | //! Finds the first element with the given id. | ||
577 | /** \param id: Id to search for. | ||
578 | \param searchchildren: Set this to true, if also children of this | ||
579 | element may contain the element with the searched id and they | ||
580 | should be searched too. | ||
581 | \return Returns the first element with the given id. If no element | ||
582 | with this id was found, 0 is returned. */ | ||
583 | virtual IGUIElement* getElementFromId(s32 id, bool searchchildren=false) const | ||
584 | { | ||
585 | IGUIElement* e = 0; | ||
586 | |||
587 | core::list<IGUIElement*>::ConstIterator it = Children.begin(); | ||
588 | for (; it != Children.end(); ++it) | ||
589 | { | ||
590 | if ((*it)->getID() == id) | ||
591 | return (*it); | ||
592 | |||
593 | if (searchchildren) | ||
594 | e = (*it)->getElementFromId(id, true); | ||
595 | |||
596 | if (e) | ||
597 | return e; | ||
598 | } | ||
599 | |||
600 | return e; | ||
601 | } | ||
602 | |||
603 | |||
604 | //! returns true if the given element is a child of this one. | ||
605 | //! \param child: The child element to check | ||
606 | bool isMyChild(IGUIElement* child) const | ||
607 | { | ||
608 | if (!child) | ||
609 | return false; | ||
610 | do | ||
611 | { | ||
612 | if (child->Parent) | ||
613 | child = child->Parent; | ||
614 | |||
615 | } while (child->Parent && child != this); | ||
616 | |||
617 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
618 | return child == this; | ||
619 | } | ||
620 | |||
621 | |||
622 | //! searches elements to find the closest next element to tab to | ||
623 | /** \param startOrder: The TabOrder of the current element, -1 if none | ||
624 | \param reverse: true if searching for a lower number | ||
625 | \param group: true if searching for a higher one | ||
626 | \param first: element with the highest/lowest known tab order depending on search direction | ||
627 | \param closest: the closest match, depending on tab order and direction | ||
628 | \param includeInvisible: includes invisible elements in the search (default=false) | ||
629 | \return true if successfully found an element, false to continue searching/fail */ | ||
630 | bool getNextElement(s32 startOrder, bool reverse, bool group, | ||
631 | IGUIElement*& first, IGUIElement*& closest, bool includeInvisible=false) const | ||
632 | { | ||
633 | // we'll stop searching if we find this number | ||
634 | s32 wanted = startOrder + ( reverse ? -1 : 1 ); | ||
635 | if (wanted==-2) | ||
636 | wanted = 1073741824; // maximum s32 | ||
637 | |||
638 | core::list<IGUIElement*>::ConstIterator it = Children.begin(); | ||
639 | |||
640 | s32 closestOrder, currentOrder; | ||
641 | |||
642 | while(it != Children.end()) | ||
643 | { | ||
644 | // ignore invisible elements and their children | ||
645 | if ( ( (*it)->isVisible() || includeInvisible ) && | ||
646 | (group == true || (*it)->isTabGroup() == false) ) | ||
647 | { | ||
648 | // only check tab stops and those with the same group status | ||
649 | if ((*it)->isTabStop() && ((*it)->isTabGroup() == group)) | ||
650 | { | ||
651 | currentOrder = (*it)->getTabOrder(); | ||
652 | |||
653 | // is this what we're looking for? | ||
654 | if (currentOrder == wanted) | ||
655 | { | ||
656 | closest = *it; | ||
657 | return true; | ||
658 | } | ||
659 | |||
660 | // is it closer than the current closest? | ||
661 | if (closest) | ||
662 | { | ||
663 | closestOrder = closest->getTabOrder(); | ||
664 | if ( ( reverse && currentOrder > closestOrder && currentOrder < startOrder) | ||
665 | ||(!reverse && currentOrder < closestOrder && currentOrder > startOrder)) | ||
666 | { | ||
667 | closest = *it; | ||
668 | } | ||
669 | } | ||
670 | else | ||
671 | if ( (reverse && currentOrder < startOrder) || (!reverse && currentOrder > startOrder) ) | ||
672 | { | ||
673 | closest = *it; | ||
674 | } | ||
675 | |||
676 | // is it before the current first? | ||
677 | if (first) | ||
678 | { | ||
679 | closestOrder = first->getTabOrder(); | ||
680 | |||
681 | if ( (reverse && closestOrder < currentOrder) || (!reverse && closestOrder > currentOrder) ) | ||
682 | { | ||
683 | first = *it; | ||
684 | } | ||
685 | } | ||
686 | else | ||
687 | { | ||
688 | first = *it; | ||
689 | } | ||
690 | } | ||
691 | // search within children | ||
692 | if ((*it)->getNextElement(startOrder, reverse, group, first, closest)) | ||
693 | { | ||
694 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
695 | return true; | ||
696 | } | ||
697 | } | ||
698 | ++it; | ||
699 | } | ||
700 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
701 | return false; | ||
702 | } | ||
703 | |||
704 | |||
705 | //! Returns the type of the gui element. | ||
706 | /** This is needed for the .NET wrapper but will be used | ||
707 | later for serializing and deserializing. | ||
708 | If you wrote your own GUIElements, you need to set the type for your element as first parameter | ||
709 | in the constructor of IGUIElement. For own (=unknown) elements, simply use EGUIET_ELEMENT as type */ | ||
710 | EGUI_ELEMENT_TYPE getType() const | ||
711 | { | ||
712 | return Type; | ||
713 | } | ||
714 | |||
715 | //! Returns true if the gui element supports the given type. | ||
716 | /** This is mostly used to check if you can cast a gui element to the class that goes with the type. | ||
717 | Most gui elements will only support their own type, but if you derive your own classes from interfaces | ||
718 | you can overload this function and add a check for the type of the base-class additionally. | ||
719 | This allows for checks comparable to the dynamic_cast of c++ with enabled rtti. | ||
720 | Note that you can't do that by calling BaseClass::hasType(type), but you have to do an explicit | ||
721 | comparison check, because otherwise the base class usually just checks for the membervariable | ||
722 | Type which contains the type of your derived class. | ||
723 | */ | ||
724 | virtual bool hasType(EGUI_ELEMENT_TYPE type) const | ||
725 | { | ||
726 | return type == Type; | ||
727 | } | ||
728 | |||
729 | |||
730 | //! Returns the type name of the gui element. | ||
731 | /** This is needed serializing elements. For serializing your own elements, override this function | ||
732 | and return your own type name which is created by your IGUIElementFactory */ | ||
733 | virtual const c8* getTypeName() const | ||
734 | { | ||
735 | return GUIElementTypeNames[Type]; | ||
736 | } | ||
737 | |||
738 | //! Returns the name of the element. | ||
739 | /** \return Name as character string. */ | ||
740 | virtual const c8* getName() const | ||
741 | { | ||
742 | return Name.c_str(); | ||
743 | } | ||
744 | |||
745 | |||
746 | //! Sets the name of the element. | ||
747 | /** \param name New name of the gui element. */ | ||
748 | virtual void setName(const c8* name) | ||
749 | { | ||
750 | Name = name; | ||
751 | } | ||
752 | |||
753 | |||
754 | //! Sets the name of the element. | ||
755 | /** \param name New name of the gui element. */ | ||
756 | virtual void setName(const core::stringc& name) | ||
757 | { | ||
758 | Name = name; | ||
759 | } | ||
760 | |||
761 | |||
762 | //! Writes attributes of the scene node. | ||
763 | /** Implement this to expose the attributes of your scene node for | ||
764 | scripting languages, editors, debuggers or xml serialization purposes. */ | ||
765 | virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const | ||
766 | { | ||
767 | out->addString("Name", Name.c_str()); | ||
768 | out->addInt("Id", ID ); | ||
769 | out->addString("Caption", getText()); | ||
770 | out->addRect("Rect", DesiredRect); | ||
771 | out->addPosition2d("MinSize", core::position2di(MinSize.Width, MinSize.Height)); | ||
772 | out->addPosition2d("MaxSize", core::position2di(MaxSize.Width, MaxSize.Height)); | ||
773 | out->addEnum("LeftAlign", AlignLeft, GUIAlignmentNames); | ||
774 | out->addEnum("RightAlign", AlignRight, GUIAlignmentNames); | ||
775 | out->addEnum("TopAlign", AlignTop, GUIAlignmentNames); | ||
776 | out->addEnum("BottomAlign", AlignBottom, GUIAlignmentNames); | ||
777 | out->addBool("Visible", IsVisible); | ||
778 | out->addBool("Enabled", IsEnabled); | ||
779 | out->addBool("TabStop", IsTabStop); | ||
780 | out->addBool("TabGroup", IsTabGroup); | ||
781 | out->addInt("TabOrder", TabOrder); | ||
782 | out->addBool("NoClip", NoClip); | ||
783 | } | ||
784 | |||
785 | |||
786 | //! Reads attributes of the scene node. | ||
787 | /** Implement this to set the attributes of your scene node for | ||
788 | scripting languages, editors, debuggers or xml deserialization purposes. */ | ||
789 | virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) | ||
790 | { | ||
791 | setName(in->getAttributeAsString("Name")); | ||
792 | setID(in->getAttributeAsInt("Id")); | ||
793 | setText(in->getAttributeAsStringW("Caption").c_str()); | ||
794 | setVisible(in->getAttributeAsBool("Visible")); | ||
795 | setEnabled(in->getAttributeAsBool("Enabled")); | ||
796 | IsTabStop = in->getAttributeAsBool("TabStop"); | ||
797 | IsTabGroup = in->getAttributeAsBool("TabGroup"); | ||
798 | TabOrder = in->getAttributeAsInt("TabOrder"); | ||
799 | |||
800 | core::position2di p = in->getAttributeAsPosition2d("MaxSize"); | ||
801 | setMaxSize(core::dimension2du(p.X,p.Y)); | ||
802 | |||
803 | p = in->getAttributeAsPosition2d("MinSize"); | ||
804 | setMinSize(core::dimension2du(p.X,p.Y)); | ||
805 | |||
806 | setAlignment((EGUI_ALIGNMENT) in->getAttributeAsEnumeration("LeftAlign", GUIAlignmentNames), | ||
807 | (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("RightAlign", GUIAlignmentNames), | ||
808 | (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("TopAlign", GUIAlignmentNames), | ||
809 | (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("BottomAlign", GUIAlignmentNames)); | ||
810 | |||
811 | setRelativePosition(in->getAttributeAsRect("Rect")); | ||
812 | |||
813 | setNotClipped(in->getAttributeAsBool("NoClip")); | ||
814 | } | ||
815 | |||
816 | protected: | ||
817 | // not virtual because needed in constructor | ||
818 | void addChildToEnd(IGUIElement* child) | ||
819 | { | ||
820 | if (child) | ||
821 | { | ||
822 | child->grab(); // prevent destruction when removed | ||
823 | child->remove(); // remove from old parent | ||
824 | child->LastParentRect = getAbsolutePosition(); | ||
825 | child->Parent = this; | ||
826 | Children.push_back(child); | ||
827 | } | ||
828 | } | ||
829 | |||
830 | // not virtual because needed in constructor | ||
831 | void recalculateAbsolutePosition(bool recursive) | ||
832 | { | ||
833 | core::rect<s32> parentAbsolute(0,0,0,0); | ||
834 | core::rect<s32> parentAbsoluteClip; | ||
835 | f32 fw=0.f, fh=0.f; | ||
836 | |||
837 | if (Parent) | ||
838 | { | ||
839 | parentAbsolute = Parent->AbsoluteRect; | ||
840 | |||
841 | if (NoClip) | ||
842 | { | ||
843 | IGUIElement* p=this; | ||
844 | while (p && p->Parent) | ||
845 | p = p->Parent; | ||
846 | parentAbsoluteClip = p->AbsoluteClippingRect; | ||
847 | } | ||
848 | else | ||
849 | parentAbsoluteClip = Parent->AbsoluteClippingRect; | ||
850 | } | ||
851 | |||
852 | const s32 diffx = parentAbsolute.getWidth() - LastParentRect.getWidth(); | ||
853 | const s32 diffy = parentAbsolute.getHeight() - LastParentRect.getHeight(); | ||
854 | |||
855 | if (AlignLeft == EGUIA_SCALE || AlignRight == EGUIA_SCALE) | ||
856 | fw = (f32)parentAbsolute.getWidth(); | ||
857 | |||
858 | if (AlignTop == EGUIA_SCALE || AlignBottom == EGUIA_SCALE) | ||
859 | fh = (f32)parentAbsolute.getHeight(); | ||
860 | |||
861 | switch (AlignLeft) | ||
862 | { | ||
863 | case EGUIA_UPPERLEFT: | ||
864 | break; | ||
865 | case EGUIA_LOWERRIGHT: | ||
866 | DesiredRect.UpperLeftCorner.X += diffx; | ||
867 | break; | ||
868 | case EGUIA_CENTER: | ||
869 | DesiredRect.UpperLeftCorner.X += diffx/2; | ||
870 | break; | ||
871 | case EGUIA_SCALE: | ||
872 | DesiredRect.UpperLeftCorner.X = core::round32(ScaleRect.UpperLeftCorner.X * fw); | ||
873 | break; | ||
874 | } | ||
875 | |||
876 | switch (AlignRight) | ||
877 | { | ||
878 | case EGUIA_UPPERLEFT: | ||
879 | break; | ||
880 | case EGUIA_LOWERRIGHT: | ||
881 | DesiredRect.LowerRightCorner.X += diffx; | ||
882 | break; | ||
883 | case EGUIA_CENTER: | ||
884 | DesiredRect.LowerRightCorner.X += diffx/2; | ||
885 | break; | ||
886 | case EGUIA_SCALE: | ||
887 | DesiredRect.LowerRightCorner.X = core::round32(ScaleRect.LowerRightCorner.X * fw); | ||
888 | break; | ||
889 | } | ||
890 | |||
891 | switch (AlignTop) | ||
892 | { | ||
893 | case EGUIA_UPPERLEFT: | ||
894 | break; | ||
895 | case EGUIA_LOWERRIGHT: | ||
896 | DesiredRect.UpperLeftCorner.Y += diffy; | ||
897 | break; | ||
898 | case EGUIA_CENTER: | ||
899 | DesiredRect.UpperLeftCorner.Y += diffy/2; | ||
900 | break; | ||
901 | case EGUIA_SCALE: | ||
902 | DesiredRect.UpperLeftCorner.Y = core::round32(ScaleRect.UpperLeftCorner.Y * fh); | ||
903 | break; | ||
904 | } | ||
905 | |||
906 | switch (AlignBottom) | ||
907 | { | ||
908 | case EGUIA_UPPERLEFT: | ||
909 | break; | ||
910 | case EGUIA_LOWERRIGHT: | ||
911 | DesiredRect.LowerRightCorner.Y += diffy; | ||
912 | break; | ||
913 | case EGUIA_CENTER: | ||
914 | DesiredRect.LowerRightCorner.Y += diffy/2; | ||
915 | break; | ||
916 | case EGUIA_SCALE: | ||
917 | DesiredRect.LowerRightCorner.Y = core::round32(ScaleRect.LowerRightCorner.Y * fh); | ||
918 | break; | ||
919 | } | ||
920 | |||
921 | RelativeRect = DesiredRect; | ||
922 | |||
923 | const s32 w = RelativeRect.getWidth(); | ||
924 | const s32 h = RelativeRect.getHeight(); | ||
925 | |||
926 | // make sure the desired rectangle is allowed | ||
927 | if (w < (s32)MinSize.Width) | ||
928 | RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MinSize.Width; | ||
929 | if (h < (s32)MinSize.Height) | ||
930 | RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MinSize.Height; | ||
931 | if (MaxSize.Width && w > (s32)MaxSize.Width) | ||
932 | RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MaxSize.Width; | ||
933 | if (MaxSize.Height && h > (s32)MaxSize.Height) | ||
934 | RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MaxSize.Height; | ||
935 | |||
936 | RelativeRect.repair(); | ||
937 | |||
938 | AbsoluteRect = RelativeRect + parentAbsolute.UpperLeftCorner; | ||
939 | |||
940 | if (!Parent) | ||
941 | parentAbsoluteClip = AbsoluteRect; | ||
942 | |||
943 | AbsoluteClippingRect = AbsoluteRect; | ||
944 | AbsoluteClippingRect.clipAgainst(parentAbsoluteClip); | ||
945 | |||
946 | LastParentRect = parentAbsolute; | ||
947 | |||
948 | if ( recursive ) | ||
949 | { | ||
950 | // update all children | ||
951 | core::list<IGUIElement*>::Iterator it = Children.begin(); | ||
952 | for (; it != Children.end(); ++it) | ||
953 | { | ||
954 | (*it)->recalculateAbsolutePosition(recursive); | ||
955 | } | ||
956 | } | ||
957 | } | ||
958 | |||
959 | protected: | ||
960 | |||
961 | //! List of all children of this element | ||
962 | core::list<IGUIElement*> Children; | ||
963 | |||
964 | //! Pointer to the parent | ||
965 | IGUIElement* Parent; | ||
966 | |||
967 | //! relative rect of element | ||
968 | core::rect<s32> RelativeRect; | ||
969 | |||
970 | //! absolute rect of element | ||
971 | core::rect<s32> AbsoluteRect; | ||
972 | |||
973 | //! absolute clipping rect of element | ||
974 | core::rect<s32> AbsoluteClippingRect; | ||
975 | |||
976 | //! the rectangle the element would prefer to be, | ||
977 | //! if it was not constrained by parent or max/min size | ||
978 | core::rect<s32> DesiredRect; | ||
979 | |||
980 | //! for calculating the difference when resizing parent | ||
981 | core::rect<s32> LastParentRect; | ||
982 | |||
983 | //! relative scale of the element inside its parent | ||
984 | core::rect<f32> ScaleRect; | ||
985 | |||
986 | //! maximum and minimum size of the element | ||
987 | core::dimension2du MaxSize, MinSize; | ||
988 | |||
989 | //! is visible? | ||
990 | bool IsVisible; | ||
991 | |||
992 | //! is enabled? | ||
993 | bool IsEnabled; | ||
994 | |||
995 | //! is a part of a larger whole and should not be serialized? | ||
996 | bool IsSubElement; | ||
997 | |||
998 | //! does this element ignore its parent's clipping rectangle? | ||
999 | bool NoClip; | ||
1000 | |||
1001 | //! caption | ||
1002 | core::stringw Text; | ||
1003 | |||
1004 | //! tooltip | ||
1005 | core::stringw ToolTipText; | ||
1006 | |||
1007 | //! users can set this for identificating the element by string | ||
1008 | core::stringc Name; | ||
1009 | |||
1010 | //! users can set this for identificating the element by integer | ||
1011 | s32 ID; | ||
1012 | |||
1013 | //! tab stop like in windows | ||
1014 | bool IsTabStop; | ||
1015 | |||
1016 | //! tab order | ||
1017 | s32 TabOrder; | ||
1018 | |||
1019 | //! tab groups are containers like windows, use ctrl+tab to navigate | ||
1020 | bool IsTabGroup; | ||
1021 | |||
1022 | //! tells the element how to act when its parent is resized | ||
1023 | EGUI_ALIGNMENT AlignLeft, AlignRight, AlignTop, AlignBottom; | ||
1024 | |||
1025 | //! GUI Environment | ||
1026 | IGUIEnvironment* Environment; | ||
1027 | |||
1028 | //! type of element | ||
1029 | EGUI_ELEMENT_TYPE Type; | ||
1030 | }; | ||
1031 | |||
1032 | |||
1033 | } // end namespace gui | ||
1034 | } // end namespace irr | ||
1035 | |||
1036 | #endif | ||
1037 | |||