mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-15 00:32:47 -04:00
Compare commits
5 Commits
ef19568dd7
...
44d836c975
| Author | SHA1 | Date | |
|---|---|---|---|
| 44d836c975 | |||
| da437e77fb | |||
| 34a6bbfb32 | |||
| 9ed53bac9e | |||
| 3a6752c3d2 |
@@ -2574,6 +2574,13 @@ Singleton {
|
||||
|
||||
property alias settingsFile: settingsFile
|
||||
|
||||
Timer {
|
||||
id: settingsFileReloadDebounce
|
||||
interval: 50
|
||||
onTriggered: settingsFile.reload()
|
||||
repeat: false
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: settingsFile
|
||||
|
||||
@@ -2581,7 +2588,8 @@ Singleton {
|
||||
blockLoading: true
|
||||
blockWrites: true
|
||||
atomicWrites: true
|
||||
watchChanges: !isGreeterMode
|
||||
watchChanges: true
|
||||
onFileChanged: settingsFileReloadDebounce.restart()
|
||||
onLoaded: {
|
||||
if (isGreeterMode)
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import QtQml
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Hyprland
|
||||
import qs.Common
|
||||
import qs.Modals.Common
|
||||
@@ -18,7 +20,11 @@ DankModal {
|
||||
modalHeight: _maxH
|
||||
onBackgroundClicked: close()
|
||||
onOpened: {
|
||||
Qt.callLater(() => modalFocusScope.forceActiveFocus());
|
||||
Qt.callLater(() => {
|
||||
modalFocusScope.forceActiveFocus();
|
||||
if (contentLoader.item?.searchField)
|
||||
contentLoader.item.searchField.forceActiveFocus();
|
||||
});
|
||||
if (!Object.keys(KeybindsService.cheatsheet).length && KeybindsService.cheatsheetAvailable)
|
||||
KeybindsService.loadCheatsheet();
|
||||
}
|
||||
@@ -63,17 +69,39 @@ DankModal {
|
||||
content: Component {
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
property alias searchField: searchField
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingL
|
||||
|
||||
StyledText {
|
||||
text: KeybindsService.cheatsheet.title || "Keybinds"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Bold
|
||||
color: Theme.primary
|
||||
RowLayout {
|
||||
width: parent.width
|
||||
|
||||
StyledText {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
text: KeybindsService.cheatsheet.title || "Keybinds"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Bold
|
||||
color: Theme.primary
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: searchField
|
||||
Layout.alignment: Qt.AlignRight
|
||||
leftIconName: "search"
|
||||
onTextEdited: searchDebounce.restart()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: searchDebounce
|
||||
interval: 50
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
mainFlickable.categories = mainFlickable.generateCategories(searchField.text);
|
||||
}
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
@@ -87,17 +115,26 @@ DankModal {
|
||||
Component.onCompleted: root.activeFlickable = mainFlickable
|
||||
|
||||
property var rawBinds: KeybindsService.cheatsheet.binds || {}
|
||||
property var categories: {
|
||||
|
||||
function generateCategories(query) {
|
||||
const lowerQuery = query ? query.toLowerCase().trim() : "";
|
||||
const processed = {};
|
||||
|
||||
for (const cat in rawBinds) {
|
||||
const binds = rawBinds[cat];
|
||||
const catLower = cat.toLowerCase();
|
||||
const subcats = {};
|
||||
let hasSubcats = false;
|
||||
|
||||
for (let i = 0; i < binds.length; i++) {
|
||||
const bind = binds[i];
|
||||
const keyLower = bind.key.toLowerCase();
|
||||
const descLower = bind.desc.toLowerCase();
|
||||
const actionLower = bind.action.toLowerCase();
|
||||
if (!(lowerQuery.length === 0 || keyLower.includes(lowerQuery) || descLower.includes(lowerQuery) || catLower.includes(lowerQuery) || actionLower.includes(lowerQuery)))
|
||||
continue;
|
||||
if (bind.hideOnOverlay)
|
||||
continue;
|
||||
|
||||
if (bind.subcat) {
|
||||
hasSubcats = true;
|
||||
if (!subcats[bind.subcat])
|
||||
@@ -119,9 +156,11 @@ DankModal {
|
||||
subcatKeys: Object.keys(subcats)
|
||||
};
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
property var categoryKeys: Object.keys(categories)
|
||||
|
||||
property var categories: generateCategories("");
|
||||
|
||||
function estimateCategoryHeight(catName) {
|
||||
const catData = categories[catName];
|
||||
@@ -136,6 +175,8 @@ DankModal {
|
||||
return 40 + bindCount * 28;
|
||||
}
|
||||
|
||||
property var categoryKeys: Object.keys(categories);
|
||||
|
||||
function distributeCategories(cols) {
|
||||
const columns = [];
|
||||
const heights = [];
|
||||
|
||||
@@ -500,10 +500,10 @@ Item {
|
||||
anchors.top: SettingsData.dockPosition === SettingsData.Position.Top ? parent.top : undefined
|
||||
anchors.left: SettingsData.dockPosition === SettingsData.Position.Left ? parent.left : undefined
|
||||
anchors.right: SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined
|
||||
anchors.bottomMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? -(SettingsData.dockSpacing / 2) : 0
|
||||
anchors.topMargin: SettingsData.dockPosition === SettingsData.Position.Top ? -(SettingsData.dockSpacing / 2) : 0
|
||||
anchors.leftMargin: SettingsData.dockPosition === SettingsData.Position.Left ? -(SettingsData.dockSpacing / 2) : 0
|
||||
anchors.rightMargin: SettingsData.dockPosition === SettingsData.Position.Right ? -(SettingsData.dockSpacing / 2) : 0
|
||||
anchors.bottomMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? -(SettingsData.dockSpacing / 2 + 1.4) : 0
|
||||
anchors.topMargin: SettingsData.dockPosition === SettingsData.Position.Top ? -(SettingsData.dockSpacing / 2 + 1.4) : 0
|
||||
anchors.leftMargin: SettingsData.dockPosition === SettingsData.Position.Left ? -(SettingsData.dockSpacing / 2 + 1.4) : 0
|
||||
anchors.rightMargin: SettingsData.dockPosition === SettingsData.Position.Right ? -(SettingsData.dockSpacing / 2 + 1.4) : 0
|
||||
|
||||
sourceComponent: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? columnIndicator : rowIndicator
|
||||
|
||||
|
||||
@@ -509,6 +509,7 @@ Item {
|
||||
value: SettingsData.dockIconSize
|
||||
minimum: 24
|
||||
maximum: 96
|
||||
unit: "px"
|
||||
defaultValue: 48
|
||||
onSliderValueChanged: newValue => SettingsData.set("dockIconSize", newValue)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 qt_TexCoord0;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 qt_Matrix;
|
||||
float qt_Opacity;
|
||||
float widthPx;
|
||||
float heightPx;
|
||||
float cornerRadiusPx;
|
||||
float rippleCenterX;
|
||||
float rippleCenterY;
|
||||
float rippleRadius;
|
||||
float rippleOpacity;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
float parentWidth;
|
||||
float parentHeight;
|
||||
vec4 rippleCol;
|
||||
} ubuf;
|
||||
|
||||
float sdRoundRect(vec2 p, vec2 b, float r) {
|
||||
vec2 q = abs(p) - (b - vec2(r));
|
||||
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 px = qt_TexCoord0 * vec2(ubuf.widthPx, ubuf.heightPx) + vec2(ubuf.offsetX, ubuf.offsetY);
|
||||
|
||||
float aa = fwidth(length(px)) * 1.5;
|
||||
|
||||
float circleD = length(px - vec2(ubuf.rippleCenterX, ubuf.rippleCenterY)) - ubuf.rippleRadius;
|
||||
float circleMask = 1.0 - smoothstep(-aa, aa, circleD);
|
||||
if (circleMask <= 0.0) {
|
||||
fragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float rrMask = 1.0;
|
||||
if (ubuf.cornerRadiusPx > 0.0) {
|
||||
vec2 halfSize = vec2(ubuf.parentWidth, ubuf.parentHeight) * 0.5;
|
||||
float r = min(ubuf.cornerRadiusPx, min(halfSize.x, halfSize.y));
|
||||
float rrD = sdRoundRect(px - halfSize, halfSize, r);
|
||||
rrMask = 1.0 - smoothstep(-aa, aa, rrD);
|
||||
}
|
||||
|
||||
float mask = circleMask * rrMask;
|
||||
if (mask <= 0.0) {
|
||||
fragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float a = ubuf.rippleCol.a * ubuf.rippleOpacity * mask * ubuf.qt_Opacity;
|
||||
fragColor = vec4(ubuf.rippleCol.rgb * a, a);
|
||||
}
|
||||
Binary file not shown.
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import qs.Common
|
||||
|
||||
Item {
|
||||
@@ -11,7 +10,7 @@ Item {
|
||||
|
||||
property real _rippleX: 0
|
||||
property real _rippleY: 0
|
||||
property real _rippleSize: 0
|
||||
property real _rippleMaxRadius: 0
|
||||
readonly property alias animating: rippleAnim.running
|
||||
|
||||
anchors.fill: parent
|
||||
@@ -24,7 +23,7 @@ Item {
|
||||
_rippleY = y;
|
||||
|
||||
const dist = (ox, oy) => ox * ox + oy * oy;
|
||||
_rippleSize = Math.sqrt(Math.max(dist(x, y), dist(x, height - y), dist(width - x, y), dist(width - x, height - y))) * 2;
|
||||
_rippleMaxRadius = Math.sqrt(Math.max(dist(x, y), dist(x, height - y), dist(width - x, y), dist(width - x, height - y)));
|
||||
|
||||
rippleAnim.restart();
|
||||
}
|
||||
@@ -33,45 +32,32 @@ Item {
|
||||
id: rippleAnim
|
||||
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "x"
|
||||
target: rippleFx
|
||||
property: "rippleCenterX"
|
||||
value: root._rippleX
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "y"
|
||||
target: rippleFx
|
||||
property: "rippleCenterY"
|
||||
value: root._rippleY
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "implicitWidth"
|
||||
target: rippleFx
|
||||
property: "rippleRadius"
|
||||
value: 0
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "implicitHeight"
|
||||
value: 0
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "opacity"
|
||||
target: rippleFx
|
||||
property: "rippleOpacity"
|
||||
value: 0.10
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
DankAnim {
|
||||
target: ripple
|
||||
property: "implicitWidth"
|
||||
target: rippleFx
|
||||
property: "rippleRadius"
|
||||
from: 0
|
||||
to: root._rippleSize
|
||||
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Theme.expressiveCurves.standardDecel
|
||||
}
|
||||
DankAnim {
|
||||
target: ripple
|
||||
property: "implicitHeight"
|
||||
from: 0
|
||||
to: root._rippleSize
|
||||
to: root._rippleMaxRadius
|
||||
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Theme.expressiveCurves.standardDecel
|
||||
}
|
||||
@@ -80,8 +66,8 @@ Item {
|
||||
duration: Math.round(Theme.expressiveDurations.expressiveDefaultSpatial * 0.6)
|
||||
}
|
||||
DankAnim {
|
||||
target: ripple
|
||||
property: "opacity"
|
||||
target: rippleFx
|
||||
property: "rippleOpacity"
|
||||
to: 0
|
||||
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Theme.expressiveCurves.standard
|
||||
@@ -90,27 +76,29 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// VRAM optimization: Use clip instead of layer+MultiEffect for rounded corners
|
||||
// The layer.enabled approach creates an offscreen texture for every clickable element
|
||||
// with rounded corners, which adds 200-400MB VRAM across the UI.
|
||||
// Using clip: true is GPU-native and much cheaper.
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: root.cornerRadius
|
||||
color: "transparent"
|
||||
clip: root.cornerRadius > 0
|
||||
ShaderEffect {
|
||||
id: rippleFx
|
||||
visible: rippleAnim.running
|
||||
|
||||
Rectangle {
|
||||
id: ripple
|
||||
property real rippleCenterX: 0
|
||||
property real rippleCenterY: 0
|
||||
property real rippleRadius: 0
|
||||
property real rippleOpacity: 0
|
||||
|
||||
radius: Math.min(width, height) / 2
|
||||
color: root.rippleColor
|
||||
opacity: 0
|
||||
x: Math.max(0, rippleCenterX - rippleRadius)
|
||||
y: Math.max(0, rippleCenterY - rippleRadius)
|
||||
width: Math.max(0, Math.min(root.width, rippleCenterX + rippleRadius) - x)
|
||||
height: Math.max(0, Math.min(root.height, rippleCenterY + rippleRadius) - y)
|
||||
|
||||
transform: Translate {
|
||||
x: -ripple.width / 2
|
||||
y: -ripple.height / 2
|
||||
}
|
||||
}
|
||||
property real widthPx: width
|
||||
property real heightPx: height
|
||||
property real cornerRadiusPx: root.cornerRadius
|
||||
property real offsetX: x
|
||||
property real offsetY: y
|
||||
property real parentWidth: root.width
|
||||
property real parentHeight: root.height
|
||||
property vector4d rippleCol: Qt.vector4d(root.rippleColor.r, root.rippleColor.g, root.rippleColor.b, root.rippleColor.a)
|
||||
|
||||
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/ripple.frag.qsb")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user