diff options
Diffstat (limited to 'player/lua/osc.lua')
-rw-r--r-- | player/lua/osc.lua | 775 |
1 files changed, 507 insertions, 268 deletions
diff --git a/player/lua/osc.lua b/player/lua/osc.lua index af59470335..0859afc9ba 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -11,10 +11,10 @@ local utils = require 'mp.utils' local user_opts = { showwindowed = true, -- show OSC when windowed? showfullscreen = true, -- show OSC when fullscreen? + idlescreen = true, -- show mpv logo on idle scalewindowed = 1, -- scaling of the controller when windowed scalefullscreen = 1, -- scaling of the controller when fullscreen - scaleforcedwindow = 2, -- scaling when rendered on a forced window - vidscale = true, -- scale the controller with the video? + vidscale = "auto", -- scale the controller with the video? valign = 0.8, -- vertical alignment, -1 (top) to 1 (bottom) halign = 0, -- horizontal alignment, -1 (left) to 1 (right) barmargin = 0, -- vertical margin of top/bottombar @@ -34,24 +34,47 @@ local user_opts = { seekbarstyle = "bar", -- bar, diamond or knob seekbarhandlesize = 0.6, -- size ratio of the diamond and knob handle seekrangestyle = "inverted",-- bar, line, slider, inverted or none - seekrangeseparate = true, -- wether the seekranges overlay on the bar-style seekbar + seekrangeseparate = true, -- whether the seekranges overlay on the bar-style seekbar seekrangealpha = 200, -- transparency of seekranges seekbarkeyframes = true, -- use keyframes when dragging the seekbar + scrollcontrols = true, -- allow scrolling when hovering certain OSC elements title = "${media-title}", -- string compatible with property-expansion -- to be shown as OSC title tooltipborder = 1, -- border of tooltip in bottom/topbar timetotal = false, -- display total time instead of remaining time? + remaining_playtime = true, -- display the remaining time in playtime or video-time mode + -- playtime takes speed into account, whereas video-time doesn't timems = false, -- display timecodes with milliseconds? + tcspace = 100, -- timecode spacing (compensate font size estimation) visibility = "auto", -- only used at init to set visibility_mode(...) boxmaxchars = 80, -- title crop threshold for box layout boxvideo = false, -- apply osc_param.video_margins to video windowcontrols = "auto", -- whether to show window controls windowcontrols_alignment = "right", -- which side to show window controls on + windowcontrols_title = "${media-title}", -- same as title but for windowcontrols greenandgrumpy = false, -- disable santa hat + livemarkers = true, -- update seekbar chapter markers on duration change + chapters_osd = true, -- whether to show chapters OSD on next/prev + playlist_osd = true, -- whether to show playlist OSD on next/prev + playlist_media_title = true, -- whether to use media titles as playlist entry names + chapter_fmt = "Chapter: %s", -- chapter print format for seekbar-hover. "no" to disable + unicodeminus = false, -- whether to use the Unicode minus sign character + + background_color = "#000000", -- background color of the osc + timecode_color = "#FFFFFF", -- color of the progress bar and time color + title_color = "#FFFFFF", -- color of the title + time_pos_color = "#FFFFFF", -- color of the timecode at hovered position + buttons_color = "#FFFFFF", -- color of big buttons, wc buttons, and bar small buttons + small_buttonsL_color = "#FFFFFF", -- color of left small buttons + small_buttonsR_color = "#FFFFFF", -- color of right small buttons + top_buttons_color = "#FFFFFF", -- color of top buttons + held_element_color = "#999999", -- color of an element while held down + + time_pos_outline_color = "#000000" -- color of the border timecodes in slimbox and TimePosBar } -- read options from config and command-line -opt.read_options(user_opts, "osc", function(list) update_options(list) end) +opt.read_options(user_opts, "osc", function() update_options() end) local osc_param = { -- calculated by osc_init() playresy = 0, -- canvas size Y @@ -64,47 +87,55 @@ local osc_param = { -- calculated by osc_init() }, } +function osc_color_convert(color) + return color:sub(6,7) .. color:sub(4,5) .. color:sub(2,3) +end + +-- luacheck: push ignore +-- luacheck: max line length local osc_styles = { - bigButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs50\\fnmpv-osd-symbols}", - smallButtonsL = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs19\\fnmpv-osd-symbols}", + bigButtons = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.buttons_color) .. "\\3c&HFFFFFF\\fs50\\fnmpv-osd-symbols}", + smallButtonsL = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.small_buttonsL_color) .. "\\3c&HFFFFFF\\fs19\\fnmpv-osd-symbols}", smallButtonsLlabel = "{\\fscx105\\fscy105\\fn" .. mp.get_property("options/osd-font") .. "}", - smallButtonsR = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs30\\fnmpv-osd-symbols}", - topButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\fnmpv-osd-symbols}", - - elementDown = "{\\1c&H999999}", - timecodes = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs20}", - vidtitle = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\q2}", - box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}", - - topButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\fnmpv-osd-symbols}", - smallButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs28\\fnmpv-osd-symbols}", - timecodesBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs27}", - timePosBar = "{\\blur0\\bord".. user_opts.tooltipborder .."\\1c&HFFFFFF\\3c&H000000\\fs30}", - vidtitleBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\q2}", - - wcButtons = "{\\1c&HFFFFFF\\fs24\\fnmpv-osd-symbols}", - wcTitle = "{\\1c&HFFFFFF\\fs24\\q2}", - wcBar = "{\\1c&H000000}", + smallButtonsR = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.small_buttonsR_color) .. "\\3c&HFFFFFF\\fs30\\fnmpv-osd-symbols}", + topButtons = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.top_buttons_color) .. "\\3c&HFFFFFF\\fs12\\fnmpv-osd-symbols}", + + elementDown = "{\\1c&H" .. osc_color_convert(user_opts.held_element_color) .."}", + timecodes = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.timecode_color) .. "\\3c&HFFFFFF\\fs20}", + vidtitle = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.title_color) .. "\\3c&HFFFFFF\\fs12\\q2}", + box = "{\\rDefault\\blur0\\bord1\\1c&H" .. osc_color_convert(user_opts.background_color) .. "\\3c&HFFFFFF}", + + topButtonsBar = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.top_buttons_color) .. "\\3c&HFFFFFF\\fs18\\fnmpv-osd-symbols}", + smallButtonsBar = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.buttons_color) .. "\\3c&HFFFFFF\\fs28\\fnmpv-osd-symbols}", + timecodesBar = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.timecode_color) .."\\3c&HFFFFFF\\fs27}", + timePosBar = "{\\blur0\\bord".. user_opts.tooltipborder .."\\1c&H" .. osc_color_convert(user_opts.time_pos_color) .. "\\3c&H" .. osc_color_convert(user_opts.time_pos_outline_color) .. "\\fs30}", + vidtitleBar = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.title_color) .. "\\3c&HFFFFFF\\fs18\\q2}", + + wcButtons = "{\\1c&H" .. osc_color_convert(user_opts.buttons_color) .. "\\fs24\\fnmpv-osd-symbols}", + wcTitle = "{\\1c&H" .. osc_color_convert(user_opts.title_color) .. "\\fs24\\q2}", + wcBar = "{\\1c&H" .. osc_color_convert(user_opts.background_color) .. "}", } +-- luacheck: pop -- internal states, do not touch local state = { - showtime, -- time of last invocation (last mouse move) + showtime = nil, -- time of last invocation (last mouse move) osc_visible = false, - anistart, -- time when the animation started - anitype, -- current type of animation - animation, -- current animation alpha + anistart = nil, -- time when the animation started + anitype = nil, -- current type of animation + animation = nil, -- current animation alpha mouse_down_counter = 0, -- used for softrepeat active_element = nil, -- nil = none, 0 = background, 1+ = see elements[] active_event_source = nil, -- the "button" that issued the current event rightTC_trem = not user_opts.timetotal, -- if the right timecode should display total or remaining time tc_ms = user_opts.timems, -- Should the timecodes display their time with milliseconds - mp_screen_sizeX, mp_screen_sizeY, -- last screen-resolution, to detect resolution changes to issue reINITs + screen_sizeX = nil, screen_sizeY = nil, -- last screen-resolution, to detect resolution changes to issue reINITs initREQ = false, -- is a re-init request pending? - last_mouseX, last_mouseY, -- last mouse position, to detect significant mouse movement + marginsREQ = false, -- is a margins update pending? + last_mouseX = nil, last_mouseY = nil, -- last mouse position, to detect significant mouse movement mouse_in_window = false, - message_text, - message_hide_timer, + message_text = nil, + message_hide_timer = nil, fullscreen = false, tick_timer = nil, tick_last_time = 0, -- when the last tick() was run @@ -114,11 +145,14 @@ local state = { enabled = true, input_enabled = true, showhide_enabled = false, + windowcontrols_buttons = false, + windowcontrols_title = false, dmx_cache = 0, using_video_margins = false, border = true, maximized = false, osd = mp.create_osd_overlay("ass-events"), + chapter_list = {}, -- sorted by time } local window_control_box_width = 80 @@ -130,7 +164,13 @@ local is_december = os.date("*t").month == 12 -- Helperfunctions -- -function set_osd(res_x, res_y, text) +function kill_animation() + state.anistart = nil + state.animation = nil + state.anitype = nil +end + +function set_osd(res_x, res_y, text, z) if state.osd.res_x == res_x and state.osd.res_y == res_y and state.osd.data == text then @@ -139,7 +179,7 @@ function set_osd(res_x, res_y, text) state.osd.res_x = res_x state.osd.res_y = res_y state.osd.data = text - state.osd.z = 1000 + state.osd.z = z state.osd:update() end @@ -262,7 +302,7 @@ function get_slider_value(element) end function countone(val) - if not (user_opts.iamaprogrammer) then + if not user_opts.iamaprogrammer then val = val + 1 end return val @@ -283,7 +323,7 @@ end function add_area(name, x1, y1, x2, y2) -- create area if needed - if (osc_param.areas[name] == nil) then + if osc_param.areas[name] == nil then osc_param.areas[name] = {} end table.insert(osc_param.areas[name], {x1=x1, y1=y1, x2=x2, y2=y2}) @@ -338,7 +378,7 @@ function update_tracklist() tracks_mpv = {} tracks_mpv.video, tracks_mpv.audio, tracks_mpv.sub = {}, {}, {} for n = 1, #tracktable do - if not (tracktable[n].type == "unknown") then + if tracktable[n].type ~= "unknown" then local type = tracktable[n].type local mpv_id = tonumber(tracktable[n].id) @@ -354,29 +394,29 @@ end -- return a nice list of tracks of the given type (video, audio, sub) function get_tracklist(type) - local msg = "Available " .. nicetypes[type] .. " Tracks: " - if #tracks_osc[type] == 0 then - msg = msg .. "none" + local message = "Available " .. nicetypes[type] .. " Tracks: " + if not tracks_osc or #tracks_osc[type] == 0 then + message = message .. "none" else for n = 1, #tracks_osc[type] do local track = tracks_osc[type][n] local lang, title, selected = "unknown", "", "○" - if not(track.lang == nil) then lang = track.lang end - if not(track.title == nil) then title = track.title end - if (track.id == tonumber(mp.get_property(type))) then + if track.lang ~= nil then lang = track.lang end + if track.title ~= nil then title = track.title end + if track.id == tonumber(mp.get_property(type)) then selected = "●" end - msg = msg.."\n"..selected.." "..n..": ["..lang.."] "..title + message = message.."\n"..selected.." "..n..": ["..lang.."] "..title end end - return msg + return message end -- relatively change the track of given <type> by <next> tracks --(+1 -> next, -1 -> previous) function set_track(type, next) local current_track_mpv, current_track_osc - if (mp.get_property(type) == "no") then + if mp.get_property(type) == "no" then current_track_osc = 0 else current_track_mpv = tonumber(mp.get_property(type)) @@ -392,10 +432,10 @@ function set_track(type, next) mp.commandv("set", type, new_track_mpv) - if (new_track_osc == 0) then + if new_track_osc == 0 then show_message(nicetypes[type] .. " Track: none") else - show_message(nicetypes[type] .. " Track: " + show_message(nicetypes[type] .. " Track: " .. new_track_osc .. "/" .. #tracks_osc[type] .. " [".. (tracks_osc[type][new_track_osc].lang or "unknown") .."] " .. (tracks_osc[type][new_track_osc].title or "")) @@ -418,7 +458,7 @@ end function window_controls_enabled() val = user_opts.windowcontrols if val == "auto" then - return not state.border + return not (state.border and state.title_bar) else return val ~= "no" end @@ -436,10 +476,10 @@ local elements = {} function prepare_elements() - -- remove elements without layout or invisble + -- remove elements without layout or invisible local elements2 = {} - for n, element in pairs(elements) do - if not (element.layout == nil) and (element.visible) then + for _, element in pairs(elements) do + if element.layout ~= nil and element.visible then table.insert(elements2, element) end end @@ -474,14 +514,14 @@ function prepare_elements() local static_ass = assdraw.ass_new() - if (element.type == "box") then + if element.type == "box" then --draw box static_ass:draw_start() ass_draw_rr_h_cw(static_ass, 0, 0, elem_geo.w, elem_geo.h, element.layout.box.radius, element.layout.box.hexagon) static_ass:draw_stop() - elseif (element.type == "slider") then + elseif element.type == "slider" then --draw static slider parts local r1 = 0 @@ -491,13 +531,13 @@ function prepare_elements() local foV = slider_lo.border + slider_lo.gap -- calculate positions of min and max points - if (slider_lo.stype ~= "bar") then + if slider_lo.stype ~= "bar" then r1 = elem_geo.h / 2 element.slider.min.ele_pos = elem_geo.h / 2 element.slider.max.ele_pos = elem_geo.w - (elem_geo.h / 2) - if (slider_lo.stype == "diamond") then + if slider_lo.stype == "diamond" then r2 = (elem_geo.h - 2 * slider_lo.border) / 2 - elseif (slider_lo.stype == "knob") then + elseif slider_lo.stype == "knob" then r2 = r1 end else @@ -525,45 +565,45 @@ function prepare_elements() r2, slider_lo.stype == "diamond") -- marker nibbles - if not (element.slider.markerF == nil) and (slider_lo.gap > 0) then + if element.slider.markerF ~= nil and slider_lo.gap > 0 then local markers = element.slider.markerF() for _,marker in pairs(markers) do - if (marker > element.slider.min.value) and - (marker < element.slider.max.value) then + if marker > element.slider.min.value and + marker < element.slider.max.value then local s = get_slider_ele_pos_for(element, marker) - if (slider_lo.gap > 1) then -- draw triangles + if slider_lo.gap > 1 then -- draw triangles local a = slider_lo.gap / 0.5 --0.866 --top - if (slider_lo.nibbles_top) then - static_ass:move_to(s - (a/2), slider_lo.border) - static_ass:line_to(s + (a/2), slider_lo.border) + if slider_lo.nibbles_top then + static_ass:move_to(s - (a / 2), slider_lo.border) + static_ass:line_to(s + (a / 2), slider_lo.border) static_ass:line_to(s, foV) end --bottom - if (slider_lo.nibbles_bottom) then - static_ass:move_to(s - (a/2), + if slider_lo.nibbles_bottom then + static_ass:move_to(s - (a / 2), elem_geo.h - slider_lo.border) static_ass:line_to(s, elem_geo.h - foV) - static_ass:line_to(s + (a/2), + static_ass:line_to(s + (a / 2), elem_geo.h - slider_lo.border) end else -- draw 2x1px nibbles --top - if (slider_lo.nibbles_top) then + if slider_lo.nibbles_top then static_ass:rect_cw(s - 1, slider_lo.border, s + 1, slider_lo.border + slider_lo.gap); end --bottom - if (slider_lo.nibbles_bottom) then + if slider_lo.nibbles_bottom then static_ass:rect_cw(s - 1, elem_geo.h -slider_lo.border -slider_lo.gap, s + 1, elem_geo.h - slider_lo.border); @@ -579,7 +619,7 @@ function prepare_elements() -- if the element is supposed to be disabled, -- style it accordingly and kill the eventresponders - if not (element.enabled) then + if not element.enabled then element.layout.alpha[1] = 136 element.eventresponder = nil end @@ -591,8 +631,35 @@ end -- Element Rendering -- +-- returns nil or a chapter element from the native property chapter-list +function get_chapter(possec) + local cl = state.chapter_list -- sorted, get latest before possec, if any + + for n=#cl,1,-1 do + if possec >= cl[n].time then + return cl[n] + end + end +end + function render_elements(master_ass) + -- when the slider is dragged or hovered and we have a target chapter name + -- then we use it instead of the normal title. we calculate it before the + -- render iterations because the title may be rendered before the slider. + state.forced_title = nil + local se, ae = state.slider_element, elements[state.active_element] + if user_opts.chapter_fmt ~= "no" and se and (ae == se or (not ae and mouse_hit(se))) then + local dur = mp.get_property_number("duration", 0) + if dur > 0 then + local possec = get_slider_value(se) * dur / 100 -- of mouse pos + local ch = get_chapter(possec) + if ch and ch.title and ch.title ~= "" then + state.forced_title = string.format(user_opts.chapter_fmt, ch.title) + end + end + end + for n=1, #elements do local element = elements[n] @@ -603,18 +670,18 @@ function render_elements(master_ass) if element.eventresponder and (state.active_element == n) then -- run render event functions - if not (element.eventresponder.render == nil) then + if element.eventresponder.render ~= nil then element.eventresponder.render(element) end if mouse_hit(element) then -- mouse down styling - if (element.styledown) then + if element.styledown then style_ass:append(osc_styles.elementDown) end - if (element.softrepeat) and (state.mouse_down_counter >= 15 - and state.mouse_down_counter % 5 == 0) then + if element.softrepeat and state.mouse_down_counter >= 15 + and state.mouse_down_counter % 5 == 0 then element.eventresponder[state.active_event_source.."_down"](element) end @@ -627,11 +694,11 @@ function render_elements(master_ass) elem_ass:merge(style_ass) - if not (element.type == "button") then + if element.type ~= "button" then elem_ass:merge(element.static_ass) end - if (element.type == "slider") then + if element.type == "slider" then local slider_lo = element.layout.slider local elem_geo = element.layout.geometry @@ -677,7 +744,8 @@ function render_elements(master_ass) if pos > range["end"] then pend = get_slider_ele_pos_for(element, range["end"]) end - elem_ass:rect_ccw(pstart, elem_geo.h - foV - seekRangeLineHeight, pend, elem_geo.h - foV) + elem_ass:rect_ccw(pstart, elem_geo.h - foV - seekRangeLineHeight, + pend, elem_geo.h - foV) end end end @@ -749,8 +817,7 @@ function render_elements(master_ass) elem_ass:draw_stop() -- add tooltip - if not (element.slider.tooltipF == nil) then - + if element.slider.tooltipF ~= nil then if mouse_hit(element) then local sliderpos = get_slider_value(element) local tooltiplabel = element.slider.tooltipF(sliderpos) @@ -759,21 +826,21 @@ function render_elements(master_ass) local ty - if (an == 2) then + if an == 2 then ty = element.hitbox.y1 - slider_lo.border else - ty = element.hitbox.y1 + elem_geo.h/2 + ty = element.hitbox.y1 + elem_geo.h / 2 end local tx = get_virt_mouse_pos() - if (slider_lo.adjust_tooltip) then - if (an == 2) then - if (sliderpos < (s_min + 3)) then + if slider_lo.adjust_tooltip then + if an == 2 then + if sliderpos < (s_min + 3) then an = an - 1 - elseif (sliderpos > (s_max - 3)) then + elseif sliderpos > (s_max - 3) then an = an + 1 end - elseif (sliderpos > (s_max-s_min)/2) then + elseif sliderpos > (s_max+s_min) / 2 then an = an + 1 tx = tx - 5 else @@ -793,27 +860,25 @@ function render_elements(master_ass) end end - elseif (element.type == "button") then + elseif element.type == "button" then local buttontext if type(element.content) == "function" then buttontext = element.content() -- function objects - elseif not (element.content == nil) then + elseif element.content ~= nil then buttontext = element.content -- text objects end local maxchars = element.layout.button.maxchars - if not (maxchars == nil) and (#buttontext > maxchars) then + if maxchars ~= nil and #buttontext > maxchars then local max_ratio = 1.25 -- up to 25% more chars while shrinking local limit = math.max(0, math.floor(maxchars * max_ratio) - 3) - if (#buttontext > limit) then + if #buttontext > limit then while (#buttontext > limit) do buttontext = buttontext:gsub(".[\128-\191]*$", "") end buttontext = buttontext .. "..." end - local _, nchars2 = buttontext:gsub(".[\128-\191]*", "") - local stretch = (maxchars/#buttontext)*100 buttontext = string.format("{\\fscx%f}", (maxchars/#buttontext)*100) .. buttontext end @@ -863,10 +928,10 @@ function get_playlist() end local message = string.format('Playlist [%d/%d]:\n', pos, count) - for i, v in ipairs(limlist) do + for _, v in ipairs(limlist) do local title = v.title local _, filename = utils.split_path(v.filename) - if title == nil then + if not user_opts.playlist_media_title or title == nil then title = filename end message = string.format('%s %s %s\n', message, @@ -900,7 +965,7 @@ function show_message(text, duration) --print("text: "..text.." duration: " .. duration) if duration == nil then duration = tonumber(mp.get_property("options/osd-duration")) / 1000 - elseif not type(duration) == "number" then + elseif type(duration) ~= "number" then print("duration: " .. duration) end @@ -908,10 +973,7 @@ function show_message(text, duration) -- may slow down massively on huge input text = string.sub(text, 0, 4000) - -- replace actual linebreaks with ASS linebreaks - text = string.gsub(text, "\n", "\\N") - - state.message_text = text + state.message_text = mp.command_native({"escape-ass", text}) if not state.message_hide_timer then state.message_hide_timer = mp.add_timeout(0, request_tick) @@ -962,7 +1024,7 @@ function new_element(name, type) elements[name].styledown = (type == "button") elements[name].state = {} - if (type == "slider") then + if type == "slider" then elements[name].slider = {min = {value = 0}, max = {value = 100}} end @@ -971,7 +1033,7 @@ function new_element(name, type) end function add_layout(name) - if not (elements[name] == nil) then + if elements[name] ~= nil then -- new layout elements[name].layout = {} @@ -979,11 +1041,11 @@ function add_layout(name) elements[name].layout.layer = 50 elements[name].layout.alpha = {[1] = 0, [2] = 255, [3] = 255, [4] = 255} - if (elements[name].type == "button") then + if elements[name].type == "button" then elements[name].layout.button = { maxchars = nil, } - elseif (elements[name].type == "slider") then + elseif elements[name].type == "slider" then -- slider defaults elements[name].layout.slider = { border = 1, @@ -996,7 +1058,7 @@ function add_layout(name) tooltip_an = 2, alpha = {[1] = 0, [2] = 255, [3] = 88, [4] = 255}, } - elseif (elements[name].type == "box") then + elseif elements[name].type == "box" then elements[name].layout.box = {radius = 0, hexagon = false} end @@ -1099,9 +1161,8 @@ function window_controls(topbar) -- deadzone below window controls local sh_area_y0, sh_area_y1 sh_area_y0 = user_opts.barmargin - sh_area_y1 = (wc_geo.y + (wc_geo.h / 2)) + - get_align(1 - (2 * user_opts.deadzonesize), - osc_param.playresy - (wc_geo.y + (wc_geo.h / 2)), 0, 0) + sh_area_y1 = wc_geo.y + get_align(1 - (2 * user_opts.deadzonesize), + osc_param.playresy - wc_geo.y, 0, 0) add_area("showhide_wc", wc_geo.x, sh_area_y0, wc_geo.w, sh_area_y1) if topbar then @@ -1115,10 +1176,9 @@ function window_controls(topbar) -- Window Title ne = new_element("wctitle", "button") ne.content = function () - local title = mp.command_native({"expand-text", user_opts.title}) - -- escape ASS, and strip newlines and trailing slashes - title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{") - return not (title == "") and title or "mpv" + local title = mp.command_native({"expand-text", user_opts.windowcontrols_title}) + title = title:gsub("\n", " ") + return title ~= "" and mp.command_native({"escape-ass", title}) or "mpv" end local left_pad = 5 local right_pad = 10 @@ -1152,8 +1212,8 @@ layouts["box"] = function () } -- make sure the OSC actually fits into the video - if (osc_param.playresx < (osc_geo.w + (2 * osc_geo.p))) then - osc_param.playresy = (osc_geo.w+(2*osc_geo.p))/osc_param.display_aspect + if osc_param.playresx < (osc_geo.w + (2 * osc_geo.p)) then + osc_param.playresy = (osc_geo.w + (2 * osc_geo.p)) / osc_param.display_aspect osc_param.playresx = osc_param.playresy * osc_param.display_aspect end @@ -1189,8 +1249,7 @@ layouts["box"] = function () add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) -- fetch values - local osc_w, osc_h, osc_r, osc_p = - osc_geo.w, osc_geo.h, osc_geo.r, osc_geo.p + local osc_w, osc_h, osc_r = osc_geo.w, osc_geo.h, osc_geo.r local lo @@ -1327,8 +1386,8 @@ layouts["slimbox"] = function () } -- make sure the OSC actually fits into the video - if (osc_param.playresx < (osc_geo.w)) then - osc_param.playresy = (osc_geo.w)/osc_param.display_aspect + if osc_param.playresx < (osc_geo.w) then + osc_param.playresy = (osc_geo.w) / osc_param.display_aspect osc_param.playresx = osc_param.playresy * osc_param.display_aspect end @@ -1365,9 +1424,11 @@ layouts["slimbox"] = function () -- styles local styles = { - box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}", - timecodes = "{\\1c&HFFFFFF\\3c&H000000\\fs20\\bord2\\blur1}", - tooltip = "{\\1c&HFFFFFF\\3c&H000000\\fs12\\bord1\\blur0.5}", + box = "{\\rDefault\\blur0\\bord1\\1c&H" .. osc_color_convert(user_opts.background_color) .. "\\3c&HFFFFFF}", + timecodes = "{\\1c&H" .. osc_color_convert(user_opts.timecode_color) .. "\\3c&H" .. + osc_color_convert(user_opts.time_pos_outline_color) .. "\\fs20\\bord2\\blur1}", + tooltip = "{\\1c&H" .. osc_color_convert(user_opts.time_pos_color).. "\\3c&H" .. + osc_color_convert(user_opts.time_pos_outline_color) .. "\\fs12\\bord1\\blur0.5}", } @@ -1379,7 +1440,7 @@ layouts["slimbox"] = function () lo.style = osc_styles.box lo.alpha[1] = user_opts.boxalpha lo.alpha[3] = 0 - if not (user_opts["seekbarstyle"] == "bar") then + if user_opts["seekbarstyle"] ~= "bar" then lo.box.radius = osc_geo.r lo.box.hexagon = user_opts["seekbarstyle"] == "diamond" end @@ -1429,9 +1490,9 @@ end function bar_layout(direction) local osc_geo = { x = -2, - y, + y = nil, an = (direction < 0) and 7 or 1, - w, + w = nil, h = 56, } @@ -1439,6 +1500,11 @@ function bar_layout(direction) local padY = 3 local buttonW = 27 local tcW = (state.tc_ms) and 170 or 110 + if user_opts.tcspace >= 50 and user_opts.tcspace <= 200 then + -- adjust our hardcoded font size estimation + tcW = tcW * user_opts.tcspace / 100 + end + local tsW = 90 local minW = (buttonW + padX)*5 + (tcW + padX)*4 + (tsW + padX)*2 @@ -1456,7 +1522,7 @@ function bar_layout(direction) padwc_r = window_control_box_width end - if ((osc_param.display_aspect > 0) and (osc_param.playresx < minW)) then + if osc_param.display_aspect > 0 and osc_param.playresx < minW then osc_param.playresy = minW / osc_param.display_aspect osc_param.playresx = osc_param.playresy * osc_param.display_aspect end @@ -1479,13 +1545,11 @@ function bar_layout(direction) if direction > 0 then -- deadzone below OSC sh_area_y0 = user_opts.barmargin - sh_area_y1 = (osc_geo.y + (osc_geo.h / 2)) + - get_align(1 - (2*user_opts.deadzonesize), - osc_param.playresy - (osc_geo.y + (osc_geo.h / 2)), 0, 0) + sh_area_y1 = osc_geo.y + get_align(1 - (2 * user_opts.deadzonesize), + osc_param.playresy - osc_geo.y, 0, 0) else -- deadzone above OSC - sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize), - osc_geo.y - (osc_geo.h / 2), 0, 0) + sh_area_y0 = get_align(-1 + (2 * user_opts.deadzonesize), osc_geo.y, 0, 0) sh_area_y1 = osc_param.playresy - user_opts.barmargin end add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) @@ -1607,7 +1671,7 @@ function bar_layout(direction) lo.style = osc_styles.timecodesBar lo.alpha[1] = math.min(255, user_opts.boxalpha + (255 - user_opts.boxalpha)*0.8) - if not (user_opts["seekbarstyle"] == "bar") then + if user_opts["seekbarstyle"] ~= "bar" then lo.box.radius = geo.h / 2 lo.box.hexagon = user_opts["seekbarstyle"] == "diamond" end @@ -1681,39 +1745,60 @@ function validate_user_opts() user_opts.windowcontrols_alignment .. "\". Ignoring.") user_opts.windowcontrols_alignment = "right" end + + local colors = { + user_opts.background_color, user_opts.top_buttons_color, + user_opts.small_buttonsL_color, user_opts.small_buttonsR_color, + user_opts.buttons_color, user_opts.title_color, + user_opts.timecode_color, user_opts.time_pos_color, + user_opts.held_element_color, user_opts.time_pos_outline_color, + } + for _, color in pairs(colors) do + if color:find("^#%x%x%x%x%x%x$") == nil then + msg.warn("'" .. color .. "' is not a valid color") + end + end end -function update_options(list) +function update_options() validate_user_opts() request_tick() visibility_mode(user_opts.visibility, true) + update_duration_watch() request_init() end +local UNICODE_MINUS = string.char(0xe2, 0x88, 0x92) -- UTF-8 for U+2212 MINUS SIGN + -- OSC INIT function osc_init() msg.debug("osc_init") -- set canvas resolution according to display aspect and scaling setting local baseResY = 720 - local display_w, display_h, display_aspect = mp.get_osd_size() - local scale = 1 + local _, display_h, display_aspect = mp.get_osd_size() + local scale - if (mp.get_property("video") == "no") then -- dummy/forced window - scale = user_opts.scaleforcedwindow - elseif state.fullscreen then + if state.fullscreen then scale = user_opts.scalefullscreen else scale = user_opts.scalewindowed end - if user_opts.vidscale then + local scale_with_video + if user_opts.vidscale == "auto" then + scale_with_video = mp.get_property_native("osd-scale-by-window") + else + scale_with_video = user_opts.vidscale == "yes" + end + + if scale_with_video then osc_param.unscaled_y = baseResY else osc_param.unscaled_y = display_h end osc_param.playresy = osc_param.unscaled_y / scale - if (display_aspect > 0) then + if display_aspect > 0 then osc_param.display_aspect = display_aspect end osc_param.playresx = osc_param.playresy * osc_param.display_aspect @@ -1738,15 +1823,15 @@ function osc_init() ne = new_element("title", "button") ne.content = function () - local title = mp.command_native({"expand-text", user_opts.title}) - -- escape ASS, and strip newlines and trailing slashes - title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{") - return not (title == "") and title or "mpv" + local title = state.forced_title or + mp.command_native({"expand-text", user_opts.title}) + title = title:gsub("\n", " ") + return title ~= "" and mp.command_native({"escape-ass", title}) or "mpv" end ne.eventresponder["mbtn_left_up"] = function () local title = mp.get_property_osd("media-title") - if (have_pl) then + if have_pl then title = string.format("[%d/%d] %s", countone(pl_pos - 1), pl_count, title) end @@ -1766,7 +1851,9 @@ function osc_init() ne.eventresponder["mbtn_left_up"] = function () mp.commandv("playlist-prev", "weak") - show_message(get_playlist(), 3) + if user_opts.playlist_osd then + show_message(get_playlist(), 3) + end end ne.eventresponder["shift+mbtn_left_up"] = function () show_message(get_playlist(), 3) end @@ -1781,7 +1868,9 @@ function osc_init() ne.eventresponder["mbtn_left_up"] = function () mp.commandv("playlist-next", "weak") - show_message(get_playlist(), 3) + if user_opts.playlist_osd then + show_message(get_playlist(), 3) + end end ne.eventresponder["shift+mbtn_left_up"] = function () show_message(get_playlist(), 3) end |