add mvi not as submodule
This commit is contained in:
parent
49ebf8a1e1
commit
e6714de34b
16 changed files with 1547 additions and 0 deletions
87
.config/mvi/README.md
Normal file
87
.config/mvi/README.md
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
This repository aggregates configurations, scripts and tips for using [mpv](https://github.com/mpv-player/mpv) as an image viewer. The affectionate nickname `mvi` is given to mpv in such case.
|
||||||
|
|
||||||
|
This README assumes basic familiarity with mpv and its configuration. The information here should be platform-agnostic for the most part.
|
||||||
|
|
||||||
|
[](https://vimeo.com/249231479)
|
||||||
|
|
||||||
|
# Why?
|
||||||
|
|
||||||
|
mpv is a competent video player and sufficiently lightweight to use comfortably to view images. It features advanced scaling algorithms and color management, which are key features in an image viewer.
|
||||||
|
It is also very extensible which allows us to compensate for some missing image viewer features easily.
|
||||||
|
It won't compete with `feh` or the likes when it comes to size or startup time, but it is still plenty fast.
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
There are several options for making an mvi configuration.
|
||||||
|
* Use the normal mpv config, and apply changes at runtime. You will need `detect-image.lua` and use [input sections](https://mpv.io/manual/master/#input-sections) and [profiles](https://mpv.io/manual/master/#profiles) to make this work.
|
||||||
|
* Or create an entirely separate `~/.config/mvi/` directory and use the alias `alias mvi='mpv --config-dir=$HOME/.config/mvi'`
|
||||||
|
|
||||||
|
The first option is more complex, the second results in essentially two separate programs.
|
||||||
|
|
||||||
|
The examples `mpv.conf` and `input.conf` in this repository are commented to highlight (un)desirable settings.
|
||||||
|
|
||||||
|
# Scripts
|
||||||
|
|
||||||
|
## image-positioning.lua
|
||||||
|
|
||||||
|
Adds several high-level commands to zoom and pan:
|
||||||
|
|
||||||
|
`drag-to-pan`: pan the image with the cursor, while keeping the same part of the image under the cursor
|
||||||
|
`pan-follows-cursor`: pan the image in the direction of the cursor
|
||||||
|
`cursor-centric-zoom`: (de)zoom the video while keeping the same part of the image under the cursor
|
||||||
|
`align-border`: align the border of the image with the border of the window
|
||||||
|
`pan-image`: pan the image in a direction, optionally ignoring the zoom or forcing the image to stay visible
|
||||||
|
`rotate-video`: rotate the image in 90 degrees increment
|
||||||
|
`reset-pan-if-visible`: reset the pan if the entire image is visible
|
||||||
|
|
||||||
|
There are no default bindings, see [`input.conf`](input.conf#L19-L67) for how to bind them.
|
||||||
|
|
||||||
|
## status-line.lua
|
||||||
|
|
||||||
|
Adds a status line that can show different properties in the corner of the window. By default it shows `filename [positon/total]` in the bottom left.
|
||||||
|
|
||||||
|
Can be activated with the commands `status-line-enable`, `status-line-disable`, `status-line-toggle` and configured through [`status_line.conf`](script-opts/status_line.conf).
|
||||||
|
|
||||||
|
## detect-image.lua
|
||||||
|
|
||||||
|
Allows you to run specific commands when images are being displayed. Does not do anything by default, needs to be configured through [`detect_image.conf`](script-opts/detect_image.conf).
|
||||||
|
|
||||||
|
For example, this makes it possible to setup bindings that are only in effect with images, like so:
|
||||||
|
```
|
||||||
|
command_on_first_image_loaded=enable-section image-viewer
|
||||||
|
command_on_non_image_loaded=disable-section image-viewer
|
||||||
|
```
|
||||||
|
Where the 'image-viewer' bindings are specified like so [`input.conf`](input.conf#L96-L99).
|
||||||
|
|
||||||
|
## minimap.lua
|
||||||
|
|
||||||
|
Adds a minimap that displays the position of the image relative to the view.
|
||||||
|
Can be activated with `minimap-enable`, `minimap-disable`, `minimap-toggle` and configured through [`minimap.conf`](script-opts/minimap.conf).
|
||||||
|
|
||||||
|
## ruler.lua
|
||||||
|
|
||||||
|
Adds a `ruler` command that lets you measure positions, distances and angles in the image.
|
||||||
|
Can be configured through [`ruler.conf`](script-opts/ruler.conf).
|
||||||
|
|
||||||
|
## freeze-window.lua
|
||||||
|
|
||||||
|
By default, mpv automatically resizes the window when the current file changes to fit its size. This script freezes the window so that this does not happen.
|
||||||
|
There is no configuration.
|
||||||
|
|
||||||
|
## Others
|
||||||
|
|
||||||
|
Some other mpv scripts work well with mvi, here are a few (feel free to send a PR for others):
|
||||||
|
|
||||||
|
[playlist-view](https://github.com/occivink/mpv-gallery-view): show all images in a grid view
|
||||||
|
[zones](https://github.com/wiiaboo/mpv-scripts/blob/master/zones.lua): send different commands depending on cursor position
|
||||||
|
[autoload](https://github.com/mpv-player/mpv/blob/master/TOOLS/lua/autoload.lua): automatically load all files in the same directory. Set `videos=no` and `audio=no` in `script-opts/autoload.conf` to only autoload images.
|
||||||
|
[delete-file](https://github.com/zenyd/mpv-scripts#delete-file): delete the current file
|
||||||
|
[mpv_crop_script](https://github.com/TheAMM/mpv_crop_script): featureful screenshot tool
|
||||||
|
[auto-profiles](https://github.com/wiiaboo/mpv-scripts/blob/master/auto-profiles.lua): apply profiles conditionally. Can be used to lower settings with huge images
|
||||||
|
[crop](https://github.com/occivink/mpv-scripts#croplua): simple cropping script
|
||||||
|
[playlist-manager](https://github.com/jonniek/mpv-playlistmanager): playlist management script
|
||||||
|
[blacklist-extensions](https://github.com/occivink/mpv-scripts#blacklist-extensionslua): remove files from the playlist based on their types
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
Thanks to haasn for coming up first with the [image-viewer config](https://gist.github.com/haasn/7919afd765e308fa91cbe19a64631d0f), all the mpv devs and the /mpv/ funposters.
|
||||||
24
.config/mvi/UNLICENSE
Normal file
24
.config/mvi/UNLICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
||||||
105
.config/mvi/input.conf
Normal file
105
.config/mvi/input.conf
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
1 change-list script-opts append image_positioning-drag_to_pan_margin=200
|
||||||
|
2 change-list script-opts append ruler-exit_bindings=8
|
||||||
|
3 change-list script-opts append ruler-line_color=FF
|
||||||
|
4 change-list script-opts append ruler-scale=25
|
||||||
|
5 change-list script-opts append ruler-max_size=20,20
|
||||||
|
|
||||||
|
SPACE repeatable playlist-next
|
||||||
|
alt+SPACE repeatable playlist-prev
|
||||||
|
|
||||||
|
UP ignore
|
||||||
|
DOWN ignore
|
||||||
|
LEFT repeatable playlist-prev
|
||||||
|
RIGHT repeatable playlist-next
|
||||||
|
|
||||||
|
# simple reminder of default bindings
|
||||||
|
#1 add contrast -1
|
||||||
|
#2 add contrast 1
|
||||||
|
#3 add brightness -1
|
||||||
|
#4 add brightness 1
|
||||||
|
#5 add gamma -1
|
||||||
|
#6 add gamma 1
|
||||||
|
#7 add saturation -1
|
||||||
|
#8 add saturation 1
|
||||||
|
|
||||||
|
# mouse-centric bindings
|
||||||
|
MBTN_RIGHT script-binding drag-to-pan
|
||||||
|
MBTN_LEFT script-binding pan-follows-cursor
|
||||||
|
MBTN_LEFT_DBL ignore
|
||||||
|
WHEEL_UP script-message cursor-centric-zoom 0.1
|
||||||
|
WHEEL_DOWN script-message cursor-centric-zoom -0.1
|
||||||
|
|
||||||
|
# panning with the keyboard:
|
||||||
|
# pan-image takes the following arguments
|
||||||
|
# pan-image AXIS AMOUNT ZOOM_INVARIANT IMAGE_CONSTRAINED
|
||||||
|
# ^ ^ ^
|
||||||
|
# x or y | |
|
||||||
|
# | |
|
||||||
|
# if yes, will pan by the same if yes, stops panning if the image
|
||||||
|
# amount regardless of zoom would go outside of the window
|
||||||
|
|
||||||
|
ctrl+down repeatable script-message pan-image y -0.1 yes yes
|
||||||
|
ctrl+up repeatable script-message pan-image y +0.1 yes yes
|
||||||
|
ctrl+right repeatable script-message pan-image x -0.1 yes yes
|
||||||
|
ctrl+left repeatable script-message pan-image x +0.1 yes yes
|
||||||
|
|
||||||
|
# now with more precision
|
||||||
|
alt+down repeatable script-message pan-image y -0.01 yes yes
|
||||||
|
alt+up repeatable script-message pan-image y +0.01 yes yes
|
||||||
|
alt+right repeatable script-message pan-image x -0.01 yes yes
|
||||||
|
alt+left repeatable script-message pan-image x +0.01 yes yes
|
||||||
|
|
||||||
|
# replace at will with h,j,k,l if you prefer vim-style bindings
|
||||||
|
|
||||||
|
# on a trackpad you may want to use these
|
||||||
|
#WHEEL_UP repeatable script-message pan-image y -0.02 yes yes
|
||||||
|
#WHEEL_DOWN repeatable script-message pan-image y +0.02 yes yes
|
||||||
|
#WHEEL_LEFT repeatable script-message pan-image x -0.02 yes yes
|
||||||
|
#WHEEL_RIGHT repeatable script-message pan-image x +0.02 yes yes
|
||||||
|
|
||||||
|
# align the border of the image to the border of the window
|
||||||
|
# align-border takes the following arguments:
|
||||||
|
# align-border ALIGN_X ALIGN_Y
|
||||||
|
# any value for ALIGN_* is accepted, -1 and 1 map to the border of the window
|
||||||
|
ctrl+shift+right script-message align-border -1 ""
|
||||||
|
ctrl+shift+left script-message align-border 1 ""
|
||||||
|
ctrl+shift+down script-message align-border "" -1
|
||||||
|
ctrl+shift+up script-message align-border "" 1
|
||||||
|
|
||||||
|
# reset the image
|
||||||
|
ctrl+0 no-osd set video-pan-x 0; no-osd set video-pan-y 0; no-osd set video-zoom 0
|
||||||
|
|
||||||
|
+ add video-zoom 0.5
|
||||||
|
- add video-zoom -0.5; script-message reset-pan-if-visible
|
||||||
|
= no-osd set video-zoom 0; script-message reset-pan-if-visible
|
||||||
|
|
||||||
|
e script-message equalizer-toggle
|
||||||
|
alt+e script-message equalizer-reset
|
||||||
|
|
||||||
|
h no-osd vf toggle hflip; show-text "Horizontal flip"
|
||||||
|
v no-osd vf toggle vflip; show-text "Vertical flip"
|
||||||
|
|
||||||
|
r script-message rotate-video 90; show-text "Clockwise rotation"
|
||||||
|
R script-message rotate-video -90; show-text "Counter-clockwise rotation"
|
||||||
|
alt+r no-osd set video-rotate 0; show-text "Reset rotation"
|
||||||
|
|
||||||
|
d script-message ruler
|
||||||
|
|
||||||
|
# Toggling between pixel-exact reproduction and interpolation
|
||||||
|
a cycle-values scale nearest ewa_lanczossharp
|
||||||
|
|
||||||
|
# Toggle color management on or off
|
||||||
|
c cycle icc-profile-auto
|
||||||
|
|
||||||
|
# Screenshot of the window output
|
||||||
|
S screenshot window
|
||||||
|
|
||||||
|
# Toggle aspect ratio information on and off
|
||||||
|
A cycle-values video-aspect-override "-1" "no"
|
||||||
|
|
||||||
|
p script-message force-print-filename
|
||||||
|
|
||||||
|
# ADVANCED: you can define bindings that belong to a "section" (named "image-viewer" here) like so:
|
||||||
|
#alt+SPACE {image-viewer} repeatable playlist-prev
|
||||||
|
#SPACE {image-viewer} repeatable playlist-next
|
||||||
|
# to load them conditionally with a command. See scripts-opts/image_viewer.conf for how you can do this
|
||||||
49
.config/mvi/mpv.conf
Normal file
49
.config/mvi/mpv.conf
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
## IMAGE
|
||||||
|
# classic opengl-hq parameter, change at will
|
||||||
|
scale=spline36
|
||||||
|
cscale=spline36
|
||||||
|
dscale=mitchell
|
||||||
|
dither-depth=auto
|
||||||
|
correct-downscaling
|
||||||
|
sigmoid-upscaling
|
||||||
|
# debanding seems rarely useful with images
|
||||||
|
#deband
|
||||||
|
# dark grey background instead of pure black
|
||||||
|
background=color
|
||||||
|
background-color=0.2
|
||||||
|
|
||||||
|
## MISC
|
||||||
|
mute=yes
|
||||||
|
# the osc is mostly useful for videos
|
||||||
|
osc=no
|
||||||
|
# don't try to autoload subtitles or audio files
|
||||||
|
sub-auto=no
|
||||||
|
audio-file-auto=no
|
||||||
|
# get rid of the useless V: 00:00:00 / 00:00:00 line
|
||||||
|
term-status-msg=
|
||||||
|
|
||||||
|
# replace mpv with mvi in the window title
|
||||||
|
title="${?media-title:${media-title}}${!media-title:No file} - mvi"
|
||||||
|
|
||||||
|
# don't slideshow by default
|
||||||
|
image-display-duration=inf
|
||||||
|
# loop files in case of webms or gifs
|
||||||
|
loop-file=inf
|
||||||
|
# and loop the whole playlist
|
||||||
|
loop-playlist=inf
|
||||||
|
|
||||||
|
# you need this if you plan to use drag-to-pan or pan-follows-cursor with MOUSE_LEFT
|
||||||
|
window-dragging=no
|
||||||
|
|
||||||
|
#according to haasn, aspect ratio info for PNG and JPG is "universally bust"
|
||||||
|
[extension.png]
|
||||||
|
video-aspect-override=no
|
||||||
|
|
||||||
|
[extension.jpg]
|
||||||
|
video-aspect-override=no
|
||||||
|
|
||||||
|
[extension.jpeg]
|
||||||
|
profile=extension.jpg
|
||||||
|
|
||||||
|
[silent]
|
||||||
|
msg-level=all=no
|
||||||
17
.config/mvi/script-opts/detect_image.conf
Normal file
17
.config/mvi/script-opts/detect_image.conf
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# commands to execute when a file detected as an image (1 frame, no audio) is loaded or unloaded
|
||||||
|
|
||||||
|
# an image was loaded, and the previous file was not an image (or there was no previous file)
|
||||||
|
command_on_first_image_loaded=
|
||||||
|
# an image was loaded (regardless of what the previous file was)
|
||||||
|
command_on_image_loaded=
|
||||||
|
# a non-image was loaded, and the previous file was an image
|
||||||
|
command_on_non_image_loaded=
|
||||||
|
|
||||||
|
# the purpose of these "hooks" is to let you change bindings, profiles, reset properties...
|
||||||
|
# see https://mpv.io/manual/master/#list-of-input-commands for general command information
|
||||||
|
# note that there is no such thing as "unloading a profile", to emulate this you must create an opposite profile and load that
|
||||||
|
|
||||||
|
# example possible values:
|
||||||
|
#command_on_first_image_loaded=apply-profile image; enable-section image-viewer; script-message status-line-enable
|
||||||
|
#command_on_image_loaded=no-osd set video-pan-x 0; script-message align-border "" -1
|
||||||
|
#command_on_non_image_loaded=disable-section image-viewer; no-osd set video-pan-x 0; no-osd set video-pan-y 0; no-osd set video-zoom 0; script-message status-line-disable
|
||||||
14
.config/mvi/script-opts/image_positioning.conf
Normal file
14
.config/mvi/script-opts/image_positioning.conf
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# size of the margins with drag-to-pan
|
||||||
|
drag_to_pan_margin=50
|
||||||
|
drag_to_pan_move_if_full_view=no
|
||||||
|
|
||||||
|
# size of the margins with pan-follows-cursor
|
||||||
|
pan_follows_cursor_margin=50
|
||||||
|
|
||||||
|
# size of the margins with cursor-centric-zoom
|
||||||
|
cursor_centric_zoom_margin=50
|
||||||
|
# if the borders would show up, move the image
|
||||||
|
# this makes it not exactly cursor-centric in some cases
|
||||||
|
cursor_centric_zoom_auto_center=yes
|
||||||
|
# allow zooming out if the image can already fully fit in the window
|
||||||
|
cursor_centric_zoom_dezoom_if_full_view=no
|
||||||
19
.config/mvi/script-opts/minimap.conf
Normal file
19
.config/mvi/script-opts/minimap.conf
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# whether to show by default
|
||||||
|
enabled=yes
|
||||||
|
# the position of the center of the minimap, in percentage of the window (x, y)
|
||||||
|
center=92,92
|
||||||
|
# the scale of the minimap (i.e. the view rectangle is scale / 100 times the size of the window)
|
||||||
|
scale=12
|
||||||
|
# the cutoff size of the minimap (i.e. the image rectangle is clipped if it falls outside of the this zone)
|
||||||
|
max_size=16,16
|
||||||
|
# opacity of the "image" (from 00=opaque to FF=transparent)
|
||||||
|
image_opacity=88
|
||||||
|
# color of the "image" (#BBGGRR where each component rages from 00 to FF)
|
||||||
|
image_color=BBBBBB
|
||||||
|
# opacity of the "view"
|
||||||
|
view_opacity=BB
|
||||||
|
view_color=222222
|
||||||
|
# whether the view should be drawn above the image
|
||||||
|
view_above_image=yes
|
||||||
|
# whether to show the minimap if the current image is fully visible
|
||||||
|
hide_when_full_image_in_view=yes
|
||||||
21
.config/mvi/script-opts/ruler.conf
Normal file
21
.config/mvi/script-opts/ruler.conf
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# whether to show the length of the lines between the two points
|
||||||
|
show_distance=yes
|
||||||
|
# whether to show the coordinates of the two points
|
||||||
|
show_coordinates=yes
|
||||||
|
# the coordinate space of the text shown. Can be "image", "window", "both"
|
||||||
|
coordinates_space=image
|
||||||
|
# can be "degrees", "radians", "both", or "no"
|
||||||
|
show_angles=degrees
|
||||||
|
line_width=2
|
||||||
|
dots_radius=3
|
||||||
|
font_size=36
|
||||||
|
# ranges from 00 (black) to FF (white)
|
||||||
|
line_color=33
|
||||||
|
# bindings used to set points. The binding to trigger ruler mode can also be used. Comma-separated list
|
||||||
|
confirm_bindings=MBTN_LEFT,ENTER
|
||||||
|
# bindings used to set points. The binding to trigger ruler mode can also be used. Comma-separated list
|
||||||
|
exit_bindings=ESC
|
||||||
|
# if yes, the first point will be immediately set at the cursor position when calling 'ruler'
|
||||||
|
set_first_point_on_begin=no
|
||||||
|
# if yes, the ruler overlay will be immediately cleared when setting the second point
|
||||||
|
clear_on_second_point_set=no
|
||||||
14
.config/mvi/script-opts/status_line.conf
Normal file
14
.config/mvi/script-opts/status_line.conf
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# whether to show by default
|
||||||
|
enabled=yes
|
||||||
|
# its font size
|
||||||
|
size=36
|
||||||
|
# distance of the text to the borders
|
||||||
|
margin=10
|
||||||
|
# the text to be expanded
|
||||||
|
# see property expansion: https://mpv.io/manual/master/#property-expansion
|
||||||
|
# \N can be used for line breaks
|
||||||
|
# you can also use ass tags, see here: http://docs.aegisub.org/3.2/ASS_Tags/
|
||||||
|
text_top_left=
|
||||||
|
text_top_right=
|
||||||
|
text_bottom_left=${filename} [${playlist-pos-1}/${playlist-count}]
|
||||||
|
text_bottom_right=[${dwidth:X}x${dheight:X}]
|
||||||
73
.config/mvi/scripts/detect-image.lua
Normal file
73
.config/mvi/scripts/detect-image.lua
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
local opts = {
|
||||||
|
command_on_first_image_loaded="",
|
||||||
|
command_on_image_loaded="",
|
||||||
|
command_on_non_image_loaded="",
|
||||||
|
}
|
||||||
|
local options = require 'mp.options'
|
||||||
|
local msg = require 'mp.msg'
|
||||||
|
|
||||||
|
options.read_options(opts, nil, function() end)
|
||||||
|
|
||||||
|
function run_maybe(str)
|
||||||
|
if str ~= "" then
|
||||||
|
mp.command(str)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local was_image = false
|
||||||
|
|
||||||
|
function set_image(is_image)
|
||||||
|
if is_image and not was_image then
|
||||||
|
msg.info("First image detected")
|
||||||
|
run_maybe(opts.command_on_first_image_loaded)
|
||||||
|
end
|
||||||
|
if is_image then
|
||||||
|
msg.info("Image detected")
|
||||||
|
run_maybe(opts.command_on_image_loaded)
|
||||||
|
end
|
||||||
|
if not is_image and was_image then
|
||||||
|
msg.info("Non-image detected")
|
||||||
|
run_maybe(opts.command_on_non_image_loaded)
|
||||||
|
end
|
||||||
|
was_image = is_image
|
||||||
|
end
|
||||||
|
|
||||||
|
local properties = {}
|
||||||
|
|
||||||
|
function properties_changed()
|
||||||
|
local dwidth = properties["dwidth"]
|
||||||
|
local tracks = properties["track-list"]
|
||||||
|
local path = properties["path"]
|
||||||
|
local framecount = properties["estimated-frame-count"]
|
||||||
|
|
||||||
|
if not path or path == "" then return end
|
||||||
|
if not tracks or #tracks == 0 then return end
|
||||||
|
local audio_tracks = 0
|
||||||
|
for _, track in ipairs(tracks) do
|
||||||
|
if track.type == "audio" then
|
||||||
|
audio_tracks = audio_tracks + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- only do things when state is consistent
|
||||||
|
if not framecount and audio_tracks > 0 then
|
||||||
|
set_image(false)
|
||||||
|
elseif framecount and dwidth and dwidth > 0 then
|
||||||
|
-- png have 0 frames, jpg 1 ¯\_(ツ)_/¯
|
||||||
|
set_image((framecount == 0 or framecount == 1) and audio_tracks == 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function observe(propname)
|
||||||
|
mp.observe_property(propname, "native", function(_, val)
|
||||||
|
if val ~= properties[propname] then
|
||||||
|
properties[propname] = val
|
||||||
|
msg.verbose("Property " .. propname .. " changed")
|
||||||
|
properties_changed()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
observe("estimated-frame-count")
|
||||||
|
observe("track-list")
|
||||||
|
observe("dwidth")
|
||||||
|
observe("path")
|
||||||
176
.config/mvi/scripts/equalizer.lua
Normal file
176
.config/mvi/scripts/equalizer.lua
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
local opts = {
|
||||||
|
bars = 'brightness,contrast,gamma,saturation,hue',
|
||||||
|
draw_icons = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local msg = require 'mp.msg'
|
||||||
|
local assdraw = require 'mp.assdraw'
|
||||||
|
local options = require 'mp.options'
|
||||||
|
local utils = require 'mp.utils'
|
||||||
|
|
||||||
|
options.read_options(opts, nil, function(c)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local enabled = false
|
||||||
|
local active_bars = {}
|
||||||
|
local bar_being_dragged = nil
|
||||||
|
local stale = false
|
||||||
|
|
||||||
|
function split_comma(input)
|
||||||
|
local ret = {}
|
||||||
|
for str in string.gmatch(input, "([^,]+)") do
|
||||||
|
ret[#ret + 1] = str
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
function get_position_normalized(x, y, bar)
|
||||||
|
return (x - bar.x) / bar.w, (y - bar.y) / bar.h
|
||||||
|
end
|
||||||
|
|
||||||
|
function handle_mouse_move()
|
||||||
|
if not bar_being_dragged then return end
|
||||||
|
local bar = bar_being_dragged
|
||||||
|
local mx, my = mp.get_mouse_pos()
|
||||||
|
local nx, _ = get_position_normalized(mx, my, bar)
|
||||||
|
nx = math.max(0, math.min(nx, 1))
|
||||||
|
local val = math.floor(nx * (bar.max_value - bar.min_value) + bar.min_value + 0.5)
|
||||||
|
mp.set_property_number(bar.property, val)
|
||||||
|
-- the observe_property call will take care of setting the value
|
||||||
|
end
|
||||||
|
|
||||||
|
function handle_mouse_left(table)
|
||||||
|
if table["event"] == "down" then
|
||||||
|
local mx, my = mp.get_mouse_pos()
|
||||||
|
for _, bar in ipairs(active_bars) do
|
||||||
|
local nx, ny = get_position_normalized(mx, my, bar)
|
||||||
|
if nx >= 0 and ny >= 0 and nx <= 1 and ny <= 1 then
|
||||||
|
bar_being_dragged = bar
|
||||||
|
local val = math.floor(nx * (bar.max_value - bar.min_value) + bar.min_value + 0.5)
|
||||||
|
mp.set_property_number(bar.property, val)
|
||||||
|
mp.add_forced_key_binding("mouse_move", "mouse_move", handle_mouse_move)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif table["event"] == "up" then
|
||||||
|
mp.remove_key_binding("mouse_move")
|
||||||
|
bar_being_dragged = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function property_changed(prop, val)
|
||||||
|
for _, bar in ipairs(active_bars) do
|
||||||
|
if bar.property == prop then
|
||||||
|
bar.value = val
|
||||||
|
stale = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function idle_handler()
|
||||||
|
if not stale then return end
|
||||||
|
stale = false
|
||||||
|
local a = assdraw.ass_new()
|
||||||
|
a:new_event()
|
||||||
|
a:append(string.format('{\\an0\\bord2\\shad0\\1a&00&\\1c&%s&}', '888888'))
|
||||||
|
a:pos(0, 0)
|
||||||
|
a:draw_start()
|
||||||
|
for _, bar in ipairs(active_bars) do
|
||||||
|
a:rect_cw(bar.x, bar.y, bar.x + bar.w, bar.y + bar.h)
|
||||||
|
end
|
||||||
|
a:new_event()
|
||||||
|
a:append(string.format('{\\an0\\bord2\\shad0\\1a&00&\\1c&%s&}', 'dddddd'))
|
||||||
|
a:pos(0, 0)
|
||||||
|
a:draw_start()
|
||||||
|
for _, bar in ipairs(active_bars) do
|
||||||
|
if bar.value > bar.min_value then
|
||||||
|
local val_norm = (bar.value - bar.min_value) / (bar.max_value - bar.min_value)
|
||||||
|
a:rect_cw(bar.x, bar.y, bar.x + val_norm * bar.w, bar.y + bar.h)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, bar in ipairs(active_bars) do
|
||||||
|
a:new_event()
|
||||||
|
a:append("{\\an6\\fs40\\bord2}")
|
||||||
|
a:pos(bar.x - 8, bar.y + bar.h/2 - 2)
|
||||||
|
a:append(bar.property:sub(1,1):upper() .. bar.property:sub(2,-1))
|
||||||
|
end
|
||||||
|
local ww, wh = mp.get_osd_size()
|
||||||
|
mp.set_osd_ass(ww, wh, a.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
function fix_position()
|
||||||
|
local ww, wh = mp.get_osd_size()
|
||||||
|
for i, bar in ipairs(active_bars) do
|
||||||
|
bar.x = ww / 5
|
||||||
|
bar.y = wh / 2 + i * 50
|
||||||
|
bar.w = ww - 2 * (ww / 5)
|
||||||
|
bar.h = 30
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function dimensions_changed()
|
||||||
|
stale = true
|
||||||
|
fix_position()
|
||||||
|
end
|
||||||
|
|
||||||
|
function enable()
|
||||||
|
if enabled then return end
|
||||||
|
enabled = true
|
||||||
|
mp.add_forced_key_binding("MBTN_LEFT", "mouse_left", handle_mouse_left, {complex=true})
|
||||||
|
for i, prop in ipairs(split_comma(opts.bars)) do
|
||||||
|
local prop_info = mp.get_property_native("option-info/" .. prop)
|
||||||
|
if not prop_info then
|
||||||
|
msg.warn("Property \'" .. prop .. "\' does not exist")
|
||||||
|
elseif not prop_info.type == 'Integer' then
|
||||||
|
msg.warn("Property \'" .. prop .. "\' is not an integer")
|
||||||
|
else
|
||||||
|
mp.observe_property(prop, 'native', property_changed)
|
||||||
|
active_bars[#active_bars + 1] = {
|
||||||
|
property = prop,
|
||||||
|
value = mp.get_property_number(prop),
|
||||||
|
min_value = prop_info.min,
|
||||||
|
max_value = prop_info.max,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
stale = true
|
||||||
|
fix_position()
|
||||||
|
mp.observe_property("osd-dimensions", "native", dimensions_changed)
|
||||||
|
mp.register_idle(idle_handler)
|
||||||
|
end
|
||||||
|
|
||||||
|
function disable()
|
||||||
|
if not enabled then return end
|
||||||
|
enabled = false
|
||||||
|
active_bars = {}
|
||||||
|
bar_being_dragged = nil
|
||||||
|
mp.remove_key_binding("mouse_left")
|
||||||
|
mp.remove_key_binding("mouse_move")
|
||||||
|
mp.unobserve_property(property_changed)
|
||||||
|
mp.unobserve_property(dimensions_changed)
|
||||||
|
mp.unregister_idle(idle_handler)
|
||||||
|
mp.set_osd_ass(1280, 720, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
function toggle()
|
||||||
|
if enabled then
|
||||||
|
disable()
|
||||||
|
else
|
||||||
|
enable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function reset()
|
||||||
|
for _, prop in ipairs(split_comma(opts.bars)) do
|
||||||
|
local prop_info = mp.get_property_native("option-info/" .. prop)
|
||||||
|
if prop_info and prop_info["default-value"] then
|
||||||
|
mp.set_property(prop_info["name"], prop_info["default-value"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mp.add_key_binding(nil, "equalizer-enable", enable)
|
||||||
|
mp.add_key_binding(nil, "equalizer-disable", disable)
|
||||||
|
mp.add_key_binding(nil, "equalizer-toggle", toggle)
|
||||||
|
mp.add_key_binding(nil, "equalizer-reset", reset)
|
||||||
14
.config/mvi/scripts/freeze-window.lua
Normal file
14
.config/mvi/scripts/freeze-window.lua
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
-- credit to TheAMM
|
||||||
|
|
||||||
|
local size_changed = false
|
||||||
|
|
||||||
|
mp.register_idle(function()
|
||||||
|
if not size_changed then return end
|
||||||
|
local ww, wh = mp.get_osd_size()
|
||||||
|
if not ww or ww <= 0 or not wh or wh <= 0 then return end
|
||||||
|
mp.set_property("geometry", string.format("%dx%d", ww, wh))
|
||||||
|
size_changed = false
|
||||||
|
end)
|
||||||
|
|
||||||
|
mp.observe_property("osd-width", "native", function() size_changed = true end)
|
||||||
|
mp.observe_property("osd-height", "native", function() size_changed = true end)
|
||||||
277
.config/mvi/scripts/image-positioning.lua
Normal file
277
.config/mvi/scripts/image-positioning.lua
Normal file
|
|
@ -0,0 +1,277 @@
|
||||||
|
local opts = {
|
||||||
|
drag_to_pan_margin = 50,
|
||||||
|
drag_to_pan_move_if_full_view=false,
|
||||||
|
|
||||||
|
pan_follows_cursor_margin = 50,
|
||||||
|
|
||||||
|
cursor_centric_zoom_margin = 50,
|
||||||
|
cursor_centric_zoom_auto_center = true,
|
||||||
|
cursor_centric_zoom_dezoom_if_full_view = false,
|
||||||
|
}
|
||||||
|
local options = require 'mp.options'
|
||||||
|
local msg = require 'mp.msg'
|
||||||
|
local assdraw = require 'mp.assdraw'
|
||||||
|
|
||||||
|
options.read_options(opts, nil, function() end)
|
||||||
|
|
||||||
|
function clamp(value, low, high)
|
||||||
|
if value <= low then
|
||||||
|
return low
|
||||||
|
elseif value >= high then
|
||||||
|
return high
|
||||||
|
else
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local cleanup = nil -- function set up by drag-to-pan/pan-follows cursor and must be called to clean lingering state
|
||||||
|
|
||||||
|
function drag_to_pan_handler(table)
|
||||||
|
if cleanup then
|
||||||
|
cleanup()
|
||||||
|
cleanup = nil
|
||||||
|
end
|
||||||
|
if table["event"] == "down" then
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then return end
|
||||||
|
local mouse_pos_origin, video_pan_origin = {}, {}
|
||||||
|
local moved = false
|
||||||
|
mouse_pos_origin[1], mouse_pos_origin[2] = mp.get_mouse_pos()
|
||||||
|
video_pan_origin[1] = mp.get_property_number("video-pan-x")
|
||||||
|
video_pan_origin[2] = mp.get_property_number("video-pan-y")
|
||||||
|
local video_size = { dim.w - dim.ml - dim.mr, dim.h - dim.mt - dim.mb }
|
||||||
|
local margin = opts.drag_to_pan_margin
|
||||||
|
local move_up = true
|
||||||
|
local move_lateral = true
|
||||||
|
if not opts.drag_to_pan_move_if_full_view then
|
||||||
|
if dim.ml >= 0 and dim.mr >= 0 then
|
||||||
|
move_lateral = false
|
||||||
|
end
|
||||||
|
if dim.mt >= 0 and dim.mb >= 0 then
|
||||||
|
move_up = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not move_up and not move_lateral then return end
|
||||||
|
local idle = function()
|
||||||
|
if moved then
|
||||||
|
local mX, mY = mp.get_mouse_pos()
|
||||||
|
local pX = video_pan_origin[1]
|
||||||
|
local pY = video_pan_origin[2]
|
||||||
|
if move_lateral then
|
||||||
|
pX = video_pan_origin[1] + (mX - mouse_pos_origin[1]) / video_size[1]
|
||||||
|
if 2 * margin > dim.ml + dim.mr then
|
||||||
|
pX = clamp(pX,
|
||||||
|
(-margin + dim.w / 2) / video_size[1] - 0.5,
|
||||||
|
(margin - dim.w / 2) / video_size[1] + 0.5)
|
||||||
|
else
|
||||||
|
pX = clamp(pX,
|
||||||
|
(margin - dim.w / 2) / video_size[1] + 0.5,
|
||||||
|
(-margin + dim.w / 2) / video_size[1] - 0.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if move_up then
|
||||||
|
pY = video_pan_origin[2] + (mY - mouse_pos_origin[2]) / video_size[2]
|
||||||
|
if 2 * margin > dim.mt + dim.mb then
|
||||||
|
pY = clamp(pY,
|
||||||
|
(-margin + dim.h / 2) / video_size[2] - 0.5,
|
||||||
|
(margin - dim.h / 2) / video_size[2] + 0.5)
|
||||||
|
else
|
||||||
|
pY = clamp(pY,
|
||||||
|
(margin - dim.h / 2) / video_size[2] + 0.5,
|
||||||
|
(-margin + dim.h / 2) / video_size[2] - 0.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mp.command("no-osd set video-pan-x " .. clamp(pX, -3, 3) .. "; no-osd set video-pan-y " .. clamp(pY, -3, 3))
|
||||||
|
moved = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mp.register_idle(idle)
|
||||||
|
mp.add_forced_key_binding("mouse_move", "image-viewer-mouse-move", function() moved = true end)
|
||||||
|
cleanup = function()
|
||||||
|
mp.remove_key_binding("image-viewer-mouse-move")
|
||||||
|
mp.unregister_idle(idle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function pan_follows_cursor_handler(table)
|
||||||
|
if cleanup then
|
||||||
|
cleanup()
|
||||||
|
cleanup = nil
|
||||||
|
end
|
||||||
|
if table["event"] == "down" then
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then return end
|
||||||
|
local video_size = { dim.w - dim.ml - dim.mr, dim.h - dim.mt - dim.mb }
|
||||||
|
local moved = true
|
||||||
|
local idle = function()
|
||||||
|
if moved then
|
||||||
|
local mX, mY = mp.get_mouse_pos()
|
||||||
|
local x = math.min(1, math.max(- 2 * mX / dim.w + 1, -1))
|
||||||
|
local y = math.min(1, math.max(- 2 * mY / dim.h + 1, -1))
|
||||||
|
local command = ""
|
||||||
|
local margin = opts.pan_follows_cursor_margin
|
||||||
|
if dim.ml + dim.mr < 0 then
|
||||||
|
command = command .. "no-osd set video-pan-x " .. clamp(x * (2 * margin - dim.ml - dim.mr) / (2 * video_size[1]), -3, 3) .. ";"
|
||||||
|
elseif mp.get_property_number("video-pan-x") ~= 0 then
|
||||||
|
command = command .. "no-osd set video-pan-x " .. "0;"
|
||||||
|
end
|
||||||
|
if dim.mt + dim.mb < 0 then
|
||||||
|
command = command .. "no-osd set video-pan-y " .. clamp(y * (2 * margin - dim.mt - dim.mb) / (2 * video_size[2]), -3, 3) .. ";"
|
||||||
|
elseif mp.get_property_number("video-pan-y") ~= 0 then
|
||||||
|
command = command .. "no-osd set video-pan-y " .. "0;"
|
||||||
|
end
|
||||||
|
if command ~= "" then
|
||||||
|
mp.command(command)
|
||||||
|
end
|
||||||
|
moved = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mp.register_idle(idle)
|
||||||
|
mp.add_forced_key_binding("mouse_move", "image-viewer-mouse-move", function() moved = true end)
|
||||||
|
cleanup = function()
|
||||||
|
mp.remove_key_binding("image-viewer-mouse-move")
|
||||||
|
mp.unregister_idle(idle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function cursor_centric_zoom_handler(amt)
|
||||||
|
local zoom_inc = tonumber(amt)
|
||||||
|
if not zoom_inc or zoom_inc == 0 then return end
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then return end
|
||||||
|
|
||||||
|
local margin = opts.cursor_centric_zoom_margin
|
||||||
|
|
||||||
|
local video_size = { dim.w - dim.ml - dim.mr, dim.h - dim.mt - dim.mb }
|
||||||
|
|
||||||
|
-- the size in pixels of the (in|de)crement
|
||||||
|
local diff_width = (2 ^ zoom_inc - 1) * video_size[1]
|
||||||
|
local diff_height = (2 ^ zoom_inc - 1) * video_size[2]
|
||||||
|
if not opts.cursor_centric_zoom_dezoom_if_full_view and
|
||||||
|
zoom_inc < 0 and
|
||||||
|
video_size[1] + diff_width + 2 * margin <= dim.w and
|
||||||
|
video_size[2] + diff_height + 2 * margin <= dim.h
|
||||||
|
then
|
||||||
|
-- the zoom decrement is too much, reduce it such that the full image is visible, no more, no less
|
||||||
|
-- in addition, this should take care of trying too zoom out while everything is already visible
|
||||||
|
local new_zoom_inc_x = math.log((dim.w - 2 * margin) / video_size[1]) / math.log(2)
|
||||||
|
local new_zoom_inc_y = math.log((dim.h - 2 * margin) / video_size[2]) / math.log(2)
|
||||||
|
local new_zoom_inc = math.min(0, math.min(new_zoom_inc_x, new_zoom_inc_y))
|
||||||
|
zoom_inc = new_zoom_inc
|
||||||
|
diff_width = (2 ^ zoom_inc - 1) * video_size[1]
|
||||||
|
diff_height = (2 ^ zoom_inc - 1) * video_size[2]
|
||||||
|
end
|
||||||
|
local new_width = video_size[1] + diff_width
|
||||||
|
local new_height = video_size[2] + diff_height
|
||||||
|
|
||||||
|
local mouse_pos_origin = {}
|
||||||
|
mouse_pos_origin[1], mouse_pos_origin[2] = mp.get_mouse_pos()
|
||||||
|
local new_pan_x, new_pan_y
|
||||||
|
|
||||||
|
-- some additional constraints:
|
||||||
|
-- if image can be fully visible (in either direction), set pan to 0
|
||||||
|
-- if border would show on either side, then prefer adjusting the pan even if not cursor-centric
|
||||||
|
local auto_c = opts.cursor_centric_zoom_auto_center
|
||||||
|
if auto_c and new_width <= dim.w then
|
||||||
|
new_pan_x = 0
|
||||||
|
else
|
||||||
|
local pan_x = mp.get_property("video-pan-x")
|
||||||
|
local rx = (dim.ml + video_size[1] / 2 - mouse_pos_origin[1]) / (video_size[1] / 2)
|
||||||
|
new_pan_x = (pan_x * video_size[1] + rx * diff_width / 2) / new_width
|
||||||
|
if auto_c then
|
||||||
|
new_pan_x = clamp(new_pan_x, (dim.w - 2 * margin) / (2 * new_width) - 0.5, - (dim.w - 2 * margin) / (2 * new_width) + 0.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if auto_c and new_height <= dim.h then
|
||||||
|
new_pan_y = 0
|
||||||
|
else
|
||||||
|
local pan_y = mp.get_property("video-pan-y")
|
||||||
|
local ry = (dim.mt + video_size[2] / 2 - mouse_pos_origin[2]) / (video_size[2] / 2)
|
||||||
|
new_pan_y = (pan_y * video_size[2] + ry * diff_height / 2) / new_height
|
||||||
|
if auto_c then
|
||||||
|
new_pan_y = clamp(new_pan_y, (dim.h - 2 * margin) / (2 * new_height) - 0.5, - (dim.h - 2 * margin) / (2 * new_height) + 0.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local zoom_origin = mp.get_property("video-zoom")
|
||||||
|
mp.command("no-osd set video-zoom " .. zoom_origin + zoom_inc .. "; no-osd set video-pan-x " .. clamp(new_pan_x, -3, 3) .. "; no-osd set video-pan-y " .. clamp(new_pan_y, -3, 3))
|
||||||
|
end
|
||||||
|
|
||||||
|
function align_border(x, y)
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then return end
|
||||||
|
local video_size = { dim.w - dim.ml - dim.mr, dim.h - dim.mt - dim.mb }
|
||||||
|
local x, y = tonumber(x), tonumber(y)
|
||||||
|
local command = ""
|
||||||
|
if x then
|
||||||
|
command = command .. "no-osd set video-pan-x " .. clamp(- x * (dim.ml + dim.mr) / (2 * video_size[1]), -3, 3) .. ";"
|
||||||
|
end
|
||||||
|
if y then
|
||||||
|
command = command .. "no-osd set video-pan-y " .. clamp(- y * (dim.mt + dim.mb) / (2 * video_size[2]), -3, 3) .. ";"
|
||||||
|
end
|
||||||
|
if command ~= "" then
|
||||||
|
mp.command(command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function pan_image(axis, amount, zoom_invariant, image_constrained)
|
||||||
|
amount = tonumber(amount)
|
||||||
|
if not amount or amount == 0 or axis ~= "x" and axis ~= "y" then return end
|
||||||
|
if zoom_invariant == "yes" then
|
||||||
|
amount = amount / 2 ^ mp.get_property_number("video-zoom")
|
||||||
|
end
|
||||||
|
local prop = "video-pan-" .. axis
|
||||||
|
local old_pan = mp.get_property_number(prop)
|
||||||
|
if image_constrained == "yes" then
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then return end
|
||||||
|
local margin =
|
||||||
|
(axis == "x" and amount > 0) and dim.ml
|
||||||
|
or (axis == "x" and amount < 0) and dim.mr
|
||||||
|
or (amount > 0) and dim.mt
|
||||||
|
or (amount < 0) and dim.mb
|
||||||
|
local vid_size = (axis == "x") and (dim.w - dim.ml - dim.mr) or (dim.h - dim.mt - dim.mb)
|
||||||
|
local pixels_moved = math.abs(amount) * vid_size
|
||||||
|
-- the margin is already visible, no point going further
|
||||||
|
if margin >= 0 then
|
||||||
|
return
|
||||||
|
elseif margin + pixels_moved > 0 then
|
||||||
|
amount = -(math.abs(amount) / amount) * margin / vid_size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mp.set_property_number(prop, old_pan + amount)
|
||||||
|
end
|
||||||
|
|
||||||
|
function rotate_video(amt)
|
||||||
|
local rot = mp.get_property_number("video-rotate")
|
||||||
|
rot = (rot + amt) % 360
|
||||||
|
mp.set_property_number("video-rotate", rot)
|
||||||
|
end
|
||||||
|
|
||||||
|
function reset_pan_if_visible()
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then return end
|
||||||
|
local command = ""
|
||||||
|
if (dim.ml + dim.mr >= 0) then
|
||||||
|
command = command .. "no-osd set video-pan-x 0" .. ";"
|
||||||
|
end
|
||||||
|
if (dim.mt + dim.mb >= 0) then
|
||||||
|
command = command .. "no-osd set video-pan-y 0" .. ";"
|
||||||
|
end
|
||||||
|
if command ~= "" then
|
||||||
|
mp.command(command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mp.add_key_binding(nil, "drag-to-pan", drag_to_pan_handler, {complex = true})
|
||||||
|
mp.add_key_binding(nil, "pan-follows-cursor", pan_follows_cursor_handler, {complex = true})
|
||||||
|
mp.add_key_binding(nil, "cursor-centric-zoom", cursor_centric_zoom_handler)
|
||||||
|
mp.add_key_binding(nil, "align-border", align_border)
|
||||||
|
mp.add_key_binding(nil, "pan-image", pan_image)
|
||||||
|
mp.add_key_binding(nil, "rotate-video", rotate_video)
|
||||||
|
mp.add_key_binding(nil, "reset-pan-if-visible", reset_pan_if_visible)
|
||||||
|
mp.add_key_binding(nil, "force-print-filename", force_print_filename)
|
||||||
201
.config/mvi/scripts/minimap.lua
Normal file
201
.config/mvi/scripts/minimap.lua
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
local opts = {
|
||||||
|
enabled = true,
|
||||||
|
center = "92,92",
|
||||||
|
scale = 12,
|
||||||
|
max_size = "16,16",
|
||||||
|
image_opacity = "88",
|
||||||
|
image_color = "BBBBBB",
|
||||||
|
view_opacity = "BB",
|
||||||
|
view_color = "222222",
|
||||||
|
view_above_image = true,
|
||||||
|
hide_when_full_image_in_view = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local msg = require 'mp.msg'
|
||||||
|
local assdraw = require 'mp.assdraw'
|
||||||
|
local options = require 'mp.options'
|
||||||
|
|
||||||
|
options.read_options(opts, nil, function(c)
|
||||||
|
if c["enabled"] then
|
||||||
|
if opts.enabled then
|
||||||
|
enable()
|
||||||
|
else
|
||||||
|
disable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mark_stale()
|
||||||
|
end)
|
||||||
|
|
||||||
|
function split_comma(input)
|
||||||
|
local ret = {}
|
||||||
|
for str in string.gmatch(input, "([^,]+)") do
|
||||||
|
ret[#ret + 1] = tonumber(str)
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local active = false
|
||||||
|
local refresh = true
|
||||||
|
|
||||||
|
function draw_ass(ass)
|
||||||
|
local ww, wh = mp.get_osd_size()
|
||||||
|
mp.set_osd_ass(ww, wh, ass)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mark_stale()
|
||||||
|
refresh = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function refresh_minimap()
|
||||||
|
if not refresh then return end
|
||||||
|
refresh = false
|
||||||
|
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then
|
||||||
|
draw_ass("")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local ww, wh = dim.w, dim.h
|
||||||
|
|
||||||
|
if not (ww > 0 and wh > 0) then return end
|
||||||
|
if opts.hide_when_full_image_in_view then
|
||||||
|
if dim.mt >= 0 and dim.mb >= 0 and dim.ml >= 0 and dim.mr >= 0 then
|
||||||
|
draw_ass("")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local center = split_comma(opts.center)
|
||||||
|
center[1] = center[1] * 0.01 * ww
|
||||||
|
center[2] = center[2] * 0.01 * wh
|
||||||
|
local cutoff = split_comma(opts.max_size)
|
||||||
|
cutoff[1] = cutoff[1] * 0.01 * ww * 0.5
|
||||||
|
cutoff[2] = cutoff[2] * 0.01 * wh * 0.5
|
||||||
|
|
||||||
|
local a = assdraw.ass_new()
|
||||||
|
local draw = function(x, y, w, h, opacity, color)
|
||||||
|
a:new_event()
|
||||||
|
a:pos(center[1], center[2])
|
||||||
|
a:append("{\\bord0}")
|
||||||
|
a:append("{\\shad0}")
|
||||||
|
a:append("{\\c&" .. color .. "&}")
|
||||||
|
a:append("{\\2a&HFF}")
|
||||||
|
a:append("{\\3a&HFF}")
|
||||||
|
a:append("{\\4a&HFF}")
|
||||||
|
a:append("{\\1a&H" .. opacity .. "}")
|
||||||
|
w = w * 0.5
|
||||||
|
h = h * 0.5
|
||||||
|
a:draw_start()
|
||||||
|
local rounded = {true,true,true,true} -- tl, tr, br, bl
|
||||||
|
local x0,y0,x1,y1 = x-w, y-h, x+w, y+h
|
||||||
|
if x0 < -cutoff[1] then
|
||||||
|
x0 = -cutoff[1]
|
||||||
|
rounded[4] = false
|
||||||
|
rounded[1] = false
|
||||||
|
end
|
||||||
|
if y0 < -cutoff[2] then
|
||||||
|
y0 = -cutoff[2]
|
||||||
|
rounded[1] = false
|
||||||
|
rounded[2] = false
|
||||||
|
end
|
||||||
|
if x1 > cutoff[1] then
|
||||||
|
x1 = cutoff[1]
|
||||||
|
rounded[2] = false
|
||||||
|
rounded[3] = false
|
||||||
|
end
|
||||||
|
if y1 > cutoff[2] then
|
||||||
|
y1 = cutoff[2]
|
||||||
|
rounded[3] = false
|
||||||
|
rounded[4] = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local r = 3
|
||||||
|
local c = 0.551915024494 * r
|
||||||
|
if rounded[0] then
|
||||||
|
a:move_to(x0 + r, y0)
|
||||||
|
else
|
||||||
|
a:move_to(x0,y0)
|
||||||
|
end
|
||||||
|
if rounded[1] then
|
||||||
|
a:line_to(x1 - r, y0)
|
||||||
|
a:bezier_curve(x1 - r + c, y0, x1, y0 + r - c, x1, y0 + r)
|
||||||
|
else
|
||||||
|
a:line_to(x1, y0)
|
||||||
|
end
|
||||||
|
if rounded[2] then
|
||||||
|
a:line_to(x1, y1 - r)
|
||||||
|
a:bezier_curve(x1, y1 - r + c, x1 - r + c, y1, x1 - r, y1)
|
||||||
|
else
|
||||||
|
a:line_to(x1, y1)
|
||||||
|
end
|
||||||
|
if rounded[3] then
|
||||||
|
a:line_to(x0 + r, y1)
|
||||||
|
a:bezier_curve(x0 + r - c, y1, x0, y1 - r + c, x0, y1 - r)
|
||||||
|
else
|
||||||
|
a:line_to(x0, y1)
|
||||||
|
end
|
||||||
|
if rounded[4] then
|
||||||
|
a:line_to(x0, y0 + r)
|
||||||
|
a:bezier_curve(x0, y0 + r - c, x0 + r - c, y0, x0 + r, y0)
|
||||||
|
else
|
||||||
|
a:line_to(x0, y0)
|
||||||
|
end
|
||||||
|
a:draw_stop()
|
||||||
|
end
|
||||||
|
local image = function()
|
||||||
|
draw((dim.ml/2 - dim.mr/2) / opts.scale,
|
||||||
|
(dim.mt/2 - dim.mb/2) / opts.scale,
|
||||||
|
(ww - dim.ml - dim.mr) / opts.scale,
|
||||||
|
(wh - dim.mt - dim.mb) / opts.scale,
|
||||||
|
opts.image_opacity,
|
||||||
|
opts.image_color)
|
||||||
|
end
|
||||||
|
local view = function()
|
||||||
|
draw(0,
|
||||||
|
0,
|
||||||
|
ww / opts.scale,
|
||||||
|
wh / opts.scale,
|
||||||
|
opts.view_opacity,
|
||||||
|
opts.view_color)
|
||||||
|
end
|
||||||
|
if opts.view_above_image then
|
||||||
|
image()
|
||||||
|
view()
|
||||||
|
else
|
||||||
|
view()
|
||||||
|
image()
|
||||||
|
end
|
||||||
|
draw_ass(a.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
function enable()
|
||||||
|
if active then return end
|
||||||
|
active = true
|
||||||
|
mp.observe_property("osd-dimensions", nil, mark_stale)
|
||||||
|
mp.register_idle(refresh_minimap)
|
||||||
|
mark_stale()
|
||||||
|
end
|
||||||
|
|
||||||
|
function disable()
|
||||||
|
if not active then return end
|
||||||
|
active = false
|
||||||
|
mp.unobserve_property(mark_stale)
|
||||||
|
mp.unregister_idle(refresh_minimap)
|
||||||
|
draw_ass("")
|
||||||
|
end
|
||||||
|
|
||||||
|
function toggle()
|
||||||
|
if active then
|
||||||
|
disable()
|
||||||
|
else
|
||||||
|
enable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts.enabled then
|
||||||
|
enable()
|
||||||
|
end
|
||||||
|
|
||||||
|
mp.add_key_binding(nil, "minimap-enable", enable)
|
||||||
|
mp.add_key_binding(nil, "minimap-disable", disable)
|
||||||
|
mp.add_key_binding(nil, "minimap-toggle", toggle)
|
||||||
314
.config/mvi/scripts/ruler.lua
Normal file
314
.config/mvi/scripts/ruler.lua
Normal file
|
|
@ -0,0 +1,314 @@
|
||||||
|
local opts = {
|
||||||
|
show_distance = true,
|
||||||
|
show_coordinates = true,
|
||||||
|
coordinates_space = "image",
|
||||||
|
show_angles = "degrees",
|
||||||
|
line_width = 2,
|
||||||
|
dots_radius = 3,
|
||||||
|
font_size = 36,
|
||||||
|
line_color = "33",
|
||||||
|
confirm_bindings = "MBTN_LEFT,ENTER",
|
||||||
|
exit_bindings = "ESC",
|
||||||
|
set_first_point_on_begin = false,
|
||||||
|
clear_on_second_point_set = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
local options = require 'mp.options'
|
||||||
|
local msg = require 'mp.msg'
|
||||||
|
local assdraw = require 'mp.assdraw'
|
||||||
|
|
||||||
|
local state = 0 -- {0,1,2,3} = {inactive,setting first point,setting second point,done}
|
||||||
|
local first_point = nil -- in normalized video space coordinates
|
||||||
|
local second_point = nil -- in normalized video space coordinates
|
||||||
|
local video_dimensions_stale = false
|
||||||
|
|
||||||
|
function split(input)
|
||||||
|
local ret = {}
|
||||||
|
for str in string.gmatch(input, "([^,]+)") do
|
||||||
|
ret[#ret + 1] = str
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local confirm_bindings = split(opts.confirm_bindings)
|
||||||
|
local exit_bindings = split(opts.exit_bindings)
|
||||||
|
|
||||||
|
options.read_options(opts, nil, function()
|
||||||
|
if state ~= 0 then
|
||||||
|
remove_bindings()
|
||||||
|
end
|
||||||
|
confirm_bindings = split(opts.confirm_bindings)
|
||||||
|
exit_bindings = split(opts.exit_bindings)
|
||||||
|
if state ~= 0 then
|
||||||
|
add_bindings()
|
||||||
|
mark_stale()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
function draw_ass(ass)
|
||||||
|
local ww, wh = mp.get_osd_size()
|
||||||
|
mp.set_osd_ass(ww, wh, ass)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function cursor_video_space_normalized(dim)
|
||||||
|
local mx, my = mp.get_mouse_pos()
|
||||||
|
local ret = {}
|
||||||
|
ret[1] = (mx - dim.ml) / (dim.w - dim.ml - dim.mr)
|
||||||
|
ret[2] = (my - dim.mt) / (dim.h - dim.mt - dim.mb)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
function refresh()
|
||||||
|
if not video_dimensions_stale then return end
|
||||||
|
video_dimensions_stale = false
|
||||||
|
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
local out_params = mp.get_property_native("video-out-params")
|
||||||
|
if not dim or not out_params then
|
||||||
|
draw_ass("")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local vid_width = out_params.dw
|
||||||
|
local vid_height = out_params.dh
|
||||||
|
|
||||||
|
function video_space_normalized_to_video(point)
|
||||||
|
local ret = {}
|
||||||
|
ret[1] = point[1] * vid_width
|
||||||
|
ret[2] = point[2] * vid_height
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
function video_space_normalized_to_screen(point)
|
||||||
|
local ret = {}
|
||||||
|
ret[1] = point[1] * (dim.w - dim.ml - dim.mr) + dim.ml
|
||||||
|
ret[2] = point[2] * (dim.h - dim.mt - dim.mb) + dim.mt
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local line_start = {}
|
||||||
|
local line_end = {}
|
||||||
|
if second_point then
|
||||||
|
line_start.image = video_space_normalized_to_video(first_point)
|
||||||
|
line_start.screen = video_space_normalized_to_screen(first_point)
|
||||||
|
line_end.image = video_space_normalized_to_video(second_point)
|
||||||
|
line_end.screen = video_space_normalized_to_screen(second_point)
|
||||||
|
elseif first_point then
|
||||||
|
line_start.image = video_space_normalized_to_video(first_point)
|
||||||
|
line_start.screen = video_space_normalized_to_screen(first_point)
|
||||||
|
line_end.image = video_space_normalized_to_video(cursor_video_space_normalized(dim))
|
||||||
|
line_end.screen = {}
|
||||||
|
line_end.screen[1], line_end.screen[2] = mp.get_mouse_pos()
|
||||||
|
else
|
||||||
|
local mx, my = mp.get_mouse_pos()
|
||||||
|
line_start.image = video_space_normalized_to_video(cursor_video_space_normalized(dim))
|
||||||
|
line_start.screen = {}
|
||||||
|
line_start.screen[1], line_start.screen[2] = mp.get_mouse_pos()
|
||||||
|
line_end = line_start
|
||||||
|
end
|
||||||
|
local distinct = (math.abs(line_start.screen[1] - line_end.screen[1]) >= 1
|
||||||
|
or math.abs(line_start.screen[2] - line_end.screen[2]) >= 1)
|
||||||
|
|
||||||
|
local a = assdraw:ass_new()
|
||||||
|
local draw_setup = function(bord)
|
||||||
|
a:new_event()
|
||||||
|
a:pos(0,0)
|
||||||
|
a:append("{\\bord" .. bord .. "}")
|
||||||
|
a:append("{\\shad0}")
|
||||||
|
local r = opts.line_color
|
||||||
|
a:append("{\\3c&H".. r .. r .. r .. "&}")
|
||||||
|
a:append("{\\1a&HFF}")
|
||||||
|
a:append("{\\2a&HFF}")
|
||||||
|
a:append("{\\3a&H00}")
|
||||||
|
a:append("{\\4a&HFF}")
|
||||||
|
a:draw_start()
|
||||||
|
end
|
||||||
|
local dot = function(pos, size)
|
||||||
|
draw_setup(size)
|
||||||
|
a:move_to(pos[1], pos[2]-0.5)
|
||||||
|
a:line_to(pos[1], pos[2]+0.5)
|
||||||
|
end
|
||||||
|
local line = function(from, to, size)
|
||||||
|
draw_setup(size)
|
||||||
|
a:move_to(from[1], from[2])
|
||||||
|
a:line_to(to[1], to[2])
|
||||||
|
end
|
||||||
|
if distinct then
|
||||||
|
dot(line_start.screen, opts.dots_radius)
|
||||||
|
line(line_start.screen, line_end.screen, opts.line_width)
|
||||||
|
dot(line_end.screen, opts.dots_radius)
|
||||||
|
else
|
||||||
|
dot(line_start.screen, opts.dots_radius)
|
||||||
|
end
|
||||||
|
|
||||||
|
local line_info = function()
|
||||||
|
if not opts.show_distance then return end
|
||||||
|
a:new_event()
|
||||||
|
a:append("{\\fs36}{\\bord1}")
|
||||||
|
a:pos((line_start.screen[1] + line_end.screen[1]) / 2, (line_start.screen[2] + line_end.screen[2]) / 2)
|
||||||
|
local an = 1
|
||||||
|
if line_start.image[1] < line_end.image[1] then an = an + 2 end
|
||||||
|
if line_start.image[2] < line_end.image[2] then an = an + 6 end
|
||||||
|
a:an(an)
|
||||||
|
local image = math.sqrt(math.pow(line_start.image[1] - line_end.image[1], 2) + math.pow(line_start.image[2] - line_end.image[2], 2))
|
||||||
|
local screen = math.sqrt(math.pow(line_start.screen[1] - line_end.screen[1], 2) + math.pow(line_start.screen[2] - line_end.screen[2], 2))
|
||||||
|
if opts.coordinates_space == "both" then
|
||||||
|
a:append(string.format("image: %.1f\\Nscreen: %.1f", image, screen))
|
||||||
|
elseif opts.coordinates_space == "image" then
|
||||||
|
a:append(string.format("%.1f", image))
|
||||||
|
elseif opts.coordinates_space == "window" then
|
||||||
|
a:append(string.format("%.1f", screen))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local dot_info = function(pos, opposite)
|
||||||
|
if not opts.show_coordinates then return end
|
||||||
|
a:new_event()
|
||||||
|
a:append("{\\fs" .. opts.font_size .."}{\\bord1}")
|
||||||
|
a:pos(pos.screen[1], pos.screen[2])
|
||||||
|
local an
|
||||||
|
if distinct then
|
||||||
|
an = 1
|
||||||
|
if line_start.image[1] > line_end.image[1] then an = an + 2 end
|
||||||
|
if line_start.image[2] < line_end.image[2] then an = an + 6 end
|
||||||
|
else
|
||||||
|
an = 7
|
||||||
|
end
|
||||||
|
if opposite then
|
||||||
|
an = 9 + 1 - an
|
||||||
|
end
|
||||||
|
a:an(an)
|
||||||
|
if opts.coordinates_space == "both" then
|
||||||
|
a:append(string.format("image: %.1f, %.1f\\Nscreen: %i, %i",
|
||||||
|
pos.image[1], pos.image[2], pos.screen[1], pos.screen[2]))
|
||||||
|
elseif opts.coordinates_space == "image" then
|
||||||
|
a:append(string.format("%.1f, %.1f", pos.image[1], pos.image[2]))
|
||||||
|
elseif opts.coordinates_space == "window" then
|
||||||
|
a:append(string.format("%i, %i", pos.screen[1], pos.screen[2]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
dot_info(line_start, true)
|
||||||
|
if distinct then
|
||||||
|
line_info()
|
||||||
|
dot_info(line_end, false)
|
||||||
|
end
|
||||||
|
if distinct and opts.show_angles ~= "no" then
|
||||||
|
local dist = 50
|
||||||
|
local pos_from_angle = function(mult, angle)
|
||||||
|
return {
|
||||||
|
line_start.screen[1] + mult * dist * math.cos(angle),
|
||||||
|
line_start.screen[2] + mult * dist * math.sin(angle),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
local extended = { line_start.screen[1], line_start.screen[2] }
|
||||||
|
if line_end.screen[1] > line_start.screen[1] then
|
||||||
|
extended[1] = extended[1] + dist
|
||||||
|
else
|
||||||
|
extended[1] = extended[1] - dist
|
||||||
|
end
|
||||||
|
line(line_start.screen, extended, math.max(0, opts.line_width-0.5))
|
||||||
|
local angle = math.atan(math.abs(line_start.image[2] - line_end.image[2]) / math.abs(line_start.image[1] - line_end.image[1]))
|
||||||
|
local fix_angle
|
||||||
|
local an
|
||||||
|
if line_end.image[2] < line_start.image[2] and line_end.image[1] > line_start.image[1] then
|
||||||
|
-- upper-right
|
||||||
|
an = 4
|
||||||
|
fix_angle = function(angle) return - angle end
|
||||||
|
elseif line_end.image[2] < line_start.image[2] then
|
||||||
|
-- upper-left
|
||||||
|
an = 6
|
||||||
|
fix_angle = function(angle) return math.pi + angle end
|
||||||
|
elseif line_end.image[1] < line_start.image[1] then
|
||||||
|
-- bottom-left
|
||||||
|
an = 6
|
||||||
|
fix_angle = function(angle) return math.pi - angle end
|
||||||
|
else
|
||||||
|
-- bottom-right
|
||||||
|
an = 4
|
||||||
|
fix_angle = function(angle) return angle end
|
||||||
|
end
|
||||||
|
-- should implement this https://math.stackexchange.com/questions/873224/calculate-control-points-of-cubic-bezier-curve-approximating-a-part-of-a-circle
|
||||||
|
local cp1 = pos_from_angle(1, fix_angle(angle*1/4))
|
||||||
|
local cp2 = pos_from_angle(1, fix_angle(angle*3/4))
|
||||||
|
local p2 = pos_from_angle(1, fix_angle(angle))
|
||||||
|
a:bezier_curve(cp1[1], cp1[2], cp2[1], cp2[2], p2[1], p2[2])
|
||||||
|
|
||||||
|
a:new_event()
|
||||||
|
a:append("{\\fs" .. opts.font_size .."}{\\bord1}")
|
||||||
|
local text_pos = pos_from_angle(1.1, fix_angle(angle*2/3)) -- you'd think /2 would make more sense, but *2/3 looks better
|
||||||
|
a:pos(text_pos[1], text_pos[2])
|
||||||
|
a:an(an)
|
||||||
|
if opts.show_angles == "both" then
|
||||||
|
a:append(string.format("%.2f\\N%.1f°", angle, angle / math.pi * 180))
|
||||||
|
elseif opts.show_angles == "degrees" then
|
||||||
|
a:append(string.format("%.1f°", angle / math.pi * 180))
|
||||||
|
elseif opts.show_angles == "radians" then
|
||||||
|
a:append(string.format("%.2f", angle))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
draw_ass(a.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mark_stale()
|
||||||
|
video_dimensions_stale = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function add_bindings()
|
||||||
|
mp.add_forced_key_binding("mouse_move", "ruler-mouse-move", mark_stale)
|
||||||
|
for _, key in ipairs(confirm_bindings) do
|
||||||
|
mp.add_forced_key_binding(key, "ruler-next-" .. key, next_step)
|
||||||
|
end
|
||||||
|
for _, key in ipairs(exit_bindings) do
|
||||||
|
mp.add_forced_key_binding(key, "ruler-stop-" .. key, stop)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function remove_bindings()
|
||||||
|
for _, key in ipairs(confirm_bindings) do
|
||||||
|
mp.remove_key_binding("ruler-next-" .. key)
|
||||||
|
end
|
||||||
|
for _, key in ipairs(exit_bindings) do
|
||||||
|
mp.remove_key_binding("ruler-stop-" .. key)
|
||||||
|
end
|
||||||
|
mp.remove_key_binding("ruler-mouse-move")
|
||||||
|
end
|
||||||
|
|
||||||
|
function next_step()
|
||||||
|
if state == 0 then
|
||||||
|
state = 1
|
||||||
|
mp.register_idle(refresh)
|
||||||
|
mp.observe_property("osd-dimensions", nil, mark_stale)
|
||||||
|
mark_stale()
|
||||||
|
add_bindings()
|
||||||
|
if opts.set_first_point_on_begin then
|
||||||
|
next_step()
|
||||||
|
end
|
||||||
|
elseif state == 1 then
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then return end
|
||||||
|
state = 2
|
||||||
|
first_point = cursor_video_space_normalized(dim)
|
||||||
|
elseif state == 2 then
|
||||||
|
local dim = mp.get_property_native("osd-dimensions")
|
||||||
|
if not dim then return end
|
||||||
|
state = 3
|
||||||
|
second_point = cursor_video_space_normalized(dim)
|
||||||
|
if opts.clear_on_second_point_set then
|
||||||
|
next_step()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
stop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function stop()
|
||||||
|
if state == 0 then return end
|
||||||
|
mp.unregister_idle(refresh)
|
||||||
|
mp.unobserve_property(mark_stale)
|
||||||
|
remove_bindings()
|
||||||
|
state = 0
|
||||||
|
first_point = nil
|
||||||
|
second_point = nil
|
||||||
|
draw_ass("")
|
||||||
|
end
|
||||||
|
|
||||||
|
mp.add_key_binding(nil, "ruler", next_step)
|
||||||
142
.config/mvi/scripts/status-line.lua
Normal file
142
.config/mvi/scripts/status-line.lua
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
local opts = {
|
||||||
|
enabled = true,
|
||||||
|
size = 36,
|
||||||
|
margin = 10,
|
||||||
|
text_top_left = "",
|
||||||
|
text_top_right = "",
|
||||||
|
text_bottom_left = "${filename} [${playlist-pos-1}/${playlist-count}]",
|
||||||
|
text_bottom_right = "[${dwidth:X}x${dheight:X}]",
|
||||||
|
}
|
||||||
|
|
||||||
|
local msg = require 'mp.msg'
|
||||||
|
local assdraw = require 'mp.assdraw'
|
||||||
|
local options = require 'mp.options'
|
||||||
|
|
||||||
|
options.read_options(opts, nil, function(c)
|
||||||
|
if c["enabled"] then
|
||||||
|
if opts.enabled then
|
||||||
|
enable()
|
||||||
|
else
|
||||||
|
disable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if c["size"] or c["margin"] then
|
||||||
|
mark_stale()
|
||||||
|
end
|
||||||
|
if c["text_top_left"] or
|
||||||
|
c["text_top_right"] or
|
||||||
|
c["text_bottom_left"] or
|
||||||
|
c["text_bottom_right"]
|
||||||
|
then
|
||||||
|
observe_properties()
|
||||||
|
mark_stale()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local stale = true
|
||||||
|
local active = false
|
||||||
|
|
||||||
|
function draw_ass(ass)
|
||||||
|
local ww, wh = mp.get_osd_size()
|
||||||
|
mp.set_osd_ass(ww, wh, ass)
|
||||||
|
end
|
||||||
|
|
||||||
|
function refresh()
|
||||||
|
if not stale then return end
|
||||||
|
stale = false
|
||||||
|
local a = assdraw:ass_new()
|
||||||
|
local draw_text = function(text, an, x, y)
|
||||||
|
if text == "" then return end
|
||||||
|
local expanded = mp.command_native({ "expand-text", text})
|
||||||
|
if not expanded then
|
||||||
|
msg.error("Error expanding status-line")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
msg.verbose("Status-line changed to: " .. expanded)
|
||||||
|
a:new_event()
|
||||||
|
a:an(an)
|
||||||
|
a:pos(x,y)
|
||||||
|
a:append("{\\fs".. opts.size.. "}{\\bord1.0}")
|
||||||
|
a:append(expanded)
|
||||||
|
end
|
||||||
|
local w,h = mp.get_osd_size()
|
||||||
|
local m = opts.margin
|
||||||
|
draw_text(opts.text_top_left, 7, m, m)
|
||||||
|
draw_text(opts.text_top_right, 9, w-m, m)
|
||||||
|
draw_text(opts.text_bottom_left, 1, m, h-m)
|
||||||
|
draw_text(opts.text_bottom_right, 3, w-m, h-m)
|
||||||
|
draw_ass(a.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mark_stale()
|
||||||
|
stale = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function observe_properties()
|
||||||
|
mp.unobserve_property(mark_stale)
|
||||||
|
if not active then return end
|
||||||
|
for _, str in ipairs({
|
||||||
|
opts.text_top_left,
|
||||||
|
opts.text_top_right,
|
||||||
|
opts.text_bottom_left,
|
||||||
|
opts.text_bottom_right,
|
||||||
|
}) do
|
||||||
|
local start = 0
|
||||||
|
while true do
|
||||||
|
local s, e, cap = string.find(str, "%${[?!]?([%l%d-/]*)", start)
|
||||||
|
if not s then break end
|
||||||
|
msg.verbose("Observing property " .. cap)
|
||||||
|
mp.observe_property(cap, nil, mark_stale)
|
||||||
|
start = e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mp.observe_property("osd-width", nil, mark_stale)
|
||||||
|
mp.observe_property("osd-height", nil, mark_stale)
|
||||||
|
end
|
||||||
|
|
||||||
|
function enable()
|
||||||
|
if active then return end
|
||||||
|
active = true
|
||||||
|
observe_properties()
|
||||||
|
mp.register_idle(refresh)
|
||||||
|
mark_stale()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function disable()
|
||||||
|
if not active then return end
|
||||||
|
active = false
|
||||||
|
observe_properties()
|
||||||
|
mp.unregister_idle(refresh)
|
||||||
|
draw_ass("")
|
||||||
|
end
|
||||||
|
|
||||||
|
function toggle()
|
||||||
|
if active then
|
||||||
|
disable()
|
||||||
|
else
|
||||||
|
enable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts.enabled then
|
||||||
|
enable()
|
||||||
|
end
|
||||||
|
|
||||||
|
mp.add_key_binding(nil, "status-line-enable", enable)
|
||||||
|
mp.add_key_binding(nil, "status-line-disable", disable)
|
||||||
|
mp.add_key_binding(nil, "status-line-toggle", toggle)
|
||||||
|
|
||||||
|
-- TODO remove
|
||||||
|
mp.add_key_binding(nil, "enable-status-line", function()
|
||||||
|
msg.warn("This binding is deprecated, use 'status-line-enable' instead")
|
||||||
|
enable()
|
||||||
|
end)
|
||||||
|
mp.add_key_binding(nil, "disable-status-line", function()
|
||||||
|
msg.warn("This binding is deprecated, use 'status-line-disable' instead")
|
||||||
|
disable()
|
||||||
|
end)
|
||||||
|
mp.add_key_binding(nil, "toggle-status-line", function()
|
||||||
|
msg.warn("This binding is deprecated, use 'status-line-toggle' instead")
|
||||||
|
toggle()
|
||||||
|
end)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue