Skip to content

Commit 85a3d2a

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 85a3d2a

File tree

10 files changed

+182
-2
lines changed

10 files changed

+182
-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+
``osd-relative-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

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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("osd-relative-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+
if dims.ml + dims.mr < 0 then
56+
local align = old_align_x + 2 * (mouse_pos.x - old_mouse_pos.x)
57+
/ (dims.ml + dims.mr)
58+
mp.set_property("video-align-x", math.min(1, math.max(align, -1)))
59+
end
60+
if dims.mt + dims.mb < 0 then
61+
local align = old_align_y + 2 * (mouse_pos.y - old_mouse_pos.y)
62+
/ (dims.mt + dims.mb)
63+
mp.set_property("video-align-y", math.min(1, math.max(align, -1)))
64+
end
65+
end)
66+
end, { complex = true })
67+
68+
mp.add_key_binding(nil, "align-to-cursor", function (t)
69+
if t.event == "up" then
70+
mp.remove_key_binding("align-to-cursor-mouse-move")
71+
return
72+
end
73+
74+
local dims = mp.get_property_native("osd-dimensions")
75+
mp.add_forced_key_binding("MOUSE_MOVE", "align-to-cursor-mouse-move", function()
76+
local mouse_pos = mp.get_property_native("mouse-pos")
77+
if dims.ml + dims.mr < 0 then
78+
mp.set_property("video-align-x", (mouse_pos.x * 2 - dims.w) / dims.w)
79+
end
80+
if dims.mt + dims.mb < 0 then
81+
mp.set_property("video-align-y", (mouse_pos.y * 2 - dims.h) / dims.h)
82+
end
83+
end)
84+
end, { complex = true })
85+
86+
mp.register_script_message("cursor-centric-zoom", function (amount)
87+
local command = (options.suppress_osd and "no-osd " or "") ..
88+
"add video-zoom " .. amount .. ";"
89+
90+
local x, y
91+
local touch_positions = mp.get_property_native("touch-pos")
92+
if next(touch_positions) then
93+
for _, position in pairs(touch_positions) do
94+
x = x + position.x
95+
y = y + position.y
96+
end
97+
x = x / #touch_positions
98+
y = y / #touch_positions
99+
else
100+
local mouse_pos = mp.get_property_native("mouse-pos")
101+
x = mouse_pos.x
102+
y = mouse_pos.y
103+
end
104+
105+
local dims = mp.get_property_native("osd-dimensions")
106+
local width = (dims.w - dims.ml - dims.mr) * 2^amount
107+
local height = (dims.h - dims.mt - dims.mb) * 2^amount
108+
109+
if width > dims.w then
110+
local old_cursor_ml = dims.ml - x
111+
local cursor_ml = old_cursor_ml * 2^amount
112+
local ml = cursor_ml + x
113+
-- video/out/aspect.c:src_dst_split_scaling() defines ml as:
114+
-- ml = (osd-width - width) * (video-align-x + 1) / 2 + pan-x * width
115+
-- So video-align-x is:
116+
local align = 2 * (ml - mp.get_property_native("video-pan-x") * width)
117+
/ (dims.w - width) - 1
118+
command = command .. "no-osd set video-align-x " ..
119+
math.min(1, math.max(align, -1)) .. ";"
120+
end
121+
122+
if height > dims.h then
123+
local mt = (dims.mt - y) * 2^amount + y
124+
local align = 2 * (mt - mp.get_property_native("video-pan-y") * height)
125+
/ (dims.h - height) - 1
126+
command = command .. "no-osd set video-align-y " ..
127+
math.min(1, math.max(align, -1))
128+
end
129+
130+
mp.command(command)
131+
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)