feat: improve volume slider visuals
I wanted to round the nudge as well, but thats just too much math and bezier curves.
This commit is contained in:
@@ -84,9 +84,9 @@ controls_persistency=
|
|||||||
# Where to display volume controls: none, left, right
|
# Where to display volume controls: none, left, right
|
||||||
volume=right
|
volume=right
|
||||||
volume_size=40
|
volume_size=40
|
||||||
volume_size_fullscreen=60
|
volume_size_fullscreen=52
|
||||||
volume_persistency=
|
volume_persistency=
|
||||||
volume_opacity=0.8
|
volume_opacity=0.9
|
||||||
volume_border=1
|
volume_border=1
|
||||||
volume_step=1
|
volume_step=1
|
||||||
|
|
||||||
|
143
scripts/uosc.lua
143
scripts/uosc.lua
@@ -14,6 +14,7 @@ local utils = require('mp.utils')
|
|||||||
local msg = require('mp.msg')
|
local msg = require('mp.msg')
|
||||||
local osd = mp.create_osd_overlay('ass-events')
|
local osd = mp.create_osd_overlay('ass-events')
|
||||||
local infinity = 1e309
|
local infinity = 1e309
|
||||||
|
local quarter_pi_sin = math.sin(math.pi/4)
|
||||||
|
|
||||||
--[[ BASE HELPERS ]]
|
--[[ BASE HELPERS ]]
|
||||||
|
|
||||||
@@ -168,9 +169,9 @@ local options = {
|
|||||||
|
|
||||||
volume = 'right',
|
volume = 'right',
|
||||||
volume_size = 40,
|
volume_size = 40,
|
||||||
volume_size_fullscreen = 60,
|
volume_size_fullscreen = 52,
|
||||||
volume_persistency = '',
|
volume_persistency = '',
|
||||||
volume_opacity = 0.8,
|
volume_opacity = 0.9,
|
||||||
volume_border = 1,
|
volume_border = 1,
|
||||||
volume_step = 1,
|
volume_step = 1,
|
||||||
|
|
||||||
@@ -2589,8 +2590,8 @@ function Timeline:init()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Timeline:get_visibility()
|
function Timeline:get_visibility()
|
||||||
return Elements.controls
|
return Elements.controls and math.max(Elements.controls.proximity, Element.get_visibility(self))
|
||||||
and math.max(Elements.controls.proximity, Element.get_visibility(self)) or Element.get_visibility(self)
|
or Element.get_visibility(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Timeline:decide_enabled()
|
function Timeline:decide_enabled()
|
||||||
@@ -2768,7 +2769,7 @@ function Timeline:render()
|
|||||||
clip = dots and '\\iclip(' .. foreground_coordinates .. ')' or nil,
|
clip = dots and '\\iclip(' .. foreground_coordinates .. ')' or nil,
|
||||||
opacity = options.timeline_chapters_opacity,
|
opacity = options.timeline_chapters_opacity,
|
||||||
}
|
}
|
||||||
|
|
||||||
if dots then
|
if dots then
|
||||||
local cx, dx = math.max(ax, fax), math.min(bx, fbx)
|
local cx, dx = math.max(ax, fax), math.min(bx, fbx)
|
||||||
-- 0.5 because clipping coordinates are rounded
|
-- 0.5 because clipping coordinates are rounded
|
||||||
@@ -3350,6 +3351,7 @@ function VolumeSlider:init(props)
|
|||||||
self.nudge_size = 0
|
self.nudge_size = 0
|
||||||
self.draw_nudge = false
|
self.draw_nudge = false
|
||||||
self.spacing = 0
|
self.spacing = 0
|
||||||
|
self.radius = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function VolumeSlider:set_volume(volume)
|
function VolumeSlider:set_volume(volume)
|
||||||
@@ -3370,6 +3372,7 @@ function VolumeSlider:on_coordinates()
|
|||||||
self.nudge_size = round(width * 0.18)
|
self.nudge_size = round(width * 0.18)
|
||||||
self.draw_nudge = self.ay < self.nudge_y
|
self.draw_nudge = self.ay < self.nudge_y
|
||||||
self.spacing = round(width * 0.2)
|
self.spacing = round(width * 0.2)
|
||||||
|
self.radius = math.max(2, (self.bx - self.ax) / 10)
|
||||||
end
|
end
|
||||||
function VolumeSlider:on_mbtn_left_down()
|
function VolumeSlider:on_mbtn_left_down()
|
||||||
self.pressed = true
|
self.pressed = true
|
||||||
@@ -3385,66 +3388,82 @@ function VolumeSlider:on_wheel_down() self:set_volume(state.volume - options.vol
|
|||||||
|
|
||||||
function VolumeSlider:render()
|
function VolumeSlider:render()
|
||||||
local visibility = self:get_visibility()
|
local visibility = self:get_visibility()
|
||||||
local width, height = self.bx - self.ax, self.by - self.ay
|
local ax, ay, bx, by = self.ax, self.ay, self.bx, self.by
|
||||||
|
local width, height = bx - ax, by - ay
|
||||||
|
|
||||||
if width <= 0 or height <= 0 or visibility <= 0 then return end
|
if width <= 0 or height <= 0 or visibility <= 0 then return end
|
||||||
|
|
||||||
local ass = assdraw.ass_new()
|
local ass = assdraw.ass_new()
|
||||||
|
|
||||||
local nudge_y, nudge_size = self.draw_nudge and self.nudge_y or -infinity, self.nudge_size
|
local nudge_y, nudge_size = self.draw_nudge and self.nudge_y or -infinity, self.nudge_size
|
||||||
|
local volume_y = self.ay + options.volume_border +
|
||||||
-- Background bar coordinates
|
((height - (options.volume_border * 2)) * (1 - math.min(state.volume / state.volume_max, 1)))
|
||||||
local bax, bay, bbx, bby = self.ax, self.ay, self.bx, self.by
|
|
||||||
|
|
||||||
-- Foreground bar coordinates
|
|
||||||
local height_without_border = height - (options.volume_border * 2)
|
|
||||||
local fax = self.ax + options.volume_border
|
|
||||||
local fay = self.ay + (height_without_border * (1 - math.min(state.volume / state.volume_max, 1))) +
|
|
||||||
options.volume_border
|
|
||||||
local fbx = self.bx - options.volume_border
|
|
||||||
local fby = self.by - options.volume_border
|
|
||||||
|
|
||||||
-- Draws a rectangle with nudge at requested position
|
-- Draws a rectangle with nudge at requested position
|
||||||
---@param ax number
|
---@param p number Padding from slider edges.
|
||||||
---@param ay number
|
---@param cy? number A y coordinate where to clip the path from the bottom.
|
||||||
---@param bx number
|
function create_nudged_path(p, cy)
|
||||||
---@param by number
|
cy = cy or ay + p
|
||||||
function make_nudged_path(ax, ay, bx, by)
|
local ax, bx, by = ax + p, bx - p, by - p
|
||||||
local fg_path = assdraw.ass_new()
|
local r = math.max(1, self.radius - p)
|
||||||
fg_path:move_to(bx, by)
|
local d, rh = r * 2, r / 2
|
||||||
fg_path:line_to(ax, by)
|
local nudge_size = ((quarter_pi_sin * (nudge_size - p)) + p) / quarter_pi_sin
|
||||||
local nudge_bottom_y = nudge_y + nudge_size
|
local path = assdraw.ass_new()
|
||||||
if ay <= nudge_bottom_y then
|
path:move_to(bx - r, by)
|
||||||
fg_path:line_to(ax, math.min(nudge_bottom_y))
|
path:line_to(ax + r, by)
|
||||||
if ay <= nudge_y then
|
if cy > by - d then
|
||||||
fg_path:line_to((ax + nudge_size), nudge_y)
|
local subtracted_radius = (d - (cy - (by - d))) / 2
|
||||||
local nudge_top_y = nudge_y - nudge_size
|
local xbd = (r - subtracted_radius * 1.35) -- x bezier delta
|
||||||
if ay <= nudge_top_y then
|
path:bezier_curve(ax + xbd, by, ax + xbd, cy, ax + r, cy)
|
||||||
fg_path:line_to(ax, nudge_top_y)
|
path:line_to(bx - r, cy)
|
||||||
fg_path:line_to(ax, ay)
|
path:bezier_curve(bx - xbd, cy, bx - xbd, by, bx - r, by)
|
||||||
fg_path:line_to(bx, ay)
|
|
||||||
fg_path:line_to(bx, nudge_top_y)
|
|
||||||
else
|
|
||||||
local triangle_side = ay - nudge_top_y
|
|
||||||
fg_path:line_to((ax + triangle_side), ay)
|
|
||||||
fg_path:line_to((bx - triangle_side), ay)
|
|
||||||
end
|
|
||||||
fg_path:line_to((bx - nudge_size), nudge_y)
|
|
||||||
else
|
|
||||||
local triangle_side = nudge_bottom_y - ay
|
|
||||||
fg_path:line_to((ax + triangle_side), ay)
|
|
||||||
fg_path:line_to((bx - triangle_side), ay)
|
|
||||||
end
|
|
||||||
fg_path:line_to(bx, nudge_bottom_y)
|
|
||||||
else
|
else
|
||||||
fg_path:line_to(ax, ay)
|
path:bezier_curve(ax + rh, by, ax, by - rh, ax, by - r)
|
||||||
fg_path:line_to(bx, ay)
|
local nudge_bottom_y = nudge_y + nudge_size
|
||||||
|
|
||||||
|
if cy + rh <= nudge_bottom_y then
|
||||||
|
path:line_to(ax, nudge_bottom_y)
|
||||||
|
if cy <= nudge_y then
|
||||||
|
path:line_to((ax + nudge_size), nudge_y)
|
||||||
|
local nudge_top_y = nudge_y - nudge_size
|
||||||
|
if cy <= nudge_top_y then
|
||||||
|
local r, rh = r, rh
|
||||||
|
if cy > nudge_top_y - r then
|
||||||
|
r = nudge_top_y - cy
|
||||||
|
rh = r / 2
|
||||||
|
end
|
||||||
|
path:line_to(ax, nudge_top_y)
|
||||||
|
path:line_to(ax, cy + r)
|
||||||
|
path:bezier_curve(ax, cy + rh, ax + rh, cy, ax + r, cy)
|
||||||
|
path:line_to(bx - r, cy)
|
||||||
|
path:bezier_curve(bx - rh, cy, bx, cy + rh, bx, cy + r)
|
||||||
|
path:line_to(bx, nudge_top_y)
|
||||||
|
else
|
||||||
|
local triangle_side = cy - nudge_top_y
|
||||||
|
path:line_to((ax + triangle_side), cy)
|
||||||
|
path:line_to((bx - triangle_side), cy)
|
||||||
|
end
|
||||||
|
path:line_to((bx - nudge_size), nudge_y)
|
||||||
|
else
|
||||||
|
local triangle_side = nudge_bottom_y - cy
|
||||||
|
path:line_to((ax + triangle_side), cy)
|
||||||
|
path:line_to((bx - triangle_side), cy)
|
||||||
|
end
|
||||||
|
path:line_to(bx, nudge_bottom_y)
|
||||||
|
else
|
||||||
|
path:line_to(ax, cy + r)
|
||||||
|
path:bezier_curve(ax, cy + rh, ax + rh, cy, ax + r, cy)
|
||||||
|
path:line_to(bx - r, cy)
|
||||||
|
path:bezier_curve(bx - rh, cy, bx, cy + rh, bx, cy + r)
|
||||||
|
end
|
||||||
|
path:line_to(bx, by - r)
|
||||||
|
path:bezier_curve(bx, by - rh, bx - rh, by, bx - r, by)
|
||||||
end
|
end
|
||||||
fg_path:line_to(bx, by)
|
return path
|
||||||
return fg_path
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- FG & BG paths
|
-- BG & FG paths
|
||||||
local fg_path = make_nudged_path(fax, fay, fbx, fby)
|
local bg_path = create_nudged_path(0)
|
||||||
local bg_path = make_nudged_path(bax, bay, bbx, bby)
|
local fg_path = create_nudged_path(options.volume_border, volume_y)
|
||||||
|
|
||||||
-- Background
|
-- Background
|
||||||
ass:new_event()
|
ass:new_event()
|
||||||
@@ -3469,13 +3488,13 @@ function VolumeSlider:render()
|
|||||||
local volume_string = tostring(round(state.volume * 10) / 10)
|
local volume_string = tostring(round(state.volume * 10) / 10)
|
||||||
local font_size = round(((width * 0.6) - (#volume_string * (width / 20))) * options.font_scale)
|
local font_size = round(((width * 0.6) - (#volume_string * (width / 20))) * options.font_scale)
|
||||||
local opacity = math.min(options.volume_opacity + 0.1, 1) * visibility
|
local opacity = math.min(options.volume_opacity + 0.1, 1) * visibility
|
||||||
if fay < self.by - self.spacing then
|
if volume_y < self.by - self.spacing then
|
||||||
ass:txt(self.ax + (width / 2), self.by - self.spacing, 2, volume_string, {
|
ass:txt(self.ax + (width / 2), self.by - self.spacing, 2, volume_string, {
|
||||||
size = font_size, color = options.color_foreground_text, opacity = opacity,
|
size = font_size, color = options.color_foreground_text, opacity = opacity,
|
||||||
clip = '\\clip(' .. fg_path.scale .. ', ' .. fg_path.text .. ')',
|
clip = '\\clip(' .. fg_path.scale .. ', ' .. fg_path.text .. ')',
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
if fay > self.by - self.spacing - font_size then
|
if volume_y > self.by - self.spacing - font_size then
|
||||||
ass:txt(self.ax + (width / 2), self.by - self.spacing, 2, volume_string, {
|
ass:txt(self.ax + (width / 2), self.by - self.spacing, 2, volume_string, {
|
||||||
size = font_size, color = options.color_background_text, opacity = opacity,
|
size = font_size, color = options.color_background_text, opacity = opacity,
|
||||||
clip = '\\iclip(' .. fg_path.scale .. ', ' .. fg_path.text .. ')',
|
clip = '\\iclip(' .. fg_path.scale .. ', ' .. fg_path.text .. ')',
|
||||||
@@ -3485,9 +3504,7 @@ function VolumeSlider:render()
|
|||||||
-- Disabled stripes for no audio
|
-- Disabled stripes for no audio
|
||||||
if not state.has_audio then
|
if not state.has_audio then
|
||||||
-- Create 100 foreground clip path
|
-- Create 100 foreground clip path
|
||||||
local f100ax, f100ay = self.ax + options.volume_border, self.ay + options.volume_border
|
local fg_100_path = create_nudged_path(options.volume_border)
|
||||||
local f100bx, f100by = self.bx - options.volume_border, self.by - options.volume_border
|
|
||||||
local fg_100_path = make_nudged_path(f100ax, f100ay, f100bx, f100by)
|
|
||||||
|
|
||||||
-- Render stripes
|
-- Render stripes
|
||||||
local stripe_height = 12
|
local stripe_height = 12
|
||||||
@@ -3531,6 +3548,10 @@ function Volume:init()
|
|||||||
self.slider = VolumeSlider:new({anchor_id = 'volume'})
|
self.slider = VolumeSlider:new({anchor_id = 'volume'})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Volume:get_visibility()
|
||||||
|
return self.slider.pressed and 1 or Element.get_visibility(self)
|
||||||
|
end
|
||||||
|
|
||||||
function Volume:update_dimensions()
|
function Volume:update_dimensions()
|
||||||
local width = state.fullormaxed and options.volume_size_fullscreen or options.volume_size
|
local width = state.fullormaxed and options.volume_size_fullscreen or options.volume_size
|
||||||
local controls, timeline, top_bar = Elements.controls, Elements.timeline, Elements.top_bar
|
local controls, timeline, top_bar = Elements.controls, Elements.timeline, Elements.top_bar
|
||||||
|
Reference in New Issue
Block a user