mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-24 09:03:48 +00:00
Merge pull request #2118 from Areloch/MenuAndPopups
Refactors the Popup menus and GuiMenuBars
This commit is contained in:
commit
c23c99dbea
30 changed files with 995 additions and 3116 deletions
|
|
@ -276,8 +276,6 @@ bool GuiCanvas::onAdd()
|
|||
// Define the menu bar for this canvas (if any)
|
||||
Con::executef(this, "onCreateMenu");
|
||||
|
||||
Sim::findObject("PlatformGenericMenubar", mMenuBarCtrl);
|
||||
|
||||
return parentRet;
|
||||
}
|
||||
|
||||
|
|
@ -302,21 +300,39 @@ void GuiCanvas::setMenuBar(SimObject *obj)
|
|||
Parent::removeObject( oldMenuBar );
|
||||
|
||||
// set new menubar
|
||||
if( mMenuBarCtrl )
|
||||
Parent::addObject(mMenuBarCtrl);
|
||||
if (mMenuBarCtrl)
|
||||
{
|
||||
//Add a wrapper control so that the menubar sizes correctly
|
||||
GuiControlProfile* profile;
|
||||
Sim::findObject("GuiModelessDialogProfile", profile);
|
||||
|
||||
if (!profile)
|
||||
{
|
||||
Con::errorf("GuiCanvas::setMenuBar: Unable to find the GuiModelessDialogProfile profile!");
|
||||
return;
|
||||
}
|
||||
|
||||
GuiControl* menuBackground = new GuiControl();
|
||||
menuBackground->registerObject();
|
||||
|
||||
menuBackground->setControlProfile(profile);
|
||||
|
||||
menuBackground->addObject(mMenuBarCtrl);
|
||||
|
||||
Parent::addObject(menuBackground);
|
||||
}
|
||||
|
||||
// update window accelerator keys
|
||||
if( oldMenuBar != mMenuBarCtrl )
|
||||
{
|
||||
StringTableEntry ste = StringTable->insert("menubar");
|
||||
GuiMenuBar* menu = NULL;
|
||||
menu = !oldMenuBar ? NULL : dynamic_cast<GuiMenuBar*>(oldMenuBar->findObjectByInternalName( ste, true));
|
||||
if( menu )
|
||||
menu->removeWindowAcceleratorMap( *getPlatformWindow()->getInputGenerator() );
|
||||
GuiMenuBar* oldMenu = dynamic_cast<GuiMenuBar*>(oldMenuBar);
|
||||
GuiMenuBar* newMenu = dynamic_cast<GuiMenuBar*>(mMenuBarCtrl);
|
||||
|
||||
menu = !mMenuBarCtrl ? NULL : dynamic_cast<GuiMenuBar*>(mMenuBarCtrl->findObjectByInternalName( ste, true));
|
||||
if( menu )
|
||||
menu->buildWindowAcceleratorMap( *getPlatformWindow()->getInputGenerator() );
|
||||
if(oldMenu)
|
||||
oldMenu->removeWindowAcceleratorMap(*getPlatformWindow()->getInputGenerator());
|
||||
|
||||
if(newMenu)
|
||||
newMenu->buildWindowAcceleratorMap(*getPlatformWindow()->getInputGenerator());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1633,27 +1649,26 @@ void GuiCanvas::maintainSizing()
|
|||
Point2I newPos = screenRect.point;
|
||||
|
||||
// if menubar is active displace content gui control
|
||||
if( mMenuBarCtrl && (ctrl == getContentControl()) )
|
||||
{
|
||||
const SimObject *menu = mMenuBarCtrl->findObjectByInternalName( StringTable->insert("menubar"), true);
|
||||
if (mMenuBarCtrl && (ctrl == getContentControl()))
|
||||
{
|
||||
/*const SimObject *menu = mMenuBarCtrl->findObjectByInternalName( StringTable->insert("menubar"), true);
|
||||
|
||||
if( !menu )
|
||||
continue;
|
||||
if( !menu )
|
||||
continue;
|
||||
|
||||
AssertFatal( dynamic_cast<const GuiControl*>(menu), "");
|
||||
AssertFatal( dynamic_cast<const GuiControl*>(menu), "");*/
|
||||
|
||||
const U32 yOffset = static_cast<const GuiControl*>(menu)->getExtent().y;
|
||||
newPos.y += yOffset;
|
||||
newExt.y -= yOffset;
|
||||
const U32 yOffset = static_cast<const GuiMenuBar*>(mMenuBarCtrl)->mMenubarHeight;
|
||||
newPos.y += yOffset;
|
||||
newExt.y -= yOffset;
|
||||
}
|
||||
|
||||
if(pos != newPos || ext != newExt)
|
||||
if (pos != newPos || ext != newExt)
|
||||
{
|
||||
ctrl->resize(newPos, newExt);
|
||||
resetUpdateRegions();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GuiCanvas::setupFences()
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ public:
|
|||
virtual void onRemove();
|
||||
|
||||
void setMenuBar(SimObject *obj);
|
||||
SimObject* getMenuBar() { return mMenuBarCtrl; }
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -23,119 +23,43 @@
|
|||
#ifndef _GUIMENUBAR_H_
|
||||
#define _GUIMENUBAR_H_
|
||||
|
||||
#ifndef _GUITEXTLISTCTRL_H_
|
||||
#include "gui/controls/guiTextListCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUITICKCTRL_H_
|
||||
#include "gui/shiny/guiTickCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _POPUPMENU_H_
|
||||
#include "gui/editor/popupMenu.h"
|
||||
#endif
|
||||
|
||||
class GuiMenuBar;
|
||||
class GuiMenuTextListCtrl;
|
||||
class WindowInputGenerator;
|
||||
|
||||
class GuiMenuBackgroundCtrl : public GuiControl
|
||||
{
|
||||
typedef GuiControl Parent;
|
||||
|
||||
protected:
|
||||
GuiMenuBar *mMenuBarCtrl;
|
||||
GuiMenuTextListCtrl *mTextList;
|
||||
public:
|
||||
GuiMenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl* textList);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
};
|
||||
|
||||
class GuiSubmenuBackgroundCtrl : public GuiMenuBackgroundCtrl
|
||||
{
|
||||
typedef GuiMenuBackgroundCtrl Parent;
|
||||
|
||||
public:
|
||||
GuiSubmenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl* textList);
|
||||
bool pointInControl(const Point2I & parentCoordPoint);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GuiMenuTextListCtrl : public GuiTextListCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextListCtrl Parent;
|
||||
|
||||
protected:
|
||||
GuiMenuBar *mMenuBarCtrl;
|
||||
|
||||
public:
|
||||
bool isSubMenu; // Indicates that this text list is in a submenu
|
||||
|
||||
GuiMenuTextListCtrl(); // for inheritance
|
||||
GuiMenuTextListCtrl(GuiMenuBar *ctrl);
|
||||
|
||||
// GuiControl overloads:
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
|
||||
virtual void onCellHighlighted(Point2I cell); // Added
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GuiMenuBar : public GuiTickCtrl // Was: GuiControl
|
||||
{
|
||||
typedef GuiTickCtrl Parent; // Was: GuiControl Parent;
|
||||
public:
|
||||
|
||||
struct Menu;
|
||||
struct MenuEntry
|
||||
{
|
||||
U32 pos;
|
||||
RectI bounds;
|
||||
|
||||
struct MenuItem // an individual item in a pull-down menu
|
||||
{
|
||||
char *text; // the text of the menu item
|
||||
U32 id; // a script-assigned identifier
|
||||
char *accelerator; // the keyboard accelerator shortcut for the menu item
|
||||
U32 acceleratorIndex; // index of this accelerator
|
||||
bool enabled; // true if the menu item is selectable
|
||||
bool visible; // true if the menu item is visible
|
||||
S32 bitmapIndex; // index of the bitmap in the bitmap array
|
||||
S32 checkGroup; // the group index of the item visa vi check marks -
|
||||
// only one item in the group can be checked.
|
||||
MenuItem *nextMenuItem; // next menu item in the linked list
|
||||
|
||||
bool isSubmenu; // This menu item has a submenu that will be displayed
|
||||
|
||||
Menu* submenuParentMenu; // For a submenu, this is the parent menu
|
||||
Menu* submenu;
|
||||
String cmd;
|
||||
};
|
||||
|
||||
struct Menu
|
||||
{
|
||||
char *text;
|
||||
U32 id;
|
||||
RectI bounds;
|
||||
bool visible;
|
||||
|
||||
S32 bitmapIndex; // Index of the bitmap in the bitmap array (-1 = no bitmap)
|
||||
bool drawBitmapOnly; // Draw only the bitmap and not the text
|
||||
bool drawBorder; // Should a border be drawn around this menu (usually if we only have a bitmap, we don't want a border)
|
||||
S32 bitmapIndex;
|
||||
bool drawBitmapOnly;
|
||||
|
||||
Menu *nextMenu;
|
||||
MenuItem *firstMenuItem;
|
||||
};
|
||||
|
||||
GuiMenuBackgroundCtrl *mBackground;
|
||||
GuiMenuTextListCtrl *mTextList;
|
||||
|
||||
GuiSubmenuBackgroundCtrl *mSubmenuBackground; // Background for a submenu
|
||||
GuiMenuTextListCtrl *mSubmenuTextList; // Text list for a submenu
|
||||
bool drawBorder;
|
||||
|
||||
Vector<Menu*> mMenuList;
|
||||
Menu *mouseDownMenu;
|
||||
Menu *mouseOverMenu;
|
||||
StringTableEntry text;
|
||||
PopupMenu* popupMenu;
|
||||
};
|
||||
|
||||
Vector<MenuEntry> mMenuList;
|
||||
|
||||
MenuEntry *mouseDownMenu;
|
||||
MenuEntry *mouseOverMenu;
|
||||
|
||||
MenuItem* mouseDownSubmenu; // Stores the menu item that is a submenu that has been selected
|
||||
MenuItem* mouseOverSubmenu; // Stores the menu item that is a submenu that has been highlighted
|
||||
|
|
@ -151,59 +75,26 @@ public:
|
|||
S32 mVerticalMargin; // Top and bottom margin around the text of each menu
|
||||
S32 mBitmapMargin; // Margin between a menu's bitmap and text
|
||||
|
||||
// Used to keep track of the amount of ticks that the mouse is hovering
|
||||
// over a menu.
|
||||
S32 mMouseOverCounter;
|
||||
bool mCountMouseOver;
|
||||
S32 mMouseHoverAmount;
|
||||
U32 mMenubarHeight;
|
||||
|
||||
bool mMouseInMenu;
|
||||
|
||||
GuiMenuBar();
|
||||
|
||||
void onRemove();
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
// internal menu handling functions
|
||||
// these are used by the script manipulation functions to add/remove/change menu items
|
||||
static Menu* sCreateMenu(const char *menuText, U32 menuId);
|
||||
void addMenu(Menu *menu, S32 pos = -1);
|
||||
void addMenu(const char *menuText, U32 menuId);
|
||||
Menu *findMenu(const char *menu); // takes either a menu text or a string id
|
||||
static MenuItem *findMenuItem(Menu *menu, const char *menuItem); // takes either a menu text or a string id
|
||||
void removeMenu(Menu *menu);
|
||||
static void removeMenuItem(Menu *menu, MenuItem *menuItem);
|
||||
static MenuItem* addMenuItem(Menu *menu, const char *text, U32 id, const char *accelerator, S32 checkGroup, const char *cmd);
|
||||
static MenuItem* addMenuItem(Menu *menu, MenuItem *menuItem);
|
||||
static void clearMenuItems(Menu *menu);
|
||||
void clearMenus();
|
||||
virtual void addObject(SimObject* object);
|
||||
|
||||
void attachToMenuBar(Menu* menu, S32 pos = -1);
|
||||
void removeFromMenuBar(Menu* menu);
|
||||
|
||||
// Methods to deal with submenus
|
||||
static MenuItem* findSubmenuItem(Menu *menu, const char *menuItem, const char *submenuItem);
|
||||
static MenuItem* findSubmenuItem(MenuItem *menuItem, const char *submenuItem);
|
||||
static void addSubmenuItem(Menu *menu, MenuItem *submenu, const char *text, U32 id, const char *accelerator, S32 checkGroup);
|
||||
static void addSubmenuItem(Menu *menu, MenuItem *submenu, MenuItem *newMenuItem );
|
||||
static void removeSubmenuItem(MenuItem *menuItem, MenuItem *submenuItem);
|
||||
static void clearSubmenuItems(MenuItem *menuitem);
|
||||
void onSubmenuAction(S32 selectionIndex, const RectI& bounds, Point2I cellSize);
|
||||
void closeSubmenu();
|
||||
void checkSubmenuMouseMove(const GuiEvent &event);
|
||||
MenuItem *findHitMenuItem(Point2I mousePoint);
|
||||
|
||||
void highlightedMenuItem(S32 selectionIndex, const RectI& bounds, Point2I cellSize); // Called whenever a menu item is highlighted by the mouse
|
||||
|
||||
// display/mouse functions
|
||||
|
||||
Menu *findHitMenu(Point2I mousePoint);
|
||||
|
||||
// Called when the GUI theme changes and a bitmap arrary may need updating
|
||||
// void onThemeChange();
|
||||
MenuEntry *findHitMenu(Point2I mousePoint);
|
||||
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
void checkMenuMouseMove(const GuiEvent &event);
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
void onMouseEnter(const GuiEvent &event);
|
||||
void onMouseLeave(const GuiEvent &event);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
|
|
@ -215,18 +106,21 @@ public:
|
|||
void removeWindowAcceleratorMap( WindowInputGenerator &inputGenerator );
|
||||
void acceleratorKeyPress(U32 index);
|
||||
|
||||
virtual void menuItemSelected(Menu *menu, MenuItem *item);
|
||||
|
||||
// Added to support 'ticks'
|
||||
void processTick();
|
||||
|
||||
void insert(SimObject* pObject, S32 pos);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
U32 getMenuListCount() { return mMenuList.size(); }
|
||||
|
||||
PopupMenu* getMenu(U32 index);
|
||||
|
||||
DECLARE_CONOBJECT(GuiMenuBar);
|
||||
DECLARE_CALLBACK( void, onMouseInMenu, ( bool hasLeftMenu ));
|
||||
DECLARE_CALLBACK( void, onMenuSelect, ( S32 menuId, const char* menuText ));
|
||||
DECLARE_CALLBACK( void, onMenuItemSelect, ( S32 menuId, const char* menuText, S32 menuItemId, const char* menuItemText ));
|
||||
DECLARE_CALLBACK( void, onSubmenuSelect, ( S32 submenuId, const char* submenuText ));
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,20 +25,32 @@
|
|||
#include "gfx/primBuilder.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
|
||||
GuiPopupMenuBackgroundCtrl::GuiPopupMenuBackgroundCtrl(GuiPopupMenuTextListCtrl *textList)
|
||||
GuiPopupMenuBackgroundCtrl::GuiPopupMenuBackgroundCtrl()
|
||||
{
|
||||
mTextList = textList;
|
||||
mTextList->mBackground = this;
|
||||
mMenuBarCtrl = nullptr;
|
||||
}
|
||||
|
||||
void GuiPopupMenuBackgroundCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
mTextList->setSelectedCell(Point2I(-1, -1));
|
||||
|
||||
}
|
||||
|
||||
void GuiPopupMenuBackgroundCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
clearPopups();
|
||||
|
||||
//Pass along the event just in case we clicked over a menu item. We don't want to eat the input for it.
|
||||
if (mMenuBarCtrl)
|
||||
mMenuBarCtrl->onMouseUp(event);
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
void GuiPopupMenuBackgroundCtrl::onMouseMove(const GuiEvent &event)
|
||||
{
|
||||
//It's possible we're trying to pan through a menubar while a popup is displayed. Pass along our event to the menubar for good measure
|
||||
if (mMenuBarCtrl)
|
||||
mMenuBarCtrl->onMouseMove(event);
|
||||
}
|
||||
|
||||
void GuiPopupMenuBackgroundCtrl::onMouseDragged(const GuiEvent &event)
|
||||
|
|
@ -48,26 +60,64 @@ void GuiPopupMenuBackgroundCtrl::onMouseDragged(const GuiEvent &event)
|
|||
void GuiPopupMenuBackgroundCtrl::close()
|
||||
{
|
||||
getRoot()->removeObject(this);
|
||||
|
||||
mMenuBarCtrl = nullptr;
|
||||
}
|
||||
|
||||
S32 GuiPopupMenuBackgroundCtrl::findPopupMenu(PopupMenu* menu)
|
||||
{
|
||||
S32 menuId = -1;
|
||||
|
||||
for (U32 i = 0; i < mPopups.size(); i++)
|
||||
{
|
||||
if (mPopups[i]->getId() == menu->getId())
|
||||
return i;
|
||||
}
|
||||
|
||||
return menuId;
|
||||
}
|
||||
|
||||
void GuiPopupMenuBackgroundCtrl::clearPopups()
|
||||
{
|
||||
for (U32 i = 0; i < mPopups.size(); i++)
|
||||
{
|
||||
mPopups[i]->mTextList->setSelectedCell(Point2I(-1, -1));
|
||||
mPopups[i]->mTextList->mPopup->hidePopup();
|
||||
}
|
||||
}
|
||||
|
||||
GuiPopupMenuTextListCtrl::GuiPopupMenuTextListCtrl()
|
||||
{
|
||||
isSubMenu = false; // Added
|
||||
mMenu = NULL;
|
||||
mMenuBar = NULL;
|
||||
mPopup = NULL;
|
||||
|
||||
mMenuBar = nullptr;
|
||||
mPopup = nullptr;
|
||||
|
||||
mLastHighlightedMenuIdx = -1;
|
||||
}
|
||||
|
||||
void GuiPopupMenuTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
|
||||
{
|
||||
if (dStrcmp(mList[cell.y].text + 3, "-\t")) // Was: dStrcmp(mList[cell.y].text + 2, "-\t")) but has been changed to take into account the submenu flag
|
||||
Parent::onRenderCell(offset, cell, selected, mouseOver);
|
||||
else
|
||||
//check if we're a real entry, or if it's a divider
|
||||
if (mPopup->mMenuItems[cell.y].isSpacer)
|
||||
{
|
||||
S32 yp = offset.y + mCellSize.y / 2;
|
||||
GFX->getDrawUtil()->drawLine(offset.x, yp, offset.x + mCellSize.x, yp, ColorI(128, 128, 128));
|
||||
GFX->getDrawUtil()->drawLine(offset.x, yp + 1, offset.x + mCellSize.x, yp + 1, ColorI(255, 255, 255));
|
||||
GFX->getDrawUtil()->drawLine(offset.x + 5, yp, offset.x + mCellSize.x - 5, yp, ColorI(128, 128, 128));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dStrcmp(mList[cell.y].text + 3, "-\t")) // Was: dStrcmp(mList[cell.y].text + 2, "-\t")) but has been changed to take into account the submenu flag
|
||||
{
|
||||
Parent::onRenderCell(offset, cell, selected, mouseOver);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 yp = offset.y + mCellSize.y / 2;
|
||||
GFX->getDrawUtil()->drawLine(offset.x, yp, offset.x + mCellSize.x, yp, ColorI(128, 128, 128));
|
||||
GFX->getDrawUtil()->drawLine(offset.x, yp + 1, offset.x + mCellSize.x, yp + 1, ColorI(255, 255, 255));
|
||||
}
|
||||
}
|
||||
|
||||
// now see if there's a bitmap...
|
||||
U8 idx = mList[cell.y].text[0];
|
||||
if (idx != 1)
|
||||
|
|
@ -153,17 +203,12 @@ void GuiPopupMenuTextListCtrl::onMouseUp(const GuiEvent &event)
|
|||
|
||||
if (selectionIndex != -1)
|
||||
{
|
||||
GuiMenuBar::MenuItem *list = mMenu->firstMenuItem;
|
||||
MenuItem *item = &mPopup->mMenuItems[selectionIndex];
|
||||
|
||||
while (selectionIndex && list)
|
||||
if (item)
|
||||
{
|
||||
list = list->nextMenuItem;
|
||||
selectionIndex--;
|
||||
}
|
||||
if (list)
|
||||
{
|
||||
if (list->enabled)
|
||||
dAtob(Con::executef(mPopup, "onSelectItem", Con::getIntArg(getSelectedCell().y), list->text ? list->text : ""));
|
||||
if (item->enabled)
|
||||
dAtob(Con::executef(mPopup, "onSelectItem", Con::getIntArg(getSelectedCell().y), item->text.isNotEmpty() ? item->text : ""));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,4 +226,23 @@ void GuiPopupMenuTextListCtrl::onCellHighlighted(Point2I cell)
|
|||
Point2I globalpoint = localToGlobalCoord(globalbounds.point);
|
||||
globalbounds.point = globalpoint;
|
||||
}
|
||||
|
||||
S32 selectionIndex = cell.y;
|
||||
|
||||
if (selectionIndex != -1 && mLastHighlightedMenuIdx != selectionIndex)
|
||||
{
|
||||
mLastHighlightedMenuIdx = selectionIndex;
|
||||
|
||||
mPopup->hidePopupSubmenus();
|
||||
}
|
||||
|
||||
if (selectionIndex != -1)
|
||||
{
|
||||
MenuItem *list = &mPopup->mMenuItems[selectionIndex];
|
||||
|
||||
if (list->isSubmenu && list->subMenu != nullptr)
|
||||
{
|
||||
list->subMenu->showPopup(getRoot(), getPosition().x + mCellSize.x, getPosition().y + (selectionIndex * mCellSize.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,6 +42,7 @@ class GuiPopupMenuBackgroundCtrl;
|
|||
class GuiPopupMenuTextListCtrl : public GuiTextListCtrl
|
||||
{
|
||||
friend class GuiPopupMenuBackgroundCtrl;
|
||||
friend class PopupMenu;
|
||||
|
||||
private:
|
||||
typedef GuiTextListCtrl Parent;
|
||||
|
|
@ -51,10 +52,12 @@ private:
|
|||
public:
|
||||
bool isSubMenu; // Indicates that this text list is in a submenu
|
||||
Point2I maxBitmapSize;
|
||||
GuiMenuBar::Menu* mMenu;
|
||||
|
||||
GuiMenuBar* mMenuBar;
|
||||
PopupMenu* mPopup;
|
||||
|
||||
S32 mLastHighlightedMenuIdx;
|
||||
|
||||
GuiPopupMenuTextListCtrl();
|
||||
|
||||
// GuiControl overloads:
|
||||
|
|
@ -70,16 +73,21 @@ class GuiPopupMenuBackgroundCtrl : public GuiControl
|
|||
{
|
||||
typedef GuiControl Parent;
|
||||
|
||||
protected:
|
||||
GuiPopupMenuTextListCtrl *mTextList;
|
||||
|
||||
public:
|
||||
GuiPopupMenuBackgroundCtrl(GuiPopupMenuTextListCtrl* textList);
|
||||
GuiPopupMenuBackgroundCtrl();
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
|
||||
void close();
|
||||
|
||||
void clearPopups();
|
||||
|
||||
S32 findPopupMenu(PopupMenu* menu);
|
||||
|
||||
Vector<PopupMenu*> mPopups;
|
||||
GuiMenuBar* mMenuBarCtrl;
|
||||
};
|
||||
|
||||
#endif
|
||||
506
Engine/source/gui/editor/popupMenu.cpp
Normal file
506
Engine/source/gui/editor/popupMenu.cpp
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "gui/editor/popupMenu.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "gui/editor/guiPopupMenuCtrl.h"
|
||||
#include "gui/editor/guiMenuBar.h"
|
||||
|
||||
static U32 sMaxPopupGUID = 0;
|
||||
PopupMenuEvent PopupMenu::smPopupMenuEvent;
|
||||
bool PopupMenu::smSelectionEventHandled = false;
|
||||
|
||||
/// Event class used to remove popup menus from the event notification in a safe way
|
||||
class PopUpNotifyRemoveEvent : public SimEvent
|
||||
{
|
||||
public:
|
||||
void process(SimObject *object)
|
||||
{
|
||||
PopupMenu::smPopupMenuEvent.remove((PopupMenu *)object, &PopupMenu::handleSelectEvent);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor/Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
PopupMenu::PopupMenu()
|
||||
{
|
||||
bitmapIndex = -1;
|
||||
|
||||
barTitle = StringTable->EmptyString();
|
||||
|
||||
mMenuBarCtrl = nullptr;
|
||||
mTextList = nullptr;
|
||||
|
||||
isSubmenu = false;
|
||||
}
|
||||
|
||||
PopupMenu::~PopupMenu()
|
||||
{
|
||||
PopupMenu::smPopupMenuEvent.remove(this, &PopupMenu::handleSelectEvent);
|
||||
}
|
||||
|
||||
IMPLEMENT_CONOBJECT(PopupMenu);
|
||||
|
||||
ConsoleDocClass( PopupMenu,
|
||||
"@brief PopupMenu represents a system menu.\n\n"
|
||||
"You can add menu items to the menu, but there is no torque object associated "
|
||||
"with these menu items, they exist only in a platform specific manner.\n\n"
|
||||
"@note Internal use only\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void PopupMenu::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("barTitle", TypeCaseString, Offset(barTitle, PopupMenu), "");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool PopupMenu::onAdd()
|
||||
{
|
||||
if(! Parent::onAdd())
|
||||
return false;
|
||||
|
||||
Con::executef(this, "onAdd");
|
||||
return true;
|
||||
}
|
||||
|
||||
void PopupMenu::onRemove()
|
||||
{
|
||||
Con::executef(this, "onRemove");
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void PopupMenu::onMenuSelect()
|
||||
{
|
||||
Con::executef(this, "onMenuSelect");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void PopupMenu::handleSelectEvent(U32 popID, U32 command)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool PopupMenu::onMessageReceived(StringTableEntry queue, const char* event, const char* data)
|
||||
{
|
||||
return Con::executef(this, "onMessageReceived", queue, event, data);
|
||||
}
|
||||
|
||||
bool PopupMenu::onMessageObjectReceived(StringTableEntry queue, Message *msg )
|
||||
{
|
||||
return Con::executef(this, "onMessageReceived", queue, Con::getIntArg(msg->getId()));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Platform Menu Data
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
GuiMenuBar* PopupMenu::getMenuBarCtrl()
|
||||
{
|
||||
return mMenuBarCtrl;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Public Methods
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
S32 PopupMenu::insertItem(S32 pos, const char *title, const char* accelerator, const char* cmd)
|
||||
{
|
||||
String titleString = title;
|
||||
|
||||
MenuItem newItem;
|
||||
newItem.id = pos;
|
||||
newItem.text = titleString;
|
||||
newItem.cmd = cmd;
|
||||
|
||||
if (titleString.isEmpty() || titleString == String("-"))
|
||||
newItem.isSpacer = true;
|
||||
else
|
||||
newItem.isSpacer = false;
|
||||
|
||||
if (accelerator[0])
|
||||
newItem.accelerator = dStrdup(accelerator);
|
||||
else
|
||||
newItem.accelerator = NULL;
|
||||
|
||||
newItem.visible = true;
|
||||
newItem.isChecked = false;
|
||||
newItem.acceleratorIndex = 0;
|
||||
newItem.enabled = !newItem.isSpacer;
|
||||
|
||||
newItem.isSubmenu = false;
|
||||
newItem.subMenu = nullptr;
|
||||
newItem.subMenuParentMenu = nullptr;
|
||||
|
||||
mMenuItems.push_back(newItem);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
S32 PopupMenu::insertSubMenu(S32 pos, const char *title, PopupMenu *submenu)
|
||||
{
|
||||
S32 itemPos = insertItem(pos, title, "", "");
|
||||
|
||||
mMenuItems[itemPos].isSubmenu = true;
|
||||
mMenuItems[itemPos].subMenu = submenu;
|
||||
mMenuItems[itemPos].subMenuParentMenu = this;
|
||||
|
||||
submenu->isSubmenu = true;
|
||||
|
||||
return itemPos;
|
||||
}
|
||||
|
||||
bool PopupMenu::setItem(S32 pos, const char *title, const char* accelerator, const char* cmd)
|
||||
{
|
||||
String titleString = title;
|
||||
|
||||
for (U32 i = 0; i < mMenuItems.size(); i++)
|
||||
{
|
||||
if (mMenuItems[i].text == titleString)
|
||||
{
|
||||
mMenuItems[i].id = pos;
|
||||
mMenuItems[i].cmd = cmd;
|
||||
|
||||
if (accelerator && accelerator[0])
|
||||
mMenuItems[i].accelerator = dStrdup(accelerator);
|
||||
else
|
||||
mMenuItems[i].accelerator = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PopupMenu::removeItem(S32 itemPos)
|
||||
{
|
||||
if (mMenuItems.size() < itemPos || itemPos < 0)
|
||||
return;
|
||||
|
||||
mMenuItems.erase(itemPos);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void PopupMenu::enableItem(S32 pos, bool enable)
|
||||
{
|
||||
if (mMenuItems.size() < pos || pos < 0)
|
||||
return;
|
||||
|
||||
mMenuItems[pos].enabled = enable;
|
||||
}
|
||||
|
||||
void PopupMenu::checkItem(S32 pos, bool checked)
|
||||
{
|
||||
if (mMenuItems.size() < pos || pos < 0)
|
||||
return;
|
||||
|
||||
if (checked && mMenuItems[pos].checkGroup != -1)
|
||||
{
|
||||
// first, uncheck everything in the group:
|
||||
for (U32 i = 0; i < mMenuItems.size(); i++)
|
||||
if (mMenuItems[i].checkGroup == mMenuItems[pos].checkGroup && mMenuItems[i].isChecked)
|
||||
mMenuItems[i].isChecked = false;
|
||||
}
|
||||
|
||||
mMenuItems[pos].isChecked;
|
||||
}
|
||||
|
||||
void PopupMenu::checkRadioItem(S32 firstPos, S32 lastPos, S32 checkPos)
|
||||
{
|
||||
for (U32 i = 0; i < mMenuItems.size(); i++)
|
||||
{
|
||||
if (mMenuItems[i].id >= firstPos && mMenuItems[i].id <= lastPos)
|
||||
{
|
||||
mMenuItems[i].isChecked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PopupMenu::isItemChecked(S32 pos)
|
||||
{
|
||||
if (mMenuItems.size() < pos || pos < 0)
|
||||
return false;
|
||||
|
||||
return mMenuItems[pos].isChecked;
|
||||
}
|
||||
|
||||
U32 PopupMenu::getItemCount()
|
||||
{
|
||||
return mMenuItems.size();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool PopupMenu::canHandleID(U32 id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PopupMenu::handleSelect(U32 command, const char *text /* = NULL */)
|
||||
{
|
||||
return dAtob(Con::executef(this, "onSelectItem", Con::getIntArg(command), text ? text : ""));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void PopupMenu::showPopup(GuiCanvas *owner, S32 x /* = -1 */, S32 y /* = -1 */)
|
||||
{
|
||||
if (owner == NULL)
|
||||
return;
|
||||
|
||||
GuiControl* editorGui;
|
||||
Sim::findObject("EditorGui", editorGui);
|
||||
|
||||
if (editorGui)
|
||||
{
|
||||
GuiPopupMenuBackgroundCtrl* backgroundCtrl;
|
||||
Sim::findObject("PopUpMenuControl", backgroundCtrl);
|
||||
|
||||
GuiControlProfile* profile;
|
||||
Sim::findObject("GuiMenubarProfile", profile);
|
||||
|
||||
if (!profile)
|
||||
return;
|
||||
|
||||
if (mTextList == nullptr)
|
||||
{
|
||||
mTextList = new GuiPopupMenuTextListCtrl();
|
||||
mTextList->registerObject();
|
||||
mTextList->setControlProfile(profile);
|
||||
|
||||
mTextList->mPopup = this;
|
||||
mTextList->mMenuBar = getMenuBarCtrl();
|
||||
}
|
||||
|
||||
if (!backgroundCtrl)
|
||||
{
|
||||
backgroundCtrl = new GuiPopupMenuBackgroundCtrl();
|
||||
|
||||
backgroundCtrl->registerObject("PopUpMenuControl");
|
||||
}
|
||||
|
||||
if (!backgroundCtrl || !mTextList)
|
||||
return;
|
||||
|
||||
if (!isSubmenu)
|
||||
{
|
||||
//if we're a 'parent' menu, then tell the background to clear out all existing other popups
|
||||
|
||||
backgroundCtrl->clearPopups();
|
||||
}
|
||||
|
||||
//find out if we're doing a first-time add
|
||||
S32 popupIndex = backgroundCtrl->findPopupMenu(this);
|
||||
|
||||
if (popupIndex == -1)
|
||||
{
|
||||
backgroundCtrl->addObject(mTextList);
|
||||
backgroundCtrl->mPopups.push_back(this);
|
||||
}
|
||||
|
||||
mTextList->mBackground = backgroundCtrl;
|
||||
|
||||
owner->pushDialogControl(backgroundCtrl, 10);
|
||||
|
||||
//Set the background control's menubar, if any, and if it's not already set
|
||||
if(backgroundCtrl->mMenuBarCtrl == nullptr)
|
||||
backgroundCtrl->mMenuBarCtrl = getMenuBarCtrl();
|
||||
|
||||
backgroundCtrl->setExtent(editorGui->getExtent());
|
||||
|
||||
mTextList->clear();
|
||||
|
||||
S32 textWidth = 0, width = 0;
|
||||
S32 acceleratorWidth = 0;
|
||||
GFont *font = profile->mFont;
|
||||
|
||||
Point2I maxBitmapSize = Point2I(0, 0);
|
||||
|
||||
S32 numBitmaps = profile->mBitmapArrayRects.size();
|
||||
if (numBitmaps)
|
||||
{
|
||||
RectI *bitmapBounds = profile->mBitmapArrayRects.address();
|
||||
for (S32 i = 0; i < numBitmaps; i++)
|
||||
{
|
||||
if (bitmapBounds[i].extent.x > maxBitmapSize.x)
|
||||
maxBitmapSize.x = bitmapBounds[i].extent.x;
|
||||
if (bitmapBounds[i].extent.y > maxBitmapSize.y)
|
||||
maxBitmapSize.y = bitmapBounds[i].extent.y;
|
||||
}
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mMenuItems.size(); i++)
|
||||
{
|
||||
if (!mMenuItems[i].visible)
|
||||
continue;
|
||||
|
||||
S32 iTextWidth = font->getStrWidth(mMenuItems[i].text.c_str());
|
||||
S32 iAcceleratorWidth = mMenuItems[i].accelerator ? font->getStrWidth(mMenuItems[i].accelerator) : 0;
|
||||
|
||||
if (iTextWidth > textWidth)
|
||||
textWidth = iTextWidth;
|
||||
if (iAcceleratorWidth > acceleratorWidth)
|
||||
acceleratorWidth = iAcceleratorWidth;
|
||||
}
|
||||
|
||||
width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4;
|
||||
|
||||
mTextList->setCellSize(Point2I(width, font->getHeight() + 2));
|
||||
mTextList->clearColumnOffsets();
|
||||
mTextList->addColumnOffset(-1); // add an empty column in for the bitmap index.
|
||||
mTextList->addColumnOffset(maxBitmapSize.x + 1);
|
||||
mTextList->addColumnOffset(maxBitmapSize.x + 1 + textWidth + 4);
|
||||
|
||||
U32 entryCount = 0;
|
||||
|
||||
for (U32 i = 0; i < mMenuItems.size(); i++)
|
||||
{
|
||||
if (!mMenuItems[i].visible)
|
||||
continue;
|
||||
|
||||
char buf[512];
|
||||
|
||||
// If this menu item is a submenu, then set the isSubmenu to 2 to indicate
|
||||
// an arrow should be drawn. Otherwise set the isSubmenu normally.
|
||||
char isSubmenu = 1;
|
||||
if (mMenuItems[i].isSubmenu)
|
||||
isSubmenu = 2;
|
||||
|
||||
char bitmapIndex = 1;
|
||||
if (mMenuItems[i].bitmapIndex >= 0 && (mMenuItems[i].bitmapIndex * 3 <= profile->mBitmapArrayRects.size()))
|
||||
bitmapIndex = mMenuItems[i].bitmapIndex + 2;
|
||||
|
||||
dSprintf(buf, sizeof(buf), "%c%c\t%s\t%s", bitmapIndex, isSubmenu, mMenuItems[i].text.c_str(), mMenuItems[i].accelerator ? mMenuItems[i].accelerator : "");
|
||||
mTextList->addEntry(entryCount, buf);
|
||||
|
||||
if (!mMenuItems[i].enabled)
|
||||
mTextList->setEntryActive(entryCount, false);
|
||||
|
||||
entryCount++;
|
||||
}
|
||||
|
||||
Point2I pos = Point2I::Zero;
|
||||
|
||||
if (x == -1 && y == -1)
|
||||
pos = owner->getCursorPos();
|
||||
else
|
||||
pos = Point2I(x, y);
|
||||
|
||||
mTextList->setPosition(pos);
|
||||
|
||||
//nudge in if we'd overshoot the screen
|
||||
S32 widthDiff = (mTextList->getPosition().x + mTextList->getExtent().x) - backgroundCtrl->getWidth();
|
||||
if (widthDiff > 0)
|
||||
{
|
||||
Point2I popupPos = mTextList->getPosition();
|
||||
mTextList->setPosition(popupPos.x - widthDiff, popupPos.y);
|
||||
}
|
||||
|
||||
mTextList->setHidden(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PopupMenu::hidePopup()
|
||||
{
|
||||
if (mTextList)
|
||||
{
|
||||
mTextList->setHidden(true);
|
||||
}
|
||||
|
||||
hidePopupSubmenus();
|
||||
}
|
||||
|
||||
void PopupMenu::hidePopupSubmenus()
|
||||
{
|
||||
for (U32 i = 0; i < mMenuItems.size(); i++)
|
||||
{
|
||||
if (mMenuItems[i].subMenu != nullptr)
|
||||
mMenuItems[i].subMenu->hidePopup();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
DefineConsoleMethod(PopupMenu, insertItem, S32, (S32 pos, const char * title, const char * accelerator, const char* cmd), ("", "", ""), "(pos[, title][, accelerator][, cmd])")
|
||||
{
|
||||
return object->insertItem(pos, title, accelerator, cmd);
|
||||
}
|
||||
|
||||
DefineConsoleMethod(PopupMenu, removeItem, void, (S32 pos), , "(pos)")
|
||||
{
|
||||
object->removeItem(pos);
|
||||
}
|
||||
|
||||
DefineConsoleMethod(PopupMenu, insertSubMenu, S32, (S32 pos, String title, String subMenu), , "(pos, title, subMenu)")
|
||||
{
|
||||
PopupMenu *mnu = dynamic_cast<PopupMenu *>(Sim::findObject(subMenu));
|
||||
if(mnu == NULL)
|
||||
{
|
||||
Con::errorf("PopupMenu::insertSubMenu - Invalid PopupMenu object specified for submenu");
|
||||
return -1;
|
||||
}
|
||||
return object->insertSubMenu(pos, title, mnu);
|
||||
}
|
||||
|
||||
DefineConsoleMethod(PopupMenu, setItem, bool, (S32 pos, const char * title, const char * accelerator, const char *cmd), (""), "(pos, title[, accelerator][, cmd])")
|
||||
{
|
||||
return object->setItem(pos, title, accelerator, cmd);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DefineConsoleMethod(PopupMenu, enableItem, void, (S32 pos, bool enabled), , "(pos, enabled)")
|
||||
{
|
||||
object->enableItem(pos, enabled);
|
||||
}
|
||||
|
||||
DefineConsoleMethod(PopupMenu, checkItem, void, (S32 pos, bool checked), , "(pos, checked)")
|
||||
{
|
||||
object->checkItem(pos, checked);
|
||||
}
|
||||
|
||||
DefineConsoleMethod(PopupMenu, checkRadioItem, void, (S32 firstPos, S32 lastPos, S32 checkPos), , "(firstPos, lastPos, checkPos)")
|
||||
{
|
||||
object->checkRadioItem(firstPos, lastPos, checkPos);
|
||||
}
|
||||
|
||||
DefineConsoleMethod(PopupMenu, isItemChecked, bool, (S32 pos), , "(pos)")
|
||||
{
|
||||
return object->isItemChecked(pos);
|
||||
}
|
||||
|
||||
DefineConsoleMethod(PopupMenu, getItemCount, S32, (), , "()")
|
||||
{
|
||||
return object->getItemCount();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
DefineConsoleMethod(PopupMenu, showPopup, void, (const char * canvasName, S32 x, S32 y), ( -1, -1), "(Canvas,[x, y])")
|
||||
{
|
||||
GuiCanvas *pCanvas = dynamic_cast<GuiCanvas*>(Sim::findObject(canvasName));
|
||||
object->showPopup(pCanvas, x, y);
|
||||
}
|
||||
184
Engine/source/gui/editor/popupMenu.h
Normal file
184
Engine/source/gui/editor/popupMenu.h
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _POPUPMENU_H_
|
||||
#define _POPUPMENU_H_
|
||||
|
||||
#include "console/simBase.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "util/messaging/dispatcher.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
|
||||
class PopupMenu;
|
||||
class GuiMenuBar;
|
||||
class GuiPopupMenuTextListCtrl;
|
||||
class GuiPopupMenuBackgroundCtrl;
|
||||
|
||||
struct MenuItem // an individual item in a pull-down menu
|
||||
{
|
||||
String text; // the text of the menu item
|
||||
U32 id; // a script-assigned identifier
|
||||
char *accelerator; // the keyboard accelerator shortcut for the menu item
|
||||
U32 acceleratorIndex; // index of this accelerator
|
||||
bool enabled; // true if the menu item is selectable
|
||||
bool visible; // true if the menu item is visible
|
||||
S32 bitmapIndex; // index of the bitmap in the bitmap array
|
||||
S32 checkGroup; // the group index of the item visa vi check marks -
|
||||
// only one item in the group can be checked.
|
||||
|
||||
bool isSubmenu; // This menu item has a submenu that will be displayed
|
||||
|
||||
bool isChecked;
|
||||
|
||||
bool isSpacer;
|
||||
|
||||
bool isMenubarEntry;
|
||||
|
||||
PopupMenu* subMenuParentMenu; // For a submenu, this is the parent menu
|
||||
PopupMenu* subMenu;
|
||||
String cmd;
|
||||
};
|
||||
|
||||
// PopupMenu represents a menu.
|
||||
// You can add menu items to the menu, but there is no torque object associated
|
||||
// with these menu items, they exist only in a platform specific manner.
|
||||
class PopupMenu : public SimObject, public virtual Dispatcher::IMessageListener
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
friend class GuiMenuBar;
|
||||
friend class GuiPopupMenuTextListCtrl;
|
||||
friend class GuiPopupMenuBackgroundCtrl;
|
||||
|
||||
protected:
|
||||
Vector<MenuItem> mMenuItems;
|
||||
|
||||
GuiMenuBar* mMenuBarCtrl;
|
||||
|
||||
StringTableEntry barTitle;
|
||||
|
||||
RectI bounds;
|
||||
bool visible;
|
||||
|
||||
S32 bitmapIndex; // Index of the bitmap in the bitmap array (-1 = no bitmap)
|
||||
bool drawBitmapOnly; // Draw only the bitmap and not the text
|
||||
bool drawBorder; // Should a border be drawn around this menu (usually if we only have a bitmap, we don't want a border)
|
||||
|
||||
bool isSubmenu;
|
||||
|
||||
//This is the gui control that renders our popup
|
||||
GuiPopupMenuTextListCtrl *mTextList;
|
||||
|
||||
public:
|
||||
PopupMenu();
|
||||
virtual ~PopupMenu();
|
||||
|
||||
DECLARE_CONOBJECT(PopupMenu);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
|
||||
static PopupMenuEvent smPopupMenuEvent;
|
||||
static bool smSelectionEventHandled; /// Set to true if any menu or submenu handles a selection event
|
||||
|
||||
/// pass NULL for @p title to insert a separator
|
||||
/// returns the menu item's ID, or -1 on failure.
|
||||
/// implementd on a per-platform basis.
|
||||
/// TODO: factor out common code
|
||||
S32 insertItem(S32 pos, const char *title, const char* accelerator, const char* cmd);
|
||||
|
||||
/// Sets the name title and accelerator for
|
||||
/// an existing item.
|
||||
bool setItem(S32 pos, const char *title, const char* accelerator, const char* cmd);
|
||||
|
||||
/// pass NULL for @p title to insert a separator
|
||||
/// returns the menu item's ID, or -1 on failure.
|
||||
/// adds the submenu to the mSubmenus vector.
|
||||
/// implemented on a per-platform basis.
|
||||
/// TODO: factor out common code
|
||||
S32 insertSubMenu(S32 pos, const char *title, PopupMenu *submenu);
|
||||
|
||||
/// remove the menu item at @p itemPos
|
||||
/// if the item has a submenu, it is removed from the mSubmenus list.
|
||||
/// implemented on a per-platform basis.
|
||||
/// TODO: factor out common code
|
||||
void removeItem(S32 itemPos);
|
||||
|
||||
/// implemented on a per-platform basis.
|
||||
void enableItem(S32 pos, bool enable);
|
||||
/// implemented on a per-platform basis.
|
||||
void checkItem(S32 pos, bool checked);
|
||||
|
||||
/// All items at positions firstPos through lastPos are unchecked, and the
|
||||
/// item at checkPos is checked.
|
||||
/// implemented on a per-platform basis.
|
||||
void checkRadioItem(S32 firstPos, S32 lastPos, S32 checkPos);
|
||||
bool isItemChecked(S32 pos);
|
||||
|
||||
/// Returns the number of items in the menu.
|
||||
U32 getItemCount();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Displays this menu as a popup menu and blocks until the user has selected
|
||||
/// an item.
|
||||
/// @param canvas the owner to show this popup associated with
|
||||
/// @param x window local x coordinate at which to display the popup menu
|
||||
/// @param y window local y coordinate at which to display the popup menu
|
||||
/// implemented on a per-platform basis.
|
||||
void showPopup(GuiCanvas *owner, S32 x = -1, S32 y = -1);
|
||||
|
||||
void hidePopup();
|
||||
void hidePopupSubmenus();
|
||||
|
||||
/// Returns true iff this menu contains an item that matches @p iD.
|
||||
/// implemented on a per-platform basis.
|
||||
/// TODO: factor out common code
|
||||
bool canHandleID(U32 iD);
|
||||
|
||||
/// A menu item in this menu has been selected by id.
|
||||
/// Submenus are given a chance to respond to the command first.
|
||||
/// If no submenu can handle the command id, this menu handles it.
|
||||
/// The script callback this::onSelectItem( position, text) is called.
|
||||
/// If @p text is null, then the text arg passed to script is the text of
|
||||
/// the selected menu item.
|
||||
/// implemented on a per-platform basis.
|
||||
/// TODO: factor out common code
|
||||
bool handleSelect(U32 command, const char *text = NULL);
|
||||
|
||||
void onMenuSelect();
|
||||
|
||||
/// Helper function to allow menu selections from signal events.
|
||||
/// Wraps canHandleID() and handleSelect() in one function
|
||||
/// without changing their internal functionality, so
|
||||
/// it should work regardless of platform.
|
||||
void handleSelectEvent(U32 popID, U32 command);
|
||||
|
||||
virtual bool onMessageReceived(StringTableEntry queue, const char* event, const char* data );
|
||||
virtual bool onMessageObjectReceived(StringTableEntry queue, Message *msg );
|
||||
|
||||
bool isVisible() { return visible; }
|
||||
void setVisible(bool isVis) { visible = isVis; }
|
||||
|
||||
GuiMenuBar* getMenuBarCtrl();
|
||||
};
|
||||
|
||||
#endif // _POPUPMENU_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue