Files
ox_lib/resource/interface/client/radial.lua
Linden bce10d0980 feat(client/radial): radial menu history and radial id getter
Store an array containing the history of opened menus, and restore
the previous menu when closing out of nested menus.
Added lib.getCurrentRadialId and improved types.
2023-02-23 22:46:22 +11:00

216 lines
4.7 KiB
Lua

---@class RadialMenuItem
---@field id string
---@field icon string
---@field label string
---@field menu? string
---@field onSelect? function
---@class RadialMenuProps
---@field id string
---@field items RadialMenuItem[]
local isOpen = false
---@type table<string, RadialMenuProps>
local menus = {}
---@type RadialMenuItem[]
local menuItems = {}
---@type string[]
local menuHistory = {}
---@type RadialMenuProps?
local currentRadial = nil
---Registers a radial sub menu with predefined options.
---@param radial RadialMenuProps
function lib.registerRadial(radial)
menus[radial.id] = radial
end
function lib.getCurrentRadialId()
return currentRadial and currentRadial.id
end
---Open a registered radial submenu with the given id.
---@param id string
local function showRadial(id)
local radial = menus[id]
if not radial then return error('No radial menu with such id found.') end
currentRadial = radial
-- Hide current menu and allow for transition
SendNUIMessage({
action = 'openRadialMenu',
data = false
})
Wait(100)
-- If menu was closed during transition, don't open the submenu
if not isOpen then return end
SendNUIMessage({
action = 'openRadialMenu',
data = {
items = radial.items,
sub = true
}
})
end
function lib.hideRadial()
if not isOpen then return end
SendNUIMessage({
action = 'openRadialMenu',
data = false
})
SetNuiFocus(false, false)
table.wipe(menuHistory)
isOpen = false
currentRadial = nil
end
---Registers an item or array of items in the global radial menu.
---@param items RadialMenuItem | RadialMenuItem[]
function lib.addRadialItem(items)
local menuSize = #menuItems
local invokingResource = GetInvokingResource()
if table.type(items) == 'array' then
for i = 1, #items do
local item = items[i]
item.resource = invokingResource
menuSize += 1
menuItems[menuSize] = item
end
else
items.resource = invokingResource
menuItems[menuSize + 1] = items
end
if isOpen and not currentRadial then
SendNUIMessage({
action = 'refreshItems',
data = menuItems
})
end
end
---Removes an item from the global radial menu with the given id.
---@param id string
function lib.removeRadialItem(id)
for i = 1, #menuItems do
local item = menuItems[i]
if item.id == id then
table.remove(menuItems, i)
break
end
end
if isOpen and not currentRadial then
SendNUIMessage({
action = 'refreshItems',
data = menuItems
})
end
end
RegisterNUICallback('radialClick', function(index, cb)
cb(1)
local item = (currentRadial and currentRadial.items or menuItems)[index + 1]
if item.menu then
if currentRadial then
menuHistory[#menuHistory + 1] = currentRadial.id
end
showRadial(item.menu)
else
lib.hideRadial()
end
if item.onSelect then item.onSelect() end
end)
RegisterNUICallback('radialBack', function(_, cb)
cb(1)
local numHistory = #menuHistory
local lastMenu = numHistory > 0 and menuHistory[numHistory]
if lastMenu then
menuHistory[numHistory] = nil
return showRadial(lastMenu)
end
currentRadial = nil
SendNUIMessage({
action = 'openRadialMenu',
data = {
items = menuItems
}
})
end)
RegisterNUICallback('radialClose', function(_, cb)
cb(1)
if not isOpen then return end
SetNuiFocus(false, false)
isOpen = false
currentRadial = nil
end)
lib.addKeybind({
name = 'ox_lib-radial',
description = 'Open radial menu',
defaultKey = 'z',
onPressed = function()
if isOpen then
return lib.hideRadial()
end
if #menuItems == 0 or IsNuiFocused() or IsPauseMenuActive() then return end
isOpen = true
SendNUIMessage({
action = 'openRadialMenu',
data = {
items = menuItems
}
})
SetNuiFocus(true, true)
SetNuiFocusKeepInput(true)
SetCursorLocation(0.5, 0.5)
while isOpen do
DisablePlayerFiring(cache.playerId, true)
DisableControlAction(0, 1, true)
DisableControlAction(0, 2, true)
Wait(0)
end
end,
-- onReleased = lib.hideRadial,
})
AddEventHandler('onClientResourceStop', function(resource)
for i = #menuItems, 1, -1 do
local item = menuItems[i]
if item.resource == resource then
table.remove(menuItems, i)
end
end
end)