ags(runner): make runner work by keyboard keys, focus entry on type + style improvements

This commit is contained in:
retrozinndev
2025-03-10 20:22:48 -03:00
parent 03813021a8
commit 902361d74e
4 changed files with 76 additions and 82 deletions
+1 -1
View File
@@ -153,7 +153,7 @@ scrollbar trough {
background: colors.$bg-translucent; background: colors.$bg-translucent;
border-top-left-radius: 8px; border-top-left-radius: 8px;
border-bottom-left-radius: 8px; border-bottom-left-radius: 8px;
padding: 0 2px; padding: 2px;
& slider { & slider {
@include mixins.reset-props; @include mixins.reset-props;
+4 -5
View File
@@ -32,15 +32,14 @@
} }
& list { & list {
& eventbox:focus > box, & > *:selected > .result,
& eventbox:hover > box, & > *:active > .result,
& listboxchild:selected eventbox > box, & > *:hover > .result {
& listboxchild:active eventbox > box {
background: colors.$bg-secondary; background: colors.$bg-secondary;
} }
} }
& list eventbox > .result { & list .result {
padding: 10px; padding: 10px;
background: colors.$bg-primary; background: colors.$bg-primary;
margin: 2px 0; margin: 2px 0;
+11 -21
View File
@@ -14,9 +14,8 @@ type ResultWidgetProps = {
}; };
@register({ GTypeName: "ResultWidget" }) @register({ GTypeName: "ResultWidget" })
class ResultWidget extends Widget.EventBox { class ResultWidget extends Widget.Box {
private readonly connections: Array<number>; public readonly onClick: (() => void);
public readonly onClick: ((() => void)|undefined);
public readonly icon: (string|undefined); public readonly icon: (string|undefined);
public readonly setup: ((() => void)|undefined); public readonly setup: ((() => void)|undefined);
public readonly closeOnClick: boolean = true; public readonly closeOnClick: boolean = true;
@@ -26,32 +25,25 @@ class ResultWidget extends Widget.EventBox {
super(); super();
if(props.icon) if(props.icon)
this.icon = props.icon; this.icon = props.icon;
if(props.onClick)
this.onClick = props.onClick;
if(props.setup) if(props.setup)
this.setup = props.setup; this.setup = props.setup;
if(props.closeOnClick !== undefined) if(props.closeOnClick !== undefined)
this.closeOnClick = props.closeOnClick; this.closeOnClick = props.closeOnClick;
this.connections = [ this.onClick = () => {
this.connect("click", () => { props.onClick && props.onClick();
this.onClick && this.onClick();
this.closeOnClick && closeRunner(); this.closeOnClick && closeRunner();
}), };
this.connect("destroy-event", () => this.connections.map((id: number) => this.set_class_name("result");
this.disconnect(id))) this.set_hexpand(true);
];
this.add(new Widget.Box({ this.add(new Widget.Icon({
className: "result",
hexpand: true,
children: [
new Widget.Icon({
visible: Boolean(props.icon), visible: Boolean(props.icon),
icon: props.icon || "image-missing" icon: props.icon || "image-missing"
} as Widget.IconProps), } as Widget.IconProps));
new Widget.Box({
this.add(new Widget.Box({
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
valign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER,
children: [ children: [
@@ -69,8 +61,6 @@ class ResultWidget extends Widget.EventBox {
label: props.description || "" label: props.description || ""
} as Widget.LabelProps) } as Widget.LabelProps)
] ]
} as Widget.BoxProps),
]
} as Widget.BoxProps)); } as Widget.BoxProps));
} }
} }
+42 -37
View File
@@ -1,4 +1,4 @@
import { Variable } from "astal"; import { AstalIO, timeout, Variable } from "astal";
import { Gdk, Gtk, Widget } from "astal/gtk3"; import { Gdk, Gtk, Widget } from "astal/gtk3";
import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow"; import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow";
import { updateApps } from "../scripts/apps"; import { updateApps } from "../scripts/apps";
@@ -8,6 +8,7 @@ import { handleApplications } from "../scripts/runner/apps";
import { ResultWidget, ResultWidgetProps } from "../widget/runner/ResultWidget"; import { ResultWidget, ResultWidgetProps } from "../widget/runner/ResultWidget";
export let runnerInstance: (Widget.Window|null) = null; export let runnerInstance: (Widget.Window|null) = null;
let onClickTimeout: (AstalIO.Time|undefined);
export function closeRunner(gtkWindow?: Widget.Window) { export function closeRunner(gtkWindow?: Widget.Window) {
const window = gtkWindow ? gtkWindow : runnerInstance; const window = gtkWindow ? gtkWindow : runnerInstance;
@@ -64,6 +65,13 @@ export namespace Runner {
className: "search", className: "search",
onChanged: (entry) => entryText.set(entry.text), onChanged: (entry) => entryText.set(entry.text),
placeholderText: props?.entryPlaceHolder || "", placeholderText: props?.entryPlaceHolder || "",
onActivate: (_) => {
const resultWidget = resultsList.get_selected_row()?.get_child();
if(resultWidget instanceof ResultWidget) {
resultWidget.onClick();
_.isFocus = false;
}
},
primary_icon_name: "system-search" primary_icon_name: "system-search"
} as Widget.EntryProps); } as Widget.EntryProps);
@@ -82,33 +90,6 @@ export namespace Runner {
: pluginResult) : pluginResult)
: null; : null;
[
new Widget.Box({
className: "not-found",
orientation: Gtk.Orientation.VERTICAL,
visible: entryText((text: string) => text.trim().length > 0),
expand: true,
children: [
new Widget.Icon({
icon: "software-update-urgent-symbolic"
} as Widget.IconProps),
new Widget.Label({
label: "Couldn't find any results with this search. Maybe try pressing F5 and searching again?",
truncate: false,
wrap: true
} as Widget.LabelProps)
]
} as Widget.BoxProps),
new Widget.Box({
className: "placeholder",
orientation: Gtk.Orientation.VERTICAL,
expand: true,
visible: Boolean(props?.resultsPlaceholder),
children: props?.resultsPlaceholder &&
props?.resultsPlaceholder()
} as Widget.BoxProps)
];
if(resultsList.get_children().length > 0) { if(resultsList.get_children().length > 0) {
resultsList.get_children().map((listItem: Gtk.Widget) => { resultsList.get_children().map((listItem: Gtk.Widget) => {
resultsList.remove(listItem); resultsList.remove(listItem);
@@ -116,10 +97,34 @@ export namespace Runner {
}); });
} }
if(results && results.length > 0) if(results && results.length > 0 && searchEntry.text.trim().length > 0) {
results.map((resultWidget: ResultWidget) => { results.map((resultWidget: ResultWidget) => {
resultsList.insert(resultWidget, -1); resultsList.insert(resultWidget, -1);
const listBoxChild = resultsList.get_row_at_index(resultsList.get_children().length - 1)!;
const resWidget = listBoxChild.get_child();
if(listBoxChild && resWidget instanceof ResultWidget) {
resultsList.connect("row-activated", (_, row: Gtk.ListBoxRow) => {
const rWidget = row.get_child()!;
if(rWidget instanceof ResultWidget) {
if(!onClickTimeout) {
rWidget.onClick();
// Timeout, so it doesn't fire the executable a hundred times :skull:
onClickTimeout = timeout(500, () => onClickTimeout = undefined);
}
}
}); });
}
});
} else {
if(props?.resultsPlaceholder) {
const widgets = props.resultsPlaceholder();
resultsList.get_children().map((res) =>
resultsList.remove(res));
widgets.map((widget) => resultsList.insert(widget, -1));
}
}
selectedResultIndex = 0; selectedResultIndex = 0;
resultsList.select_row(resultsList.get_row_at_index(selectedResultIndex)); resultsList.select_row(resultsList.get_row_at_index(selectedResultIndex));
@@ -133,17 +138,17 @@ export namespace Runner {
widthRequest: props?.width || 750, widthRequest: props?.width || 750,
heightRequest: props?.height || 450, heightRequest: props?.height || 450,
onKeyPressEvent: (_, event: Gdk.Event) => { onKeyPressEvent: (_, event: Gdk.Event) => {
const keyVal = event.get_keyval()[1];
if(!searchEntry.has_focus && keyVal !== Gdk.KEY_F5
&& keyVal !== Gdk.KEY_Down && keyVal !== Gdk.KEY_Up
&& keyVal !== Gdk.KEY_KP_Enter && keyVal !== Gdk.KEY_ISO_Enter) {
searchEntry.grab_focus_without_selecting();
}
event.get_keyval()[1] === Gdk.KEY_F5 && event.get_keyval()[1] === Gdk.KEY_F5 &&
updateApps(); updateApps();
if(event.get_keyval()[1] === Gdk.KEY_Down) {
resultsList.get_children().length > 0 &&
resultsList.select_row(resultsList.get_row_at_index(
(selectedResultIndex + 1) > (resultsList.get_children().length - 1) ?
0
: selectedResultIndex + 1
));
}
}, },
closeAction: (_) => closeRunner(_), closeAction: (_) => closeRunner(_),
onClose: () => subs.map(sub => sub()), onClose: () => subs.map(sub => sub()),