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

CEGUITabControl.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       CEGUITabControl.cpp
00003         created:        08/08/2004
00004         author:         Steve Streeting
00005         
00006         purpose:        Implementation of Tab Control widget base class
00007 *************************************************************************/
00008 /*************************************************************************
00009     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00010     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00011 
00012     This library is free software; you can redistribute it and/or
00013     modify it under the terms of the GNU Lesser General Public
00014     License as published by the Free Software Foundation; either
00015     version 2.1 of the License, or (at your option) any later version.
00016 
00017     This library is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020     Lesser General Public License for more details.
00021 
00022     You should have received a copy of the GNU Lesser General Public
00023     License along with this library; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 *************************************************************************/
00026 #include "CEGUIExceptions.h"
00027 #include "elements/CEGUITabControl.h"
00028 #include "elements/CEGUITabButton.h"
00029 #include "elements/CEGUIStatic.h"
00030 #include "elements/CEGUIGUISheet.h"
00031 #include "CEGUIFont.h"
00032 #include "CEGUIWindowManager.h"
00033 
00034 // Start of CEGUI namespace section
00035 namespace CEGUI
00036 {
00037 const String TabControl::EventNamespace("TabControl");
00038 
00039 /*************************************************************************
00040         Definition of Properties for this class
00041 *************************************************************************/
00042 TabControlProperties::TabHeight                     TabControl::d_tabHeightProperty;
00043 TabControlProperties::AbsoluteTabHeight         TabControl::d_absoluteTabHeightProperty;
00044 TabControlProperties::RelativeTabHeight         TabControl::d_relativeTabHeightProperty;
00045 TabControlProperties::TabTextPadding                TabControl::d_tabTextPaddingProperty;
00046 TabControlProperties::AbsoluteTabTextPadding    TabControl::d_absoluteTabTextPaddingProperty;
00047 TabControlProperties::RelativeTabTextPadding    TabControl::d_relativeTabTextPaddingProperty;
00048 
00049 /*************************************************************************
00050         Constants
00051 *************************************************************************/
00052 // event names
00053 const String TabControl::EventSelectionChanged( (utf8*)"TabSelectionChanged" );
00054 
00055         
00056 /*************************************************************************
00057         Constructor for TabControl base class.
00058 *************************************************************************/
00059 TabControl::TabControl(const String& type, const String& name)
00060         : Window(type, name),
00061     d_tabButtonPane(NULL),
00062     d_tabContentPane(NULL),
00063     d_nextTabIndex(0)
00064 {
00065         addTabControlEvents();
00066         addTabControlProperties();
00067     setRelativeTabHeight(0.05f);
00068     setAbsoluteTabTextPadding(5);
00069 }
00070 
00071 
00072 /*************************************************************************
00073         Destructor for TabControl base class.
00074 *************************************************************************/
00075 TabControl::~TabControl(void)
00076 {
00077     // Should be handled in superclass (all child windows)
00078 }
00079 
00080 /*************************************************************************
00081         Initialise the Window based object ready for use.
00082 *************************************************************************/
00083 void TabControl::initialise(void)
00084 {
00085         // create the component sub-widgets
00086         d_tabContentPane = createTabContentPane(getName() + "__auto_TabPane__");
00087     d_tabButtonPane = createTabButtonPane(getName() + "__auto_TabPane__Buttons");
00088 
00089         addChildWindow(d_tabContentPane);
00090     addChildWindow(d_tabButtonPane);
00091 
00092         performChildWindowLayout();
00093 }
00094 /*************************************************************************
00095 Get the number of tabs
00096 *************************************************************************/
00097 uint TabControl::getTabCount(void) const
00098 {   
00099     return d_tabContentPane->getChildCount();
00100 }
00101 /*************************************************************************
00102 Get the tab with a given name
00103 *************************************************************************/
00104 Window* TabControl::getTabContents(const String& name) const
00105 {
00106     return d_tabContentPane->getChild(name);
00107 }
00108 /*************************************************************************
00109 Get the tab at a given ID
00110 *************************************************************************/
00111 Window* TabControl::getTabContents(uint ID) const
00112 {
00113     return d_tabContentPane->getChild(ID);
00114 }
00115 /*************************************************************************
00116 Get the tab for the given index
00117 *************************************************************************/
00118 Window* TabControl::getTabContentsAtIndex(uint index) const
00119 {
00120     return d_tabButtonIndexMap.find(index)->second->getTargetWindow();
00121 }
00122 
00123 /*************************************************************************
00124 Return whether the tab content window is currently selected.
00125 *************************************************************************/
00126 bool TabControl::isTabContentsSelected(Window* wnd) const
00127 {
00128         TabButton* button = getButtonForTabContents(wnd);
00129         return button->isSelected();
00130 }
00131 
00132 /*************************************************************************
00133 Return whether the tab content window is currently selected.
00134 *************************************************************************/
00135 uint TabControl::getSelectedTabIndex() const
00136 {
00137     uint index;
00138     TabButtonIndexMap::const_iterator i, iend;
00139     iend = d_tabButtonIndexMap.end();
00140     for (i = d_tabButtonIndexMap.begin(); i != iend; ++i)
00141     {
00142         // get corresponding tab button and content window
00143         TabButton* tb = i->second;
00144         if (tb->isSelected())
00145         {
00146             index = i->first;
00147                         break;
00148         }
00149         }
00150         return index;
00151 }
00152 
00153 /*************************************************************************
00154 Set the selected tab by window name
00155 *************************************************************************/
00156 void TabControl::setSelectedTab(const String &name)
00157 {
00158     // get window
00159     Window* wnd = d_tabContentPane->getChild(name);
00160 
00161     selectTab_impl(wnd);
00162 }
00163 /*************************************************************************
00164 Set the selected tab by window ID
00165 *************************************************************************/
00166 void TabControl::setSelectedTab(uint ID)
00167 {
00168     // get window
00169     Window* wnd = d_tabContentPane->getChild(ID);
00170 
00171     selectTab_impl(wnd);
00172 }
00173 /*************************************************************************
00174 Set the selected tab by window name
00175 *************************************************************************/
00176 void TabControl::setSelectedTabAtIndex(uint index)
00177 {
00178         Window* wnd = getTabContentsAtIndex(index);
00179         selectTab_impl(wnd);
00180 }
00181 /*************************************************************************
00182 Get the tab height
00183 *************************************************************************/
00184 float TabControl::getTabHeight(void) const
00185 {
00186     MetricsMode mode = getMetricsMode();
00187     if (mode == Relative)
00188     {
00189         return d_rel_tabHeight;
00190     }
00191     else
00192     {
00193         return d_abs_tabHeight;
00194     }
00195 }
00196 
00197 /*************************************************************************
00198 Set the tab height
00199 *************************************************************************/
00200 void TabControl::setRelativeTabHeight(float height)
00201 {
00202     d_rel_tabHeight = height;
00203     d_abs_tabHeight = relativeToAbsoluteY(height);
00204 
00205     performChildWindowLayout();
00206 }
00207 /*************************************************************************
00208 Set the tab height
00209 *************************************************************************/
00210 void TabControl::setAbsoluteTabHeight(float height)
00211 {
00212     d_abs_tabHeight = height;
00213     d_rel_tabHeight = absoluteToRelativeY(height);
00214 
00215     performChildWindowLayout();
00216 }
00217 /*************************************************************************
00218 Set the tab height
00219 *************************************************************************/
00220 void TabControl::setTabHeight(float height)
00221 {
00222     if (getMetricsMode() == Relative)
00223     {
00224         setRelativeTabHeight(height);
00225     }
00226     else
00227     {
00228         setAbsoluteTabHeight(height);
00229     }
00230 }
00231 /*************************************************************************
00232 Get the tab text padding
00233 *************************************************************************/
00234 float TabControl::getTabTextPadding(void) const
00235 {
00236     MetricsMode mode = getMetricsMode();
00237     if (mode == Relative)
00238     {
00239         return d_rel_tabPadding;
00240     }
00241     else
00242     {
00243         return d_abs_tabPadding;
00244     }
00245 }
00246 
00247 /*************************************************************************
00248 Set the tab text padding
00249 *************************************************************************/
00250 void TabControl::setRelativeTabTextPadding(float height)
00251 {
00252     d_rel_tabPadding = height;
00253     d_abs_tabPadding = relativeToAbsoluteY(height);
00254 
00255     performChildWindowLayout();
00256 }
00257 /*************************************************************************
00258 Set the tab text padding
00259 *************************************************************************/
00260 void TabControl::setAbsoluteTabTextPadding(float height)
00261 {
00262     d_abs_tabPadding = height;
00263     d_rel_tabPadding = absoluteToRelativeY(height);
00264 
00265     performChildWindowLayout();
00266 }
00267 /*************************************************************************
00268 Set the tab text padding
00269 *************************************************************************/
00270 void TabControl::setTabTextPadding(float height)
00271 {
00272     if (getMetricsMode() == Relative)
00273     {
00274         setRelativeTabTextPadding(height);
00275     }
00276     else
00277     {
00278         setAbsoluteTabTextPadding(height);
00279     }
00280 }
00281 
00282 /*************************************************************************
00283 Add a new tab
00284 *************************************************************************/
00285 void TabControl::addTab(Window* wnd)
00286 {
00287     // Create a new TabButton
00288     addButtonForTabContent(wnd);
00289     // Add the window to the content pane
00290     d_tabContentPane->addChildWindow(wnd);
00291     // Auto-select?
00292     if (getTabCount() == 1)
00293     {
00294         setSelectedTab(wnd->getName());
00295     }
00296     else
00297     {
00298         // initialise invisible content
00299         wnd->setVisible(false);
00300     }
00301     // Just request redraw
00302     performChildWindowLayout();
00303     requestRedraw();
00304     // Subscribe to text changed event so that we can resize as needed
00305     wnd->subscribeEvent(Window::EventTextChanged, 
00306         Event::Subscriber(&TabControl::handleContentWindowTextChanged, this));
00307 
00308 }
00309 /*************************************************************************
00310 Remove a tab
00311 *************************************************************************/
00312 void TabControl::removeTab(const String& name)
00313 {
00314     Window* wnd = d_tabContentPane->getChild(name);
00315     // Was this selected?
00316     bool reselect = wnd->isVisible();
00317     // Tab buttons are the 2nd onward children
00318     d_tabContentPane->removeChildWindow(name);
00319 
00320     // remove button too
00321     removeButtonForTabContent(wnd);
00322 
00323     if (reselect)
00324     {
00325         // Select another tab
00326         if (getTabCount() > 0)
00327         {
00328             setSelectedTab(d_tabContentPane->getChildAtIdx(0)->getName());
00329         }
00330     }
00331 
00332     performChildWindowLayout();
00333 
00334     requestRedraw();
00335 
00336 }
00337 /*************************************************************************
00338 Remove a tab by ID
00339 *************************************************************************/
00340 void TabControl::removeTab(uint ID)
00341 {
00342     Window* wnd = d_tabContentPane->getChild(ID);
00343     // Was this selected?
00344     bool reselect = wnd->isVisible();
00345     // Tab buttons are the 2nd onward children
00346     d_tabContentPane->removeChildWindow(ID);
00347 
00348     // remove button too
00349     removeButtonForTabContent(wnd);
00350 
00351     if (reselect)
00352     {
00353         // Select another tab
00354         if (getTabCount() > 0)
00355         {
00356             setSelectedTab(d_tabContentPane->getChildAtIdx(0)->getName());
00357         }
00358     }
00359 
00360     performChildWindowLayout();
00361 
00362     requestRedraw();
00363 
00364 }
00365 /*************************************************************************
00366 Add tab button
00367 *************************************************************************/
00368 void TabControl::addButtonForTabContent(Window* wnd)
00369 {
00370     // Create the button
00371     TabButton* tb = createTabButton(makeButtonName(wnd));
00372     // Copy font
00373     tb->setFont(getFont());
00374     // Set target window
00375     tb->setTargetWindow(wnd);
00376     // Set index
00377     tb->setTabIndex(d_nextTabIndex++);
00378     // Instert into map
00379     d_tabButtonIndexMap.insert(
00380         TabButtonIndexMap::value_type(tb->getTabIndex(), tb));
00381     // add the button
00382     d_tabButtonPane->addChildWindow(tb);
00383     // Subscribe to clicked event so that we can change tab
00384     tb->subscribeEvent(TabButton::EventClicked, 
00385         Event::Subscriber(&TabControl::handleTabButtonClicked, this));
00386 
00387 }
00388 
00389 /*************************************************************************
00390         Return the tab button for the given tab content window
00391 *************************************************************************/
00392 TabButton* TabControl::getButtonForTabContents(Window* wnd) const
00393 {
00394     TabButtonIndexMap::const_iterator i, iend;
00395     iend = d_tabButtonIndexMap.end();
00396     for (i = d_tabButtonIndexMap.begin(); i != iend; ++i)
00397     {
00398         // get corresponding tab button and content window
00399         TabButton* tb = i->second;
00400         Window* child = tb->getTargetWindow();
00401         if (child == wnd)
00402         {
00403                         return tb;
00404         }
00405         }
00406         throw UnknownObjectException((utf8*)"TabControl::getButtonForTabContents - The Window object is not a tab contents.");
00407 }
00408 /*************************************************************************
00409         Calculate size and position for a tab button
00410 *************************************************************************/
00411 void TabControl::calculateTabButtonSizePosition(TabButton* btn, uint targetIndex)
00412 {
00413     // relative height is always 1.0 for buttons since they are embedded in a
00414     // panel of the correct height already
00415     btn->setHeight(Relative, 1.0f);
00416     btn->setYPosition(Relative, 0.0f);
00417     // x position is based on previous button
00418     if (targetIndex > 0)
00419     {
00420                 TabButtonIndexMap::iterator iter = d_tabButtonIndexMap.begin();
00421                 std::advance(iter, targetIndex - 1);
00422                 Window* prevButton = iter->second;
00423 
00424                 // position is prev pos + width
00425         btn->setXPosition(Relative, 
00426             prevButton->getXPosition(Relative) 
00427             + prevButton->getWidth(Relative));
00428     }
00429     else
00430     {
00431         // First button
00432         btn->setXPosition(Relative, 0);
00433     }
00434     // Width is based on font size (expressed as absolute)
00435     const Font* fnt = btn->getFont();
00436     btn->setWidth(Absolute, 
00437         fnt->getTextExtent(btn->getText()) + getAbsoluteTabTextPadding()*2);
00438     btn->requestRedraw();
00439 }
00440 /*************************************************************************
00441 Remove tab button
00442 *************************************************************************/
00443 void TabControl::removeButtonForTabContent(Window* wnd)
00444 {
00445     // get
00446     TabButton* tb = static_cast<TabButton*>(
00447         d_tabButtonPane->getChild(makeButtonName(wnd)));
00448     // remove
00449     d_tabButtonIndexMap.erase(tb->getTabIndex());
00450     d_tabButtonPane->removeChildWindow(tb);
00451         // destroy
00452         WindowManager::getSingleton().destroyWindow(tb);
00453 }
00454 /*************************************************************************
00455 Remove tab button
00456 *************************************************************************/
00457 String TabControl::makeButtonName(Window* wnd)
00458 {
00459     // derive button name
00460     String buttonName = (utf8*)"__auto_btn";
00461     buttonName.append(wnd->getName());
00462     return buttonName;
00463 }
00464 /*************************************************************************
00465 Select tab implementation
00466 *************************************************************************/
00467 void TabControl::selectTab_impl(Window* wnd)
00468 {
00469     bool modified = false;
00470     bool foundSelected = false;
00471     // Iterate in order of tab index
00472     TabButtonIndexMap::iterator i, iend;
00473     iend = d_tabButtonIndexMap.end();
00474     for (i = d_tabButtonIndexMap.begin(); i != iend; ++i)
00475     {
00476         // get corresponding tab button and content window
00477         TabButton* tb = i->second;
00478         Window* child = tb->getTargetWindow();
00479         // Should we be selecting?
00480         bool selectThis = (child == wnd);
00481         // Are we modifying this tab?
00482         modified = modified || (tb->isSelected() != selectThis);
00483         foundSelected = foundSelected || selectThis;
00484         // Select tab & set visible if this is the window, not otherwise
00485         tb->setSelected(selectThis);
00486         tb->setRightOfSelected(foundSelected);
00487         child->setVisible(selectThis);
00488     }
00489     // Trigger event?
00490     if (modified)
00491     {
00492         WindowEventArgs args(this);
00493         onSelectionChanged(args);
00494     }
00495 }
00496 /*************************************************************************
00497 Add tab control properties
00498 *************************************************************************/
00499 void TabControl::addTabControlProperties(void)
00500 {
00501     addProperty(&d_tabHeightProperty);
00502     addProperty(&d_relativeTabHeightProperty);
00503     addProperty(&d_absoluteTabHeightProperty);
00504     addProperty(&d_tabTextPaddingProperty);
00505     addProperty(&d_relativeTabTextPaddingProperty);
00506     addProperty(&d_absoluteTabTextPaddingProperty);
00507 }
00508 /*************************************************************************
00509 Internal version of adding a child window
00510 *************************************************************************/
00511 void TabControl::addChild_impl(Window* wnd)
00512 {
00513     // Look for __auto_TabPane__ in the name (hopefully no-one will use this!)
00514     if (wnd->getName().find((const utf8*)"__auto_TabPane__") != String::npos)
00515     {
00516         // perform normal addChild
00517         Window::addChild_impl(wnd);
00518     }
00519     else
00520     {
00521         // This is another control, therefore add as a tab
00522         addTab(wnd);
00523     }
00524 }
00525 /*************************************************************************
00526 Selection changed event
00527 *************************************************************************/
00528 void TabControl::onSelectionChanged(WindowEventArgs& e)
00529 {
00530     requestRedraw();
00531     fireEvent(EventSelectionChanged, e, EventNamespace);
00532 }
00533 /*************************************************************************
00534 Font changed event
00535 *************************************************************************/
00536 void TabControl::onFontChanged(WindowEventArgs& e)
00537 {
00538     // Propagate font change to buttons
00539     TabButtonIndexMap::iterator i, iend;
00540     iend = d_tabButtonIndexMap.end();
00541     for (i = d_tabButtonIndexMap.end(); i != iend; ++i)
00542     {
00543         i->second->setFont(getFont());
00544     }
00545 }
00546 /*************************************************************************
00547 Add events for this class
00548 *************************************************************************/
00549 void TabControl::addTabControlEvents(void)
00550 {
00551     addEvent(EventSelectionChanged);
00552 }
00553 /*************************************************************************
00554 Layout the widgets
00555 *************************************************************************/
00556 void TabControl::performChildWindowLayout()
00557 {
00558     Window::performChildWindowLayout();
00559 
00560     if (d_tabButtonPane)
00561     {
00562         // Set the size of the tab button area (full width, height from tab height)
00563         d_tabButtonPane->setSize(Relative, Size(1.0f, d_rel_tabHeight) );
00564         d_tabButtonPane->setPosition(Relative, Point(0.0f, 0.0f) );
00565         // Calculate the positions and sizes of the tab buttons
00566         TabButtonIndexMap::iterator i, iend;
00567         iend = d_tabButtonIndexMap.end();
00568         uint x = 0;
00569         for (i = d_tabButtonIndexMap.begin(); i != iend; ++i, ++x)
00570         {
00571             TabButton* btn = i->second;
00572             calculateTabButtonSizePosition(btn, x);
00573         }
00574     }
00575     if (d_tabContentPane)
00576     {
00577         // Set the size of the content area
00578         d_tabContentPane->setSize(Relative, Size(1.0f, 1.0f - d_rel_tabHeight) );
00579         d_tabContentPane->setPosition(Relative, Point(0.0f, d_rel_tabHeight) );
00580     }
00581 
00582 }
00583 /*************************************************************************
00584 Create tab button pane
00585 *************************************************************************/
00586 Window* TabControl::createTabButtonPane(const String& name) const
00587 {
00588         return WindowManager::getSingleton().createWindow(GUISheet::WidgetTypeName, name);
00589 }
00590 /*************************************************************************
00591 Text changed on a content window
00592 *************************************************************************/
00593 bool TabControl::handleContentWindowTextChanged(const EventArgs& args)
00594 {
00595     // update text
00596     const WindowEventArgs& wargs = static_cast<const WindowEventArgs&>(args);
00597     Window* tabButton = d_tabButtonPane->getChild(
00598         makeButtonName(wargs.window));
00599     tabButton->setText(wargs.window->getText());
00600     // sort out the layout
00601     performChildWindowLayout();
00602         requestRedraw();
00603 
00604         return true;
00605 }
00606 /*************************************************************************
00607 Tab button clicked
00608 *************************************************************************/
00609 bool TabControl::handleTabButtonClicked(const EventArgs& args)
00610 {
00611     const WindowEventArgs& wargs = static_cast<const WindowEventArgs&>(args);
00612     TabButton* tabButton = static_cast<TabButton*>(wargs.window);
00613     setSelectedTab(tabButton->getTargetWindow()->getName());
00614 
00615         return true;
00616 }
00617 
00618 int TabControl::writeChildWindowsXML(OutStream& out_stream) const
00619 {
00620     int childOutputCount = Window::writeChildWindowsXML(out_stream);
00621 
00622     // since TabControl content is actually added to the component tab
00623     // content pane window, this overridden function exists to dump those
00624     // out as if they were our own children.
00625     for (uint i = 0; i < getTabCount(); ++i)
00626     {
00627         getTabContentsAtIndex(i)->writeXMLToStream(out_stream);
00628         ++childOutputCount;
00629     }
00630 
00631     return childOutputCount;
00632 }
00633 
00634 } // End of  CEGUI namespace section

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