From 39848afad2c00f2eaeabf312a8728ba610ab21c2 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sat, 8 May 2021 20:26:07 +0930 Subject: [PATCH 01/18] mouse-mode: added experimental mouse based selector function currently this is just an experiment, and the function only works with non-scrolling directories --- file-browser.lua | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/file-browser.lua b/file-browser.lua index 6ba98c5..bf0a206 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -89,6 +89,9 @@ local o = { --directory to load external modules - currently just user-input-module module_directory = "~~/script-modules", + --enable experimental mouse mode + mouse_mode = false, + --force file-browser to use a specific text alignment (default: top-left) --uses ass tag alignment numbers: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3 --set to 0 to use the default mpv osd-align options @@ -858,7 +861,14 @@ local function toggle_select_mode() end end - +--update the selected item based on the mouse position +local function update_mouse_pos(_, mouse_pos) + if not mouse_pos.hover then return end + local scale = mp.get_property_number("osd-height", 0) / 720 + local header_offset = 65 + state.selected = math.ceil((mouse_pos.y-header_offset) / (25* scale)) + update_ass() +end -------------------------------------------------------------------------------------------------------- -----------------------------------------Directory Movement--------------------------------------------- @@ -1118,6 +1128,8 @@ local function open() mp.add_forced_key_binding(v[1], 'dynamic/'..v[2], v[3], v[4]) end + if o.mouse_mode then mp.observe_property("mouse-pos", "native", update_mouse_pos) end + utils.shared_script_property_set("file_browser-open", "yes") state.hidden = false if state.directory == nil then @@ -1141,6 +1153,7 @@ local function close() end utils.shared_script_property_set("file_browser-open", "no") + if o.mouse_mode then mp.unobserve_property(update_mouse_pos) end state.hidden = true ass:remove() end From d87a235904a6b2006b1426e730200c3a70aad219 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Fri, 16 Sep 2022 22:52:24 +0930 Subject: [PATCH 02/18] mouse-mode: add support for custom scrolling (#22) Implements a new scrolling system for mouse-mode and properly calculates the hovered item when scrolling the list. This hover should work with custom font sizes, but currently the calculations are not adding up for the header, so that is hardcoded. See the next commit for keybinds. --- file-browser.lua | 53 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/file-browser.lua b/file-browser.lua index bf0a206..e04a9d4 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -186,11 +186,12 @@ local style = { } local state = { - list = {}, - selected = 1, - hidden = true, - flag_update = false, - keybinds = nil, + list = {}, -- list of items + selected = 1, -- currently selected item + scroll_offset = 0, + hidden = true, -- whether the browser is hidden + flag_update = false, -- should we redraw the browser when next opened + keybinds = nil, -- array of dynamic deybinds parser = nil, directory = nil, @@ -710,18 +711,13 @@ local function update_ass() local start = 1 local finish = start+o.num_entries-1 - --handling cursor positioning - local mid = math.ceil(o.num_entries/2)+1 - if state.selected+mid > finish then - local offset = state.selected - finish + mid - - --if we've overshot the end of the list then undo some of the offset - if finish + offset > #state.list then - offset = offset - ((finish+offset) - #state.list) + --handling the offset caused by scrolling + if state.scroll_offset > 0 then + if finish + state.scroll_offset > #state.list then + state.scroll_offset = #state.list - finish end - - start = start + offset - finish = finish + offset + start = start + state.scroll_offset + finish = finish + state.scroll_offset end --making sure that we don't overstep the boundaries @@ -832,6 +828,12 @@ local function scroll(n, wrap) end if state.multiselect_start then drag_select(original_pos, state.selected) end + + --moves the scroll window down so that the selected item is in the middle of the screen + state.scroll_offset = state.selected - (math.ceil(o.num_entries/2)-1) + if state.scroll_offset < 0 or (state.scroll_offset + o.num_entries) > #state.list then + state.scroll_offset = 0 + end update_ass() end @@ -863,13 +865,30 @@ end --update the selected item based on the mouse position local function update_mouse_pos(_, mouse_pos) + if not mouse_pos then mouse_pos = mp.get_property_native("mouse-pos") end if not mouse_pos.hover then return end local scale = mp.get_property_number("osd-height", 0) / 720 + + --this will currently not work with different sized headers + --for some reason the scaling calculation works differently for the header local header_offset = 65 - state.selected = math.ceil((mouse_pos.y-header_offset) / (25* scale)) + if state.scroll_offset > 0 then + header_offset = header_offset + o.font_size_wrappers*scale + end + + state.selected = math.ceil((mouse_pos.y-header_offset) / (o.font_size_body* scale)) + state.scroll_offset update_ass() end +-- scrolls the view window when using mouse mode +local function wheel(direction) + state.scroll_offset = state.scroll_offset + direction + if state.scroll_offset < 0 or (state.scroll_offset + o.num_entries) > #state.list then + state.scroll_offset = 0 + end + update_mouse_pos() +end + -------------------------------------------------------------------------------------------------------- -----------------------------------------Directory Movement--------------------------------------------- -------------------------------------------------------------------------------------------------------- From fe3db26dc6cd56272b7683b5f289cb2ecc73beb6 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Fri, 16 Sep 2022 22:53:05 +0930 Subject: [PATCH 03/18] mouse-mode: add default keybinds (#22) --- file-browser.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/file-browser.lua b/file-browser.lua index e04a9d4..8c47b93 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -1480,6 +1480,23 @@ state.keybinds = { {'Ctrl+a', 'select_all', select_all} } +local function add_key(key) + table.insert(state.keybinds, key) +end + +--default keybinds for the experimental mouse-mode +if o.mouse_mode then + add_key{'WHEEL_DOWN', 'mouse/scroll_down', function() wheel(1) end} + add_key{'WHEEL_UP', 'mouse/scroll_up', function() wheel(-1) end} + add_key{'MBTN_LEFT', 'mouse/down_dir', down_dir} + add_key{'MBTN_RIGHT', 'mouse/up_dir', up_dir} + add_key{'Shift+MBTN_LEFT', 'mouse/play_left', function() open_file('replace', false) end} + + add_key{'MBTN_MID', 'mouse/play_mid', function() open_file('replace', false) end} + add_key{'Shift+MBTN_MID', 'mouse/play_append', function() open_file('append-play', false) end} + add_key{'Alt+MBTN_MID', 'mouse/play_autoload', function() open_file('replace', true) end} +end + --a map of key-keybinds - only saves the latest keybind if multiple have the same key code local top_level_keys = {} From 9c1dd6d5e411a836b7e45dc6991e0aa2c26ddf64 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Fri, 16 Sep 2022 23:19:20 +0930 Subject: [PATCH 04/18] mouse-mode: don't try to calculate selection in empty lists --- file-browser.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/file-browser.lua b/file-browser.lua index 8c47b93..7325fa8 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -865,6 +865,8 @@ end --update the selected item based on the mouse position local function update_mouse_pos(_, mouse_pos) + if state.hidden or #state.list == 0 then return end + if not mouse_pos then mouse_pos = mp.get_property_native("mouse-pos") end if not mouse_pos.hover then return end local scale = mp.get_property_number("osd-height", 0) / 720 From f75573dc707357cf3dfcd4260c6488f7107d76b8 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Fri, 16 Sep 2022 23:19:39 +0930 Subject: [PATCH 05/18] mouse-mode: double right click jumps to root --- file-browser.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/file-browser.lua b/file-browser.lua index 7325fa8..150d432 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -1492,6 +1492,7 @@ if o.mouse_mode then add_key{'WHEEL_UP', 'mouse/scroll_up', function() wheel(-1) end} add_key{'MBTN_LEFT', 'mouse/down_dir', down_dir} add_key{'MBTN_RIGHT', 'mouse/up_dir', up_dir} + add_key{'MBTN_RIGHT_DBL', 'mouse/goto_root', goto_root} add_key{'Shift+MBTN_LEFT', 'mouse/play_left', function() open_file('replace', false) end} add_key{'MBTN_MID', 'mouse/play_mid', function() open_file('replace', false) end} From b4de77d5c42baeff4a95fc3a93bf571be61a5ba8 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sun, 18 Sep 2022 14:58:43 +0930 Subject: [PATCH 06/18] mouse-mode: support different header font sizes --- file-browser.lua | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/file-browser.lua b/file-browser.lua index 150d432..663bc0c 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -865,17 +865,16 @@ end --update the selected item based on the mouse position local function update_mouse_pos(_, mouse_pos) - if state.hidden or #state.list == 0 then return end + if not o.mouse_mode or state.hidden or #state.list == 0 then return end if not mouse_pos then mouse_pos = mp.get_property_native("mouse-pos") end if not mouse_pos.hover then return end local scale = mp.get_property_number("osd-height", 0) / 720 + local osd_offset = 15 - --this will currently not work with different sized headers - --for some reason the scaling calculation works differently for the header - local header_offset = 65 + local header_offset = osd_offset + (2 * scale * o.font_size_header) if state.scroll_offset > 0 then - header_offset = header_offset + o.font_size_wrappers*scale + header_offset = header_offset + (o.font_size_wrappers * scale) end state.selected = math.ceil((mouse_pos.y-header_offset) / (o.font_size_body* scale)) + state.scroll_offset From 668ff82f39be14b128caf491f619559e23f43969 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sun, 18 Sep 2022 16:11:57 +0930 Subject: [PATCH 07/18] fix broken wrapping with new scroll logic --- file-browser.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/file-browser.lua b/file-browser.lua index 663bc0c..b333726 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -831,7 +831,7 @@ local function scroll(n, wrap) --moves the scroll window down so that the selected item is in the middle of the screen state.scroll_offset = state.selected - (math.ceil(o.num_entries/2)-1) - if state.scroll_offset < 0 or (state.scroll_offset + o.num_entries) > #state.list then + if state.scroll_offset < 0 then state.scroll_offset = 0 end update_ass() @@ -884,8 +884,10 @@ end -- scrolls the view window when using mouse mode local function wheel(direction) state.scroll_offset = state.scroll_offset + direction - if state.scroll_offset < 0 or (state.scroll_offset + o.num_entries) > #state.list then + if state.scroll_offset < 0 then state.scroll_offset = 0 + elseif (state.scroll_offset + o.num_entries) > #state.list then + state.scroll_offset = #state.list - o.num_entries end update_mouse_pos() end From 47bcdd15ac30fbdfad231a039001173900cb5a0d Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sun, 18 Sep 2022 16:12:42 +0930 Subject: [PATCH 08/18] mouse-mode: experimental new alignment logic --- file-browser.lua | 52 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/file-browser.lua b/file-browser.lua index b333726..395e8fd 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -189,6 +189,7 @@ local state = { list = {}, -- list of items selected = 1, -- currently selected item scroll_offset = 0, + osd_alignment = "", hidden = true, -- whether the browser is hidden flag_update = false, -- should we redraw the browser when next opened keybinds = nil, -- array of dynamic deybinds @@ -204,6 +205,12 @@ local state = { selection = {} } +--if the alignment isn't automated then we'll store a static value +--numbers defined here: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3 +if o.alignment >= 7 then state.osd_alignment = "top" +elseif o.alignment >= 4 then state.osd_alignment = "center" +elseif o.alignment >= 1 then state.osd_alignment = "bottom" end + --the parser table actually contains 3 entries for each parser --a numeric entry which represents the priority of the parsers and has the parser object as the value --a string entry representing the id of each parser and with the parser object as the value @@ -727,7 +734,11 @@ local function update_ass() if not overflow then finish = #state.list end --adding a header to show there are items above in the list - if start > 1 then append(style.footer_header..(start-1)..' item(s) above\\N\\N') end + append(style.footer_header) + if start > 1 then + append((start-1)..' item(s) above') + end + append('\\h\\N\\N') for i=start, finish do local v = state.list[i] @@ -765,7 +776,11 @@ local function update_ass() newline() end - if overflow then append('\\N'..style.footer_header..#state.list-finish..' item(s) remaining') end + -- always draw a gap for the footer to reserve space if osd is aligned to the bottom + append(style.footer_header.."\\N\\h") + if overflow then + append(#state.list-finish..' item(s) remaining') + end ass:update() end @@ -870,14 +885,27 @@ local function update_mouse_pos(_, mouse_pos) if not mouse_pos then mouse_pos = mp.get_property_native("mouse-pos") end if not mouse_pos.hover then return end local scale = mp.get_property_number("osd-height", 0) / 720 - local osd_offset = 15 + local osd_offset = 10 - local header_offset = osd_offset + (2 * scale * o.font_size_header) - if state.scroll_offset > 0 then - header_offset = header_offset + (o.font_size_wrappers * scale) + --calculate position when browser is aligned to the top of the screen + if state.osd_alignment == "top" then + local header_offset = osd_offset + (2 * scale * o.font_size_header) + (o.font_size_wrappers * scale * 2) + + state.selected = math.ceil((mouse_pos.y-header_offset) / (o.font_size_body* scale)) + state.scroll_offset + + --calculate position when browser is aligned to the bottom of the screen + --this calculation is slightly off when a bottom wrapper exists, hence the `+5`. + --I do not know what causes this. + elseif state.osd_alignment == "bottom" then + mouse_pos.y = (mp.get_property_number("osd-height", 0) - osd_offset) - mouse_pos.y + + local bottom = math.min(#state.list, state.scroll_offset + o.num_entries) + local footer_offset = (bottom < #state.list) and (o.font_size_wrappers * scale) + 5 or 0 + footer_offset = footer_offset + + state.selected = bottom - math.floor((mouse_pos.y - footer_offset) / (o.font_size_body* scale)) end - state.selected = math.ceil((mouse_pos.y-header_offset) / (o.font_size_body* scale)) + state.scroll_offset update_ass() end @@ -2121,6 +2149,16 @@ mp.observe_property('dvd-device', 'string', function(_, device) dvd_device = API.fix_path(device, true) end) +--if the osd-alignment changes while the browser is open then update immediately +if o.alignment == 0 then + mp.observe_property("osd-align-x", "string", function() update_ass() end) + mp.observe_property("osd-align-y", "string", function(_, alignment) + state.osd_alignment = alignment + update_mouse_pos() + update_ass() + end) +end + --declares the keybind to open the browser mp.add_key_binding('MENU','browse-files', toggle) mp.add_key_binding('Ctrl+o','open-browser', open) From 7b2229aa3b98245dcd271ca50c99457bcdd005cd Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sun, 18 Sep 2022 16:25:56 +0930 Subject: [PATCH 09/18] fix bugs when opening directories with new scrolling logic --- file-browser.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/file-browser.lua b/file-browser.lua index 395e8fd..5138ea4 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -257,7 +257,7 @@ local compatible_file_extensions = { local __cache = {} __cache.cached_values = { - "directory", "directory_label", "list", "selected", "selection", "parser", "empty_text", "co" + "directory", "directory_label", "list", "selected", "selection", "parser", "empty_text", "co", "scroll_offset" } --inserts latest state values onto the cache stack @@ -723,9 +723,14 @@ local function update_ass() if finish + state.scroll_offset > #state.list then state.scroll_offset = #state.list - finish end - start = start + state.scroll_offset - finish = finish + state.scroll_offset end + if state.selected < state.scroll_offset or state.selected > (state.scroll_offset + o.num_entries) then + state.scroll_offset = state.selected - (math.ceil(o.num_entries/2)-1) + if state.scroll_offset < 0 then state.scroll_offset = 0 end + end + + start = start + state.scroll_offset + finish = finish + state.scroll_offset --making sure that we don't overstep the boundaries if start < 1 then start = 1 end From aee15b94a3951da64c4d643a1f39dc35eeac3f9c Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sun, 18 Sep 2022 16:55:57 +0930 Subject: [PATCH 10/18] mouse-mode: osd-offset is properly scaled --- file-browser.lua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/file-browser.lua b/file-browser.lua index 5138ea4..f5ae5a5 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -890,25 +890,24 @@ local function update_mouse_pos(_, mouse_pos) if not mouse_pos then mouse_pos = mp.get_property_native("mouse-pos") end if not mouse_pos.hover then return end local scale = mp.get_property_number("osd-height", 0) / 720 - local osd_offset = 10 + local osd_offset = scale * mp.get_property("osd-margin-y", 22) --calculate position when browser is aligned to the top of the screen if state.osd_alignment == "top" then - local header_offset = osd_offset + (2 * scale * o.font_size_header) + (o.font_size_wrappers * scale * 2) + local header_offset = osd_offset + (2 * scale * o.font_size_header) + (state.scroll_offset > 0 and (scale * o.font_size_wrappers) or 0) - state.selected = math.ceil((mouse_pos.y-header_offset) / (o.font_size_body* scale)) + state.scroll_offset + state.selected = math.ceil((mouse_pos.y-header_offset) / (scale * o.font_size_body)) + state.scroll_offset --calculate position when browser is aligned to the bottom of the screen - --this calculation is slightly off when a bottom wrapper exists, hence the `+5`. + --this calculation is slightly off when a bottom wrapper exists, --I do not know what causes this. elseif state.osd_alignment == "bottom" then - mouse_pos.y = (mp.get_property_number("osd-height", 0) - osd_offset) - mouse_pos.y + mouse_pos.y = (mp.get_property_number("osd-height", 0)) - mouse_pos.y local bottom = math.min(#state.list, state.scroll_offset + o.num_entries) - local footer_offset = (bottom < #state.list) and (o.font_size_wrappers * scale) + 5 or 0 - footer_offset = footer_offset + local footer_offset = (2 * scale * o.font_size_wrappers) + osd_offset - state.selected = bottom - math.floor((mouse_pos.y - footer_offset) / (o.font_size_body* scale)) + state.selected = bottom - math.floor((mouse_pos.y - footer_offset) / (scale * o.font_size_body)) end update_ass() From e08e878d9465e6014ca4b69971ec82e3f24b564b Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sun, 18 Sep 2022 16:59:36 +0930 Subject: [PATCH 11/18] mouse-mode: reset scroll-offset when opening directory Also undo a buggy previous attempt to rectify this that caused infinite scrolling behaviour when moving the mouse above or below the viewable list. --- file-browser.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/file-browser.lua b/file-browser.lua index f5ae5a5..3f62beb 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -724,10 +724,6 @@ local function update_ass() state.scroll_offset = #state.list - finish end end - if state.selected < state.scroll_offset or state.selected > (state.scroll_offset + o.num_entries) then - state.scroll_offset = state.selected - (math.ceil(o.num_entries/2)-1) - if state.scroll_offset < 0 then state.scroll_offset = 0 end - end start = start + state.scroll_offset finish = finish + state.scroll_offset @@ -1026,6 +1022,7 @@ local function update_list(moving_adjacent) msg.verbose('opening directory: ' .. state.directory) state.selected = 1 + state.scroll_offset = 0 state.selection = {} --loads the current directry from the cache to save loading time From 084cb87b1d200305700888ebc785f6eafc321ab8 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sun, 18 Sep 2022 17:00:11 +0930 Subject: [PATCH 12/18] undo the reserved space for the top wrapper --- file-browser.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/file-browser.lua b/file-browser.lua index 3f62beb..89e5a97 100644 --- a/file-browser.lua +++ b/file-browser.lua @@ -735,11 +735,9 @@ local function update_ass() if not overflow then finish = #state.list end --adding a header to show there are items above in the list - append(style.footer_header) if start > 1 then - append((start-1)..' item(s) above') + append(style.footer_header..(start-1)..' item(s) above\\N\\N') end - append('\\h\\N\\N') for i=start, finish do local v = state.list[i] From 21ff231bf49b941a2d189e1e1fbba6f2f0dfd95f Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sat, 16 Nov 2024 11:22:48 +1030 Subject: [PATCH 13/18] fix incorrect module name from merge --- modules/keybinds.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/keybinds.lua b/modules/keybinds.lua index 3c64e14..c400750 100644 --- a/modules/keybinds.lua +++ b/modules/keybinds.lua @@ -49,8 +49,8 @@ end if o.mouse_mode then add_key{'WHEEL_DOWN', 'mouse/scroll_down', function() cursor.wheel(1) end} add_key{'WHEEL_UP', 'mouse/scroll_up', function() cursor.wheel(-1) end} - add_key{'MBTN_LEFT', 'mouse/down_dir', cursor.down_dir} - add_key{'MBTN_RIGHT', 'mouse/up_dir', cursor.up_dir} + add_key{'MBTN_LEFT', 'mouse/down_dir', movement.down_dir} + add_key{'MBTN_RIGHT', 'mouse/up_dir', movement.up_dir} add_key{'MBTN_RIGHT_DBL', 'mouse/goto_root', movement.goto_root} add_key{'Shift+MBTN_LEFT', 'mouse/play_left', function() playlist.add_files('replace', false) end} add_key{'MBTN_MID', 'mouse/play_mid', function() playlist.add_files('replace', false) end} From f75eb0a54141e8f8e579ba03b0bee6a72d5562b3 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sat, 16 Nov 2024 11:31:28 +1030 Subject: [PATCH 14/18] mouse_mode: update cursor position calculation for scaling_factor opts We no-longer set the font sizes directly as we did back when this code was first written. --- modules/globals.lua | 8 ++++---- modules/navigation/cursor.lua | 22 +++++++++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/modules/globals.lua b/modules/globals.lua index cd4084c..7ae8cb6 100644 --- a/modules/globals.lua +++ b/modules/globals.lua @@ -20,15 +20,15 @@ assert(mp.create_osd_overlay, "Script requires minimum mpv version 0.33") globals.ass = mp.create_osd_overlay("ass-events") globals.ass.res_y = 720 / o.scaling_factor_base -local BASE_FONT_SIZE = 25 +globals.BASE_FONT_SIZE = 25 globals.style = { global = o.alignment == 0 and "" or ([[{\an%d}]]):format(o.alignment), -- full line styles - header = ([[{\r\q2\b%s\fs%d\fn%s\c&H%s&}]]):format((o.font_bold_header and "1" or "0"), o.scaling_factor_header*BASE_FONT_SIZE, o.font_name_header, o.font_colour_header), - body = ([[{\r\q2\fs%d\fn%s\c&H%s&}]]):format(BASE_FONT_SIZE, o.font_name_body, o.font_colour_body), - footer_header = ([[{\r\q2\fs%d\fn%s\c&H%s&}]]):format(o.scaling_factor_wrappers*BASE_FONT_SIZE, o.font_name_wrappers, o.font_colour_wrappers), + header = ([[{\r\q2\b%s\fs%d\fn%s\c&H%s&}]]):format((o.font_bold_header and "1" or "0"), o.scaling_factor_header*globals.BASE_FONT_SIZE, o.font_name_header, o.font_colour_header), + body = ([[{\r\q2\fs%d\fn%s\c&H%s&}]]):format(globals.BASE_FONT_SIZE, o.font_name_body, o.font_colour_body), + footer_header = ([[{\r\q2\fs%d\fn%s\c&H%s&}]]):format(o.scaling_factor_wrappers*globals.BASE_FONT_SIZE, o.font_name_wrappers, o.font_colour_wrappers), --small section styles (for colours) multiselect = ([[{\c&H%s&}]]):format(o.font_colour_multiselect), diff --git a/modules/navigation/cursor.lua b/modules/navigation/cursor.lua index f605579..f7b2678 100644 --- a/modules/navigation/cursor.lua +++ b/modules/navigation/cursor.lua @@ -4,6 +4,8 @@ -------------------------------------------------------------------------------------------------------- local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' local o = require 'modules.options' local g = require 'modules.globals' @@ -133,14 +135,23 @@ function cursor.update_mouse_pos(_, mouse_pos) if not mouse_pos then mouse_pos = mp.get_property_native("mouse-pos", {}) end if not mouse_pos.hover then return end - local scale = mp.get_property_number("osd-height", 0) / 720 + msg.trace('received mouse pos:', utils.to_string(mouse_pos)) + + local scale = mp.get_property_number("osd-height", 0) / g.ass.res_y local osd_offset = scale * mp.get_property("osd-margin-y", 22) + local font_size_body = g.BASE_FONT_SIZE + local font_size_header = g.BASE_FONT_SIZE * o.scaling_factor_header + local font_size_wrappers = g.BASE_FONT_SIZE * o.scaling_factor_wrappers + + msg.trace('calculating mouse pos for', g.state.osd_alignment, 'alignment') + --calculate position when browser is aligned to the top of the screen if g.state.osd_alignment == "top" then - local header_offset = osd_offset + (2 * scale * o.font_size_header) + (g.state.scroll_offset > 0 and (scale * o.font_size_wrappers) or 0) + local header_offset = osd_offset + (2 * scale * font_size_header) + (g.state.scroll_offset > 0 and (scale * font_size_wrappers) or 0) + msg.trace('calculated header offset', header_offset) - g.state.selected = math.ceil((mouse_pos.y-header_offset) / (scale * o.font_size_body)) + g.state.scroll_offset + g.state.selected = math.ceil((mouse_pos.y-header_offset) / (scale * font_size_body)) + g.state.scroll_offset --calculate position when browser is aligned to the bottom of the screen --this calculation is slightly off when a bottom wrapper exists, @@ -149,9 +160,10 @@ function cursor.update_mouse_pos(_, mouse_pos) mouse_pos.y = (mp.get_property_number("osd-height", 0)) - mouse_pos.y local bottom = math.min(#g.state.list, g.state.scroll_offset + o.num_entries) - local footer_offset = (2 * scale * o.font_size_wrappers) + osd_offset + local footer_offset = (2 * scale * font_size_wrappers) + osd_offset + msg.trace('calculated footer offset', footer_offset) - g.state.selected = bottom - math.floor((mouse_pos.y - footer_offset) / (scale * o.font_size_body)) + g.state.selected = bottom - math.floor((mouse_pos.y - footer_offset) / (scale * font_size_body)) end ass.update_ass() From 7cf372b1bc2407e9efba2463601810f826b07e56 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sat, 16 Nov 2024 11:31:42 +1030 Subject: [PATCH 15/18] fix scroll offset calculation bugs --- modules/ass.lua | 2 +- modules/navigation/cursor.lua | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/ass.lua b/modules/ass.lua index 71d26b1..0bf4d07 100644 --- a/modules/ass.lua +++ b/modules/ass.lua @@ -77,7 +77,7 @@ local function update_ass() end local start = 1 - local finish = start+o.num_entries-1 + local finish = start + math.min(o.num_entries, #state.list) - 1 --handling the offset caused by scrolling if state.scroll_offset > 0 then diff --git a/modules/navigation/cursor.lua b/modules/navigation/cursor.lua index f7b2678..8705c9f 100644 --- a/modules/navigation/cursor.lua +++ b/modules/navigation/cursor.lua @@ -172,10 +172,11 @@ end -- scrolls the view window when using mouse mode function cursor.wheel(direction) g.state.scroll_offset = g.state.scroll_offset + direction + if (g.state.scroll_offset + o.num_entries) > #g.state.list then + g.state.scroll_offset = #g.state.list - o.num_entries + end if g.state.scroll_offset < 0 then g.state.scroll_offset = 0 - elseif (g.state.scroll_offset + o.num_entries) > #g.state.list then - g.state.scroll_offset = #g.state.list - o.num_entries end cursor.update_mouse_pos() end From 57e9ec1590685d9fe7bce9cbc02067aa6cb63976 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Fri, 20 Dec 2024 15:15:23 +1030 Subject: [PATCH 16/18] fix offset and keyind code bugs --- modules/navigation/scanning.lua | 2 +- modules/utils.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/navigation/scanning.lua b/modules/navigation/scanning.lua index 0d6ea5f..ca9bcf2 100644 --- a/modules/navigation/scanning.lua +++ b/modules/navigation/scanning.lua @@ -83,7 +83,7 @@ local function update_list(moving_adjacent) msg.verbose('opening directory: ' .. g.state.directory) g.state.selected = 1 - g.state.scroll_offset = 1 + g.state.scroll_offset = 0 g.state.selection = {} --loads the current directry from the cache to save loading time diff --git a/modules/utils.lua b/modules/utils.lua index cbe705a..a8845ee 100644 --- a/modules/utils.lua +++ b/modules/utils.lua @@ -405,7 +405,7 @@ fb_utils.code_fns = { n = function(item, s) return item and (item.label or item.name) or "" end, i = function(item, s) local i = fb_utils.list.indexOf(s.list, item) - return i ~= -1 and ('%0'..math.ceil(math.log10(#s.list))..'d'):format(i) or 0 + return ('%0'..math.ceil(math.log10(#s.list))..'d'):format(i ~= -1 and i or 0) end, j = function (item, s) return fb_utils.list.indexOf(s.list, item) ~= -1 and math.abs(fb_utils.list.indexOf( fb_utils.sort_keys(s.selection) , item)) or 0 From 140a9c9c98a099b85453dc8b09528bc9de06e84e Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Fri, 20 Dec 2024 15:17:23 +1030 Subject: [PATCH 17/18] consider format strings when calculating header height Takes the number of header newlines into account when calculating the header height. This is experimental and may change. --- modules/navigation/cursor.lua | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/navigation/cursor.lua b/modules/navigation/cursor.lua index 8705c9f..552ddc5 100644 --- a/modules/navigation/cursor.lua +++ b/modules/navigation/cursor.lua @@ -129,6 +129,22 @@ function cursor.toggle_select_mode() end end +local function count_substrings(str, substring) + local count = 0 + for match in string.gmatch(str, substring) do + count = count + 1 + end + return count +end + +local font_size_body = g.BASE_FONT_SIZE +local font_size_header = g.BASE_FONT_SIZE * o.scaling_factor_header +local font_size_wrappers = g.BASE_FONT_SIZE * o.scaling_factor_wrappers + +local num_header_lines = count_substrings(o.format_string_header, '\\N') + 1 +local num_twrapper_lines = count_substrings(o.format_string_topwrapper, '\\N') + 1 +local num_bwrapper_lines = count_substrings(o.format_string_bottomwrapper, '\\N') + 1 + --update the selected item based on the mouse position function cursor.update_mouse_pos(_, mouse_pos) if not o.mouse_mode or g.state.hidden or #g.state.list == 0 then return end @@ -140,15 +156,12 @@ function cursor.update_mouse_pos(_, mouse_pos) local scale = mp.get_property_number("osd-height", 0) / g.ass.res_y local osd_offset = scale * mp.get_property("osd-margin-y", 22) - local font_size_body = g.BASE_FONT_SIZE - local font_size_header = g.BASE_FONT_SIZE * o.scaling_factor_header - local font_size_wrappers = g.BASE_FONT_SIZE * o.scaling_factor_wrappers - msg.trace('calculating mouse pos for', g.state.osd_alignment, 'alignment') --calculate position when browser is aligned to the top of the screen if g.state.osd_alignment == "top" then - local header_offset = osd_offset + (2 * scale * font_size_header) + (g.state.scroll_offset > 0 and (scale * font_size_wrappers) or 0) + local header_offset = osd_offset + (num_header_lines * scale * font_size_header) + if g.state.scroll_offset > 0 then header_offset = header_offset + (num_twrapper_lines * scale * font_size_wrappers) end msg.trace('calculated header offset', header_offset) g.state.selected = math.ceil((mouse_pos.y-header_offset) / (scale * font_size_body)) + g.state.scroll_offset From 06f4b9338b02a79ab4a881fb8462b631109ee8a9 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Fri, 21 Mar 2025 23:05:58 +1030 Subject: [PATCH 18/18] mouse-support: update code to use type annotations --- modules/defs/mp/defaults.lua | 8 ++++++++ modules/defs/state.lua | 1 + modules/globals.lua | 9 ++++++--- modules/keybinds.lua | 1 + modules/navigation/cursor.lua | 16 +++++++++++----- modules/observers.lua | 4 +++- 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/modules/defs/mp/defaults.lua b/modules/defs/mp/defaults.lua index 2ba8ab8..2e87d53 100644 --- a/modules/defs/mp/defaults.lua +++ b/modules/defs/mp/defaults.lua @@ -28,6 +28,11 @@ local mp = {} ---@field error_string ''|'killed'|'init' ---@field killed_by_us boolean +---@class MPVMousePos +---@field x number +---@field y number +---@field hover boolean + ---@param key string ---@param name_or_fn string|function ---@param fn? async fun() @@ -145,4 +150,7 @@ function mp.set_property_number(name, value) end ---@return string? err function mp.set_property_native(name, value) end +---@param fn function +function mp.unobserve_property(fn) end + return mp \ No newline at end of file diff --git a/modules/defs/state.lua b/modules/defs/state.lua index 403c310..380d689 100644 --- a/modules/defs/state.lua +++ b/modules/defs/state.lua @@ -5,6 +5,7 @@ ---@class (exact) State ---@field list List ---@field selected number +---@field scroll_offset number ---@field hidden boolean ---@field flag_update boolean ---@field keybinds KeybindTupleStrict[]? diff --git a/modules/globals.lua b/modules/globals.lua index 6c870be..ece875d 100644 --- a/modules/globals.lua +++ b/modules/globals.lua @@ -80,11 +80,14 @@ globals.state = { selection = {} } +---@type 'top'|'center'|'bottom' +globals.osd_alignment = "top" + --if the alignment isn't automated then we'll store a static value --numbers defined here: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3 -if o.alignment >= 7 then globals.state.osd_alignment = "top" -elseif o.alignment >= 4 then globals.state.osd_alignment = "center" -elseif o.alignment >= 1 then globals.state.osd_alignment = "bottom" end +if o.alignment >= 7 then globals.osd_alignment = "top" +elseif o.alignment >= 4 then globals.osd_alignment = "center" +elseif o.alignment >= 1 then globals.osd_alignment = "bottom" end ---@class ParserRef ---@field id string diff --git a/modules/keybinds.lua b/modules/keybinds.lua index 5ea230d..38afb9d 100644 --- a/modules/keybinds.lua +++ b/modules/keybinds.lua @@ -44,6 +44,7 @@ g.state.keybinds = { ---@type KeybindList local top_level_keys = {} +---@param key KeybindTupleStrict local function add_key(key) table.insert(g.state.keybinds, key) end diff --git a/modules/navigation/cursor.lua b/modules/navigation/cursor.lua index 0b1ddc2..cff320a 100644 --- a/modules/navigation/cursor.lua +++ b/modules/navigation/cursor.lua @@ -131,6 +131,9 @@ function cursor.toggle_select_mode() end end +---@param str string +---@param substring string +---@return number local function count_substrings(str, substring) local count = 0 for match in string.gmatch(str, substring) do @@ -147,7 +150,9 @@ local num_header_lines = count_substrings(o.format_string_header, '\\N') + 1 local num_twrapper_lines = count_substrings(o.format_string_topwrapper, '\\N') + 1 local num_bwrapper_lines = count_substrings(o.format_string_bottomwrapper, '\\N') + 1 ---update the selected item based on the mouse position +---update the selected item based on the mouse position +---@param _? string +---@param mouse_pos? MPVMousePos function cursor.update_mouse_pos(_, mouse_pos) if not o.mouse_mode or g.state.hidden or #g.state.list == 0 then return end @@ -158,10 +163,10 @@ function cursor.update_mouse_pos(_, mouse_pos) local scale = mp.get_property_number("osd-height", 0) / g.ass.res_y local osd_offset = scale * mp.get_property("osd-margin-y", 22) - msg.trace('calculating mouse pos for', g.state.osd_alignment, 'alignment') + msg.trace('calculating mouse pos for', g.osd_alignment, 'alignment') --calculate position when browser is aligned to the top of the screen - if g.state.osd_alignment == "top" then + if g.osd_alignment == "top" then local header_offset = osd_offset + (num_header_lines * scale * font_size_header) if g.state.scroll_offset > 0 then header_offset = header_offset + (num_twrapper_lines * scale * font_size_wrappers) end msg.trace('calculated header offset', header_offset) @@ -171,7 +176,7 @@ function cursor.update_mouse_pos(_, mouse_pos) --calculate position when browser is aligned to the bottom of the screen --this calculation is slightly off when a bottom wrapper exists, --I do not know what causes this. - elseif g.state.osd_alignment == "bottom" then + elseif g.osd_alignment == "bottom" then mouse_pos.y = (mp.get_property_number("osd-height", 0)) - mouse_pos.y local bottom = math.min(#g.state.list, g.state.scroll_offset + o.num_entries) @@ -184,7 +189,8 @@ function cursor.update_mouse_pos(_, mouse_pos) ass.update_ass() end --- scrolls the view window when using mouse mode +---scrolls the view window when using mouse mode +---@param direction number function cursor.wheel(direction) g.state.scroll_offset = g.state.scroll_offset + direction if (g.state.scroll_offset + o.num_entries) > #g.state.list then diff --git a/modules/observers.lua b/modules/observers.lua index e444db5..3b0c866 100644 --- a/modules/observers.lua +++ b/modules/observers.lua @@ -41,8 +41,10 @@ function observers.osd_align_x() ass.update_ass() end +---@param _ string +---@param alignment string function observers.osd_align_y(_, alignment) - g.state.osd_alignment = alignment + g.osd_alignment = alignment cursor.update_mouse_pos() -- calls ass.update_ass() internally end