positioning.lua: add this script

This script provides script bindings to pan videos and images, making
mpv a better image viewer out of the box.

Fixes #3038, fixes #15020.
This commit is contained in:
Guido Cella
2024-11-16 14:18:09 +01:00
committed by Kacper Michajłow
parent 64531af454
commit aa5d37bc8e
10 changed files with 230 additions and 2 deletions
+2
View File
@@ -1532,6 +1532,8 @@ works like in older mpv releases:
.. include:: select.rst
.. include:: positioning.rst
.. include:: lua.rst
.. include:: javascript.rst
+4
View File
@@ -1067,6 +1067,10 @@ Program Behavior
Enable the builtin script that lets you select from lists of items (default:
yes). By default, its keybindings start with the ``g`` key.
``--load-positioning=<yes|no>``
Enable the builtin script that provides various keybindings to pan videos
and images (default: yes).
``--player-operation-mode=<cplayer|pseudo-gui>``
For enabling "pseudo GUI mode", which means that the defaults for some
options are changed. This option should not normally be used directly, but
+60
View File
@@ -0,0 +1,60 @@
POSITIONING
===========
This script provides script bindings to pan videos and images. It can be
disabled using the ``--load-positioning=no`` option.
Script bindings
---------------
``pan-x <amount>``
Adjust ``--video-align-x`` relatively to the OSD width, rather than
relatively to the video width like the option. This is useful to pan large
images consistently.
``amount`` is a number such that an amount of 1 scrolls as much as the OSD
width.
``pan-y <amount>``
Adjust ``--video-align-y`` relatively to the OSD height, rather than
relatively to the video height like the option.
``amount`` is a number such that an amount of 1 scrolls as much as the OSD
height.
``drag-to-pan``
Pan the video while holding a mouse button, keeping the clicked part of the
video under the cursor.
``align-to-cursor``
Pan through the whole video while holding a mouse button, or after clicking
once if ``toggle_align_to_cursor`` is ``yes``.
``cursor-centric-zoom <amount>``
Increase ``--video-zoom`` by ``amount`` while keeping the part of the video
hovered by the cursor under it, or the average position of touch points if
known.
Configuration
-------------
This script can be customized through a config file
``script-opts/positioning.conf`` placed in mpv's user directory and through the
``--script-opts`` command-line option. The configuration syntax is described in
`mp.options functions`_.
Configurable Options
~~~~~~~~~~~~~~~~~~~~
``toggle_align_to_cursor``
Default: no
Whether ``align-to-cursor`` requires holding down a mouse button to pan. If
``no``, dragging pans. If ``yes``, clicking the first time makes pan follow
the cursor, and clicking a second time disables this.
``suppress_osd``
Default: no
Whether to not print the new value of ``--video-zoom`` when using
``cursor-centric-zoom``.
+2
View File
@@ -554,6 +554,7 @@ static const m_option_t mp_opts[] = {
OPT_CHOICE(lua_load_auto_profiles, {"no", 0}, {"yes", 1}, {"auto", -1}),
.flags = UPDATE_BUILTIN_SCRIPTS},
{"load-select", OPT_BOOL(lua_load_select), .flags = UPDATE_BUILTIN_SCRIPTS},
{"load-positioning", OPT_BOOL(lua_load_positioning), .flags = UPDATE_BUILTIN_SCRIPTS},
#endif
// ------------------------- stream options --------------------
@@ -986,6 +987,7 @@ static const struct MPOpts mp_default_opts = {
.lua_load_console = true,
.lua_load_auto_profiles = -1,
.lua_load_select = true,
.lua_load_positioning = true,
#endif
.auto_load_scripts = true,
.loop_times = 1,
+1
View File
@@ -174,6 +174,7 @@ typedef struct MPOpts {
bool lua_load_console;
int lua_load_auto_profiles;
bool lua_load_select;
bool lua_load_positioning;
bool auto_load_scripts;
+1 -1
View File
@@ -444,7 +444,7 @@ typedef struct MPContext {
struct mp_ipc_ctx *ipc_ctx;
int64_t builtin_script_ids[6];
int64_t builtin_script_ids[7];
mp_mutex abort_lock;
+3
View File
@@ -84,6 +84,9 @@ static const char * const builtin_lua_scripts[][2] = {
},
{"@select.lua",
# include "player/lua/select.lua.inc"
},
{"@positioning.lua",
# include "player/lua/positioning.lua.inc"
},
{0}
};
+1 -1
View File
@@ -1,6 +1,6 @@
lua_files = ['defaults.lua', 'assdraw.lua', 'options.lua', 'osc.lua',
'ytdl_hook.lua', 'stats.lua', 'console.lua', 'auto_profiles.lua',
'input.lua', 'fzy.lua', 'select.lua']
'input.lua', 'fzy.lua', 'select.lua', 'positioning.lua']
foreach file: lua_files
lua_file = custom_target(file,
input: file,
+155
View File
@@ -0,0 +1,155 @@
--[[
This file is part of mpv.
mpv is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
mpv is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with mpv. If not, see <http://www.gnu.org/licenses/>.
]]
local options = {
toggle_align_to_cursor = false,
suppress_osd = false,
}
require "mp.options".read_options(options, nil, function () end)
local function clamp(value, min, max)
return math.min(math.max(value, min), max)
end
mp.add_key_binding(nil, "pan-x", function (t)
if t.event == "up" then
return
end
local dims = mp.get_property_native("osd-dimensions")
local width = dims.w - dims.ml - dims.mr
-- 1 video-align shifts the OSD by (width - osd-width) / 2 pixels, so the
-- equation to find how much video-align to add to offset the OSD by
-- osd-width is:
-- x/1 = osd-width / ((width - osd-width) / 2)
local amount = t.arg * t.scale * 2 * dims.w / (width - dims.w)
mp.commandv("add", "video-align-x", clamp(amount, -2, 2))
end, { complex = true, scalable = true })
mp.add_key_binding(nil, "pan-y", function (t)
if t.event == "up" then
return
end
local dims = mp.get_property_native("osd-dimensions")
local height = dims.h - dims.mt - dims.mb
local amount = t.arg * t.scale * 2 * dims.h / (height - dims.h)
mp.commandv("add", "video-align-y", clamp(amount, -2, 2))
end, { complex = true, scalable = true })
mp.add_key_binding(nil, "drag-to-pan", function (t)
if t.event == "up" then
mp.remove_key_binding("drag-to-pan-mouse-move")
return
end
local dims = mp.get_property_native("osd-dimensions")
local old_mouse_pos = mp.get_property_native("mouse-pos")
local old_align_x = mp.get_property_native("video-align-x")
local old_align_y = mp.get_property_native("video-align-y")
mp.add_forced_key_binding("MOUSE_MOVE", "drag-to-pan-mouse-move", function ()
local mouse_pos = mp.get_property_native("mouse-pos")
-- 1 video-align shifts the OSD by (dimension - osd_dimension) / 2 pixels,
-- so the equation to find how much video-align to add to offset the OSD
-- by the difference in mouse position is:
-- x/1 = (mouse_pos - old_mouse_pos) / ((dimension - osd_dimension) / 2)
local align = old_align_x + 2 * (mouse_pos.x - old_mouse_pos.x)
/ (dims.ml + dims.mr)
mp.set_property("video-align-x", clamp(align, -1, 1))
align = old_align_y + 2 * (mouse_pos.y - old_mouse_pos.y)
/ (dims.mt + dims.mb)
mp.set_property("video-align-y", clamp(align, -1, 1))
end)
end, { complex = true })
local align_to_cursor_bound = false
local function align_to_cursor(_, mouse_pos)
local dims = mp.get_property_native("osd-dimensions")
mp.set_property("video-align-x", (mouse_pos.x * 2 - dims.w) / dims.w)
mp.set_property("video-align-y", (mouse_pos.y * 2 - dims.h) / dims.h)
end
mp.add_key_binding(nil, "align-to-cursor", function (t)
if options.toggle_align_to_cursor == false then
if t.event == "down" then
mp.observe_property("mouse-pos", "native", align_to_cursor)
else
mp.unobserve_property(align_to_cursor)
end
return
end
if t.event ~= "up" then
return
end
if align_to_cursor_bound then
mp.unobserve_property(align_to_cursor)
else
mp.observe_property("mouse-pos", "native", align_to_cursor)
end
align_to_cursor_bound = not align_to_cursor_bound
end, { complex = true })
mp.add_key_binding(nil, "cursor-centric-zoom", function (t)
local amount = t.arg * t.scale
local command = (options.suppress_osd and "no-osd " or "") ..
"add video-zoom " .. amount .. ";"
local x, y
local touch_positions = mp.get_property_native("touch-pos")
if touch_positions[1] then
for _, position in pairs(touch_positions) do
x = x + position.x
y = y + position.y
end
x = x / #touch_positions
y = y / #touch_positions
else
local mouse_pos = mp.get_property_native("mouse-pos")
x = mouse_pos.x
y = mouse_pos.y
end
local dims = mp.get_property_native("osd-dimensions")
local width = (dims.w - dims.ml - dims.mr) * 2^amount
local height = (dims.h - dims.mt - dims.mb) * 2^amount
local old_cursor_ml = dims.ml - x
local cursor_ml = old_cursor_ml * 2^amount
local ml = cursor_ml + x
-- video/out/aspect.c:src_dst_split_scaling() defines ml as:
-- ml = (osd-width - width) * (video-align-x + 1) / 2 + pan-x * width
-- So video-align-x is:
local align = 2 * (ml - mp.get_property_native("video-pan-x") * width)
/ (dims.w - width) - 1
command = command .. "no-osd set video-align-x " .. clamp(align, -1, 1) .. ";"
local mt = (dims.mt - y) * 2^amount + y
align = 2 * (mt - mp.get_property_native("video-pan-y") * height)
/ (dims.h - height) - 1
command = command .. "no-osd set video-align-y " .. clamp(align, -1, 1)
mp.command(command)
end, { complex = true, scalable = true })
+1
View File
@@ -263,6 +263,7 @@ void mp_load_builtin_scripts(struct MPContext *mpctx)
load_builtin_script(mpctx, 4, mpctx->opts->lua_load_auto_profiles,
"@auto_profiles.lua");
load_builtin_script(mpctx, 5, mpctx->opts->lua_load_select, "@select.lua");
load_builtin_script(mpctx, 6, mpctx->opts->lua_load_positioning, "@positioning.lua");
}
bool mp_load_scripts(struct MPContext *mpctx)