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