639 lines
21 KiB
Lua
639 lines
21 KiB
Lua
|
|
----------------------- [ MenuV ] -----------------------
|
||
|
|
-- GitHub: https://github.com/ThymonA/menuv/
|
||
|
|
-- License: GNU General Public License v3.0
|
||
|
|
-- https://choosealicense.com/licenses/gpl-3.0/
|
||
|
|
-- Author: Thymon Arens <contact@arens.io>
|
||
|
|
-- Name: MenuV
|
||
|
|
-- Version: 1.0.0
|
||
|
|
-- Description: FiveM menu library for creating menu's
|
||
|
|
----------------------- [ MenuV ] -----------------------
|
||
|
|
local assert = assert
|
||
|
|
local pairs = assert(pairs)
|
||
|
|
local rawget = assert(rawget)
|
||
|
|
local rawset = assert(rawset)
|
||
|
|
local insert = assert(table.insert)
|
||
|
|
local remove = assert(table.remove)
|
||
|
|
local format = assert(string.format)
|
||
|
|
local upper = assert(string.upper)
|
||
|
|
local lower = assert(string.lower)
|
||
|
|
local setmetatable = assert(setmetatable)
|
||
|
|
|
||
|
|
--- FiveM globals
|
||
|
|
local GET_CURRENT_RESOURCE_NAME = assert(GetCurrentResourceName)
|
||
|
|
local HAS_STREAMED_TEXTURE_DICT_LOADED = assert(HasStreamedTextureDictLoaded)
|
||
|
|
local REQUEST_STREAMED_TEXTURE_DICT = assert(RequestStreamedTextureDict)
|
||
|
|
local REGISTER_KEY_MAPPING = assert(RegisterKeyMapping)
|
||
|
|
local REGISTER_COMMAND = assert(RegisterCommand)
|
||
|
|
local GET_HASH_KEY = assert(GetHashKey)
|
||
|
|
local CreateThread = assert(Citizen.CreateThread)
|
||
|
|
local Wait = assert(Citizen.Wait)
|
||
|
|
|
||
|
|
---@load 'config.lua'
|
||
|
|
---@load 'app/lua_components/utilities.lua'
|
||
|
|
---@load 'app/lua_components/item.lua'
|
||
|
|
---@load 'app/lua_components/menu.lua'
|
||
|
|
---@load 'app/lua_components/translations.lua'
|
||
|
|
|
||
|
|
--- MenuV table
|
||
|
|
local menuv_table = {
|
||
|
|
---@type string
|
||
|
|
__class = 'MenuV',
|
||
|
|
---@type string
|
||
|
|
__type = 'MenuV',
|
||
|
|
---@type Menu|nil
|
||
|
|
CurrentMenu = nil,
|
||
|
|
---@type string|nil
|
||
|
|
CurrentUpdateUUID = nil,
|
||
|
|
---@type string
|
||
|
|
CurrentResourceName = GET_CURRENT_RESOURCE_NAME(),
|
||
|
|
---@type boolean
|
||
|
|
Loaded = false,
|
||
|
|
---@type Menu[]
|
||
|
|
Menus = {},
|
||
|
|
---@type Menu[]
|
||
|
|
ParentMenus = {},
|
||
|
|
---@type table<string, function>
|
||
|
|
NUICallbacks = {},
|
||
|
|
---@type table<string, string>
|
||
|
|
Translations = translations,
|
||
|
|
---@class keys
|
||
|
|
Keys = setmetatable({ data = {}, __class = 'MenuVKeys', __type = 'keys' }, {
|
||
|
|
__index = function(t, k)
|
||
|
|
return rawget(t.data, k)
|
||
|
|
end,
|
||
|
|
__newindex = function(t, actionHax, v)
|
||
|
|
actionHax = Utilities:Ensure(actionHax, 'unknown')
|
||
|
|
|
||
|
|
if (actionHax == 'unknown') then return end
|
||
|
|
|
||
|
|
local rawKey = rawget(t.data, actionHax)
|
||
|
|
local keyExists = rawKey ~= nil
|
||
|
|
local prevState = Utilities:Ensure((rawKey or {}).status, false)
|
||
|
|
local newState = Utilities:Ensure(v, false)
|
||
|
|
|
||
|
|
if (keyExists) then
|
||
|
|
rawset(t.data[actionHax], 'status', newState)
|
||
|
|
|
||
|
|
if (prevState ~= newState and newState) then
|
||
|
|
rawKey.func(rawKey.menu)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end,
|
||
|
|
__call = function(t, actionHax, m, actionFunc, inputType)
|
||
|
|
actionHax = Utilities:Ensure(actionHax, 'unknown')
|
||
|
|
m = Utilities:Typeof(m) == 'Menu' and m or nil
|
||
|
|
actionFunc = Utilities:Ensure(actionFunc, function() end)
|
||
|
|
inputType = Utilities:Ensure(inputType, 'KEYBOARD')
|
||
|
|
inputType = upper(inputType)
|
||
|
|
|
||
|
|
if (actionHax == 'unknown') then return end
|
||
|
|
|
||
|
|
local rawKey = rawget(t.data, actionHax)
|
||
|
|
local keyExists = rawKey ~= nil
|
||
|
|
|
||
|
|
if (keyExists) then
|
||
|
|
if not rawKey.inputTypes[inputType] then
|
||
|
|
rawKey.inputTypes[inputType] = true
|
||
|
|
end
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
rawset(t.data, actionHax, { status = false, menu = m, func = actionFunc, inputTypes = { [inputType] = true } })
|
||
|
|
end
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
---@class MenuV
|
||
|
|
MenuV = setmetatable(menuv_table, {})
|
||
|
|
|
||
|
|
--- Send a NUI message to MenuV resource
|
||
|
|
---@param input any
|
||
|
|
local SEND_NUI_MESSAGE = function(input)
|
||
|
|
exports['menuv']:SendNUIMessage(input)
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Register a NUI callback event
|
||
|
|
---@param name string Name of callback
|
||
|
|
---@param cb function Callback to execute
|
||
|
|
local REGISTER_NUI_CALLBACK = function(name, cb)
|
||
|
|
name = Utilities:Ensure(name, 'unknown')
|
||
|
|
cb = Utilities:Ensure(cb, function(_, cb) cb('ok') end)
|
||
|
|
|
||
|
|
MenuV.NUICallbacks[name] = cb
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Load translation
|
||
|
|
---@param k string Translation key
|
||
|
|
---@return string Translation or 'MISSING TRANSLATION'
|
||
|
|
function MenuV:T(k)
|
||
|
|
k = Utilities:Ensure(k, 'unknown')
|
||
|
|
|
||
|
|
return Utilities:Ensure(MenuV.Translations[k], 'MISSING TRANSLATION')
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Create a `MenuV` menu
|
||
|
|
---@param title string Title of Menu
|
||
|
|
---@param subtitle string Subtitle of Menu
|
||
|
|
---@param position string Position of Menu
|
||
|
|
---@param r number 0-255 RED
|
||
|
|
---@param g number 0-255 GREEN
|
||
|
|
---@param b number 0-255 BLUE
|
||
|
|
---@param size string | "'size-100'" | "'size-110'" | "'size-125'" | "'size-150'" | "'size-175'" | "'size-200'"
|
||
|
|
---@param texture string Name of texture example: "default"
|
||
|
|
---@param dictionary string Name of dictionary example: "menuv"
|
||
|
|
---@param namespace string Namespace of Menu
|
||
|
|
---@param theme string Theme of Menu
|
||
|
|
---@return Menu
|
||
|
|
function MenuV:CreateMenu(title, subtitle, position, r, g, b, size, texture, dictionary, namespace, theme)
|
||
|
|
local menu = CreateMenu({
|
||
|
|
Theme = theme,
|
||
|
|
Title = title,
|
||
|
|
Subtitle = subtitle,
|
||
|
|
Position = position,
|
||
|
|
R = r,
|
||
|
|
G = g,
|
||
|
|
B = b,
|
||
|
|
Size = size,
|
||
|
|
Texture = texture,
|
||
|
|
Dictionary = dictionary,
|
||
|
|
Namespace = namespace
|
||
|
|
})
|
||
|
|
|
||
|
|
local index = #(self.Menus or {}) + 1
|
||
|
|
|
||
|
|
insert(self.Menus, index, menu)
|
||
|
|
|
||
|
|
return self.Menus[index] or menu
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Create a menu that inherits properties from another menu
|
||
|
|
---@param parent Menu|string Menu or UUID of menu
|
||
|
|
---@param overrides table<string, string|number> Properties to override in menu object (ignore parent)
|
||
|
|
---@param namespace string Namespace of menu
|
||
|
|
function MenuV:InheritMenu(parent, overrides, namespace)
|
||
|
|
overrides = Utilities:Ensure(overrides, {})
|
||
|
|
|
||
|
|
local uuid = Utilities:Typeof(parent) == 'Menu' and parent.UUID or Utilities:Typeof(parent) == 'string' and parent
|
||
|
|
|
||
|
|
if (uuid == nil) then return end
|
||
|
|
|
||
|
|
local parentMenu = self:GetMenu(uuid)
|
||
|
|
|
||
|
|
if (parentMenu == nil) then return end
|
||
|
|
|
||
|
|
local menu = CreateMenu({
|
||
|
|
Theme = Utilities:Ensure(overrides.theme or overrides.Theme, parentMenu.Theme),
|
||
|
|
Title = Utilities:Ensure(overrides.title or overrides.Title, parentMenu.Title),
|
||
|
|
Subtitle = Utilities:Ensure(overrides.subtitle or overrides.Subtitle, parentMenu.Subtitle),
|
||
|
|
Position = Utilities:Ensure(overrides.position or overrides.Position, parentMenu.Position),
|
||
|
|
R = Utilities:Ensure(overrides.r or overrides.R, parentMenu.Color.R),
|
||
|
|
G = Utilities:Ensure(overrides.g or overrides.G, parentMenu.Color.G),
|
||
|
|
B = Utilities:Ensure(overrides.b or overrides.B, parentMenu.Color.B),
|
||
|
|
Size = Utilities:Ensure(overrides.size or overrides.Size, parentMenu.Size),
|
||
|
|
Texture = Utilities:Ensure(overrides.texture or overrides.Texture, parentMenu.Texture),
|
||
|
|
Dictionary = Utilities:Ensure(overrides.dictionary or overrides.Dictionary, parentMenu.Dictionary),
|
||
|
|
Namespace = Utilities:Ensure(namespace, 'unknown')
|
||
|
|
})
|
||
|
|
|
||
|
|
local index = #(self.Menus or {}) + 1
|
||
|
|
|
||
|
|
insert(self.Menus, index, menu)
|
||
|
|
|
||
|
|
return self.Menus[index] or menu
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Load a menu based on `uuid`
|
||
|
|
---@param uuid string UUID of menu
|
||
|
|
---@return Menu|nil Founded menu or `nil`
|
||
|
|
function MenuV:GetMenu(uuid)
|
||
|
|
uuid = Utilities:Ensure(uuid, '00000000-0000-0000-0000-000000000000')
|
||
|
|
|
||
|
|
for _, v in pairs(self.Menus) do
|
||
|
|
if (v.UUID == uuid) then
|
||
|
|
return v
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return nil
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Open a menu
|
||
|
|
---@param menu Menu|string Menu or UUID of Menu
|
||
|
|
---@param cb function Execute this callback when menu has opened
|
||
|
|
function MenuV:OpenMenu(menu, cb, reopen)
|
||
|
|
local uuid = Utilities:Typeof(menu) == 'Menu' and menu.UUID or Utilities:Typeof(menu) == 'string' and menu
|
||
|
|
|
||
|
|
if (uuid == nil) then return end
|
||
|
|
|
||
|
|
cb = Utilities:Ensure(cb, function() end)
|
||
|
|
|
||
|
|
menu = self:GetMenu(uuid)
|
||
|
|
|
||
|
|
if (menu == nil) then return end
|
||
|
|
|
||
|
|
local dictionaryLoaded = HAS_STREAMED_TEXTURE_DICT_LOADED(menu.Dictionary)
|
||
|
|
|
||
|
|
if (not self.Loaded or not dictionaryLoaded) then
|
||
|
|
if (not dictionaryLoaded) then REQUEST_STREAMED_TEXTURE_DICT(menu.Dictionary) end
|
||
|
|
|
||
|
|
CreateThread(function()
|
||
|
|
repeat Wait(0) until MenuV.Loaded
|
||
|
|
|
||
|
|
if (not dictionaryLoaded) then
|
||
|
|
repeat Wait(10) until HAS_STREAMED_TEXTURE_DICT_LOADED(menu.Dictionary)
|
||
|
|
end
|
||
|
|
|
||
|
|
MenuV:OpenMenu(uuid, cb)
|
||
|
|
end)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if (self.CurrentMenu ~= nil) then
|
||
|
|
insert(self.ParentMenus, self.CurrentMenu)
|
||
|
|
|
||
|
|
self.CurrentMenu:RemoveOnEvent('update', self.CurrentUpdateUUID)
|
||
|
|
self.CurrentMenu:DestroyThreads()
|
||
|
|
end
|
||
|
|
|
||
|
|
self.CurrentMenu = menu
|
||
|
|
self.CurrentUpdateUUID = menu:On('update', function(m, k, v)
|
||
|
|
k = Utilities:Ensure(k, 'unknown')
|
||
|
|
|
||
|
|
if (k == 'Title' or k == 'title') then
|
||
|
|
SEND_NUI_MESSAGE({ action = 'UPDATE_TITLE', title = Utilities:Ensure(v, 'MenuV'), __uuid = m.UUID })
|
||
|
|
elseif (k == 'Subtitle' or k == 'subtitle') then
|
||
|
|
SEND_NUI_MESSAGE({ action = 'UPDATE_SUBTITLE', subtitle = Utilities:Ensure(v, ''), __uuid = m.UUID })
|
||
|
|
elseif (k == 'Items' or k == 'items') then
|
||
|
|
SEND_NUI_MESSAGE({ action = 'UPDATE_ITEMS', items = (m.Items:ToTable() or {}), __uuid = m.UUID })
|
||
|
|
elseif (k == 'Item' or k == 'item' and Utilities:Typeof(v) == 'Item') then
|
||
|
|
SEND_NUI_MESSAGE({ action = 'UPDATE_ITEM', item = m.Items:ItemToTable(v) or {}, __uuid = m.UUID })
|
||
|
|
elseif (k == 'AddItem' or k == 'additem' and Utilities:Typeof(v) == 'Item') then
|
||
|
|
SEND_NUI_MESSAGE({ action = 'ADD_ITEM', item = m.Items:ItemToTable(v), __uuid = m.UUID })
|
||
|
|
elseif (k == 'RemoveItem' or k == 'removeitem' and Utilities:Typeof(v) == 'Item') then
|
||
|
|
SEND_NUI_MESSAGE({ action = 'REMOVE_ITEM', uuid = v.UUID, __uuid = m.UUID })
|
||
|
|
elseif (k == 'UpdateItem' or k == 'updateitem' and Utilities:Typeof(v) == 'Item') then
|
||
|
|
SEND_NUI_MESSAGE({ action = 'UPDATE_ITEM', item = m.Items:ItemToTable(v) or {}, __uuid = m.UUID })
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
SEND_NUI_MESSAGE({
|
||
|
|
action = 'OPEN_MENU',
|
||
|
|
menu = menu:ToTable(),
|
||
|
|
reopen = Utilities:Ensure(reopen, false)
|
||
|
|
})
|
||
|
|
|
||
|
|
cb()
|
||
|
|
end
|
||
|
|
|
||
|
|
function MenuV:Refresh()
|
||
|
|
if (self.CurrentMenu == nil) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
SEND_NUI_MESSAGE({
|
||
|
|
action = 'REFRESH_MENU',
|
||
|
|
menu = self.CurrentMenu:ToTable()
|
||
|
|
})
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Close a menu
|
||
|
|
---@param menu Menu|string Menu or UUID of Menu
|
||
|
|
---@param cb function Execute this callback when menu has is closed or parent menu has opened
|
||
|
|
function MenuV:CloseMenu(menu, cb)
|
||
|
|
local uuid = Utilities:Typeof(menu) == 'Menu' and menu.UUID or Utilities:Typeof(menu) == 'string' and menu
|
||
|
|
|
||
|
|
if (uuid == nil) then cb() return end
|
||
|
|
|
||
|
|
cb = Utilities:Ensure(cb, function() end)
|
||
|
|
menu = self:GetMenu(uuid)
|
||
|
|
|
||
|
|
if (menu == nil or self.CurrentMenu == nil or self.CurrentMenu.UUID ~= uuid) then cb() return end
|
||
|
|
|
||
|
|
self.CurrentMenu:RemoveOnEvent('update', self.CurrentUpdateUUID)
|
||
|
|
self.CurrentMenu:Trigger('close')
|
||
|
|
self.CurrentMenu:DestroyThreads()
|
||
|
|
self.CurrentMenu = nil
|
||
|
|
|
||
|
|
SEND_NUI_MESSAGE({ action = 'CLOSE_MENU', uuid = uuid })
|
||
|
|
|
||
|
|
if (#self.ParentMenus <= 0) then cb() return end
|
||
|
|
|
||
|
|
local prev_index = #self.ParentMenus
|
||
|
|
local prev_menu = self.ParentMenus[prev_index] or nil
|
||
|
|
|
||
|
|
if (prev_menu == nil) then cb() return end
|
||
|
|
|
||
|
|
remove(self.ParentMenus, prev_index)
|
||
|
|
|
||
|
|
self:OpenMenu(prev_menu, function()
|
||
|
|
cb()
|
||
|
|
end, true)
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Close all menus
|
||
|
|
---@param cb function Execute this callback when all menus are closed
|
||
|
|
function MenuV:CloseAll(cb)
|
||
|
|
cb = Utilities:Ensure(cb, function() end)
|
||
|
|
|
||
|
|
if (not self.Loaded) then
|
||
|
|
CreateThread(function()
|
||
|
|
repeat Wait(0) until MenuV.Loaded
|
||
|
|
|
||
|
|
MenuV:CloseAll(cb)
|
||
|
|
end)
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if (self.CurrentMenu == nil) then cb() return end
|
||
|
|
|
||
|
|
local uuid = Utilities:Ensure(self.CurrentMenu.UUID, '00000000-0000-0000-0000-000000000000')
|
||
|
|
|
||
|
|
self.CurrentMenu:RemoveOnEvent('update', self.CurrentUpdateUUID)
|
||
|
|
self.CurrentMenu:Trigger('close')
|
||
|
|
self.CurrentMenu:DestroyThreads()
|
||
|
|
|
||
|
|
SEND_NUI_MESSAGE({ action = 'CLOSE_MENU', uuid = uuid })
|
||
|
|
|
||
|
|
self.CurrentMenu = nil
|
||
|
|
self.ParentMenus = {}
|
||
|
|
|
||
|
|
cb()
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Register keybind for specific menu
|
||
|
|
---@param menu Menu|string MenuV menu
|
||
|
|
---@param action string Name of action
|
||
|
|
---@param func function This will be executed
|
||
|
|
---@param description string Key description
|
||
|
|
---@param defaultType string Default key type
|
||
|
|
---@param defaultKey string Default key
|
||
|
|
function MenuV:AddControlKey(menu, action, func, description, defaultType, defaultKey)
|
||
|
|
local uuid = Utilities:Typeof(menu) == 'Menu' and menu.UUID or Utilities:Typeof(menu) == 'string' and menu
|
||
|
|
|
||
|
|
action = Utilities:Ensure(action, 'UNKNOWN')
|
||
|
|
func = Utilities:Ensure(func, function() end)
|
||
|
|
description = Utilities:Ensure(description, 'unknown')
|
||
|
|
defaultType = Utilities:Ensure(defaultType, 'KEYBOARD')
|
||
|
|
defaultType = upper(defaultType)
|
||
|
|
defaultKey = Utilities:Ensure(defaultKey, 'F12')
|
||
|
|
|
||
|
|
local m = self:GetMenu(uuid)
|
||
|
|
|
||
|
|
if (m == nil) then return end
|
||
|
|
|
||
|
|
if (Utilities:Typeof(m.Namespace) ~= 'string' or m.Namespace == 'unknown') then
|
||
|
|
error('[MenuV] Namespace is required for assigning keys.')
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
action = Utilities:Replace(action, ' ', '_')
|
||
|
|
action = upper(action)
|
||
|
|
|
||
|
|
local resourceName = Utilities:Ensure(self.CurrentResourceName, 'unknown')
|
||
|
|
local namespace = Utilities:Ensure(m.Namespace, 'unknown')
|
||
|
|
local actionHash = GET_HASH_KEY(('%s_%s_%s'):format(resourceName, namespace, action))
|
||
|
|
local actionHax = format('%x', actionHash)
|
||
|
|
|
||
|
|
local typeGroup = Utilities:GetInputTypeGroup(defaultType)
|
||
|
|
|
||
|
|
if (self.Keys[actionHax] and self.Keys[actionHax].inputTypes[typeGroup]) then return end
|
||
|
|
|
||
|
|
self.Keys(actionHax, m, func, typeGroup)
|
||
|
|
|
||
|
|
local k = actionHax
|
||
|
|
|
||
|
|
if typeGroup > 0 then
|
||
|
|
local inputGroupName = Utilities:GetInputGroupName(typeGroup)
|
||
|
|
k = ('%s_%s'):format(lower(inputGroupName), k)
|
||
|
|
end
|
||
|
|
|
||
|
|
REGISTER_KEY_MAPPING(('+%s'):format(k), description, defaultType, defaultKey)
|
||
|
|
REGISTER_COMMAND(('+%s'):format(k), function() MenuV.Keys[actionHax] = true end)
|
||
|
|
REGISTER_COMMAND(('-%s'):format(k), function() MenuV.Keys[actionHax] = false end)
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Checks if namespace is available
|
||
|
|
---@param namespace string Namespace
|
||
|
|
---@return boolean Returns `true` if given namespace is available
|
||
|
|
function MenuV:IsNamespaceAvailable(namespace)
|
||
|
|
namespace = lower(Utilities:Ensure(namespace, 'unknown'))
|
||
|
|
|
||
|
|
if (namespace == 'unknown') then return true end
|
||
|
|
|
||
|
|
---@param v Menu
|
||
|
|
for k, v in pairs(self.Menus or {}) do
|
||
|
|
local v_namespace = Utilities:Ensure(v.Namespace, 'unknown')
|
||
|
|
|
||
|
|
if (namespace == lower(v_namespace)) then
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
--- Mark MenuV as loaded when `main` resource is loaded
|
||
|
|
exports['menuv']:IsLoaded(function()
|
||
|
|
MenuV.Loaded = true
|
||
|
|
end)
|
||
|
|
|
||
|
|
--- Register callback handler for MenuV
|
||
|
|
exports('NUICallback', function(name, info, cb)
|
||
|
|
name = Utilities:Ensure(name, 'unknown')
|
||
|
|
|
||
|
|
if (MenuV.NUICallbacks == nil or MenuV.NUICallbacks[name] == nil) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
MenuV.NUICallbacks[name](info, cb)
|
||
|
|
end)
|
||
|
|
|
||
|
|
REGISTER_NUI_CALLBACK('open', function(info, cb)
|
||
|
|
local uuid = Utilities:Ensure(info.uuid, '00000000-0000-0000-0000-000000000000')
|
||
|
|
local new_uuid = Utilities:Ensure(info.new_uuid, '00000000-0000-0000-0000-000000000000')
|
||
|
|
|
||
|
|
cb('ok')
|
||
|
|
|
||
|
|
if (MenuV.CurrentMenu == nil or MenuV.CurrentMenu.UUID == uuid or MenuV.CurrentMenu.UUID == new_uuid) then return end
|
||
|
|
|
||
|
|
for _, v in pairs(MenuV.ParentMenus) do
|
||
|
|
if (v.UUID == uuid) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
MenuV.CurrentMenu:RemoveOnEvent('update', MenuV.CurrentUpdateUUID)
|
||
|
|
MenuV.CurrentMenu:Trigger('close')
|
||
|
|
MenuV.CurrentMenu:DestroyThreads()
|
||
|
|
MenuV.CurrentMenu = nil
|
||
|
|
MenuV.ParentMenus = {}
|
||
|
|
end)
|
||
|
|
|
||
|
|
REGISTER_NUI_CALLBACK('opened', function(info, cb)
|
||
|
|
local uuid = Utilities:Ensure(info.uuid, '00000000-0000-0000-0000-000000000000')
|
||
|
|
|
||
|
|
cb('ok')
|
||
|
|
|
||
|
|
if (MenuV.CurrentMenu == nil or MenuV.CurrentMenu.UUID ~= uuid) then return end
|
||
|
|
|
||
|
|
MenuV.CurrentMenu:Trigger('open')
|
||
|
|
end)
|
||
|
|
|
||
|
|
REGISTER_NUI_CALLBACK('submit', function(info, cb)
|
||
|
|
local uuid = Utilities:Ensure(info.uuid, '00000000-0000-0000-0000-000000000000')
|
||
|
|
|
||
|
|
cb('ok')
|
||
|
|
|
||
|
|
if (MenuV.CurrentMenu == nil) then return end
|
||
|
|
|
||
|
|
for k, v in pairs(MenuV.CurrentMenu.Items) do
|
||
|
|
if (v.UUID == uuid) then
|
||
|
|
if (v.__type == 'confirm' or v.__type == 'checkbox') then
|
||
|
|
v.Value = Utilities:Ensure(info.value, false)
|
||
|
|
elseif (v.__type == 'range') then
|
||
|
|
v.Value = Utilities:Ensure(info.value, v.Min)
|
||
|
|
elseif (v.__type == 'slider') then
|
||
|
|
v.Value = Utilities:Ensure(info.value, 0) + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
MenuV.CurrentMenu:Trigger('select', v)
|
||
|
|
|
||
|
|
if (v.__type == 'button' or v.__type == 'menu') then
|
||
|
|
MenuV.CurrentMenu.Items[k]:Trigger('select')
|
||
|
|
elseif (v.__type == 'range') then
|
||
|
|
MenuV.CurrentMenu.Items[k]:Trigger('select', v.Value)
|
||
|
|
elseif (v.__type == 'slider') then
|
||
|
|
local option = MenuV.CurrentMenu.Items[k].Values[v.Value] or nil
|
||
|
|
|
||
|
|
if (option == nil) then return end
|
||
|
|
|
||
|
|
MenuV.CurrentMenu.Items[k]:Trigger('select', option.Value)
|
||
|
|
end
|
||
|
|
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
REGISTER_NUI_CALLBACK('close', function(info, cb)
|
||
|
|
local uuid = Utilities:Ensure(info.uuid, '00000000-0000-0000-0000-000000000000')
|
||
|
|
|
||
|
|
if (MenuV.CurrentMenu == nil or MenuV.CurrentMenu.UUID ~= uuid) then cb('ok') return end
|
||
|
|
|
||
|
|
MenuV.CurrentMenu:RemoveOnEvent('update', MenuV.CurrentUpdateUUID)
|
||
|
|
MenuV.CurrentMenu:Trigger('close')
|
||
|
|
MenuV.CurrentMenu:DestroyThreads()
|
||
|
|
MenuV.CurrentMenu = nil
|
||
|
|
|
||
|
|
if (#MenuV.ParentMenus <= 0) then cb('ok') return end
|
||
|
|
|
||
|
|
local prev_index = #MenuV.ParentMenus
|
||
|
|
local prev_menu = MenuV.ParentMenus[prev_index] or nil
|
||
|
|
|
||
|
|
if (prev_menu == nil) then cb('ok') return end
|
||
|
|
|
||
|
|
remove(MenuV.ParentMenus, prev_index)
|
||
|
|
|
||
|
|
MenuV:OpenMenu(prev_menu, function()
|
||
|
|
cb('ok')
|
||
|
|
end, true)
|
||
|
|
end)
|
||
|
|
|
||
|
|
REGISTER_NUI_CALLBACK('close_all', function(info, cb)
|
||
|
|
if (MenuV.CurrentMenu == nil) then
|
||
|
|
for _, parentMenu in ipairs(MenuV.ParentMenus) do
|
||
|
|
parentMenu:Trigger('close')
|
||
|
|
end
|
||
|
|
MenuV.ParentMenus = {}
|
||
|
|
|
||
|
|
cb('ok')
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
MenuV.CurrentMenu:RemoveOnEvent('update', MenuV.CurrentUpdateUUID)
|
||
|
|
MenuV.CurrentMenu:Trigger('close')
|
||
|
|
MenuV.CurrentMenu:DestroyThreads()
|
||
|
|
MenuV.CurrentMenu = nil
|
||
|
|
for _, parentMenu in ipairs(MenuV.ParentMenus) do
|
||
|
|
parentMenu:Trigger('close')
|
||
|
|
end
|
||
|
|
MenuV.ParentMenus = {}
|
||
|
|
|
||
|
|
cb('ok')
|
||
|
|
end)
|
||
|
|
|
||
|
|
REGISTER_NUI_CALLBACK('switch', function(info, cb)
|
||
|
|
local prev_uuid = Utilities:Ensure(info.prev, '00000000-0000-0000-0000-000000000000')
|
||
|
|
local next_uuid = Utilities:Ensure(info.next, '00000000-0000-0000-0000-000000000000')
|
||
|
|
local prev_item, next_item = nil, nil
|
||
|
|
|
||
|
|
cb('ok')
|
||
|
|
|
||
|
|
if (MenuV.CurrentMenu == nil) then return end
|
||
|
|
|
||
|
|
for k, v in pairs(MenuV.CurrentMenu.Items) do
|
||
|
|
if (v.UUID == prev_uuid) then
|
||
|
|
prev_item = v
|
||
|
|
|
||
|
|
MenuV.CurrentMenu.Items[k]:Trigger('leave')
|
||
|
|
end
|
||
|
|
|
||
|
|
if (v.UUID == next_uuid) then
|
||
|
|
next_item = v
|
||
|
|
|
||
|
|
MenuV.CurrentMenu.Items[k]:Trigger('enter')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (prev_item ~= nil and next_item ~= nil) then
|
||
|
|
MenuV.CurrentMenu:Trigger('switch', next_item, prev_item)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
REGISTER_NUI_CALLBACK('update', function(info, cb)
|
||
|
|
local uuid = Utilities:Ensure(info.uuid, '00000000-0000-0000-0000-000000000000')
|
||
|
|
|
||
|
|
cb('ok')
|
||
|
|
|
||
|
|
if (MenuV.CurrentMenu == nil) then return end
|
||
|
|
|
||
|
|
for k, v in pairs(MenuV.CurrentMenu.Items) do
|
||
|
|
if (v.UUID == uuid) then
|
||
|
|
local newValue, oldValue = nil, nil
|
||
|
|
|
||
|
|
if (v.__type == 'confirm' or v.__type == 'checkbox') then
|
||
|
|
newValue = Utilities:Ensure(info.now, false)
|
||
|
|
oldValue = Utilities:Ensure(info.prev, false)
|
||
|
|
elseif (v.__type == 'range') then
|
||
|
|
newValue = Utilities:Ensure(info.now, v.Min)
|
||
|
|
oldValue = Utilities:Ensure(info.prev, v.Min)
|
||
|
|
elseif (v.__type == 'slider') then
|
||
|
|
newValue = Utilities:Ensure(info.now, 0) + 1
|
||
|
|
oldValue = Utilities:Ensure(info.prev, 0) + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
if (Utilities:Any(v.__type, { 'button', 'menu', 'label' }, 'value')) then return end
|
||
|
|
|
||
|
|
MenuV.CurrentMenu:Trigger('update', v, newValue, oldValue)
|
||
|
|
MenuV.CurrentMenu.Items[k]:Trigger('change', newValue, oldValue)
|
||
|
|
|
||
|
|
if (v.SaveOnUpdate) then
|
||
|
|
MenuV.CurrentMenu.Items[k].Value = newValue
|
||
|
|
|
||
|
|
if (v.__type == 'range') then
|
||
|
|
MenuV.CurrentMenu.Items[k]:Trigger('select', v.Value)
|
||
|
|
elseif (v.__type == 'slider') then
|
||
|
|
local option = MenuV.CurrentMenu.Items[k].Values[v.Value] or nil
|
||
|
|
|
||
|
|
if (option == nil) then return end
|
||
|
|
|
||
|
|
MenuV.CurrentMenu.Items[k]:Trigger('select', option.Value)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end)
|