Files
jellies-and-jams/src/list.lua
Squibid b153a46b87 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!
2025-10-10 14:55:20 -04:00

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