diff --git a/extension.js b/extension.js
index 06776d9..7ca02cc 100644
--- a/extension.js
+++ b/extension.js
@@ -49,6 +49,7 @@ import TVGlitch from './src/effects/TVGlitch.js';
import Wisps from './src/effects/Wisps.js';
import Mushroom from './src/effects/Mushroom.js';
+import UnicornFart from './src/effects/UnicornFart.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
@@ -82,7 +83,7 @@ export default class BurnMyWindows extends Extension {
new Matrix(), new PaintBrush(), new Pixelate(), new PixelWheel(),
new PixelWipe(), new Portal(), new RGBWarp(), new SnapOfDisintegration(),
new TeamRocket(), new TRexAttack(), new TVEffect(), new TVGlitch(),
- new Wisps(), new Mushroom(),
+ new Wisps(), new Mushroom(), new UnicornFart(),
];
diff --git a/metadata.json b/metadata.json
index 9053a09..a8cd7b5 100644
--- a/metadata.json
+++ b/metadata.json
@@ -15,5 +15,5 @@
"47"
],
"url": "https://github.com/Schneegans/Burn-My-Windows",
- "version": 45
+ "version": 47
}
\ No newline at end of file
diff --git a/prefs.js b/prefs.js
index af81f62..ea60c03 100644
--- a/prefs.js
+++ b/prefs.js
@@ -50,7 +50,7 @@ import TVEffect from './src/effects/TVEffect.js';
import TVGlitch from './src/effects/TVGlitch.js';
import Wisps from './src/effects/Wisps.js';
-
+import UnicornFart from './src/effects/UnicornFart.js';
import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
@@ -84,7 +84,7 @@ export default class BurnMyWindowsPreferences extends ExtensionPreferences {
Pixelate, PixelWheel, PixelWipe,
Portal, RGBWarp, SnapOfDisintegration,
TeamRocket, TRexAttack, TVEffect,
- TVGlitch, Wisps,
+ TVGlitch, Wisps, UnicornFart,
];
diff --git a/resources/shaders/aura-glow.frag b/resources/shaders/aura-glow.frag
index c08ea69..ad4d45d 100644
--- a/resources/shaders/aura-glow.frag
+++ b/resources/shaders/aura-glow.frag
@@ -58,54 +58,6 @@ uniform float uEdgeSize;
uniform float uEdgeHardness;
-
-vec3 offsetHue(vec3 color, float hueOffset) {
- // Convert RGB to HSV
- float maxC = max(max(color.r, color.g), color.b);
- float minC = min(min(color.r, color.g), color.b);
- float delta = maxC - minC;
-
- float hue = 0.0;
- if (delta > 0.0) {
- if (maxC == color.r) {
- hue = mod((color.g - color.b) / delta, 6.0);
- } else if (maxC == color.g) {
- hue = (color.b - color.r) / delta + 2.0;
- } else {
- hue = (color.r - color.g) / delta + 4.0;
- }
- }
- hue /= 6.0;
-
- float saturation = (maxC > 0.0) ? (delta / maxC) : 0.0;
- float value = maxC;
-
- // Offset the hue
- hue = mod(hue + hueOffset, 1.0);
-
- // Convert HSV back to RGB
- float c = value * saturation;
- float x = c * (1.0 - abs(mod(hue * 6.0, 2.0) - 1.0));
- float m = value - c;
-
- vec3 rgb;
- if (hue < 1.0 / 6.0) {
- rgb = vec3(c, x, 0.0);
- } else if (hue < 2.0 / 6.0) {
- rgb = vec3(x, c, 0.0);
- } else if (hue < 3.0 / 6.0) {
- rgb = vec3(0.0, c, x);
- } else if (hue < 4.0 / 6.0) {
- rgb = vec3(0.0, x, c);
- } else if (hue < 5.0 / 6.0) {
- rgb = vec3(x, 0.0, c);
- } else {
- rgb = vec3(c, 0.0, x);
- }
-
- return rgb + m;
-}
-
// A simple blur function
vec4 blur(vec2 uv, float radius, float samples) {
vec4 color = vec4(0.0);
diff --git a/resources/shaders/common.glsl b/resources/shaders/common.glsl
index fea52b3..0ed9395 100644
--- a/resources/shaders/common.glsl
+++ b/resources/shaders/common.glsl
@@ -185,6 +185,55 @@ vec3 darken(vec3 color, float fac) { return color * (1.0 - fac); }
// color will be white.
vec3 lighten(vec3 color, float fac) { return color + (vec3(1.0) - color) * fac; }
+
+//change the color based on an offset amount
+vec3 offsetHue(vec3 color, float hueOffset) {
+ // Convert RGB to HSV
+ float maxC = max(max(color.r, color.g), color.b);
+ float minC = min(min(color.r, color.g), color.b);
+ float delta = maxC - minC;
+
+ float hue = 0.0;
+ if (delta > 0.0) {
+ if (maxC == color.r) {
+ hue = mod((color.g - color.b) / delta, 6.0);
+ } else if (maxC == color.g) {
+ hue = (color.b - color.r) / delta + 2.0;
+ } else {
+ hue = (color.r - color.g) / delta + 4.0;
+ }
+ }
+ hue /= 6.0;
+
+ float saturation = (maxC > 0.0) ? (delta / maxC) : 0.0;
+ float value = maxC;
+
+ // Offset the hue
+ hue = mod(hue + hueOffset, 1.0);
+
+ // Convert HSV back to RGB
+ float c = value * saturation;
+ float x = c * (1.0 - abs(mod(hue * 6.0, 2.0) - 1.0));
+ float m = value - c;
+
+ vec3 rgb;
+ if (hue < 1.0 / 6.0) {
+ rgb = vec3(c, x, 0.0);
+ } else if (hue < 2.0 / 6.0) {
+ rgb = vec3(x, c, 0.0);
+ } else if (hue < 3.0 / 6.0) {
+ rgb = vec3(0.0, c, x);
+ } else if (hue < 4.0 / 6.0) {
+ rgb = vec3(0.0, x, c);
+ } else if (hue < 5.0 / 6.0) {
+ rgb = vec3(x, 0.0, c);
+ } else {
+ rgb = vec3(c, 0.0, x);
+ }
+
+ return rgb + m;
+}
+
// ---------------------------------------------------------------------- easing functions
// Here are some basic easing function. More can be added if required!
diff --git a/resources/shaders/team-rocket.frag b/resources/shaders/team-rocket.frag
index cc6dd02..e21a1f1 100644
--- a/resources/shaders/team-rocket.frag
+++ b/resources/shaders/team-rocket.frag
@@ -123,8 +123,6 @@ void main() {
// scale progress ... the first half of the animation
float scalep = remap(
progress,
- //0.0,clamp(uWT + 0.1,0.0,1.0),
- // 0.0,0.6,
0.0,uWT+0.1,
0.0,1.0
);
@@ -135,8 +133,6 @@ void main() {
// sparkle progress ... the second half of the animation
float sparkp = remap(
progress,
- // clamp((1.0 - uWT) - 0.1,0.0,1.0),1.0,
- // 0.4,1.0,
uWT-0.1,1.0,
0.0,1.0
);
diff --git a/resources/shaders/unicorn-fart.frag b/resources/shaders/unicorn-fart.frag
new file mode 100644
index 0000000..7a63590
--- /dev/null
+++ b/resources/shaders/unicorn-fart.frag
@@ -0,0 +1,521 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
+// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
+// |__/ //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// SPDX-FileCopyrightText: Justin Garza JGarza9788@gmail.com
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// The content from common.glsl is automatically prepended to each shader effect. This
+// provides the standard input:
+
+// vec2 iTexCoord: Texture coordinates for retrieving the window input color.
+// bool uIsFullscreen: True if the window is maximized or in fullscreen mode.
+// bool uForOpening: True if a window-open animation is ongoing, false otherwise.
+// float uProgress: A value which transitions from 0 to 1 during the animation.
+// float uDuration: The duration of the current animation in seconds.
+// vec2 uSize: The size of uTexture in pixels.
+// float uPadding: The empty area around the actual window (e.g. where the shadow
+// is drawn). For now, this will only be set on GNOME.
+
+// Furthermore, there are two global methods for reading the window input color and
+// setting the shader output color. Both methods assume straight alpha:
+
+// vec4 getInputColor(vec2 coords)
+// void setOutputColor(vec4 outColor)
+
+// The width of the fading effect is loaded from the settings.
+
+uniform float uSparkCount;
+uniform vec2 uSparkStartEnd;
+uniform float uSparkOffset;
+uniform float uStarCount;
+uniform float uStarRot;
+uniform float uStarSize;
+uniform vec2 uStarStartEnd;
+uniform float uBlurQuality;
+uniform float uSeed;
+
+
+//particle colors
+uniform vec4 uSparkColor0;
+uniform vec4 uSparkColor1;
+uniform vec4 uSparkColor2;
+uniform vec4 uSparkColor3;
+uniform vec4 uSparkColor4;
+uniform vec4 uSparkColor5;
+
+//star colors
+uniform vec4 uStarColor0;
+uniform vec4 uStarColor1;
+uniform vec4 uStarColor2;
+uniform vec4 uStarColor3;
+uniform vec4 uStarColor4;
+uniform vec4 uStarColor5;
+
+
+// Define a constant for 2 * PI (tau), which represents a full circle in radians.
+const float PI = 3.14159265359;
+const float tau = 6.28318530718;
+
+//helps to find the angle
+vec3 getPosByAngle(float angle)
+{
+ return vec3(cos(angle), sin(angle), 0);
+}
+
+//this returns the Spark
+float getSpark(vec2 uv,vec2 center, float brightness, float size, float rotation)
+{
+
+ //the size
+ size = clamp(size,0.001,1.0);
+
+ uv = (uv + vec2(0.5)) ; //set center
+ uv = (uv - center) ;//Center UV coordinates, then scale to fit the star size
+
+ //scale
+ uv = uv * 2.0 -1.0;
+ uv /= mix(vec2(1.0,1.0), vec2(0.0,0.0), vec2(1.0 - size));
+ uv = uv * 0.5 + 0.5;
+
+ uv = rotate(uv, rotation, vec2(0.5));
+
+
+ //the brightness of the spark
+ brightness = clamp(brightness,0.001,1.0);
+ float bn = mix(0.0,0.07,brightness); //recalculate size
+
+
+ //this is basically the brightness
+ float p = mix(-1.0,1000.0,easeInExpo(bn));
+
+ float m = mix(
+ 0.0,
+ 1.0,
+ clamp(
+ pow(abs(uv.x-0.5)*2.0,p) + pow(abs(uv.y-0.5)*2.0,p),0.0,1.0
+ )
+ );
+
+ //calcuate and return this mask
+ float mask = easeInSine(1.0 - (m - bn)) - 0.004 ;
+ mask = clamp(mask,0.0,1.0);
+ return mask;
+
+}
+
+
+//this was lifted from aura-glow
+float getMask(float t)
+{
+
+ // Calculate the aspect ratio of the render area
+ float aspect = uSize.x / uSize.y;
+
+ //standard uv
+ vec2 uv = iTexCoord.st;
+
+ // tuv is for when progress is near 0
+ vec2 tuv = uv;
+ tuv -= 0.5; // Shift UV coordinates to center (from [-0.5 to 0.5])
+ tuv.x *= aspect; // Scale x-coordinate to match aspect ratio
+ tuv += 0.5; // Shift UV coordinates back (from [0 to 1])
+
+ //mixing the UVs
+ uv = mix(tuv,uv,t);
+
+ // this controls the shape
+ // -1.0 would be a diamond-ish
+ // 0.0 would be a rounded diamond
+ // 1.0 would be a circle
+ // 2.0 will be sqircle
+ // 1000.0 will be very square
+ float p = mix(1.0,1000.0,
+ easeInExpo(t)
+ );
+
+ //this will be used later to make a mask
+ float m = mix(
+ 0.0,
+ 1.0,
+ clamp(
+ pow(abs(uv.x-0.5)*2.0,p) + pow(abs(uv.y-0.5)*2.0,p),0.0,1.0
+ )
+ );
+
+ //this is the mask
+ //float mask = (m > t) ? 0.0 : 1.0 ;
+ float mask = (m > t) ? (1.0 - (m - t)) : 1.0 ;
+ mask = clamp(mask,0.0,1.0);
+
+ return mask;
+}
+
+
+// A simple blur function
+vec4 blur(vec2 uv, float radius, float samples) {
+ // Initialize the color accumulator to zero.
+ vec4 color = vec4(0.0);
+
+
+
+ // Number of directions for sampling around the circle.
+ const float directions = 15.0;
+
+ // Outer loop iterates over multiple directions evenly spaced around a circle.
+ for (float d = 0.0; d < tau; d += tau / directions) {
+ // Inner loop samples along each direction, with decreasing intensity.
+ for (float s = 0.0; s < 1.0; s += 1.0 / samples) {
+ // Calculate the offset for this sample based on direction, radius, and step.
+ // The (1.0 - s) term ensures more sampling occurs closer to the center.
+ vec2 offset = vec2(cos(d), sin(d)) * radius * (1.0 - s) / uSize;
+
+ // Add the sampled color at the offset position to the accumulator.
+ color += getInputColor(uv + offset);
+ }
+ }
+
+ // Normalize the accumulated color by dividing by the total number of samples
+ // and directions to ensure the result is averaged.
+ return color / samples / directions;
+}
+
+
+//fades out at 0 and 1 ...based on the power
+// 1| __________
+// | / \
+// | / \
+// | / \
+// |/ \
+// 0|0.................1
+/*
+graph above ... where t is close to 0, or 1 the result will fade to zero
+i.e. this is just the function of power(x,p) shifted
+where x is time, and p is 2.0,4.0,8.0,10.0 ... or any positive even number
+*/
+float FadeInOut(float t, float power)
+{
+ float s = -1.0 * pow((t-0.5)/(0.5),power)+1.0;
+ s = clamp(s,0.0,1.0);
+ return s;
+}
+
+
+//returns the Spark's color
+vec4 getSparkColors(float v, float alpha) {
+ // Clamp v to ensure it's in [0.0, 1.0]
+ v = clamp(v, 0.0, 1.0);
+
+ // Define steps for color interpolation
+ float steps[6];
+ steps[0] = 0.0;
+ steps[1] = 0.1666;
+ steps[2] = 0.3332;
+ steps[3] = 0.4998;
+ steps[4] = 0.6664;
+ steps[5] = 0.8330;
+
+ // Define color values
+ vec4 colors[6];
+ colors[0] = uSparkColor0 ;
+ colors[1] = uSparkColor1 ;
+ colors[2] = uSparkColor2 ;
+ colors[3] = uSparkColor3 ;
+ colors[4] = uSparkColor4 ;
+ colors[5] = uSparkColor5 ;
+
+ // Assign alpha values
+ for (int i = 0; i < 6; ++i) {
+ colors[i].a = alpha * colors[i].a;
+ }
+
+ // Handle edge cases
+ if (v <= steps[0]) {
+ return colors[0];
+ }
+ if (v >= steps[5]) {
+ return colors[5];
+ }
+
+ // Find the correct interpolation segment
+ for (int i = 0; i < 5; ++i) {
+ if (v <= steps[i + 1]) {
+ float t = (v - steps[i]) / (steps[i + 1] - steps[i]);
+ return mix(colors[i], colors[i + 1], t);
+ }
+ }
+
+ // Fallback (should never be reached)
+ return vec4(0.0, 0.0, 0.0, 1.0);
+}
+
+
+
+vec4 getSparks(float t)
+{
+
+
+ //the UV for this function
+ float aspect = uSize.x / uSize.y;
+ vec2 uv = iTexCoord.st * vec2(aspect,1.0);
+
+ vec4 result = vec4(0.0);
+
+ //for each spark
+ for (float i = 0.0; i < uSparkCount ; ++i)
+ {
+ //random values
+ vec4 v4 = hash41( i * uSeed);
+
+ //the X and Y position ... at the end
+ vec3 pos = getPosByAngle( (i/uSparkCount) * tau + (v4.x * 0.3) );
+
+ //the distance the spark will travel
+ float d = mix(0.33,0.34,v4.z) ;
+ d = mix(
+ uSparkStartEnd.x + (v4.z * uSparkOffset),
+ uSparkStartEnd.y - (v4.y * uSparkOffset),
+ (1.0 - t)
+ );
+
+ float s = getSpark(
+ uv,
+ vec2(0.5 * aspect,0.5) + ( pos.xy * d ), //position (x, y)
+ FadeInOut(t,8.0) * 0.9 ,//Brightness
+ FadeInOut(t,8.0) * (v4.w * 0.5) ,//Size
+ 0.0 //rotation
+ );
+
+
+ //set the color
+ vec4 c = getSparkColors( hash11(v4.w) ,1.0);
+ s = clamp(s*2.0,0.0,1.0);
+ c.rgb *= s;
+ c.a *= s;
+
+ result += c ;
+
+ }
+
+ //make it bright
+ result.a = pow(result.a,2.0);
+
+ //fade at endges
+ result.a *= FadeInOut(iTexCoord.s,4.0);
+ result.a *= FadeInOut(iTexCoord.t,4.0);
+
+ return clamp(result,vec4(0.0),vec4(1.0));
+ // return result;
+
+}
+
+
+
+
+
+vec4 getStarColors(float v, float alpha) {
+ // Clamp v to ensure it's in [0.0, 1.0]
+ v = clamp(v, 0.0, 1.0);
+
+ // Define steps for color interpolation
+ float steps[6];
+ steps[0] = 0.0;
+ steps[1] = 0.1666;
+ steps[2] = 0.3332;
+ steps[3] = 0.4998;
+ steps[4] = 0.6664;
+ steps[5] = 0.8330;
+
+ // Define color values
+ vec4 colors[6];
+ colors[0] = uStarColor0 ;
+ colors[1] = uStarColor1 ;
+ colors[2] = uStarColor2 ;
+ colors[3] = uStarColor3 ;
+ colors[4] = uStarColor4 ;
+ colors[5] = uStarColor5 ;
+
+ // Assign alpha values
+ for (int i = 0; i < 6; ++i) {
+ colors[i].a = alpha * colors[i].a;
+ }
+
+ // Handle edge cases
+ if (v <= steps[0]) {
+ return colors[0];
+ }
+ if (v >= steps[5]) {
+ return colors[5];
+ }
+
+ // Find the correct interpolation segment
+ for (int i = 0; i < 5; ++i) {
+ if (v <= steps[i + 1]) {
+ float t = (v - steps[i]) / (steps[i + 1] - steps[i]);
+ return mix(colors[i], colors[i + 1], t);
+ }
+ }
+
+ // Fallback (should never be reached)
+ return vec4(0.0, 0.0, 0.0, 1.0);
+}
+
+
+
+
+//gets the mask of a Star
+float getStar(vec2 uv, vec2 center, float npoints, float radiusRatio, float size, float rotation)
+{
+
+ float radiusMax = 1.0;
+ float radiusMin = radiusMax * radiusRatio;
+
+ float starangle = 2.0 * PI / npoints; // Angle between points on the star
+
+ // Offset rotation to ensure one point is always up when rotation = 0
+ rotation += PI / 2.0 - starangle / 1.0;
+
+ // Define the positions for the outer and inner points of the star's initial angle, rotated by `rotation`
+ vec3 p0 = (radiusMax * size) * getPosByAngle(rotation); // Outer point, rotated by `rotation`
+ vec3 p1 = (radiusMin * size) * getPosByAngle(starangle + rotation); // Inner point, also rotated
+
+ // Calculate the position of the current fragment relative to the star's center
+ vec2 curPosuv = (uv - center); // Center UV coordinates, then scale to fit the star size
+ float curRadius = length(curPosuv); // Radius from center, no need to scale further
+ float curPosAngle = atan(curPosuv.y, curPosuv.x) - rotation; // Calculate angle and adjust by `rotation`
+
+ // Determine the fractional position within the current star segment
+ float a = fract(curPosAngle / starangle); // Fractional angle position within one segment
+ if (a >= 0.5)
+ a = 1.0 - a; // Ensure we are within the first half of the segment (symmetry)
+
+ // Calculate the current point on the star segment, applying rotation
+ a = a * starangle; // Actual angle for this position on the segment
+ vec3 curPos = curRadius * getPosByAngle(a + rotation); // Final position, rotated
+
+ // Calculate directions for edge detection using cross product
+ vec3 dir0 = p1 - p0; // Vector from outer to inner point
+ vec3 dir1 = curPos - p0; // Vector from outer point to current position
+
+ // Use cross product to determine if `curPos` is inside the star's edge
+ return step(0.0, cross(dir0, dir1).z); // Returns 1.0 if inside, 0.0 if outside (solid edge)
+}
+
+
+//convert the XY to angle
+float XYtoAngle(vec2 XY)
+{
+ return atan(XY.y, XY.x);
+}
+
+
+vec4 getStars(float t)
+{
+
+ //the UV for this function
+ float aspect = uSize.x / uSize.y;
+ vec2 uv = iTexCoord.st * vec2(aspect,1.0);
+
+ // float result = 0.0;
+ vec4 result = vec4(0.0);
+
+ //loop for each star
+ for (float i = 0.0; i < uStarCount ; ++i)
+ {
+ //random values for this star
+ vec4 v4 = hash41( i * uSeed);
+
+ //the X and Y position ... at the end
+ vec3 pos = getPosByAngle( (i/uStarCount) * tau + (uStarRot * tau * t) );
+
+ //the distance the spark will travel
+ float d = mix(0.33,0.34,v4.z) ;
+ d = mix(
+ uStarStartEnd.x ,
+ uStarStartEnd.y ,
+ (1.0 - t)
+ );
+
+
+ float s = getStar(
+ uv,
+ vec2(0.5 * aspect,0.5) + ( pos.xy * d ), //position (x, y)
+ 5.0, //npoints
+ 0.5, //Ratio
+ FadeInOut(t,4.0) * uStarSize,//Size
+ PI //rotation
+ );
+
+
+ s *= FadeInOut(iTexCoord.s,4.0);
+ s *= FadeInOut(iTexCoord.t,4.0);
+ s = clamp(s,0.0,1.0);
+
+ //the color is based on it's starting location
+ vec4 color = getStarColors( i/uStarCount ,1.0);
+ result += vec4(color.rgb * s,s * color.a);
+
+ }
+
+
+ return result;
+
+}
+
+
+
+void main() {
+ // Calculate the progression value based on the animation direction.
+ // If opening, use uProgress as-is; if closing, invert the progression.
+ float progress = uForOpening ? 1.0 - uProgress : uProgress ;
+
+ //zero to one... mostly one
+ float ztomo = remap(
+ progress,
+ 0.0,0.1,
+ 0.0,1.0
+ );
+ ztomo = easeInOutSine(ztomo);
+
+ //progress variants
+ // float oExpo = easeOutExpo(progress);
+ // float iExpo = easeInExpo(progress);
+ // float oQuad = easeOutQuad(progress);
+ float ioCubic = easeInOutCubic(progress);
+ float ioSine = easeInOutSine(progress);
+
+ vec2 uv = iTexCoord.st;
+ //center
+ uv = uv * 2.0 - 1.0;
+ //scale
+ uv /= mix(vec2(0.5,0.5), vec2(0.0,0.0), ioCubic);
+ // scale from center
+ uv = uv * 0.5 + 0.5;
+
+ //get blured version of the window
+ vec4 oColor = blur(uv, ioCubic * 200.0,uBlurQuality);
+
+ oColor.a *= (1.0 - ioSine);
+
+ //get and apply sparks
+ if (uSparkCount > 0)
+ {
+ vec4 sparks = getSparks(ioSine);
+ oColor = alphaOver(oColor, sparks);
+ }
+
+ //get and apply stars
+ if (uStarCount > 0 )
+ {
+ oColor = alphaOver(oColor, getStars(mix(0.0001,0.999,ioSine)));
+ }
+
+ setOutputColor(oColor);
+}
\ No newline at end of file
diff --git a/resources/ui/adw/unicorn-fart.ui b/resources/ui/adw/unicorn-fart.ui
new file mode 100644
index 0000000..9450b81
--- /dev/null
+++ b/resources/ui/adw/unicorn-fart.ui
@@ -0,0 +1,535 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/schemas/org.gnome.shell.extensions.burn-my-windows-profile.gschema.xml b/schemas/org.gnome.shell.extensions.burn-my-windows-profile.gschema.xml
index 20e52cf..80afe51 100644
--- a/schemas/org.gnome.shell.extensions.burn-my-windows-profile.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.burn-my-windows-profile.gschema.xml
@@ -1098,8 +1098,8 @@ SPDX-License-Identifier: CC0-1.0
0.5
- The time for the window animation
- time for window animation
+ Window vs Sparkle split
+ Window vs Sparkle split
@@ -1119,7 +1119,7 @@ SPDX-License-Identifier: CC0-1.0
Rotate the Window
Rotate the Window
-
+
0.33
Sparkle Rotation
@@ -1132,6 +1132,167 @@ SPDX-License-Identifier: CC0-1.0
Sparkle Size
+
+
+
+
+
+
+ false
+ Unicorn Fart Enable Effect
+ Use the Unicorn Fart effect.
+
+
+
+ 1500
+ Unicorn Fart Animation Time
+ The time the Unicorn Fart effect takes.
+
+
+
+
+
+ 25
+ Number of Sparks
+ Set the total number of sparks generated.
+
+
+
+ 0.0
+ Spark Start Point
+ Define the starting position for sparks.
+
+
+
+ 1.0
+ Spark End Point
+ Define the ending position for sparks.
+
+
+
+ 0.5
+ Spark Offset
+ Set the positional offset for sparks.
+
+
+
+
+ 6
+ Number of Stars
+ Set the total number of stars displayed.
+
+
+
+ 0.33
+ Star Rotation
+ Control the rotational angle of stars.
+
+
+
+ 0.1
+ Star Size
+ Set the size of the stars.
+
+
+
+ 0.0
+ Star Start Point
+ Define the starting position for stars.
+
+
+
+ 1.0
+ Star End Point
+ Define the ending position for stars.
+
+
+
+
+ 5.0
+ Blur Quality
+ Set the quality level for the blur effect.
+
+
+
+ 1.0
+ Random Seed
+ Define the seed value for random effects.
+
+
+
+
+ "rgba(255, 255, 255, 1.0)"
+ Primary Particle Color
+ Set the first color used for particles.
+
+
+
+ "rgba(255, 255, 255, 1.0)"
+ Secondary Particle Color
+ Set the second color used for particles.
+
+
+
+ "rgba(255, 255, 255, 1.0)"
+ Tertiary Particle Color
+ Set the third color used for particles.
+
+
+
+ "rgba(255, 255, 255, 1.0)"
+ Quaternary Particle Color
+ Set the fourth color used for particles.
+
+
+
+ "rgba(255, 255, 255, 1.0)"
+ Quinary Particle Color
+ Set the fifth color used for particles.
+
+
+
+ "rgba(255, 255, 255, 1.0)"
+ Senary Particle Color
+ Set the sixth color used for particles.
+
+
+
+
+ "rgba(255, 0, 0, 1.0)"
+ Primary Star Color
+ Set the first color used for stars.
+
+
+
+ "rgba(255, 255, 0, 1.0)"
+ Secondary Star Color
+ Set the second color used for stars.
+
+
+
+ "rgba(0, 255, 0, 1.0)"
+ Tertiary Star Color
+ Set the third color used for stars.
+
+
+
+ "rgba(0, 255, 255, 1.0)"
+ Quaternary Star Color
+ Set the fourth color used for stars.
+
+
+
+ "rgba(0, 0, 255, 1.0)"
+ Quinary Star Color
+ Set the fifth color used for stars.
+
+
+
+ "rgba(255, 0, 255, 1.0)"
+ Senary Star Color
+ Set the sixth color used for stars.
+
+
diff --git a/src/Shader.js b/src/Shader.js
index f115f75..b6d3398 100644
--- a/src/Shader.js
+++ b/src/Shader.js
@@ -65,6 +65,8 @@ export var Shader = GObject.registerClass({
// vfunc_build_pipeline()) from the resource file resources/shaders/.glsl
// resolving any #includes in this file.
_init(nick) {
+ log(`Shader initialized with params: ${JSON.stringify(nick)}`);
+
this._nick = nick;
// This will call vfunc_build_pipeline().
@@ -96,6 +98,7 @@ export var Shader = GObject.registerClass({
// Clean up if the animation finished or was interrupted.
this._timeline.connect('stopped', (t, finished) => {
+ // log(`Shader initialized with params: ${JSON.stringify(t)}`);
this.endAnimation();
});
}
@@ -151,6 +154,9 @@ export var Shader = GObject.registerClass({
endAnimation() {
// This will call endAnimation() again, so we can return for now.
if (this._timeline.is_playing()) {
+ // log(`Shader initialized with params:
+ // ${JSON.stringify(this._timeline.is_playing())}`);
+
this._timeline.stop();
return;
}
diff --git a/src/effects/AuraGlow.js b/src/effects/AuraGlow.js
index 4383735..a6028ba 100644
--- a/src/effects/AuraGlow.js
+++ b/src/effects/AuraGlow.js
@@ -173,7 +173,7 @@ export default class Effect {
*/
// if we use a switch instead of a checkbox
-
+
const switchWidget = dialog.getBuilder().get_object('aura-glow-random-color');
if (switchWidget) {
// Connect to the "state-set" signal to update preferences dynamically based on
@@ -191,7 +191,7 @@ export default class Effect {
// Log an error if the switch widget is not found in the UI.
log('Error: \'aura-glow-random-color\' switch widget not found.');
}
-
+
// Retrieve the necessary objects
const colorOffset = dialog.getBuilder().get_object('aura-glow-color-offset-scale');
diff --git a/src/effects/TeamRocket.js b/src/effects/TeamRocket.js
index ba7d9cc..c1ecd4b 100644
--- a/src/effects/TeamRocket.js
+++ b/src/effects/TeamRocket.js
@@ -39,14 +39,14 @@ export default class Effect {
constructor() {
this.shaderFactory = new ShaderFactory(Effect.getNick(), (shader) => {
// Store uniform locations of newly created shaders.
- shader._uWT = shader.get_uniform_location('uWT');
+ shader._uWT = shader.get_uniform_location('uWT');
shader._uXpos = shader.get_uniform_location('uXpos');
shader._uYpos = shader.get_uniform_location('uYpos');
shader._uWinRot = shader.get_uniform_location('uWinRot');
shader._uSparkleRot = shader.get_uniform_location('uSparkleRot');
shader._uSparkleSize = shader.get_uniform_location('uSparkleSize');
- shader._uSeed = shader.get_uniform_location('uSeed');
+ shader._uSeed = shader.get_uniform_location('uSeed');
// Write all uniform values at the start of each animation.
shader.connect('begin-animation', (shader, settings) => {
@@ -63,7 +63,7 @@ export default class Effect {
]);
shader.set_uniform_float(shader._uWinRot, 1,
- [settings.get_boolean('team-rocket-win-rot')]);
+ [settings.get_boolean('team-rocket-win-rot')]);
shader.set_uniform_float(shader._uSparkleRot, 1, [
settings.get_double('team-rocket-sparkle-rot'),
diff --git a/src/effects/UnicornFart.js b/src/effects/UnicornFart.js
new file mode 100644
index 0000000..a572212
--- /dev/null
+++ b/src/effects/UnicornFart.js
@@ -0,0 +1,452 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
+// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
+// |__/ //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// SPDX-FileCopyrightText: Justin Garza JGarza9788@gmail.com
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+'use strict';
+
+// Import the Gio module from the GNOME platform (GObject Introspection).
+// This module provides APIs for I/O operations, settings management, and other core
+// features.
+import Gio from 'gi://Gio';
+
+// Import utility functions from the local utils.js file.
+// These utilities likely contain helper functions or shared logic used across the
+// application.
+import * as utils from '../utils.js';
+
+// We import the ShaderFactory only in the Shell process as it is not required in the
+// preferences process. The preferences process does not create any shader instances, it
+// only uses the static metadata of the effect.
+const ShaderFactory = await utils.importInShellOnly('./ShaderFactory.js');
+
+const _ = await utils.importGettext();
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// I thought to myself, i said "self what would a unicorn fart look like" and then i came
+// up with this, and i don't care that i'm out of the box, i think outside of the box,
+// yeah f*ck that box!
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// The effect class can be used to get some metadata (like the effect's name or supported
+// GNOME Shell versions), to initialize the respective page of the settings dialog, as
+// well as to create the actual shader for the effect.
+export default class Effect {
+ // The constructor creates a ShaderFactory which will be used by extension.js to create
+ // shader instances for this effect. The shaders will be automagically created using the
+ // GLSL file in resources/shaders/.glsl. The callback will be called for each
+ // newly created shader instance.
+ constructor() {
+ this.shaderFactory = new ShaderFactory(Effect.getNick(), (shader) => {
+ // Store uniform locations of newly created shaders.
+
+ // shader._uParticles = shader.get_uniform_location('uParticles');
+ // shader._uParticleSize = shader.get_uniform_location('uParticleSize');
+ // shader._uParticleSpeed = shader.get_uniform_location('uParticleSpeed');
+ // shader._uParticleColorRandom =
+ // shader.get_uniform_location('uParticleColorRandom'); shader._uParticleColorSpeed
+ // = shader.get_uniform_location('uParticleColorSpeed');
+
+ shader._uSparkCount = shader.get_uniform_location('uSparkCount');
+ shader._uSparkStartEnd = shader.get_uniform_location('uSparkStartEnd');
+ shader._uSparkOffset = shader.get_uniform_location('uSparkOffset');
+ shader._uSparkCount = shader.get_uniform_location('uSparkCount');
+
+ shader._uStarCount = shader.get_uniform_location('uStarCount');
+ shader._uStarRot = shader.get_uniform_location('uStarRot');
+ shader._uStarSize = shader.get_uniform_location('uStarSize');
+ shader._uStarStartEnd = shader.get_uniform_location('uStarStartEnd');
+
+ shader._uBlurQuality = shader.get_uniform_location('uBlurQuality');
+ shader._uSeed = shader.get_uniform_location('uSeed');
+
+ shader._uStarColors = [
+ shader.get_uniform_location('uStarColor0'),
+ shader.get_uniform_location('uStarColor1'),
+ shader.get_uniform_location('uStarColor2'),
+ shader.get_uniform_location('uStarColor3'),
+ shader.get_uniform_location('uStarColor4'),
+ shader.get_uniform_location('uStarColor5'),
+ ];
+
+ shader._uParticleColors = [
+ shader.get_uniform_location('uSparkColor0'),
+ shader.get_uniform_location('uSparkColor1'),
+ shader.get_uniform_location('uSparkColor2'),
+ shader.get_uniform_location('uSparkColor3'),
+ shader.get_uniform_location('uSparkColor4'),
+ shader.get_uniform_location('uSparkColor5'),
+ ];
+
+ // Write all uniform values at the start of each animation.
+ shader.connect('begin-animation', (shader, settings) => {
+ for (let i = 0; i <= 5; i++) {
+ shader.set_uniform_float(
+ shader._uStarColors[i], 4,
+ utils.parseColor(settings.get_string('unicorn-fart-star-color-' + i)));
+ }
+
+ for (let i = 0; i <= 5; i++) {
+ shader.set_uniform_float(
+ shader._uParticleColors[i], 4,
+ utils.parseColor(settings.get_string('unicorn-fart-spark-color-' + i)));
+ }
+
+
+ shader.set_uniform_float(shader._uSparkCount, 1,
+ [settings.get_int('unicorn-fart-spark-count')]);
+
+ shader.set_uniform_float(shader._uSparkStartEnd, 2, [
+ settings.get_double('unicorn-fart-spark-start'),
+ settings.get_double('unicorn-fart-spark-end')
+ ]);
+
+ shader.set_uniform_float(shader._uSparkOffset, 1,
+ [settings.get_double('unicorn-fart-spark-offset')]);
+
+ shader.set_uniform_float(shader._uStarCount, 1,
+ [settings.get_int('unicorn-fart-star-count')]);
+
+ shader.set_uniform_float(shader._uStarRot, 1,
+ [settings.get_double('unicorn-fart-star-rotation')]);
+
+ shader.set_uniform_float(shader._uStarSize, 1,
+ [settings.get_double('unicorn-fart-star-size')]);
+
+ shader.set_uniform_float(shader._uStarStartEnd, 2, [
+ settings.get_double('unicorn-fart-star-start'),
+ settings.get_double('unicorn-fart-star-end')
+ ]);
+
+ shader.set_uniform_float(shader._uBlurQuality, 1,
+ [settings.get_double('unicorn-fart-blur-quality')]);
+
+ shader.set_uniform_float(shader._uSeed, 1, [Math.random()]);
+ });
+ });
+ }
+
+ // ---------------------------------------------------------------------------- metadata
+
+ // The effect is available on all GNOME Shell versions supported by this extension.
+ static getMinShellVersion() {
+ return [3, 36];
+ }
+
+ // This will be called in various places where a unique identifier for this effect is
+ // required. It should match the prefix of the settings keys which store whether the
+ // effect is enabled currently (e.g. '*-enable-effect'), and its animation time
+ // (e.g. '*-animation-time'). Also, the shader file and the settings UI files should be
+ // named likes this.
+ static getNick() {
+ return 'unicorn-fart';
+ }
+
+ // This will be shown in the sidebar of the preferences dialog as well as in the
+ // drop-down menus where the user can choose the effect.
+ static getLabel() {
+ return _('UnicornFart');
+ }
+
+ // -------------------------------------------------------------------- API for prefs.js
+
+ // This is called by the preferences dialog whenever a new effect profile is loaded. It
+ // binds all user interface elements to the respective settings keys of the profile.
+ static bindPreferences(dialog) {
+ // Empty for now... Code is added here later in the tutorial!
+
+ dialog.bindAdjustment('unicorn-fart-animation-time');
+
+ dialog.bindAdjustment('unicorn-fart-spark-count');
+ dialog.bindAdjustment('unicorn-fart-spark-start');
+ dialog.bindAdjustment('unicorn-fart-spark-end');
+ dialog.bindAdjustment('unicorn-fart-spark-offset');
+
+ dialog.bindAdjustment('unicorn-fart-star-count');
+ dialog.bindAdjustment('unicorn-fart-star-rotation');
+ dialog.bindAdjustment('unicorn-fart-star-size');
+ dialog.bindAdjustment('unicorn-fart-star-start');
+ dialog.bindAdjustment('unicorn-fart-star-end');
+ dialog.bindAdjustment('unicorn-fart-blur-quality');
+
+ // switches
+ dialog.bindSwitch('unicorn-fart-particles-enable');
+
+ // star-color
+ dialog.bindColorButton('unicorn-fart-star-color-0');
+ dialog.bindColorButton('unicorn-fart-star-color-1');
+ dialog.bindColorButton('unicorn-fart-star-color-2');
+ dialog.bindColorButton('unicorn-fart-star-color-3');
+ dialog.bindColorButton('unicorn-fart-star-color-4');
+ dialog.bindColorButton('unicorn-fart-star-color-5');
+
+ // particle-colors
+ dialog.bindColorButton('unicorn-fart-spark-color-0');
+ dialog.bindColorButton('unicorn-fart-spark-color-1');
+ dialog.bindColorButton('unicorn-fart-spark-color-2');
+ dialog.bindColorButton('unicorn-fart-spark-color-3');
+ dialog.bindColorButton('unicorn-fart-spark-color-4');
+ dialog.bindColorButton('unicorn-fart-spark-color-5');
+
+
+
+ // Ensure the button connections and other bindings happen only once,
+ // even if the bindPreferences function is called multiple times.
+ if (!Effect._isConnected) {
+ Effect._isConnected = true;
+
+ // Bind the "reset-unicorn-fart-spark-colors" button to reset all star colors to
+ // their default values.
+ dialog.getBuilder()
+ .get_object('reset-unicorn-fart-spark-colors')
+ .connect('clicked', () => {
+ // Reset each mushroom star color setting.
+ dialog.getProfileSettings().reset('unicorn-fart-spark-color-0');
+ dialog.getProfileSettings().reset('unicorn-fart-spark-color-1');
+ dialog.getProfileSettings().reset('unicorn-fart-spark-color-2');
+ dialog.getProfileSettings().reset('unicorn-fart-spark-color-3');
+ dialog.getProfileSettings().reset('unicorn-fart-spark-color-4');
+ dialog.getProfileSettings().reset('unicorn-fart-spark-color-5');
+ });
+
+ dialog.getBuilder()
+ .get_object('reset-unicorn-fart-star-colors')
+ .connect('clicked', () => {
+ // Reset each mushroom star color setting.
+ dialog.getProfileSettings().reset('unicorn-fart-star-color-0');
+ dialog.getProfileSettings().reset('unicorn-fart-star-color-1');
+ dialog.getProfileSettings().reset('unicorn-fart-star-color-2');
+ dialog.getProfileSettings().reset('unicorn-fart-star-color-3');
+ dialog.getProfileSettings().reset('unicorn-fart-star-color-4');
+ dialog.getProfileSettings().reset('unicorn-fart-star-color-5');
+ });
+
+
+ // Initialize the preset dropdown menu for mushroom star colors.
+ Effect._createUnicornFartPresets(dialog);
+ }
+ }
+
+ // ---------------------------------------------------------------- API for extension.js
+
+ // The getActorScale() is called from extension.js to adjust the actor's size during the
+ // animation. This is useful if the effect requires drawing something beyond the usual
+ // bounds of the actor. This only works for GNOME 3.38+.
+ static getActorScale(settings, forOpening, actor) {
+ return {x: 2.0, y: 2.0};
+ }
+
+ // ---------------------------------------------------------------- Presets
+
+ // This function initializes the preset dropdown menu for configuring fire options.
+ // It defines multiple color presets for the "mushroom star" effect and sets up
+ // the logic to apply these presets when selected.
+
+ static _createUnicornFartPresets(dialog) {
+ // Retrieve the builder object for the dialog and connect to the "realize" event of
+ // the button.
+ dialog.getBuilder()
+ .get_object('unicorn-fart-preset-button')
+ .connect('realize', (widget) => {
+ // Define an array of color presets, each with a name and six color values (RGBA
+ // format).
+ const presets = [
+ {
+ name: _('Unicorn Fart (Default)'),
+ SparkCount: 25,
+ SparkStart: 0.0,
+ SparkEnd: 1.0,
+ SparkOffset: 1.0,
+
+ StarCount: 6,
+ StarRot: 0.33,
+ StarSize: 0.10,
+ StarStart: 0.0,
+ StarEnd: 1.0,
+
+ BlurQuality:5.0,
+
+ Sparkcolor0: 'rgba(255,255,255,1.0)',
+ Sparkcolor1: 'rgba(255,255,255,1.0)',
+ Sparkcolor2: 'rgba(255,255,255,1.0)',
+ Sparkcolor3: 'rgba(255,255,255,1.0)',
+ Sparkcolor4: 'rgba(255,255,255,1.0)',
+ Sparkcolor5: 'rgba(255,255,255,1.0)',
+
+
+ Starcolor0: 'rgba(255,0,0,1.0)',
+ Starcolor1: 'rgba(255,255,0,1.0)',
+ Starcolor2: 'rgba(0,255,0,1.0)',
+ Starcolor3: 'rgba(0,255,255,1.0)',
+ Starcolor4: 'rgba(0,0,255,1.0)',
+ Starcolor5: 'rgba(255,0,255,1.0)',
+
+
+ },
+ {
+ name: _('Fairy🧚'),
+ SparkCount: 100,
+ SparkStart: 0.0,
+ SparkEnd: 1.0,
+ SparkOffset: 1.0,
+
+ StarCount: 0,
+ StarRot: 0.33,
+ StarSize: 0.10,
+ StarStart: 0.0,
+ StarEnd: 1.0,
+
+ BlurQuality:5.0,
+
+ Sparkcolor0: 'rgba(255,255,255,1.0)',
+ Sparkcolor1: 'rgba(255,255,255,1.0)',
+ Sparkcolor2: 'rgba(255,255,255,1.0)',
+ Sparkcolor3: 'rgba(255,255,255,1.0)',
+ Sparkcolor4: 'rgba(255,255,255,1.0)',
+ Sparkcolor5: 'rgba(255,255,255,1.0)',
+
+
+ Starcolor0: 'rgba(255,0,0,1.0)',
+ Starcolor1: 'rgba(255,255,0,1.0)',
+ Starcolor2: 'rgba(0,255,0,1.0)',
+ Starcolor3: 'rgba(0,255,255,1.0)',
+ Starcolor4: 'rgba(0,0,255,1.0)',
+ Starcolor5: 'rgba(255,0,255,1.0)',
+
+
+ },
+ {
+ name: _('Ring of Fire ❤️🔥'),
+ SparkCount: 100,
+ SparkStart: 0.0,
+ SparkEnd: 1.0,
+ SparkOffset: 1.0,
+
+ StarCount: 25,
+ StarRot: 3.0,
+ StarSize: 0.10,
+ StarStart: 0.0,
+ StarEnd: 1.0,
+
+ BlurQuality:5.0,
+
+ Sparkcolor0: 'rgba(255,0,0,1.0)', // Deep red
+ Sparkcolor1: 'rgba(255,69,0,1.0)', // Fiery orange-red
+ Sparkcolor2: 'rgba(255,140,0,1.0)', // Orange
+ Sparkcolor3: 'rgba(255,215,0,1.0)', // Bright yellow
+ Sparkcolor4: 'rgba(255,255,102,1.0)', // Light yellow
+ Sparkcolor5: 'rgba(255,255,255,1.0)', // White (hottest point)
+
+ Starcolor0: 'rgba(255,0,0,1.0)', // Deep red
+ Starcolor1: 'rgba(255,69,0,1.0)', // Fiery orange-red
+ Starcolor2: 'rgba(255,140,0,1.0)', // Orange
+ Starcolor3: 'rgba(255,215,0,1.0)', // Bright yellow
+ Starcolor4: 'rgba(255,255,102,1.0)', // Light yellow
+ Starcolor5: 'rgba(255,255,255,1.0)', // White (hottest point)
+
+ },
+ {
+ name: _('Mystic 🪄'),
+ SparkCount: 100,
+ SparkStart: 0.0,
+ SparkEnd: 1.0,
+ SparkOffset: 1.0,
+
+ StarCount: 25,
+ StarRot: 3.0,
+ StarSize: 0.10,
+ StarStart: 0.0,
+ StarEnd: 1.0,
+
+ BlurQuality:5.0,
+
+ Sparkcolor0: 'rgba(75,0,130,1.0)', // Indigo
+ Sparkcolor1: 'rgba(138,43,226,1.0)', // Blue-violet
+ Sparkcolor2: 'rgba(0,191,255,1.0)', // Deep sky blue
+ Sparkcolor3: 'rgba(0,255,127,1.0)', // Spring green
+ Sparkcolor4: 'rgba(173,255,47,1.0)', // Green-yellow
+ Sparkcolor5: 'rgba(255,20,147,1.0)', // Deep pink
+
+ Starcolor0: 'rgba(75,0,130,1.0)', // Indigo
+ Starcolor1: 'rgba(138,43,226,1.0)', // Blue-violet
+ Starcolor2: 'rgba(0,191,255,1.0)', // Deep sky blue
+ Starcolor3: 'rgba(0,255,127,1.0)', // Spring green
+ Starcolor4: 'rgba(173,255,47,1.0)', // Green-yellow
+ Starcolor5: 'rgba(255,20,147,1.0)', // Deep pink
+
+ },
+ ];
+
+ // Create a new menu model to hold the presets and an action group for handling
+ // selections.
+ const menu = Gio.Menu.new();
+ const group = Gio.SimpleActionGroup.new();
+ const groupName = 'presets';
+
+ // Iterate over the presets to populate the menu.
+ presets.forEach((preset, i) => {
+ // Define an action name based on the preset index.
+ const actionName = 'unicorn-fart' + i;
+
+ // Append the preset name to the menu.
+ menu.append(preset.name, groupName + '.' + actionName);
+
+ // Create a new action for the preset.
+ let action = Gio.SimpleAction.new(actionName, null);
+
+ // Connect the action to a function that loads the preset colors into the
+ // dialog.
+ action.connect('activate', () => {
+ dialog.getProfileSettings().set_int('unicorn-fart-spark-count',preset.SparkCount);
+ dialog.getProfileSettings().set_double('unicorn-fart-spark-start',preset.SparkStart);
+ dialog.getProfileSettings().set_double('unicorn-fart-spark-end',preset.SparkEnd);
+ dialog.getProfileSettings().set_double('unicorn-fart-spark-offset',preset.SparkOffset);
+
+ dialog.getProfileSettings().set_int('unicorn-fart-star-count',preset.StarCount);
+ dialog.getProfileSettings().set_double('unicorn-fart-star-rotation',preset.StarRot);
+ dialog.getProfileSettings().set_double('unicorn-fart-star-size',preset.StarSize);
+ dialog.getProfileSettings().set_double('unicorn-fart-star-start',preset.StarStart);
+ dialog.getProfileSettings().set_double('unicorn-fart-star-end',preset.StarEnd);
+
+ dialog.getProfileSettings().set_double('unicorn-fart-blur-quality',preset.BlurQuality);
+
+ dialog.getProfileSettings().set_string('unicorn-fart-spark-color-0',preset.Sparkcolor0);
+ dialog.getProfileSettings().set_string('unicorn-fart-spark-color-1',preset.Sparkcolor1);
+ dialog.getProfileSettings().set_string('unicorn-fart-spark-color-2',preset.Sparkcolor2);
+ dialog.getProfileSettings().set_string('unicorn-fart-spark-color-3',preset.Sparkcolor3);
+ dialog.getProfileSettings().set_string('unicorn-fart-spark-color-4',preset.Sparkcolor4);
+ dialog.getProfileSettings().set_string('unicorn-fart-spark-color-5',preset.Sparkcolor5);
+
+ dialog.getProfileSettings().set_string('unicorn-fart-star-color-0',preset.Starcolor0);
+ dialog.getProfileSettings().set_string('unicorn-fart-star-color-1',preset.Starcolor1);
+ dialog.getProfileSettings().set_string('unicorn-fart-star-color-2',preset.Starcolor2);
+ dialog.getProfileSettings().set_string('unicorn-fart-star-color-3',preset.Starcolor3);
+ dialog.getProfileSettings().set_string('unicorn-fart-star-color-4',preset.Starcolor4);
+ dialog.getProfileSettings().set_string('unicorn-fart-star-color-5',preset.Starcolor5);
+
+ });
+
+ // Add the action to the action group.
+ group.add_action(action);
+ });
+
+ // Assign the populated menu to the preset button.
+ dialog.getBuilder()
+ .get_object('unicorn-fart-preset-button')
+ .set_menu_model(menu);
+
+ // Insert the action group into the root widget for handling the presets.
+ const root = widget.get_root();
+ root.insert_action_group(groupName, group);
+ });
+ }
+}
\ No newline at end of file