summaryrefslogtreecommitdiffstats
path: root/.config/mpv/scripts/uosc_shared/lib/menus.lua
diff options
context:
space:
mode:
Diffstat (limited to '.config/mpv/scripts/uosc_shared/lib/menus.lua')
-rw-r--r--.config/mpv/scripts/uosc_shared/lib/menus.lua282
1 files changed, 0 insertions, 282 deletions
diff --git a/.config/mpv/scripts/uosc_shared/lib/menus.lua b/.config/mpv/scripts/uosc_shared/lib/menus.lua
deleted file mode 100644
index e2a4ccc..0000000
--- a/.config/mpv/scripts/uosc_shared/lib/menus.lua
+++ /dev/null
@@ -1,282 +0,0 @@
----@param data MenuData
----@param opts? {submenu?: string; mouse_nav?: boolean}
-function open_command_menu(data, opts)
- local menu = Menu:open(data, function(value)
- if type(value) == 'string' then
- mp.command(value)
- else
- ---@diagnostic disable-next-line: deprecated
- mp.commandv(unpack(value))
- end
- end, opts)
- if opts and opts.submenu then menu:activate_submenu(opts.submenu) end
- return menu
-end
-
----@param opts? {submenu?: string; mouse_nav?: boolean}
-function toggle_menu_with_items(opts)
- if Menu:is_open('menu') then Menu:close()
- else open_command_menu({type = 'menu', items = config.menu_items}, opts) end
-end
-
----@param options {type: string; title: string; list_prop: string; active_prop?: string; serializer: fun(list: any, active: any): MenuDataItem[]; on_select: fun(value: any)}
-function create_self_updating_menu_opener(options)
- return function()
- if Menu:is_open(options.type) then Menu:close() return end
- local list = mp.get_property_native(options.list_prop)
- local active = options.active_prop and mp.get_property_native(options.active_prop) or nil
- local menu
-
- local function update() menu:update_items(options.serializer(list, active)) end
-
- local ignore_initial_list = true
- local function handle_list_prop_change(name, value)
- if ignore_initial_list then ignore_initial_list = false
- else list = value update() end
- end
-
- local ignore_initial_active = true
- local function handle_active_prop_change(name, value)
- if ignore_initial_active then ignore_initial_active = false
- else active = value update() end
- end
-
- local initial_items, selected_index = options.serializer(list, active)
-
- -- Items and active_index are set in the handle_prop_change callback, since adding
- -- a property observer triggers its handler immediately, we just let that initialize the items.
- menu = Menu:open(
- {type = options.type, title = options.title, items = initial_items, selected_index = selected_index},
- options.on_select, {
- on_open = function()
- mp.observe_property(options.list_prop, 'native', handle_list_prop_change)
- if options.active_prop then
- mp.observe_property(options.active_prop, 'native', handle_active_prop_change)
- end
- end,
- on_close = function()
- mp.unobserve_property(handle_list_prop_change)
- mp.unobserve_property(handle_active_prop_change)
- end,
- })
- end
-end
-
-function create_select_tracklist_type_menu_opener(menu_title, track_type, track_prop, load_command)
- local function serialize_tracklist(tracklist)
- local items = {}
-
- if load_command then
- items[#items + 1] = {
- title = 'Load', bold = true, italic = true, hint = 'open file', value = '{load}', separator = true,
- }
- end
-
- local first_item_index = #items + 1
- local active_index = nil
- local disabled_item = nil
-
- -- Add option to disable a subtitle track. This works for all tracks,
- -- but why would anyone want to disable audio or video? Better to not
- -- let people mistakenly select what is unwanted 99.999% of the time.
- -- If I'm mistaken and there is an active need for this, feel free to
- -- open an issue.
- if track_type == 'sub' then
- disabled_item = {title = 'Disabled', italic = true, muted = true, hint = '—', value = nil, active = true}
- items[#items + 1] = disabled_item
- end
-
- for _, track in ipairs(tracklist) do
- if track.type == track_type then
- local hint_values = {}
- local function h(value) hint_values[#hint_values + 1] = value end
-
- if track.lang then h(track.lang:upper()) end
- if track['demux-h'] then
- h(track['demux-w'] and (track['demux-w'] .. 'x' .. track['demux-h']) or (track['demux-h'] .. 'p'))
- end
- if track['demux-fps'] then h(string.format('%.5gfps', track['demux-fps'])) end
- h(track.codec)
- if track['audio-channels'] then h(track['audio-channels'] .. ' channels') end
- if track['demux-samplerate'] then h(string.format('%.3gkHz', track['demux-samplerate'] / 1000)) end
- if track.forced then h('forced') end
- if track.default then h('default') end
- if track.external then h('external') end
-
- items[#items + 1] = {
- title = (track.title and track.title or 'Track ' .. track.id),
- hint = table.concat(hint_values, ', '),
- value = track.id,
- active = track.selected,
- }
-
- if track.selected then
- if disabled_item then disabled_item.active = false end
- active_index = #items
- end
- end
- end
-
- return items, active_index or first_item_index
- end
-
- local function selection_handler(value)
- if value == '{load}' then
- mp.command(load_command)
- else
- mp.commandv('set', track_prop, value and value or 'no')
-
- -- If subtitle track was selected, assume user also wants to see it
- if value and track_type == 'sub' then
- mp.commandv('set', 'sub-visibility', 'yes')
- end
- end
- end
-
- return create_self_updating_menu_opener({
- title = menu_title,
- type = track_type,
- list_prop = 'track-list',
- serializer = serialize_tracklist,
- on_select = selection_handler,
- })
-end
-
----@alias NavigationMenuOptions {type: string, title?: string, allowed_types?: string[], active_path?: string, selected_path?: string; on_open?: fun(); on_close?: fun()}
-
--- Opens a file navigation menu with items inside `directory_path`.
----@param directory_path string
----@param handle_select fun(path: string): nil
----@param opts NavigationMenuOptions
-function open_file_navigation_menu(directory_path, handle_select, opts)
- directory = serialize_path(normalize_path(directory_path))
- opts = opts or {}
-
- if not directory then
- msg.error('Couldn\'t serialize path "' .. directory_path .. '.')
- return
- end
-
- local files, directories = read_directory(directory.path, opts.allowed_types)
- local is_root = not directory.dirname
- local path_separator = path_separator(directory.path)
-
- if not files or not directories then return end
-
- sort_filenames(directories)
- sort_filenames(files)
-
- -- Pre-populate items with parent directory selector if not at root
- -- Each item value is a serialized path table it points to.
- local items = {}
-
- if is_root then
- if state.os == 'windows' then
- items[#items + 1] = {title = '..', hint = 'Drives', value = '{drives}', separator = true}
- end
- else
- items[#items + 1] = {title = '..', hint = 'parent dir', value = directory.dirname, separator = true}
- end
-
- local back_path = items[#items] and items[#items].value
- local selected_index = #items + 1
-
- for _, dir in ipairs(directories) do
- items[#items + 1] = {title = dir, value = join_path(directory.path, dir), hint = path_separator}
- end
-
- for _, file in ipairs(files) do
- items[#items + 1] = {title = file, value = join_path(directory.path, file)}
- end
-
- for index, item in ipairs(items) do
- if not item.value.is_to_parent and opts.active_path == item.value then
- item.active = true
- if not opts.selected_path then selected_index = index end
- end
-
- if opts.selected_path == item.value then selected_index = index end
- end
-
- local function open_path(path)
- local is_drives = path == '{drives}'
- local is_to_parent = is_drives or #path < #directory_path
- local inheritable_options = {
- type = opts.type, title = opts.title, allowed_types = opts.allowed_types, active_path = opts.active_path,
- }
-
- if is_drives then
- open_drives_menu(function(drive_path)
- open_file_navigation_menu(drive_path, handle_select, inheritable_options)
- end, {
- type = inheritable_options.type, title = inheritable_options.title, selected_path = directory.path,
- on_open = opts.on_open, on_close = opts.on_close,
- })
- return
- end
-
- local info, error = utils.file_info(path)
-
- if not info then
- msg.error('Can\'t retrieve path info for "' .. path .. '". Error: ' .. (error or ''))
- return
- end
-
- if info.is_dir then
- -- Preselect directory we are coming from
- if is_to_parent then
- inheritable_options.selected_path = directory.path
- end
-
- open_file_navigation_menu(path, handle_select, inheritable_options)
- else
- handle_select(path)
- end
- end
-
- local function handle_back()
- if back_path then open_path(back_path) end
- end
-
- local menu_data = {
- type = opts.type, title = opts.title or directory.basename .. path_separator, items = items,
- selected_index = selected_index,
- }
- local menu_options = {on_open = opts.on_open, on_close = opts.on_close, on_back = handle_back}
-
- return Menu:open(menu_data, open_path, menu_options)
-end
-
--- Opens a file navigation menu with Windows drives as items.
----@param handle_select fun(path: string): nil
----@param opts? NavigationMenuOptions
-function open_drives_menu(handle_select, opts)
- opts = opts or {}
- local process = mp.command_native({
- name = 'subprocess',
- capture_stdout = true,
- playback_only = false,
- args = {'wmic', 'logicaldisk', 'get', 'name', '/value'},
- })
- local items, selected_index = {}, 1
-
- if process.status == 0 then
- for _, value in ipairs(split(process.stdout, '\n')) do
- local drive = string.match(value, 'Name=([A-Z]:)')
- if drive then
- local drive_path = normalize_path(drive)
- items[#items + 1] = {
- title = drive, hint = 'drive', value = drive_path, active = opts.active_path == drive_path,
- }
- if opts.selected_path == drive_path then selected_index = #items end
- end
- end
- else
- msg.error(process.stderr)
- end
-
- return Menu:open(
- {type = opts.type, title = opts.title or 'Drives', items = items, selected_index = selected_index},
- handle_select
- )
-end