summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Schanzenbacher <ryan@rschanz.org>2024-07-02 20:45:48 -0400
committerRyan Schanzenbacher <ryan@rschanz.org>2024-07-02 20:45:48 -0400
commit0cb6e214ee4fdb4ca39dde60474f2cb6383a6735 (patch)
tree75def0b7750c7dca2e1f5e02f4de7f09f2ff375f
parentef2dba347d25a93706750281f4bbeb99bcbbd5fa (diff)
Added mpv script for live cropping, changes to hyprlock and base-system
-rw-r--r--home-config/home-configuration.scm1
-rw-r--r--home-config/mpv/scripts/easycrop.lua254
-rw-r--r--modules/ryan-config/base-system.scm2
-rw-r--r--modules/ryan-packages/wm.scm68
4 files changed, 292 insertions, 33 deletions
diff --git a/home-config/home-configuration.scm b/home-config/home-configuration.scm
index a3454cd..35390ae 100644
--- a/home-config/home-configuration.scm
+++ b/home-config/home-configuration.scm
@@ -150,6 +150,7 @@
150 ("nvim/after/ftplugin/mail/custom.vim" ,(local-file "nvim/config/after/ftplugin/mail/custom.vim")) 150 ("nvim/after/ftplugin/mail/custom.vim" ,(local-file "nvim/config/after/ftplugin/mail/custom.vim"))
151 ("sway" ,(local-file "sway" #:recursive? #t)) 151 ("sway" ,(local-file "sway" #:recursive? #t))
152 ("hypr" ,(local-file "hypr" #:recursive? #t)) 152 ("hypr" ,(local-file "hypr" #:recursive? #t))
153 ("mpv" ,(local-file "mpv" #:recursive? #t))
153 ("foot" ,(local-file "foot" #:recursive? #t)) 154 ("foot" ,(local-file "foot" #:recursive? #t))
154 ("pulse/client.conf" ,(local-file "pulseaudio/client.conf")) 155 ("pulse/client.conf" ,(local-file "pulseaudio/client.conf"))
155 ("waybar" ,(local-file "waybar" #:recursive? #t)) 156 ("waybar" ,(local-file "waybar" #:recursive? #t))
diff --git a/home-config/mpv/scripts/easycrop.lua b/home-config/mpv/scripts/easycrop.lua
new file mode 100644
index 0000000..415fce5
--- /dev/null
+++ b/home-config/mpv/scripts/easycrop.lua
@@ -0,0 +1,254 @@
1local msg = require('mp.msg')
2local assdraw = require('mp.assdraw')
3
4local script_name = "easycrop"
5
6-- Number of crop points currently chosen (0 to 2)
7local points = {}
8-- True if in cropping selection mode
9local cropping = false
10-- Original value of osc property
11local osc_prop = false
12
13-- Helper that converts two points to top-left and bottom-right
14local swizzle_points = function (p1, p2)
15 if p1.x > p2.x then p1.x, p2.x = p2.x, p1.x end
16 if p1.y > p2.y then p1.y, p2.y = p2.y, p1.y end
17end
18
19local clamp = function (val, min, max)
20 assert(min <= max)
21 if val < min then return min end
22 if val > max then return max end
23 return val
24end
25
26local video_space_from_screen_space = function (ssp)
27 -- Video native dimensions and screen size
28 local vid_w = mp.get_property("width")
29 local vid_h = mp.get_property("height")
30 local osd_w = mp.get_property("osd-width")
31 local osd_h = mp.get_property("osd-height")
32
33 -- Factor by which the video is scaled to fit the screen
34 local scale = math.min(osd_w/vid_w, osd_h/vid_h)
35
36 -- Size video takes up in screen
37 local vid_sw, vid_sh = scale*vid_w, scale*vid_h
38
39 -- Video offset within screen
40 local off_x = math.floor((osd_w - vid_sw)/2)
41 local off_y = math.floor((osd_h - vid_sh)/2)
42
43 local vsp = {}
44
45 -- Move the point to within the video
46 vsp.x = clamp(ssp.x, off_x, off_x + vid_sw)
47 vsp.y = clamp(ssp.y, off_y, off_y + vid_sh)
48
49 -- Convert screen-space to video-space
50 vsp.x = math.floor((vsp.x - off_x) / scale)
51 vsp.y = math.floor((vsp.y - off_y) / scale)
52
53 return vsp
54end
55
56local screen_space_from_video_space = function (vsp)
57 -- Video native dimensions and screen size
58 local vid_w = mp.get_property("width")
59 local vid_h = mp.get_property("height")
60 local osd_w = mp.get_property("osd-width")
61 local osd_h = mp.get_property("osd-height")
62
63 -- Factor by which the video is scaled to fit the screen
64 local scale = math.min(osd_w/vid_w, osd_h/vid_h)
65
66 -- Size video takes up in screen
67 local vid_sw, vid_sh = scale*vid_w, scale*vid_h
68
69 -- Video offset within screen
70 local off_x = math.floor((osd_w - vid_sw)/2)
71 local off_y = math.floor((osd_h - vid_sh)/2)
72
73 local ssp = {}
74 ssp.x = vsp.x * scale + off_x
75 ssp.y = vsp.y * scale + off_y
76 return ssp
77end
78
79-- Wrapper that converts RRGGBB / RRGGBBAA to ASS format
80local ass_set_color = function (idx, color)
81 assert(color:len() == 8 or color:len() == 6)
82 local ass = ""
83
84 -- Set alpha value (if present)
85 if color:len() == 8 then
86 local alpha = 0xff - tonumber(color:sub(7, 8), 16)
87 ass = ass .. string.format("\\%da&H%X&", idx, alpha)
88 end
89
90 -- Swizzle RGB to BGR and build ASS string
91 color = color:sub(5, 6) .. color:sub(3, 4) .. color:sub(1, 2)
92 return "{" .. ass .. string.format("\\%dc&H%s&", idx, color) .. "}"
93end
94
95local draw_rect = function (p1, p2)
96 local osd_w, osd_h = mp.get_property("osd-width"), mp.get_property("osd-height")
97
98 ass = assdraw.ass_new()
99
100 -- Draw overlay over surrounding unselected region
101
102 ass:draw_start()
103 ass:pos(0, 0)
104
105 ass:append(ass_set_color(1, "000000aa"))
106 ass:append(ass_set_color(3, "00000000"))
107
108 local l = math.min(p1.x, p2.x)
109 local r = math.max(p1.x, p2.x)
110 local u = math.min(p1.y, p2.y)
111 local d = math.max(p1.y, p2.y)
112
113 ass:rect_cw(0, 0, l, osd_h)
114 ass:rect_cw(r, 0, osd_w, osd_h)
115 ass:rect_cw(l, 0, r, u)
116 ass:rect_cw(l, d, r, osd_h)
117
118 ass:draw_stop()
119
120 -- Draw border around selected region
121
122 ass:new_event()
123 ass:draw_start()
124 ass:pos(0, 0)
125
126 ass:append(ass_set_color(1, "00000000"))
127 ass:append(ass_set_color(3, "000000ff"))
128 ass:append("{\\bord2}")
129
130 ass:rect_cw(p1.x, p1.y, p2.x, p2.y)
131
132 ass:draw_stop()
133
134 mp.set_osd_ass(osd_w, osd_h, ass.text)
135end
136
137local draw_fill = function ()
138 local osd_w, osd_h = mp.get_property("osd-width"), mp.get_property("osd-height")
139
140 ass = assdraw.ass_new()
141 ass:draw_start()
142 ass:pos(0, 0)
143
144 ass:append(ass_set_color(1, "000000aa"))
145 ass:append(ass_set_color(3, "00000000"))
146 ass:rect_cw(0, 0, osd_w, osd_h)
147
148 ass:draw_stop()
149 mp.set_osd_ass(osd_w, osd_h, ass.text)
150end
151
152local draw_clear = function ()
153 local osd_w, osd_h = mp.get_property("osd-width"), mp.get_property("osd-height")
154 mp.set_osd_ass(osd_w, osd_h, "")
155end
156
157local draw_cropper = function ()
158 if #points == 1 then
159 local p1 = screen_space_from_video_space(points[1])
160 local p2 = {}
161 p2.x, p2.y = mp.get_mouse_pos()
162 draw_rect(p1, p2)
163 end
164end
165
166local uncrop = function ()
167 mp.command("no-osd vf del @" .. script_name .. ":crop")
168end
169
170local crop = function(p1, p2)
171 swizzle_points(p1, p2)
172
173 local w = p2.x - p1.x
174 local h = p2.y - p1.y
175 local ok, err = mp.command(string.format(
176 "no-osd vf add @%s:crop=%s:%s:%s:%s", script_name, w, h, p1.x, p1.y))
177
178 if not ok then
179 mp.osd_message("Cropping failed")
180 points = {}
181 end
182end
183
184local easycrop_stop = function ()
185 mp.set_property("osc", osc_prop)
186 cropping = false
187 mp.remove_key_binding("easycrop_mouse_btn0")
188 draw_clear()
189end
190
191local mouse_btn0_cb = function ()
192 if not cropping then
193 return
194 end
195
196 local mx, my = mp.get_mouse_pos()
197 table.insert(points, video_space_from_screen_space({ x = mx, y = my }))
198
199 if #points == 2 then
200 crop(points[1], points[2])
201 easycrop_stop()
202 end
203end
204
205local easycrop_start = function ()
206 -- Cropping requires swdec or hwdec with copy-back
207 local hwdec = mp.get_property("hwdec-current")
208 if hwdec == nil then
209 return mp.msg.error("Cannot determine current hardware decoder mode")
210 end
211 -- Check whitelist of ok values
212 local valid_hwdec = {
213 ["no"] = true, -- software decoding
214 -- Taken from mpv manual
215 ["videotoolbox-co"] = true,
216 ["vaapi-copy"] = true,
217 ["dxva2-copy"] = true,
218 ["d3d11va-copy"] = true,
219 ["mediacodec"] = true
220 }
221 if not valid_hwdec[hwdec] then
222 return mp.osd_message("Cropping requires swdec or hwdec with copy-back (see mpv manual)")
223 end
224
225 -- Just clear the current crop and return, if there is one
226 if #points ~= 0 then
227 uncrop()
228 points = {}
229 return
230 end
231
232 -- Hide OSC
233 osc_prop = mp.get_property("osc")
234 mp.set_property("osc", "no")
235
236 cropping = true
237 mp.add_forced_key_binding("mouse_btn0", "easycrop_mouse_btn0", mouse_btn0_cb)
238 draw_fill()
239end
240
241local easycrop_activate = function ()
242 if cropping then
243 easycrop_stop()
244 else
245 easycrop_start()
246 end
247end
248
249mp.add_key_binding("mouse_move", draw_cropper)
250mp.observe_property("osd-width", "native", draw_cropper)
251mp.observe_property("osd-height", "native", draw_cropper)
252
253mp.add_key_binding("c", "easy_crop", easycrop_activate)
254
diff --git a/modules/ryan-config/base-system.scm b/modules/ryan-config/base-system.scm
index 5034f4e..ac1ac79 100644
--- a/modules/ryan-config/base-system.scm
+++ b/modules/ryan-config/base-system.scm
@@ -159,7 +159,7 @@
159 "wireplumber" 159 "wireplumber"
160 "wireshark" 160 "wireshark"
161 "zsh")) 161 "zsh"))
162 (list my-ca-certs swaylock-effects-new xdg-desktop-portal-hyprland-ryan virt-manager-ovmf bluez-ryan blueman-ryan swayidle-new waybar-new) 162 (list my-ca-certs swaylock-effects-new xdg-desktop-portal-hyprland-ryan virt-manager-ovmf bluez-ryan blueman-ryan swayidle-new waybar-new hyprlock)
163 %my-base-packages )) 163 %my-base-packages ))
164 164
165 ;; Below is the list of system services. To search for available 165 ;; Below is the list of system services. To search for available
diff --git a/modules/ryan-packages/wm.scm b/modules/ryan-packages/wm.scm
index 474596a..ada3adf 100644
--- a/modules/ryan-packages/wm.scm
+++ b/modules/ryan-packages/wm.scm
@@ -93,38 +93,42 @@
93 #~(list "-Dspectre=disabled"))) 93 #~(list "-Dspectre=disabled")))
94 (outputs '("out")))) 94 (outputs '("out"))))
95 95
96
97(define-public hyprlock 96(define-public hyprlock
98 (package 97 (let ((commit "d9a6229434fba475ea42b634ee2f03919236798d")
99 (name "hyprlock") 98 (revision "1"))
100 (version "0.3.0") 99 (package
101 (source 100 (name "hyprlock")
102 (origin 101 (version (git-version "0.3.0" revision commit))
103 (method git-fetch) 102 (source
104 (uri (git-reference 103 (origin
105 (url "https://github.com/hyprwm/hyprlock") 104 (method git-fetch)
106 (commit (string-append "v" version)))) 105 (uri (git-reference
107 (file-name (git-file-name name version)) 106 (url "https://github.com/hyprwm/hyprlock")
108 (sha256 107 (commit commit)))
109 (base32 "0w2a25hivn8xd8p05vc9xg57rd9siv12dwmr4skpqx4dcmxxbg5d")))) 108 (file-name (git-file-name name version))
110 (build-system cmake-build-system) 109 (sha256
111 (native-inputs 110 (base32 "19cg8vj4sgz5pxib9m08af1lilay9bckjhlr6h333s014l7y09sw"))))
112 (list gcc-13 111 (build-system cmake-build-system)
113 pkg-config 112 (arguments
114 mesa-headers 113 `(#:tests? #f))
115 wayland)) 114 (native-inputs
116 (inputs 115 (list gcc-13
117 (list cairo 116 pkg-config
118 pango 117 mesa-headers
119 libxkbcommon 118 wayland))
120 libdrm 119 (inputs
121 hyprlang 120 (list cairo
122 mesa 121 pango
123 wayland-protocols 122 libxkbcommon
124 linux-pam)) 123 hyprlang
125 (home-page "https://github.com/hyprwm/hyprlock") 124 mesa
126 (license license:bsd-3) 125 libdrm
127 (synopsis "Screen locker for Hyprland") 126 libglvnd
128 (description "Screen locker for hyprland."))) 127 wayland-protocols
128 linux-pam))
129 (home-page "https://github.com/hyprwm/hyprlock")
130 (license license:bsd-3)
131 (synopsis "Screen locker for Hyprland")
132 (description "Screen locker for hyprland."))))
129 133
130hyprlock 134hyprlock