From 369c88d1b24e17afa4dee418e01eae187d3a4169 Mon Sep 17 00:00:00 2001 From: Yohann Ferreira Date: Tue, 8 Mar 2011 23:52:24 +0100 Subject: Added a tab scrolling system in tabarea. Currently working on the chat window. Resolves: Mana-Mantis #308. Reviewed-by: Thorbjorn. --- src/gui/widgets/tabbedarea.cpp | 147 ++++++++++++++++++++++++++++++++++++++++- src/gui/widgets/tabbedarea.h | 43 ++++++++++++ 2 files changed, 189 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp index 101c9546..412d3ddc 100644 --- a/src/gui/widgets/tabbedarea.cpp +++ b/src/gui/widgets/tabbedarea.cpp @@ -25,11 +25,20 @@ #include -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); } @@ -90,6 +99,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) @@ -134,6 +146,7 @@ void TabbedArea::removeTab(Tab *tab) } adjustSize(); + updateTabsWidth(); adjustTabPositions(); } @@ -184,4 +197,136 @@ void TabbedArea::widgetResized(const gcn::Event &event) 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(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 925da2de..19393f8b 100644 --- a/src/gui/widgets/tabbedarea.h +++ b/src/gui/widgets/tabbedarea.h @@ -27,6 +27,8 @@ #include #include +#include "gui/widgets/button.h" + #include class Tab; @@ -107,11 +109,52 @@ class TabbedArea : public gcn::TabbedArea, public gcn::WidgetListener void widgetResized(const gcn::Event &event); + void adjustTabPositions(); + + void action(const gcn::ActionEvent& actionEvent); + // Inherited from MouseListener void mousePressed(gcn::MouseEvent &mouseEvent); private: typedef std::vector< std::pair > 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 -- cgit v1.2.3-70-g09d2