Skip to content

Commit f0b043f

Browse files
committed
positioning.lua: add this script
This script provides script messages and bindings to pan videos and images, making mpv a better image viewer out of the box.
1 parent 1c3f092 commit f0b043f

File tree

10 files changed

+170
-2
lines changed

10 files changed

+170
-2
lines changed

DOCS/man/mpv.rst

+2
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,8 @@ works like in older mpv releases:
14611461

14621462
.. include:: console.rst
14631463

1464+
.. include:: positioning.rst
1465+
14641466
.. include:: lua.rst
14651467

14661468
.. include:: javascript.rst

DOCS/man/options.rst

+4
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,10 @@ Program Behavior
10671067
Enable the builtin script that lets you select from lists of items (default:
10681068
yes). By default, its keybindings start with the ``g`` key.
10691069

1070+
``--load-positioning=<yes|no>``
1071+
Enable the builtin script that provides various keybindings to pan videos
1072+
and images (default: yes).
1073+
10701074
``--player-operation-mode=<cplayer|pseudo-gui>``
10711075
For enabling "pseudo GUI mode", which means that the defaults for some
10721076
options are changed. This option should not normally be used directly, but

DOCS/man/positioning.rst

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
POSITIONING
2+
===========
3+
4+
This script provides key bindings to pan videos and images.
5+
6+
Script messages and bindings
7+
----------------------------
8+
9+
``pan <axis> <amount>``
10+
Adjust ``--video-align-x`` or ``--video-align-y`` relatively to the OSD
11+
sizes, rather than relatively to the video sizes like the options. This is
12+
useful to pan large images consistently.
13+
14+
``axis`` can be ``x`` or ``y``, and ``amount`` is a number such that an
15+
amount of 1 scrolls as much as the OSD width or height.
16+
17+
``drag-to-pan``
18+
Pan the video while holding a mouse button, relatively to the clicked point in
19+
the OSD.
20+
21+
``align-to-cursor``
22+
Pan the video while holding a mouse button, relatively to the whole video.
23+
24+
``cursor-centric-zoom <zoom>``
25+
Increase ``--video-zoom`` by ``zoom`` and adjust ``--video-align-x`` and
26+
``--video-align-y`` to shift the OSD towards the position hovered by the
27+
cursor, or the average position of touch points if known.
28+
29+
Configurable Options
30+
~~~~~~~~~~~~~~~~~~~~
31+
32+
``suppress_osd``
33+
Default: no
34+
35+
Whether to not print the new value of ``--video-zoom`` when using
36+
``cursor-centric-zoom``.

options/options.c

+2
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ static const m_option_t mp_opts[] = {
588588
OPT_CHOICE(lua_load_auto_profiles, {"no", 0}, {"yes", 1}, {"auto", -1}),
589589
.flags = UPDATE_BUILTIN_SCRIPTS},
590590
{"load-select", OPT_BOOL(lua_load_select), .flags = UPDATE_BUILTIN_SCRIPTS},
591+
{"load-positioning", OPT_BOOL(lua_load_positioning), .flags = UPDATE_BUILTIN_SCRIPTS},
591592
#endif
592593

593594
// ------------------------- stream options --------------------
@@ -1009,6 +1010,7 @@ static const struct MPOpts mp_default_opts = {
10091010
.lua_load_console = true,
10101011
.lua_load_auto_profiles = -1,
10111012
.lua_load_select = true,
1013+
.lua_load_positioning = true,
10121014
#endif
10131015
.auto_load_scripts = true,
10141016
.loop_times = 1,

options/options.h

+1
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ typedef struct MPOpts {
186186
bool lua_load_console;
187187
int lua_load_auto_profiles;
188188
bool lua_load_select;
189+
bool lua_load_positioning;
189190

190191
bool auto_load_scripts;
191192

player/core.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ typedef struct MPContext {
440440

441441
struct mp_ipc_ctx *ipc_ctx;
442442

443-
int64_t builtin_script_ids[6];
443+
int64_t builtin_script_ids[7];
444444

445445
mp_mutex abort_lock;
446446

player/lua.c

+3
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ static const char * const builtin_lua_scripts[][2] = {
8484
},
8585
{"@select.lua",
8686
# include "player/lua/select.lua.inc"
87+
},
88+
{"@positioning.lua",
89+
# include "player/lua/positioning.lua.inc"
8790
},
8891
{0}
8992
};

player/lua/meson.build

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
lua_files = ['defaults.lua', 'assdraw.lua', 'options.lua', 'osc.lua',
22
'ytdl_hook.lua', 'stats.lua', 'console.lua', 'auto_profiles.lua',
3-
'input.lua', 'fzy.lua', 'select.lua']
3+
'input.lua', 'fzy.lua', 'select.lua', 'positioning.lua']
44
foreach file: lua_files
55
lua_file = custom_target(file,
66
input: file,

player/lua/positioning.lua

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
--[[
2+
This file is part of mpv.
3+
4+
mpv is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU Lesser General Public
6+
License as published by the Free Software Foundation; either
7+
version 2.1 of the License, or (at your option) any later version.
8+
9+
mpv is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public
15+
License along with mpv. If not, see <http://www.gnu.org/licenses/>.
16+
]]
17+
18+
local options = {
19+
suppress_osd = false,
20+
}
21+
22+
require "mp.options".read_options(options)
23+
24+
mp.register_script_message("pan", function (axis, amount)
25+
local dims = mp.get_property_native("osd-dimensions")
26+
local dimension = axis == "x" and dims.w - dims.ml - dims.mr or dims.h - dims.mt - dims.mb
27+
local osd_dimension = axis == "x" and dims.w or dims.h
28+
-- 1 video-align shifts the OSD by (dimension - osd_dimension) / 2 pixels,
29+
-- so the equation to find how much video-align to add to offset the OSD by
30+
-- osd_dimension is:
31+
-- x/1 = osd_dimension / ((dimension - osd_dimension) / 2)
32+
if dimension ~= osd_dimension then
33+
mp.commandv("add", "video-align-" .. axis,
34+
amount * 2 * osd_dimension / (dimension - osd_dimension))
35+
end
36+
end)
37+
38+
mp.add_key_binding(nil, "drag-to-pan", function (t)
39+
if t.event == "up" then
40+
mp.remove_key_binding("drag-to-pan-mouse-move")
41+
return
42+
end
43+
44+
local dims = mp.get_property_native("osd-dimensions")
45+
local old_mouse_pos = mp.get_property_native("mouse-pos")
46+
local old_align_x = mp.get_property_native("video-align-x")
47+
local old_align_y = mp.get_property_native("video-align-y")
48+
49+
mp.add_forced_key_binding("MOUSE_MOVE", "drag-to-pan-mouse-move", function()
50+
local mouse_pos = mp.get_property_native("mouse-pos")
51+
-- 1 video-align shifts the OSD by (dimension - osd_dimension) / 2 pixels,
52+
-- so the equation to find how much video-align to add to offset the OSD
53+
-- by the difference in mouse position is:
54+
-- x/1 = (mouse_pos - old_mouse_pos) / ((dimension - osd_dimension) / 2)
55+
local align = old_align_x + 2 * (mouse_pos.x - old_mouse_pos.x)
56+
/ (dims.ml + dims.mr)
57+
mp.set_property("video-align-x", math.min(1, math.max(align, -1)))
58+
align = old_align_y + 2 * (mouse_pos.y - old_mouse_pos.y)
59+
/ (dims.mt + dims.mb)
60+
mp.set_property("video-align-y", math.min(1, math.max(align, -1)))
61+
end)
62+
end, { complex = true })
63+
64+
mp.add_key_binding(nil, "align-to-cursor", function (t)
65+
if t.event == "up" then
66+
mp.remove_key_binding("align-to-cursor-mouse-move")
67+
return
68+
end
69+
70+
local dims = mp.get_property_native("osd-dimensions")
71+
mp.add_forced_key_binding("MOUSE_MOVE", "align-to-cursor-mouse-move", function()
72+
local mouse_pos = mp.get_property_native("mouse-pos")
73+
mp.set_property("video-align-x", (mouse_pos.x * 2 - dims.w) / dims.w)
74+
mp.set_property("video-align-y", (mouse_pos.y * 2 - dims.h) / dims.h)
75+
end)
76+
end, { complex = true })
77+
78+
mp.register_script_message("cursor-centric-zoom", function (amount)
79+
local command = (options.suppress_osd and "no-osd " or "") ..
80+
"add video-zoom " .. amount .. ";"
81+
82+
local x, y
83+
local touch_positions = mp.get_property_native("touch-pos")
84+
if next(touch_positions) then
85+
for _, position in pairs(touch_positions) do
86+
x = x + position.x
87+
y = y + position.y
88+
end
89+
x = x / #touch_positions
90+
y = y / #touch_positions
91+
else
92+
local mouse_pos = mp.get_property_native("mouse-pos")
93+
x = mouse_pos.x
94+
y = mouse_pos.y
95+
end
96+
97+
local dims = mp.get_property_native("osd-dimensions")
98+
local width = (dims.w - dims.ml - dims.mr) * 2^amount
99+
local height = (dims.h - dims.mt - dims.mb) * 2^amount
100+
101+
local old_cursor_ml = dims.ml - x
102+
local cursor_ml = old_cursor_ml * 2^amount
103+
local ml = cursor_ml + x
104+
-- video/out/aspect.c:src_dst_split_scaling() defines ml as:
105+
-- ml = (osd-width - width) * (video-align-x + 1) / 2 + pan-x * width
106+
-- So video-align-x is:
107+
local align = 2 * (ml - mp.get_property_native("video-pan-x") * width)
108+
/ (dims.w - width) - 1
109+
command = command .. "no-osd set video-align-x " ..
110+
math.min(1, math.max(align, -1)) .. ";"
111+
112+
local mt = (dims.mt - y) * 2^amount + y
113+
align = 2 * (mt - mp.get_property_native("video-pan-y") * height)
114+
/ (dims.h - height) - 1
115+
command = command .. "no-osd set video-align-y " ..
116+
math.min(1, math.max(align, -1))
117+
118+
mp.command(command)
119+
end)

player/scripting.c

+1
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ void mp_load_builtin_scripts(struct MPContext *mpctx)
263263
load_builtin_script(mpctx, 4, mpctx->opts->lua_load_auto_profiles,
264264
"@auto_profiles.lua");
265265
load_builtin_script(mpctx, 5, mpctx->opts->lua_load_select, "@select.lua");
266+
load_builtin_script(mpctx, 6, mpctx->opts->lua_load_positioning, "@positioning.lua");
266267
}
267268

268269
bool mp_load_scripts(struct MPContext *mpctx)

0 commit comments

Comments
 (0)