diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-01-15 15:22:22 +1100 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-01-15 15:22:22 +1100 |
| commit | dcd914dbae039560a4ad4db4edd0264845f7024b (patch) | |
| tree | 4a79a2758eef3f3f0cdd287b0c72c125652d6ada /utils/widgets.tsx | |
| parent | bar: media use identity (diff) | |
| download | caelestia-shell-dcd914dbae039560a4ad4db4edd0264845f7024b.tar.gz caelestia-shell-dcd914dbae039560a4ad4db4edd0264845f7024b.tar.bz2 caelestia-shell-dcd914dbae039560a4ad4db4edd0264845f7024b.zip | |
better popup window
Not manual using css, instead use a combination of css opacity and Hyprland animations
Diffstat (limited to 'utils/widgets.tsx')
| -rw-r--r-- | utils/widgets.tsx | 139 |
1 files changed, 25 insertions, 114 deletions
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;", -} +const overrideProp = <T,>( + prop: T | Binding<T | undefined> | undefined, + override: (prop: T | undefined) => T | undefined +) => prop && (prop instanceof Binding ? prop.as(override) : override(prop)); -@register() -export class PopupWindow extends Widget.Window { - readonly transitionType: TransitionType; - readonly transitionInDuration: number; - readonly transitionOutDuration: number; - readonly transitionAmount: number; +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(); - readonly #content: Widget.Box; - #visible: boolean = false; + return props.onKeyPressEvent?.(self, event); + }, + setup: self => { + self.connect("notify::visible", () => self.toggleClassName("visible", self.visible)); + props.setup?.(self); + }, +}); - @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(); - } -} +export const PopupWindow = (props: Widget.WindowProps) => <window {...convertPopupWindowProps(props)} />; |