
`mbtn_left` and `wheel` events are now only fired on a `cursor.on_{event}` object, which resets at the beginning of each frame, so elements need to bind these listeners in their render functions. These properties are overwritable which allows elements to take over cursor event handling from their parents if necessary.
193 lines
6.0 KiB
Lua
193 lines
6.0 KiB
Lua
local Element = require('uosc_shared/elements/Element')
|
|
|
|
---@alias Dragging { start_time: number; start_x: number; distance: number; speed_distance: number; start_speed: number; }
|
|
|
|
---@class Speed : Element
|
|
local Speed = class(Element)
|
|
|
|
---@param props? ElementProps
|
|
function Speed:new(props) return Class.new(self, props) --[[@as Speed]] end
|
|
function Speed:init(props)
|
|
Element.init(self, 'speed', props)
|
|
|
|
self.width = 0
|
|
self.height = 0
|
|
self.notches = 10
|
|
self.notch_every = 0.1
|
|
---@type number
|
|
self.notch_spacing = nil
|
|
---@type number
|
|
self.font_size = nil
|
|
---@type Dragging|nil
|
|
self.dragging = nil
|
|
end
|
|
|
|
function Speed:on_coordinates()
|
|
self.height, self.width = self.by - self.ay, self.bx - self.ax
|
|
self.notch_spacing = self.width / (self.notches + 1)
|
|
self.font_size = round(self.height * 0.48 * options.font_scale)
|
|
end
|
|
|
|
function Speed:speed_step(speed, up)
|
|
if options.speed_step_is_factor then
|
|
if up then
|
|
return speed * options.speed_step
|
|
else
|
|
return speed * 1 / options.speed_step
|
|
end
|
|
else
|
|
if up then
|
|
return speed + options.speed_step
|
|
else
|
|
return speed - options.speed_step
|
|
end
|
|
end
|
|
end
|
|
|
|
function Speed:handle_cursor_down()
|
|
self:tween_stop() -- Stop and cleanup possible ongoing animations
|
|
self.dragging = {
|
|
start_time = mp.get_time(),
|
|
start_x = cursor.x,
|
|
distance = 0,
|
|
speed_distance = 0,
|
|
start_speed = state.speed,
|
|
}
|
|
end
|
|
|
|
function Speed:on_global_mouse_move()
|
|
if not self.dragging then return end
|
|
|
|
self.dragging.distance = cursor.x - self.dragging.start_x
|
|
self.dragging.speed_distance = (-self.dragging.distance / self.notch_spacing * self.notch_every)
|
|
|
|
local speed_current = state.speed
|
|
local speed_drag_current = self.dragging.start_speed + self.dragging.speed_distance
|
|
speed_drag_current = clamp(0.01, speed_drag_current, 100)
|
|
local drag_dir_up = speed_drag_current > speed_current
|
|
|
|
local speed_step_next = speed_current
|
|
local speed_drag_diff = math.abs(speed_drag_current - speed_current)
|
|
while math.abs(speed_step_next - speed_current) < speed_drag_diff do
|
|
speed_step_next = self:speed_step(speed_step_next, drag_dir_up)
|
|
end
|
|
local speed_step_prev = self:speed_step(speed_step_next, not drag_dir_up)
|
|
|
|
local speed_new = speed_step_prev
|
|
local speed_next_diff = math.abs(speed_drag_current - speed_step_next)
|
|
local speed_prev_diff = math.abs(speed_drag_current - speed_step_prev)
|
|
if speed_next_diff < speed_prev_diff then
|
|
speed_new = speed_step_next
|
|
end
|
|
|
|
if speed_new ~= speed_current then
|
|
mp.set_property_native('speed', speed_new)
|
|
end
|
|
end
|
|
|
|
function Speed:handle_cursor_up()
|
|
if self.proximity_raw == 0 then
|
|
-- Reset speed on short clicks
|
|
if self.dragging and math.abs(self.dragging.distance) < 6 and mp.get_time() - self.dragging.start_time < 0.15 then
|
|
mp.set_property_native('speed', 1)
|
|
end
|
|
end
|
|
self.dragging = nil
|
|
request_render()
|
|
end
|
|
|
|
function Speed:on_global_mouse_leave()
|
|
self.dragging = nil
|
|
request_render()
|
|
end
|
|
|
|
function Speed:handle_wheel_up() mp.set_property_native('speed', self:speed_step(state.speed, true)) end
|
|
function Speed:handle_wheel_down() mp.set_property_native('speed', self:speed_step(state.speed, false)) end
|
|
|
|
function Speed:render()
|
|
local visibility = self:get_visibility()
|
|
local opacity = self.dragging and 1 or visibility
|
|
|
|
if opacity <= 0 then return end
|
|
|
|
if self.proximity_raw == 0 then
|
|
cursor.on_primary_down = function()
|
|
self:handle_cursor_down()
|
|
cursor.on_primary_up = function() self:handle_cursor_up() end
|
|
end
|
|
cursor.on_wheel_down = function() self:handle_wheel_down() end
|
|
cursor.on_wheel_up = function() self:handle_wheel_up() end
|
|
end
|
|
if self.dragging then
|
|
cursor.on_primary_up = function() self:handle_cursor_up() end
|
|
end
|
|
|
|
local ass = assdraw.ass_new()
|
|
|
|
-- Background
|
|
ass:rect(self.ax, self.ay, self.bx, self.by, {color = bg, radius = 2, opacity = opacity * options.speed_opacity})
|
|
|
|
-- Coordinates
|
|
local ax, ay = self.ax, self.ay
|
|
local bx, by = self.bx, ay + self.height
|
|
local half_width = (self.width / 2)
|
|
local half_x = ax + half_width
|
|
|
|
-- Notches
|
|
local speed_at_center = state.speed
|
|
if self.dragging then
|
|
speed_at_center = self.dragging.start_speed + self.dragging.speed_distance
|
|
speed_at_center = clamp(0.01, speed_at_center, 100)
|
|
end
|
|
local nearest_notch_speed = round(speed_at_center / self.notch_every) * self.notch_every
|
|
local nearest_notch_x = half_x + (((nearest_notch_speed - speed_at_center) / self.notch_every) * self.notch_spacing)
|
|
local guide_size = math.floor(self.height / 7.5)
|
|
local notch_by = by - guide_size
|
|
local notch_ay_big = ay + round(self.font_size * 1.1)
|
|
local notch_ay_medium = notch_ay_big + ((notch_by - notch_ay_big) * 0.2)
|
|
local notch_ay_small = notch_ay_big + ((notch_by - notch_ay_big) * 0.4)
|
|
local from_to_index = math.floor(self.notches / 2)
|
|
|
|
for i = -from_to_index, from_to_index do
|
|
local notch_speed = nearest_notch_speed + (i * self.notch_every)
|
|
|
|
if notch_speed >= 0 and notch_speed <= 100 then
|
|
local notch_x = nearest_notch_x + (i * self.notch_spacing)
|
|
local notch_thickness = 1
|
|
local notch_ay = notch_ay_small
|
|
if (notch_speed % (self.notch_every * 10)) < 0.00000001 then
|
|
notch_ay = notch_ay_big
|
|
notch_thickness = 1.5
|
|
elseif (notch_speed % (self.notch_every * 5)) < 0.00000001 then
|
|
notch_ay = notch_ay_medium
|
|
end
|
|
|
|
ass:rect(notch_x - notch_thickness, notch_ay, notch_x + notch_thickness, notch_by, {
|
|
color = fg, border = 1, border_color = bg,
|
|
opacity = math.min(1.2 - (math.abs((notch_x - ax - half_width) / half_width)), 1) * opacity,
|
|
})
|
|
end
|
|
end
|
|
|
|
-- Center guide
|
|
ass:new_event()
|
|
ass:append('{\\rDefault\\an7\\blur0\\bord1\\shad0\\1c&H' .. fg .. '\\3c&H' .. bg .. '}')
|
|
ass:opacity(opacity)
|
|
ass:pos(0, 0)
|
|
ass:draw_start()
|
|
ass:move_to(half_x, by - 2 - guide_size)
|
|
ass:line_to(half_x + guide_size, by - 2)
|
|
ass:line_to(half_x - guide_size, by - 2)
|
|
ass:draw_stop()
|
|
|
|
-- Speed value
|
|
local speed_text = (round(state.speed * 100) / 100) .. 'x'
|
|
ass:txt(half_x, ay + (notch_ay_big - ay) / 2, 5, speed_text, {
|
|
size = self.font_size, color = bgt, border = options.text_border, border_color = bg, opacity = opacity,
|
|
})
|
|
|
|
return ass
|
|
end
|
|
|
|
return Speed
|