1 /***********************************************************************
2     created:    21/2/2004
3     author:     Paul D Turner
4 
5     purpose:    Implements the Window base class
6 *************************************************************************/
7 /***************************************************************************
8  *   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
9  *
10  *   Permission is hereby granted, free of charge, to any person obtaining
11  *   a copy of this software and associated documentation files (the
12  *   "Software"), to deal in the Software without restriction, including
13  *   without limitation the rights to use, copy, modify, merge, publish,
14  *   distribute, sublicense, and/or sell copies of the Software, and to
15  *   permit persons to whom the Software is furnished to do so, subject to
16  *   the following conditions:
17  *
18  *   The above copyright notice and this permission notice shall be
19  *   included in all copies or substantial portions of the Software.
20  *
21  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23  *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24  *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25  *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26  *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  *   OTHER DEALINGS IN THE SOFTWARE.
28  ***************************************************************************/
29 #include "CEGUI/Window.h"
30 #include "CEGUI/Exceptions.h"
31 #include "CEGUI/WindowManager.h"
32 #include "CEGUI/System.h"
33 #include "CEGUI/FontManager.h"
34 #include "CEGUI/ImageManager.h"
35 #include "CEGUI/MouseCursor.h"
36 #include "CEGUI/CoordConverter.h"
37 #include "CEGUI/WindowRendererManager.h"
38 #include "CEGUI/WindowFactoryManager.h"
39 #include "CEGUI/widgets/Tooltip.h"
40 #include "CEGUI/falagard/WidgetLookManager.h"
41 #include "CEGUI/falagard/WidgetLookFeel.h"
42 #include "CEGUI/falagard/WidgetComponent.h"
43 #include "CEGUI/GeometryBuffer.h"
44 #include "CEGUI/GUIContext.h"
45 #include "CEGUI/RenderingContext.h"
46 #include "CEGUI/RenderingWindow.h"
47 #include "CEGUI/GlobalEventSet.h"
48 #include <algorithm>
49 #include <iterator>
50 #include <cmath>
51 #include <stdio.h>
52 #include <queue>
53 
54 #if defined (CEGUI_USE_FRIBIDI)
55     #include "CEGUI/FribidiVisualMapping.h"
56 #elif defined (CEGUI_USE_MINIBIDI)
57     #include "CEGUI/MinibidiVisualMapping.h"
58 #else
59     #include "CEGUI/BidiVisualMapping.h"
60 #endif
61 
62 #if defined(_MSC_VER)
63 #   pragma warning(push)
64 #   pragma warning(disable : 4355)
65 #endif
66 
67 // Start of CEGUI namespace section
68 namespace CEGUI
69 {
70 //----------------------------------------------------------------------------//
71 const String Window::AlphaPropertyName("Alpha");
72 const String Window::AlwaysOnTopPropertyName("AlwaysOnTop");
73 const String Window::ClippedByParentPropertyName("ClippedByParent");
74 const String Window::DestroyedByParentPropertyName("DestroyedByParent");
75 const String Window::DisabledPropertyName("Disabled");
76 const String Window::FontPropertyName("Font");
77 const String Window::IDPropertyName("ID");
78 const String Window::InheritsAlphaPropertyName("InheritsAlpha");
79 const String Window::MouseCursorImagePropertyName("MouseCursorImage");
80 const String Window::VisiblePropertyName("Visible");
81 const String Window::RestoreOldCapturePropertyName("RestoreOldCapture");
82 const String Window::TextPropertyName("Text");
83 const String Window::ZOrderingEnabledPropertyName("ZOrderingEnabled");
84 const String Window::WantsMultiClickEventsPropertyName("WantsMultiClickEvents");
85 const String Window::MouseAutoRepeatEnabledPropertyName("MouseAutoRepeatEnabled");
86 const String Window::AutoRepeatDelayPropertyName("AutoRepeatDelay");
87 const String Window::AutoRepeatRatePropertyName("AutoRepeatRate");
88 const String Window::DistributeCapturedInputsPropertyName("DistributeCapturedInputs");
89 const String Window::TooltipTypePropertyName("TooltipType");
90 const String Window::TooltipTextPropertyName("TooltipText");
91 const String Window::InheritsTooltipTextPropertyName("InheritsTooltipText");
92 const String Window::RiseOnClickEnabledPropertyName("RiseOnClickEnabled");
93 const String Window::MousePassThroughEnabledPropertyName("MousePassThroughEnabled");
94 const String Window::DragDropTargetPropertyName("DragDropTarget");
95 const String Window::AutoRenderingSurfacePropertyName("AutoRenderingSurface");
96 const String Window::TextParsingEnabledPropertyName("TextParsingEnabled");
97 const String Window::MarginPropertyName("MarginProperty");
98 const String Window::UpdateModePropertyName("UpdateMode");
99 const String Window::MouseInputPropagationEnabledPropertyName("MouseInputPropagationEnabled");
100 const String Window::AutoWindowPropertyName("AutoWindow");
101 //----------------------------------------------------------------------------//
102 const String Window::EventNamespace("Window");
103 const String Window::EventUpdated ("Updated");
104 const String Window::EventTextChanged("TextChanged");
105 const String Window::EventFontChanged("FontChanged");
106 const String Window::EventAlphaChanged("AlphaChanged");
107 const String Window::EventIDChanged("IDChanged");
108 const String Window::EventActivated("Activated");
109 const String Window::EventDeactivated("Deactivated");
110 const String Window::EventShown("Shown");
111 const String Window::EventHidden("Hidden");
112 const String Window::EventEnabled("Enabled");
113 const String Window::EventDisabled("Disabled");
114 const String Window::EventClippedByParentChanged( "ClippedByParentChanged" );
115 const String Window::EventDestroyedByParentChanged("DestroyedByParentChanged");
116 const String Window::EventInheritsAlphaChanged( "InheritsAlphaChanged" );
117 const String Window::EventAlwaysOnTopChanged("AlwaysOnTopChanged");
118 const String Window::EventInputCaptureGained( "InputCaptureGained" );
119 const String Window::EventInputCaptureLost( "InputCaptureLost" );
120 const String Window::EventInvalidated( "Invalidated" );
121 const String Window::EventRenderingStarted( "RenderingStarted" );
122 const String Window::EventRenderingEnded( "RenderingEnded" );
123 const String Window::EventDestructionStarted( "DestructionStarted" );
124 const String Window::EventDragDropItemEnters("DragDropItemEnters");
125 const String Window::EventDragDropItemLeaves("DragDropItemLeaves");
126 const String Window::EventDragDropItemDropped("DragDropItemDropped");
127 const String Window::EventWindowRendererAttached("WindowRendererAttached");
128 const String Window::EventWindowRendererDetached("WindowRendererDetached");
129 const String Window::EventTextParsingChanged("TextParsingChanged");
130 const String Window::EventMarginChanged("MarginChanged");
131 const String Window::EventMouseEntersArea("MouseEntersArea");
132 const String Window::EventMouseLeavesArea("MouseLeavesArea");
133 const String Window::EventMouseEntersSurface( "MouseEntersSurface" );
134 const String Window::EventMouseLeavesSurface( "MouseLeavesSurface" );
135 const String Window::EventMouseMove("MouseMove");
136 const String Window::EventMouseWheel("MouseWheel");
137 const String Window::EventMouseButtonDown("MouseButtonDown");
138 const String Window::EventMouseButtonUp("MouseButtonUp");
139 const String Window::EventMouseClick("MouseClick");
140 const String Window::EventMouseDoubleClick("MouseDoubleClick");
141 const String Window::EventMouseTripleClick("MouseTripleClick");
142 const String Window::EventKeyDown("KeyDown");
143 const String Window::EventKeyUp("KeyUp");
144 const String Window::EventCharacterKey("CharacterKey");
145 
146 //----------------------------------------------------------------------------//
147 // XML element and attribute names that relate to Window.
148 const String Window::WindowXMLElementName("Window");
149 const String Window::AutoWindowXMLElementName("AutoWindow");
150 const String Window::UserStringXMLElementName("UserString");
151 const String Window::WindowTypeXMLAttributeName("type");
152 const String Window::WindowNameXMLAttributeName("name");
153 const String Window::AutoWindowNamePathXMLAttributeName("namePath");
154 const String Window::UserStringNameXMLAttributeName("name");
155 const String Window::UserStringValueXMLAttributeName("value");
156 
157 //----------------------------------------------------------------------------//
158 const String Window::TooltipNameSuffix("__auto_tooltip__");
159 
160 //----------------------------------------------------------------------------//
161 BasicRenderedStringParser Window::d_basicStringParser;
162 DefaultRenderedStringParser Window::d_defaultStringParser;
163 
164 //----------------------------------------------------------------------------//
165 Window::WindowRendererProperty Window::d_windowRendererProperty;
166 Window::LookNFeelProperty Window::d_lookNFeelProperty;
167 
168 //----------------------------------------------------------------------------//
WindowRendererProperty()169 Window::WindowRendererProperty::WindowRendererProperty() : TplWindowProperty<Window,String>(
170     "WindowRenderer",
171     "Property to get/set the assigned WindowRenderer object type. For "
172     "advanced use only. See the api reference for Window::setWindowRenderer "
173     "for more information. "
174     "Value is a string.",
175     "Window", &Window::setWindowRenderer,&Window::getWindowRendererName, "")
176     {}
177 
178 //----------------------------------------------------------------------------//
writeXMLToStream(const PropertyReceiver * receiver,XMLSerializer & xml_stream) const179 void Window::WindowRendererProperty::writeXMLToStream(const PropertyReceiver* receiver,
180                                                       XMLSerializer& xml_stream) const
181 {
182     const Window* wnd = static_cast<const Window*>(receiver);
183 
184     if (!WindowFactoryManager::getSingleton().isFalagardMappedType(wnd->getType()))
185         Property::writeXMLToStream(receiver, xml_stream);
186 }
187 
188 //----------------------------------------------------------------------------//
LookNFeelProperty()189 Window::LookNFeelProperty::LookNFeelProperty() : TplWindowProperty<Window,String>(
190     "LookNFeel",
191     "Property to get/set the assigned look'n'feel. For advanced use only. See "
192     "the api reference for Window::setLookNFeel for more informaton. "
193     "Value is a string.",
194     "Window", &Window::setLookNFeel,&Window::getLookNFeel, "")
195     {}
196 
197 //----------------------------------------------------------------------------//
writeXMLToStream(const PropertyReceiver * receiver,XMLSerializer & xml_stream) const198 void Window::LookNFeelProperty::writeXMLToStream(const PropertyReceiver* receiver,
199                                                  XMLSerializer& xml_stream) const
200 {
201     const Window* wnd = static_cast<const Window*>(receiver);
202 
203     if (!WindowFactoryManager::getSingleton().isFalagardMappedType(wnd->getType()))
204         Property::writeXMLToStream(receiver, xml_stream);
205 }
206 
207 //----------------------------------------------------------------------------//
Window(const String & type,const String & name)208 Window::Window(const String& type, const String& name):
209     NamedElement(name),
210 
211     // basic types and initial window name
212     d_type(type),
213     d_autoWindow(false),
214 
215     // basic state
216     d_initialising(false),
217     d_destructionStarted(false),
218     d_enabled(true),
219     d_visible(true),
220     d_active(false),
221 
222     // parent related fields
223     d_destroyedByParent(true),
224 
225     // clipping options
226     d_clippedByParent(true),
227 
228     // rendering components and options
229     d_windowRenderer(0),
230     d_geometry(&System::getSingleton().getRenderer()->createGeometryBuffer()),
231     d_surface(0),
232     d_needsRedraw(true),
233     d_autoRenderingWindow(false),
234     d_mouseCursor(0),
235 
236     // alpha transparency set up
237     d_alpha(1.0f),
238     d_inheritsAlpha(true),
239 
240     // mouse input capture set up
241     d_oldCapture(0),
242     d_restoreOldCapture(false),
243     d_distCapturedInputs(false),
244 
245     // text system set up
246     d_font(0),
247 #ifndef CEGUI_BIDI_SUPPORT
248     d_bidiVisualMapping(0),
249 #elif defined (CEGUI_USE_FRIBIDI)
250     d_bidiVisualMapping(CEGUI_NEW_AO FribidiVisualMapping),
251 #elif defined (CEGUI_USE_MINIBIDI)
252     d_bidiVisualMapping(CEGUI_NEW_AO MinibidiVisualMapping),
253 #else
254     #error "BIDI Configuration is inconsistant, check your config!"
255 #endif
256     d_bidiDataValid(false),
257     d_renderedStringValid(false),
258     d_customStringParser(0),
259     d_textParsingEnabled(true),
260 
261     // margin
262     d_margin(UBox(UDim(0, 0))),
263 
264     // user specific data
265     d_ID(0),
266     d_userData(0),
267 
268     // z-order related options
269     d_alwaysOnTop(false),
270     d_riseOnClick(true),
271     d_zOrderingEnabled(true),
272 
273     // mouse input options
274     d_wantsMultiClicks(true),
275     d_mousePassThroughEnabled(false),
276     d_autoRepeat(false),
277     d_repeatDelay(0.3f),
278     d_repeatRate(0.06f),
279     d_repeatButton(NoButton),
280     d_repeating(false),
281     d_repeatElapsed(0.0f),
282 
283     // drag and drop
284     d_dragDropTarget(true),
285 
286     // tool tip related
287     d_customTip(0),
288     d_weOwnTip(false),
289     d_inheritsTipText(true),
290 
291     // XML writing options
292     d_allowWriteXML(true),
293 
294     // initialise area cache rects
295     d_outerRectClipper(0, 0, 0, 0),
296     d_innerRectClipper(0, 0, 0, 0),
297     d_hitTestRect(0, 0, 0, 0),
298 
299     // cached pixel rect validity flags
300     d_outerRectClipperValid(false),
301     d_innerRectClipperValid(false),
302     d_hitTestRectValid(false),
303 
304     // Initial update mode
305     d_updateMode(WUM_VISIBLE),
306 
307     // Don't propagate mouse inputs by default.
308     d_propagateMouseInputs(false),
309 
310     d_guiContext(0),
311 
312     d_containsMouse(false),
313 
314     d_fontRenderSizeChangeConnection(
315         GlobalEventSet::getSingleton().subscribeEvent(
316             "Font/RenderSizeChanged",
317             Event::Subscriber(&Window::handleFontRenderSizeChange, this)))
318 {
319     // add properties
320     addWindowProperties();
321 }
322 
323 //----------------------------------------------------------------------------//
~Window(void)324 Window::~Window(void)
325 {
326     // most cleanup actually happened earlier in Window::destroy.
327 
328     System::getSingleton().getRenderer()->destroyGeometryBuffer(*d_geometry);
329     CEGUI_DELETE_AO d_bidiVisualMapping;
330 }
331 
332 //----------------------------------------------------------------------------//
getType(void) const333 const String& Window::getType(void) const
334 {
335     return d_falagardType.empty() ? d_type : d_falagardType;
336 }
337 
338 //----------------------------------------------------------------------------//
isDisabled() const339 bool Window::isDisabled() const
340 {
341     return !d_enabled;
342 }
343 
344 //----------------------------------------------------------------------------//
isEffectiveDisabled() const345 bool Window::isEffectiveDisabled() const
346 {
347     const bool parent_disabled = !d_parent ? false : getParent()->isEffectiveDisabled();
348 
349     return !d_enabled || parent_disabled;
350 }
351 
352 //----------------------------------------------------------------------------//
isVisible() const353 bool Window::isVisible() const
354 {
355     return d_visible;
356 }
357 
358 //----------------------------------------------------------------------------//
isEffectiveVisible() const359 bool Window::isEffectiveVisible() const
360 {
361     const bool parent_visible = !d_parent ? true : getParent()->isEffectiveVisible();
362 
363     return d_visible && parent_visible;
364 }
365 
366 //----------------------------------------------------------------------------//
isActive(void) const367 bool Window::isActive(void) const
368 {
369     const bool parent_active = !d_parent ? true : getParent()->isActive();
370 
371     return d_active && parent_active;
372 }
373 
374 //----------------------------------------------------------------------------//
isChild(uint ID) const375 bool Window::isChild(uint ID) const
376 {
377     const size_t child_count = getChildCount();
378 
379     for (size_t i = 0; i < child_count; ++i)
380         if (getChildAtIdx(i)->getID() == ID)
381             return true;
382 
383     return false;
384 }
385 
386 //----------------------------------------------------------------------------//
isChildRecursive(uint ID) const387 bool Window::isChildRecursive(uint ID) const
388 {
389     const size_t child_count = getChildCount();
390 
391     for (size_t i = 0; i < child_count; ++i)
392         if (getChildAtIdx(i)->getID() == ID || getChildAtIdx(i)->isChildRecursive(ID))
393             return true;
394 
395     return false;
396 }
397 
398 //----------------------------------------------------------------------------//
getChild(uint ID) const399 Window* Window::getChild(uint ID) const
400 {
401     const size_t child_count = getChildCount();
402 
403     for (size_t i = 0; i < child_count; ++i)
404         if (getChildAtIdx(i)->getID() == ID)
405             return getChildAtIdx(i);
406 
407     char strbuf[16];
408     sprintf(strbuf, "%X", ID);
409     CEGUI_THROW(UnknownObjectException("A Window with ID: '" +
410         String(strbuf) + "' is not attached to Window '" + d_name + "'."));
411 }
412 
413 //----------------------------------------------------------------------------//
getChildRecursive(uint ID) const414 Window* Window::getChildRecursive(uint ID) const
415 {
416     const size_t child_count = getChildCount();
417 
418     std::queue<Element*> ElementsToSearch;
419 
420     for (size_t i = 0; i < child_count; ++i) // load all children into the queue
421     {
422         Element* child = getChildElementAtIdx(i);
423         ElementsToSearch.push(child);
424     }
425 
426     while (!ElementsToSearch.empty()) // breadth-first search for the child to find
427     {
428         Element* child = ElementsToSearch.front();
429         ElementsToSearch.pop();
430 
431         Window* window = dynamic_cast<Window*>(child);
432         if (window)
433         {
434             if (window->getID() == ID)
435             {
436                 return window;
437             }
438         }
439 
440         const size_t element_child_count = child->getChildCount();
441         for(size_t i = 0; i < element_child_count; ++i)
442         {
443             ElementsToSearch.push(child->getChildElementAtIdx(i));
444         }
445     }
446 
447     return 0;
448 }
449 
450 //----------------------------------------------------------------------------//
getActiveChild(void)451 Window* Window::getActiveChild(void)
452 {
453     return const_cast<Window*>(
454         static_cast<const Window*>(this)->getActiveChild());
455 }
456 
457 //----------------------------------------------------------------------------//
getActiveChild(void) const458 const Window* Window::getActiveChild(void) const
459 {
460     // are children can't be active if we are not
461     if (!isActive())
462         return 0;
463 
464     for (ChildDrawList::const_reverse_iterator it = d_drawList.rbegin(); it != d_drawList.rend(); ++it)
465     {
466         // don't need full backward scan for activeness as we already know
467         // 'this' is active.  NB: This uses the draw-ordered child list, as that
468         // should be quicker in most cases.
469 
470         const Window* wnd = *it;
471         if (wnd->d_active)
472             return wnd->getActiveChild();
473     }
474 
475     // no child was active, therefore we are the topmost active window
476     return this;
477 }
478 
479 //----------------------------------------------------------------------------//
isAncestor(uint ID) const480 bool Window::isAncestor(uint ID) const
481 {
482     // return false if we have no ancestor
483     if (!d_parent)
484         return false;
485 
486     // check our immediate parent
487     if (getParent()->getID() == ID)
488         return true;
489 
490     // not our parent, check back up the family line
491     return getParent()->isAncestor(ID);
492 }
493 
494 //----------------------------------------------------------------------------//
getFont(bool useDefault) const495 const Font* Window::getFont(bool useDefault) const
496 {
497     if (!d_font)
498         return useDefault ? getGUIContext().getDefaultFont() : 0;
499 
500     return d_font;
501 }
502 
503 //----------------------------------------------------------------------------//
getEffectiveAlpha(void) const504 float Window::getEffectiveAlpha(void) const
505 {
506     if (!d_parent || !inheritsAlpha())
507         return d_alpha;
508 
509     return d_alpha * getParent()->getEffectiveAlpha();
510 }
511 
512 //----------------------------------------------------------------------------//
getOuterRectClipper() const513 const Rectf& Window::getOuterRectClipper() const
514 {
515     if (!d_outerRectClipperValid)
516     {
517         d_outerRectClipper = getOuterRectClipper_impl();
518         d_outerRectClipperValid = true;
519     }
520 
521     return d_outerRectClipper;
522 }
523 
524 //----------------------------------------------------------------------------//
getInnerRectClipper() const525 const Rectf& Window::getInnerRectClipper() const
526 {
527     if (!d_innerRectClipperValid)
528     {
529         d_innerRectClipper = getInnerRectClipper_impl();
530         d_innerRectClipperValid = true;
531     }
532 
533     return d_innerRectClipper;
534 }
535 
536 //----------------------------------------------------------------------------//
getClipRect(const bool non_client) const537 const Rectf& Window::getClipRect(const bool non_client) const
538 {
539     return non_client ? getOuterRectClipper() : getInnerRectClipper();
540 }
541 
542 //----------------------------------------------------------------------------//
getHitTestRect() const543 const Rectf& Window::getHitTestRect() const
544 {
545     if (!d_hitTestRectValid)
546     {
547         d_hitTestRect = getHitTestRect_impl();
548         d_hitTestRectValid = true;
549     }
550 
551     return d_hitTestRect;
552 }
553 
554 //----------------------------------------------------------------------------//
getParentElementClipIntersection(const Rectf & unclipped_area) const555 Rectf Window::getParentElementClipIntersection(const Rectf& unclipped_area) const
556 {
557     return unclipped_area.getIntersection(
558         (d_parent && d_clippedByParent) ?
559             getParent()->getClipRect(isNonClient()) :
560             Rectf(Vector2f(0, 0), getRootContainerSize()));
561 }
562 
563 //----------------------------------------------------------------------------//
getUnclippedInnerRect_impl(bool skipAllPixelAlignment) const564 Rectf Window::getUnclippedInnerRect_impl(bool skipAllPixelAlignment) const
565 {
566     // TODO: skip all pixel alignment!
567     return d_windowRenderer ? d_windowRenderer->getUnclippedInnerRect() :
568                               (skipAllPixelAlignment ? getUnclippedOuterRect().getFresh(true) : getUnclippedOuterRect().get());
569 }
570 
571 //----------------------------------------------------------------------------//
getOuterRectClipper_impl() const572 Rectf Window::getOuterRectClipper_impl() const
573 {
574     return (d_surface && d_surface->isRenderingWindow()) ?
575         getUnclippedOuterRect().get() :
576         getParentElementClipIntersection(getUnclippedOuterRect().get());
577 }
578 
579 //----------------------------------------------------------------------------//
getInnerRectClipper_impl() const580 Rectf Window::getInnerRectClipper_impl() const
581 {
582     return (d_surface && d_surface->isRenderingWindow()) ?
583         getUnclippedInnerRect().get() :
584         getParentElementClipIntersection(getUnclippedInnerRect().get());
585 }
586 
587 //----------------------------------------------------------------------------//
getHitTestRect_impl() const588 Rectf Window::getHitTestRect_impl() const
589 {
590     // if clipped by parent wnd, hit test area is the intersection of our
591     // outer rect with the parent's hit test area intersected with the
592     // parent's clipper.
593     if (d_parent && d_clippedByParent)
594     {
595         return getUnclippedOuterRect().get().getIntersection(
596             getParent()->getHitTestRect().getIntersection(
597                 getParent()->getClipRect(isNonClient())));
598     }
599     // not clipped to parent wnd, so get intersection with screen area.
600     else
601     {
602         return getUnclippedOuterRect().get().getIntersection(
603             Rectf(Vector2f(0, 0), getRootContainerSize()));
604     }
605 }
606 
607 //----------------------------------------------------------------------------//
isHit(const Vector2f & position,const bool allow_disabled) const608 bool Window::isHit(const Vector2f& position, const bool allow_disabled) const
609 {
610     // cannot be hit if we are disabled.
611     if (!allow_disabled && isEffectiveDisabled())
612         return false;
613 
614     const Rectf test_area(getHitTestRect());
615 
616     if ((test_area.getWidth() == 0.0f) || (test_area.getHeight() == 0.0f))
617         return false;
618 
619     return test_area.isPointInRect(position);
620 }
621 
622 //----------------------------------------------------------------------------//
getChildAtPosition(const Vector2f & position) const623 Window* Window::getChildAtPosition(const Vector2f& position) const
624 {
625     return getChildAtPosition(position, &Window::isHit);
626 }
627 
628 //----------------------------------------------------------------------------//
getChildAtPosition(const Vector2f & position,bool (Window::* hittestfunc)(const Vector2f &,bool)const,bool allow_disabled) const629 Window* Window::getChildAtPosition(const Vector2f& position,
630                     bool (Window::*hittestfunc)(const Vector2f&, bool) const,
631                     bool allow_disabled) const
632 {
633     Vector2f p;
634     // if the window has RenderingWindow backing
635     if (d_surface && d_surface->isRenderingWindow())
636         static_cast<RenderingWindow*>(d_surface)->unprojectPoint(position, p);
637     else
638         p = position;
639 
640     const ChildDrawList::const_reverse_iterator end = d_drawList.rend();
641     ChildDrawList::const_reverse_iterator child;
642 
643     for (child = d_drawList.rbegin(); child != end; ++child)
644     {
645         if ((*child)->isEffectiveVisible())
646         {
647             // recursively scan for hit on children of this child window...
648             if (Window* const wnd = (*child)->getChildAtPosition(p, hittestfunc, allow_disabled))
649                 return wnd;
650             // see if this child is hit and return it's pointer if it is
651             else if (((*child)->*hittestfunc)(p, allow_disabled))
652                 return *child;
653         }
654     }
655 
656     // nothing hit
657     return 0;
658 }
659 
660 //----------------------------------------------------------------------------//
getTargetChildAtPosition(const Vector2f & position,const bool allow_disabled) const661 Window* Window::getTargetChildAtPosition(const Vector2f& position,
662                                          const bool allow_disabled) const
663 {
664     return getChildAtPosition(position, &Window::isHitTargetWindow, allow_disabled);
665 }
666 
667 //----------------------------------------------------------------------------//
isHitTargetWindow(const Vector2f & position,bool allow_disabled) const668 bool Window::isHitTargetWindow(const Vector2f& position, bool allow_disabled) const
669 {
670     return !isMousePassThroughEnabled() && isHit(position, allow_disabled);
671 }
672 
673 //----------------------------------------------------------------------------//
setAlwaysOnTop(bool setting)674 void Window::setAlwaysOnTop(bool setting)
675 {
676     // only react to an actual change
677     if (isAlwaysOnTop() == setting)
678         return;
679 
680     d_alwaysOnTop = setting;
681 
682     // move us in front of sibling windows with the same 'always-on-top'
683     // setting as we have.
684     if (d_parent)
685     {
686         Window* const org_parent = getParent();
687 
688         org_parent->removeChild_impl(this);
689         org_parent->addChild_impl(this);
690 
691         onZChange_impl();
692     }
693 
694     WindowEventArgs args(this);
695     onAlwaysOnTopChanged(args);
696 }
697 
698 //----------------------------------------------------------------------------//
setEnabled(bool setting)699 void Window::setEnabled(bool setting)
700 {
701     // only react if setting has changed
702     if (d_enabled == setting)
703         return;
704 
705     d_enabled = setting;
706     WindowEventArgs args(this);
707 
708     if (d_enabled)
709     {
710         // check to see if the window is actually enabled (which depends
711         // upon all ancestor windows being enabled) we do this so that
712         // events we fire give an accurate indication of the state of a
713         // window.
714         if ((d_parent && !getParent()->isDisabled()) || !d_parent)
715             onEnabled(args);
716     }
717     else
718     {
719         onDisabled(args);
720     }
721 
722     getGUIContext().updateWindowContainingMouse();
723 }
724 
725 //----------------------------------------------------------------------------//
setDisabled(bool setting)726 void Window::setDisabled(bool setting)
727 {
728     setEnabled(!setting);
729 }
730 
731 //----------------------------------------------------------------------------//
setVisible(bool setting)732 void Window::setVisible(bool setting)
733 {
734     // only react if setting has changed
735     if (d_visible == setting)
736         return;
737 
738     d_visible = setting;
739     WindowEventArgs args(this);
740     d_visible ? onShown(args) : onHidden(args);
741 
742     getGUIContext().updateWindowContainingMouse();
743 }
744 
745 //----------------------------------------------------------------------------//
activate(void)746 void Window::activate(void)
747 {
748     // exit if the window is not visible, since a hidden window may not be the
749     // active window.
750     if (!isEffectiveVisible())
751         return;
752 
753     // force complete release of input capture.
754     // NB: This is not done via releaseCapture() because that has
755     // different behaviour depending on the restoreOldCapture setting.
756     if (getCaptureWindow() && getCaptureWindow() != this)
757     {
758         Window* const tmpCapture = getCaptureWindow();
759         getGUIContext().setInputCaptureWindow(0);
760 
761         WindowEventArgs args(0);
762         tmpCapture->onCaptureLost(args);
763     }
764 
765     moveToFront();
766 }
767 
768 //----------------------------------------------------------------------------//
deactivate(void)769 void Window::deactivate(void)
770 {
771     ActivationEventArgs args(this);
772     args.otherWindow = 0;
773     onDeactivated(args);
774 }
775 
776 //----------------------------------------------------------------------------//
setClippedByParent(bool setting)777 void Window::setClippedByParent(bool setting)
778 {
779     // only react if setting has changed
780     if (d_clippedByParent == setting)
781         return;
782 
783     d_clippedByParent = setting;
784     WindowEventArgs args(this);
785     onClippingChanged(args);
786 }
787 
788 //----------------------------------------------------------------------------//
setText(const String & text)789 void Window::setText(const String& text)
790 {
791     d_textLogical = text;
792     d_renderedStringValid = false;
793     d_bidiDataValid = false;
794 
795     WindowEventArgs args(this);
796     onTextChanged(args);
797 }
798 
799 //----------------------------------------------------------------------------//
setFont(const Font * font)800 void Window::setFont(const Font* font)
801 {
802     d_font = font;
803     d_renderedStringValid = false;
804     WindowEventArgs args(this);
805     onFontChanged(args);
806 }
807 
808 //----------------------------------------------------------------------------//
setFont(const String & name)809 void Window::setFont(const String& name)
810 {
811     setFont(!name.empty() ? &FontManager::getSingleton().get(name) : 0);
812 }
813 
814 //----------------------------------------------------------------------------//
removeChild(uint ID)815 void Window::removeChild(uint ID)
816 {
817     const size_t child_count = getChildCount();
818 
819     for (size_t i = 0; i < child_count; ++i)
820     {
821         if (getChildAtIdx(i)->getID() == ID)
822         {
823             removeChild(d_children[i]);
824             return;
825         }
826 
827     }
828 }
829 
830 //----------------------------------------------------------------------------//
createChild(const String & type,const String & name)831 Window* Window::createChild(const String& type, const String& name)
832 {
833     Window* ret = WindowManager::getSingleton().createWindow(type, name);
834     addChild(ret);
835 
836     return ret;
837 }
838 
839 //----------------------------------------------------------------------------//
destroyChild(Window * wnd)840 void Window::destroyChild(Window* wnd)
841 {
842     assert(isChild(wnd) && "Window you are attempting to destroy is not a child!");
843 
844     WindowManager::getSingleton().destroyWindow(wnd);
845 }
846 
847 //----------------------------------------------------------------------------//
destroyChild(const String & name_path)848 void Window::destroyChild(const String& name_path)
849 {
850     destroyChild(getChild(name_path));
851 }
852 
853 //----------------------------------------------------------------------------//
moveToFront()854 void Window::moveToFront()
855 {
856     moveToFront_impl(false);
857 }
858 
859 //----------------------------------------------------------------------------//
moveToFront_impl(bool wasClicked)860 bool Window::moveToFront_impl(bool wasClicked)
861 {
862     bool took_action = false;
863 
864     // if the window has no parent then we can have no siblings
865     if (!d_parent)
866     {
867         // perform initial activation if required.
868         if (!isActive())
869         {
870             took_action = true;
871             ActivationEventArgs args(this);
872             args.otherWindow = 0;
873             onActivated(args);
874         }
875 
876         return took_action;
877     }
878 
879     // bring parent window to front of it's siblings
880     took_action = getParent()->moveToFront_impl(wasClicked);
881 
882     // get immediate child of parent that is currently active (if any)
883     Window* const activeWnd = getActiveSibling();
884 
885     // if a change in active window has occurred
886     if (activeWnd != this)
887     {
888         took_action = true;
889 
890         // notify ourselves that we have become active
891         ActivationEventArgs args(this);
892         args.otherWindow = activeWnd;
893         onActivated(args);
894 
895         // notify any previously active window that it is no longer active
896         if (activeWnd)
897         {
898             args.window = activeWnd;
899             args.otherWindow = this;
900             args.handled = 0;
901             activeWnd->onDeactivated(args);
902         }
903     }
904 
905     // bring us to the front of our siblings
906     if (d_zOrderingEnabled &&
907         (!wasClicked || d_riseOnClick) &&
908         !isTopOfZOrder())
909     {
910         took_action = true;
911 
912         // remove us from our parent's draw list
913         getParent()->removeWindowFromDrawList(*this);
914         // re-attach ourselves to our parent's draw list which will move us in
915         // front of sibling windows with the same 'always-on-top' setting as we
916         // have.
917         getParent()->addWindowToDrawList(*this);
918         // notify relevant windows about the z-order change.
919         onZChange_impl();
920     }
921 
922     return took_action;
923 }
924 
925 //----------------------------------------------------------------------------//
moveToBack()926 void Window::moveToBack()
927 {
928     // if the window is active, de-activate it.
929     if (isActive())
930     {
931         ActivationEventArgs args(this);
932         args.otherWindow = 0;
933         onDeactivated(args);
934     }
935 
936     // we only proceed if we have a parent (otherwise we can have no siblings)
937     if (d_parent)
938     {
939         if (d_zOrderingEnabled)
940         {
941             // remove us from our parent's draw list
942             getParent()->removeWindowFromDrawList(*this);
943             // re-attach ourselves to our parent's draw list which will move us
944             // in behind sibling windows with the same 'always-on-top' setting
945             // as we have.
946             getParent()->addWindowToDrawList(*this, true);
947             // notify relevant windows about the z-order change.
948             onZChange_impl();
949         }
950 
951         getParent()->moveToBack();
952     }
953 }
954 
955 //----------------------------------------------------------------------------//
captureInput(void)956 bool Window::captureInput(void)
957 {
958     // we can only capture if we are the active window (LEAVE THIS ALONE!)
959     if (!isActive())
960         return false;
961 
962     if (!isCapturedByThis())
963     {
964         Window* const current_capture = getCaptureWindow();
965         getGUIContext().setInputCaptureWindow(this);
966         WindowEventArgs args(this);
967 
968         // inform window which previously had capture that it doesn't anymore.
969         if (current_capture && current_capture != this && !d_restoreOldCapture)
970             current_capture->onCaptureLost(args);
971 
972         if (d_restoreOldCapture)
973             d_oldCapture = current_capture;
974 
975         onCaptureGained(args);
976     }
977 
978     return true;
979 }
980 
981 //----------------------------------------------------------------------------//
releaseInput(void)982 void Window::releaseInput(void)
983 {
984     // if we are not the window that has capture, do nothing
985     if (!isCapturedByThis())
986         return;
987 
988     // restore old captured window if that mode is set
989     if (d_restoreOldCapture)
990     {
991         getGUIContext().setInputCaptureWindow(d_oldCapture);
992 
993         // check for case when there was no previously captured window
994         if (d_oldCapture)
995         {
996             d_oldCapture = 0;
997             getCaptureWindow()->moveToFront();
998         }
999 
1000     }
1001     else
1002         getGUIContext().setInputCaptureWindow(0);
1003 
1004     WindowEventArgs args(this);
1005     onCaptureLost(args);
1006 }
1007 
1008 //----------------------------------------------------------------------------//
setRestoreOldCapture(bool setting)1009 void Window::setRestoreOldCapture(bool setting)
1010 {
1011     d_restoreOldCapture = setting;
1012 
1013     const size_t child_count = getChildCount();
1014 
1015     for (size_t i = 0; i < child_count; ++i)
1016         getChildAtIdx(i)->setRestoreOldCapture(setting);
1017 }
1018 
1019 //----------------------------------------------------------------------------//
setAlpha(const float alpha)1020 void Window::setAlpha(const float alpha)
1021 {
1022     // clamp this to the valid range [0.0, 1.0]
1023     float clampedAlpha = ceguimax(ceguimin(alpha, 1.0f), 0.0f);
1024 
1025     // Ensure that the new alpha value is actually different from the currently set one
1026     // to avoid unnecessary invalidating and re-caching of textures and children
1027     if (d_alpha == clampedAlpha)
1028         return;
1029 
1030     d_alpha = clampedAlpha;
1031 
1032     WindowEventArgs args(this);
1033     onAlphaChanged(args);
1034 }
1035 
1036 //----------------------------------------------------------------------------//
setInheritsAlpha(bool setting)1037 void Window::setInheritsAlpha(bool setting)
1038 {
1039     if (d_inheritsAlpha != setting)
1040     {
1041         // store old effective alpha so we can test if alpha value changes due
1042         // to new setting.
1043         const float oldAlpha = getEffectiveAlpha();
1044 
1045         // notify about the setting change.
1046         d_inheritsAlpha = setting;
1047 
1048         WindowEventArgs args(this);
1049         onInheritsAlphaChanged(args);
1050 
1051         // if effective alpha has changed fire notification about that too
1052         if (oldAlpha != getEffectiveAlpha())
1053         {
1054             args.handled = 0;
1055             onAlphaChanged(args);
1056         }
1057     }
1058 }
1059 
1060 //----------------------------------------------------------------------------//
invalidate(void)1061 void Window::invalidate(void)
1062 {
1063     invalidate(false);
1064 }
1065 
1066 //----------------------------------------------------------------------------//
invalidate(const bool recursive)1067 void Window::invalidate(const bool recursive)
1068 {
1069     invalidate_impl(recursive);
1070     getGUIContext().markAsDirty();
1071 }
1072 
1073 //----------------------------------------------------------------------------//
invalidate_impl(const bool recursive)1074 void Window::invalidate_impl(const bool recursive)
1075 {
1076     d_needsRedraw = true;
1077     invalidateRenderingSurface();
1078 
1079     WindowEventArgs args(this);
1080     onInvalidated(args);
1081 
1082     if (recursive)
1083     {
1084         const size_t child_count = getChildCount();
1085         for (size_t i = 0; i < child_count; ++i)
1086             getChildAtIdx(i)->invalidate_impl(true);
1087     }
1088 }
1089 
1090 //----------------------------------------------------------------------------//
render()1091 void Window::render()
1092 {
1093     // don't do anything if window is not visible
1094     if (!isEffectiveVisible())
1095         return;
1096 
1097     // get rendering context
1098     RenderingContext ctx;
1099     getRenderingContext(ctx);
1100 
1101     // clear geometry from surface if it's ours
1102     if (ctx.owner == this)
1103         ctx.surface->clearGeometry();
1104 
1105     // redraw if no surface set, or if surface is invalidated
1106     if (!d_surface || d_surface->isInvalidated())
1107     {
1108         // perform drawing for 'this' Window
1109         drawSelf(ctx);
1110 
1111         // render any child windows
1112         for (ChildDrawList::iterator it = d_drawList.begin(); it != d_drawList.end(); ++it)
1113         {
1114             (*it)->render();
1115         }
1116     }
1117 
1118     // do final rendering for surface if it's ours
1119     if (ctx.owner == this)
1120         ctx.surface->draw();
1121 }
1122 
1123 //----------------------------------------------------------------------------//
drawSelf(const RenderingContext & ctx)1124 void Window::drawSelf(const RenderingContext& ctx)
1125 {
1126     bufferGeometry(ctx);
1127     queueGeometry(ctx);
1128 }
1129 
1130 //----------------------------------------------------------------------------//
bufferGeometry(const RenderingContext &)1131 void Window::bufferGeometry(const RenderingContext&)
1132 {
1133     if (d_needsRedraw)
1134     {
1135         // dispose of already cached geometry.
1136         d_geometry->reset();
1137 
1138         // signal rendering started
1139         WindowEventArgs args(this);
1140         onRenderingStarted(args);
1141 
1142         // HACK: ensure our rendered string content is up to date
1143         getRenderedString();
1144 
1145         // get derived class or WindowRenderer to re-populate geometry buffer.
1146         if (d_windowRenderer)
1147             d_windowRenderer->render();
1148         else
1149             populateGeometryBuffer();
1150 
1151         // signal rendering ended
1152         args.handled = 0;
1153         onRenderingEnded(args);
1154 
1155         // mark ourselves as no longer needed a redraw.
1156         d_needsRedraw = false;
1157     }
1158 }
1159 
1160 //----------------------------------------------------------------------------//
queueGeometry(const RenderingContext & ctx)1161 void Window::queueGeometry(const RenderingContext& ctx)
1162 {
1163     // add geometry so that it gets drawn to the target surface.
1164     ctx.surface->addGeometryBuffer(ctx.queue, *d_geometry);
1165 }
1166 
1167 //----------------------------------------------------------------------------//
setParent(Element * parent)1168 void Window::setParent(Element* parent)
1169 {
1170     Element::setParent(parent);
1171     syncTargetSurface();
1172 }
1173 
1174 //----------------------------------------------------------------------------//
syncTargetSurface()1175 void Window::syncTargetSurface()
1176 {
1177     // if we do not have a surface, xfer any surfaces from our children to
1178     // whatever our target surface now is.
1179     if (!d_surface)
1180         transferChildSurfaces();
1181     // else, since we have a surface, child surfaces stay with us.  Though we
1182     // must now ensure /our/ surface is xferred if it is a RenderingWindow.
1183     else if (d_surface->isRenderingWindow())
1184     {
1185         // target surface is eihter the parent's target, or the gui context.
1186         RenderingSurface& tgt = d_parent ?
1187             getParent()->getTargetRenderingSurface() : getGUIContext();
1188 
1189         tgt.transferRenderingWindow(static_cast<RenderingWindow&>(*d_surface));
1190     }
1191 }
1192 
1193 //----------------------------------------------------------------------------//
cleanupChildren(void)1194 void Window::cleanupChildren(void)
1195 {
1196     while(getChildCount() != 0)
1197     {
1198         Window* wnd = static_cast<Window*>(d_children[0]);
1199 
1200         // always remove child
1201         removeChild(wnd);
1202 
1203         // destroy child if that is required
1204         if (wnd->isDestroyedByParent())
1205             WindowManager::getSingleton().destroyWindow(wnd);
1206     }
1207 }
1208 
1209 //----------------------------------------------------------------------------//
addChild_impl(Element * element)1210 void Window::addChild_impl(Element* element)
1211 {
1212     Window* wnd = dynamic_cast<Window*>(element);
1213 
1214     if (!wnd)
1215         CEGUI_THROW(InvalidRequestException(
1216             "Window can only have Elements of type Window added as children "
1217             "(Window path: " + getNamePath() + ")."));
1218 
1219     // if the element is already a child of this Window, this is a NOOP
1220     if (isChild(element))
1221         return;
1222 
1223     NamedElement::addChild_impl(wnd);
1224 
1225     addWindowToDrawList(*wnd);
1226 
1227     wnd->invalidate(true);
1228 
1229     wnd->onZChange_impl();
1230 }
1231 
1232 //----------------------------------------------------------------------------//
removeChild_impl(Element * element)1233 void Window::removeChild_impl(Element* element)
1234 {
1235     Window* wnd = static_cast<Window*>(element);
1236 
1237     Window* const capture_wnd = getCaptureWindow();
1238     if ((capture_wnd && wnd) &&
1239         (capture_wnd == wnd || capture_wnd->isAncestor(wnd)))
1240             getCaptureWindow()->releaseInput();
1241 
1242     // remove from draw list
1243     removeWindowFromDrawList(*wnd);
1244 
1245     Element::removeChild_impl(wnd);
1246 
1247     // find this window in the child list
1248     const ChildList::iterator position =
1249         std::find(d_children.begin(), d_children.end(), wnd);
1250 
1251     // if the window was found in the child list
1252     if (position != d_children.end())
1253     {
1254         // unban properties window could write as a root window
1255         wnd->unbanPropertyFromXML(RestoreOldCapturePropertyName);
1256     }
1257 
1258     wnd->onZChange_impl();
1259 
1260     // Removed windows should not be active anymore (they are not attached
1261     // to anything so this would not make sense)
1262     if(wnd->isActive())
1263     {
1264         wnd->deactivate();
1265     }
1266 }
1267 
1268 //----------------------------------------------------------------------------//
onZChange_impl(void)1269 void Window::onZChange_impl(void)
1270 {
1271     if (!d_parent)
1272     {
1273         WindowEventArgs args(this);
1274         onZChanged(args);
1275     }
1276     else
1277     {
1278         const size_t child_count = d_parent->getChildCount();
1279 
1280         for (size_t i = 0; i < child_count; ++i)
1281         {
1282             WindowEventArgs args(getParent()->getChildAtIdx(i));
1283             getParent()->getChildAtIdx(i)->onZChanged(args);
1284         }
1285 
1286     }
1287 
1288     getGUIContext().updateWindowContainingMouse();
1289 }
1290 
1291 //----------------------------------------------------------------------------//
getMouseCursor(bool useDefault) const1292 const Image* Window::getMouseCursor(bool useDefault) const
1293 {
1294     if (d_mouseCursor)
1295         return d_mouseCursor;
1296     else
1297         return useDefault ? getGUIContext().getMouseCursor().getDefaultImage() : 0;
1298 }
1299 
1300 //----------------------------------------------------------------------------//
setMouseCursor(const String & name)1301 void Window::setMouseCursor(const String& name)
1302 {
1303     setMouseCursor(
1304         &ImageManager::getSingleton().get(name));
1305 }
1306 
1307 //----------------------------------------------------------------------------//
setMouseCursor(const Image * image)1308 void Window::setMouseCursor(const Image* image)
1309 {
1310     d_mouseCursor = image;
1311 
1312     if (getGUIContext().getWindowContainingMouse() == this)
1313         getGUIContext().getMouseCursor().setImage(image);
1314 }
1315 
1316 //----------------------------------------------------------------------------//
setID(uint ID)1317 void Window::setID(uint ID)
1318 {
1319     if (d_ID == ID)
1320         return;
1321 
1322     d_ID = ID;
1323 
1324     WindowEventArgs args(this);
1325     onIDChanged(args);
1326 }
1327 
1328 //----------------------------------------------------------------------------//
setDestroyedByParent(bool setting)1329 void Window::setDestroyedByParent(bool setting)
1330 {
1331     if (d_destroyedByParent == setting)
1332         return;
1333 
1334     d_destroyedByParent = setting;
1335 
1336     WindowEventArgs args(this);
1337     onParentDestroyChanged(args);
1338 }
1339 
1340 //----------------------------------------------------------------------------//
generateAutoRepeatEvent(MouseButton button)1341 void Window::generateAutoRepeatEvent(MouseButton button)
1342 {
1343     MouseEventArgs ma(this);
1344     ma.position = getUnprojectedPosition(
1345         getGUIContext().getMouseCursor().getPosition());
1346     ma.moveDelta = Vector2f(0.0f, 0.0f);
1347     ma.button = button;
1348     ma.sysKeys = getGUIContext().getSystemKeys().get();
1349     ma.wheelChange = 0;
1350     onMouseButtonDown(ma);
1351 }
1352 
1353 //----------------------------------------------------------------------------//
addWindowProperties(void)1354 void Window::addWindowProperties(void)
1355 {
1356     const String propertyOrigin("Window");
1357 
1358     CEGUI_DEFINE_PROPERTY(Window, float,
1359         AlphaPropertyName, "Property to get/set the alpha value of the Window. Value is floating point number.",
1360         &Window::setAlpha, &Window::getAlpha, 1.0f
1361     );
1362 
1363     CEGUI_DEFINE_PROPERTY(Window, bool,
1364         AlwaysOnTopPropertyName, "Property to get/set the 'always on top' setting for the Window. Value is either \"true\" or \"false\".",
1365         &Window::setAlwaysOnTop, &Window::isAlwaysOnTop, false
1366     );
1367 
1368     CEGUI_DEFINE_PROPERTY(Window, bool,
1369         ClippedByParentPropertyName, "Property to get/set the 'clipped by parent' setting for the Window. Value is either \"true\" or \"false\".",
1370         &Window::setClippedByParent, &Window::isClippedByParent, true
1371     );
1372 
1373     CEGUI_DEFINE_PROPERTY(Window, bool,
1374         DestroyedByParentPropertyName, "Property to get/set the 'destroyed by parent' setting for the Window. Value is either \"true\" or \"false\".",
1375         &Window::setDestroyedByParent, &Window::isDestroyedByParent, true
1376     );
1377 
1378     CEGUI_DEFINE_PROPERTY(Window, bool,
1379         DisabledPropertyName, "Property to get/set the 'disabled state' setting for the Window.  Value is either \"true\" or \"false\".",
1380         &Window::setDisabled, &Window::isDisabled, false
1381     );
1382 
1383     CEGUI_DEFINE_PROPERTY(Window, Font*,
1384         FontPropertyName,"Property to get/set the font for the Window.  Value is the name of the font to use (must be loaded already).",
1385         &Window::setFont, &Window::property_getFont, 0
1386     );
1387 
1388     CEGUI_DEFINE_PROPERTY(Window, uint,
1389         IDPropertyName, "Property to get/set the ID value of the Window. Value is an unsigned integer number.",
1390         &Window::setID, &Window::getID, 0
1391     );
1392 
1393     CEGUI_DEFINE_PROPERTY(Window, bool,
1394         InheritsAlphaPropertyName, "Property to get/set the 'inherits alpha' setting for the Window. Value is either \"true\" or \"false\".",
1395         &Window::setInheritsAlpha, &Window::inheritsAlpha, true
1396     );
1397 
1398     CEGUI_DEFINE_PROPERTY(Window, Image*,
1399         MouseCursorImagePropertyName,"Property to get/set the mouse cursor image for the Window.  Value should be \"<image name>\".",
1400         &Window::setMouseCursor, &Window::property_getMouseCursor, 0
1401     );
1402 
1403     CEGUI_DEFINE_PROPERTY(Window, bool,
1404         VisiblePropertyName, "Property to get/set the 'visible state' setting for the Window. Value is either \"true\" or \"false\".",
1405         &Window::setVisible, &Window::isVisible, true
1406     );
1407 
1408     CEGUI_DEFINE_PROPERTY(Window, bool,
1409         RestoreOldCapturePropertyName, "Property to get/set the 'restore old capture' setting for the Window. Value is either \"true\" or \"false\".",
1410         &Window::setRestoreOldCapture, &Window::restoresOldCapture, false
1411     );
1412 
1413     CEGUI_DEFINE_PROPERTY(Window, String,
1414         TextPropertyName, "Property to get/set the text / caption for the Window. Value is the text string to use. Meaning of this property heavily depends on the type of the Window.",
1415         &Window::setText, &Window::getText, ""
1416     );
1417 
1418     CEGUI_DEFINE_PROPERTY(Window, bool,
1419         ZOrderingEnabledPropertyName, "Property to get/set the 'z-order changing enabled' setting for the Window. Value is either \"true\" or \"false\".",
1420         &Window::setZOrderingEnabled, &Window::isZOrderingEnabled, true
1421     );
1422 
1423     CEGUI_DEFINE_PROPERTY(Window, bool,
1424         WantsMultiClickEventsPropertyName, "Property to get/set whether the window will receive double-click and triple-click events. Value is either \"true\" or \"false\".",
1425         &Window::setWantsMultiClickEvents, &Window::wantsMultiClickEvents, true
1426     );
1427 
1428     CEGUI_DEFINE_PROPERTY(Window, bool,
1429         MouseAutoRepeatEnabledPropertyName, "Property to get/set whether the window will receive autorepeat mouse button down events. Value is either \"true\" or \"false\".",
1430         &Window::setMouseAutoRepeatEnabled, &Window::isMouseAutoRepeatEnabled, false
1431     );
1432 
1433     CEGUI_DEFINE_PROPERTY(Window, float,
1434         AutoRepeatDelayPropertyName, "Property to get/set the autorepeat delay. Value is a floating point number indicating the delay required in seconds.",
1435         &Window::setAutoRepeatDelay, &Window::getAutoRepeatDelay, 0.3f
1436     );
1437 
1438     CEGUI_DEFINE_PROPERTY(Window, float,
1439         AutoRepeatRatePropertyName, "Property to get/set the autorepeat rate. Value is a floating point number indicating the rate required in seconds.",
1440         &Window::setAutoRepeatRate, &Window::getAutoRepeatRate, 0.06f
1441     );
1442 
1443     CEGUI_DEFINE_PROPERTY(Window, bool,
1444         DistributeCapturedInputsPropertyName, "Property to get/set whether captured inputs are passed to child windows. Value is either \"true\" or \"false\".",
1445         &Window::setDistributesCapturedInputs, &Window::distributesCapturedInputs, false
1446     );
1447 
1448     CEGUI_DEFINE_PROPERTY(Window, String,
1449         TooltipTypePropertyName, "Property to get/set the custom tooltip for the window. Value is the type name of the custom tooltip. If \"\", the default System tooltip is used.",
1450         &Window::setTooltipType, &Window::getTooltipType, ""
1451     );
1452 
1453     CEGUI_DEFINE_PROPERTY(Window, String,
1454         TooltipTextPropertyName, "Property to get/set the tooltip text for the window. Value is the tooltip text for the window.",
1455         &Window::setTooltipText, &Window::getTooltipText, ""
1456     );
1457 
1458     CEGUI_DEFINE_PROPERTY(Window, bool,
1459         InheritsTooltipTextPropertyName, "Property to get/set whether the window inherits its parents tooltip text when it has none of its own. Value is either \"true\" or \"false\".",
1460         &Window::setInheritsTooltipText, &Window::inheritsTooltipText, true
1461     );
1462 
1463     CEGUI_DEFINE_PROPERTY(Window, bool,
1464         RiseOnClickEnabledPropertyName, "Property to get/set whether the window will come to the top of the Z-order when clicked. Value is either \"true\" or \"false\".",
1465         &Window::setRiseOnClickEnabled, &Window::isRiseOnClickEnabled, true
1466     );
1467 
1468     CEGUI_DEFINE_PROPERTY(Window, bool,
1469         MousePassThroughEnabledPropertyName, "Property to get/set whether the window ignores mouse events and pass them through to any windows behind it. Value is either \"true\" or \"false\".",
1470         &Window::setMousePassThroughEnabled, &Window::isMousePassThroughEnabled, false
1471     );
1472 
1473     addProperty(&d_windowRendererProperty);
1474     addProperty(&d_lookNFeelProperty);
1475 
1476     CEGUI_DEFINE_PROPERTY(Window, bool,
1477         DragDropTargetPropertyName, "Property to get/set whether the Window will receive drag and drop related notifications.  Value is either \"true\" or \"false\".",
1478         &Window::setDragDropTarget, &Window::isDragDropTarget, true
1479     );
1480 
1481     CEGUI_DEFINE_PROPERTY(Window, bool,
1482         AutoRenderingSurfacePropertyName, "Property to get/set whether the Window will automatically attempt to "
1483         "use a full imagery caching RenderingSurface (if supported by the "
1484         "renderer).  Here, full imagery caching usually will mean caching a "
1485         "window's representation onto a texture (although no such "
1486         "implementation requirement is specified.)"
1487         "  Value is either \"true\" or \"false\".",
1488         &Window::setUsingAutoRenderingSurface, &Window::isUsingAutoRenderingSurface, false /* TODO: Inconsistency*/
1489     );
1490 
1491     CEGUI_DEFINE_PROPERTY(Window, bool,
1492         TextParsingEnabledPropertyName, "Property to get/set the text parsing setting for the Window.  "
1493         "Value is either \"true\" or \"false\".",
1494         &Window::setTextParsingEnabled, &Window::isTextParsingEnabled, true
1495     );
1496 
1497     CEGUI_DEFINE_PROPERTY(Window, UBox,
1498         MarginPropertyName, "Property to get/set margin for the Window. Value format:"
1499         "{top:{[tops],[topo]},left:{[lefts],[lefto]},bottom:{[bottoms],[bottomo]},right:{[rights],[righto]}}.",
1500         &Window::setMargin, &Window::getMargin, UBox(UDim(0, 0))
1501     );
1502 
1503     CEGUI_DEFINE_PROPERTY(Window, WindowUpdateMode,
1504         UpdateModePropertyName, "Property to get/set the window update mode setting.  "
1505         "Value is one of \"Always\", \"Never\" or \"Visible\".",
1506         &Window::setUpdateMode,&Window::getUpdateMode, WUM_VISIBLE
1507     );
1508 
1509     CEGUI_DEFINE_PROPERTY(Window, bool,
1510         MouseInputPropagationEnabledPropertyName, "Property to get/set whether unhandled mouse inputs should be "
1511         "propagated back to the Window's parent.  "
1512         "Value is either \"true\" or \"false\".",
1513         &Window::setMouseInputPropagationEnabled, &Window::isMouseInputPropagationEnabled, false
1514     );
1515 
1516     CEGUI_DEFINE_PROPERTY(Window, bool,
1517         AutoWindowPropertyName, "Property to get/set whether the system considers this window to be an "
1518         "automatically created sub-component window."
1519         "Value is either \"true\" or \"false\".",
1520         &Window::setAutoWindow, &Window::isAutoWindow, false
1521     );
1522 }
1523 
1524 //----------------------------------------------------------------------------//
isZOrderingEnabled(void) const1525 bool Window::isZOrderingEnabled(void) const
1526 {
1527     return d_zOrderingEnabled;
1528 }
1529 
1530 //----------------------------------------------------------------------------//
setZOrderingEnabled(bool setting)1531 void Window::setZOrderingEnabled(bool setting)
1532 {
1533     d_zOrderingEnabled = setting;
1534 }
1535 
1536 //----------------------------------------------------------------------------//
wantsMultiClickEvents(void) const1537 bool Window::wantsMultiClickEvents(void) const
1538 {
1539     return d_wantsMultiClicks;
1540 }
1541 
1542 //----------------------------------------------------------------------------//
setWantsMultiClickEvents(bool setting)1543 void Window::setWantsMultiClickEvents(bool setting)
1544 {
1545     d_wantsMultiClicks = setting;
1546 }
1547 
1548 //----------------------------------------------------------------------------//
isMouseAutoRepeatEnabled(void) const1549 bool Window::isMouseAutoRepeatEnabled(void) const
1550 {
1551     return d_autoRepeat;
1552 }
1553 
1554 //----------------------------------------------------------------------------//
getAutoRepeatDelay(void) const1555 float Window::getAutoRepeatDelay(void) const
1556 {
1557     return d_repeatDelay;
1558 }
1559 
1560 //----------------------------------------------------------------------------//
getAutoRepeatRate(void) const1561 float Window::getAutoRepeatRate(void) const
1562 {
1563     return d_repeatRate;
1564 }
1565 
1566 //----------------------------------------------------------------------------//
setMouseAutoRepeatEnabled(bool setting)1567 void Window::setMouseAutoRepeatEnabled(bool setting)
1568 {
1569     if (d_autoRepeat == setting)
1570         return;
1571 
1572     d_autoRepeat = setting;
1573     d_repeatButton = NoButton;
1574 
1575     // FIXME: There is a potential issue here if this setting is
1576     // FIXME: changed _while_ the mouse is auto-repeating, and
1577     // FIXME: the 'captured' state of input could get messed up.
1578     // FIXME: The alternative is to always release here, but that
1579     // FIXME: has a load of side effects too - so for now nothing
1580     // FIXME: is done.  This whole aspect of the system needs a
1581     // FIXME: review an reworking - though such a change was
1582     // FIXME: beyond the scope of the bug-fix that originated this
1583     // FIXME: comment block.  PDT - 30/10/06
1584 }
1585 
1586 //----------------------------------------------------------------------------//
setAutoRepeatDelay(float delay)1587 void Window::setAutoRepeatDelay(float delay)
1588 {
1589     d_repeatDelay = delay;
1590 }
1591 
1592 //----------------------------------------------------------------------------//
setAutoRepeatRate(float rate)1593 void Window::setAutoRepeatRate(float rate)
1594 {
1595     d_repeatRate = rate;
1596 }
1597 
1598 //----------------------------------------------------------------------------//
update(float elapsed)1599 void Window::update(float elapsed)
1600 {
1601     // perform update for 'this' Window
1602     updateSelf(elapsed);
1603 
1604     // update underlying RenderingWinodw if needed
1605     if (d_surface && d_surface->isRenderingWindow())
1606         static_cast<RenderingWindow*>(d_surface)->update(elapsed);
1607 
1608     UpdateEventArgs e(this,elapsed);
1609     fireEvent(EventUpdated,e,EventNamespace);
1610 
1611     // update child windows
1612     for (size_t i = 0; i < getChildCount(); ++i)
1613     {
1614         // update children based on their WindowUpdateMode setting.
1615         if (getChildAtIdx(i)->d_updateMode == WUM_ALWAYS ||
1616                 (getChildAtIdx(i)->d_updateMode == WUM_VISIBLE &&
1617                  getChildAtIdx(i)->isVisible()))
1618         {
1619             getChildAtIdx(i)->update(elapsed);
1620         }
1621     }
1622 }
1623 
1624 //----------------------------------------------------------------------------//
updateSelf(float elapsed)1625 void Window::updateSelf(float elapsed)
1626 {
1627     // Mouse button autorepeat processing.
1628     if (d_autoRepeat && d_repeatButton != NoButton)
1629     {
1630         d_repeatElapsed += elapsed;
1631 
1632         if (d_repeating)
1633         {
1634             if (d_repeatElapsed > d_repeatRate)
1635             {
1636                 d_repeatElapsed -= d_repeatRate;
1637                 // trigger the repeated event
1638                 generateAutoRepeatEvent(d_repeatButton);
1639             }
1640         }
1641         else
1642         {
1643             if (d_repeatElapsed > d_repeatDelay)
1644             {
1645                 d_repeatElapsed = 0;
1646                 d_repeating = true;
1647                 // trigger the repeated event
1648                 generateAutoRepeatEvent(d_repeatButton);
1649             }
1650         }
1651     }
1652 
1653     // allow for updates within an assigned WindowRenderer
1654     if (d_windowRenderer)
1655         d_windowRenderer->update(elapsed);
1656 }
1657 
1658 //----------------------------------------------------------------------------//
performCopy(Clipboard &)1659 bool Window::performCopy(Clipboard& /*clipboard*/)
1660 {
1661     // deny copying by default
1662     return false;
1663 }
1664 
1665 //----------------------------------------------------------------------------//
performCut(Clipboard &)1666 bool Window::performCut(Clipboard& /*clipboard*/)
1667 {
1668     // deny cutting by default
1669     return false;
1670 }
1671 
1672 //----------------------------------------------------------------------------//
performPaste(Clipboard &)1673 bool Window::performPaste(Clipboard& /*clipboard*/)
1674 {
1675     // deny pasting by default
1676     return false;
1677 }
1678 
1679 //----------------------------------------------------------------------------//
distributesCapturedInputs(void) const1680 bool Window::distributesCapturedInputs(void) const
1681 {
1682     return d_distCapturedInputs;
1683 }
1684 
1685 //----------------------------------------------------------------------------//
setDistributesCapturedInputs(bool setting)1686 void Window::setDistributesCapturedInputs(bool setting)
1687 {
1688     d_distCapturedInputs = setting;
1689 }
1690 
1691 //----------------------------------------------------------------------------//
notifyDragDropItemEnters(DragContainer * item)1692 void Window::notifyDragDropItemEnters(DragContainer* item)
1693 {
1694     if (!item)
1695         return;
1696 
1697     DragDropEventArgs args(this);
1698     args.dragDropItem = item;
1699     onDragDropItemEnters(args);
1700 }
1701 
1702 //----------------------------------------------------------------------------//
notifyDragDropItemLeaves(DragContainer * item)1703 void Window::notifyDragDropItemLeaves(DragContainer* item)
1704 {
1705     if (!item)
1706         return;
1707 
1708     DragDropEventArgs args(this);
1709     args.dragDropItem = item;
1710     onDragDropItemLeaves(args);
1711 }
1712 
1713 //----------------------------------------------------------------------------//
notifyDragDropItemDropped(DragContainer * item)1714 void Window::notifyDragDropItemDropped(DragContainer* item)
1715 {
1716     if (!item)
1717         return;
1718 
1719     DragDropEventArgs args(this);
1720     args.dragDropItem = item;
1721     onDragDropItemDropped(args);
1722 }
1723 
1724 //----------------------------------------------------------------------------//
destroy(void)1725 void Window::destroy(void)
1726 {
1727     // because we know that people do not read the API ref properly,
1728     // here is some protection to ensure that WindowManager does the
1729     // destruction and not anyone else.
1730     WindowManager& wmgr = WindowManager::getSingleton();
1731 
1732     if (wmgr.isAlive(this))
1733     {
1734         wmgr.destroyWindow(this);
1735 
1736         // now return, the rest of what we need to do will happen
1737         // once WindowManager re-calls this method.
1738         return;
1739     }
1740 
1741     // signal our imminent destruction
1742     WindowEventArgs args(this);
1743     onDestructionStarted(args);
1744 
1745     // Check we are detached from parent
1746     if (d_parent)
1747         d_parent->removeChild(this);
1748 
1749     releaseInput();
1750 
1751     // let go of the tooltip if we have it
1752     Tooltip* const tip = getTooltip();
1753     if (tip && tip->getTargetWindow()==this)
1754         tip->setTargetWindow(0);
1755 
1756     // ensure custom tooltip is cleaned up
1757     setTooltip(static_cast<Tooltip*>(0));
1758 
1759 
1760 
1761     // clean up looknfeel related things
1762     if (!d_lookName.empty())
1763     {
1764         d_windowRenderer->onLookNFeelUnassigned();
1765         WidgetLookManager::getSingleton().getWidgetLook(d_lookName).
1766             cleanUpWidget(*this);
1767     }
1768 
1769     // free any assigned WindowRenderer
1770     if (d_windowRenderer != 0)
1771     {
1772         d_windowRenderer->onDetach();
1773         WindowRendererManager::getSingleton().
1774             destroyWindowRenderer(d_windowRenderer);
1775         d_windowRenderer = 0;
1776     }
1777 
1778     cleanupChildren();
1779 
1780     releaseRenderingWindow();
1781     invalidate();
1782 }
1783 
1784 //----------------------------------------------------------------------------//
isUsingDefaultTooltip(void) const1785 bool Window::isUsingDefaultTooltip(void) const
1786 {
1787     return d_customTip == 0;
1788 }
1789 
1790 //----------------------------------------------------------------------------//
getTooltip(void) const1791 Tooltip* Window::getTooltip(void) const
1792 {
1793     return isUsingDefaultTooltip() ?
1794         getGUIContext().getDefaultTooltipObject(): d_customTip;
1795 }
1796 
1797 //----------------------------------------------------------------------------//
setTooltip(Tooltip * tooltip)1798 void Window::setTooltip(Tooltip* tooltip)
1799 {
1800     // destroy current custom tooltip if one exists and we created it
1801     if (d_customTip && d_weOwnTip)
1802         WindowManager::getSingleton().destroyWindow(d_customTip);
1803 
1804     // set new custom tooltip
1805     d_weOwnTip = false;
1806     d_customTip = tooltip;
1807 }
1808 
1809 //----------------------------------------------------------------------------//
setTooltipType(const String & tooltipType)1810 void Window::setTooltipType(const String& tooltipType)
1811 {
1812     // destroy current custom tooltip if one exists and we created it
1813     if (d_customTip && d_weOwnTip)
1814         WindowManager::getSingleton().destroyWindow(d_customTip);
1815 
1816     if (tooltipType.empty())
1817     {
1818         d_customTip = 0;
1819         d_weOwnTip = false;
1820     }
1821     else
1822     {
1823         CEGUI_TRY
1824         {
1825             d_customTip = static_cast<Tooltip*>(
1826                 WindowManager::getSingleton().createWindow(
1827                     tooltipType, getName() + TooltipNameSuffix));
1828             d_customTip->setAutoWindow(true);
1829             d_weOwnTip = true;
1830         }
1831         CEGUI_CATCH (UnknownObjectException&)
1832         {
1833             d_customTip = 0;
1834             d_weOwnTip = false;
1835         }
1836     }
1837 }
1838 
1839 //----------------------------------------------------------------------------//
getTooltipType(void) const1840 String Window::getTooltipType(void) const
1841 {
1842     return isUsingDefaultTooltip() ? String("") : d_customTip->getType();
1843 }
1844 
1845 //----------------------------------------------------------------------------//
setTooltipText(const String & tip)1846 void Window::setTooltipText(const String& tip)
1847 {
1848     d_tooltipText = tip;
1849 
1850     Tooltip* const tooltip = getTooltip();
1851 
1852     if (tooltip && tooltip->getTargetWindow() == this)
1853         tooltip->setText(tip);
1854 }
1855 
1856 //----------------------------------------------------------------------------//
getTooltipText(void) const1857 const String& Window::getTooltipText(void) const
1858 {
1859     return d_tooltipText;
1860 }
1861 
1862 //----------------------------------------------------------------------------//
getTooltipTextIncludingInheritance(void) const1863 const String& Window::getTooltipTextIncludingInheritance(void) const
1864 {
1865     if (d_inheritsTipText && d_parent && d_tooltipText.empty())
1866         return getParent()->getTooltipText();
1867     else
1868         return d_tooltipText;
1869 }
1870 
1871 //----------------------------------------------------------------------------//
inheritsTooltipText(void) const1872 bool Window::inheritsTooltipText(void) const
1873 {
1874     return d_inheritsTipText;
1875 }
1876 
1877 //----------------------------------------------------------------------------//
setInheritsTooltipText(bool setting)1878 void Window::setInheritsTooltipText(bool setting)
1879 {
1880     d_inheritsTipText = setting;
1881 }
1882 
1883 //----------------------------------------------------------------------------//
setArea_impl(const UVector2 & pos,const USize & size,bool topLeftSizing,bool fireEvents)1884 void Window::setArea_impl(const UVector2& pos, const USize& size,
1885                           bool topLeftSizing, bool fireEvents)
1886 {
1887     markCachedWindowRectsInvalid();
1888     Element::setArea_impl(pos, size, topLeftSizing, fireEvents);
1889 
1890     //if (moved || sized)
1891     // FIXME: This is potentially wasteful
1892     getGUIContext().updateWindowContainingMouse();
1893 
1894     // update geometry position and clipping if nothing from above appears to
1895     // have done so already (NB: may be occasionally wasteful, but fixes bugs!)
1896     if (!d_unclippedOuterRect.isCacheValid())
1897         updateGeometryRenderSettings();
1898 }
1899 
1900 //----------------------------------------------------------------------------//
markCachedWindowRectsInvalid()1901 void Window::markCachedWindowRectsInvalid()
1902 {
1903     d_outerRectClipperValid = false;
1904     d_innerRectClipperValid = false;
1905     d_hitTestRectValid = false;
1906 }
1907 
1908 //----------------------------------------------------------------------------//
getLookNFeel() const1909 const String& Window::getLookNFeel() const
1910 {
1911     return d_lookName;
1912 }
1913 
1914 //----------------------------------------------------------------------------//
setLookNFeel(const String & look)1915 void Window::setLookNFeel(const String& look)
1916 {
1917     if (d_lookName == look)
1918         return;
1919 
1920     if (!d_windowRenderer)
1921         CEGUI_THROW(NullObjectException("There must be a "
1922             "window renderer assigned to the window '" + d_name +
1923             "' to set its look'n'feel"));
1924 
1925     WidgetLookManager& wlMgr = WidgetLookManager::getSingleton();
1926     if (!d_lookName.empty())
1927     {
1928         d_windowRenderer->onLookNFeelUnassigned();
1929         const WidgetLookFeel& wlf = wlMgr.getWidgetLook(d_lookName);
1930         wlf.cleanUpWidget(*this);
1931     }
1932 
1933     d_lookName = look;
1934     Logger::getSingleton().logEvent("Assigning LookNFeel '" + look +
1935         "' to window '" + d_name + "'.", Informative);
1936 
1937     // Work to initialise the look and feel...
1938     const WidgetLookFeel& wlf = wlMgr.getWidgetLook(look);
1939     // Get look and feel to initialise the widget as it needs.
1940     wlf.initialiseWidget(*this);
1941     // do the necessary binding to the stuff added by the look and feel
1942     initialiseComponents();
1943     // let the window renderer know about this
1944     d_windowRenderer->onLookNFeelAssigned();
1945 
1946     invalidate();
1947     performChildWindowLayout();
1948 }
1949 
1950 //----------------------------------------------------------------------------//
setModalState(bool state)1951 void Window::setModalState(bool state)
1952 {
1953     // do nothing if state isn't changing
1954     if (getModalState() == state)
1955         return;
1956 
1957     // if going modal
1958     if (state)
1959     {
1960         activate();
1961         getGUIContext().setModalWindow(this);
1962     }
1963     // clear the modal target
1964     else
1965         getGUIContext().setModalWindow(0);
1966 }
1967 
1968 //----------------------------------------------------------------------------//
performChildWindowLayout(const bool nonclient_sized_hint,const bool client_sized_hint)1969 void Window::performChildWindowLayout(const bool nonclient_sized_hint,
1970                                       const bool client_sized_hint)
1971 {
1972     const Sizef old_size(d_pixelSize);
1973     d_pixelSize = calculatePixelSize();
1974 
1975     layoutLookNFeelChildWidgets();
1976 
1977     const bool outer_changed = nonclient_sized_hint || d_pixelSize != old_size;
1978     const bool inner_changed = client_sized_hint || isInnerRectSizeChanged();
1979 
1980     d_outerRectClipperValid &= !outer_changed;
1981     d_innerRectClipperValid &= !inner_changed;
1982 
1983     if (d_windowRenderer)
1984         d_windowRenderer->performChildWindowLayout();
1985 
1986     notifyChildrenOfSizeChange(outer_changed, inner_changed);
1987 }
1988 
1989 //----------------------------------------------------------------------------//
layoutLookNFeelChildWidgets()1990 void Window::layoutLookNFeelChildWidgets()
1991 {
1992     if (d_lookName.empty())
1993         return;
1994 
1995     CEGUI_TRY
1996     {
1997         WidgetLookManager::getSingleton().
1998             getWidgetLook(d_lookName).layoutChildWidgets(*this);
1999     }
2000     CEGUI_CATCH (UnknownObjectException&)
2001     {
2002         Logger::getSingleton().logEvent(
2003             "Window::layoutLookNFeelChildWidgets: "
2004             "WidgetLook '" + d_lookName + "' was not found.", Errors);
2005     }
2006 }
2007 
2008 //----------------------------------------------------------------------------//
getUserString(const String & name) const2009 const String& Window::getUserString(const String& name) const
2010 {
2011     UserStringMap::const_iterator iter = d_userStrings.find(name);
2012 
2013     if (iter == d_userStrings.end())
2014         CEGUI_THROW(UnknownObjectException(
2015             "a user string named '" + name + "' is not defined for Window '" +
2016             d_name + "'."));
2017 
2018     return (*iter).second;
2019 }
2020 
2021 //----------------------------------------------------------------------------//
isUserStringDefined(const String & name) const2022 bool Window::isUserStringDefined(const String& name) const
2023 {
2024      return d_userStrings.find(name) != d_userStrings.end();
2025 }
2026 
2027 //----------------------------------------------------------------------------//
setUserString(const String & name,const String & value)2028 void Window::setUserString(const String& name, const String& value)
2029 {
2030     d_userStrings[name] = value;
2031 }
2032 
2033 //----------------------------------------------------------------------------//
writeXMLToStream(XMLSerializer & xml_stream) const2034 void Window::writeXMLToStream(XMLSerializer& xml_stream) const
2035 {
2036     // just stop now if we are'nt allowed to write XML
2037     if (!d_allowWriteXML)
2038         return;
2039 
2040     // output opening Window tag
2041     xml_stream.openTag(WindowXMLElementName)
2042         .attribute(WindowTypeXMLAttributeName, getType());
2043     // write name if not auto-generated
2044     if (getName().compare(0, WindowManager::GeneratedWindowNameBase.length(),
2045                           WindowManager::GeneratedWindowNameBase) != 0)
2046     {
2047         xml_stream.attribute(WindowNameXMLAttributeName, getName());
2048     }
2049     // write out properties.
2050     writePropertiesXML(xml_stream);
2051     // write out attached child windows.
2052     writeChildWindowsXML(xml_stream);
2053     // now ouput closing Window tag
2054     xml_stream.closeTag();
2055 }
2056 
2057 //----------------------------------------------------------------------------//
writePropertiesXML(XMLSerializer & xml_stream) const2058 int Window::writePropertiesXML(XMLSerializer& xml_stream) const
2059 {
2060     int propertiesWritten = 0;
2061     PropertySet::PropertyIterator iter =  getPropertyIterator();
2062 
2063     while(!iter.isAtEnd())
2064     {
2065         // first we check to make sure the property is'nt banned from XML
2066         if (!isPropertyBannedFromXML(iter.getCurrentValue()))
2067         {
2068             CEGUI_TRY
2069             {
2070                 // only write property if it's not at the default state
2071                 if (!isPropertyAtDefault(iter.getCurrentValue()))
2072                 {
2073                     iter.getCurrentValue()->writeXMLToStream(this, xml_stream);
2074                     ++propertiesWritten;
2075                 }
2076             }
2077             CEGUI_CATCH (InvalidRequestException&)
2078             {
2079                 // This catches errors from the MultiLineColumnList for example
2080                 Logger::getSingleton().logEvent(
2081                     "Window::writePropertiesXML: property receiving failed.  "
2082                     "Continuing...", Errors);
2083             }
2084         }
2085 
2086         ++iter;
2087     }
2088 
2089     return propertiesWritten;
2090 }
2091 
2092 //----------------------------------------------------------------------------//
writeChildWindowsXML(XMLSerializer & xml_stream) const2093 int Window::writeChildWindowsXML(XMLSerializer& xml_stream) const
2094 {
2095     int windowsWritten = 0;
2096 
2097     for (uint i = 0; i < getChildCount(); ++i)
2098     {
2099         const Window* const child = getChildAtIdx(i);
2100 
2101         // conditional to ensure that auto created windows are handled
2102         // seperately.
2103         if (!child->isAutoWindow())
2104         {
2105             child->writeXMLToStream(xml_stream);
2106             ++windowsWritten;
2107         }
2108         // this is one of those auto created windows so we do some special
2109         // handling
2110         else if (child->writeAutoChildWindowXML(xml_stream))
2111         {
2112             ++windowsWritten;
2113         }
2114     }
2115 
2116     return windowsWritten;
2117 }
2118 
2119 //----------------------------------------------------------------------------//
writeAutoChildWindowXML(XMLSerializer & xml_stream) const2120 bool Window::writeAutoChildWindowXML(XMLSerializer& xml_stream) const
2121 {
2122 
2123     // just stop now if we are'nt allowed to write XML
2124     if (!d_allowWriteXML)
2125         return false;
2126 
2127     // we temporarily output to this string stream to see if have to do the tag
2128     // at all.  Make sure this stream does UTF-8
2129     std::ostringstream ss;
2130     XMLSerializer xml(ss);
2131     xml.openTag(AutoWindowXMLElementName);
2132     // Create the XML Child Tree
2133     // write out properties.
2134     writePropertiesXML(xml);
2135     // write out attached child windows.
2136     writeChildWindowsXML(xml);
2137     xml.closeTag();
2138     if (xml.getTagCount() <= 1)
2139         return false;
2140 
2141     // output opening AutoWindow tag
2142     xml_stream.openTag(AutoWindowXMLElementName);
2143     // write name suffix attribute
2144     xml_stream.attribute(AutoWindowNamePathXMLAttributeName, getName());
2145     // Inefficient : do the XML serialization again
2146     // write out properties.
2147     writePropertiesXML(xml_stream);
2148     // write out attached child windows.
2149     writeChildWindowsXML(xml_stream);
2150     xml_stream.closeTag();
2151 
2152     return true;
2153 }
2154 
2155 //----------------------------------------------------------------------------//
addWindowToDrawList(Window & wnd,bool at_back)2156 void Window::addWindowToDrawList(Window& wnd, bool at_back)
2157 {
2158     // add behind other windows in same group
2159     if (at_back)
2160     {
2161          // calculate position where window should be added for drawing
2162         ChildDrawList::iterator pos = d_drawList.begin();
2163         if (wnd.isAlwaysOnTop())
2164         {
2165             // find first topmost window
2166             while ((pos != d_drawList.end()) && (!(*pos)->isAlwaysOnTop()))
2167                 ++pos;
2168         }
2169         // add window to draw list
2170         d_drawList.insert(pos, &wnd);
2171     }
2172     // add in front of other windows in group
2173     else
2174     {
2175         // calculate position where window should be added for drawing
2176         ChildDrawList::reverse_iterator position = d_drawList.rbegin();
2177         if (!wnd.isAlwaysOnTop())
2178         {
2179             // find last non-topmost window
2180             while ((position != d_drawList.rend()) && ((*position)->isAlwaysOnTop()))
2181                 ++position;
2182         }
2183         // add window to draw list
2184         d_drawList.insert(position.base(), &wnd);
2185     }
2186 }
2187 
2188 //----------------------------------------------------------------------------//
removeWindowFromDrawList(const Window & wnd)2189 void Window::removeWindowFromDrawList(const Window& wnd)
2190 {
2191     // if draw list is not empty
2192     if (!d_drawList.empty())
2193     {
2194         // attempt to find the window in the draw list
2195         const ChildDrawList::iterator position =
2196             std::find(d_drawList.begin(), d_drawList.end(), &wnd);
2197 
2198         // remove the window if it was found in the draw list
2199         if (position != d_drawList.end())
2200             d_drawList.erase(position);
2201     }
2202 }
2203 
2204 //----------------------------------------------------------------------------//
getActiveSibling()2205 Window* Window::getActiveSibling()
2206 {
2207     // initialise with this if we are active, else 0
2208     Window* activeWnd = isActive() ? this : 0;
2209 
2210     // if active window not already known, and we have a parent window
2211     if (!activeWnd && d_parent)
2212     {
2213         // scan backwards through the draw list, as this will
2214         // usually result in the fastest result.
2215         for (ChildDrawList::reverse_iterator it = getParent()->d_drawList.rbegin(); it != getParent()->d_drawList.rend(); ++it)
2216         {
2217             Window* wnd = *it;
2218             // if this child is active
2219             if (wnd->isActive())
2220             {
2221                 // set the return value
2222                 activeWnd = wnd;
2223                 // exit loop early, as we have found what we needed
2224                 break;
2225             }
2226         }
2227     }
2228 
2229     // return whatever we discovered
2230     return activeWnd;
2231 }
2232 
2233 //----------------------------------------------------------------------------//
onSized(ElementEventArgs & e)2234 void Window::onSized(ElementEventArgs& e)
2235 {
2236     /*
2237      * Why are we not calling Element::onSized?  It's because that function
2238      * always calls the onParentSized notification for all children - we really
2239      * want that to be done via performChildWindowLayout instead and we
2240      * definitely don't want it done twice.
2241      *
2242      * (The other option was to add an Element::performChildLayout function -
2243      * maybe we should consider that).
2244     */
2245 
2246     // resize the underlying RenderingWindow if we're using such a thing
2247     if (d_surface && d_surface->isRenderingWindow())
2248         static_cast<RenderingWindow*>(d_surface)->setSize(getPixelSize());
2249 
2250     // screen area changes when we're resized.
2251     // NB: Called non-recursive since the performChildWindowLayout call should
2252     // have dealt more selectively with child Window cases.
2253     notifyScreenAreaChanged(false);
2254     performChildWindowLayout(true, true);
2255 
2256     invalidate();
2257 
2258     fireEvent(EventSized, e, EventNamespace);
2259 }
2260 
2261 //----------------------------------------------------------------------------//
onMoved(ElementEventArgs & e)2262 void Window::onMoved(ElementEventArgs& e)
2263 {
2264     Element::onMoved(e);
2265 
2266     // handle invalidation of surfaces and trigger needed redraws
2267     if (d_parent)
2268     {
2269         getParent()->invalidateRenderingSurface();
2270         // need to redraw some geometry if parent uses a caching surface
2271         if (getParent()->getTargetRenderingSurface().isRenderingWindow())
2272             getGUIContext().markAsDirty();
2273     }
2274 }
2275 
2276 //----------------------------------------------------------------------------//
onTextChanged(WindowEventArgs & e)2277 void Window::onTextChanged(WindowEventArgs& e)
2278 {
2279     invalidate();
2280     fireEvent(EventTextChanged, e, EventNamespace);
2281 }
2282 
2283 //----------------------------------------------------------------------------//
onFontChanged(WindowEventArgs & e)2284 void Window::onFontChanged(WindowEventArgs& e)
2285 {
2286     // This was added to enable the Falagard FontDim to work
2287     // properly.  A better, more selective, solution would
2288     // probably be to do something funky with events ;)
2289     performChildWindowLayout();
2290 
2291     invalidate();
2292     fireEvent(EventFontChanged, e, EventNamespace);
2293 }
2294 
2295 //----------------------------------------------------------------------------//
onAlphaChanged(WindowEventArgs & e)2296 void Window::onAlphaChanged(WindowEventArgs& e)
2297 {
2298     // scan child list and call this method for all children that inherit alpha
2299     const size_t child_count = getChildCount();
2300 
2301     for (size_t i = 0; i < child_count; ++i)
2302     {
2303         if (getChildAtIdx(i)->inheritsAlpha())
2304         {
2305             WindowEventArgs args(getChildAtIdx(i));
2306             getChildAtIdx(i)->onAlphaChanged(args);
2307         }
2308 
2309     }
2310 
2311     invalidate();
2312     fireEvent(EventAlphaChanged, e, EventNamespace);
2313 }
2314 
2315 //----------------------------------------------------------------------------//
onIDChanged(WindowEventArgs & e)2316 void Window::onIDChanged(WindowEventArgs& e)
2317 {
2318     fireEvent(EventIDChanged, e, EventNamespace);
2319 }
2320 
2321 //----------------------------------------------------------------------------//
onShown(WindowEventArgs & e)2322 void Window::onShown(WindowEventArgs& e)
2323 {
2324     invalidate();
2325     fireEvent(EventShown, e, EventNamespace);
2326 }
2327 
2328 //----------------------------------------------------------------------------//
onHidden(WindowEventArgs & e)2329 void Window::onHidden(WindowEventArgs& e)
2330 {
2331     // first deactivate window if it is the active window.
2332     if (isActive())
2333         deactivate();
2334 
2335     invalidate();
2336     fireEvent(EventHidden, e, EventNamespace);
2337 }
2338 
2339 //----------------------------------------------------------------------------//
onEnabled(WindowEventArgs & e)2340 void Window::onEnabled(WindowEventArgs& e)
2341 {
2342     // signal all non-disabled children that they are now enabled
2343     // (via inherited state)
2344     const size_t child_count = getChildCount();
2345     for (size_t i = 0; i < child_count; ++i)
2346     {
2347         if (getChildAtIdx(i)->d_enabled)
2348         {
2349             WindowEventArgs args(getChildAtIdx(i));
2350             getChildAtIdx(i)->onEnabled(args);
2351         }
2352     }
2353 
2354     invalidate();
2355     fireEvent(EventEnabled, e, EventNamespace);
2356 }
2357 
2358 //----------------------------------------------------------------------------//
onDisabled(WindowEventArgs & e)2359 void Window::onDisabled(WindowEventArgs& e)
2360 {
2361     // signal all non-disabled children that they are now disabled
2362     // (via inherited state)
2363     const size_t child_count = getChildCount();
2364     for (size_t i = 0; i < child_count; ++i)
2365     {
2366         if (getChildAtIdx(i)->d_enabled)
2367         {
2368             WindowEventArgs args(getChildAtIdx(i));
2369             getChildAtIdx(i)->onDisabled(args);
2370         }
2371     }
2372 
2373     invalidate();
2374     fireEvent(EventDisabled, e, EventNamespace);
2375 }
2376 
2377 //----------------------------------------------------------------------------//
onClippingChanged(WindowEventArgs & e)2378 void Window::onClippingChanged(WindowEventArgs& e)
2379 {
2380     invalidate();
2381     notifyClippingChanged();
2382     fireEvent(EventClippedByParentChanged, e, EventNamespace);
2383 }
2384 
2385 //----------------------------------------------------------------------------//
onParentDestroyChanged(WindowEventArgs & e)2386 void Window::onParentDestroyChanged(WindowEventArgs& e)
2387 {
2388     fireEvent(EventDestroyedByParentChanged, e, EventNamespace);
2389 }
2390 
2391 //----------------------------------------------------------------------------//
onInheritsAlphaChanged(WindowEventArgs & e)2392 void Window::onInheritsAlphaChanged(WindowEventArgs& e)
2393 {
2394     invalidate();
2395     fireEvent(EventInheritsAlphaChanged, e, EventNamespace);
2396 }
2397 
2398 //----------------------------------------------------------------------------//
onAlwaysOnTopChanged(WindowEventArgs & e)2399 void Window::onAlwaysOnTopChanged(WindowEventArgs& e)
2400 {
2401     // we no longer want a total redraw here, instead we just get each window
2402     // to resubmit it's imagery to the Renderer.
2403     getGUIContext().markAsDirty();
2404     fireEvent(EventAlwaysOnTopChanged, e, EventNamespace);
2405 }
2406 
2407 //----------------------------------------------------------------------------//
onCaptureGained(WindowEventArgs & e)2408 void Window::onCaptureGained(WindowEventArgs& e)
2409 {
2410     fireEvent(EventInputCaptureGained, e, EventNamespace);
2411 }
2412 
2413 //----------------------------------------------------------------------------//
onCaptureLost(WindowEventArgs & e)2414 void Window::onCaptureLost(WindowEventArgs& e)
2415 {
2416     // reset auto-repeat state
2417     d_repeatButton = NoButton;
2418 
2419     // handle restore of previous capture window as required.
2420     if (d_restoreOldCapture && (d_oldCapture != 0)) {
2421         d_oldCapture->onCaptureLost(e);
2422         d_oldCapture = 0;
2423     }
2424 
2425     // handle case where mouse is now in a different window
2426     // (this is a bit of a hack that uses the mouse input injector to handle
2427     // this for us).
2428     getGUIContext().injectMouseMove(0, 0);
2429 
2430     fireEvent(EventInputCaptureLost, e, EventNamespace);
2431 }
2432 
2433 //----------------------------------------------------------------------------//
onInvalidated(WindowEventArgs & e)2434 void Window::onInvalidated(WindowEventArgs& e)
2435 {
2436     fireEvent(EventInvalidated, e, EventNamespace);
2437 }
2438 
2439 //----------------------------------------------------------------------------//
onRenderingStarted(WindowEventArgs & e)2440 void Window::onRenderingStarted(WindowEventArgs& e)
2441 {
2442     fireEvent(EventRenderingStarted, e, EventNamespace);
2443 }
2444 
2445 //----------------------------------------------------------------------------//
onRenderingEnded(WindowEventArgs & e)2446 void Window::onRenderingEnded(WindowEventArgs& e)
2447 {
2448     fireEvent(EventRenderingEnded, e, EventNamespace);
2449 }
2450 
2451 //----------------------------------------------------------------------------//
onZChanged(WindowEventArgs & e)2452 void Window::onZChanged(WindowEventArgs& e)
2453 {
2454     // we no longer want a total redraw here, instead we just get each window
2455     // to resubmit it's imagery to the Renderer.
2456     getGUIContext().markAsDirty();
2457     fireEvent(EventZOrderChanged, e, EventNamespace);
2458 }
2459 
2460 //----------------------------------------------------------------------------//
onDestructionStarted(WindowEventArgs & e)2461 void Window::onDestructionStarted(WindowEventArgs& e)
2462 {
2463     d_destructionStarted = true;
2464     fireEvent(EventDestructionStarted, e, EventNamespace);
2465 }
2466 
2467 //----------------------------------------------------------------------------//
onActivated(ActivationEventArgs & e)2468 void Window::onActivated(ActivationEventArgs& e)
2469 {
2470     d_active = true;
2471     invalidate();
2472     fireEvent(EventActivated, e, EventNamespace);
2473 }
2474 
2475 //----------------------------------------------------------------------------//
onDeactivated(ActivationEventArgs & e)2476 void Window::onDeactivated(ActivationEventArgs& e)
2477 {
2478     // first de-activate all children
2479     const size_t child_count = getChildCount();
2480     for (size_t i = 0; i < child_count; ++i)
2481     {
2482         if (getChildAtIdx(i)->isActive())
2483         {
2484             // make sure the child gets itself as the .window member
2485             ActivationEventArgs child_e(getChildAtIdx(i));
2486             child_e.otherWindow = e.otherWindow;
2487             getChildAtIdx(i)->onDeactivated(child_e);
2488         }
2489 
2490     }
2491 
2492     d_active = false;
2493     invalidate();
2494     fireEvent(EventDeactivated, e, EventNamespace);
2495 }
2496 
2497 //----------------------------------------------------------------------------//
onParentSized(ElementEventArgs & e)2498 void Window::onParentSized(ElementEventArgs& e)
2499 {
2500     Element::onParentSized(e);
2501 
2502     // if we were not moved or sized, do child layout anyway!
2503     // URGENT FIXME
2504     //if (!(moved || sized))
2505     performChildWindowLayout();
2506 }
2507 
2508 //----------------------------------------------------------------------------//
onChildAdded(ElementEventArgs & e)2509 void Window::onChildAdded(ElementEventArgs& e)
2510 {
2511     // we no longer want a total redraw here, instead we just get each window
2512     // to resubmit it's imagery to the Renderer.
2513     getGUIContext().markAsDirty();
2514 
2515     Element::onChildAdded(e);
2516 }
2517 
2518 //----------------------------------------------------------------------------//
onChildRemoved(ElementEventArgs & e)2519 void Window::onChildRemoved(ElementEventArgs& e)
2520 {
2521     // we no longer want a total redraw here, instead we just get each window
2522     // to resubmit it's imagery to the Renderer.
2523     getGUIContext().markAsDirty();
2524     // Though we do need to invalidate the rendering surface!
2525     getTargetRenderingSurface().invalidate();
2526 
2527     Element::onChildRemoved(e);
2528 }
2529 
2530 //----------------------------------------------------------------------------//
onMouseEntersArea(MouseEventArgs & e)2531 void Window::onMouseEntersArea(MouseEventArgs& e)
2532 {
2533     d_containsMouse = true;
2534     fireEvent(EventMouseEntersArea, e, EventNamespace);
2535 }
2536 
2537 //----------------------------------------------------------------------------//
onMouseLeavesArea(MouseEventArgs & e)2538 void Window::onMouseLeavesArea(MouseEventArgs& e)
2539 {
2540     d_containsMouse = false;
2541     fireEvent(EventMouseLeavesArea, e, EventNamespace);
2542 }
2543 
2544 //----------------------------------------------------------------------------//
onMouseEnters(MouseEventArgs & e)2545 void Window::onMouseEnters(MouseEventArgs& e)
2546 {
2547     // set the mouse cursor
2548     getGUIContext().
2549         getMouseCursor().setImage(getMouseCursor());
2550 
2551     // perform tooltip control
2552     Tooltip* const tip = getTooltip();
2553     if (tip && !isAncestor(tip))
2554         tip->setTargetWindow(this);
2555 
2556     fireEvent(EventMouseEntersSurface, e, EventNamespace);
2557 }
2558 
2559 //----------------------------------------------------------------------------//
onMouseLeaves(MouseEventArgs & e)2560 void Window::onMouseLeaves(MouseEventArgs& e)
2561 {
2562     // perform tooltip control
2563     const Window* const mw = getGUIContext().getWindowContainingMouse();
2564     Tooltip* const tip = getTooltip();
2565     if (tip && mw != tip && !(mw && mw->isAncestor(tip)))
2566         tip->setTargetWindow(0);
2567 
2568     fireEvent(EventMouseLeavesSurface, e, EventNamespace);
2569 }
2570 
2571 //----------------------------------------------------------------------------//
onMouseMove(MouseEventArgs & e)2572 void Window::onMouseMove(MouseEventArgs& e)
2573 {
2574     // perform tooltip control
2575     Tooltip* const tip = getTooltip();
2576     if (tip)
2577         tip->resetTimer();
2578 
2579     fireEvent(EventMouseMove, e, EventNamespace);
2580 
2581     // optionally propagate to parent
2582     if (!e.handled && d_propagateMouseInputs &&
2583         d_parent && this != getGUIContext().getModalWindow())
2584     {
2585         e.window = getParent();
2586         getParent()->onMouseMove(e);
2587 
2588         return;
2589     }
2590 
2591     // by default we now mark mouse events as handled
2592     // (derived classes may override, of course!)
2593     ++e.handled;
2594 }
2595 
2596 //----------------------------------------------------------------------------//
onMouseWheel(MouseEventArgs & e)2597 void Window::onMouseWheel(MouseEventArgs& e)
2598 {
2599     fireEvent(EventMouseWheel, e, EventNamespace);
2600 
2601     // optionally propagate to parent
2602     if (!e.handled && d_propagateMouseInputs &&
2603         d_parent && this != getGUIContext().getModalWindow())
2604     {
2605         e.window = getParent();
2606         getParent()->onMouseWheel(e);
2607 
2608         return;
2609     }
2610 
2611     // by default we now mark mouse events as handled
2612     // (derived classes may override, of course!)
2613     ++e.handled;
2614 }
2615 
2616 //----------------------------------------------------------------------------//
onMouseButtonDown(MouseEventArgs & e)2617 void Window::onMouseButtonDown(MouseEventArgs& e)
2618 {
2619     // perform tooltip control
2620     Tooltip* const tip = getTooltip();
2621     if (tip)
2622         tip->setTargetWindow(0);
2623 
2624     if ((e.button == LeftButton) && moveToFront_impl(true))
2625         ++e.handled;
2626 
2627     // if auto repeat is enabled and we are not currently tracking
2628     // the button that was just pushed (need this button check because
2629     // it could be us that generated this event via auto-repeat).
2630     if (d_autoRepeat)
2631     {
2632         if (d_repeatButton == NoButton)
2633             captureInput();
2634 
2635         if ((d_repeatButton != e.button) && isCapturedByThis())
2636         {
2637             d_repeatButton = e.button;
2638             d_repeatElapsed = 0;
2639             d_repeating = false;
2640         }
2641     }
2642 
2643     fireEvent(EventMouseButtonDown, e, EventNamespace);
2644 
2645     // optionally propagate to parent
2646     if (!e.handled && d_propagateMouseInputs &&
2647         d_parent && this != getGUIContext().getModalWindow())
2648     {
2649         e.window = getParent();
2650         getParent()->onMouseButtonDown(e);
2651 
2652         return;
2653     }
2654 
2655     // by default we now mark mouse events as handled
2656     // (derived classes may override, of course!)
2657     ++e.handled;
2658 }
2659 
2660 //----------------------------------------------------------------------------//
onMouseButtonUp(MouseEventArgs & e)2661 void Window::onMouseButtonUp(MouseEventArgs& e)
2662 {
2663     // reset auto-repeat state
2664     if (d_autoRepeat && d_repeatButton != NoButton)
2665     {
2666         releaseInput();
2667         d_repeatButton = NoButton;
2668     }
2669 
2670     fireEvent(EventMouseButtonUp, e, EventNamespace);
2671 
2672     // optionally propagate to parent
2673     if (!e.handled && d_propagateMouseInputs &&
2674         d_parent && this != getGUIContext().getModalWindow())
2675     {
2676         e.window = getParent();
2677         getParent()->onMouseButtonUp(e);
2678 
2679         return;
2680     }
2681 
2682     // by default we now mark mouse events as handled
2683     // (derived classes may override, of course!)
2684     ++e.handled;
2685 }
2686 
2687 //----------------------------------------------------------------------------//
onMouseClicked(MouseEventArgs & e)2688 void Window::onMouseClicked(MouseEventArgs& e)
2689 {
2690     fireEvent(EventMouseClick, e, EventNamespace);
2691 
2692     // optionally propagate to parent
2693     if (!e.handled && d_propagateMouseInputs &&
2694         d_parent && this != getGUIContext().getModalWindow())
2695     {
2696         e.window = getParent();
2697         getParent()->onMouseClicked(e);
2698 
2699         return;
2700     }
2701 
2702     // if event was directly injected, mark as handled to be consistent with
2703     // other mouse button injectors
2704     if (!getGUIContext().isMouseClickEventGenerationEnabled())
2705         ++e.handled;
2706 }
2707 
2708 //----------------------------------------------------------------------------//
onMouseDoubleClicked(MouseEventArgs & e)2709 void Window::onMouseDoubleClicked(MouseEventArgs& e)
2710 {
2711     fireEvent(EventMouseDoubleClick, e, EventNamespace);
2712 
2713     // optionally propagate to parent
2714     if (!e.handled && d_propagateMouseInputs &&
2715         d_parent && this != getGUIContext().getModalWindow())
2716     {
2717         e.window = getParent();
2718         getParent()->onMouseDoubleClicked(e);
2719 
2720         return;
2721     }
2722 
2723     ++e.handled;
2724 }
2725 
2726 //----------------------------------------------------------------------------//
onMouseTripleClicked(MouseEventArgs & e)2727 void Window::onMouseTripleClicked(MouseEventArgs& e)
2728 {
2729     fireEvent(EventMouseTripleClick, e, EventNamespace);
2730 
2731     // optionally propagate to parent
2732     if (!e.handled && d_propagateMouseInputs &&
2733         d_parent && this != getGUIContext().getModalWindow())
2734     {
2735         e.window = getParent();
2736         getParent()->onMouseTripleClicked(e);
2737 
2738         return;
2739     }
2740 
2741     ++e.handled;
2742 }
2743 
2744 //----------------------------------------------------------------------------//
onKeyDown(KeyEventArgs & e)2745 void Window::onKeyDown(KeyEventArgs& e)
2746 {
2747     fireEvent(EventKeyDown, e, EventNamespace);
2748 
2749     // As of 0.7.0 CEGUI::System no longer does input event propogation, so by
2750     // default we now do that here.  Generally speaking key handling widgets
2751     // may need to override this behaviour to halt further propogation.
2752     if (!e.handled && d_parent &&
2753         this != getGUIContext().getModalWindow())
2754     {
2755         e.window = getParent();
2756         getParent()->onKeyDown(e);
2757     }
2758 }
2759 
2760 //----------------------------------------------------------------------------//
onKeyUp(KeyEventArgs & e)2761 void Window::onKeyUp(KeyEventArgs& e)
2762 {
2763     fireEvent(EventKeyUp, e, EventNamespace);
2764 
2765     // As of 0.7.0 CEGUI::System no longer does input event propogation, so by
2766     // default we now do that here.  Generally speaking key handling widgets
2767     // may need to override this behaviour to halt further propogation.
2768     if (!e.handled && d_parent &&
2769         this != getGUIContext().getModalWindow())
2770     {
2771         e.window = getParent();
2772         getParent()->onKeyUp(e);
2773     }
2774 }
2775 
2776 //----------------------------------------------------------------------------//
onCharacter(KeyEventArgs & e)2777 void Window::onCharacter(KeyEventArgs& e)
2778 {
2779     fireEvent(EventCharacterKey, e, EventNamespace);
2780 
2781     // As of 0.7.0 CEGUI::System no longer does input event propogation, so by
2782     // default we now do that here.  Generally speaking key handling widgets
2783     // may need to override this behaviour to halt further propogation.
2784     if (!e.handled && d_parent &&
2785         this != getGUIContext().getModalWindow())
2786     {
2787         e.window = getParent();
2788         getParent()->onCharacter(e);
2789     }
2790 }
2791 
2792 //----------------------------------------------------------------------------//
onDragDropItemEnters(DragDropEventArgs & e)2793 void Window::onDragDropItemEnters(DragDropEventArgs& e)
2794 {
2795     fireEvent(EventDragDropItemEnters, e, EventNamespace);
2796 }
2797 
2798 //----------------------------------------------------------------------------//
onDragDropItemLeaves(DragDropEventArgs & e)2799 void Window::onDragDropItemLeaves(DragDropEventArgs& e)
2800 {
2801     fireEvent(EventDragDropItemLeaves, e, EventNamespace);
2802 }
2803 
2804 //----------------------------------------------------------------------------//
onDragDropItemDropped(DragDropEventArgs & e)2805 void Window::onDragDropItemDropped(DragDropEventArgs& e)
2806 {
2807     fireEvent(EventDragDropItemDropped, e, EventNamespace);
2808 }
2809 
2810 //----------------------------------------------------------------------------//
setWindowRenderer(const String & name)2811 void Window::setWindowRenderer(const String& name)
2812 {
2813     if (d_windowRenderer && d_windowRenderer->getName() == name)
2814         return;
2815 
2816     WindowRendererManager& wrm = WindowRendererManager::getSingleton();
2817     if (d_windowRenderer != 0)
2818     {
2819         // Allow reset of renderer
2820         if (d_windowRenderer->getName() == name)
2821             return;
2822 
2823         WindowEventArgs e(this);
2824         onWindowRendererDetached(e);
2825         wrm.destroyWindowRenderer(d_windowRenderer);
2826     }
2827 
2828     if (!name.empty())
2829     {
2830         Logger::getSingleton().logEvent("Assigning the window renderer '" +
2831             name + "' to the window '" + d_name + "'", Informative);
2832         d_windowRenderer = wrm.createWindowRenderer(name);
2833         WindowEventArgs e(this);
2834         onWindowRendererAttached(e);
2835     }
2836     else
2837         CEGUI_THROW(InvalidRequestException(
2838             "Attempt to assign a 'null' window renderer to window '" +
2839             d_name + "'."));
2840 }
2841 
2842 //----------------------------------------------------------------------------//
getWindowRenderer(void) const2843 WindowRenderer* Window::getWindowRenderer(void) const
2844 {
2845     return d_windowRenderer;
2846 }
2847 
2848 //----------------------------------------------------------------------------//
onWindowRendererAttached(WindowEventArgs & e)2849 void Window::onWindowRendererAttached(WindowEventArgs& e)
2850 {
2851     if (!validateWindowRenderer(d_windowRenderer))
2852         CEGUI_THROW(InvalidRequestException(
2853             "The window renderer '" + d_windowRenderer->getName() + "' is not "
2854             "compatible with this widget type (" + getType() + ")"));
2855 
2856     d_windowRenderer->d_window = this;
2857     d_windowRenderer->onAttach();
2858     fireEvent(EventWindowRendererAttached, e, EventNamespace);
2859 }
2860 
2861 //----------------------------------------------------------------------------//
onWindowRendererDetached(WindowEventArgs & e)2862 void Window::onWindowRendererDetached(WindowEventArgs& e)
2863 {
2864     d_windowRenderer->onDetach();
2865     d_windowRenderer->d_window = 0;
2866     fireEvent(EventWindowRendererDetached, e, EventNamespace);
2867 }
2868 
2869 //----------------------------------------------------------------------------//
validateWindowRenderer(const WindowRenderer *) const2870 bool Window::validateWindowRenderer(const WindowRenderer*) const
2871 {
2872     return true;
2873 }
2874 
2875 //----------------------------------------------------------------------------//
getWindowRendererName() const2876 const String& Window::getWindowRendererName() const
2877 {
2878     if (d_windowRenderer)
2879         return d_windowRenderer->getName();
2880 
2881     static String empty("");
2882     return empty;
2883 }
2884 
2885 
2886 //----------------------------------------------------------------------------//
banPropertyFromXML(const String & property_name)2887 void Window::banPropertyFromXML(const String& property_name)
2888 {
2889 	Property* instance = getPropertyInstance(property_name);
2890 	if (!instance->isWritable())
2891 	{
2892 		Logger::getSingleton().logEvent("Property '" + property_name + "' "
2893 				"is not writable so it's implicitly banned from XML. No need "
2894 				"to ban it manually", Warnings);
2895 
2896 		return;
2897 	}
2898 
2899     // check if the insertion failed
2900     if (!d_bannedXMLProperties.insert(property_name).second)
2901         // just log the incidence
2902         CEGUI_LOGINSANE("Window::banPropertyFromXML: The property '" +
2903             property_name + "' is already banned in window '" + d_name + "'");
2904 }
2905 
2906 //----------------------------------------------------------------------------//
banPropertyFromXMLRecursive(const String & property_name)2907 void Window::banPropertyFromXMLRecursive(const String& property_name)
2908 {
2909     banPropertyFromXML(property_name);
2910 
2911     const size_t childCount = getChildCount();
2912     for(size_t i = 0; i < childCount; ++i)
2913     {
2914         getChildAtIdx(i)->banPropertyFromXMLRecursive(property_name);
2915     }
2916 }
2917 
2918 //----------------------------------------------------------------------------//
unbanPropertyFromXML(const String & property_name)2919 void Window::unbanPropertyFromXML(const String& property_name)
2920 {
2921     d_bannedXMLProperties.erase(property_name);
2922 }
2923 
2924 //----------------------------------------------------------------------------//
unbanPropertyFromXMLRecursive(const String & property_name)2925 void Window::unbanPropertyFromXMLRecursive(const String& property_name)
2926 {
2927     unbanPropertyFromXML(property_name);
2928 
2929     const size_t childCount = getChildCount();
2930     for(size_t i = 0; i < childCount; ++i)
2931     {
2932         getChildAtIdx(i)->unbanPropertyFromXMLRecursive(property_name);
2933     }
2934 }
2935 
2936 //----------------------------------------------------------------------------//
isPropertyBannedFromXML(const String & property_name) const2937 bool Window::isPropertyBannedFromXML(const String& property_name) const
2938 {
2939     const BannedXMLPropertySet::const_iterator i =
2940         d_bannedXMLProperties.find(property_name);
2941 
2942     // generally, there will always less banned properties than all properties,
2943     // so it makes sense to check that first before querying the property instance
2944     if (i != d_bannedXMLProperties.end())
2945     {
2946     	return true;
2947     }
2948 
2949     // properties that don't write any XML code are implicitly banned
2950 
2951     // read-only properties are implicitly banned
2952     // (such stored information wouldn't be of any value in the XML anyways,
2953     // no way to apply it to the widget)
2954     Property* instance = getPropertyInstance(property_name);
2955     return (!instance->doesWriteXML() || !instance->isWritable());
2956 }
2957 
2958 //----------------------------------------------------------------------------//
banPropertyFromXML(const Property * property)2959 void Window::banPropertyFromXML(const Property* property)
2960 {
2961     if (property)
2962         banPropertyFromXML(property->getName());
2963 }
2964 
2965 //----------------------------------------------------------------------------//
unbanPropertyFromXML(const Property * property)2966 void Window::unbanPropertyFromXML(const Property* property)
2967 {
2968     if (property)
2969         unbanPropertyFromXML(property->getName());
2970 }
2971 
2972 //----------------------------------------------------------------------------//
isPropertyBannedFromXML(const Property * property) const2973 bool Window::isPropertyBannedFromXML(const Property* property) const
2974 {
2975     if (property)
2976         return isPropertyBannedFromXML(property->getName());
2977     else
2978         return false;
2979 }
2980 
2981 //----------------------------------------------------------------------------//
isPropertyAtDefault(const Property * property) const2982 bool Window::isPropertyAtDefault(const Property* property) const
2983 {
2984     // if we have a looknfeel we examine it for defaults
2985     if (!d_lookName.empty())
2986     {
2987         if (d_parent && !getParent()->getLookNFeel().empty())
2988         {
2989             const WidgetLookFeel& wlf =
2990                 WidgetLookManager::getSingleton().
2991                     getWidgetLook(getParent()->getLookNFeel());
2992 
2993             // if this property is a target of a PropertyLink, we always report
2994             // as being at default.  NB: This check is only performed on the
2995             // immediate parent.
2996             const WidgetLookFeel::PropertyLinkDefinitionList& pldl(wlf.getPropertyLinkDefinitions());
2997             WidgetLookFeel::PropertyLinkDefinitionList::const_iterator i = pldl.begin();
2998             for (; i != pldl.end(); ++i)
2999             {
3000                 if ((*i)->getPropertyName() == property->getName())
3001                     return true;
3002             }
3003 
3004             // for an auto-window see if the property is is set via a Property
3005             // tag within the WidgetComponent that defines it.
3006             if (d_autoWindow)
3007             {
3008                 // find the widget component if possible
3009                 const WidgetComponent* const wc = wlf.findWidgetComponent(getName());
3010                 if (wc)
3011                 {
3012                     const PropertyInitialiser* const propinit =
3013                         wc->findPropertyInitialiser(property->getName());
3014 
3015                     if (propinit)
3016                         return (getProperty(property->getName()) ==
3017                                 propinit->getInitialiserValue());
3018                 }
3019             }
3020         }
3021 
3022         // if the looknfeel has a new default for this property we compare
3023         // against that
3024         const WidgetLookFeel& wlf =
3025             WidgetLookManager::getSingleton().getWidgetLook(d_lookName);
3026         const PropertyInitialiser* const propinit =
3027             wlf.findPropertyInitialiser(property->getName());
3028         if (propinit)
3029             return (getProperty(property->getName()) ==
3030                     propinit->getInitialiserValue());
3031     }
3032 
3033     // we don't have a looknfeel with a new value for this property so we rely
3034     // on the hardcoded default
3035     return property->isDefault(this);
3036 }
3037 
3038 //----------------------------------------------------------------------------//
notifyClippingChanged(void)3039 void Window::notifyClippingChanged(void)
3040 {
3041     markCachedWindowRectsInvalid();
3042 
3043     // inform children that their clipped screen areas must be updated
3044     const size_t num = d_children.size();
3045     for (size_t i=0; i<num; ++i)
3046         if (getChildAtIdx(i)->isClippedByParent())
3047             getChildAtIdx(i)->notifyClippingChanged();
3048 }
3049 
3050 //----------------------------------------------------------------------------//
notifyScreenAreaChanged(bool recursive)3051 void Window::notifyScreenAreaChanged(bool recursive /* = true */)
3052 {
3053     markCachedWindowRectsInvalid();
3054     Element::notifyScreenAreaChanged(recursive);
3055 
3056     updateGeometryRenderSettings();
3057 }
3058 
3059 //----------------------------------------------------------------------------//
updateGeometryRenderSettings()3060 void Window::updateGeometryRenderSettings()
3061 {
3062     RenderingContext ctx;
3063     getRenderingContext(ctx);
3064 
3065     // move the underlying RenderingWindow if we're using such a thing
3066     if (ctx.owner == this && ctx.surface->isRenderingWindow())
3067     {
3068         static_cast<RenderingWindow*>(ctx.surface)->
3069             setPosition(getUnclippedOuterRect().get().getPosition());
3070         static_cast<RenderingWindow*>(d_surface)->setPivot(
3071             Vector3f(d_pixelSize.d_width / 2.0f,
3072                     d_pixelSize.d_height / 2.0f,
3073                     0.0f));
3074         d_geometry->setTranslation(Vector3f(0.0f, 0.0f, 0.0f));
3075     }
3076     // if we're not texture backed, update geometry position.
3077     else
3078     {
3079         // position is the offset of the window on the dest surface.
3080         const Rectf ucrect(getUnclippedOuterRect().get());
3081         d_geometry->setTranslation(Vector3f(ucrect.d_min.d_x - ctx.offset.d_x,
3082                                             ucrect.d_min.d_y - ctx.offset.d_y, 0.0f));
3083     }
3084     initialiseClippers(ctx);
3085 }
3086 
3087 //----------------------------------------------------------------------------//
isDragDropTarget() const3088 bool Window::isDragDropTarget() const
3089 {
3090     return d_dragDropTarget;
3091 }
3092 
3093 //----------------------------------------------------------------------------//
setDragDropTarget(bool setting)3094 void Window::setDragDropTarget(bool setting)
3095 {
3096     d_dragDropTarget = setting;
3097 }
3098 
3099 //-----------------------------------------------------------------------
setFalagardType(const String & type,const String & rendererType)3100 void Window::setFalagardType(const String& type, const String& rendererType)
3101 {
3102     // Retrieve the new widget look
3103     const String separator("/");
3104     String::size_type pos = type.find(separator);
3105     const String newLook(type, 0, pos);
3106 
3107     // Check if old one is the same. If so, ignore since we don't need to do
3108     // anything (type is already assigned)
3109     pos = d_falagardType.find(separator);
3110     String oldLook(d_falagardType, 0, pos);
3111     if(oldLook == newLook)
3112         return;
3113 
3114     // Obtain widget kind
3115     String widget(d_falagardType, pos + 1);
3116 
3117     // Build new type (look/widget)
3118     d_falagardType = newLook + separator + widget;
3119 
3120     // Set new renderer
3121     if(rendererType.length() > 0)
3122         setWindowRenderer(rendererType);
3123 
3124     // Apply the new look to the widget
3125     setLookNFeel(type);
3126 }
3127 
3128 //----------------------------------------------------------------------------//
isTopOfZOrder() const3129 bool Window::isTopOfZOrder() const
3130 {
3131     // if not attached, then always on top!
3132     if (!d_parent)
3133         return true;
3134 
3135     // get position of window at top of z-order in same group as this window
3136     ChildDrawList::reverse_iterator pos = getParent()->d_drawList.rbegin();
3137     if (!d_alwaysOnTop)
3138     {
3139         // find last non-topmost window
3140         while ((pos != getParent()->d_drawList.rend()) && (*pos)->isAlwaysOnTop())
3141             ++pos;
3142     }
3143 
3144     // return whether the window at the top of the z order is us
3145     return *pos == this;
3146 }
3147 
3148 //----------------------------------------------------------------------------//
insertText(const String & text,const String::size_type position)3149 void Window::insertText(const String& text, const String::size_type position)
3150 {
3151     d_textLogical.insert(position, text);
3152     d_renderedStringValid = false;
3153     d_bidiDataValid = false;
3154 
3155     WindowEventArgs args(this);
3156     onTextChanged(args);
3157 }
3158 
3159 //----------------------------------------------------------------------------//
appendText(const String & text)3160 void Window::appendText(const String& text)
3161 {
3162     d_textLogical.append(text);
3163     d_renderedStringValid = false;
3164     d_bidiDataValid = false;
3165 
3166     WindowEventArgs args(this);
3167     onTextChanged(args);
3168 }
3169 
3170 //----------------------------------------------------------------------------//
getGeometryBuffer()3171 GeometryBuffer& Window::getGeometryBuffer()
3172 {
3173     return *d_geometry;
3174 }
3175 
3176 //----------------------------------------------------------------------------//
getRenderingContext(RenderingContext & ctx) const3177 void Window::getRenderingContext(RenderingContext& ctx) const
3178 {
3179     if (d_windowRenderer)
3180         d_windowRenderer->getRenderingContext(ctx);
3181     else
3182         getRenderingContext_impl(ctx);
3183 }
3184 
3185 //----------------------------------------------------------------------------//
getRenderingContext_impl(RenderingContext & ctx) const3186 void Window::getRenderingContext_impl(RenderingContext& ctx) const
3187 {
3188     if (d_surface)
3189     {
3190         ctx.surface = d_surface;
3191         ctx.owner = this;
3192         ctx.offset = getUnclippedOuterRect().get().getPosition();
3193         ctx.queue = RQ_BASE;
3194     }
3195     else if (d_parent)
3196     {
3197         getParent()->getRenderingContext(ctx);
3198     }
3199     else
3200     {
3201         ctx.surface = &getGUIContext();
3202         ctx.owner = 0;
3203         ctx.offset = Vector2f(0, 0);
3204         ctx.queue = RQ_BASE;
3205     }
3206 }
3207 
3208 //----------------------------------------------------------------------------//
getRenderingSurface() const3209 RenderingSurface* Window::getRenderingSurface() const
3210 {
3211     return d_surface;
3212 }
3213 
3214 //----------------------------------------------------------------------------//
getTargetRenderingSurface() const3215 RenderingSurface& Window::getTargetRenderingSurface() const
3216 {
3217     if (d_surface)
3218         return *d_surface;
3219     else if (d_parent)
3220         return getParent()->getTargetRenderingSurface();
3221     else
3222         return getGUIContext();
3223 }
3224 
3225 //----------------------------------------------------------------------------//
setRenderingSurface(RenderingSurface * surface)3226 void Window::setRenderingSurface(RenderingSurface* surface)
3227 {
3228     if (d_surface == surface)
3229         return;
3230 
3231     if (d_autoRenderingWindow)
3232         setUsingAutoRenderingSurface(false);
3233 
3234     d_surface = surface;
3235 
3236     // transfer child surfaces to this new surface
3237     if (d_surface)
3238     {
3239         transferChildSurfaces();
3240         notifyScreenAreaChanged();
3241     }
3242 }
3243 
3244 //----------------------------------------------------------------------------//
invalidateRenderingSurface()3245 void Window::invalidateRenderingSurface()
3246 {
3247     // invalidate our surface chain if we have one
3248     if (d_surface)
3249         d_surface->invalidate();
3250     // else look through the hierarchy for a surface chain to invalidate.
3251     else if (d_parent)
3252         getParent()->invalidateRenderingSurface();
3253 }
3254 
3255 //----------------------------------------------------------------------------//
getRootWindow() const3256 const Window* Window::getRootWindow() const
3257 {
3258     return d_parent ? getParent()->getRootWindow() : this;
3259 }
3260 
3261 //----------------------------------------------------------------------------//
getRootWindow()3262 Window* Window::getRootWindow()
3263 {
3264     return const_cast<Window*>(
3265         static_cast<const Window*>(this)->getRootWindow());
3266 }
3267 
3268 //----------------------------------------------------------------------------//
isUsingAutoRenderingSurface() const3269 bool Window::isUsingAutoRenderingSurface() const
3270 {
3271     return d_autoRenderingWindow;
3272 }
3273 
3274 //----------------------------------------------------------------------------//
setUsingAutoRenderingSurface(bool setting)3275 void Window::setUsingAutoRenderingSurface(bool setting)
3276 {
3277     if (setting)
3278     {
3279         allocateRenderingWindow();
3280     }
3281     else
3282     {
3283         releaseRenderingWindow();
3284 
3285         // make sure we set this because releaseRenderingWindow won't do it
3286         // unless the surface was already initialised
3287         d_autoRenderingWindow = setting;
3288     }
3289 
3290     // while the actal area on screen may not have changed, the arrangement of
3291     // surfaces and geometry did...
3292     notifyScreenAreaChanged();
3293 }
3294 
3295 //----------------------------------------------------------------------------//
allocateRenderingWindow()3296 void Window::allocateRenderingWindow()
3297 {
3298     if (!d_autoRenderingWindow)
3299     {
3300         d_autoRenderingWindow = true;
3301 
3302         TextureTarget* const t =
3303             System::getSingleton().getRenderer()->createTextureTarget();
3304 
3305         // TextureTargets may not be available, so check that first.
3306         if (!t)
3307         {
3308             Logger::getSingleton().logEvent("Window::allocateRenderingWindow - "
3309                 "Failed to create a suitable TextureTarget for use by Window '"
3310                 + d_name + "'", Errors);
3311 
3312             d_surface = 0;
3313             return;
3314         }
3315 
3316         d_surface = &getTargetRenderingSurface().createRenderingWindow(*t);
3317         transferChildSurfaces();
3318 
3319         // set size and position of RenderingWindow
3320         static_cast<RenderingWindow*>(d_surface)->setSize(getPixelSize());
3321         static_cast<RenderingWindow*>(d_surface)->
3322             setPosition(getUnclippedOuterRect().get().getPosition());
3323 
3324         getGUIContext().markAsDirty();
3325     }
3326 }
3327 
3328 //----------------------------------------------------------------------------//
releaseRenderingWindow()3329 void Window::releaseRenderingWindow()
3330 {
3331     if (d_autoRenderingWindow && d_surface)
3332     {
3333         RenderingWindow* const old_surface =
3334             static_cast<RenderingWindow*>(d_surface);
3335         d_autoRenderingWindow = false;
3336         d_surface = 0;
3337         // detach child surfaces prior to destroying the owning surface
3338         transferChildSurfaces();
3339         // destroy surface and texture target it used
3340         TextureTarget* tt = &old_surface->getTextureTarget();
3341         old_surface->getOwner().destroyRenderingWindow(*old_surface);
3342         System::getSingleton().getRenderer()->destroyTextureTarget(tt);
3343 
3344         getGUIContext().markAsDirty();
3345     }
3346 }
3347 
3348 //----------------------------------------------------------------------------//
transferChildSurfaces()3349 void Window::transferChildSurfaces()
3350 {
3351     RenderingSurface& s = getTargetRenderingSurface();
3352 
3353     const size_t child_count = getChildCount();
3354     for (size_t i = 0; i < child_count; ++i)
3355     {
3356         Window* const c = getChildAtIdx(i);
3357 
3358         if (c->d_surface && c->d_surface->isRenderingWindow())
3359             s.transferRenderingWindow(
3360                 *static_cast<RenderingWindow*>(c->d_surface));
3361         else
3362             c->transferChildSurfaces();
3363     }
3364 }
3365 
3366 //----------------------------------------------------------------------------//
initialiseClippers(const RenderingContext & ctx)3367 void Window::initialiseClippers(const RenderingContext& ctx)
3368 {
3369     if (ctx.surface->isRenderingWindow() && ctx.owner == this)
3370     {
3371         RenderingWindow* const rendering_window =
3372             static_cast<RenderingWindow*>(ctx.surface);
3373 
3374         if (d_clippedByParent && d_parent)
3375             rendering_window->setClippingRegion(
3376                 getParent()->getClipRect(d_nonClient));
3377         else
3378             rendering_window->setClippingRegion(
3379                 Rectf(Vector2f(0, 0), getRootContainerSize()));
3380 
3381         d_geometry->setClippingRegion(Rectf(Vector2f(0, 0), d_pixelSize));
3382     }
3383     else
3384     {
3385         Rectf geo_clip(getOuterRectClipper());
3386 
3387         if (geo_clip.getWidth() != 0.0f && geo_clip.getHeight() != 0.0f)
3388             geo_clip.offset(Vector2f(-ctx.offset.d_x, -ctx.offset.d_y));
3389 
3390         d_geometry->setClippingRegion(geo_clip);
3391     }
3392 }
3393 
3394 //----------------------------------------------------------------------------//
onRotated(ElementEventArgs & e)3395 void Window::onRotated(ElementEventArgs& e)
3396 {
3397     Element::onRotated(e);
3398 
3399     // TODO: Checking quaternion for equality with IDENTITY is stupid,
3400     //       change this to something else, checking with tolerance.
3401     if (d_rotation != Quaternion::IDENTITY && !d_surface)
3402     {
3403         // if we have no surface set and the rotation differs from identity,
3404         // enable the auto surface
3405 
3406         Logger::getSingleton().logEvent("Window::setRotation - "
3407             "Activating AutoRenderingSurface on Window '" + d_name +
3408             "' to enable rotation support.");
3409 
3410         setUsingAutoRenderingSurface(true);
3411 
3412         // still no surface?  Renderer or HW must not support what we need :(
3413         if (!d_surface)
3414         {
3415             Logger::getSingleton().logEvent("Window::setRotation - "
3416                 "Failed to obtain a suitable ReneringWindow surface for "
3417                 "Window '" + d_name + "'.  Rotation will not be available.",
3418                 Errors);
3419 
3420             return;
3421         }
3422     }
3423 
3424     if (d_surface)
3425     {
3426         // ensure surface we have is the right type
3427         if (!d_surface->isRenderingWindow())
3428         {
3429             Logger::getSingleton().logEvent("Window::setRotation - "
3430                 "Window '" + d_name + "' has a manual RenderingSurface that is not "
3431                 "a RenderingWindow.  Rotation will not be available.", Errors);
3432 
3433             return;
3434         }
3435 
3436         // Checks / setup complete!  Now we can finally set the rotation.
3437         static_cast<RenderingWindow*>(d_surface)->setRotation(d_rotation);
3438         static_cast<RenderingWindow*>(d_surface)->setPivot(
3439             Vector3f(d_pixelSize.d_width / 2.0f, d_pixelSize.d_height / 2.0f, 0.0f));
3440     }
3441 }
3442 
3443 //----------------------------------------------------------------------------//
getRenderedString() const3444 const RenderedString& Window::getRenderedString() const
3445 {
3446     if (!d_renderedStringValid)
3447     {
3448         d_renderedString = getRenderedStringParser().parse(
3449             getTextVisual(), 0, 0);
3450         d_renderedStringValid = true;
3451     }
3452 
3453     return d_renderedString;
3454 }
3455 
3456 //----------------------------------------------------------------------------//
getCustomRenderedStringParser() const3457 RenderedStringParser* Window::getCustomRenderedStringParser() const
3458 {
3459     return d_customStringParser;
3460 }
3461 
3462 //----------------------------------------------------------------------------//
setCustomRenderedStringParser(RenderedStringParser * parser)3463 void Window::setCustomRenderedStringParser(RenderedStringParser* parser)
3464 {
3465     d_customStringParser = parser;
3466     d_renderedStringValid = false;
3467 }
3468 
3469 //----------------------------------------------------------------------------//
getRenderedStringParser() const3470 RenderedStringParser& Window::getRenderedStringParser() const
3471 {
3472     // if parsing is disabled, we use a DefaultRenderedStringParser that creates
3473     // a RenderedString to renderi the input text verbatim (i.e. no parsing).
3474     if (!d_textParsingEnabled)
3475         return d_defaultStringParser;
3476 
3477     // Next prefer a custom RenderedStringParser assigned to this Window.
3478     if (d_customStringParser)
3479         return *d_customStringParser;
3480 
3481     // Next prefer any globally set RenderedStringParser.
3482     RenderedStringParser* const global_parser =
3483         CEGUI::System::getSingleton().getDefaultCustomRenderedStringParser();
3484     if (global_parser)
3485         return *global_parser;
3486 
3487     // if parsing is enabled and no custom RenderedStringParser is set anywhere,
3488     // use the system's BasicRenderedStringParser to do the parsing.
3489     return d_basicStringParser;
3490 }
3491 
3492 //----------------------------------------------------------------------------//
getUnprojectedPosition(const Vector2f & pos) const3493 Vector2f Window::getUnprojectedPosition(const Vector2f& pos) const
3494 {
3495     RenderingSurface* rs = &getTargetRenderingSurface();
3496 
3497     // if window is not backed by RenderingWindow, return same pos.
3498     if (!rs->isRenderingWindow())
3499         return pos;
3500 
3501     // get first target RenderingWindow
3502     RenderingWindow* rw = static_cast<RenderingWindow*>(rs);
3503 
3504     // setup for loop
3505     Vector2f out_pos(pos);
3506 
3507     // while there are rendering windows
3508     while (rw)
3509     {
3510         // unproject the point for the current rw
3511         const Vector2f in_pos(out_pos);
3512         rw->unprojectPoint(in_pos, out_pos);
3513 
3514         // get next rendering window, if any
3515         rw = (rs = &rw->getOwner())->isRenderingWindow() ?
3516                 static_cast<RenderingWindow*>(rs) : 0;
3517     }
3518 
3519     return out_pos;
3520 }
3521 
3522 //----------------------------------------------------------------------------//
getTextVisual() const3523 const String& Window::getTextVisual() const
3524 {
3525     // no bidi support
3526     if (!d_bidiVisualMapping)
3527         return d_textLogical;
3528 
3529     if (!d_bidiDataValid)
3530     {
3531         d_bidiVisualMapping->updateVisual(d_textLogical);
3532         d_bidiDataValid = true;
3533     }
3534 
3535     return d_bidiVisualMapping->getTextVisual();
3536 }
3537 
3538 //----------------------------------------------------------------------------//
isTextParsingEnabled() const3539 bool Window::isTextParsingEnabled() const
3540 {
3541     return d_textParsingEnabled;
3542 }
3543 
3544 //----------------------------------------------------------------------------//
setTextParsingEnabled(const bool setting)3545 void Window::setTextParsingEnabled(const bool setting)
3546 {
3547     d_textParsingEnabled = setting;
3548     d_renderedStringValid = false;
3549 
3550     WindowEventArgs args(this);
3551     onTextParsingChanged(args);
3552 }
3553 
3554 //----------------------------------------------------------------------------//
setMargin(const UBox & margin)3555 void Window::setMargin(const UBox& margin)
3556 {
3557     d_margin = margin;
3558 
3559     WindowEventArgs args(this);
3560     onMarginChanged(args);
3561 }
3562 
3563 //----------------------------------------------------------------------------//
getMargin() const3564 const UBox& Window::getMargin() const
3565 {
3566     return d_margin;
3567 }
3568 
3569 //----------------------------------------------------------------------------//
onTextParsingChanged(WindowEventArgs & e)3570 void Window::onTextParsingChanged(WindowEventArgs& e)
3571 {
3572     fireEvent(EventTextParsingChanged, e, EventNamespace);
3573 }
3574 
3575 //----------------------------------------------------------------------------//
onMarginChanged(WindowEventArgs & e)3576 void Window::onMarginChanged(WindowEventArgs& e)
3577 {
3578     fireEvent(EventMarginChanged, e, EventNamespace);
3579 }
3580 
3581 //----------------------------------------------------------------------------//
moveInFront(const Window * const window)3582 void Window::moveInFront(const Window* const window)
3583 {
3584     if (!window || !window->d_parent || window->d_parent != d_parent ||
3585         window == this || window->d_alwaysOnTop != d_alwaysOnTop ||
3586         !d_zOrderingEnabled)
3587             return;
3588 
3589     // find our position in the parent child draw list
3590     const ChildDrawList::iterator p(std::find(getParent()->d_drawList.begin(),
3591                                               getParent()->d_drawList.end(),
3592                                               this));
3593     // sanity checK that we were attached to our parent.
3594     assert(p != getParent()->d_drawList.end());
3595 
3596     // erase us from our current position
3597     getParent()->d_drawList.erase(p);
3598 
3599     // find window we're to be moved in front of in parent's draw list
3600     ChildDrawList::iterator i(std::find(getParent()->d_drawList.begin(),
3601                                         getParent()->d_drawList.end(),
3602                                         window));
3603     // sanity check that target window was also attached to correct parent.
3604     assert(i != getParent()->d_drawList.end());
3605 
3606     // reinsert ourselves at the right location
3607     getParent()->d_drawList.insert(++i, this);
3608 
3609     // handle event notifications for affected windows.
3610     onZChange_impl();
3611 }
3612 
3613 //----------------------------------------------------------------------------//
moveBehind(const Window * const window)3614 void Window::moveBehind(const Window* const window)
3615 {
3616     if (!window || !window->d_parent || window->d_parent != d_parent ||
3617         window == this || window->d_alwaysOnTop != d_alwaysOnTop ||
3618         !d_zOrderingEnabled)
3619             return;
3620 
3621     // find our position in the parent child draw list
3622     const ChildDrawList::iterator p(std::find(getParent()->d_drawList.begin(),
3623                                               getParent()->d_drawList.end(),
3624                                               this));
3625     // sanity checK that we were attached to our parent.
3626     assert(p != getParent()->d_drawList.end());
3627 
3628     // erase us from our current position
3629     getParent()->d_drawList.erase(p);
3630 
3631     // find window we're to be moved in front of in parent's draw list
3632     const ChildDrawList::iterator i(std::find(getParent()->d_drawList.begin(),
3633                                               getParent()->d_drawList.end(),
3634                                               window));
3635     // sanity check that target window was also attached to correct parent.
3636     assert(i != getParent()->d_drawList.end());
3637 
3638     // reinsert ourselves at the right location
3639     getParent()->d_drawList.insert(i, this);
3640 
3641     // handle event notifications for affected windows.
3642     onZChange_impl();
3643 }
3644 
3645 //----------------------------------------------------------------------------//
setUpdateMode(const WindowUpdateMode mode)3646 void Window::setUpdateMode(const WindowUpdateMode mode)
3647 {
3648     d_updateMode = mode;
3649 }
3650 
3651 //----------------------------------------------------------------------------//
getUpdateMode() const3652 WindowUpdateMode Window::getUpdateMode() const
3653 {
3654     return d_updateMode;
3655 }
3656 
3657 //----------------------------------------------------------------------------//
setMouseInputPropagationEnabled(const bool enabled)3658 void Window::setMouseInputPropagationEnabled(const bool enabled)
3659 {
3660     d_propagateMouseInputs = enabled;
3661 }
3662 
3663 //----------------------------------------------------------------------------//
isMouseInputPropagationEnabled() const3664 bool Window::isMouseInputPropagationEnabled() const
3665 {
3666     return d_propagateMouseInputs;
3667 }
3668 
3669 //----------------------------------------------------------------------------//
clone(const bool deepCopy) const3670 Window* Window::clone(const bool deepCopy) const
3671 {
3672     Window* ret =
3673         WindowManager::getSingleton().createWindow(getType(), getName());
3674 
3675     // always copy properties
3676     clonePropertiesTo(*ret);
3677 
3678     // if user requested deep copy, we should copy children as well
3679     if (deepCopy)
3680         cloneChildWidgetsTo(*ret);
3681 
3682     return ret;
3683 }
3684 
3685 //----------------------------------------------------------------------------//
clonePropertiesTo(Window & target) const3686 void Window::clonePropertiesTo(Window& target) const
3687 {
3688     for (PropertySet::PropertyIterator propertyIt = getPropertyIterator();
3689          !propertyIt.isAtEnd();
3690          ++propertyIt)
3691     {
3692         const String& propertyName = propertyIt.getCurrentKey();
3693         const String propertyValue = getProperty(propertyName);
3694 
3695         // we never copy stuff that doesn't get written into XML
3696         if (isPropertyBannedFromXML(propertyName))
3697             continue;
3698 
3699         // some cases when propertyValue is "" could lead to exception throws
3700         if (propertyValue.empty())
3701         {
3702             // special case, this causes exception throw when no window renderer
3703             // is assigned to the window
3704             if (propertyName == "LookNFeel")
3705                 continue;
3706 
3707             // special case, this causes exception throw because we are setting
3708             // 'null' window renderer
3709             if (propertyName == "WindowRenderer")
3710                 continue;
3711         }
3712 
3713         target.setProperty(propertyName, propertyValue);
3714     }
3715 }
3716 
3717 //----------------------------------------------------------------------------//
cloneChildWidgetsTo(Window & target) const3718 void Window::cloneChildWidgetsTo(Window& target) const
3719 {
3720     // todo: ChildWindowIterator?
3721     for (size_t childI = 0; childI < getChildCount(); ++childI)
3722     {
3723         Window* child = getChildAtIdx(childI);
3724         if (child->isAutoWindow())
3725         {
3726             // we skip auto windows, they are already created
3727             // automatically
3728 
3729             // note: some windows store non auto windows inside auto windows,
3730             //       standard solution is to copy these non-auto windows to
3731             //       the parent window
3732             //
3733             //       If you need alternative behaviour, you have to override
3734             //       this method!
3735 
3736             // so just copy it's child widgets
3737             child->cloneChildWidgetsTo(target);
3738             // and skip the auto widget
3739             continue;
3740         }
3741 
3742         Window* newChild = child->clone(true);
3743         target.addChild(newChild);
3744     }
3745 }
3746 
3747 //----------------------------------------------------------------------------//
getZIndex() const3748 size_t Window::getZIndex() const
3749 {
3750     if (!d_parent)
3751         return 0;
3752 
3753     ChildDrawList::iterator i = std::find(
3754         getParent()->d_drawList.begin(),
3755         getParent()->d_drawList.end(),
3756         this);
3757 
3758     if (i == getParent()->d_drawList.end())
3759         CEGUI_THROW(InvalidRequestException(
3760             "Window is not in its parent's draw list."));
3761 
3762     return std::distance(getParent()->d_drawList.begin(), i);
3763 }
3764 
3765 //----------------------------------------------------------------------------//
isInFront(const Window & wnd) const3766 bool Window::isInFront(const Window& wnd) const
3767 {
3768     // children are always in front of their ancestors
3769     if (isAncestor(&wnd))
3770         return true;
3771 
3772     // conversely, ancestors are always behind their children
3773     if (wnd.isAncestor(this))
3774         return false;
3775 
3776     const Window* const w1 = getWindowAttachedToCommonAncestor(wnd);
3777 
3778     // seems not to be in same window hierarchy
3779     if (!w1)
3780         return false;
3781 
3782     const Window* const w2 = wnd.getWindowAttachedToCommonAncestor(*this);
3783 
3784     // at this point, w1 and w2 share the same parent.
3785     return w2->getZIndex() > w1->getZIndex();
3786 }
3787 
3788 //----------------------------------------------------------------------------//
getWindowAttachedToCommonAncestor(const Window & wnd) const3789 const Window* Window::getWindowAttachedToCommonAncestor(const Window& wnd) const
3790 {
3791     const Window* w = &wnd;
3792     const Window* tmp = w->getParent();
3793 
3794     while (tmp)
3795     {
3796         if (isAncestor(tmp))
3797             break;
3798 
3799         w = tmp;
3800         tmp = tmp->getParent();
3801     }
3802 
3803     return tmp ? w : 0;
3804 }
3805 
3806 //----------------------------------------------------------------------------//
isBehind(const Window & wnd) const3807 bool Window::isBehind(const Window& wnd) const
3808 {
3809     return !isInFront(wnd);
3810 }
3811 
3812 //----------------------------------------------------------------------------//
property_getFont() const3813 const Font* Window::property_getFont() const
3814 {
3815     // This is changed behaviour when compared to 0.7, we return the Font set
3816     // for this window but we don't return name of the default font when
3817     // no font is set. This is IMO more practical. User can always use
3818     // getFont() directly to get 0.7 behaviour.
3819 
3820     return getFont(false);
3821 }
3822 
3823 //----------------------------------------------------------------------------//
property_getMouseCursor() const3824 const Image* Window::property_getMouseCursor() const
3825 {
3826     return getMouseCursor();
3827 }
3828 
3829 //----------------------------------------------------------------------------//
getGUIContext() const3830 GUIContext& Window::getGUIContext() const
3831 {
3832     // GUIContext is always the one on the root window, we do not allow parts
3833     // of a hierarchy to be drawn to separate contexts (which is not much of
3834     // a limitation).
3835     //
3836     // ISSUE: if root has no GUIContext set for it, should we return 0 or
3837     //        System::getDefaultGUIContext?  Come to IRC and argue about it!
3838     if (getParent() != 0)
3839     {
3840         return getParent()->getGUIContext();
3841     }
3842     else
3843     {
3844         if (d_guiContext)
3845             return *d_guiContext;
3846         else
3847             return System::getSingleton().getDefaultGUIContext();
3848     }
3849 }
3850 
3851 //----------------------------------------------------------------------------//
setGUIContext(GUIContext * context)3852 void Window::setGUIContext(GUIContext* context)
3853 {
3854     if (d_guiContext == context)
3855         return;
3856 
3857     d_guiContext = context;
3858     syncTargetSurface();
3859 }
3860 
3861 //----------------------------------------------------------------------------//
getRootContainerSize() const3862 const Sizef& Window::getRootContainerSize() const
3863 {
3864     return getGUIContext().getSurfaceSize();
3865 }
3866 
3867 //----------------------------------------------------------------------------//
setAutoWindow(bool is_auto)3868 void Window::setAutoWindow(bool is_auto)
3869 {
3870     d_autoWindow = is_auto;
3871 
3872     if (d_autoWindow)
3873         banPropertiesForAutoWindow();
3874 }
3875 
3876 //----------------------------------------------------------------------------//
banPropertiesForAutoWindow()3877 void Window::banPropertiesForAutoWindow()
3878 {
3879     banPropertyFromXML("AutoWindow"); // :-D
3880     banPropertyFromXML("DestroyedByParent");
3881     banPropertyFromXML("VerticalAlignment");
3882     banPropertyFromXML("HorizontalAlignment");
3883     banPropertyFromXML("Area");
3884     banPropertyFromXML("Position");
3885     banPropertyFromXML("Size");
3886     banPropertyFromXML("MinSize");
3887     banPropertyFromXML("MaxSize");
3888     banPropertyFromXML(&d_windowRendererProperty);
3889     banPropertyFromXML(&d_lookNFeelProperty);
3890 }
3891 
3892 //----------------------------------------------------------------------------//
handleFontRenderSizeChange(const EventArgs & args)3893 bool Window::handleFontRenderSizeChange(const EventArgs& args)
3894 {
3895     if (!d_windowRenderer)
3896         return false;
3897 
3898     return d_windowRenderer->handleFontRenderSizeChange(
3899         static_cast<const FontEventArgs&>(args).font);
3900 }
3901 
3902 //----------------------------------------------------------------------------//
isMouseContainedInArea() const3903 bool Window::isMouseContainedInArea() const
3904 {
3905     return d_containsMouse;
3906 }
3907 
3908 //----------------------------------------------------------------------------//
3909 
3910 #if defined(_MSC_VER)
3911 #   pragma warning(pop)
3912 #endif
3913 
3914 } // End of  CEGUI namespace section
3915