diff options
-rw-r--r-- | src/gui/widgets/tabbedarea.cpp | 147 | ||||
-rw-r--r-- | src/gui/widgets/tabbedarea.h | 43 |
2 files changed, 189 insertions, 1 deletions
diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp index d93b4bb02..e0bf9e12f 100644 --- a/src/gui/widgets/tabbedarea.cpp +++ b/src/gui/widgets/tabbedarea.cpp @@ -28,11 +28,20 @@ #include <guichan/widgets/container.hpp> -TabbedArea::TabbedArea() : gcn::TabbedArea() +TabbedArea::TabbedArea() : gcn::TabbedArea(), + mTabsWidth(0), + mVisibleTabsWidth(0), + mTabScrollIndex(0) { mWidgetContainer->setOpaque(false); addWidgetListener(this); + mArrowButton[0] = new Button("<", "shift_left", this); + mArrowButton[1] = new Button(">", "shift_right", this); + + add(mArrowButton[0]); + add(mArrowButton[1]); + widgetResized(NULL); } @@ -96,6 +105,9 @@ void TabbedArea::addTab(gcn::Tab* tab, gcn::Widget* widget) int width = getWidth() - 2 * getFrameSize(); int height = getHeight() - 2 * getFrameSize() - mTabContainer->getHeight(); widget->setSize(width, height); + + updateTabsWidth(); + updateArrowEnableState(); } void TabbedArea::addTab(const std::string &caption, gcn::Widget *widget) @@ -159,6 +171,7 @@ void TabbedArea::removeTab(Tab *tab) } adjustSize(); + updateTabsWidth(); adjustTabPositions(); } @@ -209,6 +222,138 @@ void TabbedArea::widgetResized(const gcn::Event &event _UNUSED_) gcn::Widget *w = getCurrentWidget(); if (w) w->setSize(width, height); + + // Check whether there is room to show more tabs now. + int innerWidth = getWidth() - 4 - mArrowButton[0]->getWidth() + - mArrowButton[1]->getWidth(); + int newWidth = mVisibleTabsWidth; + while (mTabScrollIndex && newWidth < innerWidth) + { + newWidth += mTabs[mTabScrollIndex - 1].first->getWidth(); + if (newWidth < innerWidth) + --mTabScrollIndex; + } + + // Move the right arrow to fit the windows content. + mArrowButton[1]->setPosition(width - mArrowButton[1]->getWidth(), 0); + + updateArrowEnableState(); + adjustTabPositions(); +} + +void TabbedArea::updateTabsWidth() +{ + mTabsWidth = 0; + for (TabContainer::const_iterator itr = mTabs.begin(), itr_end = mTabs.end(); + itr != itr_end; ++itr) + { + mTabsWidth += (*itr).first->getWidth(); + } + updateVisibleTabsWidth(); +} + +void TabbedArea::updateVisibleTabsWidth() +{ + mVisibleTabsWidth = 0; + for (unsigned int i = mTabScrollIndex; i < mTabs.size(); ++i) + { + mVisibleTabsWidth += mTabs[i].first->getWidth(); + } +} + +void TabbedArea::adjustTabPositions() +{ + int maxTabHeight = 0; + for (unsigned i = 0; i < mTabs.size(); ++i) + { + if (mTabs[i].first->getHeight() > maxTabHeight) + { + maxTabHeight = mTabs[i].first->getHeight(); + } + } + + int x = mArrowButton[0]->isVisible() ? mArrowButton[0]->getWidth() : 0; + for (unsigned i = mTabScrollIndex; i < mTabs.size(); ++i) + { + gcn::Tab* tab = mTabs[i].first; + tab->setPosition(x, maxTabHeight - tab->getHeight()); + x += tab->getWidth(); + } + + // If the tabs are scrolled, we hide them away. + if (mTabScrollIndex > 0) + { + x = 0; + for (unsigned i = 0; i < mTabScrollIndex; ++i) + { + gcn::Tab* tab = mTabs[i].first; + x -= tab->getWidth(); + tab->setPosition(x, maxTabHeight - tab->getHeight()); + } + } +} + +void TabbedArea::action(const gcn::ActionEvent& actionEvent) +{ + Widget* source = actionEvent.getSource(); + Tab* tab = dynamic_cast<Tab*>(source); + + if (tab) + { + setSelectedTab(tab); + } + else + { + if (actionEvent.getId() == "shift_left") + { + if (mTabScrollIndex) + --mTabScrollIndex; + } + else if (actionEvent.getId() == "shift_right") + { + if (mTabScrollIndex < mTabs.size() - 1) + ++mTabScrollIndex; + } + adjustTabPositions(); + + updateArrowEnableState(); + } +} + +void TabbedArea::updateArrowEnableState() +{ + updateTabsWidth(); + if (mTabsWidth > getWidth() - 4 + - mArrowButton[0]->getWidth() + - mArrowButton[1]->getWidth()) + { + mArrowButton[0]->setVisible(true); + mArrowButton[1]->setVisible(true); + } + else + { + mArrowButton[0]->setVisible(false); + mArrowButton[1]->setVisible(false); + mTabScrollIndex = 0; + } + + // Left arrow consistency check + if (!mTabScrollIndex) + mArrowButton[0]->setEnabled(false); + else + mArrowButton[0]->setEnabled(true); + + // Right arrow consistency check + if (mVisibleTabsWidth < getWidth() - 4 + - mArrowButton[0]->getWidth() + - mArrowButton[1]->getWidth()) + { + mArrowButton[1]->setEnabled(false); + } + else + { + mArrowButton[1]->setEnabled(true); + } } /* diff --git a/src/gui/widgets/tabbedarea.h b/src/gui/widgets/tabbedarea.h index aff47929d..e5a00e277 100644 --- a/src/gui/widgets/tabbedarea.h +++ b/src/gui/widgets/tabbedarea.h @@ -28,6 +28,8 @@ #include <guichan/widgets/container.hpp> #include <guichan/widgets/tabbedarea.hpp> +#include "gui/widgets/button.h" + #include <string> #ifdef __GNUC__ @@ -119,12 +121,53 @@ class TabbedArea : public gcn::TabbedArea, public gcn::WidgetListener void moveRight(gcn::Tab *tab); */ + void adjustTabPositions(); + + void action(const gcn::ActionEvent& actionEvent); + // Inherited from MouseListener void mousePressed(gcn::MouseEvent &mouseEvent); private: typedef std::vector< std::pair<gcn::Tab*, gcn::Widget*> > TabContainer; + + /** The tab arrows */ + gcn::Button *mArrowButton[2]; + + /** Check whether the arrow should be clickable */ + void updateArrowEnableState(); + + /** + * Update the overall width of all tab. Used to know whether the arrows + * have to be drawn or not. + */ + void updateTabsWidth(); + + /** + * The overall width of all tab. + */ + int mTabsWidth; + + /** + * Update the overall width of visible tab. Used to know whether + * the arrows have to be enable or not. + */ + void updateVisibleTabsWidth(); + + /** + * The overall width of visible tab. + */ + int mVisibleTabsWidth; + + + /** + * The tab scroll index. When scrolling with the arrows, the tabs + * must be displayed according to the current index. + * So the first tab displayed may not be the first in the list. + * @note the index must start at 0. + */ + unsigned mTabScrollIndex; }; #endif |