summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gui/widgets/tabbedarea.cpp147
-rw-r--r--src/gui/widgets/tabbedarea.h43
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