mpv/scripts/pause-indicator.lua
2023-08-10 00:18:43 -07:00

1026 lines
35 KiB
Lua

local msg = require('mp.msg')
local log = {
debug = function(format, ...)
return msg.debug(format:format(...))
end,
info = function(format, ...)
return msg.info(format:format(...))
end,
warn = function(format, ...)
return msg.warn(format:format(...))
end,
dump = function(item, ignore)
local level = 2
if "table" ~= type(item) then
msg.info(tostring(item))
return
end
local count = 1
local tablecount = 1
local result = {
"{ @" .. tostring(tablecount)
}
local seen = {
[item] = tablecount
}
local recurse
recurse = function(item, space)
for key, value in pairs(item) do
if not (key == ignore) then
if "table" == type(value) then
if not (seen[value]) then
tablecount = tablecount + 1
seen[value] = tablecount
count = count + 1
result[count] = space .. tostring(key) .. ": { @" .. tostring(tablecount)
recurse(value, space .. " ")
count = count + 1
result[count] = space .. "}"
else
count = count + 1
result[count] = space .. tostring(key) .. ": @" .. tostring(seen[value])
end
else
if "string" == type(value) then
value = ("%q"):format(value)
end
count = count + 1
result[count] = space .. tostring(key) .. ": " .. tostring(value)
end
end
end
end
recurse(item, " ")
count = count + 1
result[count] = "}"
return msg.info(table.concat(result, "\n"))
end
}
local options = require('mp.options')
local utils = require('mp.utils')
local script_name = 'torque-progressbar'
mp.get_osd_size = mp.get_osd_size or mp.get_screen_size
local settings = {
__defaults = { }
}
local settingsMeta = {
__reload = function(self)
for key, value in pairs(self.__defaults) do
settings[key] = value
end
options.read_options(self, script_name .. '/main')
if self['bar-height-inactive'] <= 0 then
self['bar-hide-inactive'] = true
self['bar-height-inactive'] = 1
end
end,
__migrate = function(self)
local oldConfig = mp.find_config_file(('lua-settings/%s.conf'):format(script_name))
local newConfigFile = ('lua-settings/%s/main.conf'):format(script_name)
local newConfig = mp.find_config_file(newConfigFile)
if oldConfig and not newConfig then
local folder, _ = utils.split_path(oldConfig)
local configDir = utils.join_path(folder, script_name)
newConfig = utils.join_path(configDir, 'main.conf')
log.info(('Old configuration detected. Attempting to migrate %q -> %q'):format(oldConfig, newConfig))
local dirExists = mp.find_config_file(configDir)
if dirExists and not utils.readdir(configDir) then
log.warn(('Configuration migration failed. %q exists and does not appear to be a folder'):format(configDir))
return
else
if not dirExists then
local res = utils.subprocess({
args = {
'mkdir',
configDir
}
})
if res.error or res.status ~= 0 then
log.warn(('Making directory %q failed.'):format(configDir))
return
end
end
end
local res = utils.subprocess({
args = {
'mv',
oldConfig,
newConfig
}
})
if res.error or res.status ~= 0 then
log.warn(('Moving file %q -> %q failed.'):format(oldConfig, newConfig))
return
end
if mp.find_config_file(newConfigFile) then
return log.info('Configuration successfully migrated.')
end
end
end,
__newindex = function(self, key, value)
self.__defaults[key] = value
return rawset(self, key, value)
end
}
settingsMeta.__index = settingsMeta
setmetatable(settings, settingsMeta)
settings:__migrate()
local helpText = { }
settings['hover-zone-height'] = 40
helpText['hover-zone-height'] = [[Sets the height of the rectangular area at the bottom of the screen that expands
the progress bar and shows playback time information when the mouse is hovered
over it.
]]
settings['top-hover-zone-height'] = 40
helpText['top-hover-zone-height'] = [[Sets the height of the rectangular area at the top of the screen that shows the
file name and system time when the mouse is hovered over it.
]]
settings['display-scale-factor'] = 1
helpText['display-scale-factor'] = [[Acts as a multiplier to increase the size of every UI element. Useful for high-
DPI displays that cause the UI to be rendered too small (happens at least on
macOS).
]]
settings['default-style'] = [[\fnSource Sans Pro\b1\bord2\shad0\fs30\c&HFC799E&\3c&H2D2D2D&]]
helpText['default-style'] = [[Default style that is applied to all UI elements. A string of ASS override tags.
Individual elements have their own style settings which override the tags here.
Changing the font will likely require changing the hover-time margin settings
and the offscreen-pos settings.
Here are some useful ASS override tags (omit square brackets):
\fn[Font Name]: sets the font to the named font.
\fs[number]: sets the font size to the given number.
\b[1/0]: sets the text bold or not (\b1 is bold, \b0 is regular weight).
\i[1/0]: sets the text italic or not (same semantics as bold).
\bord[number]: sets the outline width to the given number (in pixels).
\shad[number]: sets the shadow size to the given number (pixels).
\c&H[BBGGRR]&: sets the fill color for the text to the given color (hex pairs in
the order, blue, green, red).
\3c&H[BBGGRR]&: sets the outline color of the text to the given color.
\4c&H[BBGGRR]&: sets the shadow color of the text to the given color.
\alpha&H[AA]&: sets the line's transparency as a hex pair. 00 is fully opaque
and FF is fully transparent. Some UI elements are composed of
multiple layered lines, so adding transparency may not look good.
For further granularity, \1a&H[AA]& controls the fill opacity,
\3a&H[AA]& controls the outline opacity, and \4a&H[AA]& controls
the shadow opacity.
]]
settings['enable-bar'] = true
helpText['enable-bar'] = [[Controls whether or not the progress bar is drawn at all. If this is disabled,
it also (naturally) disables the click-to-seek functionality.
]]
settings['bar-hide-inactive'] = false
helpText['bar-hide-inactive'] = [[Causes the bar to not be drawn unless the mouse is hovering over it or a
request-display call is active. This is somewhat redundant with setting bar-
height-inactive=0, except that it can allow for very rudimentary context-
sensitive behavior because it can be toggled at runtime. For example, by using
the binding `f cycle pause; script-binding progressbar/toggle-inactive-bar`, it
is possible to have the bar be persistently present only in windowed or
fullscreen contexts, depending on the default setting.
]]
settings['bar-height-inactive'] = 2
helpText['bar-height-inactive'] = [[Sets the height of the bar display when the mouse is not in the active zone and
there is no request-display active. A value of 0 or less will cause bar-hide-
inactive to be set to true and the bar height to be set to 1. This should result
in the desired behavior while avoiding annoying debug logging in mpv (libass
does not like zero-height objects).
]]
settings['bar-height-active'] = 8
helpText['bar-height-active'] = [[Sets the height of the bar display when the mouse is in the active zone or
request-display is active. There is no logic attached to this, so 0 or negative
values may have unexpected results.
]]
settings['progress-bar-width'] = 0
helpText['progress-bar-width'] = [[If greater than zero, changes the progress bar style to be a small segment
rather than a continuous bar and sets its width.
]]
settings['seek-precision'] = 'exact'
helpText['seek-precision'] = [[Affects precision of seeks due to clicks on the progress bar. Should be 'exact' or
'keyframes'. Exact is slightly slower, but won't jump around between two
different times when clicking in the same place.
Actually, this gets passed directly into the `seek` command, so the value can be
any of the arguments supported by mpv, though the ones above are the only ones
that really make sense.
]]
settings['bar-default-style'] = [[\bord0\shad0]]
helpText['bar-default-style'] = [[A string of ASS override tags that get applied to all three layers of the bar:
progress, cache, and background. You probably don't want to remove \bord0 unless
your default-style includes it.
]]
settings['bar-foreground-style'] = ''
helpText['bar-foreground-style'] = [[A string of ASS override tags that get applied only to the progress layer of the
bar.
]]
settings['bar-cache-style'] = [[\c&H515151&]]
helpText['bar-cache-style'] = [[A string of ASS override tags that get applied only to the cache layer of the
bar. The default sets only the color.
]]
settings['bar-background-style'] = [[\c&H2D2D2D&]]
helpText['bar-background-style'] = [[A string of ASS override tags that get applied only to the background layer of
the bar. The default sets only the color.
]]
settings['enable-elapsed-time'] = true
helpText['enable-elapsed-time'] = [[Sets whether or not the elapsed time is displayed at all.
]]
settings['elapsed-style'] = ''
helpText['elapsed-style'] = [[A string of ASS override tags that get applied only to the elapsed time display.
]]
settings['elapsed-left-margin'] = 4
helpText['elapsed-left-margin'] = [[Controls how far from the left edge of the window the elapsed time display is
positioned.
]]
settings['elapsed-bottom-margin'] = 0
helpText['elapsed-bottom-margin'] = [[Controls how far above the expanded progress bar the elapsed time display is
positioned.
]]
settings['enable-remaining-time'] = true
helpText['enable-remaining-time'] = [[Sets whether or not the remaining time is displayed at all.
]]
settings['remaining-style'] = ''
helpText['remaining-style'] = [[A string of ASS override tags that get applied only to the remaining time
display.
]]
settings['remaining-right-margin'] = 4
helpText['remaining-right-margin'] = [[Controls how far from the right edge of the window the remaining time display is
positioned.
]]
settings['remaining-bottom-margin'] = 0
helpText['remaining-bottom-margin'] = [[Controls how far above the expanded progress bar the remaining time display is
positioned.
]]
settings['enable-hover-time'] = true
helpText['enable-hover-time'] = [[Sets whether or not the calculated time corresponding to the mouse position
is displayed when the mouse hovers over the progress bar.
]]
settings['hover-time-style'] = [[\fs26]]
helpText['hover-time-style'] = [[A string of ASS override tags that get applied only to the hover time display.
Unfortunately, due to the way the hover time display is animated, alpha values
set here will be overridden. This is subject to change in future versions.
]]
settings['hover-time-left-margin'] = 120
helpText['hover-time-left-margin'] = [[Controls how close to the left edge of the window the hover time display can
get. If this value is too small, it will end up overlapping the elapsed time
display.
]]
settings['hover-time-right-margin'] = 130
helpText['hover-time-right-margin'] = [[Controls how close to the right edge of the window the hover time display can
get. If this value is too small, it will end up overlapping the remaining time
display.
]]
settings['hover-time-bottom-margin'] = 0
helpText['hover-time-bottom-margin'] = [[Controls how far above the expanded progress bar the remaining time display is
positioned.
]]
settings['enable-title'] = true
helpText['enable-title'] = [[Sets whether or not the video title is displayed at all.
]]
settings['title-style'] = ''
helpText['title-style'] = [[A string of ASS override tags that get applied only to the video title display.
]]
settings['title-left-margin'] = 4
helpText['title-left-margin'] = [[Controls how far from the left edge of the window the video title display is
positioned.
]]
settings['title-top-margin'] = 0
helpText['title-top-margin'] = [[Controls how far from the top edge of the window the video title display is
positioned.
]]
settings['title-print-to-cli'] = true
helpText['title-print-to-cli'] = [[Controls whether or not the script logs the video title and playlist position
to the console every time a new video starts.
]]
settings['enable-system-time'] = true
helpText['enable-system-time'] = [[Sets whether or not the system time is displayed at all.
]]
settings['system-time-style'] = ''
helpText['system-time-style'] = [[A string of ASS override tags that get applied only to the system time display.
]]
settings['system-time-format'] = '%H:%M'
helpText['system-time-format'] = [[Sets the format used for the system time display. This must be a strftime-
compatible format string.
]]
settings['system-time-right-margin'] = 4
helpText['system-time-right-margin'] = [[Controls how far from the right edge of the window the system time display is
positioned.
]]
settings['system-time-top-margin'] = 0
helpText['system-time-top-margin'] = [[Controls how far from the top edge of the window the system time display is
positioned.
]]
settings['pause-indicator'] = true
helpText['pause-indicator'] = [[Sets whether or not the pause indicator is displayed. The pause indicator is a
momentary icon that flashes in the middle of the screen, similar to youtube.
]]
settings['pause-indicator-foreground-style'] = [[\c&HFC799E&]]
helpText['pause-indicator-foreground-style'] = [[A string of ASS override tags that get applied only to the foreground of the
pause indicator.
]]
settings['pause-indicator-background-style'] = [[\c&H2D2D2D&]]
helpText['pause-indicator-background-style'] = [[A string of ASS override tags that get applied only to the background of the
pause indicator.
]]
settings['enable-chapter-markers'] = true
helpText['enable-chapter-markers'] = [[Sets whether or not the progress bar is decorated with chapter markers. Due to
the way the chapter markers are currently implemented, videos with a large
number of chapters may slow down the script somewhat, but I have yet to run
into this being a problem.
]]
settings['chapter-marker-width'] = 2
helpText['chapter-marker-width'] = [[Controls the width of each chapter marker when the progress bar is inactive.
]]
settings['chapter-marker-width-active'] = 4
helpText['chapter-marker-width-active'] = [[Controls the width of each chapter marker when the progress bar is active.
]]
settings['chapter-marker-active-height-fraction'] = 1
helpText['chapter-marker-active-height-fraction'] = [[Modifies the height of the chapter markers when the progress bar is active. Acts
as a multiplier on the height of the active progress bar. A value greater than 1
will cause the markers to be taller than the expanded progress bar, whereas a
value less than 1 will cause them to be shorter.
]]
settings['chapter-marker-before-style'] = [[\c&HFC799E&]]
helpText['chapter-marker-before-style'] = [[A string of ASS override tags that get applied only to chapter markers that have
not yet been passed.
]]
settings['chapter-marker-after-style'] = [[\c&H2D2D2D&]]
helpText['chapter-marker-after-style'] = [[A string of ASS override tags that get applied only to chapter markers that have
already been passed.
]]
settings['request-display-duration'] = 1
helpText['request-display-duration'] = [[Sets the amount of time in seconds that the UI stays on the screen after it
receives a request-display signal. A value of 0 will keep the display on screen
only as long as the key bound to it is held down.
]]
settings['redraw-period'] = 0.03
helpText['redraw-period'] = [[Controls how often the display is redrawn, in seconds. This does not seem to
significantly affect the smoothness of animations, and it is subject to the
accuracy limits imposed by the scheduler mpv uses. Probably not worth changing
unless you have major performance problems.
]]
settings['animation-duration'] = 0.25
helpText['animation-duration'] = [[Controls how long the UI animations take. A value of 0 disables all animations
(which breaks the pause indicator).
]]
settings['elapsed-offscreen-pos'] = -100
helpText['elapsed-offscreen-pos'] = [[Controls how far off the left side of the window the elapsed time display tries
to move when it is inactive. If you use a non-default font, this value may need
to be tweaked. If this value is not far enough off-screen, the elapsed display
will disappear without animating all the way off-screen. Positive values will
cause the display to animate the wrong direction.
]]
settings['remaining-offscreen-pos'] = -100
helpText['remaining-offscreen-pos'] = [[Controls how far off the left side of the window the remaining time display
tries to move when it is inactive. If you use a non-default font, this value may
need to be tweaked. If this value is not far enough off-screen, the elapsed
display will disappear without animating all the way off-screen. Positive values
will cause the display to animate the wrong direction.
]]
settings['hover-time-offscreen-pos'] = -50
helpText['hover-time-offscreen-pos'] = [[Controls how far off the bottom of the window the mouse hover time display tries
to move when it is inactive. If you use a non-default font, this value may need
to be tweaked. If this value is not far enough off-screen, the elapsed
display will disappear without animating all the way off-screen. Positive values
will cause the display to animate the wrong direction.
]]
settings['system-time-offscreen-pos'] = -100
helpText['system-time-offscreen-pos'] = [[Controls how far off the left side of the window the system time display tries
to move when it is inactive. If you use a non-default font, this value may need
to be tweaked. If this value is not far enough off-screen, the elapsed display
will disappear without animating all the way off-screen. Positive values will
cause the display to animate the wrong direction.
]]
settings['title-offscreen-pos'] = -40
helpText['title-offscreen-pos'] = [[Controls how far off the left side of the window the video title display tries
to move when it is inactive. If you use a non-default font, this value may need
to be tweaked. If this value is not far enough off-screen, the elapsed display
will disappear without animating all the way off-screen. Positive values will
cause the display to animate the wrong direction.
]]
settings:__reload()
local Stack
do
local _class_0
local removeElementMetadata, reindex
local _base_0 = {
insert = function(self, element, index)
if index then
table.insert(self, index, element)
element[self] = index
else
table.insert(self, element)
element[self] = #self
end
if self.containmentKey then
element[self.containmentKey] = true
end
end,
remove = function(self, element)
if element[self] == nil then
error("Trying to remove an element that doesn't exist in this stack.")
end
table.remove(self, element[self])
reindex(self, element[self])
return removeElementMetadata(self, element)
end,
clear = function(self)
local element = table.remove(self)
while element do
removeElementMetadata(self, element)
element = table.remove(self)
end
end,
removeSortedList = function(self, elementList)
if #elementList < 1 then
return
end
for i = 1, #elementList - 1 do
local element = table.remove(elementList)
table.remove(self, element[self])
removeElementMetadata(self, element)
end
local lastElement = table.remove(elementList)
table.remove(self, lastElement[self])
reindex(self, lastElement[self])
return removeElementMetadata(self, lastElement)
end,
removeList = function(self, elementList)
table.sort(elementList, function(a, b)
return a[self] < b[self]
end)
return self:removeSortedList(elementList)
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, containmentKey)
self.containmentKey = containmentKey
end,
__base = _base_0,
__name = "Stack"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0
removeElementMetadata = function(self, element)
element[self] = nil
if self.containmentKey then
element[self.containmentKey] = false
end
end
reindex = function(self, start)
if start == nil then
start = 1
end
for i = start, #self do
(self[i])[self] = i
end
end
Stack = _class_0
end
local Window
do
local _class_0
local osdScale
local _base_0 = { }
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function() end,
__base = _base_0,
__name = "Window"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0
osdScale = settings['display-scale-factor']
self.__class.w, self.__class.h = 0, 0
self.update = function(self)
local w, h = mp.get_osd_size()
w, h = math.floor(w / osdScale), math.floor(h / osdScale)
if w ~= self.w or h ~= self.h then
self.w, self.h = w, h
return true
else
return false
end
end
Window = _class_0
end
local Rect
do
local _class_0
local _base_0 = {
cacheMaxBounds = function(self)
self.xMax = self.x + self.w
self.yMax = self.y + self.h
end,
setPosition = function(self, x, y)
self.x = x or self.x
self.y = y or self.y
return self:cacheMaxBounds()
end,
setSize = function(self, w, h)
self.w = w or self.w
self.h = h or self.h
return self:cacheMaxBounds()
end,
reset = function(self, x, y, w, h)
self.x = x or self.x
self.y = y or self.y
self.w = w or self.w
self.h = h or self.h
return self:cacheMaxBounds()
end,
move = function(self, x, y)
self.x = self.x + (x or self.x)
self.y = self.y + (y or self.y)
return self:cacheMaxBounds()
end,
stretch = function(self, w, h)
self.w = self.w + (w or self.w)
self.h = self.h + (h or self.h)
return self:cacheMaxBounds()
end,
containsPoint = function(self, x, y)
return (x >= self.x) and (x < self.xMax) and (y >= self.y) and (y < self.yMax)
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, x, y, w, h)
if x == nil then
x = -1
end
if y == nil then
y = -1
end
if w == nil then
w = -1
end
if h == nil then
h = -1
end
self.x, self.y, self.w, self.h = x, y, w, h
return self:cacheMaxBounds()
end,
__base = _base_0,
__name = "Rect"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
Rect = _class_0
end
local AnimationQueue
do
local _class_0
local animationList, deletionQueue
local _base_0 = { }
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function() end,
__base = _base_0,
__name = "AnimationQueue"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0
animationList = Stack('active')
deletionQueue = { }
self.addAnimation = function(animation)
if not (animation.active) then
return animationList:insert(animation)
end
end
self.removeAnimation = function(animation)
if animation.active then
return animationList:remove(animation)
end
end
self.destroyAnimationStack = function()
return animationList:clear()
end
self.animate = function()
if #animationList == 0 then
return
end
local currentTime = mp.get_time()
for _, animation in ipairs(animationList) do
if animation:update(currentTime) then
table.insert(deletionQueue, animation)
end
end
if #deletionQueue > 0 then
return animationList:removeSortedList(deletionQueue)
end
end
self.active = function()
return #animationList > 0
end
AnimationQueue = _class_0
end
local EventLoop
do
local _class_0
local _base_0 = {
reconfigure = function(self)
settings:__reload()
AnimationQueue.destroyAnimationStack()
for _, zone in ipairs(self.activityZones) do
zone:reconfigure()
end
for _, element in ipairs(self.uiElements) do
element:reconfigure()
end
end,
addZone = function(self, zone)
if zone == nil then
return
end
return self.activityZones:insert(zone)
end,
removeZone = function(self, zone)
if zone == nil then
return
end
return self.activityZones:remove(zone)
end,
generateUIFromZones = function(self)
local seenUIElements = { }
self.script = { }
self.uiElements:clear()
AnimationQueue.destroyAnimationStack()
for _, zone in ipairs(self.activityZones) do
for _, uiElement in ipairs(zone.elements) do
if not (seenUIElements[uiElement]) then
self:addUIElement(uiElement)
seenUIElements[uiElement] = true
end
end
end
return self.updateTimer:resume()
end,
addUIElement = function(self, uiElement)
if uiElement == nil then
error('nil UIElement added.')
end
self.uiElements:insert(uiElement)
return table.insert(self.script, '')
end,
removeUIElement = function(self, uiElement)
if uiElement == nil then
error('nil UIElement removed.')
end
table.remove(self.script, uiElement[self.uiElements])
return self.uiElements:remove(uiElement)
end,
resize = function(self)
for _, zone in ipairs(self.activityZones) do
zone:resize()
end
for _, uiElement in ipairs(self.uiElements) do
uiElement:resize()
end
end,
redraw = function(self, forceRedraw)
if Window:update() then
self:resize()
end
for index, zone in ipairs(self.activityZones) do
zone:update(self.displayRequested, false)
end
AnimationQueue.animate()
for index, uiElement in ipairs(self.uiElements) do
if uiElement:redraw() then
self.script[index] = uiElement:stringify()
end
end
return mp.set_osd_ass(Window.w, Window.h, table.concat(self.script, '\n'))
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self)
self.script = { }
self.uiElements = Stack()
self.activityZones = Stack()
self.displayRequested = false
self.updateTimer = mp.add_periodic_timer(settings['redraw-period'], (function()
local _base_1 = self
local _fn_0 = _base_1.redraw
return function(...)
return _fn_0(_base_1, ...)
end
end)())
self.updateTimer:stop()
mp.register_event('shutdown', function()
return self.updateTimer:kill()
end)
local displayRequestTimer
local displayDuration = settings['request-display-duration']
mp.add_key_binding("tab", "request-display", function(event)
if event.event == "repeat" then
return
end
if event.event == "down" or event.event == "press" then
if displayRequestTimer then
displayRequestTimer:kill()
end
self.displayRequested = true
end
if event.event == "up" or event.event == "press" then
if displayDuration == 0 then
self.displayRequested = false
else
displayRequestTimer = mp.add_timeout(displayDuration, function()
self.displayRequested = false
end)
end
end
end, {
complex = true
})
return mp.add_key_binding('ctrl+r', 'reconfigure', (function()
local _base_1 = self
local _fn_0 = _base_1.reconfigure
return function(...)
return _fn_0(_base_1, ...)
end
end)(), {
repeatable = false
})
end,
__base = _base_0,
__name = "EventLoop"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
EventLoop = _class_0
end
local Animation
do
local _class_0
local _base_0 = {
update = function(self, now)
if self.isReversed then
self.linearProgress = math.max(0, math.min(1, self.linearProgress + (self.lastUpdate - now) * self.durationR))
if self.linearProgress == 0 then
self.isFinished = true
end
else
self.linearProgress = math.max(0, math.min(1, self.linearProgress + (now - self.lastUpdate) * self.durationR))
if self.linearProgress == 1 then
self.isFinished = true
end
end
self.lastUpdate = now
local progress = math.pow(self.linearProgress, self.accel)
self.value = (1 - progress) * self.initialValue + progress * self.endValue
self.updateCb(self.value)
if self.isFinished and self.finishedCb then
self:finishedCb()
end
return self.isFinished
end,
interrupt = function(self, reverse)
self.finishedCb = nil
self.lastUpdate = mp.get_time()
self.isReversed = reverse
if not (self.active) then
self.isFinished = false
return AnimationQueue.addAnimation(self)
end
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, initialValue, endValue, duration, updateCb, finishedCb, accel)
if accel == nil then
accel = 1
end
self.initialValue, self.endValue, self.duration, self.updateCb, self.finishedCb, self.accel = initialValue, endValue, duration, updateCb, finishedCb, accel
self.value = self.initialValue
self.linearProgress = 0
self.lastUpdate = mp.get_time()
self.durationR = 1 / self.duration
self.isFinished = (self.duration <= 0)
self.active = false
self.isReversed = false
end,
__base = _base_0,
__name = "Animation"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
Animation = _class_0
end
local UIElement
do
local _class_0
local _base_0 = {
stringify = function(self)
self.needsUpdate = false
if not self.active then
return ''
else
return table.concat(self.line)
end
end,
activate = function(self, activate)
if activate == true then
self.animation:interrupt(false)
self.active = true
else
self.animation:interrupt(true)
self.animation.finishedCb = function()
self.active = false
end
end
end,
reconfigure = function(self)
self.needsUpdate = true
self.animationDuration = settings['animation-duration']
end,
resize = function(self)
return error('UIElement updateSize called')
end,
redraw = function(self)
return self.needsUpdate
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self)
self.needsUpdate = false
self.active = false
self.animationDuration = settings['animation-duration']
end,
__base = _base_0,
__name = "UIElement"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
UIElement = _class_0
end
local PauseIndicator
do
local _class_0
local _base_0 = {
stringify = function(self)
return table.concat(self.line)
end,
resize = function(self)
local w, h = 0.5 * Window.w, 0.5 * Window.h
self.line[5] = ([[%g,%g]]):format(w, h)
self.line[12] = ([[%g,%g]]):format(w, h)
end,
redraw = function()
return true
end,
animate = function(self, value)
local scale = value * 50 + 100
local scaleStr = ([[{\fscx%g\fscy%g]]):format(scale, scale)
local alphaStr = ('%02X'):format(value * value * 255)
self.line[1] = scaleStr
self.line[8] = scaleStr
self.line[3] = alphaStr
self.line[10] = alphaStr
end,
destroy = function(self, animation)
return self.eventLoop:removeUIElement(self)
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, eventLoop, paused)
self.eventLoop = eventLoop
local w, h = 0.5 * Window.w, 0.5 * Window.h
self.line = {
[[{\fscx0\fscy0]],
[[\alpha&H]],
0,
[[&\pos(]],
([[%g,%g]]):format(w, h),
([[)\an5\bord0%s\p1}]]):format(settings['pause-indicator-background-style']),
0,
[[{\fscx0\fscy0]],
[[\alpha&H]],
0,
[[&\pos(]],
([[%g,%g]]):format(w, h),
([[)\an5\bord0%s\p1}]]):format(settings['pause-indicator-foreground-style']),
0
}
if paused then
self.line[7] = 'm 75 37.5 b 75 58.21 58.21 75 37.5 75 16.79 75 0 58.21 0 37.5 0 16.79 16.79 0 37.5 0 58.21 0 75 16.79 75 37.5 m 23 20 l 23 55 33 55 33 20 m 42 20 l 42 55 52 55 52 20\n'
self.line[14] = 'm 0 0 m 75 75 m 23 20 l 23 55 33 55 33 20 m 42 20 l 42 55 52 55 52 20'
else
self.line[7] = 'm 75 37.5 b 75 58.21 58.21 75 37.5 75 16.79 75 0 58.21 0 37.5 0 16.79 16.79 0 37.5 0 58.21 0 75 16.79 75 37.5 m 25.8333 17.18 l 25.8333 57.6 60.8333 37.39\n'
self.line[14] = 'm 0 0 m 75 75 m 25.8333 17.18 l 25.8333 57.6 60.8333 37.39'
end
AnimationQueue.addAnimation(Animation(0, 1, settings['animation-duration'], (function()
local _base_1 = self
local _fn_0 = _base_1.animate
return function(...)
return _fn_0(_base_1, ...)
end
end)(), (function()
local _base_1 = self
local _fn_0 = _base_1.destroy
return function(...)
return _fn_0(_base_1, ...)
end
end)()))
return self.eventLoop:addUIElement(self)
end,
__base = _base_0,
__name = "PauseIndicator"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
PauseIndicator = _class_0
end
local eventLoop = EventLoop()
local notFrameStepping = false
if settings['pause-indicator'] then
local PauseIndicatorWrapper
PauseIndicatorWrapper = function(event, paused)
if notFrameStepping then
return PauseIndicator(eventLoop, paused)
elseif paused then
notFrameStepping = true
end
end
mp.add_key_binding('.', 'step-forward', function()
notFrameStepping = false
return mp.commandv('frame_step')
end, {
repeatable = true
})
mp.add_key_binding(',', 'step-backward', function()
notFrameStepping = false
return mp.commandv('frame_back_step')
end, {
repeatable = true
})
mp.observe_property('pause', 'bool', PauseIndicatorWrapper)
end
local initDraw
initDraw = function()
mp.unregister_event(initDraw)
notFrameStepping = true
eventLoop:resize()
eventLoop:redraw()
return eventLoop.updateTimer:resume()
end
local fileLoaded
fileLoaded = function()
return mp.register_event('playback-restart', initDraw)
end
return mp.register_event('file-loaded', fileLoaded)