From 2d1a6ae65541a8b2331f04100004636be9f66797 Mon Sep 17 00:00:00 2001 From: Shuanglei Tao Date: Sat, 6 Apr 2024 18:46:11 +0800 Subject: [PATCH] sync menu data structure with mpv --- src/lua/dyn_menu.lua | 83 ++++++++++++++++++++++---------------------- src/menu.c | 21 +++++++++-- 2 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/lua/dyn_menu.lua b/src/lua/dyn_menu.lua index 4d2d0c7..e7f4246 100644 --- a/src/lua/dyn_menu.lua +++ b/src/lua/dyn_menu.lua @@ -131,6 +131,14 @@ local function compile_expr(name, s) end ------------------------------------------------------------------------ +-- append menu item to menu +local function append_menu(menu, item) + if (item.title and o.escape_title) then + item.title = item.title:gsub('&', '&&') + end + menu[#menu + 1] = item +end + -- escape codec name to make it more readable local function escape_codec(str) if not str or str == '' then return '' end @@ -181,7 +189,6 @@ end local function build_track_title(track, prefix, filename) local type = track.type local title = track.title or '' - local lang = track.lang or '' local codec = escape_codec(track.codec) -- remove filename from title if it's external track @@ -215,8 +222,6 @@ local function build_track_title(track, prefix, filename) if track.external then title = title .. ' (external)' end if track.default then title = title .. ' (*)' end - -- show language at right side (\t is used to right align the text) - if lang ~= '' then title = string.format('%s\t%s', title, lang:upper()) end -- prepend a 1-letter type prefix, used when displaying multiple track types if prefix then title = string.format('%s: %s', type:sub(1, 1):upper(), title) end return title @@ -240,6 +245,7 @@ local function build_track_items(list, type, prop, prefix) items[#items + 1] = { title = build_track_title(track, prefix, filename), + shortcut = (track.lang and track.lang ~= '') and track.lang:upper() or nil, cmd = string.format('set %s %d', prop, track.id), state = state, } @@ -283,11 +289,11 @@ local function update_tracks_menu(menu) local items_s = build_track_items(track_list, 'sub', 'sid', true) -- append video/audio/sub tracks into one submenu, separated by a separator - for _, item in ipairs(items_v) do submenu[#submenu + 1] = item end - if #submenu > 0 and #items_a > 0 then submenu[#submenu + 1] = { type = 'separator' } end - for _, item in ipairs(items_a) do submenu[#submenu + 1] = item end - if #submenu > 0 and #items_s > 0 then submenu[#submenu + 1] = { type = 'separator' } end - for _, item in ipairs(items_s) do submenu[#submenu + 1] = item end + for _, item in ipairs(items_v) do append_menu(submenu, item) end + if #submenu > 0 and #items_a > 0 then append_menu(submenu, { type = 'separator' }) end + for _, item in ipairs(items_a) do append_menu(submenu, item) end + if #submenu > 0 and #items_s > 0 then append_menu(submenu, { type = 'separator' }) end + for _, item in ipairs(items_s) do append_menu(submenu, item) end end -- handle #@tracks/ menu update for given type @@ -297,7 +303,7 @@ local function update_track_menu(menu, type, prop) if #track_list == 0 then return end local items = build_track_items(track_list, type, prop, false) - for _, item in ipairs(items) do submenu[#submenu + 1] = item end + for _, item in ipairs(items) do append_menu(submenu, item) end end -- handle #@chapters menu update @@ -310,13 +316,13 @@ local function update_chapters_menu(menu) for id, chapter in ipairs(chapter_list) do local title = abbr_title(chapter.title) if title == '' then title = 'Chapter ' .. id end - local time = string.format('%02d:%02d:%02d', chapter.time / 3600, chapter.time / 60 % 60, chapter.time % 60) - submenu[#submenu + 1] = { - title = string.format('%s\t[%s]', title, time), + append_menu(submenu, { + title = title, + shortcut = string.format('[%02d:%02d:%02d]', chapter.time / 3600, chapter.time / 60 % 60, chapter.time % 60), cmd = string.format('seek %f absolute', chapter.time), state = id == pos + 1 and { 'checked' } or {}, - } + }) end end @@ -331,11 +337,11 @@ local function update_editions_menu(menu) local title = abbr_title(edition.title) if title == '' then title = 'Edition ' .. id end if edition.default then title = title .. ' [default]' end - submenu[#submenu + 1] = { + append_menu(submenu, { title = title, cmd = string.format('set edition %d', id - 1), state = id == current + 1 and { 'checked' } or {}, - } + }) end end @@ -347,11 +353,11 @@ local function update_audio_devices_menu(menu) local current = get('audio-device', '') for _, device in ipairs(device_list) do - submenu[#submenu + 1] = { + append_menu(submenu, { title = device.description or device.name, cmd = string.format('set audio-device %s', device.name), state = device.name == current and { 'checked' } or {}, - } + }) end end @@ -366,7 +372,7 @@ local function build_playlist_title(item, id) if e then ext = e end end title = title ~= '' and abbr_title(title) or 'Item ' .. id - return ext ~= '' and title .. "\t" .. ext:upper() or title + return title, ext end -- handle #@playlist menu update @@ -386,28 +392,32 @@ local function update_playlist_menu(menu) end if from > 1 then - submenu[#submenu + 1] = { - title = string.format('...\t[%d]', from - 1), + append_menu(submenu, { + title = '...', + shortcut = string.format('[%d]', from - 1), cmd = has_uosc and 'script-message-to uosc playlist' or 'ignore', - } + }) end for id = from, to do local item = playlist[id] if item then - submenu[#submenu + 1] = { + local title, ext = build_playlist_title(item, id - 1) + append_menu(submenu, { title = build_playlist_title(item, id - 1), + shortcut = (ext and ext ~= '') and ext:upper() or nil, cmd = string.format('playlist-play-index %d', id - 1), state = (item.playing or item.current) and { 'checked' } or {}, - } + }) end end if to < #playlist then - submenu[#submenu + 1] = { - title = string.format('...\t[%d]', #playlist - to), + append_menu(submenu, { + title = '...', + shortcut = string.format('[%d]', #playlist - to), cmd = has_uosc and 'script-message-to uosc playlist' or 'ignore', - } + }) end end @@ -420,10 +430,10 @@ local function update_profiles_menu(menu) for _, profile in ipairs(profile_list) do if not (profile.name == 'default' or profile.name:find('gui') or profile.name == 'encoding' or profile.name == 'libmpv') then - submenu[#submenu + 1] = { + append_menu(submenu, { title = profile.name, cmd = string.format('show-text %s; apply-profile %s', profile.name, profile.name), - } + }) end end end @@ -577,15 +587,6 @@ local function parse_input_conf(conf) return list end - local function append_menu(menu, type, title, cmd, submenu) - menu[#menu + 1] = { - type = type, - title = (title and o.escape_title) and title:gsub('&', '&&') or title, - cmd = cmd, - submenu = submenu, - } - end - local items = {} local by_id = {} @@ -602,15 +603,15 @@ local function parse_input_conf(conf) if not by_id[submenu_id] then local submenu = {} by_id[submenu_id] = submenu - append_menu(target_menu, 'submenu', name, nil, submenu) + append_menu(target_menu, { type = 'submenu', title = name, submenu = submenu }) end target_menu = by_id[submenu_id] else if name == '-' or (o.uosc_syntax and name:sub(1, 3) == '---') then - append_menu(target_menu, 'separator') + append_menu(target_menu, { type = 'separator' }) else - local title = (key ~= '' and key ~= '_') and (name .. "\t" .. key) or name - append_menu(target_menu, nil, title, cmd) + local shortcut = (key ~= '' and key ~= '_') and key or nil + append_menu(target_menu, { title = name, shortcut = shortcut, cmd = cmd }) end end end diff --git a/src/menu.c b/src/menu.c index f3c0dd0..a2d6323 100644 --- a/src/menu.c +++ b/src/menu.c @@ -45,6 +45,17 @@ static int build_state(mpv_node *node) { return fState; } +// build dwTypeData for menu item creation +static wchar_t *build_title(void *talloc_ctx, char *title, char *shortcut) { + if (shortcut && shortcut[0]) { + char *buf = talloc_asprintf(NULL, "%s\t%s", title, shortcut); + wchar_t *wbuf = mp_from_utf8(talloc_ctx, buf); + talloc_free(buf); + return wbuf; + } + return mp_from_utf8(talloc_ctx, title); +} + // build HMENU from mpv node // // node structure: @@ -54,6 +65,7 @@ static int build_state(mpv_node *node) { // "type" MPV_FORMAT_STRING // "title" MPV_FORMAT_STRING // "cmd" MPV_FORMAT_STRING +// "shortcut" MPV_FORMAT_STRING // "state" MPV_FORMAT_NODE_ARRAY[MPV_FORMAT_STRING] // "submenu" MPV_FORMAT_NODE_ARRAY[menu item] static void build_menu(void *talloc_ctx, HMENU hmenu, mpv_node *node) { @@ -68,6 +80,7 @@ static void build_menu(void *talloc_ctx, HMENU hmenu, mpv_node *node) { char *type = ""; char *title = NULL; char *cmd = NULL; + char *shortcut = NULL; int fState = 0; HMENU submenu = NULL; @@ -83,6 +96,8 @@ static void build_menu(void *talloc_ctx, HMENU hmenu, mpv_node *node) { cmd = value->u.string; } else if (strcmp(key, "type") == 0) { type = value->u.string; + } else if (strcmp(key, "shortcut") == 0) { + shortcut = value->u.string; } break; case MPV_FORMAT_NODE_ARRAY: @@ -102,7 +117,7 @@ static void build_menu(void *talloc_ctx, HMENU hmenu, mpv_node *node) { if (strcmp(type, "separator") == 0) { append_menu(hmenu, MIIM_FTYPE, MFT_SEPARATOR, 0, NULL, NULL, NULL); } else { - if (title == NULL || strlen(title) == 0) continue; + if (title == NULL || title[0] == '\0') continue; UINT fMask = MIIM_STRING | MIIM_STATE; bool grayed = false; @@ -116,8 +131,8 @@ static void build_menu(void *talloc_ctx, HMENU hmenu, mpv_node *node) { strcmp(cmd, "ignore") == 0; } int id = append_menu(hmenu, fMask, 0, (UINT)fState, - mp_from_utf8(talloc_ctx, title), submenu, - talloc_strdup(talloc_ctx, cmd)); + build_title(talloc_ctx, title, shortcut), + submenu, talloc_strdup(talloc_ctx, cmd)); if (grayed) EnableMenuItem(hmenu, id, MF_BYCOMMAND | MF_GRAYED); } }