mirror of
https://github.com/minetest/irrlicht.git
synced 2024-11-20 09:10:25 +01:00
CGUITabControl: Center selected tab whenever possible
This greatly improves the navigation speed by clicking through the tabs without losing track of the current scroll position.
This commit is contained in:
parent
05a00a8d91
commit
afbe41019c
@ -454,7 +454,7 @@ void CGUITabControl::scrollRight()
|
|||||||
recalculateScrollBar();
|
recalculateScrollBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 CGUITabControl::calcTabWidth(s32 pos, IGUIFont* font, const wchar_t* text, bool withScrollControl) const
|
s32 CGUITabControl::calcTabWidth(IGUIFont* font, const wchar_t* text) const
|
||||||
{
|
{
|
||||||
if ( !font )
|
if ( !font )
|
||||||
return 0;
|
return 0;
|
||||||
@ -463,26 +463,11 @@ s32 CGUITabControl::calcTabWidth(s32 pos, IGUIFont* font, const wchar_t* text, b
|
|||||||
if ( TabMaxWidth > 0 && len > TabMaxWidth )
|
if ( TabMaxWidth > 0 && len > TabMaxWidth )
|
||||||
len = TabMaxWidth;
|
len = TabMaxWidth;
|
||||||
|
|
||||||
// check if we miss the place to draw the tab-button
|
|
||||||
if ( withScrollControl && ScrollControl && pos+len > UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 )
|
|
||||||
{
|
|
||||||
s32 tabMinWidth = font->getDimension(L"A").Width;
|
|
||||||
if ( TabExtraWidth > 0 && TabExtraWidth > tabMinWidth )
|
|
||||||
tabMinWidth = TabExtraWidth;
|
|
||||||
|
|
||||||
if ( ScrollControl && pos+tabMinWidth <= UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 )
|
|
||||||
{
|
|
||||||
len = UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 - pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGUITabControl::needScrollControl(s32 startIndex, bool withScrollControl)
|
bool CGUITabControl::needScrollControl(s32 startIndex, bool withScrollControl, s32 *pos_rightmost)
|
||||||
{
|
{
|
||||||
if ( startIndex >= (s32)Tabs.size() )
|
|
||||||
startIndex -= 1;
|
|
||||||
|
|
||||||
if ( startIndex < 0 )
|
if ( startIndex < 0 )
|
||||||
startIndex = 0;
|
startIndex = 0;
|
||||||
|
|
||||||
@ -492,15 +477,16 @@ bool CGUITabControl::needScrollControl(s32 startIndex, bool withScrollControl)
|
|||||||
|
|
||||||
IGUIFont* font = skin->getFont();
|
IGUIFont* font = skin->getFont();
|
||||||
|
|
||||||
core::rect<s32> frameRect(AbsoluteRect);
|
|
||||||
|
|
||||||
if (Tabs.empty())
|
if (Tabs.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!font)
|
if (!font)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
s32 pos = frameRect.UpperLeftCorner.X + 2;
|
s32 pos = AbsoluteRect.UpperLeftCorner.X + 2;
|
||||||
|
const s32 pos_right = withScrollControl ?
|
||||||
|
UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 :
|
||||||
|
AbsoluteRect.LowerRightCorner.X;
|
||||||
|
|
||||||
for (s32 i = startIndex; i < (s32)Tabs.size(); ++i)
|
for (s32 i = startIndex; i < (s32)Tabs.size(); ++i)
|
||||||
{
|
{
|
||||||
@ -511,26 +497,71 @@ bool CGUITabControl::needScrollControl(s32 startIndex, bool withScrollControl)
|
|||||||
text = Tabs[i]->getText();
|
text = Tabs[i]->getText();
|
||||||
|
|
||||||
// get text length
|
// get text length
|
||||||
s32 len = calcTabWidth(pos, font, text, false); // always without withScrollControl here or len would be shortened
|
s32 len = calcTabWidth(font, text); // always without withScrollControl here or len would be shortened
|
||||||
|
|
||||||
frameRect.LowerRightCorner.X += len;
|
|
||||||
|
|
||||||
frameRect.UpperLeftCorner.X = pos;
|
|
||||||
frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len;
|
|
||||||
pos += len;
|
pos += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( withScrollControl && pos > UpButton->getAbsolutePosition().UpperLeftCorner.X - 2)
|
if (pos > pos_right)
|
||||||
return true;
|
|
||||||
|
|
||||||
if ( !withScrollControl && pos > AbsoluteRect.LowerRightCorner.X )
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pos_rightmost)
|
||||||
|
*pos_rightmost = pos;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
s32 CGUITabControl::calculateScrollIndexFromActive()
|
||||||
|
{
|
||||||
|
if (!ScrollControl || Tabs.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
IGUISkin *skin = Environment->getSkin();
|
||||||
|
if (!skin)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IGUIFont *font = skin->getFont();
|
||||||
|
if (!font)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const s32 pos_left = AbsoluteRect.UpperLeftCorner.X + 2;
|
||||||
|
const s32 pos_right = UpButton->getAbsolutePosition().UpperLeftCorner.X - 2;
|
||||||
|
|
||||||
|
// Move from center to the left border left until it is reached
|
||||||
|
s32 pos_cl = (pos_left + pos_right) / 2;
|
||||||
|
s32 i = ActiveTabIndex;
|
||||||
|
for (; i > 0; --i) {
|
||||||
|
if (!Tabs[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s32 len = calcTabWidth(font, Tabs[i]->getText());
|
||||||
|
if (i == ActiveTabIndex)
|
||||||
|
len /= 2;
|
||||||
|
if (pos_cl - len < pos_left)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos_cl -= len;
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
// Is scrolling to right still possible?
|
||||||
|
s32 pos_rr = 0;
|
||||||
|
if (needScrollControl(i, true, &pos_rr))
|
||||||
|
return i; // Yes? -> OK
|
||||||
|
|
||||||
|
// No? -> Decrease "i" more. Append tabs until scrolling becomes necessary
|
||||||
|
for (--i; i > 0; --i) {
|
||||||
|
if (!Tabs[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pos_rr += calcTabWidth(font, Tabs[i]->getText());
|
||||||
|
if (pos_rr > pos_right)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
core::rect<s32> CGUITabControl::calcTabPos()
|
core::rect<s32> CGUITabControl::calcTabPos()
|
||||||
{
|
{
|
||||||
core::rect<s32> r;
|
core::rect<s32> r;
|
||||||
@ -613,7 +644,7 @@ void CGUITabControl::draw()
|
|||||||
IGUITab *activeTab = 0;
|
IGUITab *activeTab = 0;
|
||||||
|
|
||||||
// Draw all tab-buttons except the active one
|
// Draw all tab-buttons except the active one
|
||||||
for (u32 i=CurrentScrollTabIndex; i<Tabs.size(); ++i)
|
for (u32 i = CurrentScrollTabIndex; i < Tabs.size() && !needRightScroll; ++i)
|
||||||
{
|
{
|
||||||
// get Text
|
// get Text
|
||||||
const wchar_t* text = 0;
|
const wchar_t* text = 0;
|
||||||
@ -621,11 +652,13 @@ void CGUITabControl::draw()
|
|||||||
text = Tabs[i]->getText();
|
text = Tabs[i]->getText();
|
||||||
|
|
||||||
// get text length
|
// get text length
|
||||||
s32 len = calcTabWidth(pos, font, text, true);
|
s32 len = calcTabWidth(font, text);
|
||||||
if ( ScrollControl && pos+len > UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 )
|
if (ScrollControl) {
|
||||||
{
|
s32 space = UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 - pos;
|
||||||
|
if (space < len) {
|
||||||
needRightScroll = true;
|
needRightScroll = true;
|
||||||
break;
|
len = space;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frameRect.LowerRightCorner.X += len;
|
frameRect.LowerRightCorner.X += len;
|
||||||
@ -794,6 +827,7 @@ s32 CGUITabControl::getTabExtraWidth() const
|
|||||||
|
|
||||||
void CGUITabControl::recalculateScrollBar()
|
void CGUITabControl::recalculateScrollBar()
|
||||||
{
|
{
|
||||||
|
// Down: to right, Up: to left
|
||||||
if (!UpButton || !DownButton)
|
if (!UpButton || !DownButton)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -894,7 +928,8 @@ s32 CGUITabControl::getTabAt(s32 xpos, s32 ypos) const
|
|||||||
if (!frameRect.isPointInside(p))
|
if (!frameRect.isPointInside(p))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (s32 i=CurrentScrollTabIndex; i<(s32)Tabs.size(); ++i)
|
bool abort = false;
|
||||||
|
for (s32 i = CurrentScrollTabIndex; i < (s32)Tabs.size() && !abort; ++i)
|
||||||
{
|
{
|
||||||
// get Text
|
// get Text
|
||||||
const wchar_t* text = 0;
|
const wchar_t* text = 0;
|
||||||
@ -902,9 +937,15 @@ s32 CGUITabControl::getTabAt(s32 xpos, s32 ypos) const
|
|||||||
text = Tabs[i]->getText();
|
text = Tabs[i]->getText();
|
||||||
|
|
||||||
// get text length
|
// get text length
|
||||||
s32 len = calcTabWidth(pos, font, text, true);
|
s32 len = calcTabWidth(font, text);
|
||||||
if ( ScrollControl && pos+len > UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 )
|
if (ScrollControl) {
|
||||||
return -1;
|
// TODO: merge this with draw() ?
|
||||||
|
s32 space = UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 - pos;
|
||||||
|
if (space < len) {
|
||||||
|
abort = true;
|
||||||
|
len = space;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
frameRect.UpperLeftCorner.X = pos;
|
frameRect.UpperLeftCorner.X = pos;
|
||||||
frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len;
|
frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len;
|
||||||
@ -915,6 +956,7 @@ s32 CGUITabControl::getTabAt(s32 xpos, s32 ypos) const
|
|||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -948,6 +990,11 @@ bool CGUITabControl::setActiveTab(s32 idx)
|
|||||||
Parent->OnEvent(event);
|
Parent->OnEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ScrollControl) {
|
||||||
|
CurrentScrollTabIndex = calculateScrollIndexFromActive();
|
||||||
|
recalculateScrollBar();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,8 +153,11 @@ namespace gui
|
|||||||
|
|
||||||
void scrollLeft();
|
void scrollLeft();
|
||||||
void scrollRight();
|
void scrollRight();
|
||||||
bool needScrollControl( s32 startIndex=0, bool withScrollControl=false );
|
//! Indicates whether the tabs overflow in X direction
|
||||||
s32 calcTabWidth(s32 pos, IGUIFont* font, const wchar_t* text, bool withScrollControl ) const;
|
bool needScrollControl( s32 startIndex=0, bool withScrollControl=false, s32 *pos_rightmost=nullptr );
|
||||||
|
//! Left index calculation based on the selected tab
|
||||||
|
s32 calculateScrollIndexFromActive();
|
||||||
|
s32 calcTabWidth(IGUIFont* font, const wchar_t* text) const;
|
||||||
core::rect<s32> calcTabPos();
|
core::rect<s32> calcTabPos();
|
||||||
void setVisibleTab(s32 idx);
|
void setVisibleTab(s32 idx);
|
||||||
void removeTabButNotChild(s32 idx);
|
void removeTabButNotChild(s32 idx);
|
||||||
|
Loading…
Reference in New Issue
Block a user