mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
There was a problem that when multiiple groups were part of the attack set, then the menus for planned tasks were not correctly generated.
942 lines
34 KiB
Lua
942 lines
34 KiB
Lua
--- **Core** -- MENU_ classes model the definition of **hierarchical menu structures** and **commands for players** within a mission.
|
|
--
|
|
-- ===
|
|
--
|
|
-- 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 scanerios 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.
|
|
-- 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.
|
|
--
|
|
-- There are basically two different MENU class types that you need to use:
|
|
--
|
|
-- ### To manage **main menus**, the classes begin with **MENU_**:
|
|
--
|
|
-- * @{Menu#MENU_MISSION}: Manages main menus for whole mission file.
|
|
-- * @{Menu#MENU_COALITION}: Manages main menus for whole coalition.
|
|
-- * @{Menu#MENU_GROUP}: Manages main menus for GROUPs.
|
|
-- * @{Menu#MENU_CLIENT}: Manages main menus for CLIENTs. This manages menus for units with the skill level "Client".
|
|
--
|
|
-- ### To manage **command menus**, which are menus that allow the player to issue **functions**, the classes begin with **MENU_COMMAND_**:
|
|
--
|
|
-- * @{Menu#MENU_MISSION_COMMAND}: Manages command menus for whole mission file.
|
|
-- * @{Menu#MENU_COALITION_COMMAND}: Manages command menus for whole coalition.
|
|
-- * @{Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs.
|
|
-- * @{Menu#MENU_CLIENT_COMMAND}: Manages command menus for CLIENTs. This manages menus for units with the skill level "Client".
|
|
--
|
|
-- ===
|
|
---
|
|
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
-- ### Contributions:
|
|
--
|
|
-- ====
|
|
--
|
|
-- @module Menu
|
|
|
|
|
|
do -- MENU_BASE
|
|
|
|
--- @type MENU_BASE
|
|
-- @extends Base#BASE
|
|
|
|
--- # MENU_BASE class, extends @{Base#BASE}
|
|
-- The MENU_BASE class 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
|
|
MENU_BASE = {
|
|
ClassName = "MENU_BASE",
|
|
MenuPath = nil,
|
|
MenuText = "",
|
|
MenuParentPath = nil
|
|
}
|
|
|
|
--- Consructor
|
|
-- @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.MenuText = MenuText
|
|
self.MenuParentPath = MenuParentPath
|
|
self.Menus = {}
|
|
self.MenuCount = 0
|
|
self.MenuRemoveParent = false
|
|
self.MenuTime = timer.getTime()
|
|
|
|
return self
|
|
end
|
|
|
|
--- Gets a @{Menu} from a parent @{Menu}
|
|
-- @param #MENU_BASE self
|
|
-- @param #string MenuText The text of the child menu.
|
|
-- @return #MENU_BASE
|
|
function MENU_BASE:GetMenu( MenuText )
|
|
self:F2( { Menu = self.Menus[MenuText] } )
|
|
return self.Menus[MenuText]
|
|
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:F2( { RemoveParent } )
|
|
self.MenuRemoveParent = RemoveParent
|
|
return self
|
|
end
|
|
|
|
|
|
--- Sets a time stamp for later prevention of menu removal.
|
|
-- @param #MENU_BASE self
|
|
-- @param MenuTime
|
|
-- @return #MENU_BASE
|
|
function MENU_BASE:SetTime( MenuTime )
|
|
self.MenuTime = MenuTime
|
|
return self
|
|
end
|
|
|
|
end
|
|
|
|
do -- MENU_COMMAND_BASE
|
|
|
|
--- @type MENU_COMMAND_BASE
|
|
-- @field #function MenuCallHandler
|
|
-- @extends Core.Menu#MENU_BASE
|
|
|
|
--- # MENU_COMMAND_BASE class, extends @{Base#BASE}
|
|
-- ----------------------------------------------------------
|
|
-- The MENU_COMMAND_BASE class 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",
|
|
CommandMenuFunction = nil,
|
|
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 ) )
|
|
|
|
self.CommandMenuFunction = CommandMenuFunction
|
|
self.MenuCallHandler = function( CommandMenuArguments )
|
|
self.CommandMenuFunction( unpack( CommandMenuArguments ) )
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
end
|
|
|
|
|
|
do -- MENU_MISSION
|
|
|
|
--- @type MENU_MISSION
|
|
-- @extends Core.Menu#MENU_BASE
|
|
|
|
--- # MENU_MISSION class, extends @{Menu#MENU_BASE}
|
|
--
|
|
-- The MENU_MISSION class 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 perent menu of DCS world (under F10 other).
|
|
-- @return #MENU_MISSION
|
|
function MENU_MISSION:New( MenuText, ParentMenu )
|
|
|
|
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
|
|
|
self:F( { MenuText, ParentMenu } )
|
|
|
|
self.MenuText = MenuText
|
|
self.ParentMenu = ParentMenu
|
|
|
|
self.Menus = {}
|
|
|
|
self:T( { MenuText } )
|
|
|
|
self.MenuPath = missionCommands.addSubMenu( MenuText, self.MenuParentPath )
|
|
|
|
self:T( { self.MenuPath } )
|
|
|
|
if ParentMenu and ParentMenu.Menus then
|
|
ParentMenu.Menus[self.MenuPath] = self
|
|
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()
|
|
self:F( self.MenuPath )
|
|
|
|
for MenuID, Menu in pairs( self.Menus ) do
|
|
Menu:Remove()
|
|
end
|
|
|
|
end
|
|
|
|
--- Removes the main menu and the sub menus recursively of this MENU_MISSION.
|
|
-- @param #MENU_MISSION self
|
|
-- @return #nil
|
|
function MENU_MISSION:Remove()
|
|
self:F( self.MenuPath )
|
|
|
|
self:RemoveSubMenus()
|
|
missionCommands.removeItem( self.MenuPath )
|
|
if self.ParentMenu then
|
|
self.ParentMenu.Menus[self.MenuPath] = nil
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
end
|
|
|
|
do -- MENU_MISSION_COMMAND
|
|
|
|
--- @type MENU_MISSION_COMMAND
|
|
-- @extends Core.Menu#MENU_COMMAND_BASE
|
|
|
|
--- # MENU_MISSION_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
|
|
--
|
|
-- The MENU_MISSION_COMMAND class 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.
|
|
-- @param Menu#MENU_MISSION ParentMenu The parent menu.
|
|
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
|
|
-- @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, ... )
|
|
|
|
local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
|
|
|
self.MenuText = MenuText
|
|
self.ParentMenu = ParentMenu
|
|
|
|
self:T( { MenuText, CommandMenuFunction, arg } )
|
|
|
|
|
|
self.MenuPath = missionCommands.addCommand( MenuText, self.MenuParentPath, self.MenuCallHandler, arg )
|
|
|
|
ParentMenu.Menus[self.MenuPath] = self
|
|
|
|
return self
|
|
end
|
|
|
|
--- Removes a radio command item for a coalition
|
|
-- @param #MENU_MISSION_COMMAND self
|
|
-- @return #nil
|
|
function MENU_MISSION_COMMAND:Remove()
|
|
self:F( self.MenuPath )
|
|
|
|
missionCommands.removeItem( self.MenuPath )
|
|
if self.ParentMenu then
|
|
self.ParentMenu.Menus[self.MenuPath] = nil
|
|
end
|
|
return nil
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
do -- MENU_COALITION
|
|
|
|
--- @type MENU_COALITION
|
|
-- @extends Core.Menu#MENU_BASE
|
|
|
|
--- # MENU_COALITION class, extends @{Menu#MENU_BASE}
|
|
--
|
|
-- The @{Menu#MENU_COALITION} class manages the main menus for coalitions.
|
|
-- 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.
|
|
-- -- 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.
|
|
--
|
|
-- local Plane1 = CLIENT:FindByName( "Plane 1" )
|
|
-- local Plane2 = CLIENT:FindByName( "Plane 2" )
|
|
--
|
|
--
|
|
-- -- This would create a menu for the red coalition under the main DCS "Others" menu.
|
|
-- local MenuCoalitionRed = MENU_COALITION:New( coalition.side.RED, "Manage Menus" )
|
|
--
|
|
--
|
|
-- local function ShowStatus( StatusText, Coalition )
|
|
--
|
|
-- MESSAGE:New( Coalition, 15 ):ToRed()
|
|
-- Plane1:Message( StatusText, 15 )
|
|
-- Plane2:Message( StatusText, 15 )
|
|
-- end
|
|
--
|
|
-- local MenuStatus -- Menu#MENU_COALITION
|
|
-- local MenuStatusShow -- Menu#MENU_COALITION_COMMAND
|
|
--
|
|
-- local function RemoveStatusMenu()
|
|
-- MenuStatus:Remove()
|
|
-- 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" )
|
|
-- end
|
|
--
|
|
-- local MenuAdd = MENU_COALITION_COMMAND:New( coalition.side.RED, "Add Status Menu", MenuCoalitionRed, AddStatusMenu )
|
|
-- local MenuRemove = MENU_COALITION_COMMAND:New( coalition.side.RED, "Remove Status Menu", MenuCoalitionRed, RemoveStatusMenu )
|
|
--
|
|
-- @field #MENU_COALITION
|
|
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.DCSCoalition#coalition.side Coalition The coalition owning the menu.
|
|
-- @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 perent menu of DCS world (under F10 other).
|
|
-- @return #MENU_COALITION self
|
|
function MENU_COALITION:New( Coalition, MenuText, ParentMenu )
|
|
|
|
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
|
|
|
self:F( { Coalition, MenuText, ParentMenu } )
|
|
|
|
self.Coalition = Coalition
|
|
self.MenuText = MenuText
|
|
self.ParentMenu = ParentMenu
|
|
|
|
self.Menus = {}
|
|
|
|
self:T( { MenuText } )
|
|
|
|
self.MenuPath = missionCommands.addSubMenuForCoalition( Coalition, MenuText, self.MenuParentPath )
|
|
|
|
self:T( { self.MenuPath } )
|
|
|
|
if ParentMenu and ParentMenu.Menus then
|
|
ParentMenu.Menus[self.MenuPath] = self
|
|
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()
|
|
self:F( self.MenuPath )
|
|
|
|
for MenuID, Menu in pairs( self.Menus ) do
|
|
Menu:Remove()
|
|
end
|
|
|
|
end
|
|
|
|
--- Removes the main menu and the sub menus recursively of this MENU_COALITION.
|
|
-- @param #MENU_COALITION self
|
|
-- @return #nil
|
|
function MENU_COALITION:Remove()
|
|
self:F( self.MenuPath )
|
|
|
|
self:RemoveSubMenus()
|
|
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
|
|
if self.ParentMenu then
|
|
self.ParentMenu.Menus[self.MenuPath] = nil
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
end
|
|
|
|
do -- MENU_COALITION_COMMAND
|
|
|
|
--- @type MENU_COALITION_COMMAND
|
|
-- @extends Core.Menu#MENU_COMMAND_BASE
|
|
|
|
--- # MENU_COALITION_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
|
|
--
|
|
-- The MENU_COALITION_COMMAND class 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"
|
|
}
|
|
|
|
--- 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.DCSCoalition#coalition.side Coalition The coalition owning the menu.
|
|
-- @param #string MenuText The text for the menu.
|
|
-- @param Menu#MENU_COALITION ParentMenu The parent menu.
|
|
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
|
|
-- @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, ... )
|
|
|
|
local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
|
|
|
self.MenuCoalition = Coalition
|
|
self.MenuText = MenuText
|
|
self.ParentMenu = ParentMenu
|
|
|
|
self:T( { MenuText, CommandMenuFunction, arg } )
|
|
|
|
|
|
self.MenuPath = missionCommands.addCommandForCoalition( self.MenuCoalition, MenuText, self.MenuParentPath, self.MenuCallHandler, arg )
|
|
|
|
ParentMenu.Menus[self.MenuPath] = self
|
|
|
|
return self
|
|
end
|
|
|
|
--- Removes a radio command item for a coalition
|
|
-- @param #MENU_COALITION_COMMAND self
|
|
-- @return #nil
|
|
function MENU_COALITION_COMMAND:Remove()
|
|
self:F( self.MenuPath )
|
|
|
|
missionCommands.removeItemForCoalition( self.MenuCoalition, self.MenuPath )
|
|
if self.ParentMenu then
|
|
self.ParentMenu.Menus[self.MenuPath] = nil
|
|
end
|
|
return nil
|
|
end
|
|
|
|
end
|
|
|
|
do -- MENU_CLIENT
|
|
|
|
-- This local variable is used to cache the menus registered under clients.
|
|
-- Menus don't dissapear when clients are destroyed and restarted.
|
|
-- So every menu for a client created must be tracked so that program logic accidentally does not create
|
|
-- the same menus twice during initialization logic.
|
|
-- These menu classes are handling this logic with this variable.
|
|
local _MENUCLIENTS = {}
|
|
|
|
--- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters.
|
|
-- @type MENU_CLIENT
|
|
-- @extends Core.Menu#MENU_BASE
|
|
|
|
|
|
--- # MENU_CLIENT class, extends @{Menu#MENU_BASE}
|
|
--
|
|
-- The MENU_CLIENT class manages the main menus for coalitions.
|
|
-- You can add menus with the @{#MENU_CLIENT.New} method, which constructs a MENU_CLIENT object and returns you the object reference.
|
|
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT.Remove}.
|
|
--
|
|
-- @usage
|
|
-- -- This demo creates a menu structure for the two clients of planes.
|
|
-- -- Each client 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 clients bug is solved.
|
|
--
|
|
-- local function ShowStatus( PlaneClient, StatusText, Coalition )
|
|
--
|
|
-- MESSAGE:New( Coalition, 15 ):ToRed()
|
|
-- PlaneClient:Message( StatusText, 15 )
|
|
-- end
|
|
--
|
|
-- local MenuStatus = {}
|
|
--
|
|
-- local function RemoveStatusMenu( MenuClient )
|
|
-- local MenuClientName = MenuClient:GetName()
|
|
-- MenuStatus[MenuClientName]:Remove()
|
|
-- end
|
|
--
|
|
-- --- @param Wrapper.Client#CLIENT MenuClient
|
|
-- local function AddStatusMenu( MenuClient )
|
|
-- local MenuClientName = MenuClient:GetName()
|
|
-- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object.
|
|
-- MenuStatus[MenuClientName] = MENU_CLIENT:New( MenuClient, "Status for Planes" )
|
|
-- MENU_CLIENT_COMMAND:New( MenuClient, "Show Status", MenuStatus[MenuClientName], ShowStatus, MenuClient, "Status of planes is ok!", "Message to Red Coalition" )
|
|
-- end
|
|
--
|
|
-- SCHEDULER:New( nil,
|
|
-- function()
|
|
-- local PlaneClient = CLIENT:FindByName( "Plane 1" )
|
|
-- if PlaneClient and PlaneClient:IsAlive() then
|
|
-- local MenuManage = MENU_CLIENT:New( PlaneClient, "Manage Menus" )
|
|
-- MENU_CLIENT_COMMAND:New( PlaneClient, "Add Status Menu Plane 1", MenuManage, AddStatusMenu, PlaneClient )
|
|
-- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 1", MenuManage, RemoveStatusMenu, PlaneClient )
|
|
-- end
|
|
-- end, {}, 10, 10 )
|
|
--
|
|
-- SCHEDULER:New( nil,
|
|
-- function()
|
|
-- local PlaneClient = CLIENT:FindByName( "Plane 2" )
|
|
-- if PlaneClient and PlaneClient:IsAlive() then
|
|
-- local MenuManage = MENU_CLIENT:New( PlaneClient, "Manage Menus" )
|
|
-- MENU_CLIENT_COMMAND:New( PlaneClient, "Add Status Menu Plane 2", MenuManage, AddStatusMenu, PlaneClient )
|
|
-- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneClient )
|
|
-- end
|
|
-- end, {}, 10, 10 )
|
|
--
|
|
-- @field #MENU_CLIENT
|
|
MENU_CLIENT = {
|
|
ClassName = "MENU_CLIENT"
|
|
}
|
|
|
|
--- MENU_CLIENT constructor. Creates a new radio menu item for a client.
|
|
-- @param #MENU_CLIENT self
|
|
-- @param Wrapper.Client#CLIENT Client The Client owning the menu.
|
|
-- @param #string MenuText The text for the menu.
|
|
-- @param #table ParentMenu The parent menu.
|
|
-- @return #MENU_CLIENT self
|
|
function MENU_CLIENT:New( Client, MenuText, ParentMenu )
|
|
|
|
-- Arrange meta tables
|
|
local MenuParentPath = {}
|
|
if ParentMenu ~= nil then
|
|
MenuParentPath = ParentMenu.MenuPath
|
|
end
|
|
|
|
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, MenuParentPath ) )
|
|
self:F( { Client, MenuText, ParentMenu } )
|
|
|
|
self.MenuClient = Client
|
|
self.MenuClientGroupID = Client:GetClientGroupID()
|
|
self.MenuParentPath = MenuParentPath
|
|
self.MenuText = MenuText
|
|
self.ParentMenu = ParentMenu
|
|
|
|
self.Menus = {}
|
|
|
|
if not _MENUCLIENTS[self.MenuClientGroupID] then
|
|
_MENUCLIENTS[self.MenuClientGroupID] = {}
|
|
end
|
|
|
|
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
|
|
|
|
self:T( { Client:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } )
|
|
|
|
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
|
|
if MenuPath[MenuPathID] then
|
|
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
|
|
end
|
|
|
|
self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath )
|
|
MenuPath[MenuPathID] = self.MenuPath
|
|
|
|
self:T( { Client:GetClientGroupName(), self.MenuPath } )
|
|
|
|
if ParentMenu and ParentMenu.Menus then
|
|
ParentMenu.Menus[self.MenuPath] = self
|
|
end
|
|
return self
|
|
end
|
|
|
|
--- Removes the sub menus recursively of this @{#MENU_CLIENT}.
|
|
-- @param #MENU_CLIENT self
|
|
-- @return #MENU_CLIENT self
|
|
function MENU_CLIENT:RemoveSubMenus()
|
|
self:F( self.MenuPath )
|
|
|
|
for MenuID, Menu in pairs( self.Menus ) do
|
|
Menu:Remove()
|
|
end
|
|
|
|
end
|
|
|
|
--- Removes the sub menus recursively of this MENU_CLIENT.
|
|
-- @param #MENU_CLIENT self
|
|
-- @return #nil
|
|
function MENU_CLIENT:Remove()
|
|
self:F( self.MenuPath )
|
|
|
|
self:RemoveSubMenus()
|
|
|
|
if not _MENUCLIENTS[self.MenuClientGroupID] then
|
|
_MENUCLIENTS[self.MenuClientGroupID] = {}
|
|
end
|
|
|
|
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
|
|
|
|
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
|
|
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
|
|
end
|
|
|
|
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
|
|
self.ParentMenu.Menus[self.MenuPath] = nil
|
|
return nil
|
|
end
|
|
|
|
|
|
--- @type MENU_CLIENT_COMMAND
|
|
-- @extends Core.Menu#MENU_COMMAND
|
|
|
|
--- # MENU_CLIENT_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
|
|
--
|
|
-- The MENU_CLIENT_COMMAND class manages the command menus for coalitions, which allow players to execute functions during mission execution.
|
|
-- You can add menus with the @{#MENU_CLIENT_COMMAND.New} method, which constructs a MENU_CLIENT_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_CLIENT_COMMAND.Remove}.
|
|
--
|
|
-- @field #MENU_CLIENT_COMMAND
|
|
MENU_CLIENT_COMMAND = {
|
|
ClassName = "MENU_CLIENT_COMMAND"
|
|
}
|
|
|
|
--- MENU_CLIENT_COMMAND constructor. Creates a new radio command item for a client, which can invoke a function with parameters.
|
|
-- @param #MENU_CLIENT_COMMAND self
|
|
-- @param Wrapper.Client#CLIENT Client The Client owning the menu.
|
|
-- @param #string MenuText The text for the menu.
|
|
-- @param #MENU_BASE ParentMenu The parent menu.
|
|
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
|
|
-- @return Menu#MENU_CLIENT_COMMAND self
|
|
function MENU_CLIENT_COMMAND:New( Client, MenuText, ParentMenu, CommandMenuFunction, ... )
|
|
|
|
-- Arrange meta tables
|
|
|
|
local MenuParentPath = {}
|
|
if ParentMenu ~= nil then
|
|
MenuParentPath = ParentMenu.MenuPath
|
|
end
|
|
|
|
local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, MenuParentPath, CommandMenuFunction, arg ) ) -- Menu#MENU_CLIENT_COMMAND
|
|
|
|
self.MenuClient = Client
|
|
self.MenuClientGroupID = Client:GetClientGroupID()
|
|
self.MenuParentPath = MenuParentPath
|
|
self.MenuText = MenuText
|
|
self.ParentMenu = ParentMenu
|
|
|
|
if not _MENUCLIENTS[self.MenuClientGroupID] then
|
|
_MENUCLIENTS[self.MenuClientGroupID] = {}
|
|
end
|
|
|
|
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
|
|
|
|
self:T( { Client:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, arg } )
|
|
|
|
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
|
|
if MenuPath[MenuPathID] then
|
|
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
|
|
end
|
|
|
|
self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, self.MenuCallHandler, arg )
|
|
MenuPath[MenuPathID] = self.MenuPath
|
|
|
|
if ParentMenu and ParentMenu.Menus then
|
|
ParentMenu.Menus[self.MenuPath] = self
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Removes a menu structure for a client.
|
|
-- @param #MENU_CLIENT_COMMAND self
|
|
-- @return #nil
|
|
function MENU_CLIENT_COMMAND:Remove()
|
|
self:F( self.MenuPath )
|
|
|
|
if not _MENUCLIENTS[self.MenuClientGroupID] then
|
|
_MENUCLIENTS[self.MenuClientGroupID] = {}
|
|
end
|
|
|
|
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
|
|
|
|
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
|
|
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
|
|
end
|
|
|
|
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
|
|
self.ParentMenu.Menus[self.MenuPath] = nil
|
|
return nil
|
|
end
|
|
end
|
|
|
|
--- MENU_GROUP
|
|
|
|
do
|
|
-- This local variable is used to cache the menus registered under groups.
|
|
-- Menus don't dissapear when groups for players are destroyed and restarted.
|
|
-- So every menu for a client created must be tracked so that program logic accidentally does not create.
|
|
-- 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
|
|
|
|
|
|
--- #MENU_GROUP class, extends @{Menu#MENU_BASE}
|
|
--
|
|
-- The MENU_GROUP class manages the main menus for coalitions.
|
|
-- 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 )
|
|
--
|
|
-- MESSAGE:New( Coalition, 15 ):ToRed()
|
|
-- PlaneGroup:Message( StatusText, 15 )
|
|
-- end
|
|
--
|
|
-- local MenuStatus = {}
|
|
--
|
|
-- local function RemoveStatusMenu( MenuGroup )
|
|
-- local MenuGroupName = MenuGroup:GetName()
|
|
-- MenuStatus[MenuGroupName]:Remove()
|
|
-- end
|
|
--
|
|
-- --- @param Wrapper.Group#GROUP MenuGroup
|
|
-- local function AddStatusMenu( MenuGroup )
|
|
-- local MenuGroupName = MenuGroup:GetName()
|
|
-- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object.
|
|
-- MenuStatus[MenuGroupName] = MENU_GROUP:New( MenuGroup, "Status for Planes" )
|
|
-- MENU_GROUP_COMMAND:New( MenuGroup, "Show Status", MenuStatus[MenuGroupName], ShowStatus, MenuGroup, "Status of planes is ok!", "Message to Red Coalition" )
|
|
-- end
|
|
--
|
|
-- SCHEDULER:New( nil,
|
|
-- function()
|
|
-- local PlaneGroup = GROUP:FindByName( "Plane 1" )
|
|
-- if PlaneGroup and PlaneGroup:IsAlive() then
|
|
-- local MenuManage = MENU_GROUP:New( PlaneGroup, "Manage Menus" )
|
|
-- MENU_GROUP_COMMAND:New( PlaneGroup, "Add Status Menu Plane 1", MenuManage, AddStatusMenu, PlaneGroup )
|
|
-- MENU_GROUP_COMMAND:New( PlaneGroup, "Remove Status Menu Plane 1", MenuManage, RemoveStatusMenu, PlaneGroup )
|
|
-- end
|
|
-- end, {}, 10, 10 )
|
|
--
|
|
-- SCHEDULER:New( nil,
|
|
-- function()
|
|
-- local PlaneGroup = GROUP:FindByName( "Plane 2" )
|
|
-- if PlaneGroup and PlaneGroup:IsAlive() then
|
|
-- local MenuManage = MENU_GROUP:New( PlaneGroup, "Manage Menus" )
|
|
-- MENU_GROUP_COMMAND:New( PlaneGroup, "Add Status Menu Plane 2", MenuManage, AddStatusMenu, PlaneGroup )
|
|
-- MENU_GROUP_COMMAND:New( PlaneGroup, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneGroup )
|
|
-- end
|
|
-- end, {}, 10, 10 )
|
|
--
|
|
-- @field #MENU_GROUP
|
|
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 MenuGroup The Group owning the menu.
|
|
-- @param #string MenuText The text for the menu.
|
|
-- @param #table ParentMenu The parent menu.
|
|
-- @return #MENU_GROUP self
|
|
function MENU_GROUP:New( MenuGroup, MenuText, ParentMenu )
|
|
|
|
-- Determine if the menu was not already created and already visible at the group.
|
|
-- If it is visible, then return the cached self, otherwise, create self and cache it.
|
|
|
|
MenuGroup._Menus = MenuGroup._Menus or {}
|
|
local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText
|
|
if MenuGroup._Menus[Path] then
|
|
self = MenuGroup._Menus[Path]
|
|
else
|
|
self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
|
--if MenuGroup:IsAlive() then
|
|
MenuGroup._Menus[Path] = self
|
|
--end
|
|
|
|
self.MenuGroup = MenuGroup
|
|
self.Path = Path
|
|
self.MenuGroupID = MenuGroup:GetID()
|
|
self.MenuText = MenuText
|
|
self.ParentMenu = ParentMenu
|
|
|
|
self:T( { "Adding Menu ", MenuText, self.MenuParentPath } )
|
|
self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroupID, MenuText, self.MenuParentPath )
|
|
|
|
if self.ParentMenu and self.ParentMenu.Menus then
|
|
self.ParentMenu.Menus[MenuText] = self
|
|
self:F( { self.ParentMenu.Menus, MenuText } )
|
|
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1
|
|
end
|
|
end
|
|
|
|
--self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } )
|
|
|
|
return self
|
|
end
|
|
|
|
--- Removes the sub menus recursively of this MENU_GROUP.
|
|
-- @param #MENU_GROUP self
|
|
-- @param MenuTime
|
|
-- @return #MENU_GROUP self
|
|
function MENU_GROUP:RemoveSubMenus( MenuTime )
|
|
--self:F2( { self.MenuPath, MenuTime, self.MenuTime } )
|
|
|
|
self:T( { "Removing Group SubMenus:", MenuTime, self.MenuGroup:GetName(), self.MenuPath } )
|
|
for MenuText, Menu in pairs( self.Menus ) do
|
|
Menu:Remove( MenuTime )
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--- Removes the main menu and sub menus recursively of this MENU_GROUP.
|
|
-- @param #MENU_GROUP self
|
|
-- @param MenuTime
|
|
-- @return #nil
|
|
function MENU_GROUP:Remove( MenuTime )
|
|
--self:F2( { self.MenuGroupID, self.MenuPath, MenuTime, self.MenuTime } )
|
|
|
|
self:RemoveSubMenus( MenuTime )
|
|
|
|
if not MenuTime or self.MenuTime ~= MenuTime then
|
|
if self.MenuGroup._Menus[self.Path] then
|
|
self = self.MenuGroup._Menus[self.Path]
|
|
|
|
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
|
|
if self.ParentMenu then
|
|
self.ParentMenu.Menus[self.MenuText] = nil
|
|
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1
|
|
if self.ParentMenu.MenuCount == 0 then
|
|
if self.MenuRemoveParent == true then
|
|
self:T2( "Removing Parent Menu " )
|
|
self.ParentMenu:Remove()
|
|
end
|
|
end
|
|
end
|
|
self:T( { "Removing Group Menu:", MenuGroup = self.MenuGroup:GetName(), MenuPath = self.MenuGroup._Menus[self.Path].Path } )
|
|
self.MenuGroup._Menus[self.Path] = nil
|
|
self = nil
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
|
|
--- @type MENU_GROUP_COMMAND
|
|
-- @extends Core.Menu#MENU_BASE
|
|
|
|
--- # MENU_GROUP_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
|
|
--
|
|
-- The @{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"
|
|
}
|
|
|
|
--- Creates a new radio command item for a group
|
|
-- @param #MENU_GROUP_COMMAND self
|
|
-- @param Wrapper.Group#GROUP MenuGroup The Group owning the menu.
|
|
-- @param MenuText The text for the menu.
|
|
-- @param ParentMenu The parent menu.
|
|
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
|
|
-- @param CommandMenuArgument An argument for the function.
|
|
-- @return #MENU_GROUP_COMMAND
|
|
function MENU_GROUP_COMMAND:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, ... )
|
|
|
|
MenuGroup._Menus = MenuGroup._Menus or {}
|
|
local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText
|
|
if MenuGroup._Menus[Path] then
|
|
self = MenuGroup._Menus[Path]
|
|
self:F2( { "Re-using Group Command Menu:", MenuGroup:GetName(), MenuText } )
|
|
else
|
|
self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
|
|
|
--if MenuGroup:IsAlive() then
|
|
MenuGroup._Menus[Path] = self
|
|
--end
|
|
|
|
self.Path = Path
|
|
self.MenuGroup = MenuGroup
|
|
self.MenuGroupID = MenuGroup:GetID()
|
|
self.MenuText = MenuText
|
|
self.ParentMenu = ParentMenu
|
|
|
|
self:F( { "Adding Group Command Menu:", MenuGroup = MenuGroup:GetName(), MenuText = MenuText, MenuPath = self.MenuParentPath } )
|
|
self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroupID, MenuText, self.MenuParentPath, self.MenuCallHandler, arg )
|
|
|
|
if self.ParentMenu and self.ParentMenu.Menus then
|
|
self.ParentMenu.Menus[MenuText] = self
|
|
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1
|
|
self:F2( { ParentMenu.Menus, MenuText } )
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Removes a menu structure for a group.
|
|
-- @param #MENU_GROUP_COMMAND self
|
|
-- @param MenuTime
|
|
-- @return #nil
|
|
function MENU_GROUP_COMMAND:Remove( MenuTime )
|
|
--self:F2( { self.MenuGroupID, self.MenuPath, MenuTime, self.MenuTime } )
|
|
|
|
if not MenuTime or self.MenuTime ~= MenuTime then
|
|
if self.MenuGroup._Menus[self.Path] then
|
|
self = self.MenuGroup._Menus[self.Path]
|
|
|
|
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
|
|
self:T( { "Removing Group Command Menu:", MenuGroup = self.MenuGroup:GetName(), MenuText = self.MenuText, MenuPath = self.Path } )
|
|
|
|
self.ParentMenu.Menus[self.MenuText] = nil
|
|
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1
|
|
if self.ParentMenu.MenuCount == 0 then
|
|
if self.MenuRemoveParent == true then
|
|
self:T2( "Removing Parent Menu " )
|
|
self.ParentMenu:Remove()
|
|
end
|
|
end
|
|
|
|
self.MenuGroup._Menus[self.Path] = nil
|
|
self = nil
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
end
|
|
|