mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Merge pull request #1710 from WerWolv/feature/cloud_fog_weather_effects
Add weather widget effects for Cloudy and Foggy weather
This commit is contained in:
@@ -15,13 +15,15 @@ NBox {
|
||||
property bool showEffects: Settings.data.location.weatherShowEffects
|
||||
readonly property bool weatherReady: Settings.data.location.weatherEnabled && (LocationService.data.weather !== null)
|
||||
|
||||
// Test mode: set to "rain" or "snow"
|
||||
// Test mode: set to "rain", "snow", "cloud" or "fog"
|
||||
property string testEffects: ""
|
||||
|
||||
// Weather condition detection
|
||||
readonly property int currentWeatherCode: weatherReady ? LocationService.data.weather.current_weather.weathercode : 0
|
||||
readonly property bool isRaining: testEffects === "rain" || (testEffects === "" && ((currentWeatherCode >= 51 && currentWeatherCode <= 67) || (currentWeatherCode >= 80 && currentWeatherCode <= 82)))
|
||||
readonly property bool isSnowing: testEffects === "snow" || (testEffects === "" && ((currentWeatherCode >= 71 && currentWeatherCode <= 77) || (currentWeatherCode >= 85 && currentWeatherCode <= 86)))
|
||||
readonly property bool isRaining: testEffects === "rain" || (testEffects === "" && ((currentWeatherCode >= 51 && currentWeatherCode <= 67) || (currentWeatherCode >= 80 && currentWeatherCode <= 82)))
|
||||
readonly property bool isSnowing: testEffects === "snow" || (testEffects === "" && ((currentWeatherCode >= 71 && currentWeatherCode <= 77) || (currentWeatherCode >= 85 && currentWeatherCode <= 86)))
|
||||
readonly property bool isCloudy: testEffects === "cloud" || (testEffects === "" && (currentWeatherCode === 3))
|
||||
readonly property bool isFoggy: testEffects === "fog" || (testEffects === "" && (currentWeatherCode === 45 || currentWeatherCode === 48))
|
||||
|
||||
visible: Settings.data.location.weatherEnabled
|
||||
implicitHeight: Math.max(100 * Style.uiScaleRatio, content.implicitHeight + (Style.marginXL * 2))
|
||||
@@ -30,7 +32,7 @@ NBox {
|
||||
Loader {
|
||||
id: weatherEffectLoader
|
||||
anchors.fill: parent
|
||||
active: root.showEffects && (root.isRaining || root.isSnowing)
|
||||
active: root.showEffects && (root.isRaining || root.isSnowing || root.isCloudy || root.isFoggy)
|
||||
|
||||
sourceComponent: Item {
|
||||
anchors.fill: parent
|
||||
@@ -47,8 +49,8 @@ NBox {
|
||||
ShaderEffect {
|
||||
id: weatherEffect
|
||||
anchors.fill: parent
|
||||
// Snow fills the box, rain matches content margins
|
||||
anchors.margins: root.isSnowing ? root.border.width : Style.marginXL
|
||||
// Rain matches content margins, everything else fills the box
|
||||
anchors.margins: root.isRaining ? Style.marginXL : root.border.width
|
||||
|
||||
property var source: ShaderEffectSource {
|
||||
sourceItem: content
|
||||
@@ -59,9 +61,14 @@ NBox {
|
||||
property real itemWidth: weatherEffect.width
|
||||
property real itemHeight: weatherEffect.height
|
||||
property color bgColor: root.color
|
||||
property real cornerRadius: root.isSnowing ? (root.radius - root.border.width) : 0
|
||||
property real cornerRadius: root.isRaining ? 0 : (root.radius - root.border.width)
|
||||
property real alternative: root.isFoggy;
|
||||
|
||||
fragmentShader: root.isSnowing ? Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/weather_snow.frag.qsb") : Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/weather_rain.frag.qsb")
|
||||
fragmentShader:
|
||||
root.isSnowing ? Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/weather_snow.frag.qsb") :
|
||||
root.isRaining ? Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/weather_rain.frag.qsb") :
|
||||
root.isCloudy || root.isFoggy ? Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/weather_cloud.frag.qsb") :
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
#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 time;
|
||||
float itemWidth;
|
||||
float itemHeight;
|
||||
vec4 bgColor;
|
||||
float cornerRadius;
|
||||
float alternative;
|
||||
} ubuf;
|
||||
|
||||
// Signed distance function for rounded rectangle
|
||||
float roundedBoxSDF(vec2 center, vec2 size, float radius) {
|
||||
vec2 q = abs(center) - size + radius;
|
||||
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radius;
|
||||
}
|
||||
|
||||
float hash(vec2 p) {
|
||||
p = fract(p * vec2(234.34, 435.345));
|
||||
p += dot(p, p + 34.23);
|
||||
return fract(p.x * p.y);
|
||||
}
|
||||
|
||||
// Perlin-like noise
|
||||
float noise(vec2 p) {
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
f = f * f * (3.0 - 2.0 * f); // Smooth interpolation
|
||||
float a = hash(i);
|
||||
float b = hash(i + vec2(1.0, 0.0));
|
||||
float c = hash(i + vec2(0.0, 1.0));
|
||||
float d = hash(i + vec2(1.0, 1.0));
|
||||
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
||||
}
|
||||
|
||||
// Turbulent noise for natural fog
|
||||
float turbulence(vec2 p, float iTime) {
|
||||
float t = 0.0;
|
||||
float scale = 1.0;
|
||||
for(int i = 0; i < 5; i++) {
|
||||
t += abs(noise(p * scale + iTime * 0.1 * scale)) / scale;
|
||||
scale *= 2.0;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 uv = qt_TexCoord0;
|
||||
|
||||
vec4 col = vec4(ubuf.bgColor.rgb, 1.0);
|
||||
|
||||
// Different parameters for fog vs clouds
|
||||
float timeSpeed, layerScale1, layerScale2, layerScale3;
|
||||
float flowSpeed1, flowSpeed2;
|
||||
float densityMin, densityMax;
|
||||
float baseOpacity;
|
||||
float pulseAmount;
|
||||
|
||||
if (ubuf.alternative > 0.5) {
|
||||
// Fog: slower, larger scale, more uniform
|
||||
timeSpeed = 0.03;
|
||||
layerScale1 = 1.0;
|
||||
layerScale2 = 2.5;
|
||||
layerScale3 = 2.0;
|
||||
flowSpeed1 = 0.00;
|
||||
flowSpeed2 = 0.02;
|
||||
densityMin = 0.1;
|
||||
densityMax = 0.9;
|
||||
baseOpacity = 0.75;
|
||||
pulseAmount = 0.05;
|
||||
} else {
|
||||
// Clouds: faster, smaller scale, puffier
|
||||
timeSpeed = 0.08;
|
||||
layerScale1 = 2.0;
|
||||
layerScale2 = 4.0;
|
||||
layerScale3 = 6.0;
|
||||
flowSpeed1 = 0.03;
|
||||
flowSpeed2 = 0.04;
|
||||
densityMin = 0.35;
|
||||
densityMax = 0.75;
|
||||
baseOpacity = 0.4;
|
||||
pulseAmount = 0.15;
|
||||
}
|
||||
|
||||
float iTime = ubuf.time * timeSpeed;
|
||||
|
||||
// Create flowing patterns with multiple layers
|
||||
vec2 flow1 = vec2(iTime * flowSpeed1, iTime * flowSpeed1 * 0.7);
|
||||
vec2 flow2 = vec2(-iTime * flowSpeed2, iTime * flowSpeed2 * 0.8);
|
||||
|
||||
float fog1 = noise(uv * layerScale1 + flow1);
|
||||
float fog2 = noise(uv * layerScale2 + flow2);
|
||||
float fog3 = turbulence(uv * layerScale3, iTime);
|
||||
|
||||
float fogPattern = fog1 * 0.5 + fog2 * 0.3 + fog3 * 0.2;
|
||||
float fogDensity = smoothstep(densityMin, densityMax, fogPattern);
|
||||
|
||||
// Gentle pulsing
|
||||
float pulse = sin(iTime * 0.4) * pulseAmount + (1.0 - pulseAmount);
|
||||
fogDensity *= pulse;
|
||||
|
||||
vec3 hazeColor = vec3(0.88, 0.90, 0.93);
|
||||
float hazeOpacity = fogDensity * baseOpacity;
|
||||
vec3 fogContribution = hazeColor * hazeOpacity;
|
||||
float fogAlpha = hazeOpacity;
|
||||
|
||||
vec3 resultRGB = fogContribution + col.rgb * (1.0 - fogAlpha);
|
||||
float resultAlpha = fogAlpha + col.a * (1.0 - fogAlpha);
|
||||
|
||||
// Calculate corner mask
|
||||
vec2 pixelPos = qt_TexCoord0 * vec2(ubuf.itemWidth, ubuf.itemHeight);
|
||||
vec2 center = pixelPos - vec2(ubuf.itemWidth, ubuf.itemHeight) * 0.5;
|
||||
vec2 halfSize = vec2(ubuf.itemWidth, ubuf.itemHeight) * 0.5;
|
||||
float dist = roundedBoxSDF(center, halfSize, ubuf.cornerRadius);
|
||||
float cornerMask = 1.0 - smoothstep(-1.0, 0.0, dist);
|
||||
|
||||
// Apply global opacity and corner mask
|
||||
float finalAlpha = resultAlpha * ubuf.qt_Opacity * cornerMask;
|
||||
fragColor = vec4(resultRGB * (finalAlpha / max(resultAlpha, 0.001)), finalAlpha);
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user