--[[ Menu Opening Module --------------------- This module provides a unified function to open menus using the configured menu system. Supported systems include: • jim_bridge (built-in nui menu that works on any framework) • ox (or ox_context) • qb (using QBMenuExport) • gta (using WarMenu) • esx (using ESX.UI.Menu) ]] local contextFunc = { ["ox"] = function(Menu, data) local index = nil if data.onBack and not data.onSelected then table.insert(Menu, 1, { icon = "fas fa-circle-arrow-left", title = "Return", onSelect = data.onBack, label = "Return", }) end for k in pairs(Menu) do if data.onSelected and Menu[k].arrow then Menu[k].icon = "fas fa-angle-right" end -- If no title, use header or txt as title/label. if not Menu[k].title then if Menu[k].header ~= nil and Menu[k].header ~= "" then Menu[k].title = Menu[k].header Menu[k].label = Menu[k].header if Menu[k].txt then Menu[k].description = Menu[k].txt else Menu[k].description = "" end else Menu[k].title = Menu[k].txt Menu[k].label = Menu[k].txt end end -- Copy parameters from 'params' if available. if Menu[k].params then Menu[k].event = Menu[k].params.event Menu[k].args = Menu[k].params.args or {} end if Menu[k].isMenuHeader then Menu[k].readOnly = true end end local menuID = 'Menu' (data.onSelected and lib.registerMenu or lib.registerContext)({ id = menuID, title = data.header..br..br..(data.headertxt and data.headertxt or ""), position = 'top-right', options = Menu, canClose = data.canClose and data.canClose or nil, onClose = (data.onBack and data.onBack) or (data.onExit and data.onExit) or nil, onExit = data.onExit and data.onExit or nil, onSelected = data.onSelected and (function(selected) index = selected end) or nil, }, data.onSelected and (function(x, y, args) if Menu[x].refresh then if Menu[x].onSelect then Menu[x].onSelect() end lib.showMenu(menuID, index) else if Menu[x].onSelect then Menu[x].onSelect() else lib.showMenu(menuID, index) end end end) or nil) if data.onSelected then lib.showMenu(menuID, 1) else lib.showContext(menuID) end end, ["qb"] = function(Menu, data) if data.onBack then table.insert(Menu, 1, { icon = "fas fa-circle-arrow-left", header = " ", txt = "Return", params = { isAction = true, event = data.onBack, }, }) elseif data.canClose then table.insert(Menu, 1, { icon = "fas fa-circle-xmark", header = " ", txt = "Close", params = { isAction = true, event = data.onExit and data.onExit or (function() exports[QBMenuExport]:closeMenu() end), }, }) end if data.header ~= nil then local tempMenu = {} for k, v in pairs(Menu) do tempMenu[k + 1] = v end tempMenu[1] = { header = data.header, txt = data.headertxt or "", isMenuHeader = true } Menu = tempMenu end for k in pairs(Menu) do if not Menu[k].params or not Menu[k].params.event then Menu[k].params = { isAction = true, event = Menu[k].onSelect or function() end, } end if not Menu[k].header then Menu[k].header = " " end if Menu[k].arrow then Menu[k].icon = "fas fa-angle-right" end Menu[k].isMenuHeader = Menu[k].isMenuHeader or Menu[k].disable end exports[QBMenuExport]:openMenu(Menu) end, ["gta"] = function(Menu, data) WarMenu.CreateMenu(tostring(Menu), data.header, " ", { titleColor = { 222, 255, 255 }, maxOptionCountOnScreen = 15, width = 0.25, x = 0.7, }) if WarMenu.IsAnyMenuOpened() then return end WarMenu.OpenMenu(tostring(Menu)) CreateThread(function() local close = true while true do if WarMenu.Begin(tostring(Menu)) then if data.onBack then if WarMenu.SpriteButton("Return", 'commonmenu', "arrowleft", 127, 127, 127) then WarMenu.CloseMenu() Wait(10) data.onBack() end end for k in pairs(Menu) do local pressed = WarMenu.Button(Menu[k].header) if not Menu[k].header then Menu[k].header = Menu[k].txt Menu[k].txt = nil end if Menu[k].txt and Menu[k].txt ~= "" and WarMenu.IsItemHovered() then if Menu[k].disabled or Menu[k].isMenuHeader then WarMenu.ToolTip("~r~"..Menu[k].txt, 0.18, true) else WarMenu.ToolTip( (Menu[k].blip and "~BLIP_".."8".."~ " or "").. Menu[k].txt:gsub("%:", ":~g~"):gsub("%\n", "\n~s~"), 0.18, true) end end if pressed and not Menu[k].isMenuHeader then WarMenu.CloseMenu() close = false Wait(10) Menu[k].onSelect() end end WarMenu.End() else return end if not WarMenu.IsAnyMenuOpened() and close then stopTempCam(cam) if data.onExit then data.onExit() end end Wait(0) end end) end, ["esx"] = function(Menu, data) for k in pairs(Menu) do Menu[k].label = Menu[k].header Menu[k].name = "button"..k end if data.canClose then table.insert(Menu, 1, { icon = "fas fa-circle-xmark", label = "Close", name = "close", onSelect = data.onExit, }) end if data.onBack then table.insert(Menu, 1, { icon = "fas fa-circle-arrow-left", label = "Return", name = "return", onSelect = data.onBack, }) end ESX.UI.Menu.Open("default", getScript(), "Example_Menu", { title = data.header, align = 'top-right', elements = Menu, }, function(menuData, menu) for k in pairs(Menu) do if menuData.current.name == Menu[k].name then menu.close() Wait(10) Menu[k].onSelect() end end end, function(data, menu) menu.close() end) end, ["lation"] = function(Menu, data) if data.onBack then table.insert(Menu, 1, { icon = "fas fa-circle-arrow-left", onSelect = data.onBack, header = "Return", }) end for k in pairs(Menu) do if data.onSelected and Menu[k].arrow then Menu[k].icon = "fas fa-angle-right" end -- If no title, use header or txt as title/label. if not Menu[k].title then if Menu[k].header ~= nil and Menu[k].header ~= "" then Menu[k].title = Menu[k].header Menu[k].label = Menu[k].header if Menu[k].txt then Menu[k].description = Menu[k].txt else Menu[k].description = "" end else Menu[k].title = Menu[k].txt Menu[k].label = Menu[k].txt end end -- Copy parameters from 'params' if available. if Menu[k].params then Menu[k].event = Menu[k].params.event Menu[k].args = Menu[k].params.args or {} end if Menu[k].isMenuHeader then Menu[k].readOnly = true end end exports.lation_ui:registerMenu({ id = 'menu', title = data.header, onExit = data.onExit and data.onExit or nil, subtitle = (data.headertxt and data.headertxt or ""), options = Menu, }) -- Show menu exports.lation_ui:showMenu('menu') end, } --- Opens a menu using the configured menu system. --- --- This function translates code and creates menus in several different menu scripts, depending on the configured menu system specified in `Config.System.Menu`. --- ---@param Menu table A table containing the menu options to display. --- Each menu item can include: --- - header (`string`): The text to display for the menu item. --- - txt (`string`, optional): Additional text or description. --- - icon (`string`, optional): Icon to display with the menu item. --- - onSelect (`function`, optional): Function to execute when the menu item is selected. --- - arrow (`boolean`, optional): Whether to display an arrow next to the item (for certain menus). --- - params (`table`, optional): Additional parameters, such as events and arguments. --- - isMenuHeader (`boolean`, optional): Marks the item as a header. --- - disabled (`boolean`, optional): Disables the menu item if `true`. --- ---@param data table A table containing configuration data for the menu. --- - header (`string`): The header/title of the menu. --- - headertxt (`string`, optional): Additional header text. --- - onBack (`function`, optional): Function to call when the "Return" option is selected. --- - onExit (`function`, optional): Function to call when the menu is exited. --- - onSelected (`function`, optional): Function to call when a menu item is selected (for certain menu systems). --- - canClose (`boolean`, optional): Whether the menu can be closed by the user. --- ---@usage --- ```lua --- openMenu({ --- { header = "Option 1", txt = "Description 1", onSelect = function() print("Option 1 selected") end }, --- { header = "Option 2", txt = "Description 2", onSelect = function() print("Option 2 selected") end }, --- }, { --- header = "Main Menu", --- headertxt = "Select an option", --- onBack = function() print("Return selected") end, --- onExit = function() print("Menu closed") end, --- canClose = true, --- }) --- ``` function openMenu(Menu, data) contextFunc[Config.System.Menu](Menu, data) end -- Line break conversion table, basically, to automate the linebreak in functions `br` -- This is declared and automatically sets it for what menu you are using (depends if one is uding MD formatting or HTML formatting) local lineBreakConversion = { ["ox"] = "\n", ["gta"] = "\n", ["lation"] = "\n", ["qb"] = "
", ["esx"] = "
", } --- A line break constant used for menu header formatting. br = lineBreakConversion[Config.System.Menu] --- Checks if the current menu system is 'ox' or 'gta' for formatting purposes. --- @return boolean boolean True if using ox or gta menus, otherwise false. --- @usage --- ```lua --- if isOx() then --- -- Use specific formatting --- end --- ``` function isOx() return (Config.System.Menu == "ox" or Config.System.Menu == "gta") end --- Checks if any WarMenu menu is currently open. --- --- @return boolean boolean Returns `true` if a WarMenu menu is open; otherwise, `false`. --- --- @usage --- ```lua --- if isWarMenuOpen() then --- -- Do something --- end --- ``` function isWarMenuOpen() if Config.System.Menu == "gta" then return WarMenu.IsAnyMenuOpened() else return false end end