guiMenuBar.cpp

Engine/source/gui/editor/guiMenuBar.cpp

More...

Public Functions

ConsoleDocClass(GuiMenuBar , "@brief GUI Control which displays <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> horizontal bar with individual drop-down menu items. Each menu item may also have submenu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">items.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "<a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classguimenubar/">GuiMenuBar</a>(newMenuBar)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "  Padding = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "  //Properties not specific <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> have been omitted from this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">example.\n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "// Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> menu <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">bar\n</a>" "newMenuBar.addMenu(0,\"New Menu\");\n\n" "// Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> menu item <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the New <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Menu\n</a>" "newMenuBar.addMenuItem(0,\"New Menu Item\",0,\"n\",-1);\n\n" "// Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> submenu item <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the New Menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Item\n</a>" "newMenuBar.addSubmenuItem(0,1,\"New Submenu Item\",0,\"s\",-1);\n" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTickCtrl\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiCore\n</a>" )
DefineEngineMethod(GuiMenuBar , attachToCanvas , void , (const char *canvas, S32 pos) , "(GuiCanvas, pos)" )
DefineEngineMethod(GuiMenuBar , findMenu , S32 , (const char *barTitle) , ("") , "(barTitle)" )
DefineEngineMethod(GuiMenuBar , getMenu , S32 , (S32 index) , (0) , "(Index)" )
DefineEngineMethod(GuiMenuBar , getMenuCount , S32 , () , "()" )
DefineEngineMethod(GuiMenuBar , insert , void , (SimObject *pObject, S32 pos) , (nullAsType< SimObject * >(), -1) , "(object, pos) insert object at position" )
DefineEngineMethod(GuiMenuBar , removeFromCanvas , void , () , "()" )
IMPLEMENT_CALLBACK(GuiMenuBar , onMenuItemSelect , void , (S32 menuId, const char *menuText, S32 menuItemId, const char *menuItemText) , (menuId, menuText, menuItemId, menuItemText) , "@brief Called whenever an item in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> menu is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selected.\n\n</a>" "@param menuId Index <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of the menu which contains the selected menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">item\n</a>" "@param menuText Text of the menu which contains the selected menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">item\n\n</a>" "@param menuItemId Index <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of the selected menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">item\n</a>" "@param menuItemText Text of the selected menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">item\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// A menu item has been selected, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiMenuBar::onMenuItemSelect(%this,%menuId,%menuText,%menuItemId,%menuItemText)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTickCtrl\n\n</a>" )
IMPLEMENT_CALLBACK(GuiMenuBar , onMenuSelect , void , (S32 menuId, const char *menuText) , (menuId, menuText) , "@brief Called whenever <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> menu is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selected.\n\n</a>" "@param menuId Index <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of the clicked <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">menu\n</a>" "@param menuText Text of the clicked <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">menu\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// A menu has been selected, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiMenuBar::onMenuSelect(%this,%menuId,%menuText)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTickCtrl\n\n</a>" )
IMPLEMENT_CALLBACK(GuiMenuBar , onMouseInMenu , void , (bool isInMenu) , (isInMenu) , "@brief Called whenever the mouse enters, or persists is in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">menu.\n\n</a>" " @param isInMenu True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the mouse has entered the menu, otherwise is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">false.\n</a>" " @note To receive this callback, call setProcessTicks(true) on the menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">bar.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Mouse enters or persists within the menu, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiMenuBar::onMouseInMenu(%this,%hasLeftMenu)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTickCtrl\n\n</a>" )

Detailed Description

Public Functions

ConsoleDocClass(GuiMenuBar , "@brief GUI Control which displays <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> horizontal bar with individual drop-down menu items. Each menu item may also have submenu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">items.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "<a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classguimenubar/">GuiMenuBar</a>(newMenuBar)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "  Padding = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "  //Properties not specific <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> have been omitted from this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">example.\n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "// Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> menu <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">bar\n</a>" "newMenuBar.addMenu(0,\"New Menu\");\n\n" "// Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> menu item <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the New <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Menu\n</a>" "newMenuBar.addMenuItem(0,\"New Menu Item\",0,\"n\",-1);\n\n" "// Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> submenu item <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the New Menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Item\n</a>" "newMenuBar.addSubmenuItem(0,1,\"New Submenu Item\",0,\"s\",-1);\n" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTickCtrl\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiCore\n</a>" )

DefineEngineMethod(GuiMenuBar , attachToCanvas , void , (const char *canvas, S32 pos) , "(GuiCanvas, pos)" )

DefineEngineMethod(GuiMenuBar , findMenu , S32 , (const char *barTitle) , ("") , "(barTitle)" )

DefineEngineMethod(GuiMenuBar , getMenu , S32 , (S32 index) , (0) , "(Index)" )

DefineEngineMethod(GuiMenuBar , getMenuCount , S32 , () , "()" )

DefineEngineMethod(GuiMenuBar , insert , void , (SimObject *pObject, S32 pos) , (nullAsType< SimObject * >(), -1) , "(object, pos) insert object at position" )

DefineEngineMethod(GuiMenuBar , removeFromCanvas , void , () , "()" )

IMPLEMENT_CALLBACK(GuiMenuBar , onMenuItemSelect , void , (S32 menuId, const char *menuText, S32 menuItemId, const char *menuItemText) , (menuId, menuText, menuItemId, menuItemText) , "@brief Called whenever an item in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> menu is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selected.\n\n</a>" "@param menuId Index <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of the menu which contains the selected menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">item\n</a>" "@param menuText Text of the menu which contains the selected menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">item\n\n</a>" "@param menuItemId Index <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of the selected menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">item\n</a>" "@param menuItemText Text of the selected menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">item\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// A menu item has been selected, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiMenuBar::onMenuItemSelect(%this,%menuId,%menuText,%menuItemId,%menuItemText)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTickCtrl\n\n</a>" )

IMPLEMENT_CALLBACK(GuiMenuBar , onMenuSelect , void , (S32 menuId, const char *menuText) , (menuId, menuText) , "@brief Called whenever <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> menu is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selected.\n\n</a>" "@param menuId Index <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> of the clicked <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">menu\n</a>" "@param menuText Text of the clicked <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">menu\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// A menu has been selected, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiMenuBar::onMenuSelect(%this,%menuId,%menuText)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTickCtrl\n\n</a>" )

IMPLEMENT_CALLBACK(GuiMenuBar , onMouseInMenu , void , (bool isInMenu) , (isInMenu) , "@brief Called whenever the mouse enters, or persists is in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">menu.\n\n</a>" " @param isInMenu True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the mouse has entered the menu, otherwise is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">false.\n</a>" " @note To receive this callback, call setProcessTicks(true) on the menu <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">bar.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Mouse enters or persists within the menu, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiMenuBar::onMouseInMenu(%this,%hasLeftMenu)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTickCtrl\n\n</a>" )

IMPLEMENT_CONOBJECT(GuiMenuBar )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#include "platform/platform.h"
  25#include "gui/editor/guiMenuBar.h"
  26
  27#include "console/consoleTypes.h"
  28#include "console/console.h"
  29#include "gui/core/guiCanvas.h"
  30#include "gui/core/guiDefaultControlRender.h"
  31#include "gui/controls/guiTextListCtrl.h"
  32#include "sim/actionMap.h"
  33#include "gfx/gfxDevice.h"
  34#include "gfx/gfxDrawUtil.h"
  35#include "gfx/primBuilder.h"
  36#include "console/engineAPI.h"
  37#include "gui/editor/guiPopupMenuCtrl.h"
  38
  39// menu bar:
  40// basic idea - fixed height control bar at the top of a window, placed and sized in gui editor
  41// menu text for menus or menu items should not begin with a digit
  42// all menus can be removed via the clearMenus() console command
  43// each menu is added via the addMenu(menuText, menuId) console command
  44// each menu is added with a menu id
  45// menu items are added to menus via that addMenuItem(menu, menuItemText, menuItemId, accelerator, checkGroup) console command
  46// each menu item is added with a menu item id and an optional accelerator
  47// menu items are initially enabled, but can be disabled/re-enabled via the setMenuItemEnable(menu,menuItem,bool)
  48// menu text can be set via the setMenuText(menu, newMenuText) console method
  49// menu item text can be set via the setMenuItemText console method
  50// menu items can be removed via the removeMenuItem(menu, menuItem) console command
  51// menu items can be cleared via the clearMenuItems(menu) console command
  52// menus can be hidden or shown via the setMenuVisible(menu, bool) console command
  53// menu items can be hidden or shown via the setMenuItemVisible(menu, menuItem, bool) console command
  54// menu items can be check'd via the setMenuItemChecked(menu, menuItem, bool) console command
  55//    if the bool is true, any other items in that menu item's check group become unchecked.
  56//
  57// menu items can have a bitmap set on them via the setMenuItemBitmap(menu, menuItem, bitmapIndex)
  58//    passing -1 for the bitmap index will result in no bitmap being shown
  59//    the index paramater is an index into the bitmap array of the associated profile
  60//    this can be used, for example, to display a check next to a selected menu item
  61//    bitmap indices are actually multiplied by 3 when indexing into the bitmap
  62//    since bitmaps have normal, selected and disabled states.
  63//
  64// menus can be removed via the removeMenu console command
  65// specification arguments for menus and menu items can be either the id or the text of the menu or menu item
  66// adding the menu item "-" will add an un-selectable seperator to the menu
  67// callbacks:
  68// when a menu is clicked, before it is displayed, the menu calls its onMenuSelect(menuId, menuText) method -
  69//    this allows the callback to enable/disable menu items, or add menu items in a context-sensitive way
  70// when a menu item is clicked, the menu removes itself from display, then calls onMenuItemSelect(menuId, menuText, menuItemId, menuItemText)
  71
  72// the initial implementation does not support:
  73//    hierarchal menus
  74//    keyboard accelerators on menu text (i.e. via alt-key combos)
  75
  76//------------------------------------------------------------------------------
  77
  78IMPLEMENT_CONOBJECT(GuiMenuBar);
  79
  80ConsoleDocClass( GuiMenuBar,
  81   "@brief GUI Control which displays a horizontal bar with individual drop-down menu items. Each menu item may also have submenu items.\n\n"
  82
  83   "@tsexample\n"
  84   "new GuiMenuBar(newMenuBar)\n"
  85   "{\n"
  86   "  Padding = \"0\";\n"
  87   "  //Properties not specific to this control have been omitted from this example.\n"
  88   "};\n\n"
  89   "// Add a menu to the menu bar\n"
  90   "newMenuBar.addMenu(0,\"New Menu\");\n\n"
  91   "// Add a menu item to the New Menu\n"
  92   "newMenuBar.addMenuItem(0,\"New Menu Item\",0,\"n\",-1);\n\n"
  93   "// Add a submenu item to the New Menu Item\n"
  94   "newMenuBar.addSubmenuItem(0,1,\"New Submenu Item\",0,\"s\",-1);\n"
  95   "@endtsexample\n\n"
  96
  97   "@see GuiTickCtrl\n\n"
  98
  99   "@ingroup GuiCore\n"
 100);
 101
 102IMPLEMENT_CALLBACK( GuiMenuBar, onMouseInMenu, void, (bool isInMenu),( isInMenu ),
 103   "@brief Called whenever the mouse enters, or persists is in the menu.\n\n"
 104   "@param isInMenu True if the mouse has entered the menu, otherwise is false.\n"
 105   "@note To receive this callback, call setProcessTicks(true) on the menu bar.\n"
 106   "@tsexample\n"
 107   "// Mouse enters or persists within the menu, causing the callback to occur.\n"
 108   "GuiMenuBar::onMouseInMenu(%this,%hasLeftMenu)\n"
 109   "{\n"
 110   "  // Code to run when the callback occurs\n"
 111   "}\n"
 112   "@endtsexample\n\n"
 113   "@see GuiTickCtrl\n\n"
 114);
 115
 116IMPLEMENT_CALLBACK( GuiMenuBar, onMenuSelect, void, ( S32 menuId, const char* menuText ),( menuId , menuText ),
 117   "@brief Called whenever a menu is selected.\n\n"
 118   "@param menuId Index id of the clicked menu\n"
 119   "@param menuText Text of the clicked menu\n\n"
 120   "@tsexample\n"
 121   "// A menu has been selected, causing the callback to occur.\n"
 122   "GuiMenuBar::onMenuSelect(%this,%menuId,%menuText)\n"
 123   "{\n"
 124   "  // Code to run when the callback occurs\n"
 125   "}\n"
 126   "@endtsexample\n\n"
 127   "@see GuiTickCtrl\n\n"
 128);
 129
 130IMPLEMENT_CALLBACK( GuiMenuBar, onMenuItemSelect, void, ( S32 menuId, const char* menuText, S32 menuItemId, const char* menuItemText ),
 131                                       ( menuId, menuText, menuItemId, menuItemText ),
 132   "@brief Called whenever an item in a menu is selected.\n\n"
 133   "@param menuId Index id of the menu which contains the selected menu item\n"
 134   "@param menuText Text of the menu which contains the selected menu item\n\n"
 135   "@param menuItemId Index id of the selected menu item\n"
 136   "@param menuItemText Text of the selected menu item\n\n"
 137   "@tsexample\n"
 138   "// A menu item has been selected, causing the callback to occur.\n"
 139   "GuiMenuBar::onMenuItemSelect(%this,%menuId,%menuText,%menuItemId,%menuItemText)\n"
 140   "{\n"
 141   "  // Code to run when the callback occurs\n"
 142   "}\n"
 143   "@endtsexample\n\n"
 144   "@see GuiTickCtrl\n\n"
 145);
 146
 147//------------------------------------------------------------------------------
 148// console methods
 149//------------------------------------------------------------------------------
 150
 151/*DefineEngineMethod( GuiMenuBar, clearMenus, void, (),,
 152   "@brief Clears all the menus from the menu bar.\n\n"
 153   "@tsexample\n"
 154   "// Inform the GuiMenuBar control to clear all menus from itself.\n"
 155   "%thisGuiMenuBar.clearMenus();\n"
 156   "@endtsexample\n\n"
 157   "@see GuiTickCtrl")
 158{
 159   object->clearMenus();
 160}
 161
 162DefineEngineMethod( GuiMenuBar, setMenuMargins, void, (S32 horizontalMargin, S32 verticalMargin, S32 bitmapToTextSpacing),,
 163   "@brief Sets the menu rendering margins: horizontal, vertical, bitmap spacing.\n\n"
 164   "Detailed description\n\n"
 165   "@param horizontalMargin Number of pixels on the left and right side of a menu's text.\n"
 166   "@param verticalMargin Number of pixels on the top and bottom of a menu's text.\n"
 167   "@param bitmapToTextSpacing Number of pixels between a menu's bitmap and text.\n"
 168   "@tsexample\n"
 169   "// Define the horizontalMargin\n"
 170   "%horizontalMargin = \"5\";\n\n"
 171   "// Define the verticalMargin\n"
 172   "%verticalMargin = \"5\";\n\n"
 173   "// Define the bitmapToTextSpacing\n"
 174   "%bitmapToTextSpacing = \"12\";\n\n"
 175   "// Inform the GuiMenuBar control to set its margins based on the defined values.\n"
 176   "%thisGuiMenuBar.setMenuMargins(%horizontalMargin,%verticalMargin,%bitmapToTextSpacing);\n"
 177   "@endtsexample\n\n"
 178   "@see GuiTickCtrl")
 179{
 180   object->mHorizontalMargin = horizontalMargin;
 181   object->mVerticalMargin = verticalMargin;
 182   object->mBitmapMargin = bitmapToTextSpacing;
 183}
 184
 185DefineEngineMethod(GuiMenuBar, addMenu, void, (const char* menuText, S32 menuId),,
 186   "@brief Adds a new menu to the menu bar.\n\n"
 187   "@param menuText Text to display for the new menu item.\n"
 188   "@param menuId ID for the new menu item.\n"
 189   "@tsexample\n"
 190   "// Define the menu text\n"
 191   "%menuText = \"New Menu\";\n\n"
 192   "// Define the menu ID.\n"
 193   "%menuId = \"2\";\n\n"
 194   "// Inform the GuiMenuBar control to add the new menu\n"
 195   "%thisGuiMenuBar.addMenu(%menuText,%menuId);\n"
 196   "@endtsexample\n\n"
 197   "@see GuiTickCtrl")
 198{
 199   if(dIsdigit(menuText[0]))
 200   {
 201      Con::errorf("Cannot add menu %s (id = %s).  First character of a menu's text cannot be a digit.", menuText, menuId);
 202      return;
 203   }
 204   object->addMenu(menuText, menuId);
 205}
 206
 207DefineEngineMethod(GuiMenuBar, addMenuItem, void, (const char* targetMenu, const char* menuItemText, S32 menuItemId, const char* accelerator, int checkGroup, const char *cmd),
 208                                     ("","",0,nullAsType<const char*>(),-1,""),
 209   "@brief Adds a menu item to the specified menu.  The menu argument can be either the text of a menu or its id.\n\n"
 210   "@param menu Menu name or menu Id to add the new item to.\n"
 211   "@param menuItemText Text for the new menu item.\n"
 212   "@param menuItemId Id for the new menu item.\n"
 213   "@param accelerator Accelerator key for the new menu item.\n"
 214   "@param checkGroup Check group to include this menu item in.\n"
 215   "@tsexample\n"
 216   "// Define the menu we wish to add the item to\n"
 217   "%targetMenu = \"New Menu\";  or  %menu = \"4\";\n\n"
 218   "// Define the text for the new menu item\n"
 219   "%menuItemText = \"Menu Item\";\n\n"
 220   "// Define the id for the new menu item\n"
 221   "%menuItemId = \"3\";\n\n"
 222   "// Set the accelerator key to toggle this menu item with\n"
 223   "%accelerator = \"n\";\n\n"
 224   "// Define the Check Group that this menu item will be in, if we want it to be in a check group. -1 sets it in no check group.\n"
 225   "%checkGroup = \"4\";\n\n"
 226   "// Inform the GuiMenuBar control to add the new menu item with the defined fields\n"
 227   "%thisGuiMenuBar.addMenuItem(%menu,%menuItemText,%menuItemId,%accelerator,%checkGroup);\n"
 228   "@endtsexample\n\n"
 229   "@see GuiTickCtrl")
 230{
 231   if(dIsdigit(menuItemText[0]))
 232   {
 233      Con::errorf("Cannot add menu item %s (id = %s).  First character of a menu item's text cannot be a digit.", menuItemText, menuItemId);
 234      return;
 235   }
 236   GuiMenuBar::Menu *menu = object->findMenu(targetMenu);
 237   if(!menu)
 238   {
 239      Con::errorf("Cannot find menu %s for addMenuItem.", targetMenu);
 240      return;
 241   }
 242   object->addMenuItem(menu, menuItemText, menuItemId, accelerator != NULL ? accelerator : "", checkGroup == -1 ? -1 : checkGroup, cmd);
 243}
 244
 245DefineEngineMethod(GuiMenuBar, setMenuItemEnable, void, (const char* menuTarget, const char* menuItemTarget, bool enabled),,
 246   "@brief sets the menu item to enabled or disabled based on the enable parameter.\n"
 247   "The specified menu and menu item can either be text or ids.\n\n"
 248   "Detailed description\n\n"
 249   "@param menuTarget Menu to work in\n"
 250   "@param menuItemTarget The menu item inside of the menu to enable or disable\n"
 251   "@param enabled Boolean enable / disable value.\n"
 252   "@tsexample\n"
 253   "// Define the menu\n"
 254   "%menu = \"New Menu\";  or  %menu = \"4\";\n\n"
 255   "// Define the menu item\n"
 256   "%menuItem = \"New Menu Item\";  or %menuItem = \"2\";\n\n"
 257   "// Define the enabled state\n"
 258   "%enabled = \"true\";\n\n"
 259   "// Inform the GuiMenuBar control to set the enabled state of the requested menu item\n"
 260   "%thisGuiMenuBar.setMenuItemEnable(%menu,%menuItme,%enabled);\n"
 261   "@endtsexample\n\n"
 262   "@see GuiTickCtrl")
 263{
 264   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 265   if(!menu)
 266   {
 267      Con::errorf("Cannot find menu %s for setMenuItemEnable.", menuTarget);
 268      return;
 269   }
 270   GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, menuItemTarget);
 271   if(!menuItem)
 272   {
 273      Con::errorf("Cannot find menu item %s for setMenuItemEnable.", menuItemTarget);
 274      return;
 275   }
 276   menuItem->enabled = enabled;
 277}
 278
 279DefineEngineMethod(GuiMenuBar, setCheckmarkBitmapIndex, void, (S32 bitmapindex),,
 280   "@brief Sets the menu bitmap index for the check mark image.\n\n"
 281   "@param bitmapIndex Bitmap index for the check mark image.\n"
 282   "@tsexample\n"
 283   "// Define the bitmap index\n"
 284   "%bitmapIndex = \"2\";\n\n"
 285   "// Inform the GuiMenuBar control of the proper bitmap index for the check mark image\n"
 286   "%thisGuiMenuBar.setCheckmarkBitmapIndex(%bitmapIndex);\n"
 287   "@endtsexample\n\n"
 288   "@see GuiTickCtrl")
 289{
 290   object->mCheckmarkBitmapIndex = bitmapindex;
 291}
 292
 293DefineEngineMethod(GuiMenuBar, setMenuItemChecked, void, (const char* menuTarget, const char* menuItemTarget, bool checked),,
 294   "@brief Sets the menu item bitmap to a check mark, which by default is the first element in\n"
 295   "the bitmap array (although this may be changed with setCheckmarkBitmapIndex()).\n"
 296   "Any other menu items in the menu with the same check group become unchecked if they are checked.\n\n"
 297   "@param menuTarget Menu to work in\n"
 298   "@param menuItem Menu item to affect\n"
 299   "@param checked Whether we are setting it to checked or not\n"
 300   "@tsexample\n"
 301   ""
 302   "@endtsexample\n\n"
 303   "@return If not void, return value and description\n\n"
 304   "@see References")
 305{
 306   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 307   if(!menu)
 308   {
 309      Con::errorf("Cannot find menu %s for setMenuItemChecked.", menuTarget);
 310      return;
 311   }
 312   GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, menuItemTarget);
 313   if(!menuItem)
 314   {
 315      Con::errorf("Cannot find menu item %s for setMenuItemChecked.", menuItemTarget);
 316      return;
 317   }
 318   if(checked && menuItem->checkGroup != -1)
 319   {
 320      // first, uncheck everything in the group:
 321      for(GuiMenuBar::MenuItem *itemWalk = menu->firstMenuItem; itemWalk; itemWalk = itemWalk->nextMenuItem)
 322         if(itemWalk->checkGroup == menuItem->checkGroup && itemWalk->bitmapIndex == object->mCheckmarkBitmapIndex)
 323            itemWalk->bitmapIndex = -1;
 324   }
 325   menuItem->bitmapIndex = checked ? object->mCheckmarkBitmapIndex : -1;
 326}
 327
 328DefineEngineMethod(GuiMenuBar, setMenuText, void, (const char* menuTarget, const char* newMenuText),,
 329   "@brief Sets the text of the specified menu to the new string.\n\n"
 330   "@param menuTarget Menu to affect\n"
 331   "@param newMenuText New menu text\n"
 332   "@tsexample\n"
 333   "// Define the menu to affect"
 334   "%menu = \"New Menu\";  or %menu = \"3\";\n\n"
 335   "// Define the text to change the menu to\n"
 336   "%newMenuText = \"Still a New Menu\";\n\n"
 337   "// Inform the GuiMenuBar control to change the defined menu to the defined text\n"
 338   "%thisGuiMenuBar.setMenuText(%menu,%newMenuText);\n"
 339   "@endtsexample\n\n"
 340   "@see GuiTickCtrl")
 341{
 342   if(dIsdigit(menuTarget[0]))
 343   {
 344      Con::errorf("Cannot name menu %s to %s.  First character of a menu's text cannot be a digit.", menuTarget, newMenuText);
 345      return;
 346   }
 347   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 348   if(!menu)
 349   {
 350      Con::errorf("Cannot find menu %s for setMenuText.", menuTarget);
 351      return;
 352   }
 353   dFree(menu->text);
 354   menu->text = dStrdup(newMenuText);
 355   object->menuBarDirty = true;
 356}
 357
 358DefineEngineMethod(GuiMenuBar, setMenuBitmapIndex, void, (const char* menuTarget, S32 bitmapindex, bool bitmaponly, bool drawborder),,
 359   "@brief Sets the bitmap index for the menu and toggles rendering only the bitmap.\n\n"
 360   "@param menuTarget Menu to affect\n"
 361   "@param bitmapindex Bitmap index to set for the menu\n"
 362   "@param bitmaponly If true, only the bitmap will be rendered\n"
 363   "@param drawborder If true, a border will be drawn around the menu.\n"
 364   "@tsexample\n"
 365   "// Define the menuTarget to affect\n"
 366   "%menuTarget = \"New Menu\";  or %menuTarget = \"3\";\n\n"
 367   "// Set the bitmap index\n"
 368   "%bitmapIndex = \"5\";\n\n"
 369   "// Set if we are only to render the bitmap or not\n"
 370   "%bitmaponly = \"true\";\n\n"
 371   "// Set if we are rendering a border or not\n"
 372   "%drawborder = \"true\";\n\n"
 373   "// Inform the GuiMenuBar of the bitmap and rendering changes\n"
 374   "%thisGuiMenuBar.setMenuBitmapIndex(%menuTarget,%bitmapIndex,%bitmapOnly,%drawBorder);\n"
 375   "@endtsexample\n\n"
 376   "@see GuiTickCtrl")
 377{
 378   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 379   if(!menu)
 380   {
 381      Con::errorf("Cannot find menu %s for setMenuBitmapIndex.", menuTarget);
 382      return;
 383   }
 384
 385   menu->bitmapIndex = bitmapindex;
 386   menu->drawBitmapOnly = bitmaponly;
 387   menu->drawBorder = drawborder;
 388
 389   object->menuBarDirty = true;
 390}
 391
 392DefineEngineMethod(GuiMenuBar, setMenuVisible, void, (const char* menuTarget, bool visible),,
 393   "@brief Sets the whether or not to display the specified menu.\n\n"
 394   "@param menuTarget Menu item to affect\n"
 395   "@param visible Whether the menu item will be visible or not\n"
 396   "@tsexample\n"
 397   "// Define the menu to work with\n"
 398   "%menuTarget = \"New Menu\";  or  %menuTarget = \"4\";\n\n"
 399   "// Define if the menu should be visible or not\n"
 400   "%visible = \"true\";\n\n"
 401   "// Inform the GuiMenuBar control of the new visibility state for the defined menu\n"
 402   "%thisGuiMenuBar.setMenuVisible(%menuTarget,%visible);\n"
 403   "@endtsexample\n\n"
 404   "@see GuiTickCtrl")
 405{
 406   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 407   if(!menu)
 408   {
 409      Con::errorf("Cannot find menu %s for setMenuVisible.", menuTarget);
 410      return;
 411   }
 412   menu->visible = visible;
 413   object->menuBarDirty = true;
 414   object->setUpdate();
 415}
 416
 417DefineEngineMethod(GuiMenuBar, setMenuItemText, void, (const char* menuTarget, const char* menuItemTarget, const char* newMenuItemText),,
 418   "@brief Sets the text of the specified menu item to the new string.\n\n"
 419   "@param menuTarget Menu to affect\n"
 420   "@param menuItem Menu item in the menu to change the text at\n"
 421   "@param newMenuItemText New menu text\n"
 422   "@tsexample\n"
 423   "// Define the menuTarget\n"
 424   "%menuTarget = \"New Menu\";  or  %menuTarget = \"4\";\n\n"
 425   "// Define the menuItem\n"
 426   "%menuItem = \"New Menu Item\";  or  %menuItem = \"2\";\n\n"
 427   "// Define the new text for the menu item\n"
 428   "%newMenuItemText = \"Very New Menu Item\";\n\n"
 429   "// Inform the GuiMenuBar control to change the defined menu item with the new text\n"
 430   "%thisGuiMenuBar.setMenuItemText(%menuTarget,%menuItem,%newMenuItemText);\n"
 431   "@endtsexample\n\n"
 432   "@see GuiTickCtrl")
 433{
 434   if(dIsdigit(newMenuItemText[0]))
 435   {
 436      Con::errorf("Cannot name menu item %s to %s.  First character of a menu item's text cannot be a digit.", menuItemTarget, newMenuItemText);
 437      return;
 438   }
 439   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 440   if(!menu)
 441   {
 442      Con::errorf("Cannot find menu %s for setMenuItemText.", menuTarget);
 443      return;
 444   }
 445   GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, menuItemTarget);
 446   if(!menuItem)
 447   {
 448      Con::errorf("Cannot find menu item %s for setMenuItemText.", menuItemTarget);
 449      return;
 450   }
 451   dFree(menuItem->text);
 452   menuItem->text = dStrdup(newMenuItemText);
 453}
 454
 455DefineEngineMethod(GuiMenuBar, setMenuItemVisible, void, (const char* menuTarget, const char* menuItemTarget, bool isVisible),,
 456   "@brief Brief Description.\n\n"
 457   "Detailed description\n\n"
 458   "@param menuTarget Menu to affect the menu item in\n"
 459   "@param menuItem Menu item to affect\n"
 460   "@param isVisible Visible state to set the menu item to.\n"
 461   "@tsexample\n"
 462   "// Define the menuTarget\n"
 463   "%menuTarget = \"New Menu\";  or  %menuTarget = \"3\";\n\n"
 464   "// Define the menuItem\n"
 465   "%menuItem = \"New Menu Item\";  or  %menuItem = \"2\";\n\n"
 466   "// Define the visibility state\n"
 467   "%isVisible = \"true\";\n\n"
 468   "// Inform the GuiMenuBarControl of the visibility state of the defined menu item\n"
 469   "%thisGuiMenuBar.setMenuItemVisible(%menuTarget,%menuItem,%isVisible);\n"
 470   "@endtsexample\n\n"
 471   "@see GuiTickCtrl")
 472{
 473   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 474   if(!menu)
 475   {
 476      Con::errorf("Cannot find menu %s for setMenuItemVisible.", menuTarget);
 477      return;
 478   }
 479   GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, menuItemTarget);
 480   if(!menuItem)
 481   {
 482      Con::errorf("Cannot find menu item %s for setMenuItemVisible.", menuItemTarget);
 483      return;
 484   }
 485   menuItem->visible = isVisible;
 486}
 487
 488DefineEngineMethod(GuiMenuBar, setMenuItemBitmap, void, (const char* menuTarget, const char* menuItemTarget, S32 bitmapIndex),,
 489   "@brief Sets the specified menu item bitmap index in the bitmap array.  Setting the item's index to -1 will remove any bitmap.\n\n"
 490   "@param menuTarget Menu to affect the menuItem in\n"
 491   "@param menuItem Menu item to affect\n"
 492   "@param bitmapIndex Bitmap index to set the menu item to\n"
 493   "@tsexample\n"
 494   "// Define the menuTarget\n"
 495   "%menuTarget = \"New Menu\";  or  %menuTarget = \"3\";\n\n"
 496   "// Define the menuItem\"\n"
 497   "%menuItem = \"New Menu Item\";  or %menuItem = \"2\";\n\n"
 498   "// Define the bitmapIndex\n"
 499   "%bitmapIndex = \"6\";\n\n"
 500   "// Inform the GuiMenuBar control to set the menu item to the defined bitmap\n"
 501   "%thisGuiMenuBar.setMenuItemBitmap(%menuTarget,%menuItem,%bitmapIndex);\n"
 502   "@endtsexample\n\n"
 503   "@see GuiTickCtrl")
 504{
 505   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 506   if(!menu)
 507   {
 508      Con::errorf("Cannot find menu %s for setMenuItemBitmap.", menuTarget);
 509      return;
 510   }
 511   GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, menuItemTarget);
 512   if(!menuItem)
 513   {
 514      Con::errorf("Cannot find menu item %s for setMenuItemBitmap.", menuItemTarget);
 515      return;
 516   }
 517   menuItem->bitmapIndex = bitmapIndex;
 518}
 519
 520DefineEngineMethod(GuiMenuBar, removeMenuItem, void, (const char* menuTarget, const char* menuItemTarget),,
 521   "@brief Removes the specified menu item from the menu.\n\n"
 522   "@param menuTarget Menu to affect the menu item in\n"
 523   "@param menuItem Menu item to affect\n"
 524   "@tsexample\n"
 525   "// Define the menuTarget\n"
 526   "%menuTarget = \"New Menu\";  or %menuTarget = \"3\";\n\n"
 527   "// Define the menuItem\n"
 528   "%menuItem = \"New Menu Item\";  or  %menuItem = \"5\";\n\n"
 529   "// Request the GuiMenuBar control to remove the define menu item\n"
 530   "%thisGuiMenuBar.removeMenuItem(%menuTarget,%menuItem);\n\n"
 531   "@endtsexample\n\n"
 532   "@see GuiTickCtrl")
 533{
 534   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 535   if(!menu)
 536   {
 537      Con::errorf("Cannot find menu %s for removeMenuItem.", menuTarget);
 538      return;
 539   }
 540   GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, menuItemTarget);
 541   if(!menuItem)
 542   {
 543      Con::errorf("Cannot find menu item %s for removeMenuItem.", menuItemTarget);
 544      return;
 545   }
 546   object->removeMenuItem(menu, menuItem);
 547}
 548
 549DefineEngineMethod(GuiMenuBar, clearMenuItems, void, (const char* menuTarget),,
 550   "@brief Removes all the menu items from the specified menu.\n\n"
 551   "@param menuTarget Menu to remove all items from\n"  
 552   "@tsexample\n"
 553   "// Define the menuTarget\n"
 554   "%menuTarget = \"New Menu\";  or %menuTarget = \"3\";\n\n"
 555   "// Inform the GuiMenuBar control to clear all menu items from the defined menu\n"
 556   "%thisGuiMenuBar.clearMenuItems(%menuTarget);\n"
 557   "@endtsexample\n\n"
 558   "@see GuiTickCtrl")
 559{
 560   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 561   if(!menu)
 562   {
 563      //Con::errorf("Cannot find menu %s for clearMenuItems.", menuTarget);
 564      return;
 565   }
 566   object->clearMenuItems(menu);
 567}
 568
 569DefineEngineMethod( GuiMenuBar, removeMenu, void, (const char* menuTarget),,
 570   "@brief Removes the specified menu from the menu bar.\n\n"
 571   "@param menuTarget Menu to remove from the menu bar\n"  
 572   "@tsexample\n"
 573   "// Define the menuTarget\n"
 574   "%menuTarget = \"New Menu\";  or %menuTarget = \"3\";\n\n"
 575   "// Inform the GuiMenuBar to remove the defined menu from the menu bar\n"
 576   "%thisGuiMenuBar.removeMenu(%menuTarget);\n"
 577   "@endtsexample\n\n"
 578   "@see GuiTickCtrl")
 579{
 580   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 581   if(!menu)
 582   {
 583      //Con::errorf("Cannot find menu %s for removeMenu.", menuTarget);
 584      return;
 585   }
 586   object->clearMenuItems(menu);
 587   object->menuBarDirty = true;
 588}
 589
 590//------------------------------------------------------------------------------
 591//  Submenu console methods
 592//------------------------------------------------------------------------------
 593
 594DefineEngineMethod(GuiMenuBar, setMenuItemSubmenuState, void, (const char* menuTarget, const char* menuItem, bool isSubmenu),,
 595   "@brief Sets the given menu item to be a submenu.\n\n"
 596   "@param menuTarget Menu to affect a submenu in\n"
 597   "@param menuItem Menu item to affect\n"
 598   "@param isSubmenu Whether or not the menuItem will become a subMenu or not\n"
 599   "@tsexample\n"
 600   "// Define the menuTarget\n"
 601   "%menuTarget = \"New Menu\";  or %menuTarget = \"3\";\n\n"
 602   "// Define the menuItem\n"
 603   "%menuItem = \"New Menu Item\";  or  %menuItem = \"5\";\n\n"
 604   "// Define whether or not the Menu Item is a sub menu or not\n"
 605   "%isSubmenu = \"true\";\n\n"
 606   "// Inform the GuiMenuBar control to set the defined menu item to be a submenu or not.\n"
 607   "%thisGuiMenuBar.setMenuItemSubmenuState(%menuTarget,%menuItem,%isSubmenu);\n"
 608   "@endtsexample\n\n"
 609   "@see GuiTickCtrl")
 610{
 611   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 612   if(!menu)
 613   {
 614      Con::errorf("Cannot find menu %s for setMenuItemSubmenuState.", menuTarget);
 615      return;
 616   }
 617
 618   GuiMenuBar::MenuItem *menuitem = object->findMenuItem(menu, menuItem);
 619   if(!menuitem)
 620   {
 621      Con::errorf("Cannot find menuitem %s for setMenuItemSubmenuState.", menuItem);
 622      return;
 623   }
 624
 625   menuitem->isSubmenu = isSubmenu;
 626}
 627
 628DefineEngineMethod(GuiMenuBar, addSubmenuItem, void, (const char* menuTarget, const char* menuItem, const char* submenuItemText, 
 629                                         int submenuItemId, const char* accelerator, int checkGroup),,
 630   "@brief Adds a menu item to the specified menu.  The menu argument can be either the text of a menu or its id.\n\n"
 631   "@param menuTarget Menu to affect a submenu in\n"
 632   "@param menuItem Menu item to affect\n"
 633   "@param submenuItemText Text to show for the new submenu\n"
 634   "@param submenuItemId Id for the new submenu\n"
 635   "@param accelerator Accelerator key for the new submenu\n"
 636   "@param checkGroup Which check group the new submenu should be in, or -1 for none.\n"
 637   "@tsexample\n"
 638   "// Define the menuTarget\n"
 639   "%menuTarget = \"New Menu\";  or  %menuTarget = \"3\";\n\n"
 640   "// Define the menuItem\n"
 641   "%menuItem = \"New Menu Item\";  or  %menuItem = \"5\";\n\n"
 642   "// Define the text for the new submenu\n"
 643   "%submenuItemText = \"New Submenu Item\";\n\n"
 644   "// Define the id for the new submenu\n"
 645   "%submenuItemId = \"4\";\n\n"
 646   "// Define the accelerator key for the new submenu\n"
 647   "%accelerator = \"n\";\n\n"
 648   "// Define the checkgroup for the new submenu\n"
 649   "%checkgroup = \"7\";\n\n"
 650   "// Request the GuiMenuBar control to add the new submenu with the defined information\n"
 651   "%thisGuiMenuBar.addSubmenuItem(%menuTarget,%menuItem,%submenuItemText,%submenuItemId,%accelerator,%checkgroup);\n"
 652   "@endtsexample\n\n"
 653   "@see GuiTickCtrl\n")
 654{
 655   if(dIsdigit(submenuItemText[0]))
 656   {
 657      Con::errorf("Cannot add submenu item %s (id = %s).  First character of a menu item's text cannot be a digit.", submenuItemText, submenuItemId);
 658      return;
 659   }
 660
 661   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 662   if(!menu)
 663   {
 664      Con::errorf("Cannot find menu %s for addMenuItem.", menuTarget);
 665      return;
 666   }
 667
 668   GuiMenuBar::MenuItem *menuitem = object->findMenuItem(menu, menuItem);
 669   if(!menuitem)
 670   {
 671      Con::errorf("Cannot find menuitem %s for addSubmenuItem.", menuItem);
 672      return;
 673   }
 674
 675   object->addSubmenuItem(menu, menuitem, submenuItemText, submenuItemId, !accelerator ? "" : accelerator, checkGroup == -1 ? -1 : checkGroup);
 676}
 677
 678DefineEngineMethod(GuiMenuBar, clearSubmenuItems, void, (const char* menuTarget, const char* menuItem),,
 679   "@brief Removes all the menu items from the specified submenu.\n\n"
 680   "@param menuTarget Menu to affect a submenu in\n"
 681   "@param menuItem Menu item to affect\n"
 682   "@tsexample\n"
 683   "// Define the menuTarget\n"
 684   "%menuTarget = \"New Menu\";  or %menuTarget = \"3\";\n\n"
 685   "// Define the menuItem\n"
 686   "%menuItem = \"New Menu Item\";  or  %menuItem = \"5\";\n\n"
 687   "// Inform the GuiMenuBar to remove all submenu items from the defined menu item\n"
 688   "%thisGuiMenuBar.clearSubmenuItems(%menuTarget,%menuItem);\n\n"
 689   "@endtsexample\n\n"
 690   "@see GuiControl")
 691{
 692   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 693   if(!menu)
 694   {
 695      Con::errorf("Cannot find menu %s for clearSubmenuItems.", menuTarget);
 696      return;
 697   }
 698
 699   GuiMenuBar::MenuItem *menuitem = object->findMenuItem(menu, menuItem);
 700   if(!menuitem)
 701   {
 702      Con::errorf("Cannot find menuitem %s for clearSubmenuItems.", menuItem);
 703      return;
 704   }
 705
 706   object->clearSubmenuItems(menuitem);
 707}
 708
 709DefineEngineMethod(GuiMenuBar, setSubmenuItemChecked, void, (const char* menuTarget, const char* menuItemTarget, const char* submenuItemText, bool checked),,
 710   "@brief Sets the menu item bitmap to a check mark, which by default is the first element in the\n"
 711   "bitmap array (although this may be changed with setCheckmarkBitmapIndex()).\n"
 712   "Any other menu items in the menu with the same check group become unchecked if they are checked.\n\n"
 713   "@param menuTarget Menu to affect a submenu in\n"
 714   "@param menuItem Menu item to affect\n"
 715   "@param submenuItemText Text to show for submenu\n"
 716   "@param checked Whether or not this submenu item will be checked.\n"
 717   "@tsexample\n"
 718   "// Define the menuTarget\n"
 719   "%menuTarget = \"New Menu\";  or %menuTarget = \"3\";\n\n"
 720   "// Define the menuItem\n"
 721   "%menuItem = \"New Menu Item\";  or  %menuItem = \"5\";\n\n"
 722   "// Define the text for the new submenu\n"
 723   "%submenuItemText = \"Submenu Item\";\n\n"
 724   "// Define if this submenu item should be checked or not\n"
 725   "%checked = \"true\";\n\n"
 726   "// Inform the GuiMenuBar control to set the checked state of the defined submenu item\n"
 727   "%thisGuiMenuBar.setSubmenuItemChecked(%menuTarget,%menuItem,%submenuItemText,%checked);\n"
 728   "@endtsexample\n\n"
 729   "@return If not void, return value and description\n\n"
 730   "@see References")
 731{
 732   // Find the parent menu
 733   GuiMenuBar::Menu *menu = object->findMenu(menuTarget);
 734   if(!menu)
 735   {
 736      Con::errorf("Cannot find menu %s for setSubmenuItemChecked.", menuTarget);
 737      return;
 738   }
 739
 740   // Find the parent menu item
 741   GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, menuItemTarget);
 742   if(!menuItem)
 743   {
 744      Con::errorf("Cannot find menu item %s for setSubmenuItemChecked.", menuItemTarget);
 745      return;
 746   }
 747
 748   // Find the submenu item
 749   GuiMenuBar::MenuItem *submenuItem = object->findSubmenuItem(menu, menuItemTarget, submenuItemText);
 750   if(!submenuItem)
 751   {
 752      Con::errorf("Cannot find submenu item %s for setSubmenuItemChecked.", submenuItemText);
 753      return;
 754   }
 755
 756   if(checked && submenuItem->checkGroup != -1)
 757   {
 758      // first, uncheck everything in the group:
 759      for(GuiMenuBar::MenuItem *itemWalk = menuItem->submenu->firstMenuItem; itemWalk; itemWalk = itemWalk->nextMenuItem)
 760         if(itemWalk->checkGroup == submenuItem->checkGroup && itemWalk->bitmapIndex == object->mCheckmarkBitmapIndex)
 761            itemWalk->bitmapIndex = -1;
 762   }
 763   submenuItem->bitmapIndex = checked ? object->mCheckmarkBitmapIndex : -1;
 764}
 765
 766//------------------------------------------------------------------------------
 767// menu management methods
 768//------------------------------------------------------------------------------
 769GuiMenuBar::Menu* GuiMenuBar::sCreateMenu(const char *menuText, U32 menuId)
 770{
 771   // allocate the menu
 772   Menu *newMenu = new Menu;
 773   newMenu->text = dStrdup(menuText);
 774   newMenu->id = menuId;
 775   newMenu->nextMenu = NULL;
 776   newMenu->firstMenuItem = NULL;
 777   newMenu->visible = true;
 778
 779   // Menu bitmap variables
 780   newMenu->bitmapIndex = -1;
 781   newMenu->drawBitmapOnly = false;
 782   newMenu->drawBorder = true;
 783
 784   return newMenu;
 785}
 786
 787void GuiMenuBar::addMenu(GuiMenuBar::Menu *newMenu, S32 pos)
 788{
 789   // add it to the menu list
 790   menuBarDirty = true;
 791   if (pos == -1)
 792      mMenuList.push_back(newMenu);
 793   else
 794      mMenuList.insert(pos, newMenu);
 795}
 796
 797void GuiMenuBar::addMenu(const char *menuText, U32 menuId)
 798{
 799   Menu *newMenu = sCreateMenu(menuText, menuId);
 800   
 801   addMenu(newMenu);
 802}
 803
 804GuiMenuBar::Menu *GuiMenuBar::findMenu(const char *menu)
 805{
 806   if(dIsdigit(menu[0]))
 807   {
 808      U32 id = dAtoi(menu);
 809      for (U32 i = 0; i < mMenuList.size(); ++i)
 810         if (id == mMenuList[i].id)
 811            return mMenuList[i];
 812      return NULL;
 813   }
 814   else
 815   {
 816      for (U32 i = 0; i < mMenuList.size(); ++i)
 817         if (!dStricmp(menu, mMenuList[i].text))
 818            return mMenuList[i];
 819      return NULL;
 820   }
 821}
 822
 823GuiMenuBar::MenuItem *GuiMenuBar::findMenuItem(Menu *menu, const char *menuItem)
 824{
 825   if(dIsdigit(menuItem[0]))
 826   {
 827      U32 id = dAtoi(menuItem);
 828      for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
 829         if(id == walk->id)
 830            return walk;
 831      return NULL;
 832   }
 833   else
 834   {
 835      for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
 836         if(!dStricmp(menuItem, walk->text))
 837            return walk;
 838      return NULL;
 839   }
 840}
 841
 842void GuiMenuBar::removeMenu(Menu *menu)
 843{
 844   menuBarDirty = true;
 845   clearMenuItems(menu);
 846
 847   for (U32 i = 0; i < mMenuList.size(); ++i)
 848   {
 849      if (mMenuList[i] == menu)
 850      {
 851         mMenuList.erase(i);
 852         break;
 853      }
 854   }
 855}
 856
 857void GuiMenuBar::removeMenuItem(Menu *menu, MenuItem *menuItem)
 858{
 859   for(MenuItem **walk = &menu->firstMenuItem; *walk; walk = &(*walk)->nextMenuItem)
 860   {
 861      if(*walk == menuItem)
 862      {
 863         *walk = menuItem->nextMenuItem;
 864         break;
 865      }
 866   }
 867
 868   //  If this is a submenu, then be sure to clear the submenu's items
 869   if(menuItem->isSubmenu)
 870   {
 871      clearSubmenuItems(menuItem);
 872   }
 873
 874   dFree(menuItem->text);
 875   dFree(menuItem->accelerator);
 876   delete menuItem;
 877}
 878
 879GuiMenuBar::MenuItem* GuiMenuBar::addMenuItem(Menu *menu, const char *text, U32 id, const char *accelerator, S32 checkGroup, const char *cmd )
 880{
 881   // allocate the new menu item
 882   MenuItem *newMenuItem = new MenuItem;
 883   newMenuItem->text = dStrdup(text);
 884   if(accelerator[0])
 885      newMenuItem->accelerator = dStrdup(accelerator);
 886   else
 887      newMenuItem->accelerator = NULL;
 888   newMenuItem->cmd = cmd;
 889   newMenuItem->id = id;
 890   newMenuItem->checkGroup = checkGroup;
 891   newMenuItem->nextMenuItem = NULL;
 892   newMenuItem->acceleratorIndex = 0;
 893   newMenuItem->enabled = text[0] != '-';
 894   newMenuItem->visible = true;
 895   newMenuItem->bitmapIndex = -1;
 896
 897   //  Default to not having a submenu
 898   newMenuItem->isSubmenu = false;
 899   newMenuItem->submenu = NULL;
 900   newMenuItem->submenuParentMenu = NULL;
 901
 902   // link it into the menu's menu item list
 903   if(menu)
 904   {
 905      MenuItem **walk = &menu->firstMenuItem;
 906      while(*walk)
 907         walk = &(*walk)->nextMenuItem;
 908      *walk = newMenuItem;
 909   }
 910
 911   return newMenuItem;
 912}
 913
 914GuiMenuBar::MenuItem* GuiMenuBar::addMenuItem(Menu *menu, MenuItem* newMenuItem)
 915{
 916   // link it into the menu's menu item list
 917   if(menu)
 918   {
 919      MenuItem **walk = &menu->firstMenuItem;
 920      while(*walk)
 921         walk = &(*walk)->nextMenuItem;
 922      *walk = newMenuItem;
 923   }
 924
 925   return newMenuItem;
 926}
 927
 928void GuiMenuBar::clearMenuItems(Menu *menu)
 929{
 930   while(menu->firstMenuItem)
 931      removeMenuItem(menu, menu->firstMenuItem);
 932}
 933
 934void GuiMenuBar::clearMenus()
 935{
 936   mMenuList.clear();
 937}
 938
 939void GuiMenuBar::attachToMenuBar(Menu* menu, S32 pos)
 940{
 941   addMenu(menu, pos);
 942}
 943
 944void GuiMenuBar::removeFromMenuBar(Menu* menu)
 945{
 946   menuBarDirty = true;
 947
 948   for (U32 i = 0; i < mMenuList.size(); ++i)
 949   {
 950      if (mMenuList[i] == menu)
 951      {
 952         mMenuList.erase(i);
 953         break;
 954      }
 955   }
 956}
 957
 958//------------------------------------------------------------------------------
 959//  Submenu methods
 960//------------------------------------------------------------------------------
 961
 962//  This method will return the MenuItem class of of a submenu's menu item given
 963// its parent menu and parent menuitem.  If the menuitem ID is used, then the submenu
 964// ID must also be used.
 965GuiMenuBar::MenuItem *GuiMenuBar::findSubmenuItem(Menu *menu, const char *menuItem, const char *submenuItem)
 966{
 967   if(dIsdigit(menuItem[0]))
 968   {
 969      //  Search by ID
 970      U32 id = dAtoi(menuItem);
 971      for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
 972         if(id == walk->id)
 973       {
 974          if(walk->isSubmenu && walk->submenu)
 975         {
 976            return GuiMenuBar::findMenuItem(walk->submenu, submenuItem);
 977         }
 978         return NULL;
 979       }
 980      return NULL;
 981   }
 982   else
 983   {
 984      //  Search by name
 985      for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
 986         if(!dStricmp(menuItem, walk->text))
 987       {
 988          if(walk->isSubmenu && walk->submenu)
 989         {
 990            return GuiMenuBar::findMenuItem(walk->submenu, submenuItem);
 991         }
 992         return NULL;
 993       }
 994      return NULL;
 995   }
 996}
 997
 998GuiMenuBar::MenuItem* GuiMenuBar::findSubmenuItem(MenuItem *menuItem, const char *submenuItem)
 999{
1000   if( !menuItem->isSubmenu )
1001      return NULL;
1002
1003   return GuiMenuBar::findMenuItem( menuItem->submenu, submenuItem );
1004}
1005
1006//  Add a menuitem to the given submenu
1007void GuiMenuBar::addSubmenuItem(Menu *menu, MenuItem *submenu, const char *text, U32 id, const char *accelerator, S32 checkGroup)
1008{
1009   // Check that the given menu item supports a submenu
1010   if(submenu && !submenu->isSubmenu)
1011   {
1012      Con::errorf("GuiMenuBar::addSubmenuItem: Attempting to add menuitem '%s' to an invalid submenu",text);
1013     return;
1014   }
1015
1016   // allocate the new menu item
1017   MenuItem *newMenuItem = new MenuItem;
1018   newMenuItem->text = dStrdup(text);
1019   if(accelerator[0])
1020      newMenuItem->accelerator = dStrdup(accelerator);
1021   else
1022      newMenuItem->accelerator = NULL;
1023   newMenuItem->id = id;
1024   newMenuItem->checkGroup = checkGroup;
1025   newMenuItem->nextMenuItem = NULL;
1026   newMenuItem->acceleratorIndex = 0;
1027   newMenuItem->enabled = (dStrlen(text) > 1 || text[0] != '-');
1028   newMenuItem->visible = true;
1029   newMenuItem->bitmapIndex = -1;
1030
1031   //  Default to not having a submenu
1032   newMenuItem->isSubmenu = false;
1033   newMenuItem->submenu = NULL;
1034
1035   //  Point back to the submenu's menu
1036   newMenuItem->submenuParentMenu = menu;
1037
1038   // link it into the menu's menu item list
1039   MenuItem **walk = &submenu->submenu->firstMenuItem;
1040   while(*walk)
1041      walk = &(*walk)->nextMenuItem;
1042   *walk = newMenuItem;
1043}
1044
1045void GuiMenuBar::addSubmenuItem(Menu *menu, MenuItem *submenu, MenuItem *newMenuItem )
1046{
1047   AssertFatal( submenu && newMenuItem, "");
1048
1049   //  Point back to the submenu's menu
1050   newMenuItem->submenuParentMenu = menu;
1051
1052   // link it into the menu's menu item list
1053   MenuItem **walk = &submenu->submenu->firstMenuItem;
1054   while(*walk)
1055      walk = &(*walk)->nextMenuItem;
1056   *walk = newMenuItem;
1057}
1058
1059//  Remove a submenu item
1060void GuiMenuBar::removeSubmenuItem(MenuItem *menuItem, MenuItem *submenuItem)
1061{
1062   // Check that the given menu item supports a submenu
1063   if(menuItem && !menuItem->isSubmenu)
1064   {
1065      Con::errorf("GuiMenuBar::removeSubmenuItem: Attempting to remove submenuitem '%s' from an invalid submenu",submenuItem->text);
1066     return;
1067   }
1068
1069   GuiMenuBar::removeMenuItem(menuItem->submenu, submenuItem);
1070}
1071
1072//  Clear all menuitems from a submenu
1073void GuiMenuBar::clearSubmenuItems(MenuItem *menuitem)
1074{
1075   // Check that the given menu item supports a submenu
1076   if(menuitem && !menuitem->isSubmenu)
1077   {
1078      Con::errorf("GuiMenuBar::clearSubmenuItems: Attempting to clear an invalid submenu");
1079     return;
1080   }
1081
1082   while(menuitem->submenu->firstMenuItem)
1083      removeSubmenuItem(menuitem, menuitem->submenu->firstMenuItem);
1084}
1085*/
1086//------------------------------------------------------------------------------
1087// initialization, input and render methods
1088//------------------------------------------------------------------------------
1089
1090GuiMenuBar::GuiMenuBar()
1091{
1092   //mMenuList.clear();
1093   menuBarDirty = true;
1094   mouseDownMenu = NULL;
1095   mouseOverMenu = NULL;
1096   mCurAcceleratorIndex = 0;
1097   mPadding = 0;
1098
1099   mCheckmarkBitmapIndex = 0; // Default to the first image in the bitmap array for the check mark
1100
1101   mHorizontalMargin = 6; // Default number of pixels on the left and right side of a manu's text
1102   mVerticalMargin = 1;   // Default number of pixels on the top and bottom of a menu's text
1103   mBitmapMargin = 2;     // Default number of pixels between a menu's bitmap and text
1104
1105   mMenubarHeight = 20;
1106
1107   //  Added:
1108   mouseDownSubmenu = NULL;
1109   mouseOverSubmenu = NULL;
1110
1111   mMouseInMenu = false;
1112
1113   setProcessTicks(false);
1114}
1115
1116void GuiMenuBar::onRemove()
1117{
1118   GuiPopupMenuBackgroundCtrl* backgroundCtrl;
1119   if (Sim::findObject("PopUpMenuControl", backgroundCtrl))
1120   {
1121      if (backgroundCtrl->mMenuBarCtrl == this)
1122         backgroundCtrl->mMenuBarCtrl = nullptr;
1123   }
1124
1125   Parent::onRemove();
1126}
1127
1128void GuiMenuBar::initPersistFields()
1129{
1130   addField("padding", TypeS32, Offset( mPadding, GuiMenuBar ),"Extra padding to add to the bounds of the control.\n");
1131
1132   addField("menubarHeight", TypeS32, Offset(mMenubarHeight, GuiMenuBar), "Sets the height of the menubar when attached to the canvas.\n");
1133
1134   Parent::initPersistFields();
1135}
1136
1137bool GuiMenuBar::onWake()
1138{
1139   if(!Parent::onWake())
1140      return false;
1141   mProfile->constructBitmapArray();  // if a bitmap was specified...
1142   maxBitmapSize.set(0,0);
1143   S32 numBitmaps = mProfile->mBitmapArrayRects.size();
1144   if(numBitmaps)
1145   {
1146      RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
1147      for(S32 i = 0; i < numBitmaps; i++)
1148      {
1149         if(bitmapBounds[i].extent.x > maxBitmapSize.x)
1150            maxBitmapSize.x = bitmapBounds[i].extent.x;
1151         if(bitmapBounds[i].extent.y > maxBitmapSize.y)
1152            maxBitmapSize.y = bitmapBounds[i].extent.y;
1153      }
1154   }
1155   return true;
1156}
1157
1158void GuiMenuBar::addObject(SimObject* object)
1159{
1160   PopupMenu* popup = dynamic_cast<PopupMenu*>(object);
1161
1162   if (!popup)
1163   {
1164      //if it's not a popup, handle it normally
1165      Parent::addObject(object);
1166   }
1167   else
1168   {
1169      //otherwise, if it IS a popup, don't add it as a child object, but instead just insert it as a menu entry
1170      insert(object, -1);
1171   }
1172}
1173
1174GuiMenuBar::MenuEntry *GuiMenuBar::findHitMenu(Point2I mousePoint)
1175{
1176   Point2I pos = globalToLocalCoord(mousePoint);
1177
1178   for (U32 i = 0; i < mMenuList.size(); ++i)
1179   {
1180      if (mMenuList[i].visible && mMenuList[i].bounds.pointInRect(pos))
1181         return &mMenuList[i];
1182   }
1183
1184   return NULL;
1185}
1186
1187void GuiMenuBar::onPreRender()
1188{
1189   setHeight(mMenubarHeight);
1190
1191   Parent::onPreRender();
1192   if (menuBarDirty)
1193   {
1194      menuBarDirty = false;
1195      U32 curX = mPadding;
1196      for (U32 i = 0; i < mMenuList.size(); ++i)
1197      {
1198         if (!mMenuList[i].visible)
1199            continue;
1200
1201         // Bounds depends on if there is a bitmap to be drawn or not
1202         if (mMenuList[i].bitmapIndex == -1)
1203         {
1204            // Text only
1205            mMenuList[i].bounds.set(curX, 0, mProfile->mFont->getStrWidth(mMenuList[i].text) + (mHorizontalMargin * 2), getHeight() - (mVerticalMargin * 2));
1206
1207         }
1208         else
1209         {
1210            // Will the bitmap and text be draw?
1211            if (!mMenuList[i].drawBitmapOnly)
1212            {
1213               // Draw the bitmap and the text
1214               RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
1215               mMenuList[i].bounds.set(curX, 0, bitmapBounds[mMenuList[i].bitmapIndex].extent.x + mProfile->mFont->getStrWidth(mMenuList[i].text) + (mHorizontalMargin * 2), getHeight() + (mVerticalMargin * 2));
1216
1217            }
1218            else
1219            {
1220               // Only the bitmap will be drawn
1221               RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
1222               mMenuList[i].bounds.set(curX, 0, bitmapBounds[mMenuList[i].bitmapIndex].extent.x + mBitmapMargin + (mHorizontalMargin * 2), getHeight() + (mVerticalMargin * 2));
1223            }
1224         }
1225
1226         curX += mMenuList[i].bounds.extent.x;
1227      }
1228      mouseOverMenu = NULL;
1229      mouseDownMenu = NULL;
1230   }
1231}
1232
1233void GuiMenuBar::checkMenuMouseMove(const GuiEvent &event)
1234{
1235   MenuEntry *hit = findHitMenu(event.mousePoint);
1236   if(hit && hit != mouseDownMenu)
1237   {
1238      // gotta close out the current menu...
1239      mouseDownMenu->popupMenu->hidePopup();
1240      
1241      mouseOverMenu = mouseDownMenu = hit;
1242      setUpdate();
1243      onAction();
1244   }
1245}
1246
1247void GuiMenuBar::onMouseMove(const GuiEvent &event)
1248{
1249   MenuEntry *hit = findHitMenu(event.mousePoint);
1250
1251   if (mouseDownMenu != nullptr && hit != nullptr)
1252   {
1253      //we have a standing click, so just update and go
1254      mouseDownMenu = mouseOverMenu = hit;
1255      setUpdate();
1256      onAction();
1257
1258      return;
1259   }
1260
1261   mouseOverMenu = hit;
1262   setUpdate();
1263}
1264
1265void GuiMenuBar::onMouseEnter(const GuiEvent &event)
1266{
1267   onMouseInMenu_callback(true);
1268   mMouseInMenu = true;
1269}
1270
1271void GuiMenuBar::onMouseLeave(const GuiEvent &event)
1272{
1273   if(mouseOverMenu)
1274      setUpdate();
1275
1276   mouseOverMenu = NULL;
1277   mMouseInMenu = false;
1278}
1279
1280void GuiMenuBar::onMouseDragged(const GuiEvent &event)
1281{
1282}
1283
1284void GuiMenuBar::onMouseDown(const GuiEvent &event)
1285{
1286}
1287
1288void GuiMenuBar::onMouseUp(const GuiEvent &event)
1289{
1290   mouseDownMenu = mouseOverMenu = findHitMenu(event.mousePoint);
1291   setUpdate();
1292   onAction();
1293}
1294
1295void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect)
1296{
1297   Point2I extent = getExtent();
1298
1299   RectI ctrlRect(offset, extent);
1300
1301   GFXDrawUtil* drawUtil = GFX->getDrawUtil();
1302
1303   //if opaque, fill the update rect with the fill color
1304   if (mProfile->mOpaque)
1305      drawUtil->drawRectFill(RectI(offset, extent), mProfile->mFillColor);
1306
1307   //if there's a border, draw the border
1308   if (mProfile->mBorder)
1309      renderBorder(ctrlRect, mProfile);
1310
1311   for (U32 i = 0; i < mMenuList.size(); ++i)
1312   {
1313      if (!mMenuList[i].visible)
1314         continue;
1315
1316      ColorI fontColor = mProfile->mFontColor;
1317      RectI bounds = mMenuList[i].bounds;
1318      bounds.point += offset;
1319
1320      Point2I start;
1321
1322      start.x = mMenuList[i].bounds.point.x + mHorizontalMargin;
1323      start.y = mMenuList[i].bounds.point.y + (mMenuList[i].bounds.extent.y - mProfile->mFont->getHeight()) / 2;
1324
1325      // Draw the border
1326      if (mMenuList[i].drawBorder)
1327      {
1328         RectI highlightBounds = bounds;
1329         highlightBounds.inset(1, 1);
1330         if (&mMenuList[i] == mouseDownMenu)
1331            renderFilledBorder(highlightBounds, mProfile->mBorderColorHL, mProfile->mFillColorHL);
1332         else if (&mMenuList[i] == mouseOverMenu && mouseDownMenu == NULL)
1333            renderFilledBorder(highlightBounds, mProfile->mBorderColorHL, mProfile->mFillColorHL);
1334      }
1335
1336      // Do we draw a bitmap?
1337      if (mMenuList[i].bitmapIndex != -1)
1338      {
1339         S32 index = mMenuList[i].bitmapIndex * 3;
1340         if (&mMenuList[i] == mouseDownMenu)
1341            ++index;
1342         else if (&mMenuList[i] == mouseOverMenu && mouseDownMenu == NULL)
1343            index += 2;
1344
1345         RectI rect = mProfile->mBitmapArrayRects[index];
1346
1347         Point2I bitmapstart(start);
1348         bitmapstart.y = mMenuList[i].bounds.point.y + (mMenuList[i].bounds.extent.y - rect.extent.y) / 2;
1349
1350         drawUtil->clearBitmapModulation();
1351         drawUtil->drawBitmapSR(mProfile->mTextureObject, offset + bitmapstart, rect);
1352
1353         // Should we also draw the text?
1354         if (!mMenuList[i].drawBitmapOnly)
1355         {
1356            start.x += mBitmapMargin;
1357            drawUtil->setBitmapModulation(fontColor);
1358            drawUtil->drawText(mProfile->mFont, start + offset, mMenuList[i].text, mProfile->mFontColors);
1359         }
1360      }
1361      else
1362      {
1363         drawUtil->setBitmapModulation(fontColor);
1364         drawUtil->drawText(mProfile->mFont, start + offset, mMenuList[i].text, mProfile->mFontColors);
1365      }
1366   }
1367
1368   renderChildControls(offset, updateRect);
1369}
1370
1371void GuiMenuBar::buildWindowAcceleratorMap(WindowInputGenerator &inputGenerator)
1372{
1373   // ok, accelerator map is cleared...
1374   // add all our keys:
1375   mCurAcceleratorIndex = 1;
1376
1377   for (U32 i = 0; i < mMenuList.size(); ++i)
1378   {
1379      for (U32 item = 0; item < mMenuList[i].popupMenu->mMenuItems.size(); item++)
1380      {
1381         if (!mMenuList[i].popupMenu->mMenuItems[item].mAccelerator)
1382         {
1383            mMenuList[i].popupMenu->mMenuItems[item].mAccelerator = 0;
1384            continue;
1385         }
1386
1387         EventDescriptor accelEvent;
1388         ActionMap::createEventDescriptor(mMenuList[i].popupMenu->mMenuItems[item].mAccelerator, &accelEvent);
1389
1390         //now we have a modifier, and a key, add them to the canvas
1391         inputGenerator.addAcceleratorKey(this, mMenuList[i].popupMenu->mMenuItems[item].mCMD, accelEvent.eventCode, accelEvent.flags);
1392
1393         mMenuList[i].popupMenu->mMenuItems[item].mAcceleratorIndex = mCurAcceleratorIndex;
1394         mCurAcceleratorIndex++;
1395      }
1396   }
1397}
1398
1399void GuiMenuBar::removeWindowAcceleratorMap( WindowInputGenerator &inputGenerator )
1400{
1401    inputGenerator.removeAcceleratorKeys( this );
1402}
1403
1404void GuiMenuBar::acceleratorKeyPress(U32 index)
1405{
1406   // loop through all the menus
1407   // and find the item that corresponds to the accelerator index
1408   for (U32 i = 0; i < mMenuList.size(); ++i)
1409   {
1410      if (!mMenuList[i].visible)
1411         continue;
1412
1413      for(U32 item = 0; item < mMenuList[i].popupMenu->mMenuItems.size(); item++)
1414      {
1415         if(mMenuList[i].popupMenu->mMenuItems[item].mAcceleratorIndex == index)
1416         {
1417            // first, call the script callback for menu selection:
1418            onMenuSelect_callback(mMenuList[i].popupMenu->getId(), mMenuList[i].text);
1419            return;
1420         }
1421      }
1422   }
1423}
1424
1425void GuiMenuBar::onSleep()
1426{
1427   Parent::onSleep();
1428}
1429
1430//------------------------------------------------------------------------------
1431void GuiMenuBar::onAction()
1432{
1433   if(!mouseDownMenu)
1434      return;
1435
1436   mouseDownMenu->popupMenu->hidePopup();
1437
1438   // first, call the script callback for menu selection:
1439   onMenuSelect_callback(mouseDownMenu->popupMenu->getId(), mouseDownMenu->text);
1440
1441   mouseDownMenu->popupMenu->mMenuBarCtrl = this;
1442
1443   GuiCanvas *root = getRoot();
1444   Point2I pos = Point2I(mouseDownMenu->bounds.point.x, mouseDownMenu->bounds.point.y + mouseDownMenu->bounds.extent.y);
1445   mouseDownMenu->popupMenu->showPopup(root, pos.x, pos.y);
1446}
1447
1448//  Process a tick
1449void GuiMenuBar::processTick()
1450{
1451   if(mMouseInMenu)
1452      onMouseInMenu_callback(true);
1453}
1454
1455void GuiMenuBar::insert(SimObject* pObject, S32 pos)
1456{
1457   PopupMenu* menu = dynamic_cast<PopupMenu*>(pObject);
1458   if (menu == nullptr)
1459      return;
1460
1461   MenuEntry newMenu;
1462   newMenu.pos = pos >= mMenuList.size() || pos == -1 ? pos = mMenuList.size() : pos;
1463   newMenu.drawBitmapOnly = false;
1464   newMenu.drawBorder = true;
1465   newMenu.bitmapIndex = -1;
1466   newMenu.text = menu->mBarTitle;
1467   newMenu.visible = true;
1468   newMenu.popupMenu = menu;
1469
1470   if (pos >= mMenuList.size() || pos == -1)
1471      mMenuList.push_back(newMenu);
1472   else
1473      mMenuList.insert(pos, newMenu);
1474}
1475
1476PopupMenu* GuiMenuBar::getMenu(U32 index)
1477{
1478   if (index >= mMenuList.size())
1479      return nullptr;
1480
1481   return mMenuList[index].popupMenu;
1482}
1483
1484PopupMenu* GuiMenuBar::findMenu(String barTitle)
1485{
1486   for (U32 i = 0; i < mMenuList.size(); i++)
1487   {
1488      if (String::ToLower(mMenuList[i].text) == String::ToLower(barTitle))
1489         return mMenuList[i].popupMenu;
1490   }
1491
1492   return nullptr;
1493}
1494
1495//-----------------------------------------------------------------------------
1496// Console Methods
1497//-----------------------------------------------------------------------------
1498DefineEngineMethod(GuiMenuBar, attachToCanvas, void, (const char *canvas, S32 pos), , "(GuiCanvas, pos)")
1499{
1500   GuiCanvas* canv = dynamic_cast<GuiCanvas*>(Sim::findObject(canvas));
1501   if (canv)
1502   {
1503      canv->setMenuBar(object);
1504   }
1505}
1506
1507DefineEngineMethod(GuiMenuBar, removeFromCanvas, void, (), , "()")
1508{
1509   GuiCanvas* canvas = object->getRoot();
1510
1511   if(canvas)
1512      canvas->setMenuBar(nullptr);
1513}
1514
1515DefineEngineMethod(GuiMenuBar, getMenuCount, S32, (), , "()")
1516{
1517   return object->getMenuListCount();
1518}
1519
1520DefineEngineMethod(GuiMenuBar, getMenu, S32, (S32 index), (0), "(Index)")
1521{
1522   return object->getMenu(index)->getId();
1523}
1524
1525//-----------------------------------------------------------------------------
1526DefineEngineMethod(GuiMenuBar, insert, void, (SimObject* pObject, S32 pos), (nullAsType<SimObject*>(), -1), "(object, pos) insert object at position")
1527{
1528   object->insert(pObject, pos);
1529}
1530
1531DefineEngineMethod(GuiMenuBar, findMenu, S32, (const char* barTitle), (""), "(barTitle)")
1532{
1533   PopupMenu* menu = object->findMenu(barTitle);
1534
1535   if (menu)
1536      return menu->getId();
1537   else
1538      return 0;
1539}
1540