From b7d4e7401243f0bc1daca3d63a5cd80ff71fab30 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 19:38:23 -0500 Subject: [PATCH] NImageRounded/Circled: removed shaders and used a simpler ClippingWrapperRectangle --- Modules/Bar/Widgets/MediaMini.qml | 8 +- Modules/LockScreen/LockScreen.qml | 6 +- Modules/Notification/Notification.qml | 21 ++-- .../ControlCenter/Cards/ProfileCard.qml | 3 +- Modules/Panels/Launcher/Launcher.qml | 4 +- .../NotificationHistoryPanel.qml | 5 +- .../WidgetSettings/ControlCenterSettings.qml | 3 +- Modules/Panels/Settings/Tabs/AboutTab.qml | 5 +- Modules/Panels/Settings/Tabs/GeneralTab.qml | 3 +- Shaders/frag/circled_image.frag | 30 ----- Shaders/frag/rounded_image.frag | 56 --------- Shaders/qsb/circled_image.frag.qsb | Bin 1706 -> 0 bytes Shaders/qsb/rounded_image.frag.qsb | Bin 2750 -> 0 bytes Widgets/NImageCircled.qml | 76 ------------- Widgets/NImageRounded.qml | 107 ++++++------------ 15 files changed, 69 insertions(+), 258 deletions(-) delete mode 100644 Shaders/frag/circled_image.frag delete mode 100644 Shaders/frag/rounded_image.frag delete mode 100644 Shaders/qsb/circled_image.frag.qsb delete mode 100644 Shaders/qsb/rounded_image.frag.qsb delete mode 100644 Widgets/NImageCircled.qml diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml index 43dca611..a4ca5f1b 100644 --- a/Modules/Bar/Widgets/MediaMini.qml +++ b/Modules/Bar/Widgets/MediaMini.qml @@ -409,16 +409,17 @@ Item { anchors.fill: parent anchors.margins: showProgressRing ? (3 * scaling) : 0.5 // Adjusted to align with progress circle better - NImageCircled { + NImageRounded { id: trackArt anchors.fill: parent anchors.margins: showProgressRing ? 0 : -1 * scaling // Add negative margin to make album art larger when no progress ring + radius: width * 0.5 visible: showAlbumArt && hasActivePlayer imagePath: MediaService.trackArtUrl fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play" fallbackIconSize: showProgressRing ? 10 : 12 // Larger fallback icon when no progress ring borderWidth: 0 - border.color: Color.transparent + borderColor: Color.transparent z: 1 // In front of the progress circle } @@ -649,9 +650,10 @@ Item { z: 1 // Above the visualizer and progress ring // Album Art - NImageCircled { + NImageRounded { anchors.fill: parent visible: showAlbumArt && hasActivePlayer + radius: width * 0.5 imagePath: MediaService.trackArtUrl fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play" fallbackIconSize: 12 diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml index 1612017d..325395b4 100644 --- a/Modules/LockScreen/LockScreen.qml +++ b/Modules/LockScreen/LockScreen.qml @@ -301,10 +301,11 @@ Loader { } } - NImageCircled { + NImageRounded { anchors.centerIn: parent width: 66 height: 66 + radius: width * 0.5 imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" @@ -631,9 +632,10 @@ Loader { color: Color.transparent clip: true - NImageCircled { + NImageRounded { anchors.fill: parent anchors.margins: 2 + radius: width * 0.5 imagePath: MediaService.trackArtUrl fallbackIcon: "disc" fallbackIconSize: Style.fontSizeM diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml index 6d39860a..d4d69db4 100644 --- a/Modules/Notification/Notification.qml +++ b/Modules/Notification/Notification.qml @@ -398,17 +398,16 @@ Variants { Layout.topMargin: Style.marginM Layout.bottomMargin: Style.marginM - ColumnLayout { - NImageCircled { - Layout.preferredWidth: Math.round(40 * Style.uiScaleRatio) - Layout.preferredHeight: Math.round(40 * Style.uiScaleRatio) - Layout.alignment: Qt.AlignVCenter - imagePath: model.originalImage || "" - borderColor: Color.transparent - borderWidth: 0 - fallbackIcon: "bell" - fallbackIconSize: 24 - } + NImageRounded { + Layout.preferredWidth: Math.round(40 * Style.uiScaleRatio) + Layout.preferredHeight: Math.round(40 * Style.uiScaleRatio) + Layout.alignment: Qt.AlignVCenter + radius: width * 0.5 + imagePath: model.originalImage || "" + borderColor: Color.transparent + borderWidth: 0 + fallbackIcon: "bell" + fallbackIconSize: 24 } ColumnLayout { diff --git a/Modules/Panels/ControlCenter/Cards/ProfileCard.qml b/Modules/Panels/ControlCenter/Cards/ProfileCard.qml index b37231ed..f827b506 100644 --- a/Modules/Panels/ControlCenter/Cards/ProfileCard.qml +++ b/Modules/Panels/ControlCenter/Cards/ProfileCard.qml @@ -25,9 +25,10 @@ NBox { anchors.margins: Style.marginM spacing: Style.marginM - NImageCircled { + NImageRounded { Layout.preferredWidth: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio) Layout.preferredHeight: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio) + radius: width * 0.5 imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" borderColor: Color.mPrimary diff --git a/Modules/Panels/Launcher/Launcher.qml b/Modules/Panels/Launcher/Launcher.qml index e8dfdcda..00537379 100644 --- a/Modules/Panels/Launcher/Launcher.qml +++ b/Modules/Panels/Launcher/Launcher.qml @@ -689,7 +689,7 @@ SmartPanel { id: imagePreview anchors.fill: parent visible: modelData.isImage && !modelData.emojiChar - imageRadius: Style.radiusM + radius: Style.radiusM // This property creates a dependency on the service's revision counter readonly property int _rev: ClipboardService.revision @@ -934,7 +934,7 @@ SmartPanel { id: gridImagePreview anchors.fill: parent visible: modelData.isImage && !modelData.emojiChar - imageRadius: Style.radiusM + radius: Style.radiusM readonly property int _rev: ClipboardService.revision diff --git a/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml b/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml index 8efde22c..4e25642c 100644 --- a/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml +++ b/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml @@ -197,10 +197,11 @@ SmartPanel { spacing: Style.marginM // Icon - NImageCircled { + NImageRounded { + anchors.verticalCenter: parent.verticalCenter width: Math.round(40 * Style.uiScaleRatio) height: Math.round(40 * Style.uiScaleRatio) - anchors.verticalCenter: parent.verticalCenter + radius: width * 0.5 imagePath: model.cachedImage || model.originalImage || "" borderColor: Color.transparent borderWidth: 0 diff --git a/Modules/Panels/Settings/Bar/WidgetSettings/ControlCenterSettings.qml b/Modules/Panels/Settings/Bar/WidgetSettings/ControlCenterSettings.qml index 7a0aa453..5f9eb339 100644 --- a/Modules/Panels/Settings/Bar/WidgetSettings/ControlCenterSettings.qml +++ b/Modules/Panels/Settings/Bar/WidgetSettings/ControlCenterSettings.qml @@ -59,10 +59,11 @@ ColumnLayout { description: I18n.tr("bar.widget-settings.control-center.icon.description") } - NImageCircled { + NImageRounded { Layout.preferredWidth: Style.fontSizeXL * 2 Layout.preferredHeight: Style.fontSizeXL * 2 Layout.alignment: Qt.AlignVCenter + radius: width * 0.5 imagePath: valueCustomIconPath visible: valueCustomIconPath !== "" } diff --git a/Modules/Panels/Settings/Tabs/AboutTab.qml b/Modules/Panels/Settings/Tabs/AboutTab.qml index 127ab7f5..f226afe6 100644 --- a/Modules/Panels/Settings/Tabs/AboutTab.qml +++ b/Modules/Panels/Settings/Tabs/AboutTab.qml @@ -189,10 +189,11 @@ ColumnLayout { Layout.preferredWidth: Style.baseWidgetSize * 2 * Style.uiScaleRatio Layout.preferredHeight: Style.baseWidgetSize * 2 * Style.uiScaleRatio - NImageCircled { - imagePath: modelData.avatar_url || "" + NImageRounded { anchors.fill: parent anchors.margins: Style.marginXS + radius: width * 0.5 + imagePath: modelData.avatar_url || "" fallbackIcon: "person" borderColor: contributorArea.containsMouse ? Color.mOnHover : Color.mPrimary borderWidth: Style.borderM diff --git a/Modules/Panels/Settings/Tabs/GeneralTab.qml b/Modules/Panels/Settings/Tabs/GeneralTab.qml index 481f4013..f111222b 100644 --- a/Modules/Panels/Settings/Tabs/GeneralTab.qml +++ b/Modules/Panels/Settings/Tabs/GeneralTab.qml @@ -21,9 +21,10 @@ ColumnLayout { spacing: Style.marginL // Avatar preview - NImageCircled { + NImageRounded { Layout.preferredWidth: 88 * Style.uiScaleRatio Layout.preferredHeight: width + radius: width * 0.5 imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" borderColor: Color.mPrimary diff --git a/Shaders/frag/circled_image.frag b/Shaders/frag/circled_image.frag deleted file mode 100644 index 308a9c5b..00000000 --- a/Shaders/frag/circled_image.frag +++ /dev/null @@ -1,30 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float imageOpacity; -} ubuf; - -void main() { - // Center coordinates around (0, 0) - vec2 uv = qt_TexCoord0 - 0.5; - - // Calculate distance from center - float distance = length(uv); - - // Create circular mask - anything beyond radius 0.5 is transparent - float mask = 1.0 - smoothstep(0.48, 0.52, distance); - - // Sample the texture - vec4 color = texture(source, qt_TexCoord0); - - // Apply the circular mask and opacity - float finalAlpha = color.a * mask * ubuf.imageOpacity * ubuf.qt_Opacity; - fragColor = vec4(color.rgb * finalAlpha, finalAlpha); -} \ No newline at end of file diff --git a/Shaders/frag/rounded_image.frag b/Shaders/frag/rounded_image.frag deleted file mode 100644 index 9d493b21..00000000 --- a/Shaders/frag/rounded_image.frag +++ /dev/null @@ -1,56 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - // Custom properties with non-conflicting names - float itemWidth; - float itemHeight; - float cornerRadius; - float imageOpacity; -} ubuf; - -// Function to calculate the signed distance from a point to a rounded box -float roundedBoxSDF(vec2 centerPos, vec2 boxSize, float radius) { - vec2 d = abs(centerPos) - boxSize + radius; - return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0) - radius; -} - -void main() { - // Get size from uniforms - vec2 itemSize = vec2(ubuf.itemWidth, ubuf.itemHeight); - float cornerRadius = ubuf.cornerRadius; - float itemOpacity = ubuf.imageOpacity; - - // Normalize coordinates to [-0.5, 0.5] range - vec2 uv = qt_TexCoord0 - 0.5; - - // Scale by aspect ratio to maintain uniform rounding - vec2 aspectRatio = itemSize / max(itemSize.x, itemSize.y); - uv *= aspectRatio; - - // Calculate half size in normalized space - vec2 halfSize = 0.5 * aspectRatio; - - // Normalize the corner radius - float normalizedRadius = cornerRadius / max(itemSize.x, itemSize.y); - - // Calculate distance to rounded rectangle - float distance = roundedBoxSDF(uv, halfSize, normalizedRadius); - - // Create smooth alpha mask - float smoothedAlpha = 1.0 - smoothstep(0.0, fwidth(distance), distance); - - // Sample the texture - vec4 color = texture(source, qt_TexCoord0); - - // Apply the rounded mask and opacity - // Make sure areas outside the rounded rect are completely transparent - float finalAlpha = color.a * smoothedAlpha * itemOpacity * ubuf.qt_Opacity; - fragColor = vec4(color.rgb * finalAlpha, finalAlpha); -} \ No newline at end of file diff --git a/Shaders/qsb/circled_image.frag.qsb b/Shaders/qsb/circled_image.frag.qsb deleted file mode 100644 index 4faa90f9f62b6ac319e4ee498f3fa5ded2470831..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1706 zcmV;b237e002g?8ob6caZ_`#3zfIa^q#f@^83Rl^Ab~VEA$`%N4-yzipfXyqNl|CH ziIaLHcCfEYI#g-Ww6EK@{Vn^v|7p^`Oxrp49w#?$=-AK@o94=m&+oin*J&AJM;K$n za1X&f!Co-V47SNE)?p>)!jH#lOb1>JZuUD}Y`}#EPO>^En5-d`n?hZh|5Mdbw#@=i zXY2#`44)q;QgPuxM)(+E|oQ#c;#Hu2FJbXA!D(kEbN>xzdY>%9-hS5c@2@q?E zM67{|<<}{yDUCB9DiA=JRWQR?it-;iOz};xQTnVYkRFdsCD8sD6!AWxC!lrcaST-O z^V3HgkFq|mWeYRdS9VksRz`JK>7-NULiXn zJ=x{Q*))?w^Z23w(kCW`E!apO} z->ii6S-5}r`IqI8J_q+tmqu1Fo(rTqO#VM6dx)QhmA*v$=%j`81<3C*)d2N1!Y@<& zno_?rKwqO;Fp3xH>rAfX1kf4sJuGa>o@6M7QSyisu5^zr*C*#;J!(q#GA{Bf?g=!ifC}$O!3Te~&2r#D1NK(5Dp|>whuA zze;qG=4YJAnRo(TkUq-fOyK=3VaG@gdCL&h5yCIR$OLmaMfu+)9_pMRyhw91 zL9vfRR!E;G9jxtHCg*B`VnF^!OwQtYvUi#=w1@LCNwX2gG(~xR4*FR8Pe^8p^e+;& z27IhbifVOTi7`!hNZ+9Pen&CgB$*pz2WR0n%}-9zD-a&)&5&+E(VHW^Sw(N2@KA4o zbmu9DtArJ4_llImI@EMY$VjY6^Mv({DfU-r9=-?rD8EWND~ik-$$UmJ+-1ENT8Nbh z8&a?`VKFgV2@&5t(k~Hzjq+F|-fv)GUY-WSbj~ADW8EVn_T|*B<@vVjXgOU^wmqwA z3u?!1?6kFd(>3|x0oZl`O#0jls$AO+>d9A04X&2S3)%~AJT|#!cNPUEEFievHmf$@ zQ&GERHmokb4<-Z0uDf0fZE6AhQXuKsH(Twd<>kwo?*?Ag0)buA+q0d9wrf@M=xEdG zlw8-V>Bw{KnueLD(iEeR3U;+(pQtu17%4qFlU5@%YPQc!r)q(G({dVoCl&1WNwiG= zIWTiswBfg0m+$!8YJ;W1+yY+n3;DTRZua&S_~2HD2cDHLr)2J#z7+bRs@sm)Tx+&>OwdcEgoW%&?S=?94WC%t ztXlsr7;ROfY25eBM%mg*p_WgjxSb$LgI9RkxULF;DnH&G+VMxL5^G zb;}d&zN2|o1CqA9)V3Zr$#Y*CE%PhzDiSJm3L-kAJ7k~+Q9gI;b>HHtYJd8nC?yh+ zEgY0pD-o5>?xp37ZiY*}Bx72pfmAc#7|4d4*bQ!SOEaX9L1U~6`zQ?CWOBPIqlu2R z%IlwN+QE${51&3WN}lWc#zUtaaH`(`Yv6hF-WR3y^`~WBCN#jtdcY$_6t`eu{(VeG8Jjz+wPq) zXzz@}_D)9k#+!Grq4ESgFf1C>pkWy{K8LOAYgbW~$o9`>7$kLG0s~x23$7rfkcwpc z^6U+`I0P)%Hz#6XUp-jxug>w_!4hvy*-o_?)GTeOWpT4<_`KG%x0jPW+_zh`Tlg!x zvkWg8AHR<{X3O%S_?9NL27U4F9z$>Snj^Cqy^a~ZZqX_g(d(3+-r5?VX*-9kd8HEg zaJV$xs?$?P(=E$UT+63aXb}G30L`%5TU!~}1qW9|6ychfQ4o;lwumd!{gzXc2V(a; ztW?4mm6QvQKFQty0y893$fUbpB*N(ME^4p#7Z02#wv&wpF diff --git a/Shaders/qsb/rounded_image.frag.qsb b/Shaders/qsb/rounded_image.frag.qsb deleted file mode 100644 index 666f6434973c9fd0eb50651c6d43250023c55b53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2750 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 El;wG(X8-^I diff --git a/Widgets/NImageCircled.qml b/Widgets/NImageCircled.qml deleted file mode 100644 index c97e4440..00000000 --- a/Widgets/NImageCircled.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Widgets -import qs.Commons - -Rectangle { - id: root - - property string imagePath: "" - property color borderColor: Color.transparent - property real borderWidth: 0 - property string fallbackIcon: "" - property real fallbackIconSize: Style.fontSizeXXL - - color: Color.transparent - radius: parent.width * 0.5 - anchors.margins: Style.marginXXS - - Rectangle { - color: Color.transparent - anchors.fill: parent - - Image { - id: img - anchors.fill: parent - source: imagePath - visible: false // Hide since we're using it as shader source - mipmap: true - smooth: true - asynchronous: true - antialiasing: true - fillMode: Image.PreserveAspectCrop - } - - ShaderEffect { - anchors.fill: parent - - property var source: ShaderEffectSource { - sourceItem: img - hideSource: true - live: true - recursive: false - format: ShaderEffectSource.RGBA - } - - property real imageOpacity: root.opacity - fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/circled_image.frag.qsb") - supportsAtlasTextures: false - blending: true - } - - // Fallback icon - Loader { - active: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "") - anchors.centerIn: parent - sourceComponent: NIcon { - anchors.centerIn: parent - icon: fallbackIcon - pointSize: fallbackIconSize - z: 0 - } - } - } - - // Border - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Color.transparent - border.color: parent.borderColor - border.width: parent.borderWidth - antialiasing: true - z: 10 - } -} diff --git a/Widgets/NImageRounded.qml b/Widgets/NImageRounded.qml index 67d3a178..7d28fa2d 100644 --- a/Widgets/NImageRounded.qml +++ b/Widgets/NImageRounded.qml @@ -4,91 +4,56 @@ import Quickshell import Quickshell.Widgets import qs.Commons -Rectangle { +Item { id: root + property real radius: 0 property string imagePath: "" - property color borderColor: Color.transparent - property real borderWidth: 0 - property real imageRadius: width * 0.5 - property int imageFillMode: Image.PreserveAspectCrop property string fallbackIcon: "" property real fallbackIconSize: Style.fontSizeXXL + property real borderWidth: 0 + property color borderColor: Color.transparent - property real scaledRadius: imageRadius * Settings.data.general.radiusRatio + readonly property bool showFallback: (fallbackIcon !== undefined && fallbackIcon !== "") && (imagePath === undefined || imagePath === "") signal statusChanged(int status) - color: Color.transparent - radius: scaledRadius - anchors.margins: Style.marginXXS - - Rectangle { - color: Color.transparent + ClippingWrapperRectangle { anchors.fill: parent + color: Color.transparent + radius: root.radius + border.color: root.borderColor + border.width: root.borderWidth - Image { - id: img + Item { anchors.fill: parent - source: imagePath - visible: false - mipmap: true - smooth: true - asynchronous: true - antialiasing: true - fillMode: root.imageFillMode - horizontalAlignment: Image.AlignHCenter - verticalAlignment: Image.AlignVCenter - - onStatusChanged: root.statusChanged(status) - } - - ShaderEffect { - anchors.fill: parent - - property var source: ShaderEffectSource { - sourceItem: img - hideSource: true - live: true - recursive: false - format: ShaderEffectSource.RGBA - } - - property real itemWidth: root.width - property real itemHeight: root.height - property real cornerRadius: root.radius - property real imageOpacity: root.opacity - fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/rounded_image.frag.qsb") - - supportsAtlasTextures: false - blending: true - Rectangle { - id: background + Loader { + active: true anchors.fill: parent - color: Color.transparent - z: -1 + sourceComponent: showFallback ? fallback : image + } + + Component { + id: image + Image { + source: imagePath + mipmap: true + smooth: true + asynchronous: true + antialiasing: true + fillMode: Image.PreserveAspectCrop + onStatusChanged: root.statusChanged(status) + } + } + + Component { + id: fallback + NIcon { + anchors.centerIn: parent + icon: fallbackIcon + pointSize: fallbackIconSize + } } } - - Loader { - active: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "") - anchors.centerIn: parent - sourceComponent: NIcon { - anchors.centerIn: parent - icon: fallbackIcon - pointSize: fallbackIconSize - z: 0 - } - } - } - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Color.transparent - border.color: parent.borderColor - border.width: parent.borderWidth - antialiasing: true - z: 10 } }