refactor: cursor events consolidated into one interface (#483)
`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.
This commit is contained in:
@@ -296,7 +296,31 @@ end
|
|||||||
--[[ STATE ]]
|
--[[ STATE ]]
|
||||||
|
|
||||||
display = {width = 1280, height = 720, scale_x = 1, scale_y = 1, initialized = false}
|
display = {width = 1280, height = 720, scale_x = 1, scale_y = 1, initialized = false}
|
||||||
cursor = {hidden = true, hover_raw = false, x = 0, y = 0}
|
cursor = {
|
||||||
|
x = 0,
|
||||||
|
y = 0,
|
||||||
|
hidden = true,
|
||||||
|
hover_raw = false,
|
||||||
|
-- Event handlers that are only fired on cursor, bound during render loop. Guidelines:
|
||||||
|
-- - element activations (clicks) go to `mbtn_left_down` handler
|
||||||
|
-- - `mbtn_button_up` is only for clearing dragging/swiping
|
||||||
|
on_primary_down = nil,
|
||||||
|
on_primary_up = nil,
|
||||||
|
on_wheel_down = nil,
|
||||||
|
on_wheel_up = nil,
|
||||||
|
-- Called at the beginning of each render
|
||||||
|
reset_handlers = function()
|
||||||
|
cursor.on_primary_down, cursor.on_primary_up = nil, nil
|
||||||
|
cursor.on_wheel_down, cursor.on_wheel_up = nil, nil
|
||||||
|
end,
|
||||||
|
-- Enables pointer key group captures needed by handlers (called at the end of each render)
|
||||||
|
decide_keybinds = function()
|
||||||
|
local mbtn_left_decision = (cursor.on_primary_down or cursor.on_primary_up) and 'enable' or 'disable'
|
||||||
|
local wheel_decision = (cursor.on_wheel_down or cursor.on_wheel_up) and 'enable' or 'disable'
|
||||||
|
mp[mbtn_left_decision .. '_key_bindings']('mbtn_left')
|
||||||
|
mp[wheel_decision .. '_key_bindings']('wheel')
|
||||||
|
end
|
||||||
|
}
|
||||||
state = {
|
state = {
|
||||||
os = (function()
|
os = (function()
|
||||||
if os.getenv('windir') ~= nil then return 'windows' end
|
if os.getenv('windir') ~= nil then return 'windows' end
|
||||||
@@ -771,6 +795,23 @@ mp.observe_property('core-idle', 'native', create_state_setter('core_idle'))
|
|||||||
|
|
||||||
--[[ KEY BINDS ]]
|
--[[ KEY BINDS ]]
|
||||||
|
|
||||||
|
-- Pointer related binding groups
|
||||||
|
mp.set_key_bindings({
|
||||||
|
{
|
||||||
|
'mbtn_left',
|
||||||
|
function(...) call_maybe(cursor.on_primary_up, ...) end,
|
||||||
|
function(...)
|
||||||
|
update_mouse_pos(nil, mp.get_property_native('mouse-pos'))
|
||||||
|
call_maybe(cursor.on_primary_down, ...)
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{'mbtn_left_dbl', 'ignore'},
|
||||||
|
}, 'mbtn_left', 'force')
|
||||||
|
mp.set_key_bindings({
|
||||||
|
{'wheel_up', function(...) call_maybe(cursor.on_wheel_up, ...) end},
|
||||||
|
{'wheel_down', function(...) call_maybe(cursor.on_wheel_down, ...) end},
|
||||||
|
}, 'wheel', 'force')
|
||||||
|
|
||||||
-- Adds a key binding that respects rerouting set by `key_binding_overwrites` table.
|
-- Adds a key binding that respects rerouting set by `key_binding_overwrites` table.
|
||||||
---@param name string
|
---@param name string
|
||||||
---@param callback fun(event: table)
|
---@param callback fun(event: table)
|
||||||
|
@@ -23,19 +23,20 @@ function Button:init(id, props)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Button:on_coordinates() self.font_size = round((self.by - self.ay) * 0.7) end
|
function Button:on_coordinates() self.font_size = round((self.by - self.ay) * 0.7) end
|
||||||
function Button:on_mbtn_left_down()
|
function Button:handle_cursor_down()
|
||||||
-- Don't accept clicks while hidden.
|
|
||||||
if self:get_visibility() <= 0 then return end
|
|
||||||
-- We delay the callback to next tick, otherwise we are risking race
|
-- We delay the callback to next tick, otherwise we are risking race
|
||||||
-- conditions as we are in the middle of event dispatching.
|
-- conditions as we are in the middle of event dispatching.
|
||||||
-- For example, handler might add a menu to the end of the element stack, and that
|
-- For example, handler might add a menu to the end of the element stack, and that
|
||||||
-- than picks up this click even we are in right now, and instantly closes itself.
|
-- than picks up this click event we are in right now, and instantly closes itself.
|
||||||
mp.add_timeout(0.01, self.on_click)
|
mp.add_timeout(0.01, self.on_click)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Button:render()
|
function Button:render()
|
||||||
local visibility = self:get_visibility()
|
local visibility = self:get_visibility()
|
||||||
if visibility <= 0 then return end
|
if visibility <= 0 then return end
|
||||||
|
if self.proximity_raw == 0 then
|
||||||
|
cursor.on_primary_down = function() self:handle_cursor_down() end
|
||||||
|
end
|
||||||
|
|
||||||
local ass = assdraw.ass_new()
|
local ass = assdraw.ass_new()
|
||||||
local is_hover = self.proximity_raw == 0
|
local is_hover = self.proximity_raw == 0
|
||||||
@@ -54,7 +55,6 @@ function Button:render()
|
|||||||
-- Tooltip on hover
|
-- Tooltip on hover
|
||||||
if is_hover and self.tooltip then ass:tooltip(self, self.tooltip) end
|
if is_hover and self.tooltip then ass:tooltip(self, self.tooltip) end
|
||||||
|
|
||||||
|
|
||||||
-- Badge
|
-- Badge
|
||||||
local icon_clip
|
local icon_clip
|
||||||
if self.badge then
|
if self.badge then
|
||||||
|
@@ -29,8 +29,6 @@ function Elements:remove(idOrElement)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Elements:update_proximities()
|
function Elements:update_proximities()
|
||||||
local capture_mbtn_left = false
|
|
||||||
local capture_wheel = false
|
|
||||||
local menu_only = Elements.menu ~= nil
|
local menu_only = Elements.menu ~= nil
|
||||||
local mouse_leave_elements = {}
|
local mouse_leave_elements = {}
|
||||||
local mouse_enter_elements = {}
|
local mouse_enter_elements = {}
|
||||||
@@ -42,26 +40,13 @@ function Elements:update_proximities()
|
|||||||
|
|
||||||
-- If menu is open, all other elements have to be disabled
|
-- If menu is open, all other elements have to be disabled
|
||||||
if menu_only then
|
if menu_only then
|
||||||
if element.ignores_menu then
|
if element.ignores_menu then element:update_proximity()
|
||||||
capture_mbtn_left = true
|
else element:reset_proximity() end
|
||||||
capture_wheel = true
|
|
||||||
element:update_proximity()
|
|
||||||
else
|
|
||||||
element:reset_proximity()
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
element:update_proximity()
|
element:update_proximity()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Element has global forced key listeners
|
|
||||||
if element.on_global_mbtn_left_down then capture_mbtn_left = true end
|
|
||||||
if element.on_global_wheel_up or element.on_global_wheel_down then capture_wheel = true end
|
|
||||||
|
|
||||||
if element.proximity_raw == 0 then
|
if element.proximity_raw == 0 then
|
||||||
-- Element has local forced key listeners
|
|
||||||
if element.on_mbtn_left_down then capture_mbtn_left = true end
|
|
||||||
if element.on_wheel_up or element.on_wheel_up then capture_wheel = true end
|
|
||||||
|
|
||||||
-- Mouse entered element area
|
-- Mouse entered element area
|
||||||
if previous_proximity_raw ~= 0 then
|
if previous_proximity_raw ~= 0 then
|
||||||
mouse_enter_elements[#mouse_enter_elements + 1] = element
|
mouse_enter_elements[#mouse_enter_elements + 1] = element
|
||||||
@@ -75,10 +60,6 @@ function Elements:update_proximities()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Enable key group captures requested by elements
|
|
||||||
mp[capture_mbtn_left and 'enable_key_bindings' or 'disable_key_bindings']('mbtn_left')
|
|
||||||
mp[capture_wheel and 'enable_key_bindings' or 'disable_key_bindings']('wheel')
|
|
||||||
|
|
||||||
-- Trigger `mouse_leave` and `mouse_enter` events
|
-- Trigger `mouse_leave` and `mouse_enter` events
|
||||||
for _, element in ipairs(mouse_leave_elements) do element:trigger('mouse_leave') end
|
for _, element in ipairs(mouse_leave_elements) do element:trigger('mouse_leave') end
|
||||||
for _, element in ipairs(mouse_enter_elements) do element:trigger('mouse_enter') end
|
for _, element in ipairs(mouse_enter_elements) do element:trigger('mouse_enter') end
|
||||||
@@ -142,26 +123,4 @@ end
|
|||||||
function Elements:has(id) return self[id] ~= nil end
|
function Elements:has(id) return self[id] ~= nil end
|
||||||
function Elements:ipairs() return ipairs(self.itable) end
|
function Elements:ipairs() return ipairs(self.itable) end
|
||||||
|
|
||||||
---@param name string Event name.
|
|
||||||
function Elements:create_proximity_dispatcher(name)
|
|
||||||
return function(...) self:proximity_trigger(name, ...) end
|
|
||||||
end
|
|
||||||
|
|
||||||
mp.set_key_bindings({
|
|
||||||
{
|
|
||||||
'mbtn_left',
|
|
||||||
Elements:create_proximity_dispatcher('mbtn_left_up'),
|
|
||||||
function(...)
|
|
||||||
update_mouse_pos(nil, mp.get_property_native('mouse-pos'))
|
|
||||||
Elements:proximity_trigger('mbtn_left_down', ...)
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
{'mbtn_left_dbl', 'ignore'},
|
|
||||||
}, 'mbtn_left', 'force')
|
|
||||||
|
|
||||||
mp.set_key_bindings({
|
|
||||||
{'wheel_up', Elements:create_proximity_dispatcher('wheel_up')},
|
|
||||||
{'wheel_down', Elements:create_proximity_dispatcher('wheel_down')},
|
|
||||||
}, 'wheel', 'force')
|
|
||||||
|
|
||||||
return Elements
|
return Elements
|
||||||
|
@@ -518,7 +518,7 @@ end
|
|||||||
function Menu:on_display() self:update_dimensions() end
|
function Menu:on_display() self:update_dimensions() end
|
||||||
function Menu:on_prop_fullormaxed() self:update_content_dimensions() end
|
function Menu:on_prop_fullormaxed() self:update_content_dimensions() end
|
||||||
|
|
||||||
function Menu:on_global_mbtn_left_down()
|
function Menu:handle_cursor_down()
|
||||||
if self.proximity_raw == 0 then
|
if self.proximity_raw == 0 then
|
||||||
self.drag_data = {{y = cursor.y, time = mp.get_time()}}
|
self.drag_data = {{y = cursor.y, time = mp.get_time()}}
|
||||||
self.current.fling = nil
|
self.current.fling = nil
|
||||||
@@ -538,7 +538,7 @@ function Menu:fling_distance()
|
|||||||
return #self.drag_data < 2 and 0 or ((first.y - last.y) / ((first.time - last.time) / 0.03)) * 10
|
return #self.drag_data < 2 and 0 or ((first.y - last.y) / ((first.time - last.time) / 0.03)) * 10
|
||||||
end
|
end
|
||||||
|
|
||||||
function Menu:on_global_mbtn_left_up()
|
function Menu:handle_cursor_up()
|
||||||
if self.proximity_raw == 0 and self.drag_data and not self.is_dragging then
|
if self.proximity_raw == 0 and self.drag_data and not self.is_dragging then
|
||||||
self:select_item_below_cursor()
|
self:select_item_below_cursor()
|
||||||
self:open_selected_item({preselect_submenu_item = false, keep_open = self.modifiers and self.modifiers.shift})
|
self:open_selected_item({preselect_submenu_item = false, keep_open = self.modifiers and self.modifiers.shift})
|
||||||
@@ -570,8 +570,8 @@ function Menu:on_global_mouse_move()
|
|||||||
request_render()
|
request_render()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Menu:on_wheel_up() self:scroll_by(self.scroll_step * -3, nil, {update_cursor = true}) end
|
function Menu:handle_wheel_up() self:scroll_by(self.scroll_step * -3, nil, {update_cursor = true}) end
|
||||||
function Menu:on_wheel_down() self:scroll_by(self.scroll_step * 3, nil, {update_cursor = true}) end
|
function Menu:handle_wheel_down() self:scroll_by(self.scroll_step * 3, nil, {update_cursor = true}) end
|
||||||
|
|
||||||
function Menu:on_pgup()
|
function Menu:on_pgup()
|
||||||
local menu = self.current
|
local menu = self.current
|
||||||
@@ -647,8 +647,8 @@ function Menu:create_modified_mbtn_left_handler(modifiers)
|
|||||||
return function()
|
return function()
|
||||||
self.mouse_nav = true
|
self.mouse_nav = true
|
||||||
self.modifiers = modifiers
|
self.modifiers = modifiers
|
||||||
self:on_global_mbtn_left_down()
|
self:handle_cursor_down()
|
||||||
self:on_global_mbtn_left_up()
|
self:handle_cursor_up()
|
||||||
self.modifiers = nil
|
self.modifiers = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -677,6 +677,13 @@ function Menu:render()
|
|||||||
end
|
end
|
||||||
if update_cursor then self:select_item_below_cursor() end
|
if update_cursor then self:select_item_below_cursor() end
|
||||||
|
|
||||||
|
cursor.on_primary_down = function() self:handle_cursor_down() end
|
||||||
|
cursor.on_primary_up = function() self:handle_cursor_up() end
|
||||||
|
if self.proximity_raw == 0 then
|
||||||
|
cursor.on_wheel_down = function() self:handle_wheel_down() end
|
||||||
|
cursor.on_wheel_up = function() self:handle_wheel_up() end
|
||||||
|
end
|
||||||
|
|
||||||
local ass = assdraw.ass_new()
|
local ass = assdraw.ass_new()
|
||||||
local opacity = options.menu_opacity * self.opacity
|
local opacity = options.menu_opacity * self.opacity
|
||||||
local spacing = self.item_padding
|
local spacing = self.item_padding
|
||||||
|
@@ -44,9 +44,7 @@ function Speed:speed_step(speed, up)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Speed:on_mbtn_left_down()
|
function Speed:handle_cursor_down()
|
||||||
-- Don't accept clicks while hidden.
|
|
||||||
if self:get_visibility() <= 0 then return end
|
|
||||||
self:tween_stop() -- Stop and cleanup possible ongoing animations
|
self:tween_stop() -- Stop and cleanup possible ongoing animations
|
||||||
self.dragging = {
|
self.dragging = {
|
||||||
start_time = mp.get_time(),
|
start_time = mp.get_time(),
|
||||||
@@ -87,14 +85,13 @@ function Speed:on_global_mouse_move()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Speed:on_mbtn_left_up()
|
function Speed:handle_cursor_up()
|
||||||
-- Reset speed on short clicks
|
if self.proximity_raw == 0 then
|
||||||
if self.dragging and math.abs(self.dragging.distance) < 6 and mp.get_time() - self.dragging.start_time < 0.15 then
|
-- Reset speed on short clicks
|
||||||
mp.set_property_native('speed', 1)
|
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
|
end
|
||||||
end
|
|
||||||
|
|
||||||
function Speed:on_global_mbtn_left_up()
|
|
||||||
self.dragging = nil
|
self.dragging = nil
|
||||||
request_render()
|
request_render()
|
||||||
end
|
end
|
||||||
@@ -104,8 +101,8 @@ function Speed:on_global_mouse_leave()
|
|||||||
request_render()
|
request_render()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Speed:on_wheel_up() mp.set_property_native('speed', self:speed_step(state.speed, true)) end
|
function Speed:handle_wheel_up() mp.set_property_native('speed', self:speed_step(state.speed, true)) end
|
||||||
function Speed:on_wheel_down() mp.set_property_native('speed', self:speed_step(state.speed, false)) end
|
function Speed:handle_wheel_down() mp.set_property_native('speed', self:speed_step(state.speed, false)) end
|
||||||
|
|
||||||
function Speed:render()
|
function Speed:render()
|
||||||
local visibility = self:get_visibility()
|
local visibility = self:get_visibility()
|
||||||
@@ -113,6 +110,18 @@ function Speed:render()
|
|||||||
|
|
||||||
if opacity <= 0 then return end
|
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()
|
local ass = assdraw.ass_new()
|
||||||
|
|
||||||
-- Background
|
-- Background
|
||||||
|
@@ -6,6 +6,7 @@ local Timeline = class(Element)
|
|||||||
function Timeline:new() return Class.new(self) --[[@as Timeline]] end
|
function Timeline:new() return Class.new(self) --[[@as Timeline]] end
|
||||||
function Timeline:init()
|
function Timeline:init()
|
||||||
Element.init(self, 'timeline')
|
Element.init(self, 'timeline')
|
||||||
|
---@type false|{pause: boolean}
|
||||||
self.pressed = false
|
self.pressed = false
|
||||||
self.obstructed = false
|
self.obstructed = false
|
||||||
self.size_max = 0
|
self.size_max = 0
|
||||||
@@ -13,7 +14,8 @@ function Timeline:init()
|
|||||||
self.size_min_override = options.timeline_start_hidden and 0 or nil
|
self.size_min_override = options.timeline_start_hidden and 0 or nil
|
||||||
self.font_size = 0
|
self.font_size = 0
|
||||||
self.top_border = options.timeline_border
|
self.top_border = options.timeline_border
|
||||||
self.hovered_chapter = nil
|
self.is_hovered = false
|
||||||
|
self.has_thumbnail = false
|
||||||
|
|
||||||
-- Release any dragging when file gets unloaded
|
-- Release any dragging when file gets unloaded
|
||||||
mp.register_event('end-file', function() self.pressed = false end)
|
mp.register_event('end-file', function() self.pressed = false end)
|
||||||
@@ -44,7 +46,7 @@ function Timeline:get_effective_line_width()
|
|||||||
return state.fullormaxed and options.timeline_line_width_fullscreen or options.timeline_line_width
|
return state.fullormaxed and options.timeline_line_width_fullscreen or options.timeline_line_width
|
||||||
end
|
end
|
||||||
|
|
||||||
function Timeline:get_is_hovered() return self.enabled and (self.proximity_raw == 0 or self.hovered_chapter ~= nil) end
|
function Timeline:get_is_hovered() return self.enabled and self.is_hovered end
|
||||||
|
|
||||||
function Timeline:update_dimensions()
|
function Timeline:update_dimensions()
|
||||||
if state.fullormaxed then
|
if state.fullormaxed then
|
||||||
@@ -91,41 +93,20 @@ function Timeline:set_from_cursor(fast)
|
|||||||
end
|
end
|
||||||
function Timeline:clear_thumbnail() mp.commandv('script-message-to', 'thumbfast', 'clear') end
|
function Timeline:clear_thumbnail() mp.commandv('script-message-to', 'thumbfast', 'clear') end
|
||||||
|
|
||||||
function Timeline:determine_chapter_click_handler()
|
function Timeline:handle_cursor_down()
|
||||||
if self.hovered_chapter then
|
self.pressed = {pause = state.pause}
|
||||||
if not self.on_global_mbtn_left_down then
|
|
||||||
self.on_global_mbtn_left_down = function()
|
|
||||||
if self.hovered_chapter then mp.commandv('seek', self.hovered_chapter.time, 'absolute+exact') end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if self.on_global_mbtn_left_down then
|
|
||||||
self.on_global_mbtn_left_down = nil
|
|
||||||
if self.proximity_raw ~= 0 then self:clear_thumbnail() end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Timeline:on_mbtn_left_down()
|
|
||||||
-- `self.on_global_mbtn_left_down` has precedent
|
|
||||||
if self.on_global_mbtn_left_down then return end
|
|
||||||
|
|
||||||
self.pressed = true
|
|
||||||
self.pressed_pause = state.pause
|
|
||||||
mp.set_property_native('pause', true)
|
mp.set_property_native('pause', true)
|
||||||
self:set_from_cursor()
|
self:set_from_cursor()
|
||||||
|
cursor.on_primary_up = function() self:handle_cursor_up() end
|
||||||
end
|
end
|
||||||
function Timeline:on_prop_duration() self:decide_enabled() end
|
function Timeline:on_prop_duration() self:decide_enabled() end
|
||||||
function Timeline:on_prop_time() self:decide_enabled() end
|
function Timeline:on_prop_time() self:decide_enabled() end
|
||||||
function Timeline:on_prop_border() self:update_dimensions() end
|
function Timeline:on_prop_border() self:update_dimensions() end
|
||||||
function Timeline:on_prop_fullormaxed() self:update_dimensions() end
|
function Timeline:on_prop_fullormaxed() self:update_dimensions() end
|
||||||
function Timeline:on_display() self:update_dimensions() end
|
function Timeline:on_display() self:update_dimensions() end
|
||||||
function Timeline:on_mouse_leave()
|
function Timeline:handle_cursor_up()
|
||||||
if not self.hovered_chapter then self:clear_thumbnail() end
|
|
||||||
end
|
|
||||||
function Timeline:on_global_mbtn_left_up()
|
|
||||||
if self.pressed then
|
if self.pressed then
|
||||||
mp.set_property_native('pause', self.pressed_pause)
|
mp.set_property_native('pause', self.pressed.pause)
|
||||||
self.pressed = false
|
self.pressed = false
|
||||||
end
|
end
|
||||||
self:clear_thumbnail()
|
self:clear_thumbnail()
|
||||||
@@ -144,11 +125,12 @@ function Timeline:on_global_mouse_move()
|
|||||||
self.seek_timer:kill()
|
self.seek_timer:kill()
|
||||||
self.seek_timer:resume()
|
self.seek_timer:resume()
|
||||||
else self:set_from_cursor() end
|
else self:set_from_cursor() end
|
||||||
|
elseif self.has_thumbnail and self.proximity_raw > 0 then
|
||||||
|
self:clear_thumbnail()
|
||||||
end
|
end
|
||||||
self:determine_chapter_click_handler()
|
|
||||||
end
|
end
|
||||||
function Timeline:on_wheel_up() mp.commandv('seek', options.timeline_step) end
|
function Timeline:handle_wheel_up() mp.commandv('seek', options.timeline_step) end
|
||||||
function Timeline:on_wheel_down() mp.commandv('seek', -options.timeline_step) end
|
function Timeline:handle_wheel_down() mp.commandv('seek', -options.timeline_step) end
|
||||||
|
|
||||||
function Timeline:render()
|
function Timeline:render()
|
||||||
if self.size_max == 0 then return end
|
if self.size_max == 0 then return end
|
||||||
@@ -156,8 +138,18 @@ function Timeline:render()
|
|||||||
local size_min = self:get_effective_size_min()
|
local size_min = self:get_effective_size_min()
|
||||||
local size = self:get_effective_size()
|
local size = self:get_effective_size()
|
||||||
local visibility = self:get_visibility()
|
local visibility = self:get_visibility()
|
||||||
|
self.is_hovered = false
|
||||||
|
|
||||||
if size < 1 then return end
|
if size < 1 then return end
|
||||||
|
if self.proximity_raw == 0 then
|
||||||
|
self.is_hovered = true
|
||||||
|
cursor.on_primary_down = function() self:handle_cursor_down() end
|
||||||
|
cursor.on_wheel_down = function() self:handle_wheel_down() end
|
||||||
|
cursor.on_wheel_up = function() self:handle_wheel_up() end
|
||||||
|
end
|
||||||
|
if self.pressed then
|
||||||
|
cursor.on_primary_up = function() self:handle_cursor_up() end
|
||||||
|
end
|
||||||
|
|
||||||
local ass = assdraw.ass_new()
|
local ass = assdraw.ass_new()
|
||||||
|
|
||||||
@@ -248,7 +240,7 @@ function Timeline:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Chapters
|
-- Chapters
|
||||||
self.hovered_chapter = nil
|
local hovered_chapter = nil
|
||||||
if (options.timeline_chapters_opacity > 0
|
if (options.timeline_chapters_opacity > 0
|
||||||
and (#state.chapters > 0 or state.ab_loop_a or state.ab_loop_b)
|
and (#state.chapters > 0 or state.ab_loop_a or state.ab_loop_b)
|
||||||
) then
|
) then
|
||||||
@@ -274,7 +266,7 @@ function Timeline:render()
|
|||||||
|
|
||||||
if #state.chapters > 0 then
|
if #state.chapters > 0 then
|
||||||
-- Find hovered chapter indicator
|
-- Find hovered chapter indicator
|
||||||
local hovered_chapter, closest_delta = nil, INFINITY
|
local closest_delta = INFINITY
|
||||||
|
|
||||||
if self.proximity_raw < diamond_radius_hovered then
|
if self.proximity_raw < diamond_radius_hovered then
|
||||||
for i, chapter in ipairs(state.chapters) do
|
for i, chapter in ipairs(state.chapters) do
|
||||||
@@ -282,6 +274,10 @@ function Timeline:render()
|
|||||||
local cursor_chapter_delta = math.sqrt((cursor.x - chapter_x) ^ 2 + (cursor.y - chapter_y) ^ 2)
|
local cursor_chapter_delta = math.sqrt((cursor.x - chapter_x) ^ 2 + (cursor.y - chapter_y) ^ 2)
|
||||||
if cursor_chapter_delta <= diamond_radius_hovered and cursor_chapter_delta < closest_delta then
|
if cursor_chapter_delta <= diamond_radius_hovered and cursor_chapter_delta < closest_delta then
|
||||||
hovered_chapter, closest_delta = chapter, cursor_chapter_delta
|
hovered_chapter, closest_delta = chapter, cursor_chapter_delta
|
||||||
|
self.is_hovered = true
|
||||||
|
cursor.on_primary_down = function()
|
||||||
|
mp.commandv('seek', hovered_chapter.time, 'absolute+exact')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -291,11 +287,7 @@ function Timeline:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Render hovered chapter above others
|
-- Render hovered chapter above others
|
||||||
if hovered_chapter then
|
if hovered_chapter then draw_chapter(hovered_chapter.time, diamond_radius_hovered) end
|
||||||
draw_chapter(hovered_chapter.time, diamond_radius_hovered)
|
|
||||||
self.hovered_chapter = hovered_chapter
|
|
||||||
self:determine_chapter_click_handler()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- A-B loop indicators
|
-- A-B loop indicators
|
||||||
@@ -363,10 +355,10 @@ function Timeline:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Hovered time and chapter
|
-- Hovered time and chapter
|
||||||
if (self.proximity_raw == 0 or self.pressed or self.hovered_chapter) and
|
if (self.proximity_raw == 0 or self.pressed or hovered_chapter) and
|
||||||
not (Elements.speed and Elements.speed.dragging) then
|
not (Elements.speed and Elements.speed.dragging) then
|
||||||
local cursor_x = self.hovered_chapter and t2x(self.hovered_chapter.time) or cursor.x
|
local cursor_x = hovered_chapter and t2x(hovered_chapter.time) or cursor.x
|
||||||
local hovered_seconds = self.hovered_chapter and self.hovered_chapter.time or self:get_time_at_x(cursor.x)
|
local hovered_seconds = hovered_chapter and hovered_chapter.time or self:get_time_at_x(cursor.x)
|
||||||
|
|
||||||
-- Cursor line
|
-- Cursor line
|
||||||
-- 0.5 to switch when the pixel is half filled in
|
-- 0.5 to switch when the pixel is half filled in
|
||||||
@@ -397,7 +389,10 @@ function Timeline:render()
|
|||||||
local ax, ay = (thumb_x - border) / scale_x, (thumb_y - border) / scale_y
|
local ax, ay = (thumb_x - border) / scale_x, (thumb_y - border) / scale_y
|
||||||
local bx, by = (thumb_x + thumb_width + border) / scale_x, (thumb_y + thumb_height + border) / scale_y
|
local bx, by = (thumb_x + thumb_width + border) / scale_x, (thumb_y + thumb_height + border) / scale_y
|
||||||
ass:rect(ax, ay, bx, by, {color = bg, border = 1, border_color = fg, border_opacity = 0.08, radius = 2})
|
ass:rect(ax, ay, bx, by, {color = bg, border = 1, border_color = fg, border_opacity = 0.08, radius = 2})
|
||||||
mp.commandv('script-message-to', 'thumbfast', 'thumb', hovered_seconds, thumb_x, thumb_y)
|
if not self.pressed then
|
||||||
|
mp.commandv('script-message-to', 'thumbfast', 'thumb', hovered_seconds, thumb_x, thumb_y)
|
||||||
|
self.has_thumbnail = true
|
||||||
|
end
|
||||||
tooltip_anchor.ax, tooltip_anchor.bx, tooltip_anchor.ay = ax, bx, ay
|
tooltip_anchor.ax, tooltip_anchor.bx, tooltip_anchor.ay = ax, bx, ay
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@ function TopBarButton:init(id, props)
|
|||||||
self.command = props.command
|
self.command = props.command
|
||||||
end
|
end
|
||||||
|
|
||||||
function TopBarButton:on_mbtn_left_down()
|
function TopBarButton:handle_cursor_down()
|
||||||
mp.command(type(self.command) == 'function' and self.command() or self.command)
|
mp.command(type(self.command) == 'function' and self.command() or self.command)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -28,6 +28,7 @@ function TopBarButton:render()
|
|||||||
-- Background on hover
|
-- Background on hover
|
||||||
if self.proximity_raw == 0 then
|
if self.proximity_raw == 0 then
|
||||||
ass:rect(self.ax, self.ay, self.bx, self.by, {color = self.background, opacity = visibility})
|
ass:rect(self.ax, self.ay, self.bx, self.by, {color = self.background, opacity = visibility})
|
||||||
|
cursor.on_primary_down = function() self:handle_cursor_down() end
|
||||||
end
|
end
|
||||||
|
|
||||||
local width, height = self.bx - self.ax, self.by - self.ay
|
local width, height = self.bx - self.ax, self.by - self.ay
|
||||||
@@ -151,10 +152,6 @@ function TopBar:on_prop_maximized()
|
|||||||
self:update_dimensions()
|
self:update_dimensions()
|
||||||
end
|
end
|
||||||
|
|
||||||
function TopBar:on_mbtn_left_down()
|
|
||||||
if cursor.x < self.title_bx then self:toggle_title() end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TopBar:on_display() self:update_dimensions() end
|
function TopBar:on_display() self:update_dimensions() end
|
||||||
|
|
||||||
function TopBar:render()
|
function TopBar:render()
|
||||||
@@ -193,6 +190,12 @@ function TopBar:render()
|
|||||||
}
|
}
|
||||||
local bx = math.min(max_bx, title_ax + text_width(main_title, opts) + padding * 2)
|
local bx = math.min(max_bx, title_ax + text_width(main_title, opts) + padding * 2)
|
||||||
local by = self.by - bg_margin
|
local by = self.by - bg_margin
|
||||||
|
local rect = {ax = title_ax, ay = self.ay, bx = bx, by = self.by}
|
||||||
|
|
||||||
|
if get_point_to_rectangle_proximity(cursor, rect) == 0 then
|
||||||
|
cursor.on_primary_down = function() self:toggle_title() end
|
||||||
|
end
|
||||||
|
|
||||||
ass:rect(title_ax, title_ay, bx, by, {
|
ass:rect(title_ax, title_ay, bx, by, {
|
||||||
color = bg, opacity = visibility * options.top_bar_title_opacity, radius = 2,
|
color = bg, opacity = visibility * options.top_bar_title_opacity, radius = 2,
|
||||||
})
|
})
|
||||||
|
@@ -7,10 +7,12 @@ local MuteButton = class(Element)
|
|||||||
---@param props? ElementProps
|
---@param props? ElementProps
|
||||||
function MuteButton:new(props) return Class.new(self, 'volume_mute', props) --[[@as MuteButton]] end
|
function MuteButton:new(props) return Class.new(self, 'volume_mute', props) --[[@as MuteButton]] end
|
||||||
function MuteButton:get_visibility() return Elements.volume:get_visibility(self) end
|
function MuteButton:get_visibility() return Elements.volume:get_visibility(self) end
|
||||||
function MuteButton:on_mbtn_left_down() mp.commandv('cycle', 'mute') end
|
|
||||||
function MuteButton:render()
|
function MuteButton:render()
|
||||||
local visibility = self:get_visibility()
|
local visibility = self:get_visibility()
|
||||||
if visibility <= 0 then return end
|
if visibility <= 0 then return end
|
||||||
|
if self.proximity_raw == 0 then
|
||||||
|
cursor.on_primary_down = function() mp.commandv('cycle', 'mute') end
|
||||||
|
end
|
||||||
local ass = assdraw.ass_new()
|
local ass = assdraw.ass_new()
|
||||||
local icon_name = state.mute and 'volume_off' or 'volume_up'
|
local icon_name = state.mute and 'volume_off' or 'volume_up'
|
||||||
local width = self.bx - self.ax
|
local width = self.bx - self.ax
|
||||||
@@ -58,17 +60,11 @@ function VolumeSlider:on_coordinates()
|
|||||||
self.spacing = round(width * 0.2)
|
self.spacing = round(width * 0.2)
|
||||||
self.radius = math.max(2, (self.bx - self.ax) / 10)
|
self.radius = math.max(2, (self.bx - self.ax) / 10)
|
||||||
end
|
end
|
||||||
function VolumeSlider:on_mbtn_left_down()
|
|
||||||
self.pressed = true
|
|
||||||
self:set_from_cursor()
|
|
||||||
end
|
|
||||||
function VolumeSlider:on_global_mbtn_left_up() self.pressed = false end
|
|
||||||
function VolumeSlider:on_global_mouse_leave() self.pressed = false end
|
|
||||||
function VolumeSlider:on_global_mouse_move()
|
function VolumeSlider:on_global_mouse_move()
|
||||||
if self.pressed then self:set_from_cursor() end
|
if self.pressed then self:set_from_cursor() end
|
||||||
end
|
end
|
||||||
function VolumeSlider:on_wheel_up() self:set_volume(state.volume + options.volume_step) end
|
function VolumeSlider:handle_wheel_up() self:set_volume(state.volume + options.volume_step) end
|
||||||
function VolumeSlider:on_wheel_down() self:set_volume(state.volume - options.volume_step) end
|
function VolumeSlider:handle_wheel_down() self:set_volume(state.volume - options.volume_step) end
|
||||||
|
|
||||||
function VolumeSlider:render()
|
function VolumeSlider:render()
|
||||||
local visibility = self:get_visibility()
|
local visibility = self:get_visibility()
|
||||||
@@ -77,6 +73,19 @@ function VolumeSlider:render()
|
|||||||
|
|
||||||
if width <= 0 or height <= 0 or visibility <= 0 then return end
|
if width <= 0 or height <= 0 or visibility <= 0 then return end
|
||||||
|
|
||||||
|
if self.proximity_raw == 0 then
|
||||||
|
cursor.on_primary_down = function()
|
||||||
|
self.pressed = true
|
||||||
|
self:set_from_cursor()
|
||||||
|
cursor.on_primary_up = function() self.pressed = false 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.pressed then cursor.on_primary_up = function()
|
||||||
|
self.pressed = false end
|
||||||
|
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 +
|
local volume_y = self.ay + options.volume_border +
|
||||||
|
@@ -93,6 +93,11 @@ function get_point_to_rectangle_proximity(point, rect)
|
|||||||
return math.sqrt(dx * dx + dy * dy)
|
return math.sqrt(dx * dx + dy * dy)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Call function with args if it exists
|
||||||
|
function call_maybe(fn, ...)
|
||||||
|
if type(fn) == 'function' then fn(...) end
|
||||||
|
end
|
||||||
|
|
||||||
-- Extracts the properties used by property expansion of that string.
|
-- Extracts the properties used by property expansion of that string.
|
||||||
---@param str string
|
---@param str string
|
||||||
---@param res { [string] : boolean } | nil
|
---@param res { [string] : boolean } | nil
|
||||||
@@ -553,6 +558,8 @@ function render()
|
|||||||
if not display.initialized then return end
|
if not display.initialized then return end
|
||||||
state.render_last_time = mp.get_time()
|
state.render_last_time = mp.get_time()
|
||||||
|
|
||||||
|
cursor.reset_handlers()
|
||||||
|
|
||||||
-- Actual rendering
|
-- Actual rendering
|
||||||
local ass = assdraw.ass_new()
|
local ass = assdraw.ass_new()
|
||||||
|
|
||||||
@@ -566,6 +573,8 @@ function render()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
cursor.decide_keybinds()
|
||||||
|
|
||||||
-- submit
|
-- submit
|
||||||
if osd.res_x == display.width and osd.res_y == display.height and osd.data == ass.text then
|
if osd.res_x == display.width and osd.res_y == display.height and osd.data == ass.text then
|
||||||
return
|
return
|
||||||
|
Reference in New Issue
Block a user