waffles: screen snip
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
|
||||
<path d="M17.5 12C20.5376 12 23 14.4624 23 17.5C23 20.5376 20.5376 23 17.5 23C14.4624 23 12 20.5376 12 17.5C12 14.4624 14.4624 12 17.5 12ZM21 8.5L21.0012 12.0226C19.9907 11.3753 18.7892 11 17.5 11C13.9101 11 11 13.9101 11 17.5C11 18.7892 11.3753 19.9907 12.0226 21.0012L6.25 21C4.45507 21 3 19.5449 3 17.75V8.5H21ZM17.5 14L17.4101 14.0081C17.206 14.0451 17.0451 14.206 17.0081 14.4101L17 14.5V17H14.5L14.4101 17.0081C14.206 17.0451 14.0451 17.206 14.0081 17.4101L14 17.5L14.0081 17.5899C14.0451 17.794 14.206 17.9549 14.4101 17.9919L14.5 18H17V20.5L17.0081 20.5899C17.0451 20.794 17.206 20.9549 17.4101 20.9919L17.5 21L17.5899 20.9919C17.794 20.9549 17.9549 20.794 17.9919 20.5899L18 20.5V18H20.5L20.5899 17.9919C20.794 17.9549 20.9549 17.794 20.9919 17.5899L21 17.5L20.9919 17.4101C20.9549 17.206 20.794 17.0451 20.5899 17.0081L20.5 17H18V14.5L17.9919 14.4101C17.9549 14.206 17.794 14.0451 17.5899 14.0081L17.5 14ZM17.75 3C19.5449 3 21 4.45507 21 6.25V7H3V6.25C3 4.45507 4.45507 3 6.25 3H17.75Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
|
||||
<path d="M17.5 12C20.5376 12 23 14.4624 23 17.5C23 20.5376 20.5376 23 17.5 23C14.4624 23 12 20.5376 12 17.5C12 14.4624 14.4624 12 17.5 12ZM17.75 3C19.5449 3 21 4.45507 21 6.25L21.0012 12.0226C20.5378 11.7258 20.0342 11.4861 19.5004 11.3136L19.5 8.5H4.5V17.75C4.5 18.7165 5.2835 19.5 6.25 19.5L11.3136 19.5004C11.4861 20.0342 11.7258 20.5378 12.0226 21.0012L6.25 21C4.45507 21 3 19.5449 3 17.75V6.25C3 4.45507 4.45507 3 6.25 3H17.75ZM17.5 14L17.4101 14.0081C17.206 14.0451 17.0451 14.206 17.0081 14.4101L17 14.5V17H14.5L14.4101 17.0081C14.206 17.0451 14.0451 17.206 14.0081 17.4101L14 17.5L14.0081 17.5899C14.0451 17.794 14.206 17.9549 14.4101 17.9919L14.5 18H17V20.5L17.0081 20.5899C17.0451 20.794 17.206 20.9549 17.4101 20.9919L17.5 21L17.5899 20.9919C17.794 20.9549 17.9549 20.794 17.9919 20.5899L18 20.5V18H20.5L20.5899 17.9919C20.794 17.9549 20.9549 17.794 20.9919 17.5899L21 17.5L20.9919 17.4101C20.9549 17.206 20.794 17.0451 20.5899 17.0081L20.5 17H18V14.5L17.9919 14.4101C17.9549 14.206 17.794 14.0451 17.5899 14.0081L17.5 14ZM17.75 4.5H6.25C5.2835 4.5 4.5 5.2835 4.5 6.25V7H19.5V6.25C19.5 5.2835 18.7165 4.5 17.75 4.5Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.925 2.503a2.25 2.25 0 0 1 1.94 1.11L16.679 5h2.071A3.25 3.25 0 0 1 22 8.25v9.5A3.25 3.25 0 0 1 18.75 21H5.25A3.25 3.25 0 0 1 2 17.75v-9.5A3.25 3.25 0 0 1 5.25 5h2.08l.875-1.424a2.25 2.25 0 0 1 1.917-1.073h3.803ZM12 8a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9Zm0 1.5a3 3 0 1 1 0 6 3 3 0 0 1 0-6Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 420 B |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.925 2.503a2.25 2.25 0 0 1 1.94 1.11L16.679 5h2.071A3.25 3.25 0 0 1 22 8.25v9.5A3.25 3.25 0 0 1 18.75 21H5.25A3.25 3.25 0 0 1 2 17.75v-9.5A3.25 3.25 0 0 1 5.25 5h2.08l.875-1.424a2.25 2.25 0 0 1 1.917-1.073h3.803Zm0 1.5h-3.803a.75.75 0 0 0-.574.268l-.065.09L8.39 6.141a.75.75 0 0 1-.639.358h-2.5A1.75 1.75 0 0 0 3.5 8.25v9.5c0 .966.784 1.75 1.75 1.75h13.5a1.75 1.75 0 0 0 1.75-1.75v-9.5a1.75 1.75 0 0 0-1.75-1.75h-2.5a.75.75 0 0 1-.647-.37l-1.032-1.757a.75.75 0 0 0-.646-.37ZM12 8a4.5 4.5 0 1 1 0 9 4.5 4.5 0 0 1 0-9Zm0 1.5a3 3 0 1 0 0 6 3 3 0 0 0 0-6Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 682 B |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
|
||||
<path d="M7 15.5C7 16.2797 7.59489 16.9204 8.35554 16.9931L8.5 17H21C21.5523 17 22 17.4477 22 18C22 18.5128 21.614 18.9355 21.1166 18.9933L21 19H19V21C19 21.5523 18.5523 22 18 22C17.4872 22 17.0645 21.614 17.0067 21.1166L17 21V19H8.5C6.63144 19 5.10487 17.5357 5.00518 15.692L5 15.5V7H3C2.44772 7 2 6.55228 2 6C2 5.48716 2.38604 5.06449 2.88338 5.00673L3 5H5V3C5 2.44772 5.44772 2 6 2C6.51284 2 6.93551 2.38604 6.99327 2.88338L7 3V15.5ZM8 5H15.5C17.3686 5 18.8951 6.46428 18.9948 8.30796L19 8.5V16H17V8.5C17 7.7203 16.4051 7.07955 15.6445 7.00687L15.5 7H8V5Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 721 B |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
|
||||
<path d="M21.25 17C21.6642 17 22 17.3358 22 17.75C22 18.1297 21.7178 18.4435 21.3518 18.4932L21.25 18.5H18.5V21.25C18.5 21.6642 18.1642 22 17.75 22C17.3703 22 17.0565 21.7178 17.0068 21.3518L17 21.25V18.5H8.75C7.01697 18.5 5.60075 17.1435 5.50514 15.4344L5.5 15.25L5.499 7H2.75C2.33579 7 2 6.66421 2 6.25C2 5.8703 2.28215 5.55651 2.64823 5.50685L2.75 5.5H5.499L5.5 2.75C5.5 2.33579 5.83579 2 6.25 2C6.6297 2 6.94349 2.28215 6.99315 2.64823L7 2.75L6.999 5.5H7V7H6.999L7 15.25C7 16.1682 7.70711 16.9212 8.60647 16.9942L8.75 17H21.25ZM8 5.5H15.25C16.983 5.5 18.3992 6.85646 18.4949 8.56558L18.5 8.75V16H17V8.75C17 7.83183 16.2929 7.07881 15.3935 7.0058L15.25 7H8V5.5Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 827 B |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m11.557 13.646-.083.071-6.927 6.8a3.234 3.234 0 0 0 1.703.481h4.914l.356-1.423c.162-.648.497-1.24.97-1.712l2.11-2.11-2.075-2.036-.094-.078a.75.75 0 0 0-.873.007Zm4.946-5.394a.752.752 0 1 0-1.504 0 .752.752 0 0 0 1.504 0Zm-.843 6.441-2.085-2.046-.128-.117a2.25 2.25 0 0 0-2.888-.006l-.136.123-6.938 6.81A3.234 3.234 0 0 1 3 17.75v-11.5A3.25 3.25 0 0 1 6.25 3h11.499a3.25 3.25 0 0 1 3.25 3.25v4.761a3.279 3.279 0 0 0-2.608.95l-2.731 2.732ZM13.5 8.252a2.252 2.252 0 1 0 4.503 0 2.252 2.252 0 0 0-4.504 0Zm5.598 4.417-5.901 5.901a2.685 2.685 0 0 0-.707 1.248l-.457 1.83c-.2.797.522 1.518 1.318 1.319l1.83-.458a2.685 2.685 0 0 0 1.248-.706L22.33 15.9a2.286 2.286 0 0 0-3.233-3.232Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 804 B |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20.998 6.25A3.25 3.25 0 0 0 17.748 3H6.25A3.25 3.25 0 0 0 3 6.25v11.499a3.25 3.25 0 0 0 3.25 3.25h4.914l.356-1.424.02-.076H6.25c-.204 0-.4-.035-.582-.1l5.807-5.685.083-.07a.75.75 0 0 1 .966.07l2.079 2.036 1.06-1.06-2.09-2.048-.128-.116a2.25 2.25 0 0 0-3.02.116l-5.822 5.7a1.746 1.746 0 0 1-.103-.593v-11.5c0-.966.783-1.75 1.75-1.75h11.499c.966 0 1.75.784 1.75 1.75v4.983c.478-.19.993-.264 1.5-.22V6.25Zm-3.495 2.502a2.252 2.252 0 1 0-4.504 0 2.252 2.252 0 0 0 4.504 0Zm-3.004 0a.752.752 0 1 1 1.504 0 .752.752 0 0 1-1.504 0Zm4.6 3.917-5.902 5.901a2.685 2.685 0 0 0-.707 1.248l-.457 1.83c-.2.797.522 1.518 1.318 1.319l1.83-.458a2.685 2.685 0 0 0 1.248-.706L22.33 15.9a2.286 2.286 0 0 0-3.233-3.232Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 826 B |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M2.747 15a.75.75 0 0 1 .743.648l.007.102v3.502l.007.128a1.25 1.25 0 0 0 1.115 1.116l.128.006h3.5l.102.007a.75.75 0 0 1 0 1.486l-.102.007h-3.5l-.167-.005a2.75 2.75 0 0 1-2.578-2.57l-.005-.175V15.75l.007-.102A.75.75 0 0 1 2.747 15Zm18.5 0a.75.75 0 0 1 .743.648l.007.102v3.502a2.75 2.75 0 0 1-2.582 2.745l-.168.005h-3.5a.75.75 0 0 1-.102-1.493l.102-.007h3.5a1.25 1.25 0 0 0 1.244-1.122l.006-.128V15.75a.75.75 0 0 1 .75-.75ZM12 15a1 1 0 0 1 .117 1.993L12 17H8a1 1 0 0 1-.116-1.993L8 15h4Zm4-4a1 1 0 0 1 .117 1.993L16 13H8a1 1 0 0 1-.116-1.993L8 11h8ZM8.247 2a.75.75 0 0 1 .102 1.493l-.102.007h-3.5a1.25 1.25 0 0 0-1.243 1.122l-.007.128v3.502a.75.75 0 0 1-1.493.102l-.007-.102V4.75A2.75 2.75 0 0 1 4.58 2.005L4.747 2h3.5Zm11 0 .168.005a2.75 2.75 0 0 1 2.577 2.57l.005.175v3.502l-.007.102a.75.75 0 0 1-1.486 0l-.007-.102V4.75l-.006-.128a1.25 1.25 0 0 0-1.116-1.116l-.128-.006h-3.5l-.102-.007a.75.75 0 0 1 0-1.486L15.747 2h3.5ZM16 7a1 1 0 0 1 .117 1.993L16 9H8a1 1 0 0 1-.116-1.993L8 7h8Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M2.747 15a.75.75 0 0 1 .743.648l.007.102v3.502l.007.128a1.25 1.25 0 0 0 1.115 1.116l.128.006h3.5l.102.007a.75.75 0 0 1 0 1.486l-.102.007h-3.5l-.167-.005a2.75 2.75 0 0 1-2.578-2.57l-.005-.175V15.75l.007-.102A.75.75 0 0 1 2.747 15Zm18.5 0a.75.75 0 0 1 .743.648l.007.102v3.502a2.75 2.75 0 0 1-2.582 2.745l-.168.005h-3.5a.75.75 0 0 1-.102-1.493l.102-.007h3.5a1.25 1.25 0 0 0 1.244-1.122l.006-.128V15.75a.75.75 0 0 1 .75-.75Zm-8.992.5a.75.75 0 0 1 .102 1.493l-.102.007H7.75a.75.75 0 0 1-.102-1.493l.102-.007h4.505Zm3.995-4.25a.75.75 0 0 1 .102 1.493l-.102.007h-8.5a.75.75 0 0 1-.102-1.493l.102-.007h8.5ZM8.247 2a.75.75 0 0 1 .102 1.493l-.102.007h-3.5a1.25 1.25 0 0 0-1.243 1.122l-.007.128v3.502a.75.75 0 0 1-1.493.102l-.007-.102V4.75A2.75 2.75 0 0 1 4.58 2.005L4.747 2h3.5Zm11 0 .168.005a2.75 2.75 0 0 1 2.577 2.57l.005.175v3.502l-.007.102a.75.75 0 0 1-1.486 0l-.007-.102V4.75l-.006-.128a1.25 1.25 0 0 0-1.116-1.116l-.128-.006h-3.5l-.102-.007a.75.75 0 0 1 0-1.486L15.747 2h3.5ZM16.25 7a.75.75 0 0 1 .102 1.493l-.102.007h-8.5a.75.75 0 0 1-.102-1.493L7.75 7h8.5Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
|
||||
<path d="M3 6.5C3 4.567 4.567 3 6.5 3H9C9.55228 3 10 3.44772 10 4C10 4.55228 9.55228 5 9 5H6.5C5.67157 5 5 5.67157 5 6.5V9C5 9.55229 4.55228 10 4 10C3.44772 10 3 9.55229 3 9V6.5ZM21 17.5C21 19.433 19.433 21 17.5 21H15C14.4477 21 14 20.5523 14 20C14 19.4477 14.4477 19 15 19L17.5 19C18.3284 19 19 18.3284 19 17.5V15C19 14.4477 19.4477 14 20 14C20.5523 14 21 14.4477 21 15V17.5ZM21 6.5C21 4.567 19.433 3 17.5 3H15C14.4477 3 14 3.44772 14 4C14 4.55228 14.4477 5 15 5H17.5C18.3284 5 19 5.67157 19 6.5V9C19 9.55228 19.4477 10 20 10C20.5523 10 21 9.55229 21 9V6.5ZM6.5 21C4.567 21 3 19.433 3 17.5V15C3 14.4477 3.44772 14 4 14C4.55229 14 5 14.4477 5 15L5 17.5C5 18.3284 5.67157 19 6.5 19H9C9.55229 19 10 19.4477 10 20C10 20.5523 9.55228 21 9 21H6.5ZM12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15ZM7.5 8.75C8.19036 8.75 8.75 8.19036 8.75 7.5C8.75 6.80964 8.19036 6.25 7.5 6.25C6.80964 6.25 6.25 6.80964 6.25 7.5C6.25 8.19036 6.80964 8.75 7.5 8.75Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
|
||||
<path d="M17.75 3C19.5449 3 21 4.45508 21 6.25V9.25C21 9.66421 20.6642 10 20.25 10C19.8358 10 19.5 9.66421 19.5 9.25V6.25C19.5 5.2835 18.7165 4.5 17.75 4.5L14.75 4.5C14.3358 4.5 14 4.16421 14 3.75C14 3.33579 14.3358 3 14.75 3H17.75ZM6.25 3C4.45507 3 3 4.45507 3 6.25V9.25C3 9.66421 3.33579 10 3.75 10C4.16421 10 4.5 9.66421 4.5 9.25V6.25C4.5 5.2835 5.2835 4.5 6.25 4.5H9.25C9.66421 4.5 10 4.16421 10 3.75C10 3.33579 9.66421 3 9.25 3H6.25ZM17.75 21C19.5449 21 21 19.5449 21 17.75V14.75C21 14.3358 20.6642 14 20.25 14C19.8358 14 19.5 14.3358 19.5 14.75V17.75C19.5 18.7165 18.7165 19.5 17.75 19.5H14.75C14.3358 19.5 14 19.8358 14 20.25C14 20.6642 14.3358 21 14.75 21H17.75ZM3 17.75C3 19.5449 4.45507 21 6.25 21H9.25C9.66421 21 10 20.6642 10 20.25C10 19.8358 9.66421 19.5 9.25 19.5H6.25C5.2835 19.5 4.5 18.7165 4.5 17.75L4.5 14.75C4.5 14.3358 4.16421 14 3.75 14C3.33579 14 3 14.3358 3 14.75L3 17.75ZM12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15ZM12 13.5C11.1716 13.5 10.5 12.8284 10.5 12C10.5 11.1716 11.1716 10.5 12 10.5C12.8284 10.5 13.5 11.1716 13.5 12C13.5 12.8284 12.8284 13.5 12 13.5ZM7.5 8.5C8.05229 8.5 8.5 8.05229 8.5 7.5C8.5 6.94772 8.05229 6.5 7.5 6.5C6.94772 6.5 6.5 6.94772 6.5 7.5C6.5 8.05229 6.94772 8.5 7.5 8.5Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M16 16.25a3.25 3.25 0 0 1-3.25 3.25h-7.5A3.25 3.25 0 0 1 2 16.25v-8.5A3.25 3.25 0 0 1 5.25 4.5h7.5A3.25 3.25 0 0 1 16 7.75v8.5Zm5.762-10.357a1 1 0 0 1 .238.648v10.918a1 1 0 0 1-1.648.762L17 15.37V8.628l3.352-2.849a1 1 0 0 1 1.41.114Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 361 B |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.75 4.5A3.25 3.25 0 0 1 17 7.75v.173l3.864-2.318A.75.75 0 0 1 22 6.248V17.75a.75.75 0 0 1-1.136.643L17 16.075v.175a3.25 3.25 0 0 1-3.25 3.25h-8.5A3.25 3.25 0 0 1 2 16.25v-8.5A3.25 3.25 0 0 1 5.25 4.5h8.5Zm0 1.5h-8.5A1.75 1.75 0 0 0 3.5 7.75v8.5c0 .966.784 1.75 1.75 1.75h8.5a1.75 1.75 0 0 0 1.75-1.75v-8.5A1.75 1.75 0 0 0 13.75 6Zm6.75 1.573L17 9.674v4.651l3.5 2.1V7.573Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 502 B |
@@ -0,0 +1,81 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
pragma Singleton
|
||||
import qs.modules.common
|
||||
import qs.modules.common.utils
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.services
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Qt.labs.synchronizer
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
enum Action {
|
||||
Copy,
|
||||
Edit,
|
||||
Search,
|
||||
CharRecognition,
|
||||
Record,
|
||||
RecordWithSound
|
||||
}
|
||||
|
||||
property string imageSearchEngineBaseUrl: Config.options.search.imageSearch.imageSearchEngineBaseUrl
|
||||
property string fileUploadApiEndpoint: "https://uguu.se/upload"
|
||||
|
||||
function getCommand(x, y, width, height, screenshotPath, action, saveDir = "") {
|
||||
// Set command for action
|
||||
const rx = Math.round(x);
|
||||
const ry = Math.round(y);
|
||||
const rw = Math.round(width);
|
||||
const rh = Math.round(height);
|
||||
const cropBase = `magick ${StringUtils.shellSingleQuoteEscape(screenshotPath)} `
|
||||
+ `-crop ${rw}x${rh}+${rx}+${ry}`
|
||||
const cropToStdout = `${cropBase} -`
|
||||
const cropInPlace = `${cropBase} '${StringUtils.shellSingleQuoteEscape(screenshotPath)}'`
|
||||
const cleanup = `rm '${StringUtils.shellSingleQuoteEscape(screenshotPath)}'`
|
||||
const slurpRegion = `${rx},${ry} ${rw}x${rh}`
|
||||
const uploadAndGetUrl = (filePath) => {
|
||||
return `curl -sF files[]=@'${StringUtils.shellSingleQuoteEscape(filePath)}' ${root.fileUploadApiEndpoint} | jq -r '.files[0].url'`
|
||||
}
|
||||
const annotationCommand = `${Config.options.regionSelector.annotation.useSatty ? "satty" : "swappy"} -f -`;
|
||||
switch (action) {
|
||||
case ScreenshotAction.Action.Copy:
|
||||
if (saveDir === "") {
|
||||
// not saving the screenshot, just copy to clipboard
|
||||
return ["bash", "-c", `${cropToStdout} | wl-copy && ${cleanup}`]
|
||||
break;
|
||||
}
|
||||
return [
|
||||
"bash", "-c",
|
||||
`mkdir -p '${StringUtils.shellSingleQuoteEscape(saveDir)}' && \
|
||||
saveFileName="screenshot-$(date '+%Y-%m-%d_%H.%M.%S').png" && \
|
||||
savePath="${saveDir}/$saveFileName" && \
|
||||
${cropToStdout} | tee >(wl-copy) > "$savePath" && \
|
||||
${cleanup}`
|
||||
]
|
||||
|
||||
break;
|
||||
case ScreenshotAction.Action.Edit:
|
||||
return ["bash", "-c", `${cropToStdout} | ${annotationCommand} && ${cleanup}`]
|
||||
break;
|
||||
case ScreenshotAction.Action.Search:
|
||||
return ["bash", "-c", `${cropInPlace} && xdg-open "${root.imageSearchEngineBaseUrl}$(${uploadAndGetUrl(screenshotPath)})" && ${cleanup}`]
|
||||
break;
|
||||
case ScreenshotAction.Action.CharRecognition:
|
||||
return ["bash", "-c", `${cropInPlace} && tesseract '${StringUtils.shellSingleQuoteEscape(screenshotPath)}' stdout -l $(tesseract --list-langs | awk 'NR>1{print $1}' | tr '\\n' '+' | sed 's/\\+$/\\n/') | wl-copy && ${cleanup}`]
|
||||
break;
|
||||
case ScreenshotAction.Action.Record:
|
||||
return ["bash", "-c", `${Directories.recordScriptPath} --region '${slurpRegion}'`]
|
||||
break;
|
||||
case ScreenshotAction.Action.RecordWithSound:
|
||||
return ["bash", "-c", `${Directories.recordScriptPath} --region '${slurpRegion}' --sound`]
|
||||
break;
|
||||
default:
|
||||
console.warn("[Region Selector] Unknown snip action, skipping snip.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
|
||||
Process {
|
||||
id: screenshotProc
|
||||
running: true
|
||||
property string screenshotDir: Directories.screenshotTemp
|
||||
required property ShellScreen screen
|
||||
property string screenshotPath: `${screenshotDir}/image-${screen.name}`
|
||||
command: ["bash", "-c", `mkdir -p '${StringUtils.shellSingleQuoteEscape(screenshotDir)}' && grim -o '${StringUtils.shellSingleQuoteEscape(screen.name)}' '${StringUtils.shellSingleQuoteEscape(screenshotPath)}'`]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import QtQuick
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
|
||||
Canvas {
|
||||
id: root
|
||||
property color color: "#ffffff"
|
||||
property int dashLength: 6
|
||||
property int gapLength: 4
|
||||
property int borderWidth: 1
|
||||
|
||||
onDashLengthChanged: requestPaint()
|
||||
onGapLengthChanged: requestPaint()
|
||||
onWidthChanged: requestPaint()
|
||||
onHeightChanged: requestPaint()
|
||||
onPaint: {
|
||||
var ctx = getContext("2d");
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.save();
|
||||
ctx.strokeStyle = root.color;
|
||||
ctx.lineWidth = root.borderWidth;
|
||||
if (root.gapLength > 0) {
|
||||
ctx.setLineDash([root.dashLength, root.gapLength]); // Set dash pattern
|
||||
}
|
||||
ctx.strokeRect(root.borderWidth / 2, root.borderWidth / 2, width - root.borderWidth, height - root.borderWidth); // Draw it
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,16 @@ MouseArea {
|
||||
property bool automaticallyReset: true
|
||||
readonly property real dragDiffX: _dragDiffX
|
||||
readonly property real dragDiffY: _dragDiffY
|
||||
property real startX: 0
|
||||
property real startY: 0
|
||||
property real regionTopLeftX: Math.min(startX, startX + _dragDiffX)
|
||||
property real regionTopLeftY: Math.min(startY, startY + _dragDiffY)
|
||||
property real regionWidth: Math.abs(_dragDiffX)
|
||||
property real regionHeight: Math.abs(_dragDiffY)
|
||||
|
||||
signal dragPressed(diffX: real, diffY: real)
|
||||
signal dragReleased(diffX: real, diffY: real)
|
||||
|
||||
property real startX: 0
|
||||
property real startY: 0
|
||||
property bool dragging: false
|
||||
property real _dragDiffX: 0
|
||||
property real _dragDiffY: 0
|
||||
|
||||
@@ -12,19 +12,30 @@ Item {
|
||||
required property var tabButtonList
|
||||
|
||||
function incrementCurrentIndex() {
|
||||
tabBar.incrementCurrentIndex()
|
||||
tabBar.incrementCurrentIndex();
|
||||
}
|
||||
function decrementCurrentIndex() {
|
||||
tabBar.decrementCurrentIndex()
|
||||
tabBar.decrementCurrentIndex();
|
||||
}
|
||||
function setCurrentIndex(index) {
|
||||
tabBar.setCurrentIndex(index)
|
||||
tabBar.setCurrentIndex(index);
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
implicitWidth: contentItem.implicitWidth
|
||||
implicitHeight: 40
|
||||
|
||||
property Component delegate: ToolbarTabButton {
|
||||
required property int index
|
||||
required property var modelData
|
||||
current: index == root.currentIndex
|
||||
text: modelData.name
|
||||
materialSymbol: modelData.icon
|
||||
onClicked: {
|
||||
root.setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: contentItem
|
||||
z: 1
|
||||
@@ -33,16 +44,7 @@ Item {
|
||||
|
||||
Repeater {
|
||||
model: root.tabButtonList
|
||||
delegate: ToolbarTabButton {
|
||||
required property int index
|
||||
required property var modelData
|
||||
current: index == root.currentIndex
|
||||
text: modelData.name
|
||||
materialSymbol: modelData.icon
|
||||
onClicked: {
|
||||
root.setCurrentIndex(index)
|
||||
}
|
||||
}
|
||||
delegate: root.delegate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,23 +78,23 @@ Item {
|
||||
z: 2
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onWheel: (event) => {
|
||||
onWheel: event => {
|
||||
if (event.angleDelta.y < 0) {
|
||||
root.incrementCurrentIndex();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
root.decrementCurrentIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TabBar doesn't allow tabs to be of different sizes. Literally unusable.
|
||||
// TabBar doesn't allow tabs to be of different sizes. That's what I thought...
|
||||
// We use it only for the logic and draw stuff manually
|
||||
TabBar {
|
||||
id: tabBar
|
||||
z: -1
|
||||
background: null
|
||||
Repeater { // This is to fool the TabBar that it has tabs so it does the indices properly
|
||||
Repeater {
|
||||
// This is to fool the TabBar that it has tabs so it does the indices properly
|
||||
model: root.tabButtonList.length
|
||||
delegate: TabButton {
|
||||
background: null
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import qs.modules.common
|
||||
import qs.modules.common.utils
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.services
|
||||
@@ -32,14 +33,8 @@ PanelWindow {
|
||||
property var action: RegionSelection.SnipAction.Copy
|
||||
property var selectionMode: RegionSelection.SelectionMode.RectCorners
|
||||
signal dismiss()
|
||||
|
||||
property string saveScreenshotDir: Config.options.screenSnip.savePath !== ""
|
||||
? Config.options.screenSnip.savePath
|
||||
: ""
|
||||
|
||||
property string screenshotDir: Directories.screenshotTemp
|
||||
property string imageSearchEngineBaseUrl: Config.options.search.imageSearch.imageSearchEngineBaseUrl
|
||||
property string fileUploadApiEndpoint: "https://uguu.se/upload"
|
||||
property color overlayColor: "#88111111"
|
||||
property color brightText: Appearance.m3colors.darkmode ? Appearance.colors.colOnLayer0 : Appearance.colors.colLayer0
|
||||
property color brightSecondary: Appearance.m3colors.darkmode ? Appearance.colors.colSecondary : Appearance.colors.colOnSecondary
|
||||
@@ -180,10 +175,12 @@ PanelWindow {
|
||||
property real regionX: Math.min(dragStartX, draggingX)
|
||||
property real regionY: Math.min(dragStartY, draggingY)
|
||||
|
||||
Process {
|
||||
TempScreenshotProcess {
|
||||
id: screenshotProc
|
||||
running: true
|
||||
command: ["bash", "-c", `mkdir -p '${StringUtils.shellSingleQuoteEscape(root.screenshotDir)}' && grim -o '${StringUtils.shellSingleQuoteEscape(root.screen.name)}' '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}'`]
|
||||
screen: root.screen
|
||||
screenshotDir: root.screenshotDir
|
||||
screenshotPath: root.screenshotPath
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (root.enableContentRegions) imageDetectionProcess.running = true;
|
||||
root.preparationDone = !checkRecordingProc.running;
|
||||
@@ -229,6 +226,27 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
function getScreenshotAction() {
|
||||
switch(root.action) {
|
||||
case RegionSelection.SnipAction.Copy:
|
||||
return ScreenshotAction.Action.Copy;
|
||||
case RegionSelection.SnipAction.Edit:
|
||||
return ScreenshotAction.Action.Edit;
|
||||
case RegionSelection.SnipAction.Search:
|
||||
return ScreenshotAction.Action.Search;
|
||||
case RegionSelection.SnipAction.CharRecognition:
|
||||
return ScreenshotAction.Action.CharRecognition;
|
||||
case RegionSelection.SnipAction.Record:
|
||||
return ScreenshotAction.Action.Record;
|
||||
case RegionSelection.SnipAction.RecordWithSound:
|
||||
return ScreenshotAction.Action.RecordWithSound;
|
||||
default:
|
||||
console.warn("[Region Selector] Unknown snip action, skipping snip.");
|
||||
root.dismiss();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function snip() {
|
||||
// Validity check
|
||||
if (root.regionWidth <= 0 || root.regionHeight <= 0) {
|
||||
@@ -246,62 +264,20 @@ PanelWindow {
|
||||
if (root.action === RegionSelection.SnipAction.Copy || root.action === RegionSelection.SnipAction.Edit) {
|
||||
root.action = root.mouseButton === Qt.RightButton ? RegionSelection.SnipAction.Edit : RegionSelection.SnipAction.Copy;
|
||||
}
|
||||
|
||||
// Set command for action
|
||||
const rx = Math.round(root.regionX * root.monitorScale);
|
||||
const ry = Math.round(root.regionY * root.monitorScale);
|
||||
const rw = Math.round(root.regionWidth * root.monitorScale);
|
||||
const rh = Math.round(root.regionHeight * root.monitorScale);
|
||||
const cropBase = `magick ${StringUtils.shellSingleQuoteEscape(root.screenshotPath)} `
|
||||
+ `-crop ${rw}x${rh}+${rx}+${ry}`
|
||||
const cropToStdout = `${cropBase} -`
|
||||
const cropInPlace = `${cropBase} '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}'`
|
||||
const cleanup = `rm '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}'`
|
||||
const slurpRegion = `${rx},${ry} ${rw}x${rh}`
|
||||
const uploadAndGetUrl = (filePath) => {
|
||||
return `curl -sF files[]=@'${StringUtils.shellSingleQuoteEscape(filePath)}' ${root.fileUploadApiEndpoint} | jq -r '.files[0].url'`
|
||||
}
|
||||
const annotationCommand = `${Config.options.regionSelector.annotation.useSatty ? "satty" : "swappy"} -f -`;
|
||||
switch (root.action) {
|
||||
case RegionSelection.SnipAction.Copy:
|
||||
if (saveScreenshotDir === "") {
|
||||
// not saving the screenshot, just copy to clipboard
|
||||
snipProc.command = ["bash", "-c", `${cropToStdout} | wl-copy && ${cleanup}`]
|
||||
break;
|
||||
}
|
||||
|
||||
const savePathBase = root.saveScreenshotDir
|
||||
|
||||
snipProc.command = [
|
||||
"bash", "-c",
|
||||
`mkdir -p '${StringUtils.shellSingleQuoteEscape(savePathBase)}' && \
|
||||
saveFileName="screenshot-$(date '+%Y-%m-%d_%H.%M.%S').png" && \
|
||||
savePath="${savePathBase}/$saveFileName" && \
|
||||
${cropToStdout} | tee >(wl-copy) > "$savePath" && \
|
||||
${cleanup}`
|
||||
]
|
||||
|
||||
break;
|
||||
case RegionSelection.SnipAction.Edit:
|
||||
snipProc.command = ["bash", "-c", `${cropToStdout} | ${annotationCommand} && ${cleanup}`]
|
||||
break;
|
||||
case RegionSelection.SnipAction.Search:
|
||||
snipProc.command = ["bash", "-c", `${cropInPlace} && xdg-open "${root.imageSearchEngineBaseUrl}$(${uploadAndGetUrl(root.screenshotPath)})" && ${cleanup}`]
|
||||
break;
|
||||
case RegionSelection.SnipAction.CharRecognition:
|
||||
snipProc.command = ["bash", "-c", `${cropInPlace} && tesseract '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}' stdout -l $(tesseract --list-langs | awk 'NR>1{print $1}' | tr '\\n' '+' | sed 's/\\+$/\\n/') | wl-copy && ${cleanup}`]
|
||||
break;
|
||||
case RegionSelection.SnipAction.Record:
|
||||
snipProc.command = ["bash", "-c", `${Directories.recordScriptPath} --region '${slurpRegion}'`]
|
||||
break;
|
||||
case RegionSelection.SnipAction.RecordWithSound:
|
||||
snipProc.command = ["bash", "-c", `${Directories.recordScriptPath} --region '${slurpRegion}' --sound`]
|
||||
break;
|
||||
default:
|
||||
console.warn("[Region Selector] Unknown snip action, skipping snip.");
|
||||
root.dismiss();
|
||||
return;
|
||||
}
|
||||
|
||||
const screenshotDir = Config.options.screenSnip.savePath !== "" ? //
|
||||
Config.options.screenSnip.savePath : "";
|
||||
var screenshotAction = root.getScreenshotAction();
|
||||
const command = ScreenshotAction.getCommand(
|
||||
root.regionX * root.monitorScale, //
|
||||
root.regionY * root.monitorScale, //
|
||||
root.regionWidth * root.monitorScale,//
|
||||
root.regionHeight * root.monitorScale, //
|
||||
root.screenshotPath, //
|
||||
screenshotAction, //
|
||||
screenshotDir
|
||||
)
|
||||
snipProc.command = command;
|
||||
|
||||
// Image post-processing
|
||||
snipProc.startDetached();
|
||||
|
||||
@@ -93,8 +93,8 @@ Singleton {
|
||||
property color bgPanelFooter: ColorUtils.transparentize(root.dark ? root.darkColors.bgPanelFooter : root.lightColors.bgPanelFooter, root.panelLayerTransparency)
|
||||
property color bgPanelBody: ColorUtils.transparentize(root.dark ? root.darkColors.bgPanelBody : root.lightColors.bgPanelBody, root.panelLayerTransparency)
|
||||
property color bgPanelSeparator: ColorUtils.transparentize(root.dark ? root.darkColors.bgPanelSeparator : root.lightColors.bgPanelSeparator, root.backgroundTransparency)
|
||||
property color bg0Opaque: root.dark ? root.darkColors.bg0 : root.lightColors.bg0
|
||||
property color bg0: ColorUtils.transparentize(bg0Opaque, root.backgroundTransparency)
|
||||
property color bg0Base: root.dark ? root.darkColors.bg0 : root.lightColors.bg0
|
||||
property color bg0: ColorUtils.transparentize(bg0Base, root.backgroundTransparency)
|
||||
property color bg0Border: ColorUtils.transparentize(root.dark ? root.darkColors.bg0Border : root.lightColors.bg0Border, root.backgroundTransparency)
|
||||
property color bg1Base: root.dark ? root.darkColors.bg1Base : root.lightColors.bg1Base
|
||||
property color bg1: ColorUtils.transparentize(root.dark ? root.darkColors.bg1 : root.lightColors.bg1, root.contentTransparency)
|
||||
|
||||
@@ -39,9 +39,10 @@ Button {
|
||||
}
|
||||
}
|
||||
property color fgColor: {
|
||||
if (!root.enabled) return root.colForegroundDisabled
|
||||
if (root.checked) return root.colForegroundToggled
|
||||
if (root.enabled) return root.colForeground
|
||||
return root.colForegroundDisabled
|
||||
return root.colForeground
|
||||
}
|
||||
property alias horizontalAlignment: buttonText.horizontalAlignment
|
||||
font {
|
||||
|
||||
@@ -76,8 +76,9 @@ Menu {
|
||||
contentItem: Item {
|
||||
implicitWidth: menuListView.implicitWidth
|
||||
implicitHeight: menuListView.implicitHeight
|
||||
ListView {
|
||||
WListView {
|
||||
id: menuListView
|
||||
interactive: contentHeight > height
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
@@ -87,6 +88,7 @@ Menu {
|
||||
topMargin: root.downDirection ? root.sourceEdgeMargin : root.margins
|
||||
bottomMargin: root.downDirection ? root.margins : root.sourceEdgeMargin
|
||||
}
|
||||
clip: true
|
||||
implicitHeight: contentHeight
|
||||
implicitWidth: Array.from({
|
||||
length: count
|
||||
|
||||
@@ -6,6 +6,7 @@ import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
MenuItem {
|
||||
@@ -14,11 +15,11 @@ MenuItem {
|
||||
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
|
||||
property color colBackgroundHover: Looks.colors.bg2Hover
|
||||
property color colBackgroundActive: Looks.colors.bg2Active
|
||||
property color colBackgroundToggled: Looks.colors.accent
|
||||
property color colBackgroundToggledHover: Looks.colors.accentHover
|
||||
property color colBackgroundToggledActive: Looks.colors.accentActive
|
||||
property color colBackgroundToggled: Looks.colors.bg2Hover
|
||||
property color colBackgroundToggledHover: Looks.colors.bg2Active
|
||||
property color colBackgroundToggledActive: Looks.colors.bg2Hover
|
||||
property color colForeground: Looks.colors.fg
|
||||
property color colForegroundToggled: Looks.colors.accentFg
|
||||
property color colForegroundToggled: Looks.colors.fg
|
||||
property color colForegroundDisabled: ColorUtils.transparentize(Looks.colors.subfg, 0.4)
|
||||
property color color: {
|
||||
if (!root.enabled)
|
||||
@@ -70,27 +71,57 @@ MenuItem {
|
||||
implicitHeight: Math.max(28, contentItem.implicitHeight) + topInset + bottomInset
|
||||
implicitWidth: contentItem.implicitWidth + leftInset + rightInset + leftPadding + rightPadding
|
||||
|
||||
contentItem: RowLayout {
|
||||
id: contentLayout
|
||||
spacing: 12
|
||||
FluentIcon {
|
||||
id: buttonIcon
|
||||
monochrome: true
|
||||
implicitSize: 20
|
||||
Layout.fillWidth: false
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: root.fgColor
|
||||
visible: root.icon.name !== "";
|
||||
icon: root.icon.name
|
||||
contentItem: Item {
|
||||
implicitWidth: contentLayout.implicitWidth
|
||||
implicitHeight: contentLayout.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: contentLayout
|
||||
anchors.fill: parent
|
||||
spacing: 12
|
||||
FluentIcon {
|
||||
id: buttonIcon
|
||||
monochrome: true
|
||||
implicitSize: 20
|
||||
Layout.fillWidth: false
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: root.fgColor
|
||||
visible: root.icon.name !== ""
|
||||
icon: root.icon.name
|
||||
}
|
||||
WText {
|
||||
id: buttonText
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
text: root.text
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
color: root.fgColor
|
||||
}
|
||||
}
|
||||
WText {
|
||||
id: buttonText
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
text: root.text
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
color: root.fgColor
|
||||
|
||||
WFadeLoader {
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
leftMargin: -root.leftPadding + width
|
||||
}
|
||||
shown: root.checked
|
||||
sourceComponent: Rectangle {
|
||||
implicitWidth: 3
|
||||
implicitHeight: 3
|
||||
radius: width / 2
|
||||
color: Looks.colors.accent
|
||||
property bool forceZeroHeight: true
|
||||
height: forceZeroHeight ? 0 : Math.max(root.down ? 10 : 16, root.background.height - 18 * 2)
|
||||
Component.onCompleted: {
|
||||
forceZeroHeight = false;
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
animation: Looks.transition.resize.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real padding: 9
|
||||
property alias colBackground: background.color
|
||||
property alias spacing: toolbarLayout.spacing
|
||||
property alias radius: background.radius
|
||||
default property alias data: toolbarLayout.data
|
||||
|
||||
implicitWidth: background.implicitWidth
|
||||
implicitHeight: background.implicitHeight
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
implicitHeight: 50
|
||||
implicitWidth: toolbarLayout.implicitWidth + root.padding * 2
|
||||
radius: Looks.radius.large
|
||||
color: Looks.colors.bg0Base
|
||||
|
||||
border.width: 1
|
||||
border.color: Looks.colors.bg1Border
|
||||
|
||||
RowLayout {
|
||||
id: toolbarLayout
|
||||
spacing: 4
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: root.padding
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.modules.common
|
||||
|
||||
WButton {
|
||||
implicitHeight: 32
|
||||
radius: Looks.radius.medium
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.modules.common
|
||||
|
||||
WToolbarButton {
|
||||
id: root
|
||||
implicitWidth: height
|
||||
contentItem: Item {
|
||||
FluentIcon {
|
||||
anchors.centerIn: parent
|
||||
icon: root.icon.name
|
||||
implicitSize: 18
|
||||
color: root.fgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.modules.common
|
||||
|
||||
TabButton {
|
||||
id: root
|
||||
|
||||
implicitWidth: 38
|
||||
implicitHeight: 32
|
||||
padding: 0
|
||||
|
||||
background: null
|
||||
contentItem: Item {
|
||||
FluentIcon {
|
||||
anchors.centerIn: parent
|
||||
icon: root.icon.name
|
||||
color: root.icon.color
|
||||
implicitSize: 18
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.modules.common
|
||||
|
||||
Rectangle {
|
||||
Layout.leftMargin: 4
|
||||
Layout.rightMargin: 4
|
||||
implicitHeight: 24
|
||||
implicitWidth: 1
|
||||
color: Looks.colors.bg0Border
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
|
||||
TabBar {
|
||||
id: root
|
||||
implicitHeight: 32
|
||||
|
||||
background: Rectangle {
|
||||
radius: Looks.radius.medium
|
||||
color: Looks.colors.bgPanelFooter
|
||||
border.color: ColorUtils.transparentize(Looks.colors.bg0Border, 0.7)
|
||||
border.width: 1
|
||||
|
||||
// Indicator
|
||||
Rectangle {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
leftMargin: root.currentIndex * (root.width / root.count)
|
||||
Behavior on leftMargin {
|
||||
animation: Looks.transition.resize.createObject(this)
|
||||
}
|
||||
}
|
||||
radius: Looks.radius.medium
|
||||
color: Looks.colors.bg2Base
|
||||
border.color: Looks.colors.bg0Border
|
||||
border.width: 1
|
||||
width: root.width / root.count
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 1
|
||||
}
|
||||
implicitWidth: pressDetector.containsPress ? 16 : 12
|
||||
implicitHeight: 3
|
||||
radius: height / 2
|
||||
color: Looks.colors.accent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: pressDetector
|
||||
z: 9999
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import QtQuick
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property int regionX
|
||||
required property int regionY
|
||||
required property int regionWidth
|
||||
required property int regionHeight
|
||||
|
||||
property bool dashed: true
|
||||
property color borderColor: "#ffffff"
|
||||
property color overlayColor: ColorUtils.transparentize("#000000", 1)
|
||||
Component.onCompleted: overlayColor = ColorUtils.transparentize("#000000", 0.4)
|
||||
Behavior on overlayColor {
|
||||
ColorAnimation {
|
||||
duration: 250
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay to darken screen
|
||||
// Base dark overlay around region
|
||||
Rectangle {
|
||||
id: darkenOverlay
|
||||
z: 1
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
leftMargin: root.regionX - darkenOverlay.border.width
|
||||
topMargin: root.regionY - darkenOverlay.border.width
|
||||
}
|
||||
width: root.regionWidth + darkenOverlay.border.width * 2
|
||||
height: root.regionHeight + darkenOverlay.border.width * 2
|
||||
color: "transparent"
|
||||
border.color: root.overlayColor
|
||||
border.width: Math.max(root.width, root.height)
|
||||
}
|
||||
|
||||
// Selection border
|
||||
DashedBorder {
|
||||
id: border
|
||||
z: 2
|
||||
visible: root.regionWidth > 0 && root.regionHeight > 0
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
leftMargin: Math.round(root.regionX - borderWidth)
|
||||
topMargin: Math.round(root.regionY - borderWidth)
|
||||
}
|
||||
width: Math.round(root.regionWidth + borderWidth * 2)
|
||||
height: Math.round(root.regionHeight + borderWidth * 2)
|
||||
color: root.borderColor
|
||||
dashLength: 4
|
||||
gapLength: root.dashed ? 3 : 0
|
||||
borderWidth: 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt.labs.synchronizer
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.utils
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
enum MediaType {
|
||||
Image,
|
||||
Video
|
||||
}
|
||||
enum ImageAction {
|
||||
Copy,
|
||||
Menu,
|
||||
CharRecognition,
|
||||
Search
|
||||
}
|
||||
enum VideoAction {
|
||||
Record,
|
||||
RecordWithSound
|
||||
}
|
||||
enum SelectionMode {
|
||||
Rect,
|
||||
Window
|
||||
}
|
||||
|
||||
signal closed
|
||||
function close() {
|
||||
root.closed();
|
||||
}
|
||||
|
||||
property var mediaType: WRegionSelectionPanel.MediaType.Image
|
||||
property var imageAction: WRegionSelectionPanel.ImageAction.Copy
|
||||
property var selectionMode: WRegionSelectionPanel.SelectionMode.Rect
|
||||
|
||||
visible: false
|
||||
color: "transparent"
|
||||
WlrLayershell.namespace: "quickshell:regionSelector"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
anchors {
|
||||
left: true
|
||||
right: true
|
||||
top: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
// Hyprland stuff
|
||||
readonly property HyprlandMonitor hyprlandMonitor: Hyprland.monitorFor(screen)
|
||||
readonly property real monitorScale: hyprlandMonitor.scale
|
||||
readonly property var windows: [...HyprlandData.windowList].sort((a, b) => {
|
||||
// Sort floating=true windows before others
|
||||
if (a.floating === b.floating)
|
||||
return 0;
|
||||
return a.floating ? -1 : 1;
|
||||
})
|
||||
|
||||
property string screenshotDir: Directories.screenshotTemp
|
||||
property string screenshotPath: `${root.screenshotDir}/image-${screen.name}`
|
||||
TempScreenshotProcess {
|
||||
id: screenshotProc
|
||||
running: true
|
||||
screen: root.screen
|
||||
screenshotDir: root.screenshotDir
|
||||
screenshotPath: root.screenshotPath
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
root.preparationDone = true;
|
||||
}
|
||||
}
|
||||
property bool preparationDone: false
|
||||
onPreparationDoneChanged: {
|
||||
if (!preparationDone)
|
||||
return;
|
||||
root.visible = true;
|
||||
}
|
||||
|
||||
function getScreenshotAction() {
|
||||
switch (root.mediaType) {
|
||||
case WRegionSelectionPanel.MediaType.Image:
|
||||
switch (root.imageAction) {
|
||||
case WRegionSelectionPanel.ImageAction.Copy:
|
||||
return ScreenshotAction.Action.Copy;
|
||||
case WRegionSelectionPanel.ImageAction.Menu:
|
||||
return ScreenshotAction.Action.Edit;
|
||||
case WRegionSelectionPanel.ImageAction.CharRecognition:
|
||||
return ScreenshotAction.Action.CharRecognition;
|
||||
case WRegionSelectionPanel.ImageAction.Search:
|
||||
return ScreenshotAction.Action.Search;
|
||||
default:
|
||||
return ScreenshotAction.Action.Copy;
|
||||
}
|
||||
break;
|
||||
case WRegionSelectionPanel.MediaType.Video:
|
||||
switch (root.videoAction) {
|
||||
case WRegionSelectionPanel.VideoAction.Record:
|
||||
return ScreenshotAction.Action.Record;
|
||||
case WRegionSelectionPanel.VideoAction.RecordWithSound:
|
||||
return ScreenshotAction.Action.RecordWithSound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: snipProc
|
||||
}
|
||||
|
||||
ScreencopyView {
|
||||
id: screencopyView
|
||||
anchors.fill: parent
|
||||
live: false
|
||||
captureSource: root.screen
|
||||
|
||||
focus: root.visible
|
||||
Keys.onPressed: event => { // Esc to close
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close();
|
||||
} else if (event.key === Qt.Key_E && event.modifiers & Qt.ControlModifier) {
|
||||
if (root.imageAction === WRegionSelectionPanel.ImageAction.Menu) {
|
||||
root.imageAction = WRegionSelectionPanel.ImageAction.Copy;
|
||||
} else {
|
||||
root.imageAction = WRegionSelectionPanel.ImageAction.Menu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DragManager {
|
||||
id: dragArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
cursorShape: Qt.CrossCursor
|
||||
|
||||
property bool isWindowSelection: root.selectionMode === WRegionSelectionPanel.SelectionMode.Window
|
||||
property var hoveredWindow: root.windows.find(w => {
|
||||
const inCurrentWorkspace = w.workspace.id === HyprlandData.activeWorkspace.id;
|
||||
const withinXRange = w.at[0] <= dragArea.mouseX && dragArea.mouseX <= w.at[0] + w.size[0];
|
||||
const withinYRange = w.at[1] <= dragArea.mouseY && dragArea.mouseY <= w.at[1] + w.size[1];
|
||||
return inCurrentWorkspace && withinXRange && withinYRange;
|
||||
})
|
||||
property int winPadding: 1
|
||||
property int selectionX: isWindowSelection ? ((hoveredWindow?.at[0] ?? 0) - winPadding) : regionTopLeftX
|
||||
property int selectionY: isWindowSelection ? ((hoveredWindow?.at[1] ?? 0) - winPadding) : regionTopLeftY
|
||||
property int selectionWidth: isWindowSelection ? ((hoveredWindow?.size[0] ?? 0) + winPadding * 2) : regionWidth
|
||||
property int selectionHeight: isWindowSelection ? ((hoveredWindow?.size[1] ?? 0) + winPadding * 2) : regionHeight
|
||||
|
||||
onDragReleased: (diffX, diffY) => {
|
||||
if (selectionWidth === 0 || selectionHeight === 0) {
|
||||
return;
|
||||
}
|
||||
const screenshotDir = Config.options.screenSnip.savePath !== "" ? Config.options.screenSnip.savePath : "";
|
||||
const screenshotAction = root.getScreenshotAction();
|
||||
const command = ScreenshotAction.getCommand(dragArea.selectionX * root.monitorScale //
|
||||
, dragArea.selectionY * root.monitorScale //
|
||||
, dragArea.selectionWidth * root.monitorScale//
|
||||
, dragArea.selectionHeight * root.monitorScale //
|
||||
, root.screenshotPath //
|
||||
, screenshotAction //
|
||||
, screenshotDir); // yo wtf is this formatting qmlls do be funnie
|
||||
snipProc.command = command;
|
||||
|
||||
// Image post-processing
|
||||
snipProc.startDetached();
|
||||
root.close();
|
||||
}
|
||||
|
||||
WRectangularSelection {
|
||||
id: rectangularSelection
|
||||
anchors.fill: parent
|
||||
regionX: dragArea.selectionX
|
||||
regionY: dragArea.selectionY
|
||||
regionWidth: dragArea.selectionWidth
|
||||
regionHeight: dragArea.selectionHeight
|
||||
dashed: root.selectionMode === WRegionSelectionPanel.SelectionMode.Rect
|
||||
}
|
||||
|
||||
RegionSelectionOptionsToolbar {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.top
|
||||
topMargin: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component RegionSelectionOptionsToolbar: WToolbar {
|
||||
// Image/video
|
||||
WToolbarTabBar {
|
||||
currentIndex: switch (root.mediaType) {
|
||||
case WRegionSelectionPanel.MediaType.Image:
|
||||
return 0;
|
||||
case WRegionSelectionPanel.MediaType.Video:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
WToolbarIconTabButton {
|
||||
icon.name: "camera"
|
||||
icon.color: Looks.colors.fg
|
||||
}
|
||||
WToolbarIconTabButton {
|
||||
icon.name: "video"
|
||||
icon.color: Looks.colors.fg
|
||||
}
|
||||
onCurrentIndexChanged: {
|
||||
switch (currentIndex) {
|
||||
case 0:
|
||||
root.mediaType = WRegionSelectionPanel.MediaType.Image;
|
||||
break;
|
||||
case 1:
|
||||
root.mediaType = WRegionSelectionPanel.MediaType.Video;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WToolTip {
|
||||
text: Translation.tr("Snip")
|
||||
}
|
||||
}
|
||||
|
||||
// Selection type
|
||||
WToolbarButton {
|
||||
id: selectionTypeBtn
|
||||
implicitWidth: selectionTypeBtnRow.implicitWidth + 11 * 2
|
||||
leftPadding: 11
|
||||
rightPadding: 11
|
||||
onClicked: {
|
||||
selectionTypeMenu.visible = !selectionTypeMenu.visible;
|
||||
}
|
||||
contentItem: Row {
|
||||
id: selectionTypeBtnRow
|
||||
spacing: 4
|
||||
FluentIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
icon: switch (root.selectionMode) {
|
||||
case WRegionSelectionPanel.SelectionMode.Rect:
|
||||
return "crop";
|
||||
case WRegionSelectionPanel.SelectionMode.Window:
|
||||
return "calendar-add";
|
||||
default:
|
||||
return "crop";
|
||||
}
|
||||
implicitSize: 18
|
||||
}
|
||||
FluentIcon {
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: (parent.height - height) / 2 + (selectionTypeBtn.down ? 2 : 0)
|
||||
Behavior on topMargin {
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
}
|
||||
icon: "chevron-down"
|
||||
implicitSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
WMenu {
|
||||
id: selectionTypeMenu
|
||||
onClosed: screencopyView.focus = true
|
||||
x: -margins
|
||||
y: -margins - (selectionTypeBtn.parent.height - selectionTypeBtn.height) - 16
|
||||
topMargin: -6
|
||||
height: implicitHeight + sourceEdgeMargin
|
||||
|
||||
color: Looks.colors.bg1Base
|
||||
|
||||
Action {
|
||||
icon.name: "crop"
|
||||
text: Translation.tr("Rectangle")
|
||||
checked: root.selectionMode === WRegionSelectionPanel.SelectionMode.Rect
|
||||
onTriggered: {
|
||||
root.selectionMode = WRegionSelectionPanel.SelectionMode.Rect;
|
||||
}
|
||||
}
|
||||
Action {
|
||||
icon.name: "calendar-add"
|
||||
text: Translation.tr("Window")
|
||||
checked: root.selectionMode === WRegionSelectionPanel.SelectionMode.Window
|
||||
onTriggered: {
|
||||
root.selectionMode = WRegionSelectionPanel.SelectionMode.Window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WToolTip {
|
||||
text: Translation.tr("Snipping area")
|
||||
}
|
||||
}
|
||||
|
||||
// Markup
|
||||
WToolbarIconButton {
|
||||
icon.name: "image-edit"
|
||||
enabled: root.mediaType === WRegionSelectionPanel.MediaType.Image
|
||||
checked: root.imageAction === WRegionSelectionPanel.ImageAction.Menu
|
||||
onClicked: {
|
||||
if (root.imageAction === WRegionSelectionPanel.ImageAction.Menu) {
|
||||
root.imageAction = WRegionSelectionPanel.ImageAction.Copy;
|
||||
} else {
|
||||
root.imageAction = WRegionSelectionPanel.ImageAction.Menu;
|
||||
}
|
||||
}
|
||||
WToolTip {
|
||||
text: Translation.tr("Quick markup (Ctrl+E)")
|
||||
}
|
||||
}
|
||||
|
||||
WToolbarSeparator {}
|
||||
|
||||
// Tools
|
||||
WToolbarIconButton {
|
||||
icon.name: "search-visual"
|
||||
checked: root.imageAction === WRegionSelectionPanel.ImageAction.Search
|
||||
onClicked: {
|
||||
if (root.imageAction === WRegionSelectionPanel.ImageAction.Search && root.mediaType === WRegionSelectionPanel.MediaType.Image) {
|
||||
root.imageAction = WRegionSelectionPanel.ImageAction.Copy;
|
||||
} else {
|
||||
root.mediaType = WRegionSelectionPanel.MediaType.Image;
|
||||
root.imageAction = WRegionSelectionPanel.ImageAction.Search;
|
||||
}
|
||||
}
|
||||
WToolTip {
|
||||
text: Translation.tr("Image search")
|
||||
}
|
||||
}
|
||||
WToolbarIconButton {
|
||||
icon.name: "eyedropper"
|
||||
onClicked: {
|
||||
Quickshell.execDetached(["bash", "-c", "sleep 0.2; hyprpicker -a"]);
|
||||
root.closed();
|
||||
}
|
||||
WToolTip {
|
||||
text: Translation.tr("Color picker")
|
||||
}
|
||||
}
|
||||
WToolbarIconButton {
|
||||
icon.name: "scan-text"
|
||||
checked: root.imageAction === WRegionSelectionPanel.ImageAction.CharRecognition
|
||||
onClicked: {
|
||||
if (root.imageAction === WRegionSelectionPanel.ImageAction.CharRecognition && root.mediaType === WRegionSelectionPanel.MediaType.Image) {
|
||||
root.imageAction = WRegionSelectionPanel.ImageAction.Copy;
|
||||
} else {
|
||||
root.mediaType = WRegionSelectionPanel.MediaType.Image;
|
||||
root.imageAction = WRegionSelectionPanel.ImageAction.CharRecognition;
|
||||
}
|
||||
}
|
||||
WToolTip {
|
||||
text: Translation.tr("Text extractor")
|
||||
}
|
||||
}
|
||||
|
||||
WToolbarSeparator {}
|
||||
|
||||
WToolbarIconButton {
|
||||
icon.name: "dismiss"
|
||||
onClicked: root.close()
|
||||
WToolTip {
|
||||
text: Translation.tr("Close (Esc)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import qs
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.services
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Hyprland
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
function dismiss() {
|
||||
GlobalStates.regionSelectorOpen = false;
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: regionSelectorLoader
|
||||
active: GlobalStates.regionSelectorOpen
|
||||
|
||||
sourceComponent: WRegionSelectionPanel {
|
||||
onClosed: root.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
function screenshot() {
|
||||
GlobalStates.regionSelectorOpen = true;
|
||||
}
|
||||
|
||||
function ocr() {
|
||||
GlobalStates.regionSelectorOpen = true;
|
||||
regionSelectorLoader.item.mediaType = WRegionSelectionPanel.MediaType.Image;
|
||||
regionSelectorLoader.item.imageAction = WRegionSelectionPanel.ImageAction.CharRecognition;
|
||||
}
|
||||
|
||||
function record() {
|
||||
GlobalStates.regionSelectorOpen = true;
|
||||
regionSelectorLoader.item.mediaType = WRegionSelectionPanel.MediaType.Video;
|
||||
regionSelectorLoader.item.videoAction = WRegionSelectionPanel.VideoAction.Record;
|
||||
}
|
||||
|
||||
function recordWithSound() {
|
||||
GlobalStates.regionSelectorOpen = true;
|
||||
regionSelectorLoader.item.mediaType = WRegionSelectionPanel.MediaType.Video;
|
||||
regionSelectorLoader.item.videoAction = WRegionSelectionPanel.VideoAction.RecordWithSound;
|
||||
}
|
||||
|
||||
function search() {
|
||||
GlobalStates.regionSelectorOpen = true;
|
||||
regionSelectorLoader.item.mediaType = WRegionSelectionPanel.MediaType.Image;
|
||||
regionSelectorLoader.item.imageAction = WRegionSelectionPanel.ImageAction.Search;
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "region"
|
||||
|
||||
function screenshot() {
|
||||
root.screenshot();
|
||||
}
|
||||
function ocr() {
|
||||
root.ocr();
|
||||
}
|
||||
function record() {
|
||||
root.record();
|
||||
}
|
||||
function recordWithSound() {
|
||||
root.recordWithSound();
|
||||
}
|
||||
function search() {
|
||||
root.search();
|
||||
}
|
||||
}
|
||||
|
||||
GlobalShortcut {
|
||||
name: "regionScreenshot"
|
||||
description: "Takes a screenshot of the selected region"
|
||||
onPressed: root.screenshot()
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "regionSearch"
|
||||
description: "Searches the selected region"
|
||||
onPressed: root.search()
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "regionOcr"
|
||||
description: "Recognizes text in the selected region"
|
||||
onPressed: root.ocr()
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "regionRecord"
|
||||
description: "Records the selected region"
|
||||
onPressed: root.record()
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "regionRecordWithSound"
|
||||
description: "Records the selected region with sound"
|
||||
onPressed: root.recordWithSound()
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import qs.modules.waffle.lock
|
||||
import qs.modules.waffle.notificationCenter
|
||||
import qs.modules.waffle.onScreenDisplay
|
||||
import qs.modules.waffle.polkit
|
||||
import qs.modules.waffle.screenSnip
|
||||
import qs.modules.waffle.startMenu
|
||||
import qs.modules.waffle.sessionScreen
|
||||
import qs.modules.waffle.taskView
|
||||
@@ -89,6 +90,7 @@ ShellRoot {
|
||||
PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} }
|
||||
PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} }
|
||||
PanelLoader { identifier: "wPolkit"; component: WafflePolkit {} }
|
||||
PanelLoader { identifier: "wScreenSnip"; component: WScreenSnip {} }
|
||||
PanelLoader { identifier: "wStartMenu"; component: WaffleStartMenu {} }
|
||||
PanelLoader { identifier: "wSessionScreen"; component: WaffleSessionScreen {} }
|
||||
PanelLoader { identifier: "wTaskView"; component: WaffleTaskView {} }
|
||||
@@ -104,7 +106,7 @@ ShellRoot {
|
||||
property list<string> families: ["ii", "waffle"]
|
||||
property var panelFamilies: ({
|
||||
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"],
|
||||
"waffle": ["wActionCenter", "wBar", "wBackground", "wLock", "wNotificationCenter", "wOnScreenDisplay", "wTaskView", "wPolkit", "wSessionScreen", "wStartMenu", "iiCheatsheet", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiRegionSelector", "iiWallpaperSelector"],
|
||||
"waffle": ["wActionCenter", "wBar", "wBackground", "wLock", "wNotificationCenter", "wOnScreenDisplay", "wTaskView", "wPolkit", "wScreenSnip", "wSessionScreen", "wStartMenu", "iiCheatsheet", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiWallpaperSelector"],
|
||||
})
|
||||
function cyclePanelFamily() {
|
||||
const currentIndex = families.indexOf(Config.options.panelFamily)
|
||||
|
||||