From dcd914dbae039560a4ad4db4edd0264845f7024b Mon Sep 17 00:00:00 2001
From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>
Date: Wed, 15 Jan 2025 15:22:22 +1100
Subject: better popup window

Not manual using css, instead use a combination of css opacity and Hyprland animations
---
 utils/widgets.tsx | 145 +++++++++++-------------------------------------------
 1 file changed, 28 insertions(+), 117 deletions(-)

(limited to 'utils/widgets.tsx')

diff --git a/utils/widgets.tsx b/utils/widgets.tsx
index 033a4e2..1065fae 100644
--- a/utils/widgets.tsx
+++ b/utils/widgets.tsx
@@ -1,5 +1,5 @@
-import { Binding, property, register, timeout } from "astal";
-import { App, Astal, Gdk, Gtk, Widget } from "astal/gtk3";
+import { Binding } from "astal";
+import { App, Astal, Gdk, Widget } from "astal/gtk3";
 import AstalHyprland from "gi://AstalHyprland";
 
 export const setupCustomTooltip = (self: any, text: string | Binding<string>) => {
@@ -47,118 +47,29 @@ export const setupCustomTooltip = (self: any, text: string | Binding<string>) =>
 export const setupChildClickthrough = (self: any) =>
     self.connect("size-allocate", () => self.get_window()?.set_child_input_shapes());
 
-export enum TransitionType {
-    FADE = "",
-    SLIDE_DOWN = "margin-top: -${height}px; margin-bottom: ${height}px;",
-    SLIDE_UP = "margin-top: ${height}px; margin-bottom: -${height}px;",
-    SLIDE_RIGHT = "margin-left: -${width}px; margin-right: ${width}px;",
-    SLIDE_LEFT = "margin-left: ${width}px; margin-right: -${width}px;",
-}
-
-@register()
-export class PopupWindow extends Widget.Window {
-    readonly transitionType: TransitionType;
-    readonly transitionInDuration: number;
-    readonly transitionOutDuration: number;
-    readonly transitionAmount: number;
-
-    readonly #content: Widget.Box;
-    #visible: boolean = false;
-
-    @property(Boolean)
-    get realVisible() {
-        return this.#visible;
-    }
-
-    set realVisible(v: boolean) {
-        if (v) this.show();
-        else this.hide();
-    }
-
-    constructor(
-        props: Widget.WindowProps & {
-            transitionType?: TransitionType;
-            transitionInDuration?: number;
-            transitionOutDuration?: number;
-            transitionAmount?: number;
-        }
-    ) {
-        const {
-            clickThrough,
-            child,
-            halign = Gtk.Align.START,
-            valign = Gtk.Align.START,
-            transitionType = TransitionType.FADE,
-            transitionInDuration = 300,
-            transitionOutDuration = 200,
-            transitionAmount = 0.2,
-            ...sProps
-        } = props;
-
-        sProps.visible = false;
-        sProps.application = App;
-        sProps.namespace = `caelestia-${props.name}`;
-        sProps.anchor =
-            Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.BOTTOM | Astal.WindowAnchor.RIGHT;
-        sProps.exclusivity = Astal.Exclusivity.IGNORE;
-        if (!sProps.keymode) sProps.keymode = Astal.Keymode.ON_DEMAND;
-        sProps.onKeyPressEvent = (self, event) => {
-            // Close window on escape
-            if (event.get_keyval()[1] === Gdk.KEY_Escape) self.hide();
-
-            return props.onKeyPressEvent?.(self, event);
-        };
-        super(sProps);
-
-        this.transitionType = transitionType;
-        this.transitionInDuration = transitionInDuration;
-        this.transitionOutDuration = transitionOutDuration;
-        this.transitionAmount = transitionAmount;
-
-        // Wrapper box for animations
-        this.#content = (
-            <box halign={halign} valign={valign} className={`${props.name}-wrapper`}>
-                {clickThrough ? <eventbox>{child}</eventbox> : child}
-            </box>
-        ) as Widget.Box;
-        this.#content.css = this.#getTransitionCss(false);
-        this.add(this.#content);
-
-        if (clickThrough) setupChildClickthrough(this);
-    }
-
-    #getTransitionCss(visible: boolean) {
-        return (
-            `transition-duration: ${visible ? this.transitionInDuration : this.transitionOutDuration}ms;` +
-            (visible
-                ? "opacity: 1;" + this.transitionType.replaceAll("${width}", "0").replaceAll("${height}", "0")
-                : "opacity: 0;" +
-                  this.transitionType
-                      .replaceAll("${width}", String(this.#content.get_preferred_width()[1] * this.transitionAmount))
-                      .replaceAll("${height}", String(this.#content.get_preferred_height()[1] * this.transitionAmount)))
-        );
-    }
-
-    show() {
-        this.#visible = true;
-        this.notify("real-visible");
-
-        super.show();
-        this.#content.toggleClassName("visible", true);
-        this.#content.css = this.#getTransitionCss(true);
-    }
-
-    hide() {
-        this.#visible = false;
-        this.notify("real-visible");
-
-        this.#content.toggleClassName("visible", false);
-        this.#content.css = this.#getTransitionCss(false);
-        timeout(this.transitionOutDuration, () => !this.#visible && super.hide());
-    }
-
-    toggle() {
-        if (this.#visible) this.hide();
-        else this.show();
-    }
-}
+const overrideProp = <T,>(
+    prop: T | Binding<T | undefined> | undefined,
+    override: (prop: T | undefined) => T | undefined
+) => prop && (prop instanceof Binding ? prop.as(override) : override(prop));
+
+export const convertPopupWindowProps = (props: Widget.WindowProps): Widget.WindowProps => ({
+    keymode: Astal.Keymode.ON_DEMAND,
+    exclusivity: Astal.Exclusivity.IGNORE,
+    ...props,
+    visible: false,
+    application: App,
+    namespace: overrideProp(props.name, n => `caelestia-${n}`),
+    className: overrideProp(props.className, c => `popup ${c}`),
+    onKeyPressEvent: (self, event) => {
+        // Close window on escape
+        if (event.get_keyval()[1] === Gdk.KEY_Escape) self.hide();
+
+        return props.onKeyPressEvent?.(self, event);
+    },
+    setup: self => {
+        self.connect("notify::visible", () => self.toggleClassName("visible", self.visible));
+        props.setup?.(self);
+    },
+});
+
+export const PopupWindow = (props: Widget.WindowProps) => <window {...convertPopupWindowProps(props)} />;
-- 
cgit v1.2.3-freya

