2020-01-03 20:05:16 +01:00
|
|
|
// 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;
|
2020-06-12 22:41:49 +02:00
|
|
|
s.PosY = 0;
|
2020-01-03 20:05:16 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-12-19 16:03:11 +01:00
|
|
|
if (menu)
|
2020-01-03 20:05:16 +01:00
|
|
|
{
|
2020-12-19 16:03:11 +01:00
|
|
|
menu->setVisible(false);
|
2020-01-03 20:05:16 +01:00
|
|
|
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);
|
|
|
|
return true;
|
|
|
|
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 highligted
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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_
|
|
|
|
|