History

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.

Guido Cella committed 1 year ago

Commit aa5d37b1 parent 64531af10 files · +230 −2Browse files

Unified · Split

10 files
  1. DOCS/man/mpv.rst +2 −0
  2. DOCS/man/options.rst +4 −0
  3. DOCS/man/positioning.rst +60 −0
  4. options/options.c +2 −0
  5. options/options.h +1 −0
  6. player/core.h +1 −1
  7. player/lua.c +3 −0
  8. player/lua/meson.build +1 −1
  9. player/lua/positioning.lua +155 −0
  10. player/scripting.c +1 −0
DOCS/man/mpv.rst+2−0
@@ -1532,6 +1532,8 @@ works like in older mpv releases: · 1531 unmodified lines
1532 1532
1533.. include:: select.rst1533.. include:: select.rst
1534 1534
1535.. include:: positioning.rst
1536
1535.. include:: lua.rst1537.. include:: lua.rst
1536 1538
1537.. include:: javascript.rst1539.. include:: javascript.rst
DOCS/man/options.rst+4−0
@@ -1067,6 +1067,10 @@ Program Behavior · 1066 unmodified lines
1067 Enable the builtin script that lets you select from lists of items (default:1067 Enable the builtin script that lets you select from lists of items (default:
1068 yes). By default, its keybindings start with the ``g`` key.1068 yes). By default, its keybindings start with the ``g`` key.
1069 1069
1070``--load-positioning=<yes|no>``
1071 Enable the builtin script that provides various keybindings to pan videos
1072 and images (default: yes).
1073
1070``--player-operation-mode=<cplayer|pseudo-gui>``1074``--player-operation-mode=<cplayer|pseudo-gui>``
1071 For enabling "pseudo GUI mode", which means that the defaults for some1075 For enabling "pseudo GUI mode", which means that the defaults for some
1072 options are changed. This option should not normally be used directly, but1076 options are changed. This option should not normally be used directly, but
DOCS/man/positioning.rst+60−0
@@ -0,0 +1,60 @@
1POSITIONING
2===========
3
4This script provides script bindings to pan videos and images. It can be
5disabled using the ``--load-positioning=no`` option.
6
7Script bindings
8---------------
9
10``pan-x <amount>``
11 Adjust ``--video-align-x`` relatively to the OSD width, rather than
12 relatively to the video width like the option. This is useful to pan large
13 images consistently.
14
15 ``amount`` is a number such that an amount of 1 scrolls as much as the OSD
16 width.
17
18``pan-y <amount>``
19 Adjust ``--video-align-y`` relatively to the OSD height, rather than
20 relatively to the video height like the option.
21
22 ``amount`` is a number such that an amount of 1 scrolls as much as the OSD
23 height.
24
25``drag-to-pan``
26 Pan the video while holding a mouse button, keeping the clicked part of the
27 video under the cursor.
28
29``align-to-cursor``
30 Pan through the whole video while holding a mouse button, or after clicking
31 once if ``toggle_align_to_cursor`` is ``yes``.
32
33``cursor-centric-zoom <amount>``
34 Increase ``--video-zoom`` by ``amount`` while keeping the part of the video
35 hovered by the cursor under it, or the average position of touch points if
36 known.
37
38Configuration
39-------------
40
41This script can be customized through a config file
42``script-opts/positioning.conf`` placed in mpv's user directory and through the
43``--script-opts`` command-line option. The configuration syntax is described in
44`mp.options functions`_.
45
46Configurable Options
47~~~~~~~~~~~~~~~~~~~~
48
49``toggle_align_to_cursor``
50 Default: no
51
52 Whether ``align-to-cursor`` requires holding down a mouse button to pan. If
53 ``no``, dragging pans. If ``yes``, clicking the first time makes pan follow
54 the cursor, and clicking a second time disables this.
55
56``suppress_osd``
57 Default: no
58
59 Whether to not print the new value of ``--video-zoom`` when using
60 ``cursor-centric-zoom``.
options/options.c+2−0
@@ -554,6 +554,7 @@ static const m_option_t mp_opts[] = { · 553 unmodified lines
554 OPT_CHOICE(lua_load_auto_profiles, {"no", 0}, {"yes", 1}, {"auto", -1}),554 OPT_CHOICE(lua_load_auto_profiles, {"no", 0}, {"yes", 1}, {"auto", -1}),
555 .flags = UPDATE_BUILTIN_SCRIPTS},555 .flags = UPDATE_BUILTIN_SCRIPTS},
556 {"load-select", OPT_BOOL(lua_load_select), .flags = UPDATE_BUILTIN_SCRIPTS},556 {"load-select", OPT_BOOL(lua_load_select), .flags = UPDATE_BUILTIN_SCRIPTS},
557 {"load-positioning", OPT_BOOL(lua_load_positioning), .flags = UPDATE_BUILTIN_SCRIPTS},
557#endif558#endif
558 559
559// ------------------------- stream options --------------------560// ------------------------- stream options --------------------
@@ -986,6 +987,7 @@ static const struct MPOpts mp_default_opts = { · 426 unmodified lines
986 .lua_load_console = true,987 .lua_load_console = true,
987 .lua_load_auto_profiles = -1,988 .lua_load_auto_profiles = -1,
988 .lua_load_select = true,989 .lua_load_select = true,
990 .lua_load_positioning = true,
989#endif991#endif
990 .auto_load_scripts = true,992 .auto_load_scripts = true,
991 .loop_times = 1,993 .loop_times = 1,
options/options.h+1−0
@@ -174,6 +174,7 @@ typedef struct MPOpts { · 173 unmodified lines
174 bool lua_load_console;174 bool lua_load_console;
175 int lua_load_auto_profiles;175 int lua_load_auto_profiles;
176 bool lua_load_select;176 bool lua_load_select;
177 bool lua_load_positioning;
177 178
178 bool auto_load_scripts;179 bool auto_load_scripts;
179 180
player/core.h+1−1
@@ -444,7 +444,7 @@ typedef struct MPContext { · 443 unmodified lines
444 444
445 struct mp_ipc_ctx *ipc_ctx;445 struct mp_ipc_ctx *ipc_ctx;
446 446
447 int64_t builtin_script_ids[6];447 int64_t builtin_script_ids[7];
448 448
449 mp_mutex abort_lock;449 mp_mutex abort_lock;
450 450
player/lua.c+3−0
@@ -84,6 +84,9 @@ static const char * const builtin_lua_scripts[][2] = { · 83 unmodified lines
84 },84 },
85 {"@select.lua",85 {"@select.lua",
86# include "player/lua/select.lua.inc"86# include "player/lua/select.lua.inc"
87 },
88 {"@positioning.lua",
89# include "player/lua/positioning.lua.inc"
87 },90 },
88 {0}91 {0}
89};92};
player/lua/meson.build+1−1
@@ -1,6 +1,6 @@
1lua_files = ['defaults.lua', 'assdraw.lua', 'options.lua', 'osc.lua',1lua_files = ['defaults.lua', 'assdraw.lua', 'options.lua', 'osc.lua',
2 'ytdl_hook.lua', 'stats.lua', 'console.lua', 'auto_profiles.lua',2 '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']
4foreach file: lua_files4foreach file: lua_files
5 lua_file = custom_target(file,5 lua_file = custom_target(file,
6 input: file,6 input: file,
player/lua/positioning.lua+155−0
@@ -0,0 +1,155 @@
1--[[
2This file is part of mpv.
3
4mpv is free software; you can redistribute it and/or
5modify it under the terms of the GNU Lesser General Public
6License as published by the Free Software Foundation; either
7version 2.1 of the License, or (at your option) any later version.
8
9mpv is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU Lesser General Public License for more details.
13
14You should have received a copy of the GNU Lesser General Public
15License along with mpv. If not, see <http://www.gnu.org/licenses/>.
16]]
17
18local options = {
19 toggle_align_to_cursor = false,
20 suppress_osd = false,
21}
22
23require "mp.options".read_options(options, nil, function () end)
24
25local function clamp(value, min, max)
26 return math.min(math.max(value, min), max)
27end
28
29mp.add_key_binding(nil, "pan-x", function (t)
30 if t.event == "up" then
31 return
32 end
33
34 local dims = mp.get_property_native("osd-dimensions")
35 local width = dims.w - dims.ml - dims.mr
36 -- 1 video-align shifts the OSD by (width - osd-width) / 2 pixels, so the
37 -- equation to find how much video-align to add to offset the OSD by
38 -- osd-width is:
39 -- x/1 = osd-width / ((width - osd-width) / 2)
40 local amount = t.arg * t.scale * 2 * dims.w / (width - dims.w)
41 mp.commandv("add", "video-align-x", clamp(amount, -2, 2))
42end, { complex = true, scalable = true })
43
44mp.add_key_binding(nil, "pan-y", function (t)
45 if t.event == "up" then
46 return
47 end
48
49 local dims = mp.get_property_native("osd-dimensions")
50 local height = dims.h - dims.mt - dims.mb
51 local amount = t.arg * t.scale * 2 * dims.h / (height - dims.h)
52 mp.commandv("add", "video-align-y", clamp(amount, -2, 2))
53end, { complex = true, scalable = true })
54
55mp.add_key_binding(nil, "drag-to-pan", function (t)
56 if t.event == "up" then
57 mp.remove_key_binding("drag-to-pan-mouse-move")
58 return
59 end
60
61 local dims = mp.get_property_native("osd-dimensions")
62 local old_mouse_pos = mp.get_property_native("mouse-pos")
63 local old_align_x = mp.get_property_native("video-align-x")
64 local old_align_y = mp.get_property_native("video-align-y")
65
66 mp.add_forced_key_binding("MOUSE_MOVE", "drag-to-pan-mouse-move", function ()
67 local mouse_pos = mp.get_property_native("mouse-pos")
68 -- 1 video-align shifts the OSD by (dimension - osd_dimension) / 2 pixels,
69 -- so the equation to find how much video-align to add to offset the OSD
70 -- by the difference in mouse position is:
71 -- x/1 = (mouse_pos - old_mouse_pos) / ((dimension - osd_dimension) / 2)
72 local align = old_align_x + 2 * (mouse_pos.x - old_mouse_pos.x)
73 / (dims.ml + dims.mr)
74 mp.set_property("video-align-x", clamp(align, -1, 1))
75 align = old_align_y + 2 * (mouse_pos.y - old_mouse_pos.y)
76 / (dims.mt + dims.mb)
77 mp.set_property("video-align-y", clamp(align, -1, 1))
78 end)
79end, { complex = true })
80
81
82local align_to_cursor_bound = false
83
84local function align_to_cursor(_, mouse_pos)
85 local dims = mp.get_property_native("osd-dimensions")
86 mp.set_property("video-align-x", (mouse_pos.x * 2 - dims.w) / dims.w)
87 mp.set_property("video-align-y", (mouse_pos.y * 2 - dims.h) / dims.h)
88end
89
90mp.add_key_binding(nil, "align-to-cursor", function (t)
91 if options.toggle_align_to_cursor == false then
92 if t.event == "down" then
93 mp.observe_property("mouse-pos", "native", align_to_cursor)
94 else
95 mp.unobserve_property(align_to_cursor)
96 end
97
98 return
99 end
100
101 if t.event ~= "up" then
102 return
103 end
104
105 if align_to_cursor_bound then
106 mp.unobserve_property(align_to_cursor)
107 else
108 mp.observe_property("mouse-pos", "native", align_to_cursor)
109 end
110 align_to_cursor_bound = not align_to_cursor_bound
111end, { complex = true })
112
113
114mp.add_key_binding(nil, "cursor-centric-zoom", function (t)
115 local amount = t.arg * t.scale
116
117 local command = (options.suppress_osd and "no-osd " or "") ..
118 "add video-zoom " .. amount .. ";"
119
120 local x, y
121 local touch_positions = mp.get_property_native("touch-pos")
122 if touch_positions[1] then
123 for _, position in pairs(touch_positions) do
124 x = x + position.x
125 y = y + position.y
126 end
127 x = x / #touch_positions
128 y = y / #touch_positions
129 else
130 local mouse_pos = mp.get_property_native("mouse-pos")
131 x = mouse_pos.x
132 y = mouse_pos.y
133 end
134
135 local dims = mp.get_property_native("osd-dimensions")
136 local width = (dims.w - dims.ml - dims.mr) * 2^amount
137 local height = (dims.h - dims.mt - dims.mb) * 2^amount
138
139 local old_cursor_ml = dims.ml - x
140 local cursor_ml = old_cursor_ml * 2^amount
141 local ml = cursor_ml + x
142 -- video/out/aspect.c:src_dst_split_scaling() defines ml as:
143 -- ml = (osd-width - width) * (video-align-x + 1) / 2 + pan-x * width
144 -- So video-align-x is:
145 local align = 2 * (ml - mp.get_property_native("video-pan-x") * width)
146 / (dims.w - width) - 1
147 command = command .. "no-osd set video-align-x " .. clamp(align, -1, 1) .. ";"
148
149 local mt = (dims.mt - y) * 2^amount + y
150 align = 2 * (mt - mp.get_property_native("video-pan-y") * height)
151 / (dims.h - height) - 1
152 command = command .. "no-osd set video-align-y " .. clamp(align, -1, 1)
153
154 mp.command(command)
155end, { complex = true, scalable = true })
player/scripting.c+1−0
@@ -263,6 +263,7 @@ void mp_load_builtin_scripts(struct MPContext *mpctx) · 262 unmodified lines
263 load_builtin_script(mpctx, 4, mpctx->opts->lua_load_auto_profiles,263 load_builtin_script(mpctx, 4, mpctx->opts->lua_load_auto_profiles,
264 "@auto_profiles.lua");264 "@auto_profiles.lua");
265 load_builtin_script(mpctx, 5, mpctx->opts->lua_load_select, "@select.lua");265 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");
266}267}
267 268
268bool mp_load_scripts(struct MPContext *mpctx)269bool mp_load_scripts(struct MPContext *mpctx)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t