diff --git a/localization/en-us.lua b/localization/en-us.lua index 8df7f5fc..5baea84c 100644 --- a/localization/en-us.lua +++ b/localization/en-us.lua @@ -1113,6 +1113,9 @@ return { "Once per Ante", "Off", }, + k_sc_title = "SHORTCUTS", + k_sc_hint = "Press key or release TAB to close", + b_sc_choose_deck = "Choose Deck/Stake", loc_ready = "Ready for PvP", loc_selecting = "Selecting a Blind", loc_shop = "Shopping", diff --git a/ui/shortcuts_menu.lua b/ui/shortcuts_menu.lua new file mode 100644 index 00000000..1c4b4818 --- /dev/null +++ b/ui/shortcuts_menu.lua @@ -0,0 +1,277 @@ +-- TAB-hold shortcuts menu +-- Shows a context-aware overlay of quick actions while TAB is held + +MP.SHORTCUTS = { + visible = false, + ui = nil, +} + +-- Build the list of available shortcuts based on current state +local function get_shortcuts() + local shortcuts = {} + local in_lobby = MP.LOBBY.code ~= nil + local connected = MP.LOBBY.connected + local in_menu = G.STAGE == G.STAGES.MAIN_MENU + + if in_menu then + if in_lobby then + table.insert(shortcuts, { + label = localize("b_copy_code"), + key = "C", + action = function() + MP.UTILS.copy_to_clipboard(MP.LOBBY.code) + end, + }) + table.insert(shortcuts, { + label = localize("b_view_code"), + key = "V", + action = function() + MP.UI.UTILS.overlay_message(MP.LOBBY.code) + end, + }) + if MP.LOBBY.is_host or MP.LOBBY.config.different_decks then + table.insert(shortcuts, { + label = localize("b_sc_choose_deck"), + key = "D", + action = function() + G.FUNCS.lobby_choose_deck({ config = {} }) + end, + }) + end + table.insert(shortcuts, { + label = localize("b_leave_lobby"), + key = "L", + action = function() + G.FUNCS.lobby_leave() + end, + }) + elseif connected then + table.insert(shortcuts, { + label = localize("b_join_lobby_clipboard"), + key = "V", + action = function() + G.FUNCS.join_from_clipboard() + end, + }) + table.insert(shortcuts, { + label = localize("b_join_lobby"), + key = "J", + action = function() + G.FUNCS.join_lobby() + end, + }) + table.insert(shortcuts, { + label = localize("b_create_lobby"), + key = "C", + action = function() + G.FUNCS.create_lobby() + end, + }) + else + table.insert(shortcuts, { + label = localize("b_reconnect"), + key = "R", + action = function() + G.FUNCS.reconnect() + end, + }) + end + end + + return shortcuts +end + +-- Create the UI definition for the shortcuts overlay +local function create_shortcuts_ui(shortcuts) + local rows = {} + + -- Header + table.insert(rows, { + n = G.UIT.R, + config = { align = "cm", padding = 0.08 }, + nodes = { + { + n = G.UIT.T, + config = { + text = localize("k_sc_title"), + scale = 0.5, + colour = G.C.UI.TEXT_LIGHT, + shadow = true, + }, + }, + }, + }) + + -- Shortcut rows + for _, sc in ipairs(shortcuts) do + table.insert(rows, { + n = G.UIT.R, + config = { + align = "cm", + padding = 0.04, + r = 0.08, + colour = G.C.L_BLACK, + hover = true, + button = "mp_shortcut_exec", + ref_table = sc, + }, + nodes = { + { + n = G.UIT.C, + config = { align = "cm", minw = 1 }, + nodes = { + { + n = G.UIT.R, + config = { + align = "cm", + padding = 0.04, + r = 0.05, + colour = G.C.PURPLE, + minw = 0.6, + }, + nodes = { + { + n = G.UIT.T, + config = { + text = sc.key, + scale = 0.4, + colour = G.C.UI.TEXT_LIGHT, + shadow = true, + }, + }, + }, + }, + }, + }, + { + n = G.UIT.C, + config = { align = "cl", minw = 3.5 }, + nodes = { + { + n = G.UIT.T, + config = { + text = " " .. sc.label, + scale = 0.38, + colour = G.C.UI.TEXT_LIGHT, + }, + }, + }, + }, + }, + }) + end + + -- Footer hint + table.insert(rows, { + n = G.UIT.R, + config = { align = "cm", padding = 0.06 }, + nodes = { + { + n = G.UIT.T, + config = { + text = localize("k_sc_hint"), + scale = 0.3, + colour = G.C.UI.TEXT_INACTIVE, + }, + }, + }, + }) + + return { + n = G.UIT.ROOT, + config = { + align = "cl", + colour = { 0, 0, 0, 0.4 }, + r = 0.15, + padding = 0.15, + minw = 5, + }, + nodes = { + { + n = G.UIT.C, + config = { align = "cl", padding = 0.05 }, + nodes = rows, + }, + }, + } +end + +function G.FUNCS.mp_shortcut_exec(e) + if e.config.ref_table and e.config.ref_table.action then + MP.SHORTCUTS.hide() + e.config.ref_table.action() + end +end + +function MP.SHORTCUTS.show() + if MP.SHORTCUTS.visible then return end + + local shortcuts = get_shortcuts() + if #shortcuts == 0 then return end + + MP.SHORTCUTS.visible = true + MP.SHORTCUTS.current_shortcuts = shortcuts + + MP.SHORTCUTS.ui = UIBox({ + definition = create_shortcuts_ui(shortcuts), + config = { + align = "cm", + offset = { x = -5, y = 0 }, + major = G.ROOM_ATTACH, + bond = "Weak", + }, + }) +end + +function MP.SHORTCUTS.hide() + if not MP.SHORTCUTS.visible then return end + + MP.SHORTCUTS.visible = false + if MP.SHORTCUTS.ui then + MP.SHORTCUTS.ui:remove() + MP.SHORTCUTS.ui = nil + end + MP.SHORTCUTS.current_shortcuts = nil +end + +-- Execute a shortcut by its key letter +function MP.SHORTCUTS.execute_key(key) + if not MP.SHORTCUTS.current_shortcuts then return false end + + local upper_key = string.upper(key) + for _, sc in ipairs(MP.SHORTCUTS.current_shortcuts) do + if sc.key == upper_key then + MP.SHORTCUTS.hide() + sc.action() + return true + end + end + return false +end + +-- Hook into Controller to detect TAB press and shortcut key presses +local key_press_update_ref = Controller.key_press_update +function Controller:key_press_update(key, dt) + -- Intercept shortcut key presses while menu is visible + if MP.SHORTCUTS.visible and #key == 1 then + if MP.SHORTCUTS.execute_key(key) then + return + end + end + + if key == "tab" then + if not G.OVERLAY_MENU then + MP.SHORTCUTS.show() + return + end + end + key_press_update_ref(self, key, dt) +end + +local key_release_update_ref = Controller.key_release_update +function Controller:key_release_update(key, dt) + if key == "tab" then + MP.SHORTCUTS.hide() + end + key_release_update_ref(self, key, dt) +end