- Now stores the different lists in a tree which caches each path to enable the minimum amount of re-fetching - Every request is async allowing input while waiting for the server to respond - No longer requires a list library as a list implementation is built in Currently I've yet to implement the video handling, but that's next!
182 lines
4.6 KiB
Lua
182 lines
4.6 KiB
Lua
local mp = require("mp")
|
|
local msg = require("mp.msg")
|
|
|
|
local misc = require("src.utils.misc")
|
|
|
|
---@class list.item
|
|
---@field ass string
|
|
---@field style string
|
|
|
|
---@class list
|
|
---@field open boolean is the list open
|
|
---@field header string default header
|
|
---@field default_style string default ass styling for each item
|
|
---@field osd table mpv osd overlay table
|
|
---@field items list.item[]
|
|
---@field selected number index representing which item in items is selected
|
|
---@field keybinds table[] a list of keybinds to be applied
|
|
---@field max_items number the maximum number of items which can fit on the screen
|
|
local list = {}
|
|
|
|
--- create a new list
|
|
---@return list list
|
|
function list:new()
|
|
---@type list
|
|
---@diagnostic disable-next-line: missing-fields
|
|
local o = {}
|
|
|
|
setmetatable(o, self)
|
|
self.__index = self
|
|
|
|
o.header = [[{\c&HC35CAA&}J{\c&HC66691&}e{\c&HCA7079&}l{\c&HCD7A61&}l{\c&HD18548&}y{\c&HD48F30&}f{\c&HD89918&}i{\c&HDCA400&}n]]
|
|
o.default_style = [[{\r\fs23\fnmonospace}]]
|
|
|
|
o.osd = mp.create_osd_overlay("ass-events")
|
|
o.osd.data = ""
|
|
o.selected = 1
|
|
o.keybinds = {}
|
|
o.max_items = 26
|
|
|
|
return o
|
|
end
|
|
|
|
--- small wrapper around the list to set all items and redraw immediately
|
|
---@param items list.item[]?
|
|
function list:set(items)
|
|
self.items = items or {}
|
|
self:update()
|
|
end
|
|
|
|
--- display text fading in and out
|
|
---@param rate number time between each step
|
|
---@param text string
|
|
---@return table timer
|
|
function list:set_fade_animation(rate, text)
|
|
self.selected = 0
|
|
local opacity, direction = 255, -1
|
|
local function load_animation()
|
|
opacity = opacity + direction * 10
|
|
if opacity >= 255 then
|
|
opacity = 255
|
|
direction = -1
|
|
elseif opacity <= 0 then
|
|
opacity = 0
|
|
direction = 1
|
|
end
|
|
self:set({{
|
|
style = string.format(
|
|
[[{\alpha%s&}{\c&Hffffff&}]],
|
|
string.format("&H%02X&", 255 - math.floor(opacity))
|
|
),
|
|
ass = text,
|
|
}})
|
|
end
|
|
return misc.mpv_timer(rate, load_animation, text)
|
|
end
|
|
|
|
--- small wrapper around list:set to log the text provided
|
|
---@param item list.item
|
|
function list:log(item)
|
|
self.selected = 0
|
|
msg.fatal(item.ass)
|
|
self:set({ item })
|
|
end
|
|
|
|
--- draw the list to the screen
|
|
function list:update()
|
|
self.open = true
|
|
|
|
-- add all keybinds when we open the ui
|
|
for _, v in ipairs(self.keybinds) do
|
|
mp.add_forced_key_binding(v[1], "dynamic/"..self.osd.id.."/"..v[2], v[3], v[4])
|
|
end
|
|
|
|
---@type list.item[]
|
|
local scrolled_items = {}
|
|
local selected = self.selected
|
|
if self.selected > (self.max_items / 2) then
|
|
if (#self.items - self.selected) > (self.max_items / 2) then
|
|
scrolled_items = { table.unpack(
|
|
self.items or {},
|
|
self.selected - (self.max_items / 2) + 1
|
|
) }
|
|
selected = (self.max_items / 2)
|
|
else
|
|
scrolled_items = { table.unpack(
|
|
self.items or {},
|
|
(#self.items - self.max_items) + 1
|
|
) }
|
|
selected = (self.max_items / 2) + (((self.max_items / 2) + self.selected)
|
|
- #self.items)
|
|
end
|
|
else
|
|
scrolled_items = self.items or {}
|
|
end
|
|
|
|
-- put all the items in the list
|
|
self.osd.data = [[{\r\fnmonospace}]]..self.header..[[\N]]
|
|
for i, item in ipairs(scrolled_items) do
|
|
-- if self.selected <= 0 then there should be no selection indicators drawn
|
|
if self.selected > 0 then
|
|
if i == selected then
|
|
self.osd.data = self.osd.data..self.default_style..[[● ]]
|
|
else
|
|
self.osd.data = self.osd.data..self.default_style..[[○ ]]
|
|
end
|
|
else
|
|
self.osd.data = self.osd.data..self.default_style
|
|
end
|
|
self.osd.data = self.osd.data
|
|
..(item.style or [[{\c&Hffffff&}]])
|
|
..item.ass
|
|
if self.items[i + 1] then
|
|
self.osd.data = self.osd.data..[[{\r}\N]]
|
|
end
|
|
end
|
|
self.osd:update()
|
|
end
|
|
|
|
--- close the list
|
|
function list:close()
|
|
-- remove all the keybinds
|
|
for _,v in ipairs(self.keybinds) do
|
|
mp.remove_key_binding("dynamic/"..self.osd.id.."/"..v[2])
|
|
end
|
|
|
|
-- close the list
|
|
self.osd:remove()
|
|
self.open = false
|
|
end
|
|
|
|
--- go up
|
|
function list:up()
|
|
if self.selected > 1 then
|
|
self.selected = self.selected - 1
|
|
self:update()
|
|
end
|
|
end
|
|
|
|
--- go down
|
|
function list:down()
|
|
if self.selected < #self.items then
|
|
self.selected = self.selected + 1
|
|
self:update()
|
|
end
|
|
end
|
|
|
|
--- helper to addkeys to the list view
|
|
---@param keys string keybind
|
|
---@param name string action name
|
|
---@param fn function callback
|
|
---@param opts? table options
|
|
function list:addkey(keys, name, fn, opts)
|
|
opts = opts or { repeatable = true }
|
|
local i = 1
|
|
for key in keys:gmatch("%S+") do
|
|
table.insert(self.keybinds, { key, name..i, fn, opts })
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
return list
|