diff options
| author | David Vazgenovich Shakaryan <dvshakaryan@gmail.com> | 2026-01-30 14:17:03 -0800 |
|---|---|---|
| committer | David Vazgenovich Shakaryan <dvshakaryan@gmail.com> | 2026-01-30 14:17:03 -0800 |
| commit | 37585452259b2c5ae32c3e50e97aa0aca545f52e (patch) | |
| tree | 98c1be30d6238ce9c1f50531e1040c2bd12ccce4 | |
| parent | 2451df1a217c49b471895941fb1734a25d55ba5c (diff) | |
| download | mpv-iptv-menu-37585452259b2c5ae32c3e50e97aa0aca545f52e.tar.gz mpv-iptv-menu-37585452259b2c5ae32c3e50e97aa0aca545f52e.tar.xz | |
| -rw-r--r-- | osd.lua | 2 | ||||
| -rw-r--r-- | rt.lua | 72 | ||||
| -rw-r--r-- | state.lua | 57 |
3 files changed, 83 insertions, 48 deletions
@@ -175,7 +175,7 @@ function mt:menu_title(menu) str = str:gsub('<num_total>', #menu.search_options) end - if menu.sorted then + if menu:is_sorted() then str = colour.icon_sorted .. icon.sorted .. ' ' .. col .. str end @@ -166,7 +166,7 @@ local function save_favourites() config.favourites_file, {favourites = state.favourites}) end -function rt.set_cursor(pos, opts) +local function set_cursor(pos, opts) local moved = state:menu():set_cursor(pos, osd:menu_lines(state), opts) if moved then osd:dirty() @@ -174,49 +174,49 @@ function rt.set_cursor(pos, opts) end function rt.cursor_up() - rt.set_cursor(state:menu().cursor - 1, {margin = config.scroll_margin}) + set_cursor(state:menu().cursor - 1, {margin = config.scroll_margin}) end function rt.cursor_down() - rt.set_cursor(state:menu().cursor + 1, {margin = config.scroll_margin}) + set_cursor(state:menu().cursor + 1, {margin = config.scroll_margin}) end function rt.cursor_start() - rt.set_cursor(1) + set_cursor(1) end function rt.cursor_end() - rt.set_cursor(#state:menu().options) + set_cursor(#state:menu().options) end function rt.cursor_page_up() - rt.set_cursor( + set_cursor( state:menu().cursor - osd:menu_lines(state), {keep_offset = true, margin = config.scroll_margin}) end function rt.cursor_page_down() - rt.set_cursor( + set_cursor( state:menu().cursor + osd:menu_lines(state), {keep_offset = true, margin = config.scroll_margin}) end function rt.cursor_wheel_up() - rt.set_cursor(state:menu().cursor - 1, {keep_offset = true}) + set_cursor(state:menu().cursor - 1, {keep_offset = true}) end function rt.cursor_wheel_down() - rt.set_cursor(state:menu().cursor + 1, {keep_offset = true}) + set_cursor(state:menu().cursor + 1, {keep_offset = true}) end function rt.cursor_wheel_page_up() - rt.set_cursor( + set_cursor( state:menu().cursor - osd:menu_lines(state), {keep_offset = true}) end function rt.cursor_wheel_page_down() - rt.set_cursor( + set_cursor( state:menu().cursor + osd:menu_lines(state), {keep_offset = true}) end @@ -224,7 +224,7 @@ end local function cursor_to_id(id) for i, v in ipairs(state:menu().options) do if v.id == id then - rt.set_cursor(i, {centre = true}) + set_cursor(i, {centre = true}) return end end @@ -232,13 +232,13 @@ end local function move_option(pos, opts) local menu = state:menu() - if menu.group_id ~= 'favourites' or menu.sorted then + if menu.group_id ~= 'favourites' or menu:is_sorted() then return end local prev_cursor = menu.cursor local opts = opts or {} - rt.set_cursor(pos, opts) + set_cursor(pos, opts) if menu.cursor == prev_cursor then return end @@ -313,26 +313,26 @@ function rt.push_group_menu(group) }) end --- refresh options when navigating up the stack to a previous favourites menu. --- existing menu options are never removed, even if unfavourited. -local function refresh_favourites_menu() +-- refresh menu options from current catalogue state, while keeping existing +-- options that have been removed. this is designed to update the favourites +-- menu when navigating up the stack. +local function merge_refreshed_menu_options() local menu = state:menu() - local opt = menu.options[menu.cursor] - local sorted = menu.sorted - if sorted then - menu:set_sort(false) - end + local pos = menu.cursor + local top = menu.view_top + local opt = menu.options[pos] - menu.options = util.stable_kmerge( - menu.options, + menu:set_options(util.stable_kmerge( + menu:master_options(), rx.menu_options_group(ctx.catalogue:get(menu.group_id)), - 'id') + 'id')) - if sorted then - menu:set_sort(true, rx.sort_menu_options) - end if opt then - cursor_to_id(opt.id) + if menu.options[pos].id and menu.options[pos].id == opt.id then + set_cursor(pos, {view_top=top}) + else + cursor_to_id(opt.id) + end end end @@ -344,7 +344,7 @@ function rt.prev_menu() rt.push_group_menu(ctx.catalogue:get(state.menus[1].group_id)) else if state:menu().group_id == 'favourites' then - refresh_favourites_menu() + merge_refreshed_menu_options() end end @@ -411,7 +411,7 @@ function rt.goto_option() elseif menu.type == 'search' then state.depth = state.depth - 1 if state:menu().group_id == 'favourites' then - refresh_favourites_menu() + merge_refreshed_menu_options() end end @@ -471,7 +471,7 @@ local function open_option_channel_epg(opt) type = 'epg', img_url = opt.img_url, }) - rt.set_cursor(idx, {centre = true}) + set_cursor(idx, {centre = true}) osd:dirty() end @@ -664,7 +664,7 @@ function rt.toggle_menu_sort() return end - menu:set_sort(not menu.sorted, rx.sort_menu_options) + menu:set_sort(not menu:is_sorted() and rx.sort_menu_options or nil) osd:dirty() end @@ -680,7 +680,7 @@ function rt.click_menu() return end - rt.set_cursor(pos) + set_cursor(pos) end function rt.dbl_click_menu() @@ -692,7 +692,7 @@ function rt.dbl_click_menu() -- title if line < 0 then if line == -1 then - rt.set_cursor(1) + set_cursor(1) else state.depth = state.depth + line + 1 osd:dirty() @@ -711,7 +711,7 @@ end function rt.dbl_click_scrollbar() -- set_cursor handles out-of-bounds moves (when ratio == 1) - rt.set_cursor( + set_cursor( math.floor(osd.mstate.ratio * #state:menu().options) + 1, {centre = true}) end @@ -100,6 +100,8 @@ function menu_mt:set_cursor(pos, lines, opts) top = pos - math.floor((lines - 1) / 2) elseif opts and opts.keep_offset then top = top + pos - self.cursor + elseif opts and opts.view_top then + top = opts.view_top elseif margin > 0 then margin = math.max(0, math.min( margin, @@ -120,25 +122,58 @@ function menu_mt:set_cursor(pos, lines, opts) return true end -function menu_mt:set_sort(bool, f) - if not self.sorted == not bool then - return - end +function menu_mt:options_key() + return self.type == 'search' and 'search_options' or 'options' +end - local key = self.type == 'search' and 'search_options' or 'options' - if bool then - self['orig_' .. key] = self[key] - self[key] = util.copy_table(self[key]) +function menu_mt:set_sort(f) + local key = self:options_key() + local orig_key = 'orig_' .. key + + if f then + if not self[orig_key] then + self[orig_key] = self[key] + end + self[key] = util.copy_table(self[orig_key]) f(self[key]) + elseif self.sort_f then + self[key] = self[orig_key] + self[orig_key] = nil + end + + self.sort_f = f + + if self.type == 'search' then + self:update_search_matches() + end +end + +function menu_mt:is_sorted() + return self.sort_f ~= nil +end + +function menu_mt:master_options() + local key = self:options_key() + return self.sort_f and self['orig_' .. key] or self[key] +end + +function menu_mt:set_options(options) + local key = self:options_key() + if self.sort_f then + self['orig_' .. key] = options + self[key] = util.copy_table(options) + self.sort_f(self[key]) else - self[key] = self['orig_' .. key] - self['orig_' .. key] = nil + self[key] = options end if self.type == 'search' then self:update_search_matches() end - self.sorted = bool + + -- previous position could have become invalid. reset to top and let + -- caller deal with remembering position if it is needed. + self:set_cursor(1) end function menu_mt:set_search_cursor(pos) |
