1 /***********************************************************************
2 created: 1/3/2005
3 author: Paul D Turner
4 *************************************************************************/
5 /***************************************************************************
6 * Copyright (C) 2004 - 2015 Paul D Turner & The CEGUI Development Team
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 ***************************************************************************/
27 #include "CEGUI/widgets/ScrollablePane.h"
28 #include "CEGUI/widgets/ScrolledContainer.h"
29 #include "CEGUI/widgets/Scrollbar.h"
30 #include "CEGUI/WindowManager.h"
31 #include "CEGUI/Exceptions.h"
32 #include <math.h>
33
34 // Start of CEGUI namespace section
35 namespace CEGUI
36 {
37 //----------------------------------------------------------------------------//
38 const String ScrollablePane::WidgetTypeName("CEGUI/ScrollablePane");
39 const String ScrollablePane::EventNamespace("ScrollablePane");
40 const String ScrollablePane::EventContentPaneChanged("ContentPaneChanged");
41 const String ScrollablePane::EventVertScrollbarModeChanged("VertScrollbarModeChanged");
42 const String ScrollablePane::EventHorzScrollbarModeChanged("HorzScrollbarModeChanged");
43 const String ScrollablePane::EventAutoSizeSettingChanged("AutoSizeSettingChanged");
44 const String ScrollablePane::EventContentPaneScrolled("ContentPaneScrolled");
45 const String ScrollablePane::VertScrollbarName( "__auto_vscrollbar__" );
46 const String ScrollablePane::HorzScrollbarName( "__auto_hscrollbar__" );
47 const String ScrollablePane::ScrolledContainerName( "__auto_container__" );
48 //----------------------------------------------------------------------------//
ScrollablePaneWindowRenderer(const String & name)49 ScrollablePaneWindowRenderer::ScrollablePaneWindowRenderer(const String& name) :
50 WindowRenderer(name, ScrollablePane::EventNamespace)
51 {
52 }
53
54 //----------------------------------------------------------------------------//
ScrollablePane(const String & type,const String & name)55 ScrollablePane::ScrollablePane(const String& type, const String& name) :
56 Window(type, name),
57 d_forceVertScroll(false),
58 d_forceHorzScroll(false),
59 d_contentRect(0, 0, 0, 0),
60 d_vertStep(0.1f),
61 d_vertOverlap(0.01f),
62 d_horzStep(0.1f),
63 d_horzOverlap(0.01f)
64 {
65 addScrollablePaneProperties();
66
67 // create scrolled container widget
68 ScrolledContainer* container = static_cast<ScrolledContainer*>(
69 WindowManager::getSingleton().createWindow(
70 ScrolledContainer::WidgetTypeName,
71 ScrolledContainerName));
72 container->setAutoWindow(true);
73
74 // add scrolled container widget as child
75 addChild(container);
76 }
77
78 //----------------------------------------------------------------------------//
~ScrollablePane(void)79 ScrollablePane::~ScrollablePane(void)
80 {}
81
82 //----------------------------------------------------------------------------//
getContentPane(void) const83 const ScrolledContainer* ScrollablePane::getContentPane(void) const
84 {
85 return getScrolledContainer();
86 }
87
88 //----------------------------------------------------------------------------//
isVertScrollbarAlwaysShown(void) const89 bool ScrollablePane::isVertScrollbarAlwaysShown(void) const
90 {
91 return d_forceVertScroll;
92 }
93
94 //----------------------------------------------------------------------------//
setShowVertScrollbar(bool setting)95 void ScrollablePane::setShowVertScrollbar(bool setting)
96 {
97 if (d_forceVertScroll != setting)
98 {
99 d_forceVertScroll = setting;
100
101 configureScrollbars();
102 WindowEventArgs args(this);
103 onVertScrollbarModeChanged(args);
104 }
105 }
106
107 //----------------------------------------------------------------------------//
isHorzScrollbarAlwaysShown(void) const108 bool ScrollablePane::isHorzScrollbarAlwaysShown(void) const
109 {
110 return d_forceHorzScroll;
111 }
112
113 //----------------------------------------------------------------------------//
setShowHorzScrollbar(bool setting)114 void ScrollablePane::setShowHorzScrollbar(bool setting)
115 {
116 if (d_forceHorzScroll != setting)
117 {
118 d_forceHorzScroll = setting;
119
120 configureScrollbars();
121 WindowEventArgs args(this);
122 onHorzScrollbarModeChanged(args);
123 }
124 }
125
126 //----------------------------------------------------------------------------//
isContentPaneAutoSized(void) const127 bool ScrollablePane::isContentPaneAutoSized(void) const
128 {
129 return getScrolledContainer()->isContentPaneAutoSized();
130 }
131
132 //----------------------------------------------------------------------------//
setContentPaneAutoSized(bool setting)133 void ScrollablePane::setContentPaneAutoSized(bool setting)
134 {
135 getScrolledContainer()->setContentPaneAutoSized(setting);
136 }
137
138 //----------------------------------------------------------------------------//
getContentPaneArea(void) const139 const Rectf& ScrollablePane::getContentPaneArea(void) const
140 {
141 return getScrolledContainer()->getContentArea();
142 }
143
144 //----------------------------------------------------------------------------//
setContentPaneArea(const Rectf & area)145 void ScrollablePane::setContentPaneArea(const Rectf& area)
146 {
147 getScrolledContainer()->setContentArea(area);
148 }
149
150 //----------------------------------------------------------------------------//
getHorizontalStepSize(void) const151 float ScrollablePane::getHorizontalStepSize(void) const
152 {
153 return d_horzStep;
154 }
155
156 //----------------------------------------------------------------------------//
setHorizontalStepSize(float step)157 void ScrollablePane::setHorizontalStepSize(float step)
158 {
159 d_horzStep = step;
160 configureScrollbars();
161 }
162
163 //----------------------------------------------------------------------------//
getHorizontalOverlapSize(void) const164 float ScrollablePane::getHorizontalOverlapSize(void) const
165 {
166 return d_horzOverlap;
167 }
168
169 //----------------------------------------------------------------------------//
setHorizontalOverlapSize(float overlap)170 void ScrollablePane::setHorizontalOverlapSize(float overlap)
171 {
172 d_horzOverlap = overlap;
173 configureScrollbars();
174 }
175
176 //----------------------------------------------------------------------------//
getHorizontalScrollPosition(void) const177 float ScrollablePane::getHorizontalScrollPosition(void) const
178 {
179 return getHorzScrollbar()->getUnitIntervalScrollPosition();
180 }
181
182 //----------------------------------------------------------------------------//
setHorizontalScrollPosition(float position)183 void ScrollablePane::setHorizontalScrollPosition(float position)
184 {
185 getHorzScrollbar()->setUnitIntervalScrollPosition(position);
186 }
187
188 //----------------------------------------------------------------------------//
getVerticalStepSize(void) const189 float ScrollablePane::getVerticalStepSize(void) const
190 {
191 return d_vertStep;
192 }
193
194 //----------------------------------------------------------------------------//
setVerticalStepSize(float step)195 void ScrollablePane::setVerticalStepSize(float step)
196 {
197 d_vertStep = step;
198 configureScrollbars();
199 }
200
201 //----------------------------------------------------------------------------//
getVerticalOverlapSize(void) const202 float ScrollablePane::getVerticalOverlapSize(void) const
203 {
204 return d_vertOverlap;
205 }
206
207 //----------------------------------------------------------------------------//
setVerticalOverlapSize(float overlap)208 void ScrollablePane::setVerticalOverlapSize(float overlap)
209 {
210 d_vertOverlap = overlap;
211 configureScrollbars();
212 }
213
214 //----------------------------------------------------------------------------//
getVerticalScrollPosition(void) const215 float ScrollablePane::getVerticalScrollPosition(void) const
216 {
217 return getVertScrollbar()->getUnitIntervalScrollPosition();
218 }
219
220 //----------------------------------------------------------------------------//
setVerticalScrollPosition(float position)221 void ScrollablePane::setVerticalScrollPosition(float position)
222 {
223 getVertScrollbar()->setUnitIntervalScrollPosition(position);
224 }
225
226 //----------------------------------------------------------------------------//
initialiseComponents(void)227 void ScrollablePane::initialiseComponents(void)
228 {
229 // get horizontal scrollbar
230 Scrollbar* horzScrollbar = getHorzScrollbar();
231
232 // get vertical scrollbar
233 Scrollbar* vertScrollbar = getVertScrollbar();
234
235 // get scrolled container widget
236 ScrolledContainer* container = getScrolledContainer();
237
238 // ban properties forwarded from here
239 container->banPropertyFromXML(Window::MouseInputPropagationEnabledPropertyName);
240 container->banPropertyFromXML("ContentArea");
241 container->banPropertyFromXML("ContentPaneAutoSized");
242 horzScrollbar->banPropertyFromXML(Window::AlwaysOnTopPropertyName);
243 vertScrollbar->banPropertyFromXML(Window::AlwaysOnTopPropertyName);
244
245 // do a bit of initialisation
246 horzScrollbar->setAlwaysOnTop(true);
247 vertScrollbar->setAlwaysOnTop(true);
248 // container pane is always same size as this parent pane,
249 // scrolling is actually implemented via positioning and clipping tricks.
250 container->setSize(USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));
251
252 // subscribe to events we need to hear about
253 vertScrollbar->subscribeEvent(
254 Scrollbar::EventScrollPositionChanged,
255 Event::Subscriber(&ScrollablePane::handleScrollChange, this));
256
257 horzScrollbar->subscribeEvent(
258 Scrollbar::EventScrollPositionChanged,
259 Event::Subscriber(&ScrollablePane::handleScrollChange, this));
260
261 d_contentChangedConn = container->subscribeEvent(
262 ScrolledContainer::EventContentChanged,
263 Event::Subscriber(&ScrollablePane::handleContentAreaChange, this));
264
265 d_autoSizeChangedConn = container->subscribeEvent(
266 ScrolledContainer::EventAutoSizeSettingChanged,
267 Event::Subscriber(&ScrollablePane::handleAutoSizePaneChanged, this));
268
269 // finalise setup
270 configureScrollbars();
271 }
272
273 //----------------------------------------------------------------------------//
configureScrollbars(void)274 void ScrollablePane::configureScrollbars(void)
275 {
276 // controls should all be valid by this stage
277 Scrollbar* const vertScrollbar = getVertScrollbar();
278 Scrollbar* const horzScrollbar = getHorzScrollbar();
279
280 const bool horzScrollBarWasVisible = horzScrollbar->isVisible();
281 const bool vertScrollBarWasVisible = vertScrollbar->isVisible();
282
283 // enable required scrollbars
284 vertScrollbar->setVisible(isVertScrollbarNeeded());
285 horzScrollbar->setVisible(isHorzScrollbarNeeded());
286
287 // Check if the addition of the horizontal scrollbar means we
288 // now also need the vertical bar.
289 if (horzScrollbar->isVisible())
290 vertScrollbar->setVisible(isVertScrollbarNeeded());
291
292 if (horzScrollBarWasVisible != horzScrollbar->isVisible() ||
293 vertScrollBarWasVisible != vertScrollbar->isVisible())
294 {
295 ElementEventArgs args(this);
296 onSized(args);
297 }
298
299 performChildWindowLayout();
300
301 // get viewable area
302 const Rectf viewableArea(getViewableArea());
303
304 // set up vertical scroll bar values
305 vertScrollbar->setDocumentSize(fabsf(d_contentRect.getHeight()));
306 vertScrollbar->setPageSize(viewableArea.getHeight());
307 vertScrollbar->setStepSize(ceguimax(1.0f, viewableArea.getHeight() * d_vertStep));
308 vertScrollbar->setOverlapSize(ceguimax(1.0f, viewableArea.getHeight() * d_vertOverlap));
309 vertScrollbar->setScrollPosition(vertScrollbar->getScrollPosition());
310
311 // set up horizontal scroll bar values
312 horzScrollbar->setDocumentSize(fabsf(d_contentRect.getWidth()));
313 horzScrollbar->setPageSize(viewableArea.getWidth());
314 horzScrollbar->setStepSize(ceguimax(1.0f, viewableArea.getWidth() * d_horzStep));
315 horzScrollbar->setOverlapSize(ceguimax(1.0f, viewableArea.getWidth() * d_horzOverlap));
316 horzScrollbar->setScrollPosition(horzScrollbar->getScrollPosition());
317 }
318
319 //----------------------------------------------------------------------------//
isHorzScrollbarNeeded(void) const320 bool ScrollablePane::isHorzScrollbarNeeded(void) const
321 {
322 return ((fabs(d_contentRect.getWidth()) > getViewableArea().getWidth()) ||
323 d_forceHorzScroll);
324 }
325
326 //----------------------------------------------------------------------------//
isVertScrollbarNeeded(void) const327 bool ScrollablePane::isVertScrollbarNeeded(void) const
328 {
329 return ((fabs(d_contentRect.getHeight()) > getViewableArea().getHeight()) ||
330 d_forceVertScroll);
331 }
332
333 //----------------------------------------------------------------------------//
updateContainerPosition(void)334 void ScrollablePane::updateContainerPosition(void)
335 {
336 // basePos is the position represented by the scrollbars
337 // (these are negated so pane is scrolled in the correct directions)
338 UVector2 basePos(cegui_absdim(-getHorzScrollbar()->getScrollPosition()),
339 cegui_absdim(-getVertScrollbar()->getScrollPosition()));
340
341 // this bias is the absolute position that 0 on the scrollbars represent.
342 // Allows the pane to function correctly with negatively positioned content.
343 UVector2 bias(cegui_absdim(d_contentRect.d_min.d_x),
344 cegui_absdim(d_contentRect.d_min.d_y));
345
346 // set the new container pane position to be what the scrollbars request
347 // minus any bias generated by the location of the content.
348 getScrolledContainer()->setPosition(basePos - bias);
349 }
350
351 //----------------------------------------------------------------------------//
validateWindowRenderer(const WindowRenderer * renderer) const352 bool ScrollablePane::validateWindowRenderer(const WindowRenderer* renderer) const
353 {
354 return dynamic_cast<const ScrollablePaneWindowRenderer*>(renderer) != 0;
355 }
356
357 //----------------------------------------------------------------------------//
onContentPaneChanged(WindowEventArgs & e)358 void ScrollablePane::onContentPaneChanged(WindowEventArgs& e)
359 {
360 fireEvent(EventContentPaneChanged, e, EventNamespace);
361 }
362
363 //----------------------------------------------------------------------------//
onVertScrollbarModeChanged(WindowEventArgs & e)364 void ScrollablePane::onVertScrollbarModeChanged(WindowEventArgs& e)
365 {
366 fireEvent(EventVertScrollbarModeChanged, e, EventNamespace);
367 }
368
369 //----------------------------------------------------------------------------//
onHorzScrollbarModeChanged(WindowEventArgs & e)370 void ScrollablePane::onHorzScrollbarModeChanged(WindowEventArgs& e)
371 {
372 fireEvent(EventHorzScrollbarModeChanged, e, EventNamespace);
373 }
374
375 //----------------------------------------------------------------------------//
onAutoSizeSettingChanged(WindowEventArgs & e)376 void ScrollablePane::onAutoSizeSettingChanged(WindowEventArgs& e)
377 {
378 fireEvent(EventAutoSizeSettingChanged, e, EventNamespace);
379 }
380
381 //----------------------------------------------------------------------------//
onContentPaneScrolled(WindowEventArgs & e)382 void ScrollablePane::onContentPaneScrolled(WindowEventArgs& e)
383 {
384 updateContainerPosition();
385 fireEvent(EventContentPaneScrolled, e, EventNamespace);
386 }
387
388 //----------------------------------------------------------------------------//
handleScrollChange(const EventArgs &)389 bool ScrollablePane::handleScrollChange(const EventArgs&)
390 {
391 WindowEventArgs args(this);
392 onContentPaneScrolled(args);
393 return true;
394 }
395
396 //----------------------------------------------------------------------------//
handleContentAreaChange(const EventArgs &)397 bool ScrollablePane::handleContentAreaChange(const EventArgs&)
398 {
399 // get updated extents of the content
400 const Rectf contentArea(getScrolledContainer()->getContentArea());
401
402 // calculate any change on the top and left edges.
403 const float xChange = contentArea.d_min.d_x - d_contentRect.d_min.d_x;
404 const float yChange = contentArea.d_min.d_y - d_contentRect.d_min.d_y;
405
406 // store new content extents information
407 d_contentRect = contentArea;
408
409 configureScrollbars();
410
411 // update scrollbar positions (which causes container pane to be moved as needed).
412 Scrollbar* const horzScrollbar = getHorzScrollbar();
413 horzScrollbar->setScrollPosition(horzScrollbar->getScrollPosition() - xChange);
414 Scrollbar* const vertScrollbar = getVertScrollbar();
415 vertScrollbar->setScrollPosition(vertScrollbar->getScrollPosition() - yChange);
416
417 // this call may already have been made if the scroll positions changed. The call
418 // is required here for cases where the top/left 'bias' has changed; in which
419 // case the scroll position notification may or may not have been fired.
420 if (xChange || yChange)
421 updateContainerPosition();
422
423 // fire event
424 WindowEventArgs args(this);
425 onContentPaneChanged(args);
426
427 return true;
428 }
429
430 //----------------------------------------------------------------------------//
handleAutoSizePaneChanged(const EventArgs &)431 bool ScrollablePane::handleAutoSizePaneChanged(const EventArgs&)
432 {
433 // just forward event to client.
434 WindowEventArgs args(this);
435 fireEvent(EventAutoSizeSettingChanged, args, EventNamespace);
436 return args.handled > 0;
437 }
438
439 //----------------------------------------------------------------------------//
addChild_impl(Element * element)440 void ScrollablePane::addChild_impl(Element* element)
441 {
442 Window* wnd = dynamic_cast<Window*>(element);
443
444 if (!wnd)
445 CEGUI_THROW(InvalidRequestException(
446 "ScrollablePane can only have Elements of "
447 "type Window added as children (Window path: " +
448 getNamePath() + ")."));
449
450 if (wnd->isAutoWindow())
451 {
452 // This is an internal widget, so should be added normally.
453 Window::addChild_impl(wnd);
454 }
455 // this is a client window/widget, so should be added to the pane container.
456 else
457 {
458 // container should always be valid by the time we're adding client
459 // controls
460 getScrolledContainer()->addChild(wnd);
461 }
462 }
463
464 //----------------------------------------------------------------------------//
removeChild_impl(Element * element)465 void ScrollablePane::removeChild_impl(Element* element)
466 {
467 Window* wnd = static_cast<Window*>(element);
468
469 if (wnd->isAutoWindow())
470 {
471 // This is an internal widget, so should be removed normally.
472 Window::removeChild_impl(wnd);
473 }
474 // this is a client window/widget, so should be removed from the pane
475 // container.
476 else
477 {
478 // container should always be valid by the time we're handling client
479 // controls
480 getScrolledContainer()->removeChild(wnd);
481 }
482 }
483
484 //----------------------------------------------------------------------------//
onSized(ElementEventArgs & e)485 void ScrollablePane::onSized(ElementEventArgs& e)
486 {
487 configureScrollbars();
488 updateContainerPosition();
489 Window::onSized(e);
490
491 ++e.handled;
492 }
493
494 //----------------------------------------------------------------------------//
onMouseWheel(MouseEventArgs & e)495 void ScrollablePane::onMouseWheel(MouseEventArgs& e)
496 {
497 // base class processing.
498 Window::onMouseWheel(e);
499
500 Scrollbar* vertScrollbar = getVertScrollbar();
501 Scrollbar* horzScrollbar = getHorzScrollbar();
502
503 if (vertScrollbar->isEffectiveVisible() &&
504 (vertScrollbar->getDocumentSize() > vertScrollbar->getPageSize()))
505 {
506 vertScrollbar->setScrollPosition(vertScrollbar->getScrollPosition() +
507 vertScrollbar->getStepSize() * -e.wheelChange);
508 }
509 else if (horzScrollbar->isEffectiveVisible() &&
510 (horzScrollbar->getDocumentSize() > horzScrollbar->getPageSize()))
511 {
512 horzScrollbar->setScrollPosition(horzScrollbar->getScrollPosition() +
513 horzScrollbar->getStepSize() * -e.wheelChange);
514 }
515
516 ++e.handled;
517 }
518
519 //----------------------------------------------------------------------------//
addScrollablePaneProperties(void)520 void ScrollablePane::addScrollablePaneProperties(void)
521 {
522 const String& propertyOrigin = WidgetTypeName;
523
524 CEGUI_DEFINE_PROPERTY(ScrollablePane, bool,
525 "ForceVertScrollbar", "Property to get/set the 'always show' setting for the vertical scroll "
526 "bar of the tree. Value is either \"true\" or \"false\".",
527 &ScrollablePane::setShowVertScrollbar, &ScrollablePane::isVertScrollbarAlwaysShown, false /* TODO: Inconsistency */
528 );
529
530 CEGUI_DEFINE_PROPERTY(ScrollablePane, bool,
531 "ForceHorzScrollbar", "Property to get/set the 'always show' setting for the horizontal "
532 "scroll bar of the tree. Value is either \"true\" or \"false\".",
533 &ScrollablePane::setShowHorzScrollbar, &ScrollablePane::isHorzScrollbarAlwaysShown, false /* TODO: Inconsistency */
534 );
535
536 CEGUI_DEFINE_PROPERTY(ScrollablePane, float,
537 "HorzStepSize", "Property to get/set the step size for the horizontal Scrollbar. Value is a float.",
538 &ScrollablePane::setHorizontalStepSize, &ScrollablePane::getHorizontalStepSize, 0.1f /* TODO: Inconsistency */
539 );
540
541 CEGUI_DEFINE_PROPERTY(ScrollablePane, float,
542 "HorzOverlapSize", "Property to get/set the overlap size for the horizontal Scrollbar. Value is a float.",
543 &ScrollablePane::setHorizontalOverlapSize, &ScrollablePane::getHorizontalOverlapSize, 0.01f /* TODO: Inconsistency */
544 );
545
546 CEGUI_DEFINE_PROPERTY(ScrollablePane, float,
547 "HorzScrollPosition", "Property to get/set the scroll position of the horizontal Scrollbar as a fraction. Value is a float.",
548 &ScrollablePane::setHorizontalScrollPosition, &ScrollablePane::getHorizontalScrollPosition, 0.0f
549 );
550
551 CEGUI_DEFINE_PROPERTY(ScrollablePane, float,
552 "VertStepSize", "Property to get/set the step size for the vertical Scrollbar. Value is a float.",
553 &ScrollablePane::setVerticalStepSize, &ScrollablePane::getVerticalStepSize, 0.1f /* TODO: Inconsistency */
554 );
555
556 CEGUI_DEFINE_PROPERTY(ScrollablePane, float,
557 "VertOverlapSize", "Property to get/set the overlap size for the vertical Scrollbar. Value is a float.",
558 &ScrollablePane::setVerticalOverlapSize, &ScrollablePane::getVerticalOverlapSize, 0.01f /* TODO: Inconsistency */
559 );
560
561 CEGUI_DEFINE_PROPERTY(ScrollablePane, float,
562 "VertScrollPosition", "Property to get/set the scroll position of the vertical Scrollbar as a fraction. Value is a float.",
563 &ScrollablePane::setVerticalScrollPosition, &ScrollablePane::getVerticalScrollPosition, 0.0f /* TODO: Inconsistency */
564 );
565
566 CEGUI_DEFINE_PROPERTY(ScrollablePane, bool,
567 "ContentPaneAutoSized", "Property to get/set the setting which controls whether the content pane will auto-size itself. Value is either \"true\" or \"false\".",
568 &ScrollablePane::setContentPaneAutoSized, &ScrollablePane::isContentPaneAutoSized, true
569 );
570
571 CEGUI_DEFINE_PROPERTY(ScrollablePane, Rectf,
572 "ContentArea", "Property to get/set the current content area rectangle of the content pane. Value is \"l:[float] t:[float] r:[float] b:[float]\" (where l is left, t is top, r is right, and b is bottom).",
573 &ScrollablePane::setContentPaneArea, &ScrollablePane::getContentPaneArea, Rectf::zero() /* TODO: Inconsistency */
574 );
575 }
576
577 //----------------------------------------------------------------------------//
getVertScrollbar() const578 Scrollbar* ScrollablePane::getVertScrollbar() const
579 {
580 return static_cast<Scrollbar*>(getChild(VertScrollbarName));
581 }
582
583 //----------------------------------------------------------------------------//
getHorzScrollbar() const584 Scrollbar* ScrollablePane::getHorzScrollbar() const
585 {
586 return static_cast<Scrollbar*>(getChild(HorzScrollbarName));
587 }
588
589 //----------------------------------------------------------------------------//
getScrolledContainer() const590 ScrolledContainer* ScrollablePane::getScrolledContainer() const
591 {
592 return static_cast<ScrolledContainer*>(getChild(ScrolledContainerName));
593 }
594
595 //----------------------------------------------------------------------------//
getViewableArea() const596 Rectf ScrollablePane::getViewableArea() const
597 {
598 if (!d_windowRenderer)
599 CEGUI_THROW(InvalidRequestException(
600 "This function must be implemented by the window renderer module"));
601
602 ScrollablePaneWindowRenderer* wr =
603 static_cast<ScrollablePaneWindowRenderer*>(d_windowRenderer);
604 return wr->getViewableArea();
605 }
606
607 //----------------------------------------------------------------------------//
destroy(void)608 void ScrollablePane::destroy(void)
609 {
610 // detach from events on content pane
611 d_contentChangedConn->disconnect();
612 d_autoSizeChangedConn->disconnect();
613
614 // now do the cleanup
615 Window::destroy();
616 }
617
618 //----------------------------------------------------------------------------//
getChildByNamePath_impl(const String & name_path) const619 NamedElement* ScrollablePane::getChildByNamePath_impl(const String& name_path) const
620 {
621 // FIXME: This is horrible
622 //
623 if (name_path.substr(0, 7) == "__auto_")
624 return Window::getChildByNamePath_impl(name_path);
625 else
626 return Window::getChildByNamePath_impl(ScrolledContainerName + '/' + name_path);
627 }
628 //----------------------------------------------------------------------------//
629
writeChildWindowsXML(XMLSerializer & xml_stream) const630 int ScrollablePane::writeChildWindowsXML(XMLSerializer& xml_stream) const
631 {
632 // This is an easy and safe workaround for not writing out the buttonPane and contentPane. While in fact
633 // we would eventually want to write these two to XML themselves, we do not want to write out their children
634 // but there is no way to control this from inside these windows and currently there is also no way to do it
635 // from the outside. This was determined to be the best solution, others would break ABI or are too hacky
636 // Negative side-effects: any changes to AutoWindows (properties etc) will be lost in the output
637 bool wasContentPaneWritingAllowed = getScrolledContainer()->isWritingXMLAllowed();
638
639 getScrolledContainer()->setWritingXMLAllowed(false);
640
641 int childOutputCount = Window::writeChildWindowsXML(xml_stream);
642
643 getScrolledContainer()->setWritingXMLAllowed(wasContentPaneWritingAllowed);
644
645 // since TabControl content is actually added to the component tab
646 // content pane window, this overridden function exists to dump those
647 // out as if they were our own children.
648 const size_t childCount = getContentPane()->getChildCount();
649 for (size_t i = 0; i < childCount; ++i)
650 {
651 getScrolledContainer()->getChildAtIdx(i)->writeXMLToStream(xml_stream);
652 ++childOutputCount;
653 }
654
655 return childOutputCount;
656 }
657
658 }
659