From c5ecba3389feee2d68d873b48527a51b06c48e39 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 24 Apr 2022 14:05:45 +0200 Subject: [PATCH] Menu cleanup for Refresh() --- Moose Development/Moose/Core/Menu.lua | 508 +++++++++++--------------- 1 file changed, 208 insertions(+), 300 deletions(-) diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua index b3d6ab618..ab62ed465 100644 --- a/Moose Development/Moose/Core/Menu.lua +++ b/Moose Development/Moose/Core/Menu.lua @@ -1,9 +1,9 @@ --- **Core** - Manage hierarchical menu structures and commands for players within a mission. --- +-- -- === --- +-- -- ### Features: --- +-- -- * Setup mission sub menus. -- * Setup mission command menus. -- * Setup coalition sub menus. @@ -21,35 +21,35 @@ -- * Update the parameters and the receiving methods, without updating the menu within DCS! -- * Provide a great performance boost in menu management. -- * Provide a great tool to manage menus in your code. --- --- DCS Menus can be managed using the MENU classes. +-- +-- DCS Menus can be managed using the MENU classes. -- The advantage of using MENU classes is that it hides the complexity of dealing with menu management in more advanced scenarios where you need to -- set menus and later remove them, and later set them again. You'll find while using use normal DCS scripting functions, that setting and removing --- menus is not a easy feat if you have complex menu hierarchies defined. +-- menus is not a easy feat if you have complex menu hierarchies defined. -- Using the MOOSE menu classes, the removal and refreshing of menus are nicely being handled within these classes, and becomes much more easy. --- On top, MOOSE implements **variable parameter** passing for command menus. --- +-- On top, MOOSE implements **variable parameter** passing for command menus. +-- -- There are basically two different MENU class types that you need to use: --- +-- -- ### To manage **main menus**, the classes begin with **MENU_**: --- +-- -- * @{Core.Menu#MENU_MISSION}: Manages main menus for whole mission file. -- * @{Core.Menu#MENU_COALITION}: Manages main menus for whole coalition. -- * @{Core.Menu#MENU_GROUP}: Manages main menus for GROUPs. --- +-- -- ### To manage **command menus**, which are menus that allow the player to issue **functions**, the classes begin with **MENU_COMMAND_**: --- +-- -- * @{Core.Menu#MENU_MISSION_COMMAND}: Manages command menus for whole mission file. -- * @{Core.Menu#MENU_COALITION_COMMAND}: Manages command menus for whole coalition. -- * @{Core.Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs. --- +-- -- === ---- +--- -- ### Author: **FlightControl** --- ### Contributions: --- +-- ### Contributions: +-- -- === --- +-- -- @module Core.Menu -- @image Core_Menu.JPG @@ -64,20 +64,19 @@ MENU_INDEX.Coalition[coalition.side.RED].Menus = {} MENU_INDEX.Group = {} function MENU_INDEX:ParentPath( ParentMenu, MenuText ) - local Path = ParentMenu and "@" .. table.concat( ParentMenu.MenuPath or {}, "@" ) or "" - if ParentMenu then + if ParentMenu then if ParentMenu:IsInstanceOf( "MENU_GROUP" ) or ParentMenu:IsInstanceOf( "MENU_GROUP_COMMAND" ) then local GroupName = ParentMenu.Group:GetName() if not self.Group[GroupName].Menus[Path] then - BASE:E( { Path = Path, GroupName = GroupName } ) + BASE:E( { Path = Path, GroupName = GroupName } ) error( "Parent path not found in menu index for group menu" ) return nil end elseif ParentMenu:IsInstanceOf( "MENU_COALITION" ) or ParentMenu:IsInstanceOf( "MENU_COALITION_COMMAND" ) then local Coalition = ParentMenu.Coalition if not self.Coalition[Coalition].Menus[Path] then - BASE:E( { Path = Path, Coalition = Coalition } ) + BASE:E( { Path = Path, Coalition = Coalition } ) error( "Parent path not found in menu index for coalition menu" ) return nil end @@ -89,25 +88,23 @@ function MENU_INDEX:ParentPath( ParentMenu, MenuText ) end end end - + Path = Path .. "@" .. MenuText return Path - end function MENU_INDEX:PrepareMission() - self.MenuMission.Menus = self.MenuMission.Menus or {} + self.MenuMission.Menus = self.MenuMission.Menus or {} end function MENU_INDEX:PrepareCoalition( CoalitionSide ) - self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {} - self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {} + self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {} + self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {} end - --- -- @param Wrapper.Group#GROUP Group function MENU_INDEX:PrepareGroup( Group ) - if Group and Group:IsAlive() ~= nil then -- something was changed here! + if Group and Group:IsAlive() ~= nil then -- something was changed here! local GroupName = Group:GetName() self.Group[GroupName] = self.Group[GroupName] or {} self.Group[GroupName].Menus = self.Group[GroupName].Menus or {} @@ -115,32 +112,22 @@ function MENU_INDEX:PrepareGroup( Group ) end function MENU_INDEX:HasMissionMenu( Path ) - return self.MenuMission.Menus[Path] end - function MENU_INDEX:SetMissionMenu( Path, Menu ) - self.MenuMission.Menus[Path] = Menu end - function MENU_INDEX:ClearMissionMenu( Path ) - self.MenuMission.Menus[Path] = nil end function MENU_INDEX:HasCoalitionMenu( Coalition, Path ) - return self.Coalition[Coalition].Menus[Path] end - function MENU_INDEX:SetCoalitionMenu( Coalition, Path, Menu ) - self.Coalition[Coalition].Menus[Path] = Menu end - function MENU_INDEX:ClearCoalitionMenu( Coalition, Path ) - self.Coalition[Coalition].Menus[Path] = nil end @@ -151,46 +138,36 @@ function MENU_INDEX:HasGroupMenu( Group, Path ) end return nil end - function MENU_INDEX:SetGroupMenu( Group, Path, Menu ) - local MenuGroupName = Group:GetName() - Group:F( { MenuGroupName = MenuGroupName, Path = Path } ) + Group:F({MenuGroupName=MenuGroupName,Path=Path}) self.Group[MenuGroupName].Menus[Path] = Menu end - function MENU_INDEX:ClearGroupMenu( Group, Path ) - local MenuGroupName = Group:GetName() self.Group[MenuGroupName].Menus[Path] = nil end - function MENU_INDEX:Refresh( Group ) - - for MenuID, Menu in pairs( self.MenuMission.Menus ) do - Menu:Refresh() - end - - for MenuID, Menu in pairs( self.Coalition[coalition.side.BLUE].Menus ) do - Menu:Refresh() - end - - for MenuID, Menu in pairs( self.Coalition[coalition.side.RED].Menus ) do - Menu:Refresh() - end - - local GroupName = Group:GetName() - for MenuID, Menu in pairs( self.Group[GroupName].Menus ) do - Menu:Refresh() - end - + for MenuID, Menu in pairs( self.MenuMission.Menus ) do + Menu:Refresh() + end + for MenuID, Menu in pairs( self.Coalition[coalition.side.BLUE].Menus ) do + Menu:Refresh() + end + for MenuID, Menu in pairs( self.Coalition[coalition.side.RED].Menus ) do + Menu:Refresh() + end + local GroupName = Group:GetName() + for MenuID, Menu in pairs( self.Group[GroupName].Menus ) do + Menu:Refresh() + end + + return self end do -- MENU_BASE - --- @type MENU_BASE -- @extends Core.Base#BASE - --- Defines the main MENU class where other MENU classes are derived from. -- This is an abstract class, so don't use it. -- @field #MENU_BASE @@ -200,37 +177,35 @@ do -- MENU_BASE MenuText = "", MenuParentPath = nil, } - + --- Constructor -- @param #MENU_BASE -- @return #MENU_BASE function MENU_BASE:New( MenuText, ParentMenu ) - + local MenuParentPath = {} if ParentMenu ~= nil then MenuParentPath = ParentMenu.MenuPath end - local self = BASE:Inherit( self, BASE:New() ) - - self.MenuPath = nil + + self.MenuPath = nil self.MenuText = MenuText self.ParentMenu = ParentMenu self.MenuParentPath = MenuParentPath - self.Path = (self.ParentMenu and "@" .. table.concat( self.MenuParentPath or {}, "@" ) or "") .. "@" .. self.MenuText + self.Path = ( self.ParentMenu and "@" .. table.concat( self.MenuParentPath or {}, "@" ) or "" ) .. "@" .. self.MenuText self.Menus = {} self.MenuCount = 0 self.MenuStamp = timer.getTime() self.MenuRemoveParent = false - + if self.ParentMenu then self.ParentMenu.Menus = self.ParentMenu.Menus or {} self.ParentMenu.Menus[MenuText] = self end - + return self end - function MENU_BASE:SetParentMenu( MenuText, Menu ) if self.ParentMenu then self.ParentMenu.Menus = self.ParentMenu.Menus or {} @@ -238,27 +213,25 @@ do -- MENU_BASE self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1 end end - function MENU_BASE:ClearParentMenu( MenuText ) if self.ParentMenu and self.ParentMenu.Menus[MenuText] then self.ParentMenu.Menus[MenuText] = nil self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1 if self.ParentMenu.MenuCount == 0 then - -- self.ParentMenu:Remove() + --self.ParentMenu:Remove() end end end - --- Sets a @{Menu} to remove automatically the parent menu when the menu removed is the last child menu of that parent @{Menu}. -- @param #MENU_BASE self -- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}. -- @return #MENU_BASE function MENU_BASE:SetRemoveParent( RemoveParent ) - -- self:F( { RemoveParent } ) + --self:F( { RemoveParent } ) self.MenuRemoveParent = RemoveParent return self end - + --- Gets a @{Menu} from a parent @{Menu} -- @param #MENU_BASE self -- @param #string MenuText The text of the child menu. @@ -266,7 +239,6 @@ do -- MENU_BASE function MENU_BASE:GetMenu( MenuText ) return self.Menus[MenuText] end - --- Sets a menu stamp for later prevention of menu removal. -- @param #MENU_BASE self -- @param MenuStamp @@ -275,14 +247,16 @@ do -- MENU_BASE self.MenuStamp = MenuStamp return self end - + + --- Gets a menu stamp for later prevention of menu removal. -- @param #MENU_BASE self -- @return MenuStamp function MENU_BASE:GetStamp() return timer.getTime() end - + + --- Sets a time stamp for later prevention of menu removal. -- @param #MENU_BASE self -- @param MenuStamp @@ -291,7 +265,7 @@ do -- MENU_BASE self.MenuStamp = MenuStamp return self end - + --- Sets a tag for later selection of menu refresh. -- @param #MENU_BASE self -- @param #string MenuTag A Tag or Key that will filter only menu items set with this key. @@ -300,18 +274,16 @@ do -- MENU_BASE self.MenuTag = MenuTag return self end - + end - do -- MENU_COMMAND_BASE - --- @type MENU_COMMAND_BASE -- @field #function MenuCallHandler -- @extends Core.Menu#MENU_BASE - - --- Defines the main MENU class where other MENU COMMAND_ + + --- Defines the main MENU class where other MENU COMMAND_ -- classes are derived from, in order to set commands. - -- + -- -- @field #MENU_COMMAND_BASE MENU_COMMAND_BASE = { ClassName = "MENU_COMMAND_BASE", @@ -319,14 +291,13 @@ do -- MENU_COMMAND_BASE CommandMenuArgument = nil, MenuCallHandler = nil, } - + --- Constructor -- @param #MENU_COMMAND_BASE -- @return #MENU_COMMAND_BASE function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments ) - + local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE - -- When a menu function goes into error, DCS displays an obscure menu message. -- This error handler catches the menu error and displays the full call stack. local ErrorHandler = function( errmsg ) @@ -336,20 +307,20 @@ do -- MENU_COMMAND_BASE end return errmsg end - + self:SetCommandMenuFunction( CommandMenuFunction ) self:SetCommandMenuArguments( CommandMenuArguments ) self.MenuCallHandler = function() - local function MenuFunction() + local function MenuFunction() return self.CommandMenuFunction( unpack( self.CommandMenuArguments ) ) end local Status, Result = xpcall( MenuFunction, ErrorHandler ) end - + return self end - - --- This sets the new command function of a menu, + + --- This sets the new command function of a menu, -- so that if a menu is regenerated, or if command function changes, -- that the function set for the menu is loosely coupled with the menu itself!!! -- If the function changes, no new menu needs to be generated if the menu text is the same!!! @@ -359,7 +330,6 @@ do -- MENU_COMMAND_BASE self.CommandMenuFunction = CommandMenuFunction return self end - --- This sets the new command arguments of a menu, -- so that if a menu is regenerated, or if command arguments change, -- that the arguments set for the menu are loosely coupled with the menu itself!!! @@ -370,85 +340,78 @@ do -- MENU_COMMAND_BASE self.CommandMenuArguments = CommandMenuArguments return self end - end do -- MENU_MISSION - --- @type MENU_MISSION -- @extends Core.Menu#MENU_BASE - - --- Manages the main menus for a complete mission. - -- + --- Manages the main menus for a complete mission. + -- -- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}. -- @field #MENU_MISSION MENU_MISSION = { ClassName = "MENU_MISSION", } - + --- MENU_MISSION constructor. Creates a new MENU_MISSION object and creates the menu for a complete mission file. -- @param #MENU_MISSION self -- @param #string MenuText The text for the menu. -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the parent menu of DCS world (under F10 other). -- @return #MENU_MISSION function MENU_MISSION:New( MenuText, ParentMenu ) - + MENU_INDEX:PrepareMission() local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText ) - local MissionMenu = MENU_INDEX:HasMissionMenu( Path ) - + local MissionMenu = MENU_INDEX:HasMissionMenu( Path ) if MissionMenu then return MissionMenu else local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) MENU_INDEX:SetMissionMenu( Path, self ) - + self.MenuPath = missionCommands.addSubMenu( self.MenuText, self.MenuParentPath ) self:SetParentMenu( self.MenuText, self ) return self end - + end - --- Refreshes a radio item for a mission -- @param #MENU_MISSION self -- @return #MENU_MISSION function MENU_MISSION:Refresh() - do missionCommands.removeItem( self.MenuPath ) self.MenuPath = missionCommands.addSubMenu( self.MenuText, self.MenuParentPath ) end - + return self end - + --- Removes the sub menus recursively of this MENU_MISSION. Note that the main menu is kept! -- @param #MENU_MISSION self -- @return #MENU_MISSION function MENU_MISSION:RemoveSubMenus() - + for MenuID, Menu in pairs( self.Menus or {} ) do Menu:Remove() end - + self.Menus = nil - + end - + --- Removes the main menu and the sub menus recursively of this MENU_MISSION. -- @param #MENU_MISSION self -- @return #nil function MENU_MISSION:Remove( MenuStamp, MenuTag ) - + MENU_INDEX:PrepareMission() local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText ) - local MissionMenu = MENU_INDEX:HasMissionMenu( Path ) - + local MissionMenu = MENU_INDEX:HasMissionMenu( Path ) if MissionMenu == self then self:RemoveSubMenus() if not MenuStamp or self.MenuStamp ~= MenuStamp then - if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then + if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then self:F( { Text = self.MenuText, Path = self.MenuPath } ) if self.MenuPath ~= nil then missionCommands.removeItem( self.MenuPath ) @@ -461,27 +424,26 @@ do -- MENU_MISSION else BASE:E( { "Cannot Remove MENU_MISSION", Path = Path, ParentMenu = self.ParentMenu, MenuText = self.MenuText } ) end - + return self end end - do -- MENU_MISSION_COMMAND - + --- @type MENU_MISSION_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - - --- Manages the command menus for a complete mission, which allow players to execute functions during mission execution. - -- + + --- Manages the command menus for a complete mission, which allow players to execute functions during mission execution. + -- -- You can add menus with the @{#MENU_MISSION_COMMAND.New} method, which constructs a MENU_MISSION_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION_COMMAND.Remove}. - -- + -- -- @field #MENU_MISSION_COMMAND MENU_MISSION_COMMAND = { ClassName = "MENU_MISSION_COMMAND", } - + --- MENU_MISSION constructor. Creates a new radio command item for a complete mission file, which can invoke a function with parameters. -- @param #MENU_MISSION_COMMAND self -- @param #string MenuText The text for the menu. @@ -490,11 +452,10 @@ do -- MENU_MISSION_COMMAND -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. -- @return #MENU_MISSION_COMMAND self function MENU_MISSION_COMMAND:New( MenuText, ParentMenu, CommandMenuFunction, ... ) - + MENU_INDEX:PrepareMission() local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText ) - local MissionMenu = MENU_INDEX:HasMissionMenu( Path ) - + local MissionMenu = MENU_INDEX:HasMissionMenu( Path ) if MissionMenu then MissionMenu:SetCommandMenuFunction( CommandMenuFunction ) MissionMenu:SetCommandMenuArguments( arg ) @@ -502,37 +463,34 @@ do -- MENU_MISSION_COMMAND else local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) MENU_INDEX:SetMissionMenu( Path, self ) - + self.MenuPath = missionCommands.addCommand( MenuText, self.MenuParentPath, self.MenuCallHandler ) self:SetParentMenu( self.MenuText, self ) return self end end - --- Refreshes a radio item for a mission -- @param #MENU_MISSION_COMMAND self -- @return #MENU_MISSION_COMMAND function MENU_MISSION_COMMAND:Refresh() - do missionCommands.removeItem( self.MenuPath ) missionCommands.addCommand( self.MenuText, self.MenuParentPath, self.MenuCallHandler ) end - + return self end - + --- Removes a radio command item for a coalition -- @param #MENU_MISSION_COMMAND self -- @return #nil function MENU_MISSION_COMMAND:Remove() - + MENU_INDEX:PrepareMission() local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText ) - local MissionMenu = MENU_INDEX:HasMissionMenu( Path ) - + local MissionMenu = MENU_INDEX:HasMissionMenu( Path ) if MissionMenu == self then if not MenuStamp or self.MenuStamp ~= MenuStamp then - if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then + if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then self:F( { Text = self.MenuText, Path = self.MenuPath } ) if self.MenuPath ~= nil then missionCommands.removeItem( self.MenuPath ) @@ -545,22 +503,19 @@ do -- MENU_MISSION_COMMAND else BASE:E( { "Cannot Remove MENU_MISSION_COMMAND", Path = Path, ParentMenu = self.ParentMenu, MenuText = self.MenuText } ) end - + return self end - end - do -- MENU_COALITION - --- @type MENU_COALITION -- @extends Core.Menu#MENU_BASE - - --- Manages the main menus for @{DCS.coalition}s. - -- + + --- Manages the main menus for @{DCS.coalition}s. + -- -- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}. - -- + -- -- -- @usage -- -- This demo creates a menu structure for the planes within the red coalition. @@ -590,7 +545,7 @@ do -- MENU_COALITION -- end -- -- local function AddStatusMenu() - -- + -- -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. -- MenuStatus = MENU_COALITION:New( coalition.side.RED, "Status for Planes" ) -- MenuStatusShow = MENU_COALITION_COMMAND:New( coalition.side.RED, "Show Status", MenuStatus, ShowStatus, "Status of planes is ok!", "Message to Red Coalition" ) @@ -601,9 +556,9 @@ do -- MENU_COALITION -- -- @field #MENU_COALITION MENU_COALITION = { - ClassName = "MENU_COALITION", + ClassName = "MENU_COALITION" } - + --- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition. -- @param #MENU_COALITION self -- @param DCS#coalition.side Coalition The coalition owning the menu. @@ -611,63 +566,57 @@ do -- MENU_COALITION -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the parent menu of DCS world (under F10 other). -- @return #MENU_COALITION self function MENU_COALITION:New( Coalition, MenuText, ParentMenu ) - MENU_INDEX:PrepareCoalition( Coalition ) local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText ) - local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( Coalition, Path ) - + local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( Coalition, Path ) if CoalitionMenu then return CoalitionMenu else - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) MENU_INDEX:SetCoalitionMenu( Coalition, Path, self ) - + self.Coalition = Coalition - + self.MenuPath = missionCommands.addSubMenuForCoalition( Coalition, MenuText, self.MenuParentPath ) self:SetParentMenu( self.MenuText, self ) return self end end - --- Refreshes a radio item for a coalition -- @param #MENU_COALITION self -- @return #MENU_COALITION function MENU_COALITION:Refresh() - do missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) missionCommands.addSubMenuForCoalition( self.Coalition, self.MenuText, self.MenuParentPath ) end - + return self end - + --- Removes the sub menus recursively of this MENU_COALITION. Note that the main menu is kept! -- @param #MENU_COALITION self -- @return #MENU_COALITION function MENU_COALITION:RemoveSubMenus() - + for MenuID, Menu in pairs( self.Menus or {} ) do Menu:Remove() end - + self.Menus = nil end - + --- Removes the main menu and the sub menus recursively of this MENU_COALITION. -- @param #MENU_COALITION self -- @return #nil function MENU_COALITION:Remove( MenuStamp, MenuTag ) - + MENU_INDEX:PrepareCoalition( self.Coalition ) local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText ) - local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( self.Coalition, Path ) - + local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( self.Coalition, Path ) if CoalitionMenu == self then self:RemoveSubMenus() if not MenuStamp or self.MenuStamp ~= MenuStamp then - if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then + if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then self:F( { Coalition = self.Coalition, Text = self.MenuText, Path = self.MenuPath } ) if self.MenuPath ~= nil then missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) @@ -680,27 +629,25 @@ do -- MENU_COALITION else BASE:E( { "Cannot Remove MENU_COALITION", Path = Path, ParentMenu = self.ParentMenu, MenuText = self.MenuText, Coalition = self.Coalition } ) end - + return self end - end - do -- MENU_COALITION_COMMAND - + --- @type MENU_COALITION_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - - --- Manages the command menus for coalitions, which allow players to execute functions during mission execution. - -- + + --- Manages the command menus for coalitions, which allow players to execute functions during mission execution. + -- -- You can add menus with the @{#MENU_COALITION_COMMAND.New} method, which constructs a MENU_COALITION_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION_COMMAND.Remove}. -- -- @field #MENU_COALITION_COMMAND MENU_COALITION_COMMAND = { - ClassName = "MENU_COALITION_COMMAND", + ClassName = "MENU_COALITION_COMMAND" } - + --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. -- @param #MENU_COALITION_COMMAND self -- @param DCS#coalition.side Coalition The coalition owning the menu. @@ -710,52 +657,48 @@ do -- MENU_COALITION_COMMAND -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. -- @return #MENU_COALITION_COMMAND function MENU_COALITION_COMMAND:New( Coalition, MenuText, ParentMenu, CommandMenuFunction, ... ) - + MENU_INDEX:PrepareCoalition( Coalition ) local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText ) - local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( Coalition, Path ) - + local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( Coalition, Path ) if CoalitionMenu then CoalitionMenu:SetCommandMenuFunction( CommandMenuFunction ) CoalitionMenu:SetCommandMenuArguments( arg ) return CoalitionMenu else - + local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) MENU_INDEX:SetCoalitionMenu( Coalition, Path, self ) - + self.Coalition = Coalition self.MenuPath = missionCommands.addCommandForCoalition( self.Coalition, MenuText, self.MenuParentPath, self.MenuCallHandler ) self:SetParentMenu( self.MenuText, self ) return self end - end - --- Refreshes a radio item for a coalition -- @param #MENU_COALITION_COMMAND self -- @return #MENU_COALITION_COMMAND function MENU_COALITION_COMMAND:Refresh() - do missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) missionCommands.addCommandForCoalition( self.Coalition, self.MenuText, self.MenuParentPath, self.MenuCallHandler ) end - + + return self end - + --- Removes a radio command item for a coalition -- @param #MENU_COALITION_COMMAND self -- @return #nil function MENU_COALITION_COMMAND:Remove( MenuStamp, MenuTag ) - + MENU_INDEX:PrepareCoalition( self.Coalition ) local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText ) - local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( self.Coalition, Path ) - + local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( self.Coalition, Path ) if CoalitionMenu == self then if not MenuStamp or self.MenuStamp ~= MenuStamp then - if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then + if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then self:F( { Coalition = self.Coalition, Text = self.MenuText, Path = self.MenuPath } ) if self.MenuPath ~= nil then missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) @@ -768,14 +711,12 @@ do -- MENU_COALITION_COMMAND else BASE:E( { "Cannot Remove MENU_COALITION_COMMAND", Path = Path, ParentMenu = self.ParentMenu, MenuText = self.MenuText, Coalition = self.Coalition } ) end - + return self end - end --- MENU_GROUP - do -- This local variable is used to cache the menus registered under groups. -- Menus don't disappear when groups for players are destroyed and restarted. @@ -783,22 +724,22 @@ do -- the same menus twice during initialization logic. -- These menu classes are handling this logic with this variable. local _MENUGROUPS = {} - --- @type MENU_GROUP -- @extends Core.Menu#MENU_BASE - - --- Manages the main menus for @{Wrapper.Group}s. - -- + + + --- Manages the main menus for @{Wrapper.Group}s. + -- -- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. - -- + -- -- @usage -- -- This demo creates a menu structure for the two groups of planes. -- -- Each group will receive a different menu structure. -- -- To test, join the planes, then look at the other radio menus (Option F10). -- -- Then switch planes and check if the menu is still there. -- -- And play with the Add and Remove menu options. - -- + -- -- -- Note that in multi player, this will only work after the DCS groups bug is solved. -- -- local function ShowStatus( PlaneGroup, StatusText, Coalition ) @@ -844,9 +785,9 @@ do -- -- @field #MENU_GROUP MENU_GROUP = { - ClassName = "MENU_GROUP", + ClassName = "MENU_GROUP" } - + --- MENU_GROUP constructor. Creates a new radio menu item for a group. -- @param #MENU_GROUP self -- @param Wrapper.Group#GROUP Group The Group owning the menu. @@ -854,57 +795,52 @@ do -- @param #table ParentMenu The parent menu. -- @return #MENU_GROUP self function MENU_GROUP:New( Group, MenuText, ParentMenu ) - + MENU_INDEX:PrepareGroup( Group ) local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText ) local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path ) - if GroupMenu then return GroupMenu else self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) MENU_INDEX:SetGroupMenu( Group, Path, self ) - self.Group = Group self.GroupID = Group:GetID() - self.MenuPath = missionCommands.addSubMenuForGroup( self.GroupID, MenuText, self.MenuParentPath ) - + self:SetParentMenu( self.MenuText, self ) return self end - + end - --- Refreshes a new radio item for a group and submenus -- @param #MENU_GROUP self -- @return #MENU_GROUP function MENU_GROUP:Refresh() - do missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath ) - + for MenuText, Menu in pairs( self.Menus or {} ) do Menu:Refresh() end end - + + return self end - + --- Removes the sub menus recursively of this MENU_GROUP. -- @param #MENU_GROUP self -- @param MenuStamp -- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set. -- @return #MENU_GROUP self function MENU_GROUP:RemoveSubMenus( MenuStamp, MenuTag ) - for MenuText, Menu in pairs( self.Menus or {} ) do Menu:Remove( MenuStamp, MenuTag ) end - + self.Menus = nil - + end --- Removes the main menu and sub menus recursively of this MENU_GROUP. @@ -913,15 +849,13 @@ do -- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set. -- @return #nil function MENU_GROUP:Remove( MenuStamp, MenuTag ) - MENU_INDEX:PrepareGroup( self.Group ) local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText ) - local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path ) - + local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path ) if GroupMenu == self then self:RemoveSubMenus( MenuStamp, MenuTag ) if not MenuStamp or self.MenuStamp ~= MenuStamp then - if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then + if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if self.MenuPath ~= nil then self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) @@ -935,22 +869,23 @@ do BASE:E( { "Cannot Remove MENU_GROUP", Path = Path, ParentMenu = self.ParentMenu, MenuText = self.MenuText, Group = self.Group } ) return nil end - + return self end - + + --- @type MENU_GROUP_COMMAND -- @extends Core.Menu#MENU_COMMAND_BASE - - --- The @{Core.Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. + + --- The @{Core.Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. -- You can add menus with the @{#MENU_GROUP_COMMAND.New} method, which constructs a MENU_GROUP_COMMAND object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND.Remove}. -- -- @field #MENU_GROUP_COMMAND MENU_GROUP_COMMAND = { - ClassName = "MENU_GROUP_COMMAND", + ClassName = "MENU_GROUP_COMMAND" } - + --- Creates a new radio command item for a group -- @param #MENU_GROUP_COMMAND self -- @param Wrapper.Group#GROUP Group The Group owning the menu. @@ -960,59 +895,52 @@ do -- @param CommandMenuArgument An argument for the function. -- @return #MENU_GROUP_COMMAND function MENU_GROUP_COMMAND:New( Group, MenuText, ParentMenu, CommandMenuFunction, ... ) - MENU_INDEX:PrepareGroup( Group ) local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText ) - local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path ) - + local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path ) if GroupMenu then GroupMenu:SetCommandMenuFunction( CommandMenuFunction ) GroupMenu:SetCommandMenuArguments( arg ) return GroupMenu else self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) - MENU_INDEX:SetGroupMenu( Group, Path, self ) - + self.Group = Group self.GroupID = Group:GetID() - + self.MenuPath = missionCommands.addCommandForGroup( self.GroupID, MenuText, self.MenuParentPath, self.MenuCallHandler ) - + self:SetParentMenu( self.MenuText, self ) return self end - end - --- Refreshes a radio item for a group -- @param #MENU_GROUP_COMMAND self -- @return #MENU_GROUP_COMMAND function MENU_GROUP_COMMAND:Refresh() - do missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler ) end - + + return self end - + --- Removes a menu structure for a group. -- @param #MENU_GROUP_COMMAND self -- @param MenuStamp -- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set. -- @return #nil function MENU_GROUP_COMMAND:Remove( MenuStamp, MenuTag ) - MENU_INDEX:PrepareGroup( self.Group ) local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText ) - local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path ) - + local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path ) if GroupMenu == self then if not MenuStamp or self.MenuStamp ~= MenuStamp then - if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then + if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if self.MenuPath ~= nil then - self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) + self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) end MENU_INDEX:ClearGroupMenu( self.Group, Path ) @@ -1023,20 +951,17 @@ do else BASE:E( { "Cannot Remove MENU_GROUP_COMMAND", Path = Path, ParentMenu = self.ParentMenu, MenuText = self.MenuText, Group = self.Group } ) end - + return self end - end - --- MENU_GROUP_DELAYED - do - --- @type MENU_GROUP_DELAYED -- @extends Core.Menu#MENU_BASE - - --- The MENU_GROUP_DELAYED class manages the main menus for groups. + + + --- The MENU_GROUP_DELAYED class manages the main menus for groups. -- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. -- The creation of the menu item is delayed however, and must be created using the @{#MENU_GROUP.Set} method. @@ -1045,9 +970,9 @@ do -- -- @field #MENU_GROUP_DELAYED MENU_GROUP_DELAYED = { - ClassName = "MENU_GROUP_DELAYED", + ClassName = "MENU_GROUP_DELAYED" } - + --- MENU_GROUP_DELAYED constructor. Creates a new radio menu item for a group. -- @param #MENU_GROUP_DELAYED self -- @param Wrapper.Group#GROUP Group The Group owning the menu. @@ -1055,80 +980,74 @@ do -- @param #table ParentMenu The parent menu. -- @return #MENU_GROUP_DELAYED self function MENU_GROUP_DELAYED:New( Group, MenuText, ParentMenu ) - + MENU_INDEX:PrepareGroup( Group ) local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText ) local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path ) - if GroupMenu then return GroupMenu else self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) MENU_INDEX:SetGroupMenu( Group, Path, self ) - self.Group = Group self.GroupID = Group:GetID() - if self.MenuParentPath then self.MenuPath = UTILS.DeepCopy( self.MenuParentPath ) else self.MenuPath = {} end table.insert( self.MenuPath, self.MenuText ) - + self:SetParentMenu( self.MenuText, self ) return self end - + end --- Refreshes a new radio item for a group and submenus -- @param #MENU_GROUP_DELAYED self -- @return #MENU_GROUP_DELAYED function MENU_GROUP_DELAYED:Set() - do if not self.MenuSet then missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath ) self.MenuSet = true end - + for MenuText, Menu in pairs( self.Menus or {} ) do Menu:Set() end end - end --- Refreshes a new radio item for a group and submenus -- @param #MENU_GROUP_DELAYED self -- @return #MENU_GROUP_DELAYED function MENU_GROUP_DELAYED:Refresh() - do missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath ) - + for MenuText, Menu in pairs( self.Menus or {} ) do Menu:Refresh() end end - + + return self end - + --- Removes the sub menus recursively of this MENU_GROUP_DELAYED. -- @param #MENU_GROUP_DELAYED self -- @param MenuStamp -- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set. -- @return #MENU_GROUP_DELAYED self function MENU_GROUP_DELAYED:RemoveSubMenus( MenuStamp, MenuTag ) - for MenuText, Menu in pairs( self.Menus or {} ) do Menu:Remove( MenuStamp, MenuTag ) end - + self.Menus = nil - + end --- Removes the main menu and sub menus recursively of this MENU_GROUP. @@ -1137,15 +1056,13 @@ do -- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set. -- @return #nil function MENU_GROUP_DELAYED:Remove( MenuStamp, MenuTag ) - MENU_INDEX:PrepareGroup( self.Group ) local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText ) - local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path ) - + local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path ) if GroupMenu == self then self:RemoveSubMenus( MenuStamp, MenuTag ) if not MenuStamp or self.MenuStamp ~= MenuStamp then - if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then + if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if self.MenuPath ~= nil then self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) @@ -1159,23 +1076,24 @@ do BASE:E( { "Cannot Remove MENU_GROUP_DELAYED", Path = Path, ParentMenu = self.ParentMenu, MenuText = self.MenuText, Group = self.Group } ) return nil end - + return self end - + + --- @type MENU_GROUP_COMMAND_DELAYED -- @extends Core.Menu#MENU_COMMAND_BASE - - --- Manages the command menus for coalitions, which allow players to execute functions during mission execution. - -- + + --- Manages the command menus for coalitions, which allow players to execute functions during mission execution. + -- -- You can add menus with the @{#MENU_GROUP_COMMAND_DELAYED.New} method, which constructs a MENU_GROUP_COMMAND_DELAYED object and returns you the object reference. -- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND_DELAYED.Remove}. -- -- @field #MENU_GROUP_COMMAND_DELAYED MENU_GROUP_COMMAND_DELAYED = { - ClassName = "MENU_GROUP_COMMAND_DELAYED", + ClassName = "MENU_GROUP_COMMAND_DELAYED" } - + --- Creates a new radio command item for a group -- @param #MENU_GROUP_COMMAND_DELAYED self -- @param Wrapper.Group#GROUP Group The Group owning the menu. @@ -1185,76 +1103,67 @@ do -- @param CommandMenuArgument An argument for the function. -- @return #MENU_GROUP_COMMAND_DELAYED function MENU_GROUP_COMMAND_DELAYED:New( Group, MenuText, ParentMenu, CommandMenuFunction, ... ) - MENU_INDEX:PrepareGroup( Group ) local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText ) - local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path ) - + local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path ) if GroupMenu then GroupMenu:SetCommandMenuFunction( CommandMenuFunction ) GroupMenu:SetCommandMenuArguments( arg ) return GroupMenu else self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) - MENU_INDEX:SetGroupMenu( Group, Path, self ) - + self.Group = Group self.GroupID = Group:GetID() - + if self.MenuParentPath then self.MenuPath = UTILS.DeepCopy( self.MenuParentPath ) else self.MenuPath = {} end table.insert( self.MenuPath, self.MenuText ) - + self:SetParentMenu( self.MenuText, self ) return self end - end - --- Refreshes a radio item for a group -- @param #MENU_GROUP_COMMAND_DELAYED self -- @return #MENU_GROUP_COMMAND_DELAYED function MENU_GROUP_COMMAND_DELAYED:Set() - do if not self.MenuSet then self.MenuPath = missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler ) self.MenuSet = true end end - end - + --- Refreshes a radio item for a group -- @param #MENU_GROUP_COMMAND_DELAYED self -- @return #MENU_GROUP_COMMAND_DELAYED function MENU_GROUP_COMMAND_DELAYED:Refresh() - do missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler ) end - + + return self end - + --- Removes a menu structure for a group. -- @param #MENU_GROUP_COMMAND_DELAYED self -- @param MenuStamp -- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set. -- @return #nil function MENU_GROUP_COMMAND_DELAYED:Remove( MenuStamp, MenuTag ) - MENU_INDEX:PrepareGroup( self.Group ) local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText ) - local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path ) - + local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path ) if GroupMenu == self then if not MenuStamp or self.MenuStamp ~= MenuStamp then - if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then + if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then if self.MenuPath ~= nil then self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } ) missionCommands.removeItemForGroup( self.GroupID, self.MenuPath ) @@ -1267,9 +1176,8 @@ do else BASE:E( { "Cannot Remove MENU_GROUP_COMMAND_DELAYED", Path = Path, ParentMenu = self.ParentMenu, MenuText = self.MenuText, Group = self.Group } ) end - + return self end - end