feat: rewrite the whole code
- 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!
This commit is contained in:
181
src/list.lua
Normal file
181
src/list.lua
Normal file
@@ -0,0 +1,181 @@
|
||||
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
|
Reference in New Issue
Block a user