mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-25 02:00:30 +01:00
17c7a1bd6e
This got in the way of allowing to move a camera with right-mouse-button while having a context menu. Hard to tell which way is "more" correct as this break of behavior probably can also mess up some situations. There also would be 3rd option of only catching the event when highlighting happens. Anyway - usually if this should be caught it should be caught for all ui elements and people will check focused or hovered. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6412 dfc29bdd-3216-0410-991c-e03cc46cb475
881 lines
20 KiB
C++
881 lines
20 KiB
C++
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
|
// This file is part of the "Irrlicht Engine".
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
#include "CGUIContextMenu.h"
|
|
|
|
#ifdef _IRR_COMPILE_WITH_GUI_
|
|
|
|
#include "IGUISkin.h"
|
|
#include "IGUIEnvironment.h"
|
|
#include "IVideoDriver.h"
|
|
#include "IGUIFont.h"
|
|
#include "IGUISpriteBank.h"
|
|
#include "os.h"
|
|
|
|
namespace irr
|
|
{
|
|
namespace gui
|
|
{
|
|
|
|
|
|
//! constructor
|
|
CGUIContextMenu::CGUIContextMenu(IGUIEnvironment* environment,
|
|
IGUIElement* parent, s32 id,
|
|
core::rect<s32> rectangle, bool getFocus, bool allowFocus)
|
|
: IGUIContextMenu(environment, parent, id, rectangle), EventParent(0), LastFont(0),
|
|
CloseHandling(ECMC_REMOVE), HighLighted(-1), ChangeTime(0), AllowFocus(allowFocus)
|
|
{
|
|
#ifdef _DEBUG
|
|
setDebugName("CGUIContextMenu");
|
|
#endif
|
|
|
|
Pos = rectangle.UpperLeftCorner;
|
|
recalculateSize();
|
|
|
|
if (getFocus)
|
|
Environment->setFocus(this);
|
|
|
|
setNotClipped(true);
|
|
}
|
|
|
|
|
|
//! destructor
|
|
CGUIContextMenu::~CGUIContextMenu()
|
|
{
|
|
for (u32 i=0; i<Items.size(); ++i)
|
|
if (Items[i].SubMenu)
|
|
Items[i].SubMenu->drop();
|
|
|
|
if (LastFont)
|
|
LastFont->drop();
|
|
}
|
|
|
|
//! set behavior when menus are closed
|
|
void CGUIContextMenu::setCloseHandling(ECONTEXT_MENU_CLOSE onClose)
|
|
{
|
|
CloseHandling = onClose;
|
|
}
|
|
|
|
//! get current behavior when the menue will be closed
|
|
ECONTEXT_MENU_CLOSE CGUIContextMenu::getCloseHandling() const
|
|
{
|
|
return CloseHandling;
|
|
}
|
|
|
|
//! Returns amount of menu items
|
|
u32 CGUIContextMenu::getItemCount() const
|
|
{
|
|
return Items.size();
|
|
}
|
|
|
|
|
|
//! Adds a menu item.
|
|
u32 CGUIContextMenu::addItem(const wchar_t* text, s32 commandId, bool enabled, bool hasSubMenu, bool checked, bool autoChecking)
|
|
{
|
|
return insertItem(Items.size(), text, commandId, enabled, hasSubMenu, checked, autoChecking);
|
|
}
|
|
|
|
//! Insert a menu item at specified position.
|
|
u32 CGUIContextMenu::insertItem(u32 idx, const wchar_t* text, s32 commandId, bool enabled,
|
|
bool hasSubMenu, bool checked, bool autoChecking)
|
|
{
|
|
SItem s;
|
|
s.Enabled = enabled;
|
|
s.Checked = checked;
|
|
s.AutoChecking = autoChecking;
|
|
s.Text = text;
|
|
s.IsSeparator = (text == 0);
|
|
s.SubMenu = 0;
|
|
s.CommandId = commandId;
|
|
s.PosY = 0;
|
|
|
|
if (hasSubMenu)
|
|
{
|
|
s.SubMenu = new CGUIContextMenu(Environment, this, commandId,
|
|
core::rect<s32>(0,0,100,100), false, false);
|
|
s.SubMenu->setVisible(false);
|
|
}
|
|
|
|
u32 result = idx;
|
|
if ( idx < Items.size() )
|
|
{
|
|
Items.insert(s, idx);
|
|
}
|
|
else
|
|
{
|
|
Items.push_back(s);
|
|
result = Items.size() - 1;
|
|
}
|
|
|
|
recalculateSize();
|
|
return result;
|
|
}
|
|
|
|
s32 CGUIContextMenu::findItemWithCommandId(s32 commandId, u32 idxStartSearch) const
|
|
{
|
|
for ( u32 i=idxStartSearch; i<Items.size(); ++i )
|
|
{
|
|
if ( Items[i].CommandId == commandId )
|
|
{
|
|
return (s32)i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//! Adds a sub menu from an element that already exists.
|
|
void CGUIContextMenu::setSubMenu(u32 index, CGUIContextMenu* menu)
|
|
{
|
|
if (index >= Items.size())
|
|
return;
|
|
|
|
if (menu)
|
|
menu->grab();
|
|
if (Items[index].SubMenu)
|
|
Items[index].SubMenu->drop();
|
|
|
|
Items[index].SubMenu = menu;
|
|
|
|
if (menu)
|
|
{
|
|
menu->setVisible(false);
|
|
menu->AllowFocus = false;
|
|
if ( Environment->getFocus() == menu )
|
|
{
|
|
Environment->setFocus( this );
|
|
}
|
|
}
|
|
|
|
recalculateSize();
|
|
}
|
|
|
|
|
|
//! Adds a separator item to the menu
|
|
void CGUIContextMenu::addSeparator()
|
|
{
|
|
addItem(0, -1, true, false, false, false);
|
|
}
|
|
|
|
|
|
//! Returns text of the menu item.
|
|
const wchar_t* CGUIContextMenu::getItemText(u32 idx) const
|
|
{
|
|
if (idx >= Items.size())
|
|
return 0;
|
|
|
|
return Items[idx].Text.c_str();
|
|
}
|
|
|
|
|
|
//! Sets text of the menu item.
|
|
void CGUIContextMenu::setItemText(u32 idx, const wchar_t* text)
|
|
{
|
|
if (idx >= Items.size())
|
|
return;
|
|
|
|
Items[idx].Text = text;
|
|
recalculateSize();
|
|
}
|
|
|
|
//! should the element change the checked status on clicking
|
|
void CGUIContextMenu::setItemAutoChecking(u32 idx, bool autoChecking)
|
|
{
|
|
if ( idx >= Items.size())
|
|
return;
|
|
|
|
Items[idx].AutoChecking = autoChecking;
|
|
}
|
|
|
|
//! does the element change the checked status on clicking
|
|
bool CGUIContextMenu::getItemAutoChecking(u32 idx) const
|
|
{
|
|
if (idx >= Items.size())
|
|
return false;
|
|
|
|
return Items[idx].AutoChecking;
|
|
}
|
|
|
|
|
|
//! Returns if a menu item is enabled
|
|
bool CGUIContextMenu::isItemEnabled(u32 idx) const
|
|
{
|
|
if (idx >= Items.size())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Items[idx].Enabled;
|
|
}
|
|
|
|
|
|
//! Returns if a menu item is checked
|
|
bool CGUIContextMenu::isItemChecked(u32 idx) const
|
|
{
|
|
if (idx >= Items.size())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Items[idx].Checked;
|
|
}
|
|
|
|
|
|
//! Sets if the menu item should be enabled.
|
|
void CGUIContextMenu::setItemEnabled(u32 idx, bool enabled)
|
|
{
|
|
if (idx >= Items.size())
|
|
return;
|
|
|
|
Items[idx].Enabled = enabled;
|
|
}
|
|
|
|
|
|
//! Sets if the menu item should be checked.
|
|
void CGUIContextMenu::setItemChecked(u32 idx, bool checked )
|
|
{
|
|
if (idx >= Items.size())
|
|
return;
|
|
|
|
Items[idx].Checked = checked;
|
|
}
|
|
|
|
|
|
//! Removes a menu item
|
|
void CGUIContextMenu::removeItem(u32 idx)
|
|
{
|
|
if (idx >= Items.size())
|
|
return;
|
|
|
|
if (Items[idx].SubMenu)
|
|
{
|
|
Items[idx].SubMenu->drop();
|
|
Items[idx].SubMenu = 0;
|
|
}
|
|
|
|
Items.erase(idx);
|
|
recalculateSize();
|
|
}
|
|
|
|
|
|
//! Removes all menu items
|
|
void CGUIContextMenu::removeAllItems()
|
|
{
|
|
for (u32 i=0; i<Items.size(); ++i)
|
|
if (Items[i].SubMenu)
|
|
Items[i].SubMenu->drop();
|
|
|
|
Items.clear();
|
|
recalculateSize();
|
|
}
|
|
|
|
|
|
//! called if an event happened.
|
|
bool CGUIContextMenu::OnEvent(const SEvent& event)
|
|
{
|
|
if (isEnabled())
|
|
{
|
|
|
|
switch(event.EventType)
|
|
{
|
|
case EET_GUI_EVENT:
|
|
switch(event.GUIEvent.EventType)
|
|
{
|
|
case EGET_ELEMENT_FOCUS_LOST:
|
|
if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element) && AllowFocus)
|
|
{
|
|
// set event parent of submenus
|
|
IGUIElement * p = EventParent ? EventParent : Parent;
|
|
if ( p ) // can be 0 when element got removed already
|
|
{
|
|
setEventParent(p);
|
|
|
|
SEvent eventClose;
|
|
eventClose.EventType = EET_GUI_EVENT;
|
|
eventClose.GUIEvent.Caller = this;
|
|
eventClose.GUIEvent.Element = 0;
|
|
eventClose.GUIEvent.EventType = EGET_ELEMENT_CLOSED;
|
|
if ( !p->OnEvent(eventClose) )
|
|
{
|
|
if ( CloseHandling & ECMC_HIDE )
|
|
{
|
|
setVisible(false);
|
|
}
|
|
if ( CloseHandling & ECMC_REMOVE )
|
|
{
|
|
remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
break;
|
|
case EGET_ELEMENT_FOCUSED:
|
|
if (event.GUIEvent.Caller == this && !AllowFocus)
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case EET_MOUSE_INPUT_EVENT:
|
|
switch(event.MouseInput.Event)
|
|
{
|
|
case EMIE_LMOUSE_LEFT_UP:
|
|
{
|
|
// menu might be removed if it loses focus in sendClick, so grab a reference
|
|
grab();
|
|
const u32 t = sendClick(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
|
|
if ((t==0 || t==1) && Environment->hasFocus(this))
|
|
Environment->removeFocus(this);
|
|
drop();
|
|
}
|
|
return true;
|
|
case EMIE_LMOUSE_PRESSED_DOWN:
|
|
return true;
|
|
case EMIE_MOUSE_MOVED:
|
|
if (Environment->hasFocus(this))
|
|
highlight(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y), true);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return IGUIElement::OnEvent(event);
|
|
}
|
|
|
|
|
|
//! Sets the visible state of this element.
|
|
void CGUIContextMenu::setVisible(bool visible)
|
|
{
|
|
HighLighted = -1;
|
|
ChangeTime = os::Timer::getTime();
|
|
for (u32 j=0; j<Items.size(); ++j)
|
|
if (Items[j].SubMenu)
|
|
Items[j].SubMenu->setVisible(false);
|
|
|
|
IGUIElement::setVisible(visible);
|
|
}
|
|
|
|
|
|
//! sends a click Returns:
|
|
//! 0 if click went outside of the element,
|
|
//! 1 if a valid button was clicked,
|
|
//! 2 if a nonclickable element was clicked
|
|
u32 CGUIContextMenu::sendClick(const core::position2d<s32>& p)
|
|
{
|
|
u32 t = 0;
|
|
|
|
// get number of open submenu
|
|
s32 openmenu = -1;
|
|
s32 j;
|
|
for (j=0; j<(s32)Items.size(); ++j)
|
|
if (Items[j].SubMenu && Items[j].SubMenu->isVisible())
|
|
{
|
|
openmenu = j;
|
|
break;
|
|
}
|
|
|
|
// delegate click operation to submenu
|
|
if (openmenu != -1)
|
|
{
|
|
t = Items[j].SubMenu->sendClick(p);
|
|
if (t != 0)
|
|
return t; // clicked something
|
|
}
|
|
|
|
// check click on myself
|
|
if (isPointInside(p) &&
|
|
(u32)HighLighted < Items.size())
|
|
{
|
|
if (!Items[HighLighted].Enabled ||
|
|
Items[HighLighted].IsSeparator ||
|
|
Items[HighLighted].SubMenu)
|
|
return 2;
|
|
|
|
if ( Items[HighLighted].AutoChecking )
|
|
{
|
|
Items[HighLighted].Checked = Items[HighLighted].Checked ? false : true;
|
|
}
|
|
|
|
SEvent event;
|
|
event.EventType = EET_GUI_EVENT;
|
|
event.GUIEvent.Caller = this;
|
|
event.GUIEvent.Element = 0;
|
|
event.GUIEvent.EventType = EGET_MENU_ITEM_SELECTED;
|
|
if (EventParent)
|
|
EventParent->OnEvent(event);
|
|
else if (Parent)
|
|
Parent->OnEvent(event);
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//! returns true, if an element was highlighted
|
|
bool CGUIContextMenu::highlight(const core::position2d<s32>& p, bool canOpenSubMenu)
|
|
{
|
|
if (!isEnabled())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// get number of open submenu
|
|
s32 openmenu = -1;
|
|
s32 i;
|
|
for (i=0; i<(s32)Items.size(); ++i)
|
|
if (Items[i].Enabled && Items[i].SubMenu && Items[i].SubMenu->isVisible())
|
|
{
|
|
openmenu = i;
|
|
break;
|
|
}
|
|
|
|
// delegate highlight operation to submenu
|
|
if (openmenu != -1)
|
|
{
|
|
if (Items[openmenu].Enabled && Items[openmenu].SubMenu->highlight(p, canOpenSubMenu))
|
|
{
|
|
HighLighted = openmenu;
|
|
ChangeTime = os::Timer::getTime();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// highlight myself
|
|
for (i=0; i<(s32)Items.size(); ++i)
|
|
{
|
|
if (Items[i].Enabled && getHRect(Items[i], AbsoluteRect).isPointInside(p))
|
|
{
|
|
HighLighted = i;
|
|
ChangeTime = os::Timer::getTime();
|
|
|
|
// make submenus visible/invisible
|
|
for (s32 j=0; j<(s32)Items.size(); ++j)
|
|
if (Items[j].SubMenu)
|
|
{
|
|
if ( j == i && canOpenSubMenu && Items[j].Enabled )
|
|
Items[j].SubMenu->setVisible(true);
|
|
else if ( j != i )
|
|
Items[j].SubMenu->setVisible(false);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
HighLighted = openmenu;
|
|
return false;
|
|
}
|
|
|
|
|
|
//! returns the item highlight-area
|
|
core::rect<s32> CGUIContextMenu::getHRect(const SItem& i, const core::rect<s32>& absolute) const
|
|
{
|
|
core::rect<s32> r = absolute;
|
|
r.UpperLeftCorner.Y += i.PosY;
|
|
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height;
|
|
return r;
|
|
}
|
|
|
|
|
|
//! Gets drawing rect of Item
|
|
core::rect<s32> CGUIContextMenu::getRect(const SItem& i, const core::rect<s32>& absolute) const
|
|
{
|
|
core::rect<s32> r = absolute;
|
|
r.UpperLeftCorner.Y += i.PosY;
|
|
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height;
|
|
r.UpperLeftCorner.X += 20;
|
|
return r;
|
|
}
|
|
|
|
|
|
//! draws the element and its children
|
|
void CGUIContextMenu::draw()
|
|
{
|
|
if (!IsVisible)
|
|
return;
|
|
|
|
IGUISkin* skin = Environment->getSkin();
|
|
|
|
if (!skin)
|
|
return;
|
|
|
|
IGUIFont* font = skin->getFont(EGDF_MENU);
|
|
if (font != LastFont)
|
|
{
|
|
if (LastFont)
|
|
LastFont->drop();
|
|
LastFont = font;
|
|
if (LastFont)
|
|
LastFont->grab();
|
|
|
|
recalculateSize();
|
|
}
|
|
|
|
IGUISpriteBank* sprites = skin->getSpriteBank();
|
|
|
|
core::rect<s32> rect = AbsoluteRect;
|
|
core::rect<s32>* clip = 0;
|
|
|
|
// draw frame
|
|
skin->draw3DMenuPane(this, AbsoluteRect, clip);
|
|
|
|
// loop through all menu items
|
|
|
|
rect = AbsoluteRect;
|
|
s32 y = AbsoluteRect.UpperLeftCorner.Y;
|
|
|
|
for (s32 i=0; i<(s32)Items.size(); ++i)
|
|
{
|
|
if (Items[i].IsSeparator)
|
|
{
|
|
// draw separator
|
|
rect = AbsoluteRect;
|
|
rect.UpperLeftCorner.Y += Items[i].PosY + 3;
|
|
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;
|
|
rect.UpperLeftCorner.X += 5;
|
|
rect.LowerRightCorner.X -= 5;
|
|
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), rect, clip);
|
|
|
|
rect.LowerRightCorner.Y += 1;
|
|
rect.UpperLeftCorner.Y += 1;
|
|
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
|
|
|
|
y += 10;
|
|
}
|
|
else
|
|
{
|
|
rect = getRect(Items[i], AbsoluteRect);
|
|
|
|
// draw highlighted
|
|
|
|
if (i == HighLighted && Items[i].Enabled)
|
|
{
|
|
core::rect<s32> r = AbsoluteRect;
|
|
r.LowerRightCorner.Y = rect.LowerRightCorner.Y;
|
|
r.UpperLeftCorner.Y = rect.UpperLeftCorner.Y;
|
|
r.LowerRightCorner.X -= 5;
|
|
r.UpperLeftCorner.X += 5;
|
|
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), r, clip);
|
|
}
|
|
|
|
// draw text
|
|
|
|
EGUI_DEFAULT_COLOR c = EGDC_BUTTON_TEXT;
|
|
|
|
if (i == HighLighted)
|
|
c = EGDC_HIGH_LIGHT_TEXT;
|
|
|
|
if (!Items[i].Enabled)
|
|
c = EGDC_GRAY_TEXT;
|
|
|
|
if (font)
|
|
font->draw(Items[i].Text.c_str(), rect,
|
|
skin->getColor(c), false, true, clip);
|
|
|
|
// draw submenu symbol
|
|
if (Items[i].SubMenu && sprites)
|
|
{
|
|
core::rect<s32> r = rect;
|
|
r.UpperLeftCorner.X = r.LowerRightCorner.X - 15;
|
|
|
|
sprites->draw2DSprite(skin->getIcon(EGDI_CURSOR_RIGHT),
|
|
r.getCenter(), clip, skin->getColor(c),
|
|
(i == HighLighted) ? ChangeTime : 0,
|
|
(i == HighLighted) ? os::Timer::getTime() : 0,
|
|
(i == HighLighted), true);
|
|
}
|
|
|
|
// draw checked symbol
|
|
if (Items[i].Checked && sprites)
|
|
{
|
|
core::rect<s32> r = rect;
|
|
r.LowerRightCorner.X = r.UpperLeftCorner.X - 15;
|
|
r.UpperLeftCorner.X = r.LowerRightCorner.X + 15;
|
|
sprites->draw2DSprite(skin->getIcon(EGDI_CHECK_BOX_CHECKED),
|
|
r.getCenter(), clip, skin->getColor(c),
|
|
(i == HighLighted) ? ChangeTime : 0,
|
|
(i == HighLighted) ? os::Timer::getTime() : 0,
|
|
(i == HighLighted), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
IGUIElement::draw();
|
|
}
|
|
|
|
|
|
void CGUIContextMenu::recalculateSize()
|
|
{
|
|
IGUIFont* font = Environment->getSkin()->getFont(EGDF_MENU);
|
|
|
|
if (!font)
|
|
return;
|
|
|
|
core::rect<s32> rect;
|
|
rect.UpperLeftCorner = RelativeRect.UpperLeftCorner;
|
|
u32 width = 100;
|
|
u32 height = 3;
|
|
|
|
u32 i;
|
|
for (i=0; i<Items.size(); ++i)
|
|
{
|
|
if (Items[i].IsSeparator)
|
|
{
|
|
Items[i].Dim.Width = 100;
|
|
Items[i].Dim.Height = 10;
|
|
}
|
|
else
|
|
{
|
|
Items[i].Dim = font->getDimension(Items[i].Text.c_str());
|
|
Items[i].Dim.Width += 40;
|
|
|
|
if (Items[i].Dim.Width > width)
|
|
width = Items[i].Dim.Width;
|
|
}
|
|
|
|
Items[i].PosY = height;
|
|
height += Items[i].Dim.Height;
|
|
}
|
|
|
|
height += 5;
|
|
|
|
if (height < 10)
|
|
height = 10;
|
|
|
|
rect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + width;
|
|
rect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + height;
|
|
|
|
setRelativePosition(rect);
|
|
|
|
// recalculate submenus
|
|
for (i=0; i<Items.size(); ++i)
|
|
{
|
|
if (Items[i].SubMenu)
|
|
{
|
|
// move submenu
|
|
const s32 w = Items[i].SubMenu->getAbsolutePosition().getWidth();
|
|
const s32 h = Items[i].SubMenu->getAbsolutePosition().getHeight();
|
|
|
|
core::rect<s32> subRect(width-5, Items[i].PosY, width+w-5, Items[i].PosY+h);
|
|
|
|
gui::IGUIElement * root = Environment->getRootGUIElement();
|
|
if ( root )
|
|
{
|
|
core::rect<s32> rectRoot( root->getAbsolutePosition() );
|
|
|
|
// if it would be drawn beyond the right border, then add it to the left side
|
|
if ( getAbsolutePosition().UpperLeftCorner.X+subRect.LowerRightCorner.X > rectRoot.LowerRightCorner.X )
|
|
{
|
|
subRect.UpperLeftCorner.X = -w;
|
|
subRect.LowerRightCorner.X = 0;
|
|
}
|
|
|
|
// if it would be drawn below bottom border, move it up, but not further than to top.
|
|
irr::s32 belowBottom = getAbsolutePosition().UpperLeftCorner.Y+subRect.LowerRightCorner.Y - rectRoot.LowerRightCorner.Y;
|
|
if ( belowBottom > 0 )
|
|
{
|
|
irr::s32 belowTop = getAbsolutePosition().UpperLeftCorner.Y+subRect.UpperLeftCorner.Y;
|
|
irr::s32 moveUp = belowBottom < belowTop ? belowBottom : belowTop;
|
|
subRect.UpperLeftCorner.Y -= moveUp;
|
|
subRect.LowerRightCorner.Y -= moveUp;
|
|
}
|
|
}
|
|
|
|
Items[i].SubMenu->setRelativePosition(subRect);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//! Returns the selected item in the menu
|
|
s32 CGUIContextMenu::getSelectedItem() const
|
|
{
|
|
return HighLighted;
|
|
}
|
|
|
|
|
|
//! \return Returns a pointer to the submenu of an item.
|
|
IGUIContextMenu* CGUIContextMenu::getSubMenu(u32 idx) const
|
|
{
|
|
if (idx >= Items.size())
|
|
return 0;
|
|
|
|
return Items[idx].SubMenu;
|
|
}
|
|
|
|
|
|
//! Returns command id of a menu item
|
|
s32 CGUIContextMenu::getItemCommandId(u32 idx) const
|
|
{
|
|
if (idx >= Items.size())
|
|
return -1;
|
|
|
|
return Items[idx].CommandId;
|
|
}
|
|
|
|
|
|
//! Sets the command id of a menu item
|
|
void CGUIContextMenu::setItemCommandId(u32 idx, s32 id)
|
|
{
|
|
if (idx >= Items.size())
|
|
return;
|
|
|
|
Items[idx].CommandId = id;
|
|
}
|
|
|
|
|
|
//! Writes attributes of the element.
|
|
void CGUIContextMenu::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
|
|
{
|
|
IGUIElement::serializeAttributes(out,options);
|
|
out->addPosition2d("Position", Pos);
|
|
|
|
if (Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU )
|
|
{
|
|
const IGUIContextMenu* const ptr = (const IGUIContextMenu*)Parent;
|
|
// find the position of this item in its parent's list
|
|
u32 i;
|
|
// VC6 needs the cast for this
|
|
for (i=0; (i<ptr->getItemCount()) && (ptr->getSubMenu(i) != (const IGUIContextMenu*)this); ++i)
|
|
; // do nothing
|
|
|
|
out->addInt("ParentItem", i);
|
|
}
|
|
|
|
out->addInt("CloseHandling", (s32)CloseHandling);
|
|
|
|
// write out the item list
|
|
out->addInt("ItemCount", Items.size());
|
|
|
|
core::stringc tmp;
|
|
|
|
for (u32 i=0; i < Items.size(); ++i)
|
|
{
|
|
tmp = "IsSeparator"; tmp += i;
|
|
out->addBool(tmp.c_str(), Items[i].IsSeparator);
|
|
|
|
if (!Items[i].IsSeparator)
|
|
{
|
|
tmp = "Text"; tmp += i;
|
|
out->addString(tmp.c_str(), Items[i].Text.c_str());
|
|
tmp = "CommandID"; tmp += i;
|
|
out->addInt(tmp.c_str(), Items[i].CommandId);
|
|
tmp = "Enabled"; tmp += i;
|
|
out->addBool(tmp.c_str(), Items[i].Enabled);
|
|
tmp = "Checked"; tmp += i;
|
|
out->addBool(tmp.c_str(), Items[i].Checked);
|
|
tmp = "AutoChecking"; tmp += i;
|
|
out->addBool(tmp.c_str(), Items[i].AutoChecking);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//! Reads attributes of the element
|
|
void CGUIContextMenu::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
|
|
{
|
|
IGUIElement::deserializeAttributes(in,options);
|
|
|
|
Pos = in->getAttributeAsPosition2d("Position");
|
|
|
|
// link to this item's parent
|
|
if (Parent && ( Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU ) )
|
|
((CGUIContextMenu*)Parent)->setSubMenu(in->getAttributeAsInt("ParentItem"),this);
|
|
|
|
CloseHandling = (ECONTEXT_MENU_CLOSE)in->getAttributeAsInt("CloseHandling");
|
|
|
|
removeAllItems();
|
|
|
|
// read the item list
|
|
const s32 count = in->getAttributeAsInt("ItemCount");
|
|
|
|
for (s32 i=0; i<count; ++i)
|
|
{
|
|
core::stringc tmp;
|
|
core::stringw txt;
|
|
s32 commandid=-1;
|
|
bool enabled=true;
|
|
bool checked=false;
|
|
bool autochecking=false;
|
|
|
|
tmp = "IsSeparator"; tmp += i;
|
|
if ( in->existsAttribute(tmp.c_str()) && in->getAttributeAsBool(tmp.c_str()) )
|
|
addSeparator();
|
|
else
|
|
{
|
|
tmp = "Text"; tmp += i;
|
|
if ( in->existsAttribute(tmp.c_str()) )
|
|
txt = in->getAttributeAsStringW(tmp.c_str());
|
|
|
|
tmp = "CommandID"; tmp += i;
|
|
if ( in->existsAttribute(tmp.c_str()) )
|
|
commandid = in->getAttributeAsInt(tmp.c_str());
|
|
|
|
tmp = "Enabled"; tmp += i;
|
|
if ( in->existsAttribute(tmp.c_str()) )
|
|
enabled = in->getAttributeAsBool(tmp.c_str());
|
|
|
|
tmp = "Checked"; tmp += i;
|
|
if ( in->existsAttribute(tmp.c_str()) )
|
|
checked = in->getAttributeAsBool(tmp.c_str());
|
|
|
|
tmp = "AutoChecking"; tmp += i;
|
|
if ( in->existsAttribute(tmp.c_str()) )
|
|
autochecking = in->getAttributeAsBool(tmp.c_str());
|
|
|
|
addItem(core::stringw(txt.c_str()).c_str(), commandid, enabled, false, checked, autochecking);
|
|
}
|
|
}
|
|
|
|
recalculateSize();
|
|
}
|
|
|
|
|
|
// because sometimes the element has no parent at click time
|
|
void CGUIContextMenu::setEventParent(IGUIElement *parent)
|
|
{
|
|
EventParent = parent;
|
|
|
|
for (u32 i=0; i<Items.size(); ++i)
|
|
if (Items[i].SubMenu)
|
|
Items[i].SubMenu->setEventParent(parent);
|
|
}
|
|
|
|
|
|
bool CGUIContextMenu::hasOpenSubMenu() const
|
|
{
|
|
for (u32 i=0; i<Items.size(); ++i)
|
|
if (Items[i].SubMenu && Items[i].SubMenu->isVisible())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void CGUIContextMenu::closeAllSubMenus()
|
|
{
|
|
for (u32 i=0; i<Items.size(); ++i)
|
|
if (Items[i].SubMenu)
|
|
Items[i].SubMenu->setVisible(false);
|
|
|
|
//HighLighted = -1;
|
|
}
|
|
|
|
|
|
} // end namespace
|
|
} // end namespace
|
|
|
|
#endif // _IRR_COMPILE_WITH_GUI_
|
|
|