Add vertical tabs (#3314)
* Add vertical tabs to ribbon widget types * Update GUI engine for vertical tabs * Add the ability to get a ribbon's active children number * Add full looping for vertical tabs
This commit is contained in:
parent
750320fbeb
commit
be98a6c4c3
@ -99,7 +99,8 @@ namespace GUIEngine
|
||||
|
||||
\n
|
||||
\subsection widget1 WTYPE_RIBBON
|
||||
<em> Names in XML files: </em> \c "ribbon", \c "buttonbar", \c "tabs"
|
||||
<em> Names in XML files: </em> \c "ribbon", \c "buttonbar", \c "tabs",
|
||||
\c"vertical-tabs"
|
||||
|
||||
Appears as an horizontal bar containing elements laid in a row, each being
|
||||
and icon and/or a label
|
||||
@ -351,9 +352,9 @@ namespace GUIEngine
|
||||
size (parent size means the parent \<div\> or the whole screen if none). A
|
||||
negative value can also be passed to start coordinate from right and/or
|
||||
bottom, instead of starting from top-left corner as usual.
|
||||
Note that in many cases, it is not necessary to manually a position. Div
|
||||
Note that in many cases, it is not necessary to manually set a position. Div
|
||||
layouts will often manage that for you (see PROP_LAYOUT). Other widgets will
|
||||
also automativally manage the position and size of their children, for
|
||||
also automatically manage the position and size of their children, for
|
||||
instance ribbons.
|
||||
|
||||
\n
|
||||
@ -367,7 +368,7 @@ namespace GUIEngine
|
||||
Note that in many cases, it is not necessary to manually a size. Div layouts
|
||||
will often manage that for you (see PROP_LAYOUT). In addition, sizes are
|
||||
automatically calculated for widgets made of icons and/or text like labels
|
||||
and plain icons. Other widgets will also automativally manage the position
|
||||
and plain icons. Other widgets will also automatically manage the position
|
||||
and size of their children, for instance ribbons.
|
||||
|
||||
Another possible value is "fit", which will make a \<div\> fit to its
|
||||
|
@ -433,12 +433,12 @@ void EventHandler::sendNavigationEvent(const NavigationDirection nav, const int
|
||||
else if (nav == NAV_DOWN)
|
||||
propagation_state = widget_to_call->downPressed(playerID);
|
||||
|
||||
if (propagation_state == EVENT_LET)
|
||||
sendEventToUser(widget_to_call, widget_to_call->m_properties[PROP_ID], playerID);
|
||||
|
||||
if (propagation_state == EVENT_LET || propagation_state == EVENT_BLOCK_BUT_HANDLED)
|
||||
handled_by_widget = true;
|
||||
|
||||
if (propagation_state == EVENT_LET)
|
||||
sendEventToUser(widget_to_call, widget_to_call->m_properties[PROP_ID], playerID);
|
||||
|
||||
if (widget_to_call->m_event_handler == NULL)
|
||||
break;
|
||||
|
||||
@ -476,6 +476,20 @@ void EventHandler::navigate(const NavigationDirection nav, const int playerID)
|
||||
assert(list != NULL);
|
||||
list->setSelectionID(nav == NAV_UP ? list->getItemCount() - 1 : 0);
|
||||
}
|
||||
// Similar exception for vertical tabs, only apply when entering with down/up
|
||||
if (closest_widget->m_type == GUIEngine::WTYPE_RIBBON && (nav == NAV_UP || nav == NAV_DOWN))
|
||||
{
|
||||
RibbonWidget* ribbon = dynamic_cast<RibbonWidget*>(closest_widget);
|
||||
assert(ribbon != NULL);
|
||||
if (ribbon->getRibbonType() == GUIEngine::RibbonType::RIBBON_VERTICAL_TABS)
|
||||
{
|
||||
int new_selection = (nav == NAV_UP) ?
|
||||
ribbon->getActiveChildrenNumber(playerID) - 1 : 0;
|
||||
ribbon->setSelection(new_selection, playerID);
|
||||
// The tab selection triggers an action
|
||||
sendEventToUser(ribbon, ribbon->m_properties[PROP_ID], playerID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
@ -535,6 +549,7 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
int rightmost = w_test->m_x + w_test->m_w;
|
||||
|
||||
if (nav == NAV_UP || nav == NAV_DOWN)
|
||||
{
|
||||
@ -564,7 +579,7 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
|
||||
// we substract the smaller from the bigger
|
||||
// else, the smaller is 0 and we keep the bigger
|
||||
int right_offset = std::max(0, w_test->m_x - w->m_x);
|
||||
int left_offset = std::max(0, (w->m_x + w->m_w) - (w_test->m_x + w_test->m_w));
|
||||
int left_offset = std::max(0, (w->m_x + w->m_w) - rightmost);
|
||||
offset = std::max (right_offset - left_offset, left_offset - right_offset);
|
||||
}
|
||||
else if (nav == NAV_LEFT || nav == NAV_RIGHT)
|
||||
@ -572,7 +587,7 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
|
||||
if (nav == NAV_LEFT)
|
||||
{
|
||||
// compare current leftmost point with other widget rightmost
|
||||
distance = w->m_x - (w_test->m_x + w_test->m_w);
|
||||
distance = w->m_x - rightmost;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -585,9 +600,28 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p
|
||||
int up_offset = std::max(0, (w->m_y + w->m_h) - (w_test->m_y + w_test->m_h));
|
||||
offset = std::max (down_offset - up_offset, up_offset - down_offset);
|
||||
|
||||
// Special case for vertical tabs : select the top element of the body
|
||||
if (w->m_type == GUIEngine::WTYPE_RIBBON)
|
||||
{
|
||||
RibbonWidget* ribbon = dynamic_cast<RibbonWidget*>(w);
|
||||
if (ribbon->getRibbonType() == GUIEngine::RibbonType::RIBBON_VERTICAL_TABS)
|
||||
{
|
||||
offset = w_test->m_y;
|
||||
offset *= 100;
|
||||
|
||||
// Don't count elements above the tabs or too high as valid
|
||||
if (!(w_test->m_x > (w->m_x + w->m_w) || rightmost < w->m_x) ||
|
||||
(w_test->m_y + w_test->m_h) < w->m_y)
|
||||
{
|
||||
distance = BIG_DISTANCE;
|
||||
wrapping_distance = BIG_DISTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No lateral selection if there is not at least partial alignement
|
||||
// >= because we don't want it to trigger if two widgets touch each other
|
||||
if (offset >= w->m_h)
|
||||
else if (offset >= w->m_h)
|
||||
{
|
||||
distance = BIG_DISTANCE;
|
||||
wrapping_distance = BIG_DISTANCE;
|
||||
@ -912,4 +946,3 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
@ -102,6 +102,10 @@ void Screen::parseScreenFileDiv(irr::io::IXMLReader* xml, PtrVector<Widget>& app
|
||||
{
|
||||
append_to.push_back(new RibbonWidget(RIBBON_TABS));
|
||||
}
|
||||
else if (wcscmp(L"vertical-tabs", xml->getNodeName()) == 0)
|
||||
{
|
||||
append_to.push_back(new RibbonWidget(RIBBON_VERTICAL_TABS));
|
||||
}
|
||||
else if (wcscmp(L"spinner", xml->getNodeName()) == 0)
|
||||
{
|
||||
append_to.push_back(new SpinnerWidget());
|
||||
@ -270,9 +274,10 @@ if(prop_name != NULL) widget.m_properties[prop_flag] = core::stringc(prop_name).
|
||||
|
||||
// We're done parsing this 'ribbon', return one step back in
|
||||
// the recursive call.
|
||||
if (wcscmp(L"ribbon", xml->getNodeName()) == 0 ||
|
||||
wcscmp(L"buttonbar", xml->getNodeName()) == 0 ||
|
||||
wcscmp(L"tabs", xml->getNodeName()) == 0)
|
||||
if (wcscmp(L"ribbon", xml->getNodeName()) == 0 ||
|
||||
wcscmp(L"buttonbar", xml->getNodeName()) == 0 ||
|
||||
wcscmp(L"tabs", xml->getNodeName()) == 0 ||
|
||||
wcscmp(L"vertical-tabs", xml->getNodeName()) == 0)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -1003,6 +1003,56 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget,
|
||||
material2D.UseMipMaps = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* vertical tab-bar ribbons */
|
||||
else if (type == RIBBON_VERTICAL_TABS)
|
||||
{
|
||||
video::SMaterial& material2D =
|
||||
irr_driver->getVideoDriver()->getMaterial2D();
|
||||
for (unsigned int n=0; n<MATERIAL_MAX_TEXTURES; n++)
|
||||
{
|
||||
material2D.UseMipMaps = false;
|
||||
}
|
||||
|
||||
const bool mouseIn = rect.isPointInside(irr_driver->getDevice()
|
||||
->getCursorControl()
|
||||
->getPosition() );
|
||||
|
||||
BoxRenderParams* params;
|
||||
|
||||
if (mark_selected && (focused || parent_focused))
|
||||
params = &SkinConfig::m_render_params["verticalTab::focused"];
|
||||
else if (parentRibbon->m_mouse_focus == widget && mouseIn)
|
||||
params = &SkinConfig::m_render_params["verticalTab::focused"];
|
||||
else if (mark_selected)
|
||||
params = &SkinConfig::m_render_params["verticalTab::down"];
|
||||
else
|
||||
params = &SkinConfig::m_render_params["verticalTab::neutral"];
|
||||
|
||||
|
||||
// automatically guess from position on-screen if tabs go left or right
|
||||
unsigned int screen_width = irr_driver->getActualScreenSize().Width;
|
||||
const bool horizontal_flip =
|
||||
(unsigned int)rect.UpperLeftCorner.X > screen_width/ 2;
|
||||
params->m_vertical_flip = false;
|
||||
|
||||
core::recti rect2 = rect;
|
||||
if (mark_selected)
|
||||
{
|
||||
// the selected tab should be slighlty bigger than others
|
||||
if (horizontal_flip) rect2.UpperLeftCorner.X -= screen_width/50;
|
||||
else rect2.LowerRightCorner.X += screen_width/50;
|
||||
}
|
||||
|
||||
drawBoxFromStretchableTexture(widget, rect2, *params,
|
||||
parentRibbon->m_deactivated ||
|
||||
widget->m_deactivated);
|
||||
|
||||
for (unsigned int n=0; n<MATERIAL_MAX_TEXTURES; n++)
|
||||
{
|
||||
material2D.UseMipMaps = true;
|
||||
}
|
||||
}
|
||||
/* icon ribbons */
|
||||
else
|
||||
{
|
||||
|
@ -115,7 +115,7 @@ void RibbonWidget::add()
|
||||
if (m_active_children[i].m_type != WTYPE_ICON_BUTTON &&
|
||||
m_active_children[i].m_type != WTYPE_BUTTON)
|
||||
{
|
||||
Log::warn("RiggonWidget", "Ribbon widgets can only have "
|
||||
Log::warn("RibbonWidget", "Ribbon widgets can only have "
|
||||
"(icon)button widgets as children");
|
||||
continue;
|
||||
}
|
||||
@ -144,19 +144,26 @@ void RibbonWidget::add()
|
||||
//int biggest_y = 0;
|
||||
const int button_y = 10;
|
||||
|
||||
const int one_button_space = (subbuttons_amount == 0 ? m_w :
|
||||
const int one_button_width = (subbuttons_amount == 0 ? m_w :
|
||||
int(roundf((float)m_w / (float)subbuttons_amount)));
|
||||
|
||||
const int one_button_height = (subbuttons_amount == 0 ? m_h :
|
||||
int(roundf((float)m_h / (float)subbuttons_amount)));
|
||||
|
||||
int widget_x = -1;
|
||||
int widget_y = -1;
|
||||
|
||||
// ---- add children
|
||||
// TODO : the content of the ifs is way too large, separate functions would be better.
|
||||
// Several pre-loop variables are used inside the ifs,
|
||||
// so care must be taken to not break things
|
||||
for (int i=0; i<subbuttons_amount; i++)
|
||||
{
|
||||
// ---- tab ribbons
|
||||
if (getRibbonType() == RIBBON_TABS)
|
||||
{
|
||||
const int large_tab = (int)((with_label + without_label)
|
||||
*one_button_space
|
||||
*one_button_width
|
||||
/ (with_label + without_label/2.0f));
|
||||
const int small_tab = large_tab/2;
|
||||
|
||||
@ -277,11 +284,108 @@ void RibbonWidget::add()
|
||||
|
||||
if (message.size() == 0) widget_x += small_tab/2;
|
||||
else widget_x += large_tab/2;
|
||||
}
|
||||
} // tabs
|
||||
|
||||
|
||||
// ---- vertical tab ribbons
|
||||
else if (getRibbonType() == RIBBON_VERTICAL_TABS)
|
||||
{
|
||||
const int tab_width = (int)((with_label + without_label)
|
||||
*m_w
|
||||
/ (with_label + without_label/2.0f));
|
||||
|
||||
stringw& message = m_active_children[i].m_text;
|
||||
|
||||
widget_x = tab_width/2;
|
||||
|
||||
if (widget_y == -1)
|
||||
widget_y = 0;
|
||||
else
|
||||
widget_y += one_button_height;
|
||||
|
||||
IGUIButton * subbtn = NULL;
|
||||
|
||||
// The buttons will overlap without this,
|
||||
// as drawBoxFromStretchableTexture draw the borders outside
|
||||
// of a widget's reserved area
|
||||
int VERT_BORDER_MARGIN = 8;
|
||||
rect<s32> subbtn_rec = rect<s32>(widget_x - tab_width/2+2, widget_y + VERT_BORDER_MARGIN,
|
||||
widget_x + tab_width/2-2, widget_y - VERT_BORDER_MARGIN + one_button_height);
|
||||
|
||||
|
||||
// TODO Add support for BUTTON type when needed
|
||||
if (m_active_children[i].m_type == WTYPE_ICON_BUTTON)
|
||||
{
|
||||
// The icon will take 1/3rd of the tab width at most, less if height is lacking
|
||||
int icon_size = std::min(m_w/3, subbtn_rec.getHeight()+2*VERT_BORDER_MARGIN);
|
||||
|
||||
rect<s32> icon_part = rect<s32>(5,
|
||||
one_button_height/2 - icon_size/2-VERT_BORDER_MARGIN,
|
||||
icon_size+5,
|
||||
one_button_height/2 + icon_size/2-VERT_BORDER_MARGIN);
|
||||
|
||||
// label at the *right* of the icon (for tabs)
|
||||
rect<s32> label_part = rect<s32>(icon_size+5,
|
||||
5-VERT_BORDER_MARGIN,
|
||||
subbtn_rec.getWidth()-5,
|
||||
one_button_height-5-VERT_BORDER_MARGIN);
|
||||
|
||||
// use the same ID for all subcomponents; since event handling
|
||||
// is done per-ID, no matter which one your hover, this
|
||||
// widget will get it
|
||||
int same_id = getNewNoFocusID();
|
||||
subbtn = GUIEngine::getGUIEnv()->addButton(subbtn_rec, btn,
|
||||
same_id, L"", L"");
|
||||
|
||||
IGUIButton* icon =
|
||||
GUIEngine::getGUIEnv()->addButton(icon_part, subbtn,
|
||||
same_id, L"");
|
||||
icon->setScaleImage(true);
|
||||
std::string filename = file_manager->getAsset(
|
||||
m_active_children[i].m_properties[PROP_ICON]);
|
||||
icon->setImage( irr_driver->getTexture(filename.c_str()) );
|
||||
icon->setUseAlphaChannel(true);
|
||||
icon->setDrawBorder(false);
|
||||
icon->setTabStop(false);
|
||||
|
||||
IGUIStaticText* label =
|
||||
GUIEngine::getGUIEnv()->addStaticText(message.c_str(),
|
||||
label_part,
|
||||
false /* border */,
|
||||
true /* word wrap */,
|
||||
subbtn, same_id);
|
||||
|
||||
if ((int)GUIEngine::getFont()->getDimension(message.c_str())
|
||||
.Width > label_part.getWidth()&&
|
||||
message.findFirst(L' ') == -1 &&
|
||||
message.findFirst(L'\u00AD') == -1 )
|
||||
{
|
||||
// if message too long and contains no space and no soft
|
||||
// hyphen, make the font smaller
|
||||
label->setOverrideFont(GUIEngine::getSmallFont());
|
||||
}
|
||||
label->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
|
||||
label->setTabStop(false);
|
||||
label->setNotClipped(true);
|
||||
label->setRightToLeft(translations->isRTLText(message));
|
||||
m_labels.push_back(label);
|
||||
|
||||
subbtn->setTabStop(false);
|
||||
subbtn->setTabGroup(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("RibbonWidget", "Invalid tab bar contents");
|
||||
}
|
||||
|
||||
m_active_children[i].m_element = subbtn;
|
||||
} // vertical-tabs
|
||||
|
||||
|
||||
// ---- icon ribbons
|
||||
else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON)
|
||||
{
|
||||
if (widget_x == -1) widget_x = one_button_space/2;
|
||||
if (widget_x == -1) widget_x = one_button_width/2;
|
||||
|
||||
// find how much space to keep for the label under the button.
|
||||
// consider font size, whether the label is multiline, etc...
|
||||
@ -316,7 +420,7 @@ void RibbonWidget::add()
|
||||
float image_h = (float)image->getSize().Height;
|
||||
float image_w = image_h*imageRatio;
|
||||
float zoom = (float) (m_h - button_y - needed_space_under_button) / image_h;
|
||||
float zoom_x = (float) one_button_space / image_w;
|
||||
float zoom_x = (float) one_button_width / image_w;
|
||||
if(zoom_x < zoom)
|
||||
zoom = zoom_x;
|
||||
|
||||
@ -338,7 +442,7 @@ void RibbonWidget::add()
|
||||
if (icon->m_properties[PROP_EXTEND_LABEL].size() == 0)
|
||||
{
|
||||
icon->m_properties[PROP_EXTEND_LABEL] =
|
||||
StringUtils::toString(one_button_space - icon->m_w);
|
||||
StringUtils::toString(one_button_width - icon->m_w);
|
||||
}
|
||||
|
||||
m_active_children.get(i)->m_parent = btn;
|
||||
@ -354,7 +458,7 @@ void RibbonWidget::add()
|
||||
// adds the label outside of the widget area it is assigned to,
|
||||
// the label will appear in the area we want at the bottom
|
||||
|
||||
widget_x += one_button_space;
|
||||
widget_x += one_button_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -373,7 +477,7 @@ void RibbonWidget::add()
|
||||
|
||||
if (!m_is_visible)
|
||||
setVisible(false);
|
||||
} // add
|
||||
} // add
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@ -460,65 +564,64 @@ void RibbonWidget::select(std::string item, const int mousePlayerID)
|
||||
// ----------------------------------------------------------------------------
|
||||
EventPropagation RibbonWidget::rightPressed(const int playerID)
|
||||
{
|
||||
EventPropagation result = m_ribbon_type != RIBBON_TOOLBAR ? EVENT_LET : EVENT_BLOCK_BUT_HANDLED;
|
||||
|
||||
if (m_deactivated) return result;
|
||||
// empty ribbon, or only one item (can't move right)
|
||||
if (m_active_children.size() < 2) return result;
|
||||
|
||||
m_selection[playerID]++;
|
||||
|
||||
if (m_selection[playerID] >= int(m_active_children.size()))
|
||||
{
|
||||
if (m_listener != NULL) m_listener->onRibbonWidgetScroll(1);
|
||||
|
||||
m_selection[playerID] = m_event_handler ? m_active_children.size()-1 : 0;
|
||||
}
|
||||
updateSelection();
|
||||
|
||||
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS)
|
||||
{
|
||||
const int mousePlayerID = input_manager->getPlayerKeyboardID();
|
||||
if (playerID == mousePlayerID || playerID == PLAYER_ID_GAME_MASTER)
|
||||
{
|
||||
m_mouse_focus = m_active_children.get(m_selection[playerID]);
|
||||
}
|
||||
}
|
||||
|
||||
// if we reached a filler item, move again (but don't wrap)
|
||||
if (getSelectionIDString(playerID) == RibbonWidget::NO_ITEM_ID)
|
||||
{
|
||||
if (m_selection[playerID] + 1 < int(m_active_children.size()))
|
||||
{
|
||||
rightPressed(playerID);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return moveToNextItem(/*horizontal*/ true, /*reverse*/ false, playerID);
|
||||
} // rightPressed
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
EventPropagation RibbonWidget::leftPressed(const int playerID)
|
||||
{
|
||||
EventPropagation result = m_ribbon_type != RIBBON_TOOLBAR ? EVENT_LET : EVENT_BLOCK_BUT_HANDLED;
|
||||
|
||||
if (m_deactivated) return result;
|
||||
// empty ribbon, or only one item (can't move left)
|
||||
if (m_active_children.size() < 2) return result;
|
||||
return moveToNextItem(/*horizontal*/ true, /*reverse*/ true, playerID);
|
||||
} // leftPressed
|
||||
|
||||
m_selection[playerID]--;
|
||||
if (m_selection[playerID] < 0)
|
||||
// ----------------------------------------------------------------------------
|
||||
EventPropagation RibbonWidget::downPressed(const int playerID)
|
||||
{
|
||||
return moveToNextItem(/*horizontal*/ false, /*reverse*/ false, playerID);
|
||||
} // downPressed
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
EventPropagation RibbonWidget::upPressed(const int playerID)
|
||||
{
|
||||
return moveToNextItem(/*horizontal*/ false, /*reverse*/ true, playerID);
|
||||
} // upPressed
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
EventPropagation RibbonWidget::moveToNextItem(const bool horizontally, const bool reverse, const int playerID)
|
||||
{
|
||||
EventPropagation result = propagationType(horizontally);
|
||||
|
||||
// Do nothing and do not block navigating out of the widget
|
||||
if (result == EVENT_BLOCK) return result;
|
||||
|
||||
if (reverse)
|
||||
m_selection[playerID]--;
|
||||
else
|
||||
m_selection[playerID]++;
|
||||
|
||||
if (m_selection[playerID] >= int(m_active_children.size()) || m_selection[playerID] < 0)
|
||||
{
|
||||
if (m_listener != NULL) m_listener->onRibbonWidgetScroll(-1);
|
||||
// In vertical tabs, don't loop when reaching the top or bottom
|
||||
if (!horizontally)
|
||||
{
|
||||
if (reverse)
|
||||
m_selection[playerID]++;
|
||||
else
|
||||
m_selection[playerID]--;
|
||||
|
||||
m_selection[playerID] = m_event_handler
|
||||
? 0
|
||||
: m_active_children.size()-1;
|
||||
return EVENT_BLOCK;
|
||||
}
|
||||
bool left = (m_selection[playerID] < 0);
|
||||
|
||||
if (m_listener != NULL) m_listener->onRibbonWidgetScroll(left ? -1 : 1);
|
||||
|
||||
bool select_zero = (m_event_handler && left) || (!m_event_handler && !left);
|
||||
|
||||
m_selection[playerID] = select_zero ? 0 : m_active_children.size()-1;
|
||||
}
|
||||
|
||||
updateSelection();
|
||||
|
||||
if (m_ribbon_type == RIBBON_COMBO)
|
||||
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS ||
|
||||
m_ribbon_type == RIBBON_VERTICAL_TABS)
|
||||
{
|
||||
const int mousePlayerID = input_manager->getPlayerKeyboardID();
|
||||
if (playerID == mousePlayerID || playerID == PLAYER_ID_GAME_MASTER)
|
||||
@ -530,16 +633,38 @@ EventPropagation RibbonWidget::leftPressed(const int playerID)
|
||||
// if we reached a filler item, move again (but don't wrap)
|
||||
if (getSelectionIDString(playerID) == RibbonWidget::NO_ITEM_ID)
|
||||
{
|
||||
if (m_selection[playerID] > 0) leftPressed(playerID);
|
||||
if (((m_selection[playerID] > 0) && reverse ) ||
|
||||
((m_selection[playerID] + 1 < int(m_active_children.size()))&& !reverse) )
|
||||
{
|
||||
moveToNextItem(horizontally, reverse, playerID);
|
||||
}
|
||||
}
|
||||
|
||||
//if (m_ribbon_type != RIBBON_TOOLBAR)
|
||||
//{
|
||||
//GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID );
|
||||
//}
|
||||
return result;
|
||||
} // moveToNextItem
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
EventPropagation RibbonWidget::propagationType(const bool horizontally)
|
||||
{
|
||||
EventPropagation result;
|
||||
|
||||
if (horizontally)
|
||||
{
|
||||
result = m_ribbon_type == RIBBON_VERTICAL_TABS ? EVENT_BLOCK :
|
||||
m_ribbon_type != RIBBON_TOOLBAR ? EVENT_LET :
|
||||
EVENT_BLOCK_BUT_HANDLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = m_ribbon_type != RIBBON_VERTICAL_TABS ? EVENT_BLOCK :
|
||||
EVENT_LET;
|
||||
}
|
||||
if (m_deactivated) result = EVENT_BLOCK;
|
||||
// empty ribbon, or only one item (can't move)
|
||||
if (m_active_children.size() < 2) result = EVENT_BLOCK;
|
||||
|
||||
return result;
|
||||
} // leftPressed
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@ -549,7 +674,8 @@ EventPropagation RibbonWidget::focused(const int playerID)
|
||||
|
||||
if (m_active_children.size() < 1) return EVENT_LET; // empty ribbon
|
||||
|
||||
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS)
|
||||
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS ||
|
||||
m_ribbon_type == RIBBON_VERTICAL_TABS)
|
||||
{
|
||||
const int mousePlayerID = input_manager->getPlayerKeyboardID();
|
||||
if (m_mouse_focus == NULL && m_selection[playerID] != -1 &&
|
||||
@ -598,7 +724,8 @@ EventPropagation RibbonWidget::mouseHovered(Widget* child,
|
||||
|
||||
const int subbuttons_amount = m_active_children.size();
|
||||
|
||||
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS)
|
||||
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS ||
|
||||
m_ribbon_type == RIBBON_VERTICAL_TABS)
|
||||
{
|
||||
//Log::info("RibbonWidget", "Setting m_mouse_focus");
|
||||
m_mouse_focus = child;
|
||||
@ -765,12 +892,8 @@ int RibbonWidget::findItemNamed(const char* internalName)
|
||||
{
|
||||
const int size = m_children.size();
|
||||
|
||||
//printf("Ribbon : Looking for %s among %i items\n", internalName, size);
|
||||
|
||||
for (int n=0; n<size; n++)
|
||||
{
|
||||
//printf(" Ribbon : Looking for %s in item %i : %s\n",
|
||||
// internalName, n, m_children[n].m_properties[PROP_ID].c_str());
|
||||
if (m_children[n].m_properties[PROP_ID] == internalName) return n;
|
||||
}
|
||||
return -1;
|
||||
|
@ -37,7 +37,8 @@ namespace GUIEngine
|
||||
{
|
||||
RIBBON_COMBO, //!< select one item out of many, like in a combo box
|
||||
RIBBON_TOOLBAR, //!< a row of individual buttons
|
||||
RIBBON_TABS //!< a tab bar
|
||||
RIBBON_TABS, //!< a tab bar
|
||||
RIBBON_VERTICAL_TABS //!< a vertical tab bar
|
||||
};
|
||||
|
||||
/** \brief A static text/icons/tabs bar widget.
|
||||
@ -66,17 +67,21 @@ namespace GUIEngine
|
||||
|
||||
int m_selection[MAX_PLAYER_COUNT];
|
||||
|
||||
/** The type of this ribbon (toolbar, combo, tabs) */
|
||||
/** The type of this ribbon (toolbar, combo, tabs, vertical tabs) */
|
||||
RibbonType m_ribbon_type;
|
||||
|
||||
/** Each item within the ribbon holds a flag saying whether it is
|
||||
* selected or not. This method updates the flag in all of this
|
||||
* ribbon's children. Called everytime selection changes.*/
|
||||
void updateSelection();
|
||||
|
||||
|
||||
/** Callbacks */
|
||||
virtual EventPropagation rightPressed(const int playerID=0) OVERRIDE;
|
||||
virtual EventPropagation leftPressed(const int playerID=0) OVERRIDE;
|
||||
virtual EventPropagation upPressed(const int playerID=0) OVERRIDE;
|
||||
virtual EventPropagation downPressed(const int playerID=0) OVERRIDE;
|
||||
EventPropagation moveToNextItem(const bool horizontally, const bool reverse, const int playerID);
|
||||
EventPropagation propagationType(const bool horizontally);
|
||||
virtual EventPropagation mouseHovered(Widget* child,
|
||||
const int playerID) OVERRIDE;
|
||||
virtual EventPropagation transmitEvent(Widget* w,
|
||||
@ -121,6 +126,10 @@ namespace GUIEngine
|
||||
* for detailed descriptions) */
|
||||
RibbonType getRibbonType() const { return m_ribbon_type; }
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the number of active items within the ribbon */
|
||||
int getActiveChildrenNumber(const int playerID) const
|
||||
{ return m_active_children.size(); }
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the numerical ID of the selected item within the ribbon */
|
||||
int getSelection(const int playerID) const
|
||||
{ return m_selection[playerID]; }
|
||||
|
Loading…
Reference in New Issue
Block a user