You may notice it's a complete copy of CGUITab and CGUITabControl with some added functionality for CGUIScrollingTabControl.
CGUIScrollingTabControl.h
Code: Select all
#ifndef INC_CGUISCROLLINGTABCONTROL_H
#define INC_CGUISCROLLINGTABCONTROL_H
#include <irrlicht.h>
using namespace irr;
using namespace gui;
// A tab, onto which other gui elements could be added.
class CGUITab : public IGUITab
{
public:
//! constructor
CGUITab(s32 number, IGUIEnvironment* environment,
IGUIElement* parent, const core::rect<s32>& rectangle,
s32 id);
//! Returns number of this tab in tabcontrol. Can be accessed
//! later IGUITabControl::getTab() by this number.
virtual s32 getNumber() const;
//! Sets the number
virtual void setNumber(s32 n);
//! draws the element and its children
virtual void draw();
//! sets if the tab should draw its background
virtual void setDrawBackground(bool draw=true);
//! sets the color of the background, if it should be drawn.
virtual void setBackgroundColor(video::SColor c);
//! returns true if the tab is drawing its background, false if not
virtual bool isDrawingBackground() const;
//! returns the color of the background
virtual video::SColor getBackgroundColor() const;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
private:
s32 Number;
bool DrawBackground;
video::SColor BackColor;
};
//! A standard tab control
class CGUIScrollingTabControl : public IGUITabControl
{
public:
//! destructor
CGUIScrollingTabControl(IGUIEnvironment* environment,
IGUIElement* parent, const core::rect<s32>& rectangle,
bool fillbackground=true, bool border=true, s32 id=-1);
//! destructor
virtual ~CGUIScrollingTabControl();
//! Adds a tab
virtual CGUITab* addTab(const wchar_t* caption, s32 id=-1);
//! Adds a tab that has already been created
virtual void addTab(CGUITab* tab);
//! Returns amount of tabs in the tabcontrol
virtual s32 getTabCount() const;
//! Returns a tab based on zero based index
virtual IGUITab* getTab(s32 idx) const;
//! Brings a tab to front.
virtual bool setActiveTab(s32 idx);
//! Brings a tab to front.
virtual bool setActiveTab(IGUIElement *tab);
//! Returns which tab is currently active
virtual s32 getActiveTab() const;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! Removes a child.
virtual void removeChild(IGUIElement* child);
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
//! Returns the maximum width of a tab
virtual inline u32 getMaxTabWidth() { return MaxTabWidth; }
//! Sets the maximum width of a tab
virtual inline void setMaxTabWidth(u32 val) { MaxTabWidth = val; }
private:
s32 getTabsLengthUpTo(s32 tab);
s32 getActiveTabLength();
void selectTab(core::position2d<s32> p);
core::array<CGUITab*> Tabs;
s32 ActiveTab;
s32 TabStartPosX;
u32 MaxTabWidth;
bool Border;
bool FillBackground;
IGUIButton* leftButton;
IGUIButton* rightButton;
};
#endif /* INC_CGUISCROLLINGTABCONTROL_H */
CGUIScrollingTabControl.cpp
Code: Select all
#include "CGUIScrollingTabControl.h"
//! constructor
CGUITab::CGUITab(s32 number, IGUIEnvironment* environment,
IGUIElement* parent, const core::rect<s32>& rectangle,
s32 id)
: IGUITab(environment, parent, id, rectangle), Number(number),
DrawBackground(false), BackColor(0,0,0,0)
{
#ifdef _DEBUG
setDebugName("CGUITab");
#endif
}
//! Returns number of tab in tabcontrol. Can be accessed
//! later IGUITabControl::getTab() by this number.
s32 CGUITab::getNumber() const
{
return Number;
}
//! Sets the number
void CGUITab::setNumber(s32 n)
{
Number = n;
}
//! draws the element and its children
void CGUITab::draw()
{
if (!IsVisible)
return;
IGUISkin *skin = Environment->getSkin();
if (skin && DrawBackground)
skin->draw2DRectangle(this, BackColor, AbsoluteRect, &AbsoluteClippingRect);
IGUIElement::draw();
}
//! sets if the tab should draw its background
void CGUITab::setDrawBackground(bool draw)
{
DrawBackground = draw;
}
//! sets the color of the background, if it should be drawn.
void CGUITab::setBackgroundColor(video::SColor c)
{
BackColor = c;
}
//! returns true if the tab is drawing its background, false if not
bool CGUITab::isDrawingBackground() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return DrawBackground;
}
//! returns the color of the background
video::SColor CGUITab::getBackgroundColor() const
{
return BackColor;
}
//! Writes attributes of the element.
void CGUITab::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUITab::serializeAttributes(out,options);
out->addInt ("TabNumber", Number);
out->addBool ("DrawBackground", DrawBackground);
out->addColor ("BackColor", BackColor);
}
//! Reads attributes of the element
void CGUITab::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUITab::deserializeAttributes(in,options);
setNumber(in->getAttributeAsInt("TabNumber"));
setDrawBackground(in->getAttributeAsBool("DrawBackground"));
setBackgroundColor(in->getAttributeAsColor("BackColor"));
if (Parent && Parent->getType() == EGUIET_TAB_CONTROL)
{
((CGUIScrollingTabControl*)Parent)->addTab(this);
if (isVisible())
((CGUIScrollingTabControl*)Parent)->setActiveTab(this);
}
}
//! constructor
CGUIScrollingTabControl::CGUIScrollingTabControl(IGUIEnvironment* environment,
IGUIElement* parent, const core::rect<s32>& rectangle,
bool fillbackground, bool border, s32 id)
: IGUITabControl(environment, parent, id, rectangle), ActiveTab(-1),
Border(border), FillBackground(fillbackground)
{
#ifdef _DEBUG
setDebugName("CGUIScrollingTabControl");
#endif
TabStartPosX = AbsoluteRect.UpperLeftCorner.X + 25;
MaxTabWidth = AbsoluteRect.getWidth()/2;
leftButton = environment->addButton(core::rect<s32>(0, 0, 20, 30), this, -1, L"<");
rightButton = environment->addButton(core::rect<s32>(rectangle.getWidth()-20, 0, rectangle.getWidth(), 30), this, -1, L">");
}
//! destructor
CGUIScrollingTabControl::~CGUIScrollingTabControl()
{
for (u32 i=0; i<Tabs.size(); ++i)
{
if (Tabs[i])
Tabs[i]->drop();
}
}
//! Adds a tab
CGUITab* CGUIScrollingTabControl::addTab(const wchar_t* caption, s32 id)
{
IGUISkin* skin = Environment->getSkin();
if (!skin)
return 0;
s32 tabheight = skin->getSize(gui::EGDS_BUTTON_HEIGHT) + 2;
core::rect<s32> r(1,tabheight,
AbsoluteRect.getWidth()-1,
AbsoluteRect.getHeight()-1);
CGUITab* tab = new CGUITab(Tabs.size(), Environment, this, r, id);
tab->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
tab->setText(caption);
tab->setVisible(false);
Tabs.push_back(tab);
if (ActiveTab == -1)
{
ActiveTab = 0;
tab->setVisible(true);
}
return tab;
}
//! adds a tab which has been created elsewhere
void CGUIScrollingTabControl::addTab(CGUITab* tab)
{
if (!tab)
return;
// check if its already added
for (u32 i=0; i < Tabs.size(); ++i)
{
if (Tabs[i] == tab)
return;
}
tab->grab();
if (tab->getNumber() == -1)
tab->setNumber((s32)Tabs.size());
while (tab->getNumber() >= (s32)Tabs.size())
Tabs.push_back(0);
if (Tabs[tab->getNumber()])
{
Tabs.push_back(Tabs[tab->getNumber()]);
Tabs[Tabs.size()-1]->setNumber(Tabs.size());
}
Tabs[tab->getNumber()] = tab;
if (ActiveTab == -1)
ActiveTab = tab->getNumber();
if (tab->getNumber() == ActiveTab)
{
setActiveTab(ActiveTab);
}
}
//! Returns amount of tabs in the tabcontrol
s32 CGUIScrollingTabControl::getTabCount() const
{
return Tabs.size();
}
//! Returns a tab based on zero based index
IGUITab* CGUIScrollingTabControl::getTab(s32 idx) const
{
if ((u32)idx >= Tabs.size())
return 0;
return Tabs[idx];
}
//! called if an event happened.
bool CGUIScrollingTabControl::OnEvent(const SEvent& event) {
if (!IsEnabled)
return Parent ? Parent->OnEvent(event) : false;
switch(event.EventType) {
case EET_GUI_EVENT: {
switch (event.GUIEvent.EventType) {
case EGET_BUTTON_CLICKED:
if (event.GUIEvent.Caller == leftButton) {
s32 idx = ActiveTab - 1;
if (idx < 0) idx = 0;
setActiveTab(idx);
return true;
} else if (event.GUIEvent.Caller == rightButton) {
s32 idx = ActiveTab + 1;
if (idx > Tabs.size()-1) idx = Tabs.size()-1;
setActiveTab(idx);
return true;
}
}
break;
}
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event) {
case EMIE_LMOUSE_PRESSED_DOWN:
Environment->setFocus(this);
return true;
case EMIE_LMOUSE_LEFT_UP:
Environment->removeFocus(this);
s32 offset = TabStartPosX - (AbsoluteRect.UpperLeftCorner.X + 25); // offset due to scrolling
selectTab(core::position2d<s32>(event.MouseInput.X - offset, event.MouseInput.Y));
return true;
}
break;
}
return Parent ? Parent->OnEvent(event) : false;
}
void CGUIScrollingTabControl::selectTab(core::position2d<s32> p)
{
IGUISkin* skin = Environment->getSkin();
IGUIFont* font = skin->getFont();
core::rect<s32> frameRect(AbsoluteRect);
s32 tabheight = skin->getSize(gui::EGDS_BUTTON_HEIGHT);
frameRect.UpperLeftCorner.Y += 2;
frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + tabheight;
s32 pos = frameRect.UpperLeftCorner.X + 2 + 25;
for (u32 i=0; i<Tabs.size(); ++i)
{
// get Text
const wchar_t* text = 0;
if (Tabs[i])
text = Tabs[i]->getText();
// get text length
s32 len = 0;
if (font)
len = font->getDimension(text).Width + 10;
if (len > MaxTabWidth && (s32)i != ActiveTab) len = MaxTabWidth;
frameRect.UpperLeftCorner.X = pos;
frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len;
pos += len;
if (frameRect.isPointInside(p))
{
setActiveTab(i);
return;
}
}
}
s32 CGUIScrollingTabControl::getTabsLengthUpTo(s32 tab) {
IGUIFont* font = Environment->getSkin()->getFont();
const wchar_t* text = 0;
s32 totalLength = 0;
s32 len = 0;
for (u32 i = 0 ; i < tab ; ++i) {
if (Tabs[i]) {
text = Tabs[i]->getText();
len = font->getDimension(text).Width + 10;
if (len > MaxTabWidth && (s32)i != ActiveTab) len = MaxTabWidth;
totalLength += len;
}
}
return totalLength;
}
s32 CGUIScrollingTabControl::getActiveTabLength() {
IGUIFont* font = Environment->getSkin()->getFont();
if (Tabs[ActiveTab]) return font->getDimension(Tabs[ActiveTab]->getText()).Width + 10;
return 0;
}
//! draws the element and its children
void CGUIScrollingTabControl::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
IGUIFont* font = skin->getFont();
core::rect<s32> frameRect(AbsoluteRect);
if (Tabs.empty())
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT),
frameRect, &AbsoluteClippingRect);
if (!font)
return;
s32 tabheight = skin->getSize(gui::EGDS_BUTTON_HEIGHT);
frameRect.UpperLeftCorner.Y += 2;
frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + tabheight;
core::rect<s32> tr;
// Check whether we need to shift the tabs backwards to make the selected one visible
s32 prevLen = getTabsLengthUpTo(ActiveTab);
s32 activeLen = getActiveTabLength();
s32 offset = frameRect.UpperLeftCorner.X + 25;
if (prevLen > ((frameRect.LowerRightCorner.X-frameRect.UpperLeftCorner.X)-50)-activeLen) offset -= activeLen + (prevLen - ((frameRect.LowerRightCorner.X-frameRect.UpperLeftCorner.X)-50));
if (TabStartPosX != offset) TabStartPosX += (offset>TabStartPosX?1:-1);
// left and right pos of the active tab
s32 left = 0;
s32 right = 0;
core::stringw activetext = "";
s32 pos = TabStartPosX;
for (u32 i=0; i<Tabs.size(); ++i)
{
// get Text
core::stringw text = "";
if (Tabs[i])
text = Tabs[i]->getText();
// get text length
s32 len = font->getDimension(text.c_str()).Width + 10;
if (len > MaxTabWidth && (s32)i != ActiveTab) len = MaxTabWidth;
frameRect.UpperLeftCorner.X = pos;
frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len;
pos += len;
if ((s32)i == ActiveTab)
{
left = frameRect.UpperLeftCorner.X;
right = frameRect.LowerRightCorner.X;
activetext = text;
}
else
{
skin->draw3DTabButton(this, false, frameRect, &AbsoluteClippingRect);
if (len >= MaxTabWidth) {
do {
text.erase(text.size()-1);
} while (font->getDimension(text.c_str()).Width + 10 > MaxTabWidth - 5);
text += "...";
}
// draw text
font->draw(text.c_str(), frameRect, skin->getColor(EGDC_BUTTON_TEXT),
true, true, &AbsoluteClippingRect);
}
}
// draw active tab
if (left != 0 && right != 0)
{
frameRect.UpperLeftCorner.X = left-2;
frameRect.LowerRightCorner.X = right+2;
frameRect.UpperLeftCorner.Y -= 2;
skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect);
// draw text
font->draw(activetext.c_str(), frameRect, skin->getColor(EGDC_BUTTON_TEXT),
true, true, &AbsoluteClippingRect);
// draw upper highlight frame
tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X;
tr.LowerRightCorner.X = left - 1;
tr.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - 1;
tr.LowerRightCorner.Y = frameRect.LowerRightCorner.Y;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);
tr.UpperLeftCorner.X = right;
tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);
}
skin->draw3DTabBody(this, Border, FillBackground, AbsoluteRect, &AbsoluteClippingRect);
IGUIElement::draw();
}
//! Returns which tab is currently active
s32 CGUIScrollingTabControl::getActiveTab() const
{
return ActiveTab;
}
bool CGUIScrollingTabControl::setActiveTab(IGUIElement *tab)
{
for (s32 i=0; i<(s32)Tabs.size(); ++i)
if (Tabs[i] == tab)
return setActiveTab(i);
return false;
}
//! Brings a tab to front.
bool CGUIScrollingTabControl::setActiveTab(s32 idx)
{
if ((u32)idx >= Tabs.size())
return false;
bool changed = (ActiveTab != idx);
ActiveTab = idx;
for (s32 i=0; i<(s32)Tabs.size(); ++i)
if (Tabs[i])
Tabs[i]->setVisible( i == ActiveTab );
if (changed)
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_TAB_CHANGED;
Parent->OnEvent(event);
}
return true;
}
//! Removes a child.
void CGUIScrollingTabControl::removeChild(IGUIElement* child)
{
bool isTab = false;
u32 i=0;
// check if it is a tab
while (i<Tabs.size())
{
if (Tabs[i] == child)
{
Tabs[i]->drop();
Tabs.erase(i);
isTab = true;
}
else
++i;
}
// reassign numbers
if (isTab)
{
for (i=0; i<Tabs.size(); ++i)
if (Tabs[i])
Tabs[i]->setNumber(i);
}
// remove real element
IGUIElement::removeChild(child);
}
//! Writes attributes of the element.
void CGUIScrollingTabControl::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUITabControl::serializeAttributes(out,options);
out->addInt("ActiveTab", ActiveTab);
out->addBool("Border", Border);
out->addBool("FillBackground", FillBackground);
}
//! Reads attributes of the element
void CGUIScrollingTabControl::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
Border = in->getAttributeAsBool("Border");
FillBackground = in->getAttributeAsBool("FillBackground");
ActiveTab = -1;
IGUITabControl::deserializeAttributes(in,options);
setActiveTab(in->getAttributeAsInt("ActiveTab"));
}
Usage is as simple as:
Code: Select all
IGUITabControl* tabControl = new CGUIScrollingTabControl(env, wnd, core::rect<s32>(6,25,294,193), true, true);
And it then behaves just like a normal IGUITabControl.