2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// 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 "platform/platform.h"
# include "gui/editor/guiMenuBar.h"
# include "console/consoleTypes.h"
# include "console/console.h"
# include "gui/core/guiCanvas.h"
# include "gui/core/guiDefaultControlRender.h"
# include "gui/controls/guiTextListCtrl.h"
# include "sim/actionMap.h"
# include "gfx/gfxDevice.h"
# include "gfx/gfxDrawUtil.h"
# include "gfx/primBuilder.h"
# include "console/engineAPI.h"
2019-03-16 07:38:40 +00:00
# include "gui/editor/guiPopupMenuCtrl.h"
2025-03-09 16:53:23 +00:00
# include "console/typeValidators.h"
2012-09-19 15:15:01 +00:00
// menu bar:
// basic idea - fixed height control bar at the top of a window, placed and sized in gui editor
// menu text for menus or menu items should not begin with a digit
// all menus can be removed via the clearMenus() console command
// each menu is added via the addMenu(menuText, menuId) console command
// each menu is added with a menu id
// menu items are added to menus via that addMenuItem(menu, menuItemText, menuItemId, accelerator, checkGroup) console command
// each menu item is added with a menu item id and an optional accelerator
// menu items are initially enabled, but can be disabled/re-enabled via the setMenuItemEnable(menu,menuItem,bool)
// menu text can be set via the setMenuText(menu, newMenuText) console method
// menu item text can be set via the setMenuItemText console method
// menu items can be removed via the removeMenuItem(menu, menuItem) console command
// menu items can be cleared via the clearMenuItems(menu) console command
// menus can be hidden or shown via the setMenuVisible(menu, bool) console command
// menu items can be hidden or shown via the setMenuItemVisible(menu, menuItem, bool) console command
// menu items can be check'd via the setMenuItemChecked(menu, menuItem, bool) console command
// if the bool is true, any other items in that menu item's check group become unchecked.
//
// menu items can have a bitmap set on them via the setMenuItemBitmap(menu, menuItem, bitmapIndex)
// passing -1 for the bitmap index will result in no bitmap being shown
// the index paramater is an index into the bitmap array of the associated profile
// this can be used, for example, to display a check next to a selected menu item
// bitmap indices are actually multiplied by 3 when indexing into the bitmap
// since bitmaps have normal, selected and disabled states.
//
// menus can be removed via the removeMenu console command
// specification arguments for menus and menu items can be either the id or the text of the menu or menu item
// adding the menu item "-" will add an un-selectable seperator to the menu
// callbacks:
// when a menu is clicked, before it is displayed, the menu calls its onMenuSelect(menuId, menuText) method -
// this allows the callback to enable/disable menu items, or add menu items in a context-sensitive way
// when a menu item is clicked, the menu removes itself from display, then calls onMenuItemSelect(menuId, menuText, menuItemId, menuItemText)
// the initial implementation does not support:
// hierarchal menus
// keyboard accelerators on menu text (i.e. via alt-key combos)
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT ( GuiMenuBar ) ;
ConsoleDocClass ( GuiMenuBar ,
" @brief GUI Control which displays a horizontal bar with individual drop-down menu items. Each menu item may also have submenu items. \n \n "
" @tsexample \n "
" new GuiMenuBar(newMenuBar) \n "
" { \n "
2017-01-07 04:10:14 +00:00
" Padding = \" 0 \" ; \n "
" //Properties not specific to this control have been omitted from this example. \n "
2012-09-19 15:15:01 +00:00
" }; \n \n "
" // Add a menu to the menu bar \n "
" newMenuBar.addMenu(0, \" New Menu \" ); \n \n "
" // Add a menu item to the New Menu \n "
" newMenuBar.addMenuItem(0, \" New Menu Item \" ,0, \" n \" ,-1); \n \n "
" // Add a submenu item to the New Menu Item \n "
" newMenuBar.addSubmenuItem(0,1, \" New Submenu Item \" ,0, \" s \" ,-1); \n "
" @endtsexample \n \n "
" @see GuiTickCtrl \n \n "
" @ingroup GuiCore \n "
) ;
IMPLEMENT_CALLBACK ( GuiMenuBar , onMouseInMenu , void , ( bool isInMenu ) , ( isInMenu ) ,
" @brief Called whenever the mouse enters, or persists is in the menu. \n \n "
" @param isInMenu True if the mouse has entered the menu, otherwise is false. \n "
" @note To receive this callback, call setProcessTicks(true) on the menu bar. \n "
" @tsexample \n "
" // Mouse enters or persists within the menu, causing the callback to occur. \n "
" GuiMenuBar::onMouseInMenu(%this,%hasLeftMenu) \n "
" { \n "
2017-01-07 04:10:14 +00:00
" // Code to run when the callback occurs \n "
2012-09-19 15:15:01 +00:00
" } \n "
" @endtsexample \n \n "
" @see GuiTickCtrl \n \n "
) ;
2015-02-07 22:41:54 +00:00
IMPLEMENT_CALLBACK ( GuiMenuBar , onMenuSelect , void , ( S32 menuId , const char * menuText ) , ( menuId , menuText ) ,
2012-09-19 15:15:01 +00:00
" @brief Called whenever a menu is selected. \n \n "
" @param menuId Index id of the clicked menu \n "
" @param menuText Text of the clicked menu \n \n "
" @tsexample \n "
" // A menu has been selected, causing the callback to occur. \n "
" GuiMenuBar::onMenuSelect(%this,%menuId,%menuText) \n "
" { \n "
2017-01-07 04:10:14 +00:00
" // Code to run when the callback occurs \n "
2012-09-19 15:15:01 +00:00
" } \n "
" @endtsexample \n \n "
" @see GuiTickCtrl \n \n "
) ;
2015-02-07 22:41:54 +00:00
IMPLEMENT_CALLBACK ( GuiMenuBar , onMenuItemSelect , void , ( S32 menuId , const char * menuText , S32 menuItemId , const char * menuItemText ) ,
2017-01-07 04:10:14 +00:00
( menuId , menuText , menuItemId , menuItemText ) ,
2012-09-19 15:15:01 +00:00
" @brief Called whenever an item in a menu is selected. \n \n "
" @param menuId Index id of the menu which contains the selected menu item \n "
" @param menuText Text of the menu which contains the selected menu item \n \n "
" @param menuItemId Index id of the selected menu item \n "
" @param menuItemText Text of the selected menu item \n \n "
" @tsexample \n "
" // A menu item has been selected, causing the callback to occur. \n "
" GuiMenuBar::onMenuItemSelect(%this,%menuId,%menuText,%menuItemId,%menuItemText) \n "
" { \n "
2017-01-07 04:10:14 +00:00
" // Code to run when the callback occurs \n "
2012-09-19 15:15:01 +00:00
" } \n "
" @endtsexample \n \n "
" @see GuiTickCtrl \n \n "
) ;
//------------------------------------------------------------------------------
// initialization, input and render methods
//------------------------------------------------------------------------------
GuiMenuBar : : GuiMenuBar ( )
{
2017-11-11 07:21:48 +00:00
//mMenuList.clear();
2012-09-19 15:15:01 +00:00
menuBarDirty = true ;
mouseDownMenu = NULL ;
mouseOverMenu = NULL ;
mCurAcceleratorIndex = 0 ;
mPadding = 0 ;
mCheckmarkBitmapIndex = 0 ; // Default to the first image in the bitmap array for the check mark
mHorizontalMargin = 6 ; // Default number of pixels on the left and right side of a manu's text
mVerticalMargin = 1 ; // Default number of pixels on the top and bottom of a menu's text
mBitmapMargin = 2 ; // Default number of pixels between a menu's bitmap and text
2023-09-05 03:50:45 +00:00
mMenubarHeight = 24 ;
2017-11-11 07:21:48 +00:00
2012-09-19 15:15:01 +00:00
// Added:
mouseDownSubmenu = NULL ;
mouseOverSubmenu = NULL ;
2017-11-11 07:21:48 +00:00
mMouseInMenu = false ;
2012-09-19 15:15:01 +00:00
setProcessTicks ( false ) ;
}
2017-11-11 07:21:48 +00:00
void GuiMenuBar : : onRemove ( )
{
2019-03-16 07:38:40 +00:00
GuiPopupMenuBackgroundCtrl * backgroundCtrl ;
if ( Sim : : findObject ( " PopUpMenuControl " , backgroundCtrl ) )
{
if ( backgroundCtrl - > mMenuBarCtrl = = this )
backgroundCtrl - > mMenuBarCtrl = nullptr ;
}
2017-11-11 07:21:48 +00:00
Parent : : onRemove ( ) ;
}
2012-09-19 15:15:01 +00:00
void GuiMenuBar : : initPersistFields ( )
{
2023-01-27 07:13:15 +00:00
docsURL ;
2025-03-09 16:53:23 +00:00
addFieldV ( " padding " , TypeRangedS32 , Offset ( mPadding , GuiMenuBar ) , & CommonValidators : : PositiveInt , " Extra padding to add to the bounds of the control. \n " ) ;
2012-09-19 15:15:01 +00:00
2025-03-09 16:53:23 +00:00
addFieldV ( " menubarHeight " , TypeRangedS32 , Offset ( mMenubarHeight , GuiMenuBar ) , & CommonValidators : : PositiveInt , " Sets the height of the menubar when attached to the canvas. \n " ) ;
2017-11-11 07:21:48 +00:00
2012-09-19 15:15:01 +00:00
Parent : : initPersistFields ( ) ;
}
bool GuiMenuBar : : onWake ( )
{
if ( ! Parent : : onWake ( ) )
return false ;
mProfile - > constructBitmapArray ( ) ; // if a bitmap was specified...
maxBitmapSize . set ( 0 , 0 ) ;
S32 numBitmaps = mProfile - > mBitmapArrayRects . size ( ) ;
if ( numBitmaps )
{
RectI * bitmapBounds = mProfile - > 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 ;
}
}
return true ;
}
2017-11-11 07:21:48 +00:00
void GuiMenuBar : : addObject ( SimObject * object )
{
PopupMenu * popup = dynamic_cast < PopupMenu * > ( object ) ;
if ( ! popup )
{
//if it's not a popup, handle it normally
Parent : : addObject ( object ) ;
}
else
{
//otherwise, if it IS a popup, don't add it as a child object, but instead just insert it as a menu entry
insert ( object , - 1 ) ;
}
}
GuiMenuBar : : MenuEntry * GuiMenuBar : : findHitMenu ( Point2I mousePoint )
2012-09-19 15:15:01 +00:00
{
Point2I pos = globalToLocalCoord ( mousePoint ) ;
2015-08-05 03:57:25 +00:00
for ( U32 i = 0 ; i < mMenuList . size ( ) ; + + i )
2017-11-11 07:21:48 +00:00
{
if ( mMenuList [ i ] . visible & & mMenuList [ i ] . bounds . pointInRect ( pos ) )
return & mMenuList [ i ] ;
}
2012-09-19 15:15:01 +00:00
return NULL ;
}
void GuiMenuBar : : onPreRender ( )
{
2017-11-11 07:21:48 +00:00
setHeight ( mMenubarHeight ) ;
2012-09-19 15:15:01 +00:00
Parent : : onPreRender ( ) ;
2017-11-11 07:21:48 +00:00
if ( menuBarDirty )
2012-09-19 15:15:01 +00:00
{
menuBarDirty = false ;
U32 curX = mPadding ;
2015-08-05 03:57:25 +00:00
for ( U32 i = 0 ; i < mMenuList . size ( ) ; + + i )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
if ( ! mMenuList [ i ] . visible )
2012-09-19 15:15:01 +00:00
continue ;
2017-11-11 07:21:48 +00:00
// Bounds depends on if there is a bitmap to be drawn or not
if ( mMenuList [ i ] . bitmapIndex = = - 1 )
{
2012-09-19 15:15:01 +00:00
// Text only
2017-11-11 07:21:48 +00:00
mMenuList [ i ] . bounds . set ( curX , 0 , mProfile - > mFont - > getStrWidth ( mMenuList [ i ] . text ) + ( mHorizontalMargin * 2 ) , getHeight ( ) - ( mVerticalMargin * 2 ) ) ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
}
else
2017-01-07 04:10:14 +00:00
{
2017-11-11 07:21:48 +00:00
// Will the bitmap and text be draw?
if ( ! mMenuList [ i ] . drawBitmapOnly )
{
2012-09-19 15:15:01 +00:00
// Draw the bitmap and the text
RectI * bitmapBounds = mProfile - > mBitmapArrayRects . address ( ) ;
2017-11-11 07:21:48 +00:00
mMenuList [ i ] . bounds . set ( curX , 0 , bitmapBounds [ mMenuList [ i ] . bitmapIndex ] . extent . x + mProfile - > mFont - > getStrWidth ( mMenuList [ i ] . text ) + ( mHorizontalMargin * 2 ) , getHeight ( ) + ( mVerticalMargin * 2 ) ) ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
}
else
{
2012-09-19 15:15:01 +00:00
// Only the bitmap will be drawn
RectI * bitmapBounds = mProfile - > mBitmapArrayRects . address ( ) ;
2017-11-11 07:21:48 +00:00
mMenuList [ i ] . bounds . set ( curX , 0 , bitmapBounds [ mMenuList [ i ] . bitmapIndex ] . extent . x + mBitmapMargin + ( mHorizontalMargin * 2 ) , getHeight ( ) + ( mVerticalMargin * 2 ) ) ;
}
2017-01-07 04:10:14 +00:00
}
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
curX + = mMenuList [ i ] . bounds . extent . x ;
2012-09-19 15:15:01 +00:00
}
2017-01-07 04:10:14 +00:00
mouseOverMenu = NULL ;
mouseDownMenu = NULL ;
2012-09-19 15:15:01 +00:00
}
}
void GuiMenuBar : : checkMenuMouseMove ( const GuiEvent & event )
{
2017-11-11 07:21:48 +00:00
MenuEntry * hit = findHitMenu ( event . mousePoint ) ;
2012-09-19 15:15:01 +00:00
if ( hit & & hit ! = mouseDownMenu )
{
// gotta close out the current menu...
2017-11-11 07:21:48 +00:00
mouseDownMenu - > popupMenu - > hidePopup ( ) ;
2012-09-19 15:15:01 +00:00
mouseOverMenu = mouseDownMenu = hit ;
setUpdate ( ) ;
onAction ( ) ;
}
}
void GuiMenuBar : : onMouseMove ( const GuiEvent & event )
{
2017-11-11 07:21:48 +00:00
MenuEntry * hit = findHitMenu ( event . mousePoint ) ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
if ( mouseDownMenu ! = nullptr & & hit ! = nullptr )
{
//we have a standing click, so just update and go
mouseDownMenu = mouseOverMenu = hit ;
2017-01-07 04:10:14 +00:00
setUpdate ( ) ;
2017-11-11 07:21:48 +00:00
onAction ( ) ;
return ;
2017-01-07 04:10:14 +00:00
}
2017-11-11 07:21:48 +00:00
mouseOverMenu = hit ;
setUpdate ( ) ;
}
void GuiMenuBar : : onMouseEnter ( const GuiEvent & event )
{
onMouseInMenu_callback ( true ) ;
mMouseInMenu = true ;
2012-09-19 15:15:01 +00:00
}
void GuiMenuBar : : onMouseLeave ( const GuiEvent & event )
{
if ( mouseOverMenu )
2017-01-07 04:10:14 +00:00
setUpdate ( ) ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
mouseOverMenu = NULL ;
mMouseInMenu = false ;
2012-09-19 15:15:01 +00:00
}
void GuiMenuBar : : onMouseDragged ( const GuiEvent & event )
{
}
void GuiMenuBar : : onMouseDown ( const GuiEvent & event )
{
}
void GuiMenuBar : : onMouseUp ( const GuiEvent & event )
{
2017-11-11 07:21:48 +00:00
mouseDownMenu = mouseOverMenu = findHitMenu ( event . mousePoint ) ;
2017-01-07 04:10:14 +00:00
setUpdate ( ) ;
2017-11-11 07:21:48 +00:00
onAction ( ) ;
2012-09-19 15:15:01 +00:00
}
void GuiMenuBar : : onRender ( Point2I offset , const RectI & updateRect )
{
2017-11-11 07:21:48 +00:00
Point2I extent = getExtent ( ) ;
RectI ctrlRect ( offset , extent ) ;
2012-09-19 15:15:01 +00:00
2015-07-14 03:51:17 +00:00
GFXDrawUtil * drawUtil = GFX - > getDrawUtil ( ) ;
2012-09-19 15:15:01 +00:00
//if opaque, fill the update rect with the fill color
if ( mProfile - > mOpaque )
2017-11-11 07:21:48 +00:00
drawUtil - > drawRectFill ( RectI ( offset , extent ) , mProfile - > mFillColor ) ;
2012-09-19 15:15:01 +00:00
//if there's a border, draw the border
if ( mProfile - > mBorder )
renderBorder ( ctrlRect , mProfile ) ;
2015-08-05 03:57:25 +00:00
for ( U32 i = 0 ; i < mMenuList . size ( ) ; + + i )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
if ( ! mMenuList [ i ] . visible )
2012-09-19 15:15:01 +00:00
continue ;
2017-11-11 07:21:48 +00:00
2012-09-19 15:15:01 +00:00
ColorI fontColor = mProfile - > mFontColor ;
2017-11-11 07:21:48 +00:00
RectI bounds = mMenuList [ i ] . bounds ;
2012-09-19 15:15:01 +00:00
bounds . point + = offset ;
2017-11-11 07:21:48 +00:00
2012-09-19 15:15:01 +00:00
Point2I start ;
2017-11-11 07:21:48 +00:00
start . x = mMenuList [ i ] . bounds . point . x + mHorizontalMargin ;
start . y = mMenuList [ i ] . bounds . point . y + ( mMenuList [ i ] . bounds . extent . y - mProfile - > mFont - > getHeight ( ) ) / 2 ;
// Draw the border
if ( mMenuList [ i ] . drawBorder )
{
RectI highlightBounds = bounds ;
highlightBounds . inset ( 1 , 1 ) ;
if ( & mMenuList [ i ] = = mouseDownMenu )
renderFilledBorder ( highlightBounds , mProfile - > mBorderColorHL , mProfile - > mFillColorHL ) ;
else if ( & mMenuList [ i ] = = mouseOverMenu & & mouseDownMenu = = NULL )
renderFilledBorder ( highlightBounds , mProfile - > mBorderColorHL , mProfile - > mFillColorHL ) ;
}
// Do we draw a bitmap?
if ( mMenuList [ i ] . bitmapIndex ! = - 1 )
{
S32 index = mMenuList [ i ] . bitmapIndex * 3 ;
if ( & mMenuList [ i ] = = mouseDownMenu )
2012-09-19 15:15:01 +00:00
+ + index ;
2017-11-11 07:21:48 +00:00
else if ( & mMenuList [ i ] = = mouseOverMenu & & mouseDownMenu = = NULL )
2012-09-19 15:15:01 +00:00
index + = 2 ;
RectI rect = mProfile - > mBitmapArrayRects [ index ] ;
2017-11-11 07:21:48 +00:00
Point2I bitmapstart ( start ) ;
bitmapstart . y = mMenuList [ i ] . bounds . point . y + ( mMenuList [ i ] . bounds . extent . y - rect . extent . y ) / 2 ;
2012-09-19 15:15:01 +00:00
2015-07-14 03:51:17 +00:00
drawUtil - > clearBitmapModulation ( ) ;
2021-07-19 06:07:08 +00:00
drawUtil - > drawBitmapSR ( mProfile - > getBitmapResource ( ) , offset + bitmapstart , rect ) ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
// Should we also draw the text?
if ( ! mMenuList [ i ] . drawBitmapOnly )
{
2012-09-19 15:15:01 +00:00
start . x + = mBitmapMargin ;
2017-11-11 07:21:48 +00:00
drawUtil - > setBitmapModulation ( fontColor ) ;
drawUtil - > drawText ( mProfile - > mFont , start + offset , mMenuList [ i ] . text , mProfile - > mFontColors ) ;
}
}
else
{
drawUtil - > setBitmapModulation ( fontColor ) ;
drawUtil - > drawText ( mProfile - > mFont , start + offset , mMenuList [ i ] . text , mProfile - > mFontColors ) ;
}
2012-09-19 15:15:01 +00:00
}
2017-11-11 07:21:48 +00:00
renderChildControls ( offset , updateRect ) ;
2012-09-19 15:15:01 +00:00
}
2017-11-11 07:21:48 +00:00
void GuiMenuBar : : buildWindowAcceleratorMap ( WindowInputGenerator & inputGenerator )
2012-09-19 15:15:01 +00:00
{
// ok, accelerator map is cleared...
// add all our keys:
mCurAcceleratorIndex = 1 ;
2015-08-05 03:57:25 +00:00
for ( U32 i = 0 ; i < mMenuList . size ( ) ; + + i )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
for ( U32 item = 0 ; item < mMenuList [ i ] . popupMenu - > mMenuItems . size ( ) ; item + + )
2012-09-19 15:15:01 +00:00
{
2018-03-12 19:30:49 +00:00
if ( ! mMenuList [ i ] . popupMenu - > mMenuItems [ item ] . mAccelerator )
2012-09-19 15:15:01 +00:00
{
2018-03-12 19:30:49 +00:00
mMenuList [ i ] . popupMenu - > mMenuItems [ item ] . mAccelerator = 0 ;
2012-09-19 15:15:01 +00:00
continue ;
}
2017-11-11 07:21:48 +00:00
2012-09-19 15:15:01 +00:00
EventDescriptor accelEvent ;
2018-03-12 19:30:49 +00:00
ActionMap : : createEventDescriptor ( mMenuList [ i ] . popupMenu - > mMenuItems [ item ] . mAccelerator , & accelEvent ) ;
2017-11-11 07:21:48 +00:00
2012-09-19 15:15:01 +00:00
//now we have a modifier, and a key, add them to the canvas
2018-03-12 19:30:49 +00:00
inputGenerator . addAcceleratorKey ( this , mMenuList [ i ] . popupMenu - > mMenuItems [ item ] . mCMD , accelEvent . eventCode , accelEvent . flags ) ;
2015-01-18 21:52:29 +00:00
2018-03-12 19:30:49 +00:00
mMenuList [ i ] . popupMenu - > mMenuItems [ item ] . mAcceleratorIndex = mCurAcceleratorIndex ;
2012-09-19 15:15:01 +00:00
mCurAcceleratorIndex + + ;
}
}
}
2015-01-18 21:52:29 +00:00
void GuiMenuBar : : removeWindowAcceleratorMap ( WindowInputGenerator & inputGenerator )
{
inputGenerator . removeAcceleratorKeys ( this ) ;
}
2012-09-19 15:15:01 +00:00
void GuiMenuBar : : acceleratorKeyPress ( U32 index )
{
// loop through all the menus
// and find the item that corresponds to the accelerator index
2015-08-05 03:57:25 +00:00
for ( U32 i = 0 ; i < mMenuList . size ( ) ; + + i )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
if ( ! mMenuList [ i ] . visible )
2012-09-19 15:15:01 +00:00
continue ;
2017-11-11 07:21:48 +00:00
for ( U32 item = 0 ; item < mMenuList [ i ] . popupMenu - > mMenuItems . size ( ) ; item + + )
2012-09-19 15:15:01 +00:00
{
2018-03-12 19:30:49 +00:00
if ( mMenuList [ i ] . popupMenu - > mMenuItems [ item ] . mAcceleratorIndex = = index )
2012-09-19 15:15:01 +00:00
{
// first, call the script callback for menu selection:
2017-11-11 07:21:48 +00:00
onMenuSelect_callback ( mMenuList [ i ] . popupMenu - > getId ( ) , mMenuList [ i ] . text ) ;
2012-09-19 15:15:01 +00:00
return ;
}
}
}
}
void GuiMenuBar : : onSleep ( )
{
Parent : : onSleep ( ) ;
}
//------------------------------------------------------------------------------
void GuiMenuBar : : onAction ( )
{
if ( ! mouseDownMenu )
return ;
2017-11-11 07:21:48 +00:00
mouseDownMenu - > popupMenu - > hidePopup ( ) ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
// first, call the script callback for menu selection:
onMenuSelect_callback ( mouseDownMenu - > popupMenu - > getId ( ) , mouseDownMenu - > text ) ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
mouseDownMenu - > popupMenu - > mMenuBarCtrl = this ;
2012-09-19 15:15:01 +00:00
GuiCanvas * root = getRoot ( ) ;
2017-11-11 07:21:48 +00:00
Point2I pos = Point2I ( mouseDownMenu - > bounds . point . x , mouseDownMenu - > bounds . point . y + mouseDownMenu - > bounds . extent . y ) ;
mouseDownMenu - > popupMenu - > showPopup ( root , pos . x , pos . y ) ;
2012-09-19 15:15:01 +00:00
}
2025-01-26 05:59:17 +00:00
void GuiMenuBar : : closeMenu ( )
{
if ( mouseDownMenu )
mouseDownMenu - > popupMenu - > hidePopup ( ) ;
mouseOverMenu = NULL ;
mouseDownMenu = NULL ;
mMouseInMenu = false ;
}
2017-11-11 07:21:48 +00:00
// Process a tick
void GuiMenuBar : : processTick ( )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
if ( mMouseInMenu )
onMouseInMenu_callback ( true ) ;
}
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
void GuiMenuBar : : insert ( SimObject * pObject , S32 pos )
{
PopupMenu * menu = dynamic_cast < PopupMenu * > ( pObject ) ;
if ( menu = = nullptr )
2023-10-22 05:47:29 +00:00
{
Con : : errorf ( " GuiMenuBar::insert() - attempted to insert non-popupMenu object: %d " , pObject - > getId ( ) ) ;
2012-09-19 15:15:01 +00:00
return ;
2023-10-22 05:47:29 +00:00
}
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
MenuEntry newMenu ;
newMenu . pos = pos > = mMenuList . size ( ) | | pos = = - 1 ? pos = mMenuList . size ( ) : pos ;
newMenu . drawBitmapOnly = false ;
newMenu . drawBorder = true ;
newMenu . bitmapIndex = - 1 ;
2018-03-12 19:30:49 +00:00
newMenu . text = menu - > mBarTitle ;
2017-11-11 07:21:48 +00:00
newMenu . visible = true ;
newMenu . popupMenu = menu ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
if ( pos > = mMenuList . size ( ) | | pos = = - 1 )
mMenuList . push_back ( newMenu ) ;
else
mMenuList . insert ( pos , newMenu ) ;
2023-10-22 05:47:29 +00:00
menuBarDirty = true ; //ensure we refresh
}
void GuiMenuBar : : remove ( SimObject * pObject )
{
PopupMenu * menu = dynamic_cast < PopupMenu * > ( pObject ) ;
if ( menu = = nullptr )
{
Con : : errorf ( " GuiMenuBar::remove() - attempted to remove non-popupMenu object: %d " , pObject - > getId ( ) ) ;
return ;
}
for ( U32 i = 0 ; i < mMenuList . size ( ) ; i + + )
{
if ( mMenuList [ i ] . popupMenu = = menu )
{
mMenuList . erase ( i ) ;
menuBarDirty = true ; //ensure we refresh
return ;
}
}
2012-09-19 15:15:01 +00:00
}
2017-11-11 07:21:48 +00:00
PopupMenu * GuiMenuBar : : getMenu ( U32 index )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
if ( index > = mMenuList . size ( ) )
return nullptr ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
return mMenuList [ index ] . popupMenu ;
}
2012-09-19 15:15:01 +00:00
2019-03-16 07:38:40 +00:00
PopupMenu * GuiMenuBar : : findMenu ( String barTitle )
2018-01-28 21:14:16 +00:00
{
for ( U32 i = 0 ; i < mMenuList . size ( ) ; i + + )
{
2019-03-16 07:38:40 +00:00
if ( String : : ToLower ( mMenuList [ i ] . text ) = = String : : ToLower ( barTitle ) )
2018-01-28 21:14:16 +00:00
return mMenuList [ i ] . popupMenu ;
}
return nullptr ;
}
2017-11-11 07:21:48 +00:00
//-----------------------------------------------------------------------------
// Console Methods
//-----------------------------------------------------------------------------
2024-03-10 19:29:17 +00:00
# ifdef TORQUE_TOOLS
2018-04-17 19:01:50 +00:00
DefineEngineMethod ( GuiMenuBar , attachToCanvas , void , ( const char * canvas , S32 pos ) , , " (GuiCanvas, pos) " )
2017-11-11 07:21:48 +00:00
{
GuiCanvas * canv = dynamic_cast < GuiCanvas * > ( Sim : : findObject ( canvas ) ) ;
if ( canv )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
canv - > setMenuBar ( object ) ;
2012-09-19 15:15:01 +00:00
}
}
2018-04-17 19:01:50 +00:00
DefineEngineMethod ( GuiMenuBar , removeFromCanvas , void , ( ) , , " () " )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
GuiCanvas * canvas = object - > getRoot ( ) ;
2012-09-19 15:15:01 +00:00
2017-11-11 07:21:48 +00:00
if ( canvas )
canvas - > setMenuBar ( nullptr ) ;
2012-09-19 15:15:01 +00:00
}
2024-03-10 19:29:17 +00:00
# endif
2012-09-19 15:15:01 +00:00
2018-04-17 19:01:50 +00:00
DefineEngineMethod ( GuiMenuBar , getMenuCount , S32 , ( ) , , " () " )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
return object - > getMenuListCount ( ) ;
2012-09-19 15:15:01 +00:00
}
2018-04-17 19:01:50 +00:00
DefineEngineMethod ( GuiMenuBar , getMenu , S32 , ( S32 index ) , ( 0 ) , " (Index) " )
2012-09-19 15:15:01 +00:00
{
2017-11-11 07:21:48 +00:00
return object - > getMenu ( index ) - > getId ( ) ;
2012-09-19 15:15:01 +00:00
}
2017-11-11 07:21:48 +00:00
//-----------------------------------------------------------------------------
2018-04-17 19:01:50 +00:00
DefineEngineMethod ( GuiMenuBar , insert , void , ( SimObject * pObject , S32 pos ) , ( nullAsType < SimObject * > ( ) , - 1 ) , " (object, pos) insert object at position " )
2017-11-11 07:21:48 +00:00
{
2023-10-22 05:47:29 +00:00
if ( pObject = = nullptr )
{
Con : : errorf ( " GuiMenuBar::insert() - null object " ) ;
return ;
}
2017-11-11 07:21:48 +00:00
object - > insert ( pObject , pos ) ;
2018-01-28 21:14:16 +00:00
}
2023-10-22 05:47:29 +00:00
DefineEngineMethod ( GuiMenuBar , remove , void , ( SimObject * pObject ) , ( nullAsType < SimObject * > ( ) ) , " (object, pos) remove object " )
{
if ( pObject = = nullptr )
{
Con : : errorf ( " GuiMenuBar::remove() - null object " ) ;
return ;
}
object - > remove ( pObject ) ;
}
2018-04-17 19:01:50 +00:00
DefineEngineMethod ( GuiMenuBar , findMenu , S32 , ( const char * barTitle ) , ( " " ) , " (barTitle) " )
2018-01-28 21:14:16 +00:00
{
2019-03-16 07:38:40 +00:00
PopupMenu * menu = object - > findMenu ( barTitle ) ;
2018-01-28 21:14:16 +00:00
if ( menu )
return menu - > getId ( ) ;
else
return 0 ;
}