nixos-configs/modules/ags/config/ts/misc/sorted-list.ts
matt1432 e4384c5434
All checks were successful
Discord / discord commits (push) Has been skipped
fix(ags): reset scroll on opening app and clip
2024-05-20 23:10:04 -04:00

198 lines
5.5 KiB
TypeScript

const Hyprland = await Service.import('hyprland');
const { Box, Entry, Icon, Label, ListBox, Revealer, Scrollable } = Widget;
/* Types */
import { PopupWindow, PopupWindowProps } from '../misc/popup.ts';
import type { Widget as AgsWidget } from 'types/widgets/widget';
import { ListBoxRow } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
import { Monitor } from 'types/service/hyprland';
import { Binding } from 'types/service';
type MakeChild = ReturnType<typeof makeChild>;
type SortedListProps<Attr = unknown, Self = SortedList<Attr>> =
PopupWindowProps<MakeChild['child'], Attr, Self> & {
on_select: (row: ListBoxRow) => void;
init_rows: (list: MakeChild['list']) => void;
set_sort: (
text: string,
list: MakeChild['list'],
placeholder: MakeChild['placeholder'],
) => void;
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export interface SortedList<Attr> extends AgsWidget<Attr> { }
const centerCursor = async(): Promise<void> => {
let x: number;
let y: number;
const monitor = (JSON.parse(await Hyprland.messageAsync('j/monitors')) as Monitor[])
.find((m) => m.focused) as Monitor;
switch (monitor.transform) {
case 1:
x = monitor.x - (monitor.height / 2);
y = monitor.y - (monitor.width / 2);
break;
case 2:
x = monitor.x - (monitor.width / 2);
y = monitor.y - (monitor.height / 2);
break;
case 3:
x = monitor.x + (monitor.height / 2);
y = monitor.y + (monitor.width / 2);
break;
default:
x = monitor.x + (monitor.width / 2);
y = monitor.y + (monitor.height / 2);
break;
}
await Hyprland.messageAsync(`dispatch movecursor ${x} ${y}`);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const makeChild = (class_name: string | Binding<any, any, string>) => {
const list = ListBox();
const placeholder = Revealer({
child: Label({
label: " Couldn't find a match",
class_name: 'placeholder',
}),
});
const entry = Entry({
// Set some text so on-change works the first time
text: '-',
hexpand: true,
});
const scrollable = Scrollable({
hscroll: 'never',
vscroll: 'automatic',
child: Box({
vertical: true,
children: [list, placeholder],
}),
});
return {
list,
entry,
placeholder,
scrollable,
child: Box({
class_name,
vertical: true,
children: [
Box({
class_name: 'header',
children: [
Icon('preferences-system-search-symbolic'),
entry,
],
}),
scrollable,
],
}),
};
};
export class SortedList<
Attr,
> extends PopupWindow<MakeChild['child'], Attr> {
static {
Widget.register(this, {
properties: {
},
});
}
private _list: MakeChild['list'];
private _entry: MakeChild['entry'];
private _placeholder: MakeChild['placeholder'];
private _scrollable: MakeChild['scrollable'];
private _on_select: (row: ListBoxRow) => void;
private _init_rows: (list: MakeChild['list']) => void;
private _set_sort: (
text: string,
list: MakeChild['list'],
placeholder: MakeChild['placeholder'],
) => void;
set on_open(fun: (self: PopupWindow<MakeChild['child'], Attr>) => void) {
this._on_open = () => {
this._entry.text = '';
fun(this);
this._init_rows(this._list);
centerCursor();
const adjustScroll = this._scrollable.vadjustment;
this._scrollable.vadjustment.set_value(adjustScroll.lower);
this._entry.grab_focus();
};
}
constructor({
on_select,
init_rows,
set_sort,
on_open = () => { /**/ },
class_name = '',
keymode = 'on-demand',
...rest
}: SortedListProps<Attr, PopupWindow<MakeChild['child'], Attr>>) {
const makeChildResult = makeChild(class_name);
// PopupWindow
super({
child: makeChildResult.child,
keymode,
...rest,
});
this.on_open = on_open;
// SortedList
this._on_select = on_select;
this._init_rows = init_rows;
this._set_sort = set_sort;
this._placeholder = makeChildResult.placeholder;
this._scrollable = makeChildResult.scrollable;
this._list = makeChildResult.list;
this._list.on('row-activated', (_, row) => {
this._on_select(row);
});
this._entry = makeChildResult.entry;
this._entry.on_change = ({ text }) => {
if (text !== null || typeof text === 'string') {
this._set_sort(text, this._list, this._placeholder);
(this._list.get_children() as ListBoxRow[]).forEach((r) => {
r.changed();
});
}
};
// TODO: add on_accept where it just selects the first visible one
this._init_rows(this._list);
this._set_sort('', this._list, this._placeholder);
}
}
export default <Attr>(
props: SortedListProps<Attr, PopupWindow<MakeChild['child'], Attr>>,
) => new SortedList(props);