popupwindow: switch to class

This commit is contained in:
2 * r + 2 * t 2025-01-16 16:23:30 +11:00
parent bb0a071034
commit 476fbe69d3
2 changed files with 48 additions and 38 deletions

View file

@ -8,7 +8,7 @@ import { Apps } from "../services/apps";
import Math, { type HistoryItem } from "../services/math"; import Math, { type HistoryItem } from "../services/math";
import { getAppCategoryIcon } from "../utils/icons"; import { getAppCategoryIcon } from "../utils/icons";
import { launch } from "../utils/system"; import { launch } from "../utils/system";
import { convertPopupWindowProps, setupCustomTooltip } from "../utils/widgets"; import { PopupWindow, setupCustomTooltip } from "../utils/widgets";
type Mode = "apps" | "files" | "math"; type Mode = "apps" | "files" | "math";
@ -346,7 +346,7 @@ const LauncherContent = ({
); );
@register() @register()
export default class Launcher extends Widget.Window { export default class Launcher extends PopupWindow {
readonly mode: Variable<Mode>; readonly mode: Variable<Mode>;
constructor() { constructor() {
@ -354,26 +354,24 @@ export default class Launcher extends Widget.Window {
const mode = Variable<Mode>("apps"); const mode = Variable<Mode>("apps");
const showResults = Variable.derive([bind(entry, "textLength"), mode], (t, m) => t > 0 || m !== "apps"); const showResults = Variable.derive([bind(entry, "textLength"), mode], (t, m) => t > 0 || m !== "apps");
super( super({
convertPopupWindowProps({ name: "launcher",
name: "launcher", anchor: Astal.WindowAnchor.TOP,
anchor: Astal.WindowAnchor.TOP, keymode: Astal.Keymode.EXCLUSIVE,
keymode: Astal.Keymode.EXCLUSIVE, onKeyPressEvent(_, event) {
onKeyPressEvent(_, event) { const keyval = event.get_keyval()[1];
const keyval = event.get_keyval()[1]; // Focus entry on typing
// Focus entry on typing if (!entry.isFocus && keyval >= 32 && keyval <= 126) {
if (!entry.isFocus && keyval >= 32 && keyval <= 126) { entry.text += String.fromCharCode(keyval);
entry.text += String.fromCharCode(keyval); entry.grab_focus();
entry.grab_focus(); entry.set_position(-1);
entry.set_position(-1);
// Consume event, if not consumed it will duplicate character in entry // Consume event, if not consumed it will duplicate character in entry
return true; return true;
} }
}, },
child: <LauncherContent mode={mode} showResults={showResults} entry={entry} />, child: <LauncherContent mode={mode} showResults={showResults} entry={entry} />,
}) });
);
this.mode = mode; this.mode = mode;

View file

@ -1,4 +1,4 @@
import { Binding } from "astal"; import { Binding, register } from "astal";
import { App, Astal, Gdk, Widget } from "astal/gtk3"; import { App, Astal, Gdk, Widget } from "astal/gtk3";
import AstalHyprland from "gi://AstalHyprland"; import AstalHyprland from "gi://AstalHyprland";
@ -52,21 +52,33 @@ const extendProp = <T,>(
override: (prop: T | undefined) => T | undefined override: (prop: T | undefined) => T | undefined
) => prop && (prop instanceof Binding ? prop.as(override) : override(prop)); ) => prop && (prop instanceof Binding ? prop.as(override) : override(prop));
export const convertPopupWindowProps = (props: Widget.WindowProps): Widget.WindowProps => ({ @register()
keymode: Astal.Keymode.ON_DEMAND, export class PopupWindow extends Widget.Window {
exclusivity: Astal.Exclusivity.IGNORE, constructor(props: Widget.WindowProps) {
...props, super({
visible: false, keymode: Astal.Keymode.ON_DEMAND,
application: App, exclusivity: Astal.Exclusivity.IGNORE,
name: props.monitor ? extendProp(props.name, n => (n ? n + props.monitor : undefined)) : props.name, ...props,
namespace: extendProp(props.name, n => `caelestia-${n}`), visible: false,
onKeyPressEvent: (self, event) => { application: App,
// Close window on escape name: props.monitor ? extendProp(props.name, n => (n ? n + props.monitor : undefined)) : props.name,
if (event.get_keyval()[1] === Gdk.KEY_Escape) self.hide(); namespace: extendProp(props.name, n => `caelestia-${n}`),
onKeyPressEvent: (self, event) => {
// Close window on escape
if (event.get_keyval()[1] === Gdk.KEY_Escape) self.hide();
return props.onKeyPressEvent?.(self, event); return props.onKeyPressEvent?.(self, event);
}, },
borderWidth: 20, // To allow shadow, cause if not it gets cut off borderWidth: 20, // To allow shadow, cause if not it gets cut off
}); });
}
export const PopupWindow = (props: Widget.WindowProps) => <window {...convertPopupWindowProps(props)} />; popup_at_widget(widget: JSX.Element, event: Gdk.Event) {
const { width, height } = widget.get_allocation();
const [_, x, y] = event.get_coords();
const { x: cx, y: cy } = AstalHyprland.get_default().get_cursor_position();
this.marginLeft = cx + ((width - this.get_preferred_width()[1]) / 2 - x);
this.marginTop = cy + (height - y);
this.show();
}
}