summaryrefslogtreecommitdiff
path: root/mac/.config/mpv/script-modules/scroll-list.lua
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-08-23 12:42:37 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-08-23 12:42:37 +0900
commit07d294425a98ee5d1e22d03e2b24ae2c76e487c0 (patch)
treea6818f0d64438c5fdb88b00a35d944f80c056213 /mac/.config/mpv/script-modules/scroll-list.lua
parent6fc28cdb3529ca8ee864cb5c41674cb0a4af72a1 (diff)
updates
Diffstat (limited to 'mac/.config/mpv/script-modules/scroll-list.lua')
-rw-r--r--mac/.config/mpv/script-modules/scroll-list.lua293
1 files changed, 293 insertions, 0 deletions
diff --git a/mac/.config/mpv/script-modules/scroll-list.lua b/mac/.config/mpv/script-modules/scroll-list.lua
new file mode 100644
index 0000000..5d8f9fa
--- /dev/null
+++ b/mac/.config/mpv/script-modules/scroll-list.lua
@@ -0,0 +1,293 @@
+local mp = require 'mp'
+local scroll_list = {
+ global_style = [[]],
+ header_style = [[{\q2\fs35\c&00ccff&}]],
+ list_style = [[{\q2\fs25\c&Hffffff&}]],
+ wrapper_style = [[{\c&00ccff&\fs16}]],
+ cursor_style = [[{\c&00ccff&}]],
+ selected_style = [[{\c&Hfce788&}]],
+
+ cursor = [[➤\h]],
+ indent = [[\h\h\h\h]],
+
+ num_entries = 16,
+ wrap = false,
+ empty_text = "no entries"
+}
+
+--formats strings for ass handling
+--this function is based on a similar function from https://github.com/mpv-player/mpv/blob/master/player/lua/console.lua#L110
+function scroll_list.ass_escape(str, replace_newline)
+ if replace_newline == true then replace_newline = "\\\239\187\191n" end
+
+ --escape the invalid single characters
+ str = str:gsub('[\\{}\n]', {
+ -- There is no escape for '\' in ASS (I think?) but '\' is used verbatim if
+ -- it isn't followed by a recognised character, so add a zero-width
+ -- non-breaking space
+ ['\\'] = '\\\239\187\191',
+ ['{'] = '\\{',
+ ['}'] = '\\}',
+ -- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of
+ -- consecutive newlines
+ ['\n'] = '\239\187\191\\N',
+ })
+
+ -- Turn leading spaces into hard spaces to prevent ASS from stripping them
+ str = str:gsub('\\N ', '\\N\\h')
+ str = str:gsub('^ ', '\\h')
+
+ if replace_newline then
+ str = str:gsub("\\N", replace_newline)
+ end
+ return str
+end
+
+--format and return the header string
+function scroll_list:format_header_string(str)
+ return str
+end
+
+--appends the entered text to the overlay
+function scroll_list:append(text)
+ if text == nil then return end
+ self.ass.data = self.ass.data .. text
+ end
+
+--appends a newline character to the osd
+function scroll_list:newline()
+ self.ass.data = self.ass.data .. '\\N'
+end
+
+--re-parses the list into an ass string
+--if the list is closed then it flags an update on the next open
+function scroll_list:update()
+ if self.hidden then self.flag_update = true
+ else self:update_ass() end
+end
+
+--prints the header to the overlay
+function scroll_list:format_header()
+ self:append(self.header_style)
+ self:append(self:format_header_string(self.header))
+ self:newline()
+end
+
+--formats each line of the list and prints it to the overlay
+function scroll_list:format_line(index, item)
+ self:append(self.list_style)
+
+ if index == self.selected then self:append(self.cursor_style..self.cursor..self.selected_style)
+ else self:append(self.indent) end
+
+ self:append(item.style)
+ self:append(item.ass)
+ self:newline()
+end
+
+--refreshes the ass text using the contents of the list
+function scroll_list:update_ass()
+ self.ass.data = self.global_style
+ self:format_header()
+
+ if #self.list < 1 then
+ self:append(self.empty_text)
+ self.ass:update()
+ return
+ end
+
+ local start = 1
+ local finish = start+self.num_entries-1
+
+ --handling cursor positioning
+ local mid = math.ceil(self.num_entries/2)+1
+ if self.selected+mid > finish then
+ local offset = self.selected - finish + mid
+
+ --if we've overshot the end of the list then undo some of the offset
+ if finish + offset > #self.list then
+ offset = offset - ((finish+offset) - #self.list)
+ end
+
+ start = start + offset
+ finish = finish + offset
+ end
+
+ --making sure that we don't overstep the boundaries
+ if start < 1 then start = 1 end
+ local overflow = finish < #self.list
+ --this is necessary when the number of items in the dir is less than the max
+ if not overflow then finish = #self.list end
+
+ --adding a header to show there are items above in the list
+ if start > 1 then self:append(self.wrapper_style..(start-1)..' item(s) above\\N\\N') end
+
+ for i=start, finish do
+ self:format_line(i, self.list[i])
+ end
+
+ if overflow then self:append('\\N'..self.wrapper_style..#self.list-finish..' item(s) remaining') end
+ self.ass:update()
+end
+
+--moves the selector down the list
+function scroll_list:scroll_down()
+ if self.selected < #self.list then
+ self.selected = self.selected + 1
+ self:update_ass()
+ elseif self.wrap then
+ self.selected = 1
+ self:update_ass()
+ end
+end
+
+--moves the selector up the list
+function scroll_list:scroll_up()
+ if self.selected > 1 then
+ self.selected = self.selected - 1
+ self:update_ass()
+ elseif self.wrap then
+ self.selected = #self.list
+ self:update_ass()
+ end
+end
+
+--moves the selector to the list next page
+function scroll_list:move_pagedown()
+ if #self.list > self.num_entries then
+ self.selected = self.selected + self.num_entries
+ if self.selected > #self.list then self.selected = #self.list end
+ self:update_ass()
+ end
+end
+
+--moves the selector to the list previous page
+function scroll_list:move_pageup()
+ if #self.list > self.num_entries then
+ self.selected = self.selected - self.num_entries
+ if self.selected < 1 then self.selected = 1 end
+ self:update_ass()
+ end
+end
+
+--moves the selector to the list begin
+function scroll_list:move_begin()
+ if #self.list > 1 then
+ self.selected = 1
+ self:update_ass()
+ end
+end
+
+--moves the selector to the list end
+function scroll_list:move_end()
+ if #self.list > 1 then
+ self.selected = #self.list
+ self:update_ass()
+ end
+end
+
+--adds the forced keybinds
+function scroll_list:add_keybinds()
+ for _,v in ipairs(self.keybinds) do
+ mp.add_forced_key_binding(v[1], 'dynamic/'..self.ass.id..'/'..v[2], v[3], v[4])
+ end
+end
+
+--removes the forced keybinds
+function scroll_list:remove_keybinds()
+ for _,v in ipairs(self.keybinds) do
+ mp.remove_key_binding('dynamic/'..self.ass.id..'/'..v[2])
+ end
+end
+
+--opens the list and sets the hidden flag
+function scroll_list:open_list()
+ self.hidden = false
+ if not self.flag_update then self.ass:update()
+ else self.flag_update = false ; self:update_ass() end
+end
+
+--closes the list and sets the hidden flag
+function scroll_list:close_list()
+ self.hidden = true
+ self.ass:remove()
+end
+
+--modifiable function that opens the list
+function scroll_list:open()
+ if self.hidden then self:add_keybinds() end
+ self:open_list()
+end
+
+--modifiable function that closes the list
+function scroll_list:close()
+ self:remove_keybinds()
+ self:close_list()
+end
+
+--toggles the list
+function scroll_list:toggle()
+ if self.hidden then self:open()
+ else self:close() end
+end
+
+--clears the list in-place
+function scroll_list:clear()
+ local i = 1
+ while self.list[i] do
+ self.list[i] = nil
+ i = i + 1
+ end
+end
+
+--added alias for ipairs(list.list) for lua 5.1
+function scroll_list:ipairs()
+ return ipairs(self.list)
+end
+
+--append item to the end of the list
+function scroll_list:insert(item)
+ self.list[#self.list + 1] = item
+end
+
+local metatable = {
+ __index = function(t, key)
+ if scroll_list[key] ~= nil then return scroll_list[key]
+ elseif key == "__current" then return t.list[t.selected]
+ elseif type(key) == "number" then return t.list[key] end
+ end,
+ __newindex = function(t, key, value)
+ if type(key) == "number" then rawset(t.list, key, value)
+ else rawset(t, key, value) end
+ end,
+ __scroll_list = scroll_list,
+ __len = function(t) return #t.list end,
+ __ipairs = function(t) return ipairs(t.list) end
+}
+
+--creates a new list object
+function scroll_list:new()
+ local vars
+ vars = {
+ ass = mp.create_osd_overlay('ass-events'),
+ hidden = true,
+ flag_update = true,
+
+ header = "header \\N ----------------------------------------------",
+ list = {},
+ selected = 1,
+
+ keybinds = {
+ {'DOWN', 'scroll_down', function() vars:scroll_down() end, {repeatable = true}},
+ {'UP', 'scroll_up', function() vars:scroll_up() end, {repeatable = true}},
+ {'PGDWN', 'move_pagedown', function() vars:move_pagedown() end, {}},
+ {'PGUP', 'move_pageup', function() vars:move_pageup() end, {}},
+ {'HOME', 'move_begin', function() vars:move_begin() end, {}},
+ {'END', 'move_end', function() vars:move_end() end, {}},
+ {'ESC', 'close_browser', function() vars:close() end, {}}
+ }
+ }
+ return setmetatable(vars, metatable)
+end
+
+return scroll_list:new()