feat!: refine option to improve features at a cost of some performance (#816)

Replaces option `text_width_estimation`, which is now one of its available flags:

```
refine=text_width
```
This commit is contained in:
Tomas Klaen
2023-12-28 13:05:59 +01:00
committed by GitHub
parent b36cefed88
commit 0d7825a4ad
5 changed files with 66 additions and 67 deletions

View File

@@ -155,9 +155,12 @@ color=
# This does not affect any text, which is always rendered fully opaque. Defaults: # This does not affect any text, which is always rendered fully opaque. Defaults:
# timeline=0.9,position=1,chapters=0.8,slider=0.9,slider_gauge=1,controls=0,speed=0.6,menu=1,submenu=0.4,border=1,title=1,tooltip=1,thumbnail=1,curtain=0.8,idle_indicator=0.8,audio_indicator=0.5,buffering_indicator=0.3,playlist_position=0.8 # timeline=0.9,position=1,chapters=0.8,slider=0.9,slider_gauge=1,controls=0,speed=0.6,menu=1,submenu=0.4,border=1,title=1,tooltip=1,thumbnail=1,curtain=0.8,idle_indicator=0.8,audio_indicator=0.5,buffering_indicator=0.3,playlist_position=0.8
opacity= opacity=
# Use a faster estimation method instead of accurate measurement # A comma delimited list of features to refine at a cost of some performance impact.
# setting this to `no` might have a noticeable impact on performance, especially in large menus. # text_width - Use a more accurate text width measurement that measures each text string individually
text_width_estimation=yes # instead of just measuring the width of known letters once and adding them up.
# sorting - Use filename sorting that handles non-english languages better, especially asian ones.
# At the moment, this is only available on windows, and has no effect on other platforms.
refine=
# Duration of animations in milliseconds # Duration of animations in milliseconds
animation_duration=100 animation_duration=100
# Execute command for background clicks shorter than this number of milliseconds, 0 to disable # Execute command for background clicks shorter than this number of milliseconds, 0 to disable

View File

@@ -210,8 +210,8 @@ function open_file_navigation_menu(directory_path, handle_select, opts)
if not files or not directories then return end if not files or not directories then return end
sort_filenames(directories) sort_strings(directories)
sort_filenames(files) sort_strings(files)
-- Pre-populate items with parent directory selector if not at root -- Pre-populate items with parent directory selector if not at root
-- Each item value is a serialized path table it points to. -- Each item value is a serialized path table it points to.

View File

@@ -382,7 +382,7 @@ do
---@type boolean, boolean ---@type boolean, boolean
local bold, italic = opts.bold or options.font_bold, opts.italic or false local bold, italic = opts.bold or options.font_bold, opts.italic or false
if options.text_width_estimation then if config.refine.text_width then
---@type {[string|number]: {[1]: number, [2]: integer}} ---@type {[string|number]: {[1]: number, [2]: integer}}
local text_width = get_cache_stage(width_cache, bold) local text_width = get_cache_stage(width_cache, bold)
local width_px = text_width[text] local width_px = text_width[text]

View File

@@ -6,61 +6,52 @@
--- In place sorting of filenames --- In place sorting of filenames
---@param filenames string[] ---@param filenames string[]
----- winapi start ----- -- String sorting
-- in windows system, we can use the sorting function provided by the win32 API do
-- see https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strcmplogicalw ----- winapi start -----
-- this function was taken from https://github.com/mpvnet-player/mpv.net/issues/575#issuecomment-1817413401 -- in windows system, we can use the sorting function provided by the win32 API
local winapi = {} -- see https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strcmplogicalw
-- this function was taken from https://github.com/mpvnet-player/mpv.net/issues/575#issuecomment-1817413401
local winapi = nil
if state.platform == 'windows' then if state.platform == 'windows' and config.refine.sorting then
-- is_ffi_loaded is false usually means the mpv builds without luajit -- is_ffi_loaded is false usually means the mpv builds without luajit
local is_ffi_loaded, ffi = pcall(require, 'ffi') local is_ffi_loaded, ffi = pcall(require, 'ffi')
if is_ffi_loaded then if is_ffi_loaded then
winapi = { winapi = {
ffi = ffi, ffi = ffi,
C = ffi.C, C = ffi.C,
CP_UTF8 = 65001, CP_UTF8 = 65001,
shlwapi = ffi.load('shlwapi'), shlwapi = ffi.load('shlwapi'),
} }
-- ffi code from https://github.com/po5/thumbfast, Mozilla Public License Version 2.0 -- ffi code from https://github.com/po5/thumbfast, Mozilla Public License Version 2.0
ffi.cdef[[ ffi.cdef [[
int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr,
int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
int __stdcall StrCmpLogicalW(wchar_t *psz1, wchar_t *psz2); int __stdcall StrCmpLogicalW(wchar_t *psz1, wchar_t *psz2);
]] ]]
winapi.utf8_to_wide = function(utf8_str) winapi.utf8_to_wide = function(utf8_str)
if utf8_str then if utf8_str then
local utf16_len = winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, utf8_str, -1, nil, 0) local utf16_len = winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, utf8_str, -1, nil, 0)
if utf16_len > 0 then if utf16_len > 0 then
local utf16_str = winapi.ffi.new('wchar_t[?]', utf16_len) local utf16_str = winapi.ffi.new('wchar_t[?]', utf16_len)
if winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, utf8_str, -1, utf16_str, utf16_len) > 0 then if winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, utf8_str, -1, utf16_str, utf16_len) > 0 then
return utf16_str return utf16_str
end
end end
end end
end
return '' return ''
end
end end
end end
end ----- winapi end -----
----- winapi end -----
function sort_filenames_windows(filenames)
table.sort(filenames, function(a, b)
local a_wide = winapi.utf8_to_wide(a)
local b_wide = winapi.utf8_to_wide(b)
return winapi.shlwapi.StrCmpLogicalW(a_wide, b_wide) == -1
end)
return filenames
end
function sort_filenames_lua(filenames)
-- alphanum sorting for humans in Lua -- alphanum sorting for humans in Lua
-- http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua -- http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua
local function padnum(n, d) local function padnum(n, d)
@@ -68,23 +59,27 @@ function sort_filenames_lua(filenames)
or ('%03d%s'):format(#n, n) or ('%03d%s'):format(#n, n)
end end
local tuples = {} local function sort_lua(strings)
for i, f in ipairs(filenames) do local tuples = {}
tuples[i] = {f:lower():gsub('0*(%d+)%.?(%d*)', padnum), f} for i, f in ipairs(strings) do
tuples[i] = {f:lower():gsub('0*(%d+)%.?(%d*)', padnum), f}
end
table.sort(tuples, function(a, b)
return a[1] == b[1] and #b[2] < #a[2] or a[1] < b[1]
end)
for i, tuple in ipairs(tuples) do strings[i] = tuple[2] end
return strings
end end
table.sort(tuples, function(a, b)
return a[1] == b[1] and #b[2] < #a[2] or a[1] < b[1]
end)
for i, tuple in ipairs(tuples) do filenames[i] = tuple[2] end
return filenames
end
function sort_filenames(filenames) ---@param strings string[]
local is_ffi_loaded = pcall(require, 'ffi') function sort_strings(strings)
if state.platform == 'windows' and is_ffi_loaded then if winapi then
sort_filenames_windows(filenames) table.sort(strings, function(a, b)
else return winapi.shlwapi.StrCmpLogicalW(winapi.utf8_to_wide(a), winapi.utf8_to_wide(b)) == -1
sort_filenames_lua(filenames) end)
else
sort_lua(strings)
end
end end
end end
@@ -465,7 +460,7 @@ function get_adjacent_files(file_path, opts)
if not current_meta then return end if not current_meta then return end
local files = read_directory(current_meta.dirname, {hidden = opts.hidden}) local files = read_directory(current_meta.dirname, {hidden = opts.hidden})
if not files then return end if not files then return end
sort_filenames(files) sort_strings(files)
local current_file_index local current_file_index
local paths = {} local paths = {}
for _, file in ipairs(files) do for _, file in ipairs(files) do

View File

@@ -71,7 +71,7 @@ defaults = {
color = '', color = '',
opacity = '', opacity = '',
animation_duration = 100, animation_duration = 100,
text_width_estimation = true, refine = '',
pause_on_click_shorter_than = 0, -- deprecated by below pause_on_click_shorter_than = 0, -- deprecated by below
click_threshold = 0, click_threshold = 0,
click_command = 'cycle pause; script-binding uosc/flash-pause-indicator', click_command = 'cycle pause; script-binding uosc/flash-pause-indicator',
@@ -175,6 +175,7 @@ config = {
osd_margin_y = mp.get_property('osd-margin-y'), osd_margin_y = mp.get_property('osd-margin-y'),
osd_alignment_x = mp.get_property('osd-align-x'), osd_alignment_x = mp.get_property('osd-align-x'),
osd_alignment_y = mp.get_property('osd-align-y'), osd_alignment_y = mp.get_property('osd-align-y'),
refine = create_set(comma_split(options.refine)),
types = { types = {
video = comma_split(options.video_types), video = comma_split(options.video_types),
audio = comma_split(options.audio_types), audio = comma_split(options.audio_types),
@@ -542,7 +543,7 @@ function load_file_index_in_current_directory(index)
}) })
if not files then return end if not files then return end
sort_filenames(files) sort_strings(files)
if index < 0 then index = #files + index + 1 end if index < 0 then index = #files + index + 1 end
if files[index] then if files[index] then