Merge branch 'end-4:main' into parallax

This commit is contained in:
Ivan Rosinskii
2025-12-23 23:35:22 +01:00
committed by GitHub
53 changed files with 1215 additions and 200 deletions
+2 -2
View File
@@ -4,8 +4,8 @@ monitor=,preferred,auto,1
gesture = 3, swipe, move, gesture = 3, swipe, move,
gesture = 3, pinch, float gesture = 3, pinch, float
gesture = 4, horizontal, workspace gesture = 4, horizontal, workspace
gesture = 4, up, dispatcher, global, quickshell:overviewToggle gesture = 4, up, dispatcher, global, quickshell:overviewWorkspacesToggle
gesture = 4, down, dispatcher, global, quickshell:overviewClose gesture = 4, down, dispatcher, global, quickshell:overviewWorkspacesClose
gestures { gestures {
workspace_swipe_distance = 700 workspace_swipe_distance = 700
workspace_swipe_cancel_ratio = 0.2 workspace_swipe_cancel_ratio = 0.2
@@ -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

@@ -30,13 +30,9 @@ Singleton {
let y = 0.5768 * (x * x) - 0.759 * (x) + 0.2896 let y = 0.5768 * (x * x) - 0.759 * (x) + 0.2896
return Math.max(0, Math.min(0.22, y)) return Math.max(0, Math.min(0.22, y))
} }
property real autoContentTransparency: { // y = -10.1734x^2 + 3.4457x + 0.1872 property real autoContentTransparency: 0.9
let x = autoBackgroundTransparency
let y = -10.1734 * (x * x) + 3.4457 * (x) + 0.1872
return Math.max(0, Math.min(0.6, y))
}
property real backgroundTransparency: Config?.options.appearance.transparency.enable ? Config?.options.appearance.transparency.automatic ? autoBackgroundTransparency : Config?.options.appearance.transparency.backgroundTransparency : 0 property real backgroundTransparency: Config?.options.appearance.transparency.enable ? Config?.options.appearance.transparency.automatic ? autoBackgroundTransparency : Config?.options.appearance.transparency.backgroundTransparency : 0
property real contentTransparency: Config?.options.appearance.transparency.enable ? Config?.options.appearance.transparency.automatic ? autoContentTransparency : Config?.options.appearance.transparency.contentTransparency : 0 property real contentTransparency: Config?.options.appearance.transparency.automatic ? autoContentTransparency : Config?.options.appearance.transparency.contentTransparency
m3colors: QtObject { m3colors: QtObject {
property bool darkmode: true property bool darkmode: true
@@ -114,30 +110,41 @@ Singleton {
colors: QtObject { colors: QtObject {
property color colSubtext: m3colors.m3outline property color colSubtext: m3colors.m3outline
property color colLayer0: ColorUtils.mix(ColorUtils.transparentize(m3colors.m3background, root.backgroundTransparency), m3colors.m3primary, Config.options.appearance.extraBackgroundTint ? 0.99 : 1) // Layer 0
property color colLayer0Base: ColorUtils.mix(m3colors.m3background, m3colors.m3primary, Config.options.appearance.extraBackgroundTint ? 0.99 : 1)
property color colLayer0: ColorUtils.transparentize(colLayer0Base, root.backgroundTransparency)
property color colOnLayer0: m3colors.m3onBackground property color colOnLayer0: m3colors.m3onBackground
property color colLayer0Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer0, colOnLayer0, 0.9, root.contentTransparency)) property color colLayer0Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer0, colOnLayer0, 0.9, root.contentTransparency))
property color colLayer0Active: ColorUtils.transparentize(ColorUtils.mix(colLayer0, colOnLayer0, 0.8, root.contentTransparency)) property color colLayer0Active: ColorUtils.transparentize(ColorUtils.mix(colLayer0, colOnLayer0, 0.8, root.contentTransparency))
property color colLayer0Border: ColorUtils.mix(root.m3colors.m3outlineVariant, colLayer0, 0.4) property color colLayer0Border: ColorUtils.mix(root.m3colors.m3outlineVariant, colLayer0, 0.4)
property color colLayer1: ColorUtils.transparentize(m3colors.m3surfaceContainerLow, root.contentTransparency); // Layer 1
property color colLayer1Base: m3colors.m3surfaceContainerLow
property color colLayer1: ColorUtils.solveOverlayColor(colLayer0Base, colLayer1Base, 1 - root.contentTransparency);
property color colOnLayer1: m3colors.m3onSurfaceVariant; property color colOnLayer1: m3colors.m3onSurfaceVariant;
property color colOnLayer1Inactive: ColorUtils.mix(colOnLayer1, colLayer1, 0.45); property color colOnLayer1Inactive: ColorUtils.mix(colOnLayer1, colLayer1, 0.45);
property color colLayer2: ColorUtils.transparentize(m3colors.m3surfaceContainer, root.contentTransparency)
property color colOnLayer2: m3colors.m3onSurface;
property color colOnLayer2Disabled: ColorUtils.mix(colOnLayer2, m3colors.m3background, 0.4);
property color colLayer1Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer1, colOnLayer1, 0.92), root.contentTransparency) property color colLayer1Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer1, colOnLayer1, 0.92), root.contentTransparency)
property color colLayer1Active: ColorUtils.transparentize(ColorUtils.mix(colLayer1, colOnLayer1, 0.85), root.contentTransparency); property color colLayer1Active: ColorUtils.transparentize(ColorUtils.mix(colLayer1, colOnLayer1, 0.85), root.contentTransparency);
property color colLayer2Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer2, colOnLayer2, 0.90), root.contentTransparency) // Layer 2
property color colLayer2Active: ColorUtils.transparentize(ColorUtils.mix(colLayer2, colOnLayer2, 0.80), root.contentTransparency); property color colLayer2Base: m3colors.m3surfaceContainer
property color colLayer2Disabled: ColorUtils.transparentize(ColorUtils.mix(colLayer2, m3colors.m3background, 0.8), root.contentTransparency); property color colLayer2: ColorUtils.solveOverlayColor(colLayer1Base, colLayer2Base, 1 - root.contentTransparency)
property color colLayer3: ColorUtils.transparentize(m3colors.m3surfaceContainerHigh, root.contentTransparency) property color colLayer2Hover: ColorUtils.solveOverlayColor(colLayer1Base, ColorUtils.mix(colLayer2Base, colOnLayer2, 0.90), 1 - root.contentTransparency)
property color colLayer2Active: ColorUtils.solveOverlayColor(colLayer1Base, ColorUtils.mix(colLayer2Base, colOnLayer2, 0.80), 1 - root.contentTransparency);
property color colLayer2Disabled: ColorUtils.solveOverlayColor(colLayer1Base, ColorUtils.mix(colLayer2Base, m3colors.m3background, 0.8), 1 - root.contentTransparency);
property color colOnLayer2: m3colors.m3onSurface;
property color colOnLayer2Disabled: ColorUtils.mix(colOnLayer2, m3colors.m3background, 0.4);
// Layer 3
property color colLayer3Base: m3colors.m3surfaceContainerHigh
property color colLayer3: ColorUtils.solveOverlayColor(colLayer2Base, colLayer3Base, 1 - root.contentTransparency)
property color colLayer3Hover: ColorUtils.solveOverlayColor(colLayer2Base, ColorUtils.mix(colLayer3Base, colOnLayer3, 0.90), 1 - root.contentTransparency)
property color colLayer3Active: ColorUtils.solveOverlayColor(colLayer2Base, ColorUtils.mix(colLayer3Base, colOnLayer3, 0.80), 1 - root.contentTransparency);
property color colOnLayer3: m3colors.m3onSurface; property color colOnLayer3: m3colors.m3onSurface;
property color colLayer3Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer3, colOnLayer3, 0.90), root.contentTransparency) // Layer 4
property color colLayer3Active: ColorUtils.transparentize(ColorUtils.mix(colLayer3, colOnLayer3, 0.80), root.contentTransparency); property color colLayer4Base: m3colors.m3surfaceContainerHighest
property color colLayer4: ColorUtils.transparentize(m3colors.m3surfaceContainerHighest, root.contentTransparency) property color colLayer4: ColorUtils.solveOverlayColor(colLayer3Base, colLayer4Base, 1 - root.contentTransparency)
property color colLayer4Hover: ColorUtils.solveOverlayColor(colLayer3Base, ColorUtils.mix(colLayer4Base, colOnLayer4, 0.90), 1 - root.contentTransparency)
property color colLayer4Active: ColorUtils.solveOverlayColor(colLayer3Base, ColorUtils.mix(colLayer4Base, colOnLayer4, 0.80), 1 - root.contentTransparency);
property color colOnLayer4: m3colors.m3onSurface; property color colOnLayer4: m3colors.m3onSurface;
property color colLayer4Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer4, colOnLayer4, 0.90), root.contentTransparency) // Primary
property color colLayer4Active: ColorUtils.transparentize(ColorUtils.mix(colLayer4, colOnLayer4, 0.80), root.contentTransparency);
property color colPrimary: m3colors.m3primary property color colPrimary: m3colors.m3primary
property color colOnPrimary: m3colors.m3onPrimary property color colOnPrimary: m3colors.m3onPrimary
property color colPrimaryHover: ColorUtils.mix(colors.colPrimary, colLayer1Hover, 0.87) property color colPrimaryHover: ColorUtils.mix(colors.colPrimary, colLayer1Hover, 0.87)
@@ -146,13 +153,16 @@ Singleton {
property color colPrimaryContainerHover: ColorUtils.mix(colors.colPrimaryContainer, colors.colOnPrimaryContainer, 0.9) property color colPrimaryContainerHover: ColorUtils.mix(colors.colPrimaryContainer, colors.colOnPrimaryContainer, 0.9)
property color colPrimaryContainerActive: ColorUtils.mix(colors.colPrimaryContainer, colors.colOnPrimaryContainer, 0.8) property color colPrimaryContainerActive: ColorUtils.mix(colors.colPrimaryContainer, colors.colOnPrimaryContainer, 0.8)
property color colOnPrimaryContainer: m3colors.m3onPrimaryContainer property color colOnPrimaryContainer: m3colors.m3onPrimaryContainer
// Secondary
property color colSecondary: m3colors.m3secondary property color colSecondary: m3colors.m3secondary
property color colOnSecondary: m3colors.m3onSecondary
property color colSecondaryHover: ColorUtils.mix(m3colors.m3secondary, colLayer1Hover, 0.85) property color colSecondaryHover: ColorUtils.mix(m3colors.m3secondary, colLayer1Hover, 0.85)
property color colSecondaryActive: ColorUtils.mix(m3colors.m3secondary, colLayer1Active, 0.4) property color colSecondaryActive: ColorUtils.mix(m3colors.m3secondary, colLayer1Active, 0.4)
property color colOnSecondary: m3colors.m3onSecondary
property color colSecondaryContainer: m3colors.m3secondaryContainer property color colSecondaryContainer: m3colors.m3secondaryContainer
property color colSecondaryContainerHover: ColorUtils.mix(m3colors.m3secondaryContainer, m3colors.m3onSecondaryContainer, 0.90) property color colSecondaryContainerHover: ColorUtils.mix(m3colors.m3secondaryContainer, m3colors.m3onSecondaryContainer, 0.90)
property color colSecondaryContainerActive: ColorUtils.mix(m3colors.m3secondaryContainer, m3colors.m3onSecondaryContainer, 0.54) property color colSecondaryContainerActive: ColorUtils.mix(m3colors.m3secondaryContainer, m3colors.m3onSecondaryContainer, 0.54)
property color colOnSecondaryContainer: m3colors.m3onSecondaryContainer
// Tertiary
property color colTertiary: m3colors.m3tertiary property color colTertiary: m3colors.m3tertiary
property color colTertiaryHover: ColorUtils.mix(m3colors.m3tertiary, colLayer1Hover, 0.85) property color colTertiaryHover: ColorUtils.mix(m3colors.m3tertiary, colLayer1Hover, 0.85)
property color colTertiaryActive: ColorUtils.mix(m3colors.m3tertiary, colLayer1Active, 0.4) property color colTertiaryActive: ColorUtils.mix(m3colors.m3tertiary, colLayer1Active, 0.4)
@@ -161,16 +171,17 @@ Singleton {
property color colTertiaryContainerActive: ColorUtils.mix(m3colors.m3tertiaryContainer, colLayer1Active, 0.54) property color colTertiaryContainerActive: ColorUtils.mix(m3colors.m3tertiaryContainer, colLayer1Active, 0.54)
property color colOnTertiary: m3colors.m3onTertiary property color colOnTertiary: m3colors.m3onTertiary
property color colOnTertiaryContainer: m3colors.m3onTertiaryContainer property color colOnTertiaryContainer: m3colors.m3onTertiaryContainer
property color colOnSecondaryContainer: m3colors.m3onSecondaryContainer // Surface
property color colSurfaceContainerLow: ColorUtils.transparentize(m3colors.m3surfaceContainerLow, root.contentTransparency)
property color colSurfaceContainer: ColorUtils.transparentize(m3colors.m3surfaceContainer, root.contentTransparency)
property color colBackgroundSurfaceContainer: ColorUtils.transparentize(m3colors.m3surfaceContainer, root.backgroundTransparency) property color colBackgroundSurfaceContainer: ColorUtils.transparentize(m3colors.m3surfaceContainer, root.backgroundTransparency)
property color colSurfaceContainerHigh: ColorUtils.transparentize(m3colors.m3surfaceContainerHigh, root.contentTransparency) property color colSurfaceContainerLow: ColorUtils.solveOverlayColor(m3colors.m3background, m3colors.m3surfaceContainerLow, 1 - root.contentTransparency)
property color colSurfaceContainerHighest: ColorUtils.transparentize(m3colors.m3surfaceContainerHighest, root.contentTransparency) property color colSurfaceContainer: ColorUtils.solveOverlayColor(m3colors.m3surfaceContainerLow, m3colors.m3surfaceContainer, 1 - root.contentTransparency)
property color colSurfaceContainerHigh: ColorUtils.solveOverlayColor(m3colors.m3surfaceContainer, m3colors.m3surfaceContainerHigh, 1 - root.contentTransparency)
property color colSurfaceContainerHighest: ColorUtils.solveOverlayColor(m3colors.m3surfaceContainerHigh, m3colors.m3surfaceContainerHighest, 1 - root.contentTransparency)
property color colSurfaceContainerHighestHover: ColorUtils.mix(m3colors.m3surfaceContainerHighest, m3colors.m3onSurface, 0.95) property color colSurfaceContainerHighestHover: ColorUtils.mix(m3colors.m3surfaceContainerHighest, m3colors.m3onSurface, 0.95)
property color colSurfaceContainerHighestActive: ColorUtils.mix(m3colors.m3surfaceContainerHighest, m3colors.m3onSurface, 0.85) property color colSurfaceContainerHighestActive: ColorUtils.mix(m3colors.m3surfaceContainerHighest, m3colors.m3onSurface, 0.85)
property color colOnSurface: m3colors.m3onSurface property color colOnSurface: m3colors.m3onSurface
property color colOnSurfaceVariant: m3colors.m3onSurfaceVariant property color colOnSurfaceVariant: m3colors.m3onSurfaceVariant
// Misc
property color colTooltip: m3colors.m3inverseSurface property color colTooltip: m3colors.m3inverseSurface
property color colOnTooltip: m3colors.m3inverseOnSurface property color colOnTooltip: m3colors.m3inverseOnSurface
property color colScrim: ColorUtils.transparentize(m3colors.m3scrim, 0.5) property color colScrim: ColorUtils.transparentize(m3colors.m3scrim, 0.5)
@@ -135,4 +135,38 @@ Singleton {
var c = Qt.color(color); var c = Qt.color(color);
return c.hslLightness < 0.5; return c.hslLightness < 0.5;
} }
/**
* Clamps a value to the inclusive range [0, 1].
*
* @param {number} x - The value to clamp.
* @returns {number} The clamped value in the range [0, 1].
*/
function clamp01(x) {
return Math.min(1, Math.max(0, x));
}
/**
* Solves for the solid overlay color that, when composited over a base color
* with a given opacity, yields the target color.
*
* The compositing equation is:
* result = overlay * overlayOpacity + base * (1 - overlayOpacity)
*
* This function algebraically inverts that equation per channel.
*
* @param {Qt.rgba} baseColor - The base (background) color.
* @param {Qt.rgba} targetColor - The resulting color after compositing.
* @param {number} overlayOpacity - The overlay opacity (0-1).
* @returns {Qt.rgba} The solved overlay color
*/
function solveOverlayColor(baseColor, targetColor, overlayOpacity) {
let invA = 1.0 - overlayOpacity;
let r = (targetColor.r - baseColor.r * invA) / overlayOpacity;
let g = (targetColor.g - baseColor.g * invA) / overlayOpacity;
let b = (targetColor.b - baseColor.b * invA) / overlayOpacity;
return Qt.rgba(clamp01(r), clamp01(g), clamp01(b), overlayOpacity);
}
} }
@@ -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 property bool automaticallyReset: true
readonly property real dragDiffX: _dragDiffX readonly property real dragDiffX: _dragDiffX
readonly property real dragDiffY: _dragDiffY 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 dragPressed(diffX: real, diffY: real)
signal dragReleased(diffX: real, diffY: real) signal dragReleased(diffX: real, diffY: real)
property real startX: 0
property real startY: 0
property bool dragging: false property bool dragging: false
property real _dragDiffX: 0 property real _dragDiffX: 0
property real _dragDiffY: 0 property real _dragDiffY: 0
@@ -121,7 +121,7 @@ MouseArea { // Notification group area
id: background id: background
anchors.left: parent.left anchors.left: parent.left
width: parent.width width: parent.width
color: popup ? ColorUtils.applyAlpha(Appearance.colors.colLayer2, 1 - Appearance.backgroundTransparency) : Appearance.colors.colLayer2 color: popup ? Appearance.colors.colBackgroundSurfaceContainer : Appearance.colors.colLayer2
radius: Appearance.rounding.normal radius: Appearance.rounding.normal
anchors.leftMargin: root.xOffset anchors.leftMargin: root.xOffset
@@ -12,19 +12,30 @@ Item {
required property var tabButtonList required property var tabButtonList
function incrementCurrentIndex() { function incrementCurrentIndex() {
tabBar.incrementCurrentIndex() tabBar.incrementCurrentIndex();
} }
function decrementCurrentIndex() { function decrementCurrentIndex() {
tabBar.decrementCurrentIndex() tabBar.decrementCurrentIndex();
} }
function setCurrentIndex(index) { function setCurrentIndex(index) {
tabBar.setCurrentIndex(index) tabBar.setCurrentIndex(index);
} }
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
implicitWidth: contentItem.implicitWidth implicitWidth: contentItem.implicitWidth
implicitHeight: 40 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 { Row {
id: contentItem id: contentItem
z: 1 z: 1
@@ -33,16 +44,7 @@ Item {
Repeater { Repeater {
model: root.tabButtonList model: root.tabButtonList
delegate: ToolbarTabButton { delegate: root.delegate
required property int index
required property var modelData
current: index == root.currentIndex
text: modelData.name
materialSymbol: modelData.icon
onClicked: {
root.setCurrentIndex(index)
}
}
} }
} }
@@ -76,23 +78,23 @@ Item {
z: 2 z: 2
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onWheel: (event) => { onWheel: event => {
if (event.angleDelta.y < 0) { if (event.angleDelta.y < 0) {
root.incrementCurrentIndex(); root.incrementCurrentIndex();
} } else {
else {
root.decrementCurrentIndex(); 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 // We use it only for the logic and draw stuff manually
TabBar { TabBar {
id: tabBar id: tabBar
z: -1 z: -1
background: null 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 model: root.tabButtonList.length
delegate: TabButton { delegate: TabButton {
background: null background: null
@@ -4,5 +4,5 @@ import qs.modules.common
Rectangle { Rectangle {
id: contentItem id: contentItem
anchors.fill: parent anchors.fill: parent
color: Appearance.colors.colSurfaceContainer color: Appearance.m3colors.m3surfaceContainer
} }
@@ -190,7 +190,7 @@ AbstractOverlayWidget {
fill: parent fill: parent
margins: root.resizeMargin margins: root.resizeMargin
} }
color: ColorUtils.transparentize(Appearance.colors.colLayer1, (root.fancyBorders && GlobalStates.overlayOpen) ? 0 : 1) color: ColorUtils.transparentize(Appearance.colors.colLayer1Base, (root.fancyBorders && GlobalStates.overlayOpen) ? 0 : 1)
radius: root.radius radius: root.radius
border.color: ColorUtils.transparentize(Appearance.colors.colOutlineVariant, GlobalStates.overlayOpen ? 0 : 1) border.color: ColorUtils.transparentize(Appearance.colors.colOutlineVariant, GlobalStates.overlayOpen ? 0 : 1)
border.width: 1 border.width: 1
@@ -217,7 +217,7 @@ AbstractOverlayWidget {
Layout.fillWidth: true Layout.fillWidth: true
implicitWidth: titleBarRow.implicitWidth + root.padding * 2 implicitWidth: titleBarRow.implicitWidth + root.padding * 2
implicitHeight: titleBarRow.implicitHeight + root.padding * 2 implicitHeight: titleBarRow.implicitHeight + root.padding * 2
color: root.fancyBorders ? "transparent" : Appearance.colors.colLayer1 color: root.fancyBorders ? "transparent" : Appearance.colors.colLayer1Base
// border.color: Appearance.colors.colOutlineVariant // border.color: Appearance.colors.colOutlineVariant
// border.width: 1 // border.width: 1
@@ -192,6 +192,14 @@ Scope {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
} }
} }
GlobalShortcut {
name: "overviewWorkspacesClose"
description: "Closes overview on press"
onPressed: {
GlobalStates.overviewOpen = false;
}
}
GlobalShortcut { GlobalShortcut {
name: "overviewWorkspacesToggle" name: "overviewWorkspacesToggle"
description: "Toggles overview on press" description: "Toggles overview on press"
@@ -101,7 +101,7 @@ Item {
required property int index required property int index
property int colIndex: index property int colIndex: index
property int workspaceValue: root.workspaceGroup * root.workspacesShown + getWsInCell(row.index, colIndex) property int workspaceValue: root.workspaceGroup * root.workspacesShown + getWsInCell(row.index, colIndex)
property color defaultWorkspaceColor: ColorUtils.mix(Appearance.colors.colBackgroundSurfaceContainer, Appearance.colors.colSurfaceContainerHigh, 0.8) property color defaultWorkspaceColor: Appearance.colors.colSurfaceContainerLow
property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1) property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1)
property color hoveredBorderColor: Appearance.colors.colLayer2Hover property color hoveredBorderColor: Appearance.colors.colLayer2Hover
property bool hoveredWhileDragging: false property bool hoveredWhileDragging: false
@@ -1,5 +1,6 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import qs.modules.common import qs.modules.common
import qs.modules.common.utils
import qs.modules.common.functions import qs.modules.common.functions
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
@@ -32,14 +33,8 @@ PanelWindow {
property var action: RegionSelection.SnipAction.Copy property var action: RegionSelection.SnipAction.Copy
property var selectionMode: RegionSelection.SelectionMode.RectCorners property var selectionMode: RegionSelection.SelectionMode.RectCorners
signal dismiss() signal dismiss()
property string saveScreenshotDir: Config.options.screenSnip.savePath !== ""
? Config.options.screenSnip.savePath
: ""
property string screenshotDir: Directories.screenshotTemp 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 overlayColor: "#88111111"
property color brightText: Appearance.m3colors.darkmode ? Appearance.colors.colOnLayer0 : Appearance.colors.colLayer0 property color brightText: Appearance.m3colors.darkmode ? Appearance.colors.colOnLayer0 : Appearance.colors.colLayer0
property color brightSecondary: Appearance.m3colors.darkmode ? Appearance.colors.colSecondary : Appearance.colors.colOnSecondary 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 regionX: Math.min(dragStartX, draggingX)
property real regionY: Math.min(dragStartY, draggingY) property real regionY: Math.min(dragStartY, draggingY)
Process { TempScreenshotProcess {
id: screenshotProc id: screenshotProc
running: true 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) => { onExited: (exitCode, exitStatus) => {
if (root.enableContentRegions) imageDetectionProcess.running = true; if (root.enableContentRegions) imageDetectionProcess.running = true;
root.preparationDone = !checkRecordingProc.running; 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() { function snip() {
// Validity check // Validity check
if (root.regionWidth <= 0 || root.regionHeight <= 0) { if (root.regionWidth <= 0 || root.regionHeight <= 0) {
@@ -246,62 +264,20 @@ PanelWindow {
if (root.action === RegionSelection.SnipAction.Copy || root.action === RegionSelection.SnipAction.Edit) { if (root.action === RegionSelection.SnipAction.Copy || root.action === RegionSelection.SnipAction.Edit) {
root.action = root.mouseButton === Qt.RightButton ? RegionSelection.SnipAction.Edit : RegionSelection.SnipAction.Copy; root.action = root.mouseButton === Qt.RightButton ? RegionSelection.SnipAction.Edit : RegionSelection.SnipAction.Copy;
} }
// Set command for action const screenshotDir = Config.options.screenSnip.savePath !== "" ? //
const rx = Math.round(root.regionX * root.monitorScale); Config.options.screenSnip.savePath : "";
const ry = Math.round(root.regionY * root.monitorScale); var screenshotAction = root.getScreenshotAction();
const rw = Math.round(root.regionWidth * root.monitorScale); const command = ScreenshotAction.getCommand(
const rh = Math.round(root.regionHeight * root.monitorScale); root.regionX * root.monitorScale, //
const cropBase = `magick ${StringUtils.shellSingleQuoteEscape(root.screenshotPath)} ` root.regionY * root.monitorScale, //
+ `-crop ${rw}x${rh}+${rx}+${ry}` root.regionWidth * root.monitorScale,//
const cropToStdout = `${cropBase} -` root.regionHeight * root.monitorScale, //
const cropInPlace = `${cropBase} '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}'` root.screenshotPath, //
const cleanup = `rm '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}'` screenshotAction, //
const slurpRegion = `${rx},${ry} ${rw}x${rh}` screenshotDir
const uploadAndGetUrl = (filePath) => { )
return `curl -sF files[]=@'${StringUtils.shellSingleQuoteEscape(filePath)}' ${root.fileUploadApiEndpoint} | jq -r '.files[0].url'` snipProc.command = command;
}
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;
}
// Image post-processing // Image post-processing
snipProc.startDetached(); snipProc.startDetached();
@@ -25,6 +25,10 @@ Rectangle {
border.width: targeted ? 4 : 2 border.width: targeted ? 4 : 2
radius: 4 radius: 4
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
visible: opacity > 0 visible: opacity > 0
Behavior on opacity { Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
@@ -45,9 +45,7 @@ Scope {
WlrLayershell.namespace: "quickshell:session" WlrLayershell.namespace: "quickshell:session"
WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
// This is a big surface so we needa carefully choose the transparency, color: ColorUtils.transparentize(Appearance.m3colors.m3background, Appearance.m3colors.darkmode ? 0.05 : 0.12)
// or we'll get a large scary rgb blob
color: ColorUtils.transparentize(Appearance.m3colors.m3background, Appearance.m3colors.darkmode ? 0.04 : 0.12)
anchors { anchors {
top: true top: true
@@ -314,7 +314,10 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
implicitWidth: statusRowLayout.implicitWidth + 10 * 2 implicitWidth: statusRowLayout.implicitWidth + 10 * 2
implicitHeight: Math.max(statusRowLayout.implicitHeight, 38) implicitHeight: Math.max(statusRowLayout.implicitHeight, 38)
radius: Appearance.rounding.normal - root.padding radius: Appearance.rounding.normal - root.padding
color: Appearance.colors.colLayer2 color: messageListView.atYBeginning ? Appearance.colors.colLayer2 : Appearance.colors.colLayer2Base
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
RowLayout { RowLayout {
id: statusRowLayout id: statusRowLayout
anchors.centerIn: parent anchors.centerIn: parent
@@ -13,7 +13,7 @@ Scope {
LazyLoader { LazyLoader {
id: barLoader id: barLoader
active: GlobalStates.barOpen && !GlobalStates.screenLocked active: GlobalStates.barOpen
component: Variants { component: Variants {
model: Quickshell.screens model: Quickshell.screens
delegate: PanelWindow { // Bar window delegate: PanelWindow { // Bar window
@@ -17,8 +17,9 @@ Singleton {
property string iconsPath: `${Directories.assetsPath}/icons/fluent` property string iconsPath: `${Directories.assetsPath}/icons/fluent`
property bool dark: Appearance.m3colors.darkmode property bool dark: Appearance.m3colors.darkmode
property real backgroundTransparency: 0.16 readonly property bool transparencyEnabled: Config.options.appearance.transparency.enable
property real panelBackgroundTransparency: 0.14 property real backgroundTransparency: transparencyEnabled ? 0.16 : 0
property real panelBackgroundTransparency: transparencyEnabled ? 0.14 : 0
property real panelLayerTransparency: root.dark ? 0.9 : 0.7 property real panelLayerTransparency: root.dark ? 0.9 : 0.7
property real contentTransparency: root.dark ? 0.87 : 0.5 property real contentTransparency: root.dark ? 0.87 : 0.5
function applyBackgroundTransparency(col) { function applyBackgroundTransparency(col) {
@@ -27,23 +28,22 @@ Singleton {
function applyContentTransparency(col) { function applyContentTransparency(col) {
return ColorUtils.applyAlpha(col, 1 - root.contentTransparency) return ColorUtils.applyAlpha(col, 1 - root.contentTransparency)
} }
lightColors: QtObject { // TODO: figure out transparency lightColors: QtObject {
id: lightColors id: lightColors
property color bgPanelFooter: "#EEEEEE"
property color bgPanelBody: "#F2F2F2" property color bgPanelBody: "#F2F2F2"
property color bgPanelSeparator: "#E0E0E0" property color bgPanelSeparator: "#E0E0E0"
property color bg0: "#EEEEEE" property color bg0: "#EEEEEE"
property color bg0Border: '#adadad' property color bg0Border: '#BEBEBE'
property color bg1: "#F7F7F7"
property color bg1Base: "#F7F7F7" property color bg1Base: "#F7F7F7"
property color bg1: "#F7F7F7"
property color bg1Hover: "#F7F7F7" property color bg1Hover: "#F7F7F7"
property color bg1Active: '#EFEFEF' property color bg1Active: '#EFEFEF'
property color bg1Border: '#d7d7d7' property color bg1Border: '#E9E9E9'
property color bg2: "#FBFBFB" property color bg2: "#FBFBFB"
property color bg2Base: "#FBFBFB" property color bg2Base: "#FBFBFB"
property color bg2Hover: '#ffffff' property color bg2Hover: '#ffffff'
property color bg2Active: '#eeeeee' property color bg2Active: '#eeeeee'
property color bg2Border: '#cdcdcd' property color bg2Border: '#E0E0E0'
property color subfg: "#5C5C5C" property color subfg: "#5C5C5C"
property color fg: "#000000" property color fg: "#000000"
property color fg1: "#626262" property color fg1: "#626262"
@@ -58,21 +58,20 @@ Singleton {
} }
darkColors: QtObject { darkColors: QtObject {
id: darkColors id: darkColors
property color bgPanelFooter: "#1C1C1C" property color bgPanelBody: '#242424'
property color bgPanelBody: '#616161'
property color bgPanelSeparator: "#191919" property color bgPanelSeparator: "#191919"
property color bg0: "#1C1C1C" property color bg0: "#1C1C1C"
property color bg0Border: "#404040" property color bg0Border: "#404040"
property color bg1Base: "#2C2C2C" property color bg1Base: '#2C2C2C'
property color bg1: '#9f9f9f' property color bg1: '#2C2C2C'
property color bg1Hover: "#b3b3b3" property color bg1Hover: "#292929"
property color bg1Active: '#727272' property color bg1Active: '#252525'
property color bg1Border: '#bebebe' property color bg1Border: '#bebebe'
property color bg2Base: "#313131" property color bg2Base: "#313131"
property color bg2: '#8a8a8a' property color bg2: '#313131'
property color bg2Hover: '#b1b1b1' property color bg2Hover: '#363636'
property color bg2Active: '#919191' property color bg2Active: '#2B2B2B'
property color bg2Border: '#bdbdbd' property color bg2Border: '#404040'
property color subfg: "#CED1D7" property color subfg: "#CED1D7"
property color fg: "#FFFFFF" property color fg: "#FFFFFF"
property color fg1: "#D1D1D1" property color fg1: "#D1D1D1"
@@ -87,38 +86,46 @@ Singleton {
} }
colors: QtObject { colors: QtObject {
id: colors id: colors
// Special
property color shadow: ColorUtils.transparentize('#161616', 0.62) property color shadow: ColorUtils.transparentize('#161616', 0.62)
property color ambientShadow: ColorUtils.transparentize("#000000", 0.75) property color ambientShadow: ColorUtils.transparentize("#000000", 0.75)
property color bgPanelFooterBase: ColorUtils.transparentize(root.dark ? root.darkColors.bgPanelFooter : root.lightColors.bgPanelFooter, root.panelBackgroundTransparency) property color bgPanelFooterBase: ColorUtils.transparentize(root.dark ? root.darkColors.bg0 : root.lightColors.bg0, root.panelBackgroundTransparency)
property color bgPanelFooter: ColorUtils.transparentize(root.dark ? root.darkColors.bgPanelFooter : root.lightColors.bgPanelFooter, root.panelLayerTransparency) property color bgPanelFooter: ColorUtils.transparentize(bgPanelFooterBase, root.panelLayerTransparency)
property color bgPanelBody: ColorUtils.transparentize(root.dark ? root.darkColors.bgPanelBody : root.lightColors.bgPanelBody, root.panelLayerTransparency) property color bgPanelBodyBase: root.dark ? root.darkColors.bgPanelBody : root.lightColors.bgPanelBody
property color bgPanelSeparator: ColorUtils.transparentize(root.dark ? root.darkColors.bgPanelSeparator : root.lightColors.bgPanelSeparator, root.backgroundTransparency) property color bgPanelBody: ColorUtils.solveOverlayColor(bgPanelFooterBase,bgPanelBodyBase, 1 - root.panelLayerTransparency)
property color bg0Opaque: root.dark ? root.darkColors.bg0 : root.lightColors.bg0 property color bgPanelSeparator: ColorUtils.solveOverlayColor(bgPanelBodyBase, root.dark ? root.darkColors.bgPanelSeparator : root.lightColors.bgPanelSeparator, 1 - root.panelBackgroundTransparency)
property color bg0: ColorUtils.transparentize(bg0Opaque, root.backgroundTransparency) // Layer 0
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 bg0Border: ColorUtils.transparentize(root.dark ? root.darkColors.bg0Border : root.lightColors.bg0Border, root.backgroundTransparency)
property color bg1Base: root.dark ? root.darkColors.bg1Base : root.lightColors.bg1Base // Layer 1
property color bg1: ColorUtils.transparentize(root.dark ? root.darkColors.bg1 : root.lightColors.bg1, root.contentTransparency) property color bg1Base: root.dark ? root.darkColors.bg1 : root.lightColors.bg1
property color bg1Hover: ColorUtils.transparentize(root.dark ? root.darkColors.bg1Hover : root.lightColors.bg1Hover, root.contentTransparency) property color bg1: ColorUtils.solveOverlayColor(bg0Base, bg1Base, 1 - root.contentTransparency)
property color bg1Active: ColorUtils.transparentize(root.dark ? root.darkColors.bg1Active : root.lightColors.bg1Active, root.contentTransparency) property color bg1Hover: ColorUtils.solveOverlayColor(bg0Base, root.dark ? root.darkColors.bg1Hover : root.lightColors.bg1Hover, 1 - root.contentTransparency)
property color bg1Border: ColorUtils.transparentize(root.dark ? root.darkColors.bg1Border : root.lightColors.bg1Border, root.contentTransparency) property color bg1Active: ColorUtils.solveOverlayColor(bg0Base, root.dark ? root.darkColors.bg1Active : root.lightColors.bg1Active, 1 - root.contentTransparency)
property color bg2Base: root.dark ? root.darkColors.bg2Base : root.lightColors.bg2Base property color bg1Border: ColorUtils.solveOverlayColor(bg0Base, root.dark ? root.darkColors.bg1Border : root.lightColors.bg1Border, 1 - root.contentTransparency)
property color bg2: ColorUtils.transparentize(root.dark ? root.darkColors.bg2 : root.lightColors.bg2, root.contentTransparency) // Layer 2
property color bg2Hover: ColorUtils.transparentize(root.dark ? root.darkColors.bg2Hover : root.lightColors.bg2Hover, root.contentTransparency) property color bg2Base: root.dark ? root.darkColors.bg2 : root.lightColors.bg2
property color bg2Active: ColorUtils.transparentize(root.dark ? root.darkColors.bg2Active : root.lightColors.bg2Active, root.contentTransparency) property color bg2: ColorUtils.solveOverlayColor(bgPanelBodyBase, bg2Base, 1 - root.contentTransparency)
property color bg2Border: ColorUtils.transparentize(root.dark ? root.darkColors.bg2Border : root.lightColors.bg2Border, root.contentTransparency) property color bg2Hover: ColorUtils.solveOverlayColor(bgPanelBodyBase, root.dark ? root.darkColors.bg2Hover : root.lightColors.bg2Hover, 1 - root.contentTransparency)
property color bg2Active: ColorUtils.solveOverlayColor(bgPanelBodyBase, root.dark ? root.darkColors.bg2Active : root.lightColors.bg2Active, 1 - root.contentTransparency)
property color bg2Border: ColorUtils.solveOverlayColor(bgPanelBodyBase, root.dark ? root.darkColors.bg2Border : root.lightColors.bg2Border, 1 - root.contentTransparency)
// Foreground / Text
property color subfg: root.dark ? root.darkColors.subfg : root.lightColors.subfg property color subfg: root.dark ? root.darkColors.subfg : root.lightColors.subfg
property color fg: root.dark ? root.darkColors.fg : root.lightColors.fg property color fg: root.dark ? root.darkColors.fg : root.lightColors.fg
property color fg1: root.dark ? root.darkColors.fg1 : root.lightColors.fg1 property color fg1: root.dark ? root.darkColors.fg1 : root.lightColors.fg1
property color inactiveIcon: root.dark ? root.darkColors.inactiveIcon : root.lightColors.inactiveIcon property color inactiveIcon: root.dark ? root.darkColors.inactiveIcon : root.lightColors.inactiveIcon
property color link: root.dark ? root.darkColors.link : root.lightColors.link
// Controls
property color controlBgInactive: root.dark ? root.darkColors.controlBgInactive : root.lightColors.controlBgInactive property color controlBgInactive: root.dark ? root.darkColors.controlBgInactive : root.lightColors.controlBgInactive
property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg
property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover
property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg
property color inputBg: root.dark ? root.darkColors.inputBg : root.lightColors.inputBg property color inputBg: root.dark ? root.darkColors.inputBg : root.lightColors.inputBg
property color link: root.dark ? root.darkColors.link : root.lightColors.link
property color danger: "#C42B1C" property color danger: "#C42B1C"
property color dangerActive: "#B62D1F" property color dangerActive: "#B62D1F"
property color warning: "#FF9900" property color warning: "#FF9900"
// Accent
property color accent: Appearance.colors.colPrimary property color accent: Appearance.colors.colPrimary
property color accentHover: Appearance.colors.colPrimaryHover property color accentHover: Appearance.colors.colPrimaryHover
property color accentActive: Appearance.colors.colPrimaryActive property color accentActive: Appearance.colors.colPrimaryActive
@@ -39,9 +39,10 @@ Button {
} }
} }
property color fgColor: { property color fgColor: {
if (!root.enabled) return root.colForegroundDisabled
if (root.checked) return root.colForegroundToggled if (root.checked) return root.colForegroundToggled
if (root.enabled) return root.colForeground if (root.enabled) return root.colForeground
return root.colForegroundDisabled return root.colForeground
} }
property alias horizontalAlignment: buttonText.horizontalAlignment property alias horizontalAlignment: buttonText.horizontalAlignment
font { font {
@@ -76,8 +76,9 @@ Menu {
contentItem: Item { contentItem: Item {
implicitWidth: menuListView.implicitWidth implicitWidth: menuListView.implicitWidth
implicitHeight: menuListView.implicitHeight implicitHeight: menuListView.implicitHeight
ListView { WListView {
id: menuListView id: menuListView
interactive: contentHeight > height
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
@@ -87,6 +88,7 @@ Menu {
topMargin: root.downDirection ? root.sourceEdgeMargin : root.margins topMargin: root.downDirection ? root.sourceEdgeMargin : root.margins
bottomMargin: root.downDirection ? root.margins : root.sourceEdgeMargin bottomMargin: root.downDirection ? root.margins : root.sourceEdgeMargin
} }
clip: true
implicitHeight: contentHeight implicitHeight: contentHeight
implicitWidth: Array.from({ implicitWidth: Array.from({
length: count length: count
@@ -6,6 +6,7 @@ import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import qs.modules.common import qs.modules.common
import qs.modules.common.functions import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks import qs.modules.waffle.looks
MenuItem { MenuItem {
@@ -14,11 +15,11 @@ MenuItem {
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1) property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property color colBackgroundHover: Looks.colors.bg2Hover property color colBackgroundHover: Looks.colors.bg2Hover
property color colBackgroundActive: Looks.colors.bg2Active property color colBackgroundActive: Looks.colors.bg2Active
property color colBackgroundToggled: Looks.colors.accent property color colBackgroundToggled: Looks.colors.bg2Hover
property color colBackgroundToggledHover: Looks.colors.accentHover property color colBackgroundToggledHover: Looks.colors.bg2Active
property color colBackgroundToggledActive: Looks.colors.accentActive property color colBackgroundToggledActive: Looks.colors.bg2Hover
property color colForeground: Looks.colors.fg 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 colForegroundDisabled: ColorUtils.transparentize(Looks.colors.subfg, 0.4)
property color color: { property color color: {
if (!root.enabled) if (!root.enabled)
@@ -70,27 +71,57 @@ MenuItem {
implicitHeight: Math.max(28, contentItem.implicitHeight) + topInset + bottomInset implicitHeight: Math.max(28, contentItem.implicitHeight) + topInset + bottomInset
implicitWidth: contentItem.implicitWidth + leftInset + rightInset + leftPadding + rightPadding implicitWidth: contentItem.implicitWidth + leftInset + rightInset + leftPadding + rightPadding
contentItem: RowLayout { contentItem: Item {
id: contentLayout implicitWidth: contentLayout.implicitWidth
spacing: 12 implicitHeight: contentLayout.implicitHeight
FluentIcon {
id: buttonIcon RowLayout {
monochrome: true id: contentLayout
implicitSize: 20 anchors.fill: parent
Layout.fillWidth: false spacing: 12
Layout.alignment: Qt.AlignVCenter FluentIcon {
color: root.fgColor id: buttonIcon
visible: root.icon.name !== ""; monochrome: true
icon: root.icon.name 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 WFadeLoader {
Layout.fillWidth: true anchors {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft verticalCenter: parent.verticalCenter
text: root.text left: parent.left
horizontalAlignment: Text.AlignLeft leftMargin: -root.leftPadding + width
font.pixelSize: Looks.font.pixelSize.large }
color: root.fgColor 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
}
}
@@ -7,7 +7,7 @@ import qs.modules.common.widgets
import qs.modules.common.functions import qs.modules.common.functions
import qs.modules.waffle.looks import qs.modules.waffle.looks
BodyRectangle { FooterRectangle {
id: root id: root
anchors.fill: parent anchors.fill: parent
implicitHeight: 230 implicitHeight: 230
@@ -15,6 +15,9 @@ MouseArea {
required property var notification required property var notification
property bool expanded: notification.actions.length > 0 property bool expanded: notification.actions.length > 0
property string groupExpandControlMessage: "" property string groupExpandControlMessage: ""
readonly property bool isPopup: notification?.popup ?? false
signal groupExpandToggle signal groupExpandToggle
hoverEnabled: true hoverEnabled: true
@@ -56,13 +59,13 @@ MouseArea {
Rectangle { Rectangle {
id: contentItem id: contentItem
width: parent.width width: parent.width
color: Looks.colors.bgPanelBody color: root.isPopup ? Looks.colors.bg0 : Looks.colors.bgPanelBody
radius: Looks.radius.medium radius: root.isPopup ? Looks.radius.large : Looks.radius.medium
property real padding: 12 property real padding: 12
implicitHeight: notificationContent.implicitHeight + padding * 2 implicitHeight: notificationContent.implicitHeight + padding * 2
implicitWidth: notificationContent.implicitWidth + padding * 2 implicitWidth: notificationContent.implicitWidth + padding * 2
border.width: 1 border.width: 1
border.color: ColorUtils.applyAlpha(Looks.colors.ambientShadow, 0.1) border.color: root.isPopup ? Looks.colors.bg2Border : Looks.colors.bgPanelSeparator
Behavior on x { Behavior on x {
animation: Looks.transition.enter.createObject(this) animation: Looks.transition.enter.createObject(this)
@@ -157,9 +160,9 @@ MouseArea {
NotificationHeaderButton { NotificationHeaderButton {
Layout.rightMargin: 4 Layout.rightMargin: 4
opacity: root.containsMouse ? 1 : 0 opacity: (root.containsMouse || root.isPopup) ? 1 : 0
icon.name: "dismiss" icon.name: "dismiss"
implicitSize: 12 implicitSize: 14
onClicked: root.dismiss() onClicked: root.dismiss()
} }
} }
@@ -0,0 +1,66 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.notificationCenter
Scope {
id: notificationPopup
PanelWindow {
id: root
visible: (Notifications.popupList.length > 0) && !GlobalStates.screenLocked
screen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name) ?? null
WlrLayershell.namespace: "quickshell:notificationPopup"
WlrLayershell.layer: WlrLayer.Overlay
exclusiveZone: 0
anchors {
top: true
right: true
bottom: true
}
mask: Region {
item: listview.contentItem
}
color: "transparent"
implicitWidth: listview.implicitWidth
WListView {
id: listview
anchors {
bottom: parent.bottom
right: parent.right
left: parent.left
}
leftMargin: 16
rightMargin: 16
topMargin: 16
bottomMargin: 16
height: Math.min(contentItem.height + topMargin + bottomMargin, parent.height)
width: parent.width - Appearance.sizes.elevationMargin * 2
implicitWidth: 396
spacing:12
model: ScriptModel {
values: Notifications.popupList
}
delegate: WSingleNotification {
required property var modelData
notification: modelData
width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
}
}
}
}
@@ -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()
}
}
@@ -44,7 +44,7 @@ WChoiceButton {
Layout.fillHeight: true Layout.fillHeight: true
horizontalPadding: 10 horizontalPadding: 10
verticalPadding: 11 verticalPadding: 11
implicitHeight: root.firstEntry ? 62 : 36 implicitHeight: Math.max(root.firstEntry ? 62 : 36, entryContentRow.implicitHeight + 8 * 2)
implicitWidth: entryContentRow.implicitWidth + leftPadding + rightPadding implicitWidth: entryContentRow.implicitWidth + leftPadding + rightPadding
topRightRadius: 0 topRightRadius: 0
bottomRightRadius: 0 bottomRightRadius: 0
@@ -54,6 +54,7 @@ WChoiceButton {
id: entryContentRow id: entryContentRow
anchors { anchors {
left: parent.left left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
spacing: 8 spacing: 8
@@ -102,6 +103,7 @@ WChoiceButton {
text: root.entry.name text: root.entry.name
font.pixelSize: Looks.font.pixelSize.large font.pixelSize: Looks.font.pixelSize.large
maximumLineCount: 2 maximumLineCount: 2
elide: Text.ElideRight
} }
WText { WText {
@@ -109,6 +111,7 @@ WChoiceButton {
visible: root.firstEntry visible: root.firstEntry
text: root.entry.type text: root.entry.type
color: Looks.colors.accentUnfocused color: Looks.colors.accentUnfocused
elide: Text.ElideRight
} }
} }
@@ -15,6 +15,7 @@ RowLayout {
id: root id: root
property int maxResultsPerCategory: 4 property int maxResultsPerCategory: 4
property int resultLimit: 20
property StartMenuContext context property StartMenuContext context
property int currentIndex: context.currentIndex property int currentIndex: context.currentIndex
onCurrentIndexChanged: { onCurrentIndexChanged: {
@@ -99,21 +100,33 @@ RowLayout {
// Collect max 4 per category // Collect max 4 per category
var categorizedResults = []; var categorizedResults = [];
categories.forEach(category => { let categoriesArray = Array.from(categories);
let totalCount = 0;
for (let c = 0; c < categoriesArray.length; c++) {
let category = categoriesArray[c];
let count = 0; let count = 0;
for (let i = 0; i < allResults.length; i++) { for (let i = 0; i < allResults.length; i++) {
if (allResults[i].type === category) { if (allResults[i].type === category) {
if (totalCount >= root.resultLimit) {
break;
}
const entry = allResults[i]; const entry = allResults[i];
const tweakedEntry = searchResultComp.createObject(null, Object.assign({}, entry)); const tweakedEntry = searchResultComp.createObject(null, Object.assign({}, entry));
tweakedEntry.category = categorizedResults.length === 0 ? Translation.tr("Best match") : entry.type tweakedEntry.category = categorizedResults.length === 0 ? Translation.tr("Best match") : entry.type;
categorizedResults.push(tweakedEntry); // Section header categorizedResults.push(tweakedEntry); // Section header
count++; count++;
totalCount++;
if (count >= root.maxResultsPerCategory) { if (count >= root.maxResultsPerCategory) {
break; break;
} }
} }
} }
}); if (totalCount >= root.resultLimit) {
break;
}
}
// print(JSON.stringify(categorizedResults, null, 2)); // print(JSON.stringify(categorizedResults, null, 2));
return categorizedResults; return categorizedResults;
} }
@@ -28,13 +28,13 @@ GridLayout {
}), aggAppCatComp.createObject(null, { }), aggAppCatComp.createObject(null, {
name: Translation.tr("Creativity"), name: Translation.tr("Creativity"),
categories: ["AudioVideo", "Graphics"] categories: ["AudioVideo", "Graphics"]
}), aggAppCatComp.createObject(null, {
name: Translation.tr("Other"),
categories: ["Game"]
}), aggAppCatComp.createObject(null, { }), aggAppCatComp.createObject(null, {
name: Translation.tr("System"), name: Translation.tr("System"),
categories: ["Settings", "System"] categories: ["Settings", "System"]
}) }), aggAppCatComp.createObject(null, {
name: Translation.tr("Other"),
categories: ["Game"]
}),
] ]
Repeater { Repeater {
@@ -135,8 +135,8 @@ Singleton {
property var groupsByAppName: groupsForList(root.list) property var groupsByAppName: groupsForList(root.list)
property var popupGroupsByAppName: groupsForList(root.popupList) property var popupGroupsByAppName: groupsForList(root.popupList)
property var appNameList: appNameListForGroups(root.groupsByAppName) property list<string> appNameList: appNameListForGroups(root.groupsByAppName)
property var popupAppNameList: appNameListForGroups(root.popupGroupsByAppName) property list<string> popupAppNameList: appNameListForGroups(root.popupGroupsByAppName)
// Quickshell's notification IDs starts at 1 on each run, while saved notifications // Quickshell's notification IDs starts at 1 on each run, while saved notifications
// can already contain higher IDs. This is for avoiding id collisions // can already contain higher IDs. This is for avoiding id collisions
+5 -1
View File
@@ -32,8 +32,10 @@ import qs.modules.waffle.background
import qs.modules.waffle.bar import qs.modules.waffle.bar
import qs.modules.waffle.lock import qs.modules.waffle.lock
import qs.modules.waffle.notificationCenter import qs.modules.waffle.notificationCenter
import qs.modules.waffle.notificationPopup
import qs.modules.waffle.onScreenDisplay import qs.modules.waffle.onScreenDisplay
import qs.modules.waffle.polkit import qs.modules.waffle.polkit
import qs.modules.waffle.screenSnip
import qs.modules.waffle.startMenu import qs.modules.waffle.startMenu
import qs.modules.waffle.sessionScreen import qs.modules.waffle.sessionScreen
import qs.modules.waffle.taskView import qs.modules.waffle.taskView
@@ -87,8 +89,10 @@ ShellRoot {
PanelLoader { identifier: "wBackground"; component: WaffleBackground {} } PanelLoader { identifier: "wBackground"; component: WaffleBackground {} }
PanelLoader { identifier: "wLock"; component: WaffleLock {} } PanelLoader { identifier: "wLock"; component: WaffleLock {} }
PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} } PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} }
PanelLoader { identifier: "wNotificationPopup"; component: WaffleNotificationPopup {} }
PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} } PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} }
PanelLoader { identifier: "wPolkit"; component: WafflePolkit {} } PanelLoader { identifier: "wPolkit"; component: WafflePolkit {} }
PanelLoader { identifier: "wScreenSnip"; component: WScreenSnip {} }
PanelLoader { identifier: "wStartMenu"; component: WaffleStartMenu {} } PanelLoader { identifier: "wStartMenu"; component: WaffleStartMenu {} }
PanelLoader { identifier: "wSessionScreen"; component: WaffleSessionScreen {} } PanelLoader { identifier: "wSessionScreen"; component: WaffleSessionScreen {} }
PanelLoader { identifier: "wTaskView"; component: WaffleTaskView {} } PanelLoader { identifier: "wTaskView"; component: WaffleTaskView {} }
@@ -104,7 +108,7 @@ ShellRoot {
property list<string> families: ["ii", "waffle"] property list<string> families: ["ii", "waffle"]
property var panelFamilies: ({ property var panelFamilies: ({
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"], "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", "wNotificationPopup", "wOnScreenDisplay", "wTaskView", "wPolkit", "wScreenSnip", "wSessionScreen", "wStartMenu", "iiCheatsheet", "iiOnScreenKeyboard", "iiOverlay", "iiWallpaperSelector"],
}) })
function cyclePanelFamily() { function cyclePanelFamily() {
const currentIndex = families.indexOf(Config.options.panelFamily) const currentIndex = families.indexOf(Config.options.panelFamily)