feat: menu items now accept selectable
and align
options
Allows creating placeholder items like "Empty" that can't be selected or clicked.
This commit is contained in:
parent
9c544bf565
commit
128c76c3ba
|
@ -428,6 +428,8 @@ Command {
|
|||
value: string | string[];
|
||||
bold?: boolean;
|
||||
italic?: boolean;
|
||||
align?: 'left'|'center'|'right';
|
||||
selectable?: boolean;
|
||||
muted?: boolean;
|
||||
active?: integer;
|
||||
keep_open?: boolean;
|
||||
|
|
|
@ -617,7 +617,7 @@ end
|
|||
function select_current_chapter()
|
||||
local current_chapter
|
||||
if state.time and state.chapters then
|
||||
_, current_chapter = itable_find(state.chapters, function(c) return state.time >= c.time end, true)
|
||||
_, current_chapter = itable_find(state.chapters, function(c) return state.time >= c.time end, #state.chapters, 1)
|
||||
end
|
||||
set_state('current_chapter', current_chapter)
|
||||
end
|
||||
|
|
|
@ -3,13 +3,13 @@ local Element = require('uosc_shared/elements/Element')
|
|||
-- Menu data structure accepted by `Menu:open(menu)`.
|
||||
---@alias MenuData {type?: string; title?: string; hint?: string; keep_open?: boolean; separator?: boolean; items?: MenuDataItem[]; selected_index?: integer;}
|
||||
---@alias MenuDataItem MenuDataValue|MenuData
|
||||
---@alias MenuDataValue {title?: string; hint?: string; icon?: string; value: any; bold?: boolean; italic?: boolean; muted?: boolean; active?: boolean; keep_open?: boolean; separator?: boolean;}
|
||||
---@alias MenuDataValue {title?: string; hint?: string; icon?: string; value: any; bold?: boolean; italic?: boolean; muted?: boolean; active?: boolean; keep_open?: boolean; separator?: boolean; selectable?: boolean; align?: 'left'|'center'|'right'}
|
||||
---@alias MenuOptions {mouse_nav?: boolean; on_open?: fun(); on_close?: fun(); on_back?: fun(); on_move_item?: fun(from_index: integer, to_index: integer, submenu_path: integer[]); on_delete_item?: fun(index: integer, submenu_path: integer[])}
|
||||
|
||||
-- Internal data structure created from `Menu`.
|
||||
---@alias MenuStack {id?: string; type?: string; title?: string; hint?: string; selected_index?: number; keep_open?: boolean; separator?: boolean; items: MenuStackItem[]; parent_menu?: MenuStack; submenu_path: integer[]; active?: boolean; width: number; height: number; top: number; scroll_y: number; scroll_height: number; title_width: number; hint_width: number; max_width: number; is_root?: boolean; fling?: Fling}
|
||||
---@alias MenuStackItem MenuStackValue|MenuStack
|
||||
---@alias MenuStackValue {title?: string; hint?: string; icon?: string; value: any; active?: boolean; bold?: boolean; italic?: boolean; muted?: boolean; keep_open?: boolean; separator?: boolean; title_width: number; hint_width: number}
|
||||
---@alias MenuStackValue {title?: string; hint?: string; icon?: string; value: any; active?: boolean; bold?: boolean; italic?: boolean; muted?: boolean; keep_open?: boolean; separator?: boolean; selectable?: boolean; align?: 'left'|'center'|'right'; title_width: number; hint_width: number}
|
||||
---@alias Fling {y: number, distance: number, time: number, easing: fun(x: number), duration: number, update_cursor?: boolean}
|
||||
|
||||
---@alias Modifiers {shift?: boolean, ctrl?: boolean, alt?: boolean}
|
||||
|
@ -156,7 +156,9 @@ function Menu:update(data)
|
|||
|
||||
-- Update items
|
||||
local first_active_index = nil
|
||||
menu.items = {{title = t('Empty'), value = 'ignore', italic = 'true', muted = 'true'}}
|
||||
menu.items = {
|
||||
{title = t('Empty'), value = 'ignore', italic = 'true', muted = 'true', selectable = false, align = 'center'}
|
||||
}
|
||||
|
||||
for i, item_data in ipairs(menu_data.items or {}) do
|
||||
if item_data.active and not first_active_index then first_active_index = i end
|
||||
|
@ -164,6 +166,7 @@ function Menu:update(data)
|
|||
local item = {}
|
||||
table_assign(item, item_data, {
|
||||
'title', 'icon', 'hint', 'active', 'bold', 'italic', 'muted', 'value', 'keep_open', 'separator',
|
||||
'selectable', 'align'
|
||||
})
|
||||
if item.keep_open == nil then item.keep_open = menu.keep_open end
|
||||
|
||||
|
@ -267,8 +270,10 @@ function Menu:reset_navigation()
|
|||
self:scroll_to(menu.scroll_y) -- clamps scroll_y to scroll limits
|
||||
if self.mouse_nav then
|
||||
self:select_item_below_cursor()
|
||||
elseif menu.items and #menu.items > 0 then
|
||||
self:select_index(itable_find(menu.items, function(item) return item.selectable ~= false end))
|
||||
else
|
||||
self:select_index((menu.items and #menu.items > 0) and clamp(1, menu.selected_index or 1, #menu.items) or nil)
|
||||
self:select_index(nil)
|
||||
end
|
||||
|
||||
-- Walk up the parent menu chain and activate items that lead to current menu
|
||||
|
@ -445,15 +450,21 @@ end
|
|||
---@param menu? MenuStack
|
||||
function Menu:prev(menu)
|
||||
menu = menu or self.current
|
||||
menu.selected_index = math.max(menu.selected_index and menu.selected_index - 1 or #menu.items, 1)
|
||||
self:scroll_to_index(menu.selected_index, menu, true)
|
||||
local initial_index = menu.selected_index and menu.selected_index - 1 or #menu.items
|
||||
if initial_index > 0 then
|
||||
menu.selected_index = itable_find(menu.items, function(item) return item.selectable ~= false end, initial_index, 1)
|
||||
self:scroll_to_index(menu.selected_index, menu, true)
|
||||
end
|
||||
end
|
||||
|
||||
---@param menu? MenuStack
|
||||
function Menu:next(menu)
|
||||
menu = menu or self.current
|
||||
menu.selected_index = math.min(menu.selected_index and menu.selected_index + 1 or 1, #menu.items)
|
||||
self:scroll_to_index(menu.selected_index, menu, true)
|
||||
local initial_index = menu.selected_index and menu.selected_index + 1 or 1
|
||||
if initial_index <= #menu.items then
|
||||
menu.selected_index = itable_find(menu.items, function(item) return item.selectable ~= false end, initial_index)
|
||||
self:scroll_to_index(menu.selected_index, menu, true)
|
||||
end
|
||||
end
|
||||
|
||||
function Menu:back()
|
||||
|
@ -498,7 +509,10 @@ end
|
|||
|
||||
function Menu:open_selected_item_soft() self:open_selected_item({keep_open = true}) end
|
||||
function Menu:open_selected_item_preselect() self:open_selected_item({preselect_submenu_item = true}) end
|
||||
function Menu:select_item_below_cursor() self.current.selected_index = self:get_item_index_below_cursor() end
|
||||
function Menu:select_item_below_cursor()
|
||||
local index = self:get_item_index_below_cursor()
|
||||
self.current.selected_index = index and self.current.items[index].selectable ~= false and index or nil
|
||||
end
|
||||
|
||||
---@param index integer
|
||||
function Menu:move_selected_item_to(index)
|
||||
|
@ -787,7 +801,13 @@ function Menu:render()
|
|||
item.ass_safe_title = item.ass_safe_title or ass_escape(item.title)
|
||||
local clip = '\\clip(' .. ax .. ',' .. math.max(item_ay, ay) .. ','
|
||||
.. title_cut_x .. ',' .. math.min(item_by, by) .. ')'
|
||||
ass:txt(content_ax, item_center_y, 4, item.ass_safe_title, {
|
||||
local title_x, align = content_ax, 4
|
||||
if item.align == 'right' then
|
||||
title_x, align = title_cut_x, 6
|
||||
elseif item.align == 'center' then
|
||||
title_x, align = content_ax + (title_cut_x - content_ax) / 2, 5
|
||||
end
|
||||
ass:txt(title_x, item_center_y, align, item.ass_safe_title, {
|
||||
size = self.font_size, color = font_color, italic = item.italic, bold = item.bold, wrap = 2,
|
||||
opacity = text_opacity * (item.muted and 0.5 or 1), clip = clip,
|
||||
shadow = 1, shadow_color = shadow_color,
|
||||
|
|
|
@ -411,7 +411,7 @@ function Timeline:render()
|
|||
|
||||
-- Chapter title
|
||||
if #state.chapters > 0 then
|
||||
local _, chapter = itable_find(state.chapters, function(c) return hovered_seconds >= c.time end, true)
|
||||
local _, chapter = itable_find(state.chapters, function(c) return hovered_seconds >= c.time end, #state.chapters, 1)
|
||||
if chapter and not chapter.is_end_only then
|
||||
ass:tooltip(tooltip_anchor, chapter.title_wrapped, {
|
||||
size = self.font_size, offset = 10, responsive = false, bold = true,
|
||||
|
|
|
@ -77,13 +77,18 @@ end
|
|||
|
||||
---@param itable table
|
||||
---@param compare fun(value: any, index: number)
|
||||
---@param from_end? boolean Search from the end of the table.
|
||||
---@param from? number Where to start search, defaults to `1`.
|
||||
---@param to? number Where to end search, defaults to `#itable`.
|
||||
---@return number|nil index
|
||||
---@return any|nil value
|
||||
function itable_find(itable, compare, from_end)
|
||||
local from, to, step = from_end and #itable or 1, from_end and 1 or #itable, from_end and -1 or 1
|
||||
function itable_find(itable, compare, from, to)
|
||||
from, to = from or 1, to or #itable
|
||||
if from == 0 or from > #itable or to == 0 or to > #itable then return end
|
||||
local step = from < to and 1 or -1
|
||||
for index = from, to, step do
|
||||
if compare(itable[index], index) then return index, itable[index] end
|
||||
if index > 0 and index <= #itable and compare(itable[index], index) then
|
||||
return index, itable[index]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user