Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

CEGUIScrollablePane.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       CEGUIScrollablePane.cpp
00003         created:        1/3/2005
00004         author:         Paul D Turner
00005 *************************************************************************/
00006 /*************************************************************************
00007     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00008     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00009 
00010     This library is free software; you can redistribute it and/or
00011     modify it under the terms of the GNU Lesser General Public
00012     License as published by the Free Software Foundation; either
00013     version 2.1 of the License, or (at your option) any later version.
00014 
00015     This library is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018     Lesser General Public License for more details.
00019 
00020     You should have received a copy of the GNU Lesser General Public
00021     License along with this library; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 *************************************************************************/
00024 #include "elements/CEGUIScrollablePane.h"
00025 #include "elements/CEGUIScrolledContainer.h"
00026 #include "elements/CEGUIScrollbar.h"
00027 #include "CEGUIWindowManager.h"
00028 #include <math.h>
00029 
00030 // Start of CEGUI namespace section
00031 namespace CEGUI
00032 {
00034     // Event name constants
00035     const String ScrollablePane::EventNamespace("ScrollablePane");
00036     const String ScrollablePane::EventContentPaneChanged("ContentPaneChanged");
00037     const String ScrollablePane::EventVertScrollbarModeChanged("VertScrollbarModeChanged");
00038     const String ScrollablePane::EventHorzScrollbarModeChanged("HorzScrollbarModeChanged");
00039     const String ScrollablePane::EventAutoSizeSettingChanged("AutoSizeSettingChanged");
00040     const String ScrollablePane::EventContentPaneScrolled("ContentPaneScrolled");
00041     // Property objects
00042     ScrollablePaneProperties::ForceHorzScrollbar   ScrollablePane::d_horzScrollbarProperty;
00043     ScrollablePaneProperties::ForceVertScrollbar   ScrollablePane::d_vertScrollbarProperty;
00044     ScrollablePaneProperties::ContentPaneAutoSized ScrollablePane::d_autoSizedProperty;
00045     ScrollablePaneProperties::ContentArea          ScrollablePane::d_contentAreaProperty;
00046     ScrollablePaneProperties::HorzStepSize         ScrollablePane::d_horzStepProperty;
00047     ScrollablePaneProperties::HorzOverlapSize      ScrollablePane::d_horzOverlapProperty;
00048     ScrollablePaneProperties::HorzScrollPosition   ScrollablePane::d_horzScrollPositionProperty;
00049     ScrollablePaneProperties::VertStepSize         ScrollablePane::d_vertStepProperty;
00050     ScrollablePaneProperties::VertOverlapSize      ScrollablePane::d_vertOverlapProperty;
00051     ScrollablePaneProperties::VertScrollPosition   ScrollablePane::d_vertScrollPositionProperty;
00053 
00054     ScrollablePane::ScrollablePane(const String& type, const String& name) :
00055         Window(type, name),
00056         d_forceVertScroll(false),
00057         d_forceHorzScroll(false),
00058         d_contentRect(0, 0, 0, 0),
00059         d_vertStep(0.1f),
00060         d_vertOverlap(0.01f),
00061         d_horzStep(0.1f),
00062         d_horzOverlap(0.01f),
00063         d_vertScrollbar(0),
00064         d_horzScrollbar(0),
00065         d_container(0)
00066     {
00067         addScrollablePaneEvents();
00068         addScrollablePaneProperties();
00069     }
00070 
00071     ScrollablePane::~ScrollablePane(void)
00072     {
00073     }
00074 
00075     const ScrolledContainer* ScrollablePane::getContentPane(void) const
00076     {
00077         assert (d_container != 0);
00078         return d_container;
00079     }
00080 
00081     bool ScrollablePane::isVertScrollbarAlwaysShown(void) const
00082     {
00083         return d_forceVertScroll;
00084     }
00085 
00086     void ScrollablePane::setShowVertScrollbar(bool setting)
00087     {
00088         if (d_forceVertScroll != setting)
00089         {
00090             d_forceVertScroll = setting;
00091 
00092             configureScrollbars();
00093             WindowEventArgs args(this);
00094             onVertScrollbarModeChanged(args);
00095         }
00096     }
00097 
00098     bool ScrollablePane::isHorzScrollbarAlwaysShown(void) const
00099     {
00100         return d_forceHorzScroll;
00101     }
00102 
00103     void ScrollablePane::setShowHorzScrollbar(bool setting)
00104     {
00105         if (d_forceHorzScroll != setting)
00106         {
00107             d_forceHorzScroll = setting;
00108 
00109             configureScrollbars();
00110             WindowEventArgs args(this);
00111             onHorzScrollbarModeChanged(args);
00112         }
00113     }
00114 
00115     bool ScrollablePane::isContentPaneAutoSized(void) const
00116     {
00117         assert(d_container != 0);
00118         return d_container->isContentPaneAutoSized();
00119     }
00120 
00121     void ScrollablePane::setContentPaneAutoSized(bool setting)
00122     {
00123         assert(d_container != 0);
00124         d_container->setContentPaneAutoSized(setting);
00125     }
00126 
00127     const Rect& ScrollablePane::getContentPaneArea(void) const
00128     {
00129         assert(d_container != 0);
00130         return d_container->getContentArea();
00131     }
00132 
00133     void ScrollablePane::setContentPaneArea(const Rect& area)
00134     {
00135         assert(d_container != 0);
00136         d_container->setContentArea(area);
00137     }
00138 
00139     float ScrollablePane::getHorizontalStepSize(void) const
00140     {
00141         return d_horzStep;
00142     }
00143 
00144     void ScrollablePane::setHorizontalStepSize(float step)
00145     {
00146         d_horzStep = step;
00147         configureScrollbars();
00148     }
00149 
00150     float ScrollablePane::getHorizontalOverlapSize(void) const
00151     {
00152         return d_horzOverlap;
00153     }
00154 
00155     void ScrollablePane::setHorizontalOverlapSize(float overlap)
00156     {
00157         d_horzOverlap = overlap;
00158         configureScrollbars();
00159     }
00160 
00161     float ScrollablePane::getHorizontalScrollPosition(void) const
00162     {
00163         assert(d_horzScrollbar != 0);
00164         float docSz = d_horzScrollbar->getDocumentSize();
00165         return (docSz != 0) ? d_horzScrollbar->getScrollPosition() / docSz : 0.0f;
00166     }
00167 
00168     void ScrollablePane::setHorizontalScrollPosition(float position)
00169     {
00170         assert(d_horzScrollbar != 0);
00171         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getDocumentSize() * position);
00172     }
00173 
00174     float ScrollablePane::getVerticalStepSize(void) const
00175     {
00176         return d_vertStep;
00177     }
00178 
00179     void ScrollablePane::setVerticalStepSize(float step)
00180     {
00181         d_vertStep = step;
00182         configureScrollbars();
00183     }
00184 
00185     float ScrollablePane::getVerticalOverlapSize(void) const
00186     {
00187         return d_vertOverlap;
00188     }
00189 
00190     void ScrollablePane::setVerticalOverlapSize(float overlap)
00191     {
00192         d_vertOverlap = overlap;
00193         configureScrollbars();
00194     }
00195 
00196     float ScrollablePane::getVerticalScrollPosition(void) const
00197     {
00198         assert(d_vertScrollbar != 0);
00199         float docSz = d_vertScrollbar->getDocumentSize();
00200         return (docSz != 0) ? d_vertScrollbar->getScrollPosition() / docSz : 0.0f;
00201     }
00202 
00203     void ScrollablePane::setVerticalScrollPosition(float position)
00204     {
00205         assert(d_vertScrollbar != 0);
00206         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getDocumentSize() * position);
00207     }
00208 
00209     void ScrollablePane::initialise(void)
00210     {
00211         String widgetName;
00212         // create horizontal scrollbar
00213         widgetName = d_name + "__auto_hscrollbar__";
00214         d_horzScrollbar = createHorizontalScrollbar(widgetName);
00215         // perform consistency checks on what we got back
00216         assert(d_horzScrollbar != 0);
00217         assert(d_horzScrollbar->getName() == widgetName);
00218 
00219         // create vertical scrollbar
00220         widgetName = d_name + "__auto_vscrollbar__";
00221         d_vertScrollbar = createVerticalScrollbar(widgetName);
00222         // perform consistency checks on what we got back
00223         assert(d_vertScrollbar != 0);
00224         assert(d_vertScrollbar->getName() == widgetName);
00225 
00226         // create scrolled container widget
00227         d_container = 
00228             static_cast<ScrolledContainer*>(WindowManager::getSingleton().createWindow(
00229                 ScrolledContainer::WidgetTypeName, d_name + "__auto_container__"));
00230 
00231         // add child controls
00232         addChildWindow(d_horzScrollbar);
00233         addChildWindow(d_vertScrollbar);
00234         addChildWindow(d_container);
00235 
00236         // do a bit of initialisation
00237         d_horzScrollbar->setAlwaysOnTop(true);
00238         d_vertScrollbar->setAlwaysOnTop(true);
00239         // container pane is always same size as this parent pane,
00240         // scrolling is actually implemented via positioning and clipping tricks.
00241         d_container->setSize(Relative, Size(1.0f, 1.0f));
00242 
00243         // subscribe to events we need to hear about
00244         d_vertScrollbar->subscribeEvent(
00245             Scrollbar::EventScrollPositionChanged,
00246             Event::Subscriber(&ScrollablePane::handleScrollChange, this));
00247         d_horzScrollbar->subscribeEvent(
00248             Scrollbar::EventScrollPositionChanged,
00249             Event::Subscriber(&ScrollablePane::handleScrollChange, this));
00250         d_container->subscribeEvent(
00251             ScrolledContainer::EventContentChanged,
00252             Event::Subscriber(&ScrollablePane::handleContentAreaChange, this));
00253         d_container->subscribeEvent(
00254             ScrolledContainer::EventAutoSizeSettingChanged,
00255             Event::Subscriber(&ScrollablePane::handleAutoSizePaneChanged, this));
00256 
00257         // finalise setup
00258         configureScrollbars();
00259     }
00260 
00261     void ScrollablePane::addScrollablePaneEvents(void)
00262     {
00263         addEvent(EventAutoSizeSettingChanged);
00264         addEvent(EventContentPaneChanged);
00265         addEvent(EventHorzScrollbarModeChanged);
00266         addEvent(EventVertScrollbarModeChanged);
00267         addEvent(EventContentPaneScrolled);
00268     }
00269 
00270     void ScrollablePane::configureScrollbars(void)
00271     {
00272         // controls should all be valid by this stage
00273         assert(d_container != 0);
00274         assert(d_vertScrollbar != 0);
00275         assert(d_horzScrollbar != 0);
00276 
00277         // enable required scrollbars
00278         d_vertScrollbar->setVisible(isVertScrollbarNeeded());
00279         d_horzScrollbar->setVisible(isHorzScrollbarNeeded());
00280 
00281         // Check if the addition of the horizontal scrollbar means we
00282         // now also need the vertical bar.
00283         if (d_horzScrollbar->isVisible())
00284         {
00285             d_vertScrollbar->setVisible(isVertScrollbarNeeded());
00286         }
00287 
00288         performChildWindowLayout();
00289 
00290         // get viewable area
00291         Rect viewableArea(getViewableArea());
00292 
00293         // set up vertical scroll bar values
00294         d_vertScrollbar->setDocumentSize(fabsf(d_contentRect.getHeight()));
00295         d_vertScrollbar->setPageSize(viewableArea.getHeight());
00296         d_vertScrollbar->setStepSize(ceguimax(1.0f, viewableArea.getHeight() * d_vertStep));
00297         d_vertScrollbar->setOverlapSize(ceguimax(1.0f, viewableArea.getHeight() * d_vertOverlap));
00298         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition());
00299 
00300         // set up horizontal scroll bar values
00301         d_horzScrollbar->setDocumentSize(fabsf(d_contentRect.getWidth()));
00302         d_horzScrollbar->setPageSize(viewableArea.getWidth());
00303         d_horzScrollbar->setStepSize(ceguimax(1.0f, viewableArea.getWidth() * d_horzStep));
00304         d_horzScrollbar->setOverlapSize(ceguimax(1.0f, viewableArea.getWidth() * d_horzOverlap));
00305         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition());
00306     }
00307 
00308     bool ScrollablePane::isHorzScrollbarNeeded(void) const
00309     {
00310         assert(d_container != 0);
00311 
00312         return ((fabs(d_contentRect.getWidth()) > getViewableArea().getWidth()) || d_forceHorzScroll);
00313     }
00314 
00315     bool ScrollablePane::isVertScrollbarNeeded(void) const
00316     {
00317         assert(d_container != 0);
00318 
00319         return ((fabs(d_contentRect.getHeight()) > getViewableArea().getHeight()) || d_forceVertScroll);
00320     }
00321 
00322     void ScrollablePane::updateContainerPosition(void)
00323     {
00324         assert(d_container != 0);
00325         assert(d_horzScrollbar != 0);
00326         assert(d_vertScrollbar != 0);
00327 
00328         // basePos is the position represented by the scrollbars
00329         // (these are negated so pane is scrolled in the correct directions)
00330         Point basePos(-d_horzScrollbar->getScrollPosition(), -d_vertScrollbar->getScrollPosition());
00331 
00332         // this bias is the absolute position that 0 on the scrollbars represent.
00333         // effectively removes un-used empty space from the pane.
00334         Point bias(d_contentRect.d_left, d_contentRect.d_top);
00335 
00336         // set the new container pane position to be what the scrollbars request
00337         // minus any bias generated by the location of the content.
00338         d_container->setPosition(Absolute, basePos - bias);
00339     }
00340 
00341     void ScrollablePane::onContentPaneChanged(WindowEventArgs& e)
00342     {
00343         fireEvent(EventContentPaneChanged, e, EventNamespace);
00344     }
00345 
00346     void ScrollablePane::onVertScrollbarModeChanged(WindowEventArgs& e)
00347     {
00348         fireEvent(EventVertScrollbarModeChanged, e, EventNamespace);
00349     }
00350 
00351     void ScrollablePane::onHorzScrollbarModeChanged(WindowEventArgs& e)
00352     {
00353         fireEvent(EventHorzScrollbarModeChanged, e, EventNamespace);
00354     }
00355 
00356     void ScrollablePane::onAutoSizeSettingChanged(WindowEventArgs& e)
00357     {
00358         fireEvent(EventAutoSizeSettingChanged, e, EventNamespace);
00359     }
00360 
00361     void ScrollablePane::onContentPaneScrolled(WindowEventArgs& e)
00362     {
00363         updateContainerPosition();
00364         fireEvent(EventContentPaneScrolled, e, EventNamespace);
00365     }
00366 
00367     bool ScrollablePane::handleScrollChange(const EventArgs& e)
00368     {
00369         WindowEventArgs args(this);
00370         onContentPaneScrolled(args);
00371         return true;
00372     }
00373 
00374     bool ScrollablePane::handleContentAreaChange(const EventArgs& e)
00375     {
00376         assert(d_container != 0);
00377         assert(d_horzScrollbar != 0);
00378         assert(d_vertScrollbar != 0);
00379 
00380         // get updated extents of the content
00381         Rect contentArea(d_container->getContentArea());
00382 
00383         // calculate any change on the top and left edges.
00384         float xChange = contentArea.d_left - d_contentRect.d_left;
00385         float yChange = contentArea.d_top - d_contentRect.d_top;
00386 
00387         // store new content extents information
00388         d_contentRect = contentArea;
00389 
00390         configureScrollbars();
00391 
00392         // update scrollbar positions (which causes container pane to be moved as needed).
00393         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() - xChange);
00394         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() - yChange);
00395 
00396         // this call may already have been made if the scroll positions changed.  The call
00397         // is required here for cases where the top/left 'bias' has changed; in which
00398         // case the scroll position notification may or may not have been fired.
00399         if (xChange || yChange)
00400         {
00401             updateContainerPosition();
00402         }
00403     
00404         // fire event
00405         WindowEventArgs args(this);
00406         onContentPaneChanged(args);
00407 
00408         return true;
00409     }
00410 
00411     bool ScrollablePane::handleAutoSizePaneChanged(const EventArgs& e)
00412     {
00413         // just forward event to client.
00414         WindowEventArgs args(this);
00415         fireEvent(EventAutoSizeSettingChanged, args, EventNamespace);
00416         return args.handled;
00417     }
00418 
00419     void ScrollablePane::addChild_impl(Window* wnd)
00420     {
00421         // null is not a valid window pointer!
00422         assert(wnd != 0);
00423 
00424         // See if this is an internally generated window (will have "__auto_" in the name)
00425         if (wnd->getName().find("__auto_") != String::npos)
00426         {
00427             // This is an internal widget, so should be added normally.
00428             Window::addChild_impl(wnd);
00429         }
00430         // this is a client window/widget, so should be added to the pane container.
00431         else
00432         {
00433             // container should always be valid by the time we're adding client controls
00434             assert(d_container != 0);
00435             d_container->addChildWindow(wnd);
00436         }
00437     }
00438 
00439     void ScrollablePane::removeChild_impl(Window* wnd)
00440     {
00441         // null is not a valid window pointer!
00442         assert(wnd != 0);
00443 
00444         // See if this is an internally generated window (will have "__auto_" in the name)
00445         if (wnd->getName().find("__auto_") != String::npos)
00446         {
00447             // This is an internal widget, so should be removed normally.
00448             Window::removeChild_impl(wnd);
00449         }
00450         // this is a client window/widget, so should be removed from the pane container.
00451         else
00452         {
00453             // container should always be valid by the time we're handling client controls
00454             assert(d_container != 0);
00455             d_container->removeChildWindow(wnd);
00456         }
00457     }
00458 
00459     void ScrollablePane::onSized(WindowEventArgs& e)
00460     {
00461         Window::onSized(e);
00462         configureScrollbars();
00463         updateContainerPosition();
00464 
00465         e.handled = true;
00466     }
00467 
00468     void ScrollablePane::onMouseWheel(MouseEventArgs& e)
00469     {
00470         // base class processing.
00471         Window::onMouseWheel(e);
00472 
00473         if (d_vertScrollbar->isVisible() && (d_vertScrollbar->getDocumentSize() > d_vertScrollbar->getPageSize()))
00474         {
00475             d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + d_vertScrollbar->getStepSize() * -e.wheelChange);
00476         }
00477         else if (d_horzScrollbar->isVisible() && (d_horzScrollbar->getDocumentSize() > d_horzScrollbar->getPageSize()))
00478         {
00479             d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + d_horzScrollbar->getStepSize() * -e.wheelChange);
00480         }
00481 
00482         e.handled = true;
00483     }
00484 
00485     void ScrollablePane::addScrollablePaneProperties(void)
00486     {
00487         addProperty(&d_horzScrollbarProperty);
00488         addProperty(&d_vertScrollbarProperty);
00489         addProperty(&d_autoSizedProperty);
00490         addProperty(&d_contentAreaProperty);
00491         addProperty(&d_horzStepProperty);
00492         addProperty(&d_horzOverlapProperty);
00493         addProperty(&d_horzScrollPositionProperty);
00494         addProperty(&d_vertStepProperty);
00495         addProperty(&d_vertOverlapProperty);
00496         addProperty(&d_vertScrollPositionProperty);
00497     }
00498 
00499 } // End of  CEGUI namespace section

Generated on Wed Sep 7 09:56:33 2005 for Crazy Eddies GUI System by  doxygen 1.4.3