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

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_tabContentPane(NULL),
00062     d_tabButtonPane(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();
00087     d_tabButtonPane = createTabButtonPane();
00088 
00089         addChildWindow(d_tabContentPane);
00090     addChildWindow(d_tabButtonPane);
00091 
00092         layoutComponentWidgets();
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_tabContentPane->getChildAtIdx(index);
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 = 0;
00138     TabButtonIndexMap::const_iterator i, iend;
00139     iend = d_tabButtonIndexMap.end();
00140     for (i = d_tabButtonIndexMap.begin(); i != iend; ++i, ++index)
00141     {
00142         // get corresponding tab button and content window
00143         TabButton* tb = i->second;
00144         if (tb->isSelected())
00145         {
00146                         break;
00147         }
00148         }
00149         return index;
00150 }
00151 
00152 /*************************************************************************
00153 Set the selected tab by window name
00154 *************************************************************************/
00155 void TabControl::setSelectedTab(const String &name)
00156 {
00157     // get window
00158     Window* wnd = d_tabContentPane->getChild(name);
00159 
00160     selectTab_impl(wnd);
00161 }
00162 /*************************************************************************
00163 Set the selected tab by window ID
00164 *************************************************************************/
00165 void TabControl::setSelectedTab(uint ID)
00166 {
00167     // get window
00168     Window* wnd = d_tabContentPane->getChild(ID);
00169 
00170     selectTab_impl(wnd);
00171 }
00172 /*************************************************************************
00173 Set the selected tab by window name
00174 *************************************************************************/
00175 void TabControl::setSelectedTabAtIndex(uint index)
00176 {
00177         Window* wnd = getTabContentsAtIndex(index);
00178         selectTab_impl(wnd);
00179 }
00180 /*************************************************************************
00181 Get the tab height
00182 *************************************************************************/
00183 float TabControl::getTabHeight(void) const
00184 {
00185     MetricsMode mode = getMetricsMode();
00186     if (mode == Relative)
00187     {
00188         return d_rel_tabHeight;
00189     }
00190     else
00191     {
00192         return d_abs_tabHeight;
00193     }
00194 }
00195 
00196 /*************************************************************************
00197 Set the tab height
00198 *************************************************************************/
00199 void TabControl::setRelativeTabHeight(float height)
00200 {
00201     d_rel_tabHeight = height;
00202     d_abs_tabHeight = relativeToAbsoluteY(height);
00203 
00204     layoutComponentWidgets();
00205 }
00206 /*************************************************************************
00207 Set the tab height
00208 *************************************************************************/
00209 void TabControl::setAbsoluteTabHeight(float height)
00210 {
00211     d_abs_tabHeight = height;
00212     d_rel_tabHeight = absoluteToRelativeY(height);
00213 
00214     layoutComponentWidgets();
00215 }
00216 /*************************************************************************
00217 Set the tab height
00218 *************************************************************************/
00219 void TabControl::setTabHeight(float height)
00220 {
00221     if (getMetricsMode() == Relative)
00222     {
00223         setRelativeTabHeight(height);
00224     }
00225     else
00226     {
00227         setAbsoluteTabHeight(height);
00228     }
00229 }
00230 /*************************************************************************
00231 Get the tab text padding
00232 *************************************************************************/
00233 float TabControl::getTabTextPadding(void) const
00234 {
00235     MetricsMode mode = getMetricsMode();
00236     if (mode == Relative)
00237     {
00238         return d_rel_tabPadding;
00239     }
00240     else
00241     {
00242         return d_abs_tabPadding;
00243     }
00244 }
00245 
00246 /*************************************************************************
00247 Set the tab text padding
00248 *************************************************************************/
00249 void TabControl::setRelativeTabTextPadding(float height)
00250 {
00251     d_rel_tabPadding = height;
00252     d_abs_tabPadding = relativeToAbsoluteY(height);
00253 
00254     layoutComponentWidgets();
00255 }
00256 /*************************************************************************
00257 Set the tab text padding
00258 *************************************************************************/
00259 void TabControl::setAbsoluteTabTextPadding(float height)
00260 {
00261     d_abs_tabPadding = height;
00262     d_rel_tabPadding = absoluteToRelativeY(height);
00263 
00264     layoutComponentWidgets();
00265 }
00266 /*************************************************************************
00267 Set the tab text padding
00268 *************************************************************************/
00269 void TabControl::setTabTextPadding(float height)
00270 {
00271     if (getMetricsMode() == Relative)
00272     {
00273         setRelativeTabTextPadding(height);
00274     }
00275     else
00276     {
00277         setAbsoluteTabTextPadding(height);
00278     }
00279 }
00280 
00281 /*************************************************************************
00282 Add a new tab
00283 *************************************************************************/
00284 void TabControl::addTab(Window* wnd)
00285 {
00286     // Create a new TabButton
00287     addButtonForTabContent(wnd);
00288     // Add the window to the content pane
00289     d_tabContentPane->addChildWindow(wnd);
00290     // Auto-select?
00291     if (getTabCount() == 1)
00292     {
00293         setSelectedTab(wnd->getName());
00294     }
00295     else
00296     {
00297         // initialise invisible content
00298         wnd->setVisible(false);
00299     }
00300     // Just request redraw
00301     layoutComponentWidgets();
00302     requestRedraw();
00303     // Subscribe to text changed event so that we can resize as needed
00304     wnd->subscribeEvent(Window::EventTextChanged, 
00305         Event::Subscriber(&TabControl::handleContentWindowTextChanged, this));
00306 
00307 }
00308 /*************************************************************************
00309 Remove a tab
00310 *************************************************************************/
00311 void TabControl::removeTab(const String& name)
00312 {
00313     Window* wnd = d_tabContentPane->getChild(name);
00314     // Was this selected?
00315     bool reselect = wnd->isVisible();
00316     // Tab buttons are the 2nd onward children
00317     d_tabContentPane->removeChildWindow(name);
00318 
00319     // remove button too
00320     removeButtonForTabContent(wnd);
00321 
00322     if (reselect)
00323     {
00324         // Select another tab
00325         if (getTabCount() > 0)
00326         {
00327             setSelectedTab(d_tabContentPane->getChildAtIdx(0)->getName());
00328         }
00329     }
00330 
00331     layoutComponentWidgets();
00332 
00333     requestRedraw();
00334 
00335 }
00336 /*************************************************************************
00337 Remove a tab by ID
00338 *************************************************************************/
00339 void TabControl::removeTab(uint ID)
00340 {
00341     Window* wnd = d_tabContentPane->getChild(ID);
00342     // Was this selected?
00343     bool reselect = wnd->isVisible();
00344     // Tab buttons are the 2nd onward children
00345     d_tabContentPane->removeChildWindow(ID);
00346 
00347     // remove button too
00348     removeButtonForTabContent(wnd);
00349 
00350     if (reselect)
00351     {
00352         // Select another tab
00353         if (getTabCount() > 0)
00354         {
00355             setSelectedTab(d_tabContentPane->getChildAtIdx(0)->getName());
00356         }
00357     }
00358 
00359     layoutComponentWidgets();
00360 
00361     requestRedraw();
00362 
00363 }
00364 /*************************************************************************
00365 Add tab button
00366 *************************************************************************/
00367 void TabControl::addButtonForTabContent(Window* wnd)
00368 {
00369     // Create the button
00370     TabButton* tb = createTabButton(makeButtonName(wnd));
00371     // Copy font
00372     tb->setFont(getFont());
00373     // Set target window
00374     tb->setTargetWindow(wnd);
00375     // Set index
00376     tb->setTabIndex(d_nextTabIndex++);
00377     // Instert into map
00378     d_tabButtonIndexMap.insert(
00379         TabButtonIndexMap::value_type(tb->getTabIndex(), tb));
00380     // add the button
00381     d_tabButtonPane->addChildWindow(tb);
00382     // Subscribe to clicked event so that we can change tab
00383     tb->subscribeEvent(TabButton::EventClicked, 
00384         Event::Subscriber(&TabControl::handleTabButtonClicked, this));
00385 
00386 }
00387 
00388 /*************************************************************************
00389         Return the tab button for the given tab content window
00390 *************************************************************************/
00391 TabButton* TabControl::getButtonForTabContents(Window* wnd) const
00392 {
00393     TabButtonIndexMap::const_iterator i, iend;
00394     iend = d_tabButtonIndexMap.end();
00395     for (i = d_tabButtonIndexMap.begin(); i != iend; ++i)
00396     {
00397         // get corresponding tab button and content window
00398         TabButton* tb = i->second;
00399         Window* child = tb->getTargetWindow();
00400         if (child == wnd)
00401         {
00402                         return tb;
00403         }
00404         }
00405         throw UnknownObjectException((utf8*)"TabControl::getButtonForTabContents - The Window object is not a tab contents.");
00406 }
00407 /*************************************************************************
00408         Calculate size and position for a tab button
00409 *************************************************************************/
00410 void TabControl::calculateTabButtonSizePosition(TabButton* btn, uint targetIndex)
00411 {
00412     // relative height is always 1.0 for buttons since they are embedded in a
00413     // panel of the correct height already
00414     btn->setHeight(Relative, 1.0f);
00415     btn->setYPosition(Relative, 0.0f);
00416     // x position is based on previous button
00417     if (targetIndex > 0)
00418     {
00419                 TabButtonIndexMap::iterator iter = d_tabButtonIndexMap.begin();
00420                 std::advance(iter, targetIndex - 1);
00421                 Window* prevButton = iter->second;
00422 
00423                 // position is prev pos + width
00424         btn->setXPosition(Relative, 
00425             prevButton->getXPosition(Relative) 
00426             + prevButton->getWidth(Relative));
00427     }
00428     else
00429     {
00430         // First button
00431         btn->setXPosition(Relative, 0);
00432     }
00433     // Width is based on font size (expressed as absolute)
00434     const Font* fnt = btn->getFont();
00435     btn->setWidth(Absolute, 
00436         fnt->getTextExtent(btn->getText()) + getAbsoluteTabTextPadding()*2);
00437     btn->requestRedraw();
00438 }
00439 /*************************************************************************
00440 Remove tab button
00441 *************************************************************************/
00442 void TabControl::removeButtonForTabContent(Window* wnd)
00443 {
00444     // get
00445     TabButton* tb = static_cast<TabButton*>(
00446         d_tabButtonPane->getChild(makeButtonName(wnd)));
00447     // remove
00448     d_tabButtonIndexMap.erase(tb->getTabIndex());
00449     d_tabButtonPane->removeChildWindow(tb);
00450         // destroy
00451         WindowManager::getSingleton().destroyWindow(tb);
00452 }
00453 /*************************************************************************
00454 Remove tab button
00455 *************************************************************************/
00456 String TabControl::makeButtonName(Window* wnd)
00457 {
00458     // derive button name
00459     String buttonName = (utf8*)"__auto_btn";
00460     buttonName.append(wnd->getName());
00461     return buttonName;
00462 }
00463 /*************************************************************************
00464 Select tab implementation
00465 *************************************************************************/
00466 void TabControl::selectTab_impl(Window* wnd)
00467 {
00468     bool modified = false;
00469     bool foundSelected = false;
00470     // Iterate in order of tab index
00471     TabButtonIndexMap::iterator i, iend;
00472     iend = d_tabButtonIndexMap.end();
00473     for (i = d_tabButtonIndexMap.begin(); i != iend; ++i)
00474     {
00475         // get corresponding tab button and content window
00476         TabButton* tb = i->second;
00477         Window* child = tb->getTargetWindow();
00478         // Should we be selecting?
00479         bool selectThis = (child == wnd);
00480         // Are we modifying this tab?
00481         modified = modified || (tb->isSelected() != selectThis);
00482         foundSelected = foundSelected || selectThis;
00483         // Select tab & set visible if this is the window, not otherwise
00484         tb->setSelected(selectThis);
00485         tb->setRightOfSelected(foundSelected);
00486         child->setVisible(selectThis);
00487     }
00488     // Trigger event?
00489     if (modified)
00490     {
00491         WindowEventArgs args(this);
00492         onSelectionChanged(args);
00493     }
00494 }
00495 /*************************************************************************
00496 Add tab control properties
00497 *************************************************************************/
00498 void TabControl::addTabControlProperties(void)
00499 {
00500     addProperty(&d_tabHeightProperty);
00501     addProperty(&d_relativeTabHeightProperty);
00502     addProperty(&d_absoluteTabHeightProperty);
00503     addProperty(&d_tabTextPaddingProperty);
00504     addProperty(&d_relativeTabTextPaddingProperty);
00505     addProperty(&d_absoluteTabTextPaddingProperty);
00506 }
00507 /*************************************************************************
00508 Internal version of adding a child window
00509 *************************************************************************/
00510 void TabControl::addChild_impl(Window* wnd)
00511 {
00512     // Look for __auto_TabPane__ in the name (hopefully no-one will use this!)
00513     if (wnd->getName().find((const utf8*)"__auto_TabPane__") != String::npos)
00514     {
00515         // perform normal addChild
00516         Window::addChild_impl(wnd);
00517     }
00518     else
00519     {
00520         // This is another control, therefore add as a tab
00521         addTab(wnd);
00522     }
00523 }
00524 /*************************************************************************
00525 Selection changed event
00526 *************************************************************************/
00527 void TabControl::onSelectionChanged(WindowEventArgs& e)
00528 {
00529     requestRedraw();
00530     fireEvent(EventSelectionChanged, e, EventNamespace);
00531 }
00532 /*************************************************************************
00533 Font changed event
00534 *************************************************************************/
00535 void TabControl::onFontChanged(WindowEventArgs& e)
00536 {
00537     // Propagate font change to buttons
00538     TabButtonIndexMap::iterator i, iend;
00539     iend = d_tabButtonIndexMap.end();
00540     for (i = d_tabButtonIndexMap.end(); i != iend; ++i)
00541     {
00542         i->second->setFont(getFont());
00543     }
00544 }
00545 /*************************************************************************
00546 Add events for this class
00547 *************************************************************************/
00548 void TabControl::addTabControlEvents(void)
00549 {
00550     addEvent(EventSelectionChanged);
00551 }
00552 /*************************************************************************
00553 Handler for when widget is re-sized
00554 *************************************************************************/
00555 void TabControl::onSized(WindowEventArgs& e)
00556 {
00557     // base class processing
00558     Window::onSized(e);
00559 
00560     layoutComponentWidgets();
00561 
00562     e.handled = true;
00563 }
00564 /*************************************************************************
00565 Layout the widgets
00566 *************************************************************************/
00567 void TabControl::layoutComponentWidgets(void)
00568 {
00569     if (d_tabButtonPane)
00570     {
00571         // Set the size of the tab button area (full width, height from tab height)
00572         d_tabButtonPane->setSize(Relative, Size(1.0f, d_rel_tabHeight) );
00573         d_tabButtonPane->setPosition(Relative, Point(0.0f, 0.0f) );
00574         // Calculate the positions and sizes of the tab buttons
00575         TabButtonIndexMap::iterator i, iend;
00576         iend = d_tabButtonIndexMap.end();
00577         uint x = 0;
00578         for (i = d_tabButtonIndexMap.begin(); i != iend; ++i, ++x)
00579         {
00580             TabButton* btn = i->second;
00581             calculateTabButtonSizePosition(btn, x);
00582         }
00583     }
00584     if (d_tabContentPane)
00585     {
00586         // Set the size of the content area
00587         d_tabContentPane->setSize(Relative, Size(1.0f, 1.0f - d_rel_tabHeight) );
00588         d_tabContentPane->setPosition(Relative, Point(0.0f, d_rel_tabHeight) );
00589     }
00590 
00591 }
00592 /*************************************************************************
00593 Create tab button pane
00594 *************************************************************************/
00595 Window* TabControl::createTabButtonPane(void) const
00596 {
00597     // Generate name based on own name
00598     String newName = getName() + (utf8*)"__auto_TabPane__Buttons";
00599         return WindowManager::getSingleton().createWindow(GUISheet::WidgetTypeName, newName);
00600 }
00601 /*************************************************************************
00602 Text changed on a content window
00603 *************************************************************************/
00604 bool TabControl::handleContentWindowTextChanged(const EventArgs& args)
00605 {
00606     // update text
00607     const WindowEventArgs& wargs = static_cast<const WindowEventArgs&>(args);
00608     Window* tabButton = d_tabButtonPane->getChild(
00609         makeButtonName(wargs.window));
00610     tabButton->setText(wargs.window->getText());
00611     // sort out the layout
00612     layoutComponentWidgets();
00613         requestRedraw();
00614 
00615         return true;
00616 }
00617 /*************************************************************************
00618 Tab button clicked
00619 *************************************************************************/
00620 bool TabControl::handleTabButtonClicked(const EventArgs& args)
00621 {
00622     const WindowEventArgs& wargs = static_cast<const WindowEventArgs&>(args);
00623     TabButton* tabButton = static_cast<TabButton*>(wargs.window);
00624     setSelectedTab(tabButton->getTargetWindow()->getName());
00625 
00626         return true;
00627 }
00628 } // End of  CEGUI namespace section

Generated on Wed Feb 16 12:41:07 2005 for Crazy Eddies GUI System by  doxygen 1.3.9.1