refactor(ags): start update types and use classes for cbox and popup
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
49f3a92ce3
commit
9c64b00243
30 changed files with 914 additions and 610 deletions
|
@ -2,7 +2,7 @@
|
|||
"env": {
|
||||
"es2021": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"overrides": [],
|
||||
"parserOptions": {
|
||||
|
@ -19,9 +19,6 @@
|
|||
"no-unreachable-loop": ["error", { "ignore": [
|
||||
"ForInStatement", "ForOfStatement"
|
||||
]}],
|
||||
"no-use-before-define": ["error", {
|
||||
"functions": false
|
||||
}],
|
||||
|
||||
|
||||
"block-scoped-var": ["error"],
|
||||
|
@ -79,6 +76,7 @@
|
|||
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
"@typescript-eslint/no-unsafe-declaration-merging": "off",
|
||||
|
||||
"@stylistic/array-bracket-newline": ["warn", "consistent"],
|
||||
"@stylistic/array-bracket-spacing": ["warn", "never"],
|
||||
|
|
129
modules/ags/config/global-types.d.ts
vendored
Normal file
129
modules/ags/config/global-types.d.ts
vendored
Normal file
|
@ -0,0 +1,129 @@
|
|||
import { Widget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||
|
||||
import { Widget as agsWidget } from 'types/widgets/widget';
|
||||
export type AgsWidget = agsWidget<unknown> & Widget;
|
||||
|
||||
// For ./ts/applauncher/main.ts
|
||||
import { Application } from 'types/service/applications.ts';
|
||||
import { CursorBoxProps } from 'ts/misc/cursorbox';
|
||||
export type AgsAppItem = AgsEventBox<Widget, { app: Application }
|
||||
& CursorBoxProps<Widget, unknown>>;
|
||||
|
||||
// For ./ts/bar/hovers/keyboard.ts
|
||||
export type Keyboard = {
|
||||
address: string;
|
||||
name: string;
|
||||
rules: string;
|
||||
model: string;
|
||||
layout: string;
|
||||
variant: string;
|
||||
options: string;
|
||||
active_keymap: string;
|
||||
main: boolean;
|
||||
};
|
||||
|
||||
// For ./ts/bar/items/workspaces.ts
|
||||
// TODO: improve type
|
||||
export type Workspace = AgsRevealer<unknown & Widget, unknown & { id: number }>;
|
||||
|
||||
// For ./ts/bar/fullscreen.ts
|
||||
export type DefaultProps = RevealerProps<CenterBoxGeneric>;
|
||||
|
||||
// For ./ts/media-player/gesture.ts
|
||||
export type Gesture = {
|
||||
attribute?: object
|
||||
setup?(self: OverlayGeneric): void
|
||||
props?: OverlayProps<unknown & Widget, unknown>
|
||||
};
|
||||
|
||||
// For ./ts/media-player/mpris.ts
|
||||
type PlayerDragProps = unknown & { dragging: boolean };
|
||||
export type PlayerDrag = AgsCenterBox<
|
||||
unknown & Widget, unknown & Widget, unknown & Widget, unknown & PlayerDragProps
|
||||
>;
|
||||
type Colors = {
|
||||
imageAccent: string;
|
||||
buttonAccent: string;
|
||||
buttonText: string;
|
||||
hoverAccent: string;
|
||||
};
|
||||
|
||||
// For ./ts/media-player
|
||||
export type PlayerBoxProps = {
|
||||
bgStyle: string,
|
||||
player: MprisPlayer,
|
||||
};
|
||||
export type PlayerBox = AgsCenterBox<
|
||||
unknown & Widget, unknown & Widget, unknown & Widget, PlayerBoxProps
|
||||
>;
|
||||
export type PlayerOverlay = AgsOverlay<AgsWidget, {
|
||||
players: Map;
|
||||
setup: boolean;
|
||||
dragging: boolean;
|
||||
includesWidget(playerW: PlayerBox): PlayerBox;
|
||||
showTopOnly(): void;
|
||||
moveToTop(player: PlayerBox): void;
|
||||
}>;
|
||||
export type PlayerButtonType = {
|
||||
player: MprisPlayer
|
||||
colors: Var<Colors>
|
||||
items: Array<[name: string, widget: AgsWidget]>
|
||||
onClick: string
|
||||
prop: string
|
||||
};
|
||||
|
||||
// For CursorBox
|
||||
import { CursorBox, CursorBoxProps } from 'ts/misc/cursorbox';
|
||||
export type CursorBox = CursorBox;
|
||||
export type CursorBoxProps = CursorBoxProps;
|
||||
|
||||
// For PopupWindow
|
||||
export type PopupChild = Binding<
|
||||
Var<Widget>,
|
||||
'is_listening' | 'is_polling' | 'value',
|
||||
Widget[]
|
||||
>;
|
||||
export type CloseType = 'none' | 'stay' | 'released' | 'clicked';
|
||||
export type PopupWindowProps<Child extends Widget, Attr = unknown> =
|
||||
WindowProps<Child> & {
|
||||
transition?: RevealerProps<Widget>['transition']
|
||||
transition_duration?: number
|
||||
bezier?: string
|
||||
on_open?(self: AgsWindow<Widget, unknown>): void
|
||||
on_close?(self: AgsWindow<Widget, unknown>): void
|
||||
blur?: boolean
|
||||
close_on_unfocus?: CloseType
|
||||
attribute?: Attr;
|
||||
content?: Widget
|
||||
anchor?: Array<'top' | 'bottom' | 'right' | 'left'>;
|
||||
};
|
||||
import { PopupWindow } from 'ts/misc/popup';
|
||||
export type PopupWindow = PopupWindow;
|
||||
|
||||
|
||||
// Generic widgets
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
export type BoxGeneric = AgsBox<unknown & Widget, unknown>;
|
||||
|
||||
import AgsCenterBox, { CenterBoxProps } from 'types/widgets/centerbox';
|
||||
export type CenterBoxGeneric = AgsCenterBox<
|
||||
unknown & Widget, unknown & Widget, unknown & Widget, unknown
|
||||
>;
|
||||
export type CenterBoxPropsGeneric = CenterBoxProps<
|
||||
unknown & Widget, unknown & Widget, unknown & Widget, unknown
|
||||
>;
|
||||
|
||||
import AgsEventBox from 'types/widgets/eventbox.ts';
|
||||
export type EventBoxGeneric = AgsEventBox<unknown & Widget, unknown>;
|
||||
|
||||
import AgsLabel from 'types/widgets/label.ts';
|
||||
export type LabelGeneric = AgsLabel<unknown>;
|
||||
|
||||
import AgsOverlay, { OverlayProps } from 'types/widgets/overlay.ts';
|
||||
export type OverlayGeneric = AgsOverlay<unknown & Widget, unknown>;
|
||||
|
||||
import AgsRevealer, { RevealerProps } from 'types/widgets/revealer.ts';
|
||||
export type RevealerGeneric = AgsRevealer<unknown & Widget, unknown>;
|
||||
|
||||
import AgsStack from 'types/widgets/stack.ts';
|
||||
export type StackGeneric = AgsStack<unknown & Widget, unknown>;
|
|
@ -27,7 +27,7 @@
|
|||
padding: 4.5px 9px;
|
||||
}
|
||||
|
||||
&.hover box {
|
||||
&:hover box {
|
||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||
background-color: rgba(238, 238, 238, 0.154);
|
||||
color: #f1f1f1;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
padding: 4.5px 9px;
|
||||
}
|
||||
|
||||
&.hover box {
|
||||
&:hover box {
|
||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||
background-color: rgba(238, 238, 238, 0.154);
|
||||
color: #f1f1f1;
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
border 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.toggle-on.hover, .toggle-off.hover {
|
||||
.toggle-on:hover, .toggle-off:hover {
|
||||
background-color: rgba(127, 132, 156, 0.4);
|
||||
transition: background-color 0.5s ease-in-out,
|
||||
border 0.5s ease-in-out;
|
||||
|
|
|
@ -15,7 +15,7 @@ const ON_CLICK_TRIGGERS = [
|
|||
];
|
||||
|
||||
// Types
|
||||
import AgsWindow from 'types/widgets/window';
|
||||
import { PopupWindow } from 'global-types';
|
||||
import { Subprocess } from 'types/@girs/gio-2.0/gio-2.0.cjs';
|
||||
type Layer = {
|
||||
address: string;
|
||||
|
@ -54,7 +54,7 @@ class Pointers extends Service {
|
|||
|
||||
#process = null as Subprocess | null;
|
||||
#lastLine = '';
|
||||
#pointers = [] as Array<String>;
|
||||
#pointers = [] as Array<string>;
|
||||
|
||||
get process() {
|
||||
return this.#process;
|
||||
|
@ -114,11 +114,11 @@ class Pointers extends Service {
|
|||
#initAppConnection() {
|
||||
App.connect('window-toggled', () => {
|
||||
const anyVisibleAndClosable =
|
||||
(Array.from(App.windows) as Array<[string, AgsWindow]>)
|
||||
(Array.from(App.windows) as Array<[string, PopupWindow]>)
|
||||
.some((w) => {
|
||||
const closable = w[1].attribute?.close_on_unfocus &&
|
||||
!(w[1].attribute.close_on_unfocus === 'none' ||
|
||||
w[1].attribute.close_on_unfocus === 'stay');
|
||||
const closable = w[1].close_on_unfocus &&
|
||||
!(w[1].close_on_unfocus === 'none' ||
|
||||
w[1].close_on_unfocus === 'stay');
|
||||
|
||||
return w[1].visible && closable;
|
||||
});
|
||||
|
@ -134,10 +134,10 @@ class Pointers extends Service {
|
|||
}
|
||||
|
||||
static detectClickedOutside(clickStage: string) {
|
||||
const toClose = (Array.from(App.windows) as Array<[string, AgsWindow]>)
|
||||
const toClose = (Array.from(App.windows) as Array<[string, PopupWindow]>)
|
||||
.some((w) => {
|
||||
const closable = (w[1].attribute?.close_on_unfocus &&
|
||||
w[1].attribute.close_on_unfocus === clickStage);
|
||||
const closable = (w[1].close_on_unfocus &&
|
||||
w[1].close_on_unfocus === clickStage);
|
||||
|
||||
return w[1].visible && closable;
|
||||
});
|
||||
|
@ -190,11 +190,11 @@ class Pointers extends Service {
|
|||
|
||||
const widgets = overlayLayer.filter((n) => {
|
||||
const window =
|
||||
(App.getWindow(n.namespace) as AgsWindow);
|
||||
(App.getWindow(n.namespace) as PopupWindow);
|
||||
|
||||
return window &&
|
||||
window.attribute?.close_on_unfocus &&
|
||||
window.attribute?.close_on_unfocus ===
|
||||
window.close_on_unfocus &&
|
||||
window.close_on_unfocus ===
|
||||
clickStage;
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Applications from 'resource:///com/github/Aylur/ags/service/applications.js';
|
||||
// FIXME: find cleaner way to import this
|
||||
// @ts-expect-error
|
||||
import { Fzf } from 'file:///home/matt/.nix/modules/ags/config/node_modules/fzf/dist/fzf.es.js';
|
||||
// @ts-expect-error find cleaner way to import this
|
||||
import { Fzf, FzfResultItem } from 'file:///home/matt/.nix/modules/ags/config/node_modules/fzf/dist/fzf.es.js';
|
||||
|
||||
import { Box, Entry, Icon, Label, ListBox, Revealer, Scrollable } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
|
||||
|
@ -10,14 +9,13 @@ import PopupWindow from '../misc/popup.ts';
|
|||
import AppItem from './app-item.ts';
|
||||
|
||||
// Types
|
||||
import { Application } from 'types/service/applications.ts';
|
||||
import { ListBoxRow } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||
import AgsEventBox from 'types/widgets/eventbox';
|
||||
import { Application } from 'types/service/applications.ts';
|
||||
import { AgsAppItem } from 'global-types';
|
||||
|
||||
|
||||
const Applauncher = (window_name = 'applauncher') => {
|
||||
let fzfResults: Array<any>;
|
||||
// @ts-expect-error
|
||||
let fzfResults: FzfResultItem<Application>[];
|
||||
const list = ListBox();
|
||||
|
||||
const setSort = (text: string) => {
|
||||
|
@ -31,25 +29,21 @@ const Applauncher = (window_name = 'applauncher') => {
|
|||
});
|
||||
|
||||
fzfResults = fzf.find(text);
|
||||
list.set_sort_func(
|
||||
(a: ListBoxRow, b: ListBoxRow) => {
|
||||
const row1 = (a.get_children()[0] as AgsEventBox)
|
||||
?.attribute.app.name;
|
||||
const row2 = (b.get_children()[0] as AgsEventBox)
|
||||
?.attribute.app.name;
|
||||
list.set_sort_func((a, b) => {
|
||||
const row1 = (a.get_children()[0] as AgsAppItem).attribute.app.name;
|
||||
const row2 = (b.get_children()[0] as AgsAppItem).attribute.app.name;
|
||||
|
||||
if (!row1 || !row2) {
|
||||
return 0;
|
||||
}
|
||||
if (!row1 || !row2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fzfResults.indexOf(row1) -
|
||||
return fzfResults.indexOf(row1) -
|
||||
fzfResults.indexOf(row1) || 0;
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const makeNewChildren = () => {
|
||||
const rows = list.get_children() as Array<ListBoxRow>;
|
||||
const rows = list.get_children() as ListBoxRow[];
|
||||
|
||||
rows.forEach((ch) => {
|
||||
ch.destroy();
|
||||
|
@ -94,14 +88,14 @@ const Applauncher = (window_name = 'applauncher') => {
|
|||
setSort(text);
|
||||
let visibleApps = 0;
|
||||
|
||||
const rows = list.get_children() as Array<ListBoxRow>;
|
||||
const rows = list.get_children() as ListBoxRow[];
|
||||
|
||||
rows.forEach((row) => {
|
||||
row.changed();
|
||||
|
||||
const item = (row.get_children()[0] as AgsEventBox);
|
||||
const item = (row.get_children()[0] as AgsAppItem);
|
||||
|
||||
if (item?.attribute.app) {
|
||||
if (item.attribute.app) {
|
||||
const isMatching = fzfResults.find((r) => {
|
||||
return r.item.name === item.attribute.app.name;
|
||||
});
|
||||
|
@ -162,5 +156,5 @@ const Applauncher = (window_name = 'applauncher') => {
|
|||
export default () => PopupWindow({
|
||||
name: 'applauncher',
|
||||
keymode: 'on-demand',
|
||||
child: Applauncher(),
|
||||
content: Applauncher(),
|
||||
});
|
||||
|
|
|
@ -5,8 +5,8 @@ import { Box, EventBox, Revealer, Window } from 'resource:///com/github/Aylur/ag
|
|||
|
||||
// Types
|
||||
import { Variable as Var } from 'types/variable';
|
||||
import AgsBox from 'types/widgets/box';
|
||||
import { RevealerProps } from 'types/widgets/revealer';
|
||||
import { BoxGeneric, DefaultProps } from 'global-types';
|
||||
|
||||
|
||||
const BarCloser = (variable: Var<boolean>) => Window({
|
||||
name: 'bar-closer',
|
||||
|
@ -30,7 +30,7 @@ const BarCloser = (variable: Var<boolean>) => Window({
|
|||
}),
|
||||
});
|
||||
|
||||
export default (props: RevealerProps) => {
|
||||
export default (props?: DefaultProps) => {
|
||||
const Revealed = Variable(true);
|
||||
const barCloser = BarCloser(Revealed);
|
||||
|
||||
|
@ -50,7 +50,7 @@ export default (props: RevealerProps) => {
|
|||
}
|
||||
};
|
||||
|
||||
const checkGlobalFsState = (_: AgsBox, fullscreen: boolean) => {
|
||||
const checkGlobalFsState = (_: BoxGeneric, fullscreen: boolean) => {
|
||||
Revealed.value = !fullscreen;
|
||||
};
|
||||
|
||||
|
|
|
@ -6,22 +6,11 @@ import HoverRevealer from './hover-revealer.ts';
|
|||
|
||||
const DEFAULT_KB = 'at-translated-set-2-keyboard';
|
||||
|
||||
import AgsLabel from 'types/widgets/label.ts';
|
||||
type Keyboard = {
|
||||
address: string;
|
||||
name: string;
|
||||
rules: string;
|
||||
model: string;
|
||||
layout: string;
|
||||
variant: string;
|
||||
options: string;
|
||||
active_keymap: string;
|
||||
main: boolean;
|
||||
};
|
||||
// Types
|
||||
import { Keyboard, LabelGeneric } from 'global-types';
|
||||
|
||||
|
||||
|
||||
const getKbdLayout = (self: AgsLabel, _: string, layout: string) => {
|
||||
const getKbdLayout = (self: LabelGeneric, _: string, layout: string) => {
|
||||
if (layout) {
|
||||
if (layout === 'error') {
|
||||
return;
|
||||
|
@ -35,7 +24,7 @@ const getKbdLayout = (self: AgsLabel, _: string, layout: string) => {
|
|||
// At launch, kb layout is undefined
|
||||
Hyprland.sendMessage('j/devices').then((obj) => {
|
||||
const keyboards = Array.from(JSON.parse(obj)
|
||||
.keyboards) as Array<Keyboard>;
|
||||
.keyboards) as Keyboard[];
|
||||
const kb = keyboards.find((v) => v.name === DEFAULT_KB);
|
||||
|
||||
if (kb) {
|
||||
|
|
|
@ -9,15 +9,15 @@ import Separator from '../../misc/separator.ts';
|
|||
const SPACING = 4;
|
||||
|
||||
// Types
|
||||
import AgsWindow from 'types/widgets/window.ts';
|
||||
import { PopupWindow } from 'global-types';
|
||||
|
||||
|
||||
export default () => CursorBox({
|
||||
class_name: 'toggle-off',
|
||||
|
||||
on_primary_click_release: (self) => {
|
||||
(App.getWindow('notification-center') as AgsWindow)
|
||||
?.attribute.set_x_pos(
|
||||
(App.getWindow('notification-center') as PopupWindow)
|
||||
.set_x_pos(
|
||||
self.get_allocation(),
|
||||
'right',
|
||||
);
|
||||
|
|
|
@ -14,9 +14,7 @@ import Separator from '../../misc/separator.ts';
|
|||
const SPACING = 4;
|
||||
|
||||
// Types
|
||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import AgsWindow from 'types/widgets/window.ts';
|
||||
import { PopupWindow } from 'global-types';
|
||||
|
||||
|
||||
export default () => {
|
||||
|
@ -36,8 +34,8 @@ export default () => {
|
|||
class_name: 'toggle-off',
|
||||
|
||||
on_primary_click_release: (self) => {
|
||||
(App.getWindow('quick-settings') as AgsWindow)
|
||||
?.attribute.set_x_pos(
|
||||
(App.getWindow('quick-settings') as PopupWindow)
|
||||
.set_x_pos(
|
||||
self.get_allocation(),
|
||||
'right',
|
||||
);
|
||||
|
@ -55,17 +53,15 @@ export default () => {
|
|||
|
||||
attribute: {
|
||||
hoverRevealers: hoverRevealers.map((rev) => {
|
||||
const box = rev.child as AgsBox;
|
||||
const box = rev.child;
|
||||
|
||||
return box.children[1];
|
||||
}),
|
||||
},
|
||||
on_hover_lost: (self) => {
|
||||
self.attribute.hoverRevealers.forEach(
|
||||
(rev: AgsRevealer) => {
|
||||
rev.reveal_child = false;
|
||||
},
|
||||
);
|
||||
self.attribute.hoverRevealers.forEach((rev) => {
|
||||
rev.reveal_child = false;
|
||||
});
|
||||
},
|
||||
|
||||
child: Box({
|
||||
|
|
|
@ -10,7 +10,6 @@ const SPACING = 12;
|
|||
|
||||
// Types
|
||||
import { TrayItem } from 'types/service/systemtray.ts';
|
||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
||||
|
||||
|
||||
const SysTrayItem = (item: TrayItem) => {
|
||||
|
@ -54,7 +53,7 @@ const SysTray = () => MenuBar({
|
|||
self.child = w;
|
||||
self.show_all();
|
||||
|
||||
(<AgsRevealer> w.child).reveal_child = true;
|
||||
w.child.reveal_child = true;
|
||||
}, 'added')
|
||||
|
||||
.hook(SystemTray, (_, id) => {
|
||||
|
|
|
@ -8,10 +8,13 @@ import CursorBox from '../../misc/cursorbox.ts';
|
|||
const URGENT_DURATION = 1000;
|
||||
|
||||
// Types
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
||||
import AgsOverlay from 'types/widgets/overlay.ts';
|
||||
import AgsEventBox from 'types/widgets/eventbox.ts';
|
||||
import {
|
||||
BoxGeneric,
|
||||
EventBoxGeneric,
|
||||
OverlayGeneric,
|
||||
RevealerGeneric,
|
||||
Workspace,
|
||||
} from 'global-types';
|
||||
|
||||
|
||||
const Workspace = ({ id }: { id: number }) => {
|
||||
|
@ -31,7 +34,10 @@ const Workspace = ({ id }: { id: number }) => {
|
|||
class_name: 'button',
|
||||
|
||||
setup: (self) => {
|
||||
const update = (_: AgsBox, addr: string | undefined) => {
|
||||
const update = (
|
||||
_: BoxGeneric,
|
||||
addr: string | undefined,
|
||||
) => {
|
||||
const workspace = Hyprland.getWorkspace(id);
|
||||
const occupied = workspace && workspace.windows > 0;
|
||||
|
||||
|
@ -79,13 +85,13 @@ export default () => {
|
|||
const L_PADDING = 16;
|
||||
const WS_WIDTH = 30;
|
||||
|
||||
const updateHighlight = (self: AgsBox) => {
|
||||
const updateHighlight = (self: BoxGeneric) => {
|
||||
const currentId = Hyprland.active.workspace.id;
|
||||
|
||||
const indicators = (((self.get_parent() as AgsOverlay)
|
||||
.child as AgsEventBox)
|
||||
.child as AgsBox)
|
||||
.children as Array<AgsRevealer>;
|
||||
const indicators = (((self.get_parent() as OverlayGeneric)
|
||||
.child as EventBoxGeneric)
|
||||
.child as BoxGeneric)
|
||||
.children as Workspace[];
|
||||
|
||||
const currentIndex = indicators
|
||||
.findIndex((w) => w.attribute.id === currentId);
|
||||
|
@ -111,26 +117,26 @@ export default () => {
|
|||
child: Box({
|
||||
class_name: 'workspaces',
|
||||
|
||||
attribute: { workspaces: [] },
|
||||
attribute: { workspaces: [] as Workspace[] },
|
||||
|
||||
setup: (self) => {
|
||||
const workspaces = (): Array<AgsRevealer> =>
|
||||
self.attribute.workspaces;
|
||||
|
||||
const refresh = () => {
|
||||
(self.children as Array<AgsRevealer>).forEach((rev) => {
|
||||
rev.reveal_child = false;
|
||||
});
|
||||
(self.children as RevealerGeneric[])
|
||||
.forEach((rev) => {
|
||||
rev.reveal_child = false;
|
||||
});
|
||||
|
||||
workspaces().forEach((ws) => {
|
||||
ws.reveal_child = true;
|
||||
});
|
||||
self.attribute.workspaces
|
||||
.forEach((ws) => {
|
||||
ws.reveal_child = true;
|
||||
});
|
||||
};
|
||||
|
||||
const updateWorkspaces = () => {
|
||||
Hyprland.workspaces.forEach((ws) => {
|
||||
const currentWs = (self.children as Array<AgsBox>)
|
||||
.find((ch) => ch.attribute.id === ws.id);
|
||||
const currentWs =
|
||||
(self.children as Workspace[])
|
||||
.find((ch) => ch.attribute.id === ws.id);
|
||||
|
||||
if (!currentWs && ws.id > 0) {
|
||||
self.add(Workspace({ id: ws.id }));
|
||||
|
@ -139,21 +145,22 @@ export default () => {
|
|||
self.show_all();
|
||||
|
||||
// Make sure the order is correct
|
||||
workspaces().forEach((workspace, i) => {
|
||||
(<AgsBox> workspace.get_parent()).reorder_child(
|
||||
workspace,
|
||||
i,
|
||||
);
|
||||
self.attribute.workspaces.forEach((workspace, i) => {
|
||||
(workspace.get_parent() as BoxGeneric)
|
||||
.reorder_child(workspace, i);
|
||||
});
|
||||
};
|
||||
|
||||
self.hook(Hyprland, () => {
|
||||
self.attribute.workspaces =
|
||||
(self.children as Array<AgsBox>).filter((ch) => {
|
||||
return Hyprland.workspaces.find((ws) => {
|
||||
return ws.id === ch.attribute.id;
|
||||
});
|
||||
}).sort((a, b) => a.attribute.id - b.attribute.id);
|
||||
(self.children as Workspace[])
|
||||
.filter((ch) => {
|
||||
return Hyprland.workspaces.find((ws) => {
|
||||
return ws.id === ch.attribute.id;
|
||||
});
|
||||
})
|
||||
.sort((a, b) =>
|
||||
a.attribute.id - b.attribute.id);
|
||||
|
||||
updateWorkspaces();
|
||||
refresh();
|
||||
|
|
|
@ -26,10 +26,7 @@ export default (
|
|||
.get_property('border-radius', Gtk.StateFlags.NORMAL);
|
||||
|
||||
widget.set_size_request(r, r);
|
||||
widget.connect('draw', (_, context) => {
|
||||
// FIXME: get proper Context type
|
||||
const cr = context as any;
|
||||
|
||||
widget.connect('draw', (_, cr) => {
|
||||
const c = widget.get_style_context()
|
||||
.get_property('background-color', Gtk.StateFlags.NORMAL);
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ export default () => PopupWindow({
|
|||
anchor: ['top'],
|
||||
margins: [TOP_MARGIN, 0, 0, 0],
|
||||
|
||||
child: Box({
|
||||
content: Box({
|
||||
class_name: 'date',
|
||||
vertical: true,
|
||||
|
||||
|
|
|
@ -10,20 +10,15 @@ const TRANSITION = `transition: margin ${ANIM_DURATION}ms ease,
|
|||
opacity ${ANIM_DURATION}ms ease;`;
|
||||
|
||||
// Types
|
||||
import AgsOverlay from 'types/widgets/overlay';
|
||||
import OverlayProps from 'types/widgets/overlay';
|
||||
import AgsBox from 'types/widgets/box';
|
||||
import AgsCenterBox from 'types/widgets/centerbox';
|
||||
import { Connectable } from 'types/widgets/widget';
|
||||
type Gesture = {
|
||||
attribute?: Object
|
||||
setup?(self: Connectable<AgsOverlay> & AgsOverlay): void
|
||||
props?: OverlayProps
|
||||
};
|
||||
import {
|
||||
CenterBoxGeneric,
|
||||
Gesture,
|
||||
OverlayGeneric,
|
||||
PlayerBox,
|
||||
} from 'global-types';
|
||||
|
||||
|
||||
export default ({
|
||||
attribute = {},
|
||||
setup = () => {/**/},
|
||||
...props
|
||||
}: Gesture) => {
|
||||
|
@ -39,10 +34,11 @@ export default ({
|
|||
const content = Overlay({
|
||||
...props,
|
||||
attribute: {
|
||||
...attribute,
|
||||
players: new Map(),
|
||||
setup: false,
|
||||
dragging: false,
|
||||
|
||||
includesWidget: (playerW: AgsOverlay) => {
|
||||
includesWidget: (playerW: OverlayGeneric) => {
|
||||
return content.overlays.find((w) => w === playerW);
|
||||
},
|
||||
|
||||
|
@ -50,7 +46,7 @@ export default ({
|
|||
over.visible = over === content.overlays.at(-1);
|
||||
}),
|
||||
|
||||
moveToTop: (player: AgsCenterBox) => {
|
||||
moveToTop: (player: CenterBoxGeneric) => {
|
||||
player.visible = true;
|
||||
content.reorder_overlay(player, -1);
|
||||
timeout(ANIM_DURATION, () => {
|
||||
|
@ -82,7 +78,7 @@ export default ({
|
|||
|
||||
self.attribute.dragging = true;
|
||||
let offset = gesture.get_offset()[1];
|
||||
const playerBox = self.overlays.at(-1) as AgsBox;
|
||||
const playerBox = self.overlays.at(-1) as PlayerBox;
|
||||
|
||||
if (!offset) {
|
||||
return;
|
||||
|
@ -118,7 +114,7 @@ export default ({
|
|||
self.attribute.dragging = false;
|
||||
const offset = gesture.get_offset()[1];
|
||||
|
||||
const playerBox = self.overlays.at(-1) as AgsBox;
|
||||
const playerBox = self.overlays.at(-1) as PlayerBox;
|
||||
|
||||
// If crosses threshold after letting go, slide away
|
||||
if (offset && Math.abs(offset) > MAX_OFFSET) {
|
||||
|
|
|
@ -31,17 +31,23 @@ const icons = {
|
|||
// Types
|
||||
import { MprisPlayer } from 'types/service/mpris.ts';
|
||||
import { Variable as Var } from 'types/variable';
|
||||
import AgsOverlay from 'types/widgets/overlay.ts';
|
||||
import AgsCenterBox, { CenterBoxProps } from 'types/widgets/centerbox.ts';
|
||||
import AgsLabel from 'types/widgets/label.ts';
|
||||
import AgsIcon from 'types/widgets/icon.ts';
|
||||
import AgsStack from 'types/widgets/stack.ts';
|
||||
|
||||
import {
|
||||
AgsWidget,
|
||||
CenterBoxPropsGeneric,
|
||||
Colors,
|
||||
PlayerBox,
|
||||
PlayerButtonType,
|
||||
PlayerDrag,
|
||||
PlayerOverlay,
|
||||
StackGeneric,
|
||||
} from 'global-types';
|
||||
|
||||
|
||||
export const CoverArt = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
props: CenterBoxProps,
|
||||
colors: Var<Colors>,
|
||||
props: CenterBoxPropsGeneric,
|
||||
) => CenterBox({
|
||||
...props,
|
||||
vertical: true,
|
||||
|
@ -51,7 +57,7 @@ export const CoverArt = (
|
|||
player,
|
||||
},
|
||||
|
||||
setup: (self) => {
|
||||
setup: (self: PlayerBox) => {
|
||||
// Give temp cover art
|
||||
readFileAsync(player.cover_path).catch(() => {
|
||||
if (!colors.value && !player.track_cover_url) {
|
||||
|
@ -93,7 +99,7 @@ export const CoverArt = (
|
|||
background-position: center;
|
||||
`;
|
||||
|
||||
if (!(self.get_parent() as AgsCenterBox)
|
||||
if (!(self.get_parent() as PlayerDrag)
|
||||
.attribute.dragging) {
|
||||
self.setCss(self.attribute.bgStyle);
|
||||
}
|
||||
|
@ -126,16 +132,18 @@ export const ArtistLabel = (player: MprisPlayer) => Label({
|
|||
});
|
||||
|
||||
|
||||
export const PlayerIcon = (player: MprisPlayer, overlay: AgsOverlay) => {
|
||||
export const PlayerIcon = (player: MprisPlayer, overlay: PlayerOverlay) => {
|
||||
const playerIcon = (
|
||||
p: MprisPlayer,
|
||||
widget?: AgsOverlay,
|
||||
over?: AgsOverlay,
|
||||
widget?: PlayerOverlay,
|
||||
playerBox?: PlayerBox,
|
||||
) => CursorBox({
|
||||
tooltip_text: p.identity || '',
|
||||
|
||||
on_primary_click_release: () => {
|
||||
widget?.attribute.moveToTop(over);
|
||||
if (widget && playerBox) {
|
||||
widget.attribute.moveToTop(playerBox);
|
||||
}
|
||||
},
|
||||
|
||||
child: Icon({
|
||||
|
@ -153,7 +161,7 @@ export const PlayerIcon = (player: MprisPlayer, overlay: AgsOverlay) => {
|
|||
});
|
||||
|
||||
return Box().hook(Mpris, (self) => {
|
||||
const grandPa = self.get_parent()?.get_parent();
|
||||
const grandPa = self.get_parent()?.get_parent() as AgsWidget;
|
||||
|
||||
if (!grandPa) {
|
||||
return;
|
||||
|
@ -162,13 +170,13 @@ export const PlayerIcon = (player: MprisPlayer, overlay: AgsOverlay) => {
|
|||
const thisIndex = overlay.overlays
|
||||
.indexOf(grandPa);
|
||||
|
||||
self.children = (overlay.overlays as Array<AgsOverlay>)
|
||||
.map((over, i) => {
|
||||
self.children = (overlay.overlays as PlayerBox[])
|
||||
.map((playerBox, i) => {
|
||||
self.children.push(Separator(2));
|
||||
|
||||
return i === thisIndex ?
|
||||
playerIcon(player) :
|
||||
playerIcon(over.attribute.player, overlay, over);
|
||||
playerIcon(playerBox.attribute.player, overlay, playerBox);
|
||||
})
|
||||
.reverse();
|
||||
});
|
||||
|
@ -179,7 +187,7 @@ const display = Gdk.Display.get_default();
|
|||
|
||||
export const PositionSlider = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
colors: Var<Colors>,
|
||||
) => Slider({
|
||||
class_name: 'position-slider',
|
||||
vpack: 'center',
|
||||
|
@ -258,13 +266,6 @@ export const PositionSlider = (
|
|||
},
|
||||
});
|
||||
|
||||
type PlayerButtonType = {
|
||||
player: MprisPlayer
|
||||
colors: Var<any>
|
||||
items: Array<[name: string, widget: AgsLabel | AgsIcon]>
|
||||
onClick: string
|
||||
prop: string
|
||||
};
|
||||
const PlayerButton = ({
|
||||
player,
|
||||
colors,
|
||||
|
@ -316,7 +317,7 @@ const PlayerButton = ({
|
|||
setup: (self) => {
|
||||
self
|
||||
.hook(player, () => {
|
||||
(self.child as AgsStack).shown = `${player[prop]}`;
|
||||
(self.child as StackGeneric).shown = `${player[prop]}`;
|
||||
})
|
||||
.hook(colors, () => {
|
||||
if (!Mpris.players.find((p) => player === p)) {
|
||||
|
@ -364,7 +365,7 @@ const PlayerButton = ({
|
|||
|
||||
export const ShuffleButton = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
colors: Var<Colors>,
|
||||
) => PlayerButton({
|
||||
player,
|
||||
colors,
|
||||
|
@ -384,7 +385,7 @@ export const ShuffleButton = (
|
|||
|
||||
export const LoopButton = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
colors: Var<Colors>,
|
||||
) => PlayerButton({
|
||||
player,
|
||||
colors,
|
||||
|
@ -408,7 +409,7 @@ export const LoopButton = (
|
|||
|
||||
export const PlayPauseButton = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
colors: Var<Colors>,
|
||||
) => PlayerButton({
|
||||
player,
|
||||
colors,
|
||||
|
@ -432,7 +433,7 @@ export const PlayPauseButton = (
|
|||
|
||||
export const PreviousButton = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
colors: Var<Colors>,
|
||||
) => PlayerButton({
|
||||
player,
|
||||
colors,
|
||||
|
@ -452,7 +453,7 @@ export const PreviousButton = (
|
|||
|
||||
export const NextButton = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
colors: Var<Colors>,
|
||||
) => PlayerButton({
|
||||
player,
|
||||
colors,
|
||||
|
|
|
@ -12,14 +12,13 @@ const SPACING = 8;
|
|||
|
||||
// Types
|
||||
import { MprisPlayer } from 'types/service/mpris.ts';
|
||||
import AgsOverlay from 'types/widgets/overlay.ts';
|
||||
import { Variable as Var } from 'types/variable';
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import { Colors, PlayerBox, PlayerOverlay } from 'global-types';
|
||||
|
||||
|
||||
const Top = (
|
||||
player: MprisPlayer,
|
||||
overlay: AgsOverlay,
|
||||
overlay: PlayerOverlay,
|
||||
) => Box({
|
||||
class_name: 'top',
|
||||
hpack: 'start',
|
||||
|
@ -32,7 +31,7 @@ const Top = (
|
|||
|
||||
const Center = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
colors: Var<Colors>,
|
||||
) => Box({
|
||||
class_name: 'center',
|
||||
|
||||
|
@ -65,7 +64,7 @@ const Center = (
|
|||
|
||||
const Bottom = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
colors: Var<Colors>,
|
||||
) => Box({
|
||||
class_name: 'bottom',
|
||||
|
||||
|
@ -88,8 +87,8 @@ const Bottom = (
|
|||
|
||||
const PlayerBox = (
|
||||
player: MprisPlayer,
|
||||
colors: Var<any>,
|
||||
overlay: AgsOverlay,
|
||||
colors: Var<Colors>,
|
||||
overlay: PlayerOverlay,
|
||||
) => {
|
||||
const widget = mpris.CoverArt(player, colors, {
|
||||
class_name: `player ${player.name}`,
|
||||
|
@ -107,14 +106,9 @@ const PlayerBox = (
|
|||
|
||||
export default () => {
|
||||
const content = PlayerGesture({
|
||||
attribute: {
|
||||
players: new Map(),
|
||||
setup: false,
|
||||
},
|
||||
|
||||
setup: (self) => {
|
||||
setup: (self: PlayerOverlay) => {
|
||||
self
|
||||
.hook(Mpris, (_: AgsOverlay, bus_name: string) => {
|
||||
.hook(Mpris, (_, bus_name) => {
|
||||
const players = self.attribute.players;
|
||||
|
||||
if (players.has(bus_name)) {
|
||||
|
@ -136,11 +130,16 @@ export default () => {
|
|||
}
|
||||
|
||||
// Get the one on top so we can move it up later
|
||||
const previousFirst = self.overlays.at(-1);
|
||||
const previousFirst = self.overlays.at(-1) as PlayerBox;
|
||||
|
||||
// Make the new player
|
||||
const player = Mpris.getPlayer(bus_name);
|
||||
const Colors = Variable(null);
|
||||
const colorsVar = Variable({
|
||||
imageAccent: '#6b4fa2',
|
||||
buttonAccent: '#ecdcff',
|
||||
buttonText: '#25005a',
|
||||
hoverAccent: '#d4baff',
|
||||
});
|
||||
|
||||
if (!player) {
|
||||
return;
|
||||
|
@ -148,19 +147,15 @@ export default () => {
|
|||
|
||||
players.set(
|
||||
bus_name,
|
||||
PlayerBox(
|
||||
player,
|
||||
Colors,
|
||||
content.get_children()[0] as AgsOverlay,
|
||||
),
|
||||
PlayerBox(player, colorsVar, self),
|
||||
);
|
||||
self.overlays = Array.from(players.values())
|
||||
.map((widget) => widget) as Array<AgsBox>;
|
||||
.map((widget) => widget) as PlayerBox[];
|
||||
|
||||
const includes = self.attribute
|
||||
.includesWidget(previousFirst);
|
||||
|
||||
// Select favorite player at startup
|
||||
// Select favorite player at startup
|
||||
const attrs = self.attribute;
|
||||
|
||||
if (!attrs.setup && players.has(FAVE_PLAYER)) {
|
||||
|
@ -168,28 +163,28 @@ export default () => {
|
|||
attrs.setup = true;
|
||||
}
|
||||
|
||||
// Move previousFirst on top again
|
||||
// Move previousFirst on top again
|
||||
else if (includes) {
|
||||
attrs.moveToTop(previousFirst);
|
||||
}
|
||||
}, 'player-added')
|
||||
|
||||
.hook(Mpris, (_: AgsOverlay, bus_name: string) => {
|
||||
.hook(Mpris, (_, bus_name) => {
|
||||
const players = self.attribute.players;
|
||||
|
||||
if (!bus_name || !players.has(bus_name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the one on top so we can move it up later
|
||||
const previousFirst = self.overlays.at(-1);
|
||||
// Get the one on top so we can move it up later
|
||||
const previousFirst = self.overlays.at(-1) as PlayerBox;
|
||||
|
||||
// Remake overlays without deleted one
|
||||
// Remake overlays without deleted one
|
||||
players.delete(bus_name);
|
||||
self.overlays = Array.from(players.values())
|
||||
.map((widget) => widget) as Array<AgsBox>;
|
||||
.map((widget) => widget) as PlayerBox[];
|
||||
|
||||
// Move previousFirst on top again
|
||||
// Move previousFirst on top again
|
||||
const includes = self.attribute
|
||||
.includesWidget(previousFirst);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Audio.connect('speaker-changed', () => {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Audio.speaker.stream.is_muted) {
|
||||
if (Audio.speaker.stream?.is_muted) {
|
||||
SpeakerIcon.value = speakerIcons[0];
|
||||
}
|
||||
else {
|
||||
|
@ -43,7 +43,7 @@ Audio.connect('microphone-changed', () => {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Audio.microphone.stream.is_muted) {
|
||||
if (Audio.microphone.stream?.is_muted) {
|
||||
MicIcon.value = micIcons[0];
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
|
||||
// Types
|
||||
import AgsWindow from 'types/widgets/window';
|
||||
import { PopupWindow } from 'global-types';
|
||||
|
||||
|
||||
export default () => {
|
||||
(Array.from(App.windows) as Array<[string, AgsWindow]>)
|
||||
.filter((w) => w[1].attribute?.close_on_unfocus &&
|
||||
w[1].attribute?.close_on_unfocus !== 'stay')
|
||||
(Array.from(App.windows) as Array<[string, PopupWindow]>)
|
||||
.filter((w) =>
|
||||
w[1].attribute.close_on_unfocus &&
|
||||
w[1].attribute.close_on_unfocus !== 'stay')
|
||||
.forEach((w) => {
|
||||
App.closeWindow(w[0]);
|
||||
});
|
||||
|
|
|
@ -1,93 +1,268 @@
|
|||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||
import { register } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import Gtk from 'gi://Gtk?version=3.0';
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
|
||||
import { EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
// Types
|
||||
import { BaseProps, Widget } from 'types/widgets/widget';
|
||||
type EventHandler<Self> = (self: Self, event: Gdk.Event) => boolean | unknown;
|
||||
|
||||
const { Gtk, Gdk } = imports.gi;
|
||||
const display = Gdk.Display.get_default();
|
||||
export type CursorBoxProps<
|
||||
Child extends Gtk.Widget,
|
||||
Attr = unknown,
|
||||
Self = CursorBox<Child, Attr>,
|
||||
> = BaseProps<Self, Gtk.EventBox.ConstructorProperties & {
|
||||
child?: Child
|
||||
on_hover?: EventHandler<Self>
|
||||
on_hover_lost?: EventHandler<Self>
|
||||
|
||||
import * as EventBoxTypes from 'types/widgets/eventbox';
|
||||
type CursorBox = EventBoxTypes.EventBoxProps & {
|
||||
on_primary_click_release?(self: EventBoxTypes.default): void;
|
||||
on_hover?(self: EventBoxTypes.default): void;
|
||||
on_hover_lost?(self: EventBoxTypes.default): void;
|
||||
};
|
||||
on_scroll_up?: EventHandler<Self>
|
||||
on_scroll_down?: EventHandler<Self>
|
||||
|
||||
on_primary_click?: EventHandler<Self>
|
||||
on_middle_click?: EventHandler<Self>
|
||||
on_secondary_click?: EventHandler<Self>
|
||||
|
||||
on_primary_click_release?: EventHandler<Self>
|
||||
on_middle_click_release?: EventHandler<Self>
|
||||
on_secondary_click_release?: EventHandler<Self>
|
||||
}, Attr>;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export interface CursorBox<Child, Attr> extends Widget<Attr> { }
|
||||
|
||||
|
||||
export default ({
|
||||
on_primary_click_release = () => {/**/},
|
||||
on_hover = () => {/**/},
|
||||
on_hover_lost = () => {/**/},
|
||||
attribute,
|
||||
...props
|
||||
}: CursorBox) => {
|
||||
export class CursorBox<Child extends Gtk.Widget, Attr> extends Gtk.EventBox {
|
||||
static {
|
||||
register(this, {
|
||||
properties: {
|
||||
'on-clicked': ['jsobject', 'rw'],
|
||||
|
||||
'on-hover': ['jsobject', 'rw'],
|
||||
'on-hover-lost': ['jsobject', 'rw'],
|
||||
|
||||
'on-scroll-up': ['jsobject', 'rw'],
|
||||
'on-scroll-down': ['jsobject', 'rw'],
|
||||
|
||||
'on-primary-click': ['jsobject', 'rw'],
|
||||
'on-secondary-click': ['jsobject', 'rw'],
|
||||
'on-middle-click': ['jsobject', 'rw'],
|
||||
|
||||
'on-primary-click-release': ['jsobject', 'rw'],
|
||||
'on-secondary-click-release': ['jsobject', 'rw'],
|
||||
'on-middle-click-release': ['jsobject', 'rw'],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
constructor(props: CursorBoxProps<Child, Attr> = {}) {
|
||||
super(props as Gtk.EventBox.ConstructorProperties);
|
||||
this.add_events(Gdk.EventMask.SCROLL_MASK);
|
||||
this.add_events(Gdk.EventMask.SMOOTH_SCROLL_MASK);
|
||||
|
||||
// Gesture stuff
|
||||
const gesture = Gtk.GestureLongPress.new(this);
|
||||
|
||||
this.hook(gesture, () => {
|
||||
const pointer = gesture.get_point(null);
|
||||
const x = pointer[1];
|
||||
const y = pointer[2];
|
||||
|
||||
if ((!x || !y) || (x === 0 && y === 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#canRun.value = !(
|
||||
x > this.get_allocated_width() ||
|
||||
y > this.get_allocated_height()
|
||||
);
|
||||
}, 'end');
|
||||
|
||||
this.connect('enter-notify-event', (_, event: Gdk.Event) => {
|
||||
this.set_state_flags(Gtk.StateFlags.PRELIGHT, false);
|
||||
|
||||
if (!this.#display) {
|
||||
return;
|
||||
}
|
||||
this.window.set_cursor(Gdk.Cursor.new_from_name(
|
||||
this.#display,
|
||||
this.#disabled.value ?
|
||||
'not-allowed' :
|
||||
'pointer',
|
||||
));
|
||||
|
||||
return this.on_hover?.(this, event);
|
||||
});
|
||||
|
||||
this.connect('leave-notify-event', (_, event: Gdk.Event) => {
|
||||
this.unset_state_flags(Gtk.StateFlags.PRELIGHT);
|
||||
|
||||
this.window.set_cursor(null);
|
||||
|
||||
return this.on_hover_lost?.(this, event);
|
||||
});
|
||||
|
||||
this.connect('button-press-event', (_, event: Gdk.Event) => {
|
||||
this.set_state_flags(Gtk.StateFlags.ACTIVE, false);
|
||||
if (this.#disabled.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.get_button()[1] === Gdk.BUTTON_PRIMARY) {
|
||||
return this.on_primary_click?.(this, event);
|
||||
}
|
||||
|
||||
else if (event.get_button()[1] === Gdk.BUTTON_MIDDLE) {
|
||||
return this.on_middle_click?.(this, event);
|
||||
}
|
||||
|
||||
else if (event.get_button()[1] === Gdk.BUTTON_SECONDARY) {
|
||||
return this.on_secondary_click?.(this, event);
|
||||
}
|
||||
});
|
||||
|
||||
this.connect('button-release-event', (_, event: Gdk.Event) => {
|
||||
this.unset_state_flags(Gtk.StateFlags.ACTIVE);
|
||||
if (this.#disabled.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.get_button()[1] === Gdk.BUTTON_PRIMARY) {
|
||||
// Every click, do a one shot connect to
|
||||
// CanRun to wait for location of click
|
||||
const id = this.#canRun.connect('changed', () => {
|
||||
if (this.#canRun.value) {
|
||||
this.on_primary_click_release?.(this, event);
|
||||
}
|
||||
|
||||
this.#canRun.disconnect(id);
|
||||
});
|
||||
}
|
||||
|
||||
else if (event.get_button()[1] === Gdk.BUTTON_MIDDLE) {
|
||||
return this.on_middle_click_release?.(this, event);
|
||||
}
|
||||
|
||||
else if (event.get_button()[1] === Gdk.BUTTON_SECONDARY) {
|
||||
return this.on_secondary_click_release?.(this, event);
|
||||
}
|
||||
});
|
||||
|
||||
this.connect('scroll-event', (_, event: Gdk.Event) => {
|
||||
if (event.get_scroll_deltas()[2] < 0) {
|
||||
return this.on_scroll_up?.(this, event);
|
||||
}
|
||||
|
||||
else if (event.get_scroll_deltas()[2] > 0) {
|
||||
return this.on_scroll_down?.(this, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#display = Gdk.Display.get_default();
|
||||
|
||||
// Make this variable to know if the function should
|
||||
// be executed depending on where the click is released
|
||||
const CanRun = Variable(true);
|
||||
const Disabled = Variable(false);
|
||||
#canRun = Variable(true);
|
||||
#disabled = Variable(false);
|
||||
|
||||
const cursorBox = EventBox({
|
||||
...props,
|
||||
get disabled() {
|
||||
return this.#disabled.value;
|
||||
}
|
||||
|
||||
attribute: {
|
||||
...attribute,
|
||||
disabled: Disabled,
|
||||
},
|
||||
set disabled(value: boolean) {
|
||||
this.#disabled.value = value;
|
||||
}
|
||||
|
||||
on_primary_click_release: (self) => {
|
||||
// Every click, do a one shot connect to
|
||||
// CanRun to wait for location of click
|
||||
const id = CanRun.connect('changed', () => {
|
||||
if (CanRun.value && !Disabled.value) {
|
||||
on_primary_click_release(self);
|
||||
}
|
||||
get child() {
|
||||
return super.child as Child;
|
||||
}
|
||||
|
||||
CanRun.disconnect(id);
|
||||
});
|
||||
},
|
||||
set child(child: Child) {
|
||||
super.child = child;
|
||||
}
|
||||
|
||||
// OnHover
|
||||
}).on('enter-notify-event', (self) => {
|
||||
on_hover(self);
|
||||
|
||||
if (!display) {
|
||||
return;
|
||||
}
|
||||
self.window.set_cursor(Gdk.Cursor.new_from_name(
|
||||
display,
|
||||
Disabled.value ?
|
||||
'not-allowed' :
|
||||
'pointer',
|
||||
));
|
||||
self.toggleClassName('hover', true);
|
||||
get on_hover() {
|
||||
return this._get('on-hover');
|
||||
}
|
||||
|
||||
// OnHoverLost
|
||||
}).on('leave-notify-event', (self) => {
|
||||
on_hover_lost(self);
|
||||
set on_hover(callback: EventHandler<this>) {
|
||||
this._set('on-hover', callback);
|
||||
}
|
||||
|
||||
self.window.set_cursor(null);
|
||||
self.toggleClassName('hover', false);
|
||||
get on_hover_lost() {
|
||||
return this._get('on-hover-lost');
|
||||
}
|
||||
|
||||
// Disabled class
|
||||
}).hook(Disabled, (self) => {
|
||||
self.toggleClassName('disabled', Disabled.value);
|
||||
});
|
||||
set on_hover_lost(callback: EventHandler<this>) {
|
||||
this._set('on-hover-lost', callback);
|
||||
}
|
||||
|
||||
const gesture = Gtk.GestureLongPress.new(cursorBox);
|
||||
get on_scroll_up() {
|
||||
return this._get('on-scroll-up');
|
||||
}
|
||||
|
||||
cursorBox.hook(gesture, () => {
|
||||
const pointer = gesture.get_point(null);
|
||||
const x = pointer[1];
|
||||
const y = pointer[2];
|
||||
set on_scroll_up(callback: EventHandler<this>) {
|
||||
this._set('on-scroll-up', callback);
|
||||
}
|
||||
|
||||
if ((!x || !y) || (x === 0 && y === 0)) {
|
||||
return;
|
||||
}
|
||||
get on_scroll_down() {
|
||||
return this._get('on-scroll-down');
|
||||
}
|
||||
|
||||
CanRun.value = !(
|
||||
x > cursorBox.get_allocated_width() ||
|
||||
y > cursorBox.get_allocated_height()
|
||||
);
|
||||
}, 'end');
|
||||
set on_scroll_down(callback: EventHandler<this>) {
|
||||
this._set('on-scroll-down', callback);
|
||||
}
|
||||
|
||||
return cursorBox;
|
||||
};
|
||||
get on_primary_click() {
|
||||
return this._get('on-primary-click');
|
||||
}
|
||||
|
||||
set on_primary_click(callback: EventHandler<this>) {
|
||||
this._set('on-primary-click', callback);
|
||||
}
|
||||
|
||||
get on_middle_click() {
|
||||
return this._get('on-middle-click');
|
||||
}
|
||||
|
||||
set on_middle_click(callback: EventHandler<this>) {
|
||||
this._set('on-middle-click', callback);
|
||||
}
|
||||
|
||||
get on_secondary_click() {
|
||||
return this._get('on-secondary-click');
|
||||
}
|
||||
|
||||
set on_secondary_click(callback: EventHandler<this>) {
|
||||
this._set('on-secondary-click', callback);
|
||||
}
|
||||
|
||||
get on_primary_click_release() {
|
||||
return this._get('on-primary-click-release');
|
||||
}
|
||||
|
||||
set on_primary_click_release(callback: EventHandler<this>) {
|
||||
this._set('on-primary-click-release', callback);
|
||||
}
|
||||
|
||||
get on_middle_click_release() {
|
||||
return this._get('on-middle-click-release');
|
||||
}
|
||||
|
||||
set on_middle_click_release(callback: EventHandler<this>) {
|
||||
this._set('on-middle-click-release', callback);
|
||||
}
|
||||
|
||||
get on_secondary_click_release() {
|
||||
return this._get('on-secondary-click-release');
|
||||
}
|
||||
|
||||
set on_secondary_click_release(callback: EventHandler<this>) {
|
||||
this._set('on-secondary-click-release', callback);
|
||||
}
|
||||
}
|
||||
|
||||
export default <Child extends Gtk.Widget, Attr>(
|
||||
props?: CursorBoxProps<Child, Attr>,
|
||||
) => new CursorBox(props ?? {});
|
||||
|
|
|
@ -2,381 +2,391 @@ import App from 'resource:///com/github/Aylur/ags/app.js';
|
|||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||
|
||||
import { Box, Overlay, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import { Box, Overlay, register } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
// Types
|
||||
import { Window } from 'resource:///com/github/Aylur/ags/widgets/window.js';
|
||||
import { Allocation, Widget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||
import { RevealerProps } from 'types/widgets/revealer';
|
||||
import { WindowProps } from 'types/widgets/window';
|
||||
import AgsWindow from 'types/widgets/window';
|
||||
import AgsBox from 'types/widgets/box';
|
||||
import AgsOverlay from 'types/widgets/overlay';
|
||||
import { Binding } from 'types/service';
|
||||
type PopupWindow = WindowProps & {
|
||||
transition?: RevealerProps['transition']
|
||||
transition_duration?: number
|
||||
bezier?: string
|
||||
on_open?(self: AgsWindow): void
|
||||
on_close?(self: AgsWindow): void
|
||||
blur?: boolean
|
||||
close_on_unfocus?: 'none' | 'stay' | 'released' | 'clicked'
|
||||
anchor?: Array<string>
|
||||
name: string
|
||||
};
|
||||
import { Variable as Var } from 'types/variable';
|
||||
|
||||
import {
|
||||
CloseType,
|
||||
BoxGeneric,
|
||||
OverlayGeneric,
|
||||
PopupChild,
|
||||
PopupWindowProps,
|
||||
} from 'global-types';
|
||||
|
||||
// FIXME: deal with overlay children?
|
||||
// TODO: make this a new class to be able to edit props
|
||||
// TODO: make props changes affect the widget
|
||||
|
||||
export default ({
|
||||
transition = 'slide_down',
|
||||
transition_duration = 800,
|
||||
bezier = 'cubic-bezier(0.68, -0.4, 0.32, 1.4)',
|
||||
on_open = () => {/**/},
|
||||
on_close = () => {/**/},
|
||||
|
||||
// Window props
|
||||
name,
|
||||
child = Box(),
|
||||
visible = false,
|
||||
anchor = [],
|
||||
layer = 'overlay',
|
||||
blur = false,
|
||||
close_on_unfocus = 'released',
|
||||
...props
|
||||
}: PopupWindow) => {
|
||||
const Child = Variable(child);
|
||||
const AntiClip = Variable(false);
|
||||
|
||||
const needsAnticlipping = bezier.match(/-[0-9]/) !== null &&
|
||||
transition !== 'crossfade';
|
||||
|
||||
const attribute = {
|
||||
set_x_pos: (
|
||||
alloc: Allocation,
|
||||
side = 'right' as 'left' | 'right',
|
||||
) => {
|
||||
const window = App.getWindow(name) as AgsWindow;
|
||||
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
const width = window.get_display()
|
||||
.get_monitor_at_point(alloc.x, alloc.y)
|
||||
.get_geometry().width;
|
||||
|
||||
window.margins = [
|
||||
window.margins[0],
|
||||
|
||||
side === 'right' ?
|
||||
(width - alloc.x - alloc.width) :
|
||||
window.margins[1],
|
||||
|
||||
window.margins[2],
|
||||
|
||||
side === 'right' ?
|
||||
window.margins[3] :
|
||||
(alloc.x - alloc.width),
|
||||
];
|
||||
},
|
||||
|
||||
get_child: () => Child.value,
|
||||
|
||||
set_child: (new_child: Widget) => {
|
||||
Child.value = new_child;
|
||||
App.getWindow(name)?.child.show_all();
|
||||
},
|
||||
|
||||
// This is for my custom pointers.ts
|
||||
close_on_unfocus,
|
||||
};
|
||||
|
||||
if (transition === 'none') {
|
||||
return Window({
|
||||
name,
|
||||
layer,
|
||||
anchor,
|
||||
visible: false,
|
||||
...props,
|
||||
attribute,
|
||||
child: Child.bind(),
|
||||
export class PopupWindow<
|
||||
Child extends Widget,
|
||||
Attr,
|
||||
> extends Window<Child, Attr> {
|
||||
static {
|
||||
register(this, {
|
||||
properties: {
|
||||
content: ['widget', 'rw'],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const window = Window({
|
||||
#content: Var<Widget>;
|
||||
#antiClip: Var<boolean>;
|
||||
#needsAnticlipping: boolean;
|
||||
#close_on_unfocus: CloseType;
|
||||
|
||||
get content() {
|
||||
return this.#content.value;
|
||||
}
|
||||
|
||||
set content(value: Widget) {
|
||||
this.#content.value = value;
|
||||
this.child.show_all();
|
||||
}
|
||||
|
||||
get close_on_unfocus() {
|
||||
return this.#close_on_unfocus;
|
||||
}
|
||||
|
||||
set close_on_unfocus(value: 'none' | 'stay' | 'released' | 'clicked') {
|
||||
this.#close_on_unfocus = value;
|
||||
}
|
||||
|
||||
constructor({
|
||||
transition = 'slide_down',
|
||||
transition_duration = 800,
|
||||
bezier = 'cubic-bezier(0.68, -0.4, 0.32, 1.4)',
|
||||
on_open = () => {/**/},
|
||||
on_close = () => {/**/},
|
||||
|
||||
// Window props
|
||||
name,
|
||||
layer,
|
||||
anchor,
|
||||
visible: false,
|
||||
...props,
|
||||
|
||||
visible = false,
|
||||
anchor = [],
|
||||
layer = 'overlay',
|
||||
attribute,
|
||||
content = Box(),
|
||||
blur = false,
|
||||
close_on_unfocus = 'released',
|
||||
...rest
|
||||
}: PopupWindowProps<Child, Attr>) {
|
||||
const needsAnticlipping = bezier.match(/-[0-9]/) !== null &&
|
||||
transition !== 'crossfade';
|
||||
const contentVar = Variable(Box() as Widget);
|
||||
const antiClip = Variable(false);
|
||||
|
||||
setup: () => {
|
||||
// Add way to make window open on startup
|
||||
const id = App.connect('config-parsed', () => {
|
||||
if (visible) {
|
||||
App.openWindow(`${name}`);
|
||||
if (content) {
|
||||
contentVar.value = content;
|
||||
}
|
||||
|
||||
super({
|
||||
...rest,
|
||||
name,
|
||||
visible,
|
||||
anchor,
|
||||
layer,
|
||||
attribute,
|
||||
setup: () => {
|
||||
// Add way to make window open on startup
|
||||
const id = App.connect('config-parsed', () => {
|
||||
if (visible) {
|
||||
App.openWindow(`${name}`);
|
||||
}
|
||||
App.disconnect(id);
|
||||
});
|
||||
|
||||
if (blur) {
|
||||
Hyprland.sendMessage('[[BATCH]] ' +
|
||||
`keyword layerrule ignorealpha[0.97],${name}; ` +
|
||||
`keyword layerrule blur,${name}`);
|
||||
}
|
||||
App.disconnect(id);
|
||||
});
|
||||
},
|
||||
child: Overlay({
|
||||
overlays: [Box({
|
||||
css: `
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
padding: 1px;
|
||||
`,
|
||||
setup: (self) => {
|
||||
// Make sure child doesn't
|
||||
// get bigger than it should
|
||||
const MAX_ANCHORS = 4;
|
||||
|
||||
if (blur) {
|
||||
Hyprland.sendMessage('[[BATCH]] ' +
|
||||
`keyword layerrule ignorealpha[0.97],${name}; ` +
|
||||
`keyword layerrule blur,${name}`);
|
||||
}
|
||||
},
|
||||
|
||||
child: Overlay({
|
||||
overlays: [Box({
|
||||
css: `
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
padding: 1px;
|
||||
`,
|
||||
setup: (self) => {
|
||||
// Make sure child doesn't
|
||||
// get bigger than it should
|
||||
const MAX_ANCHORS = 4;
|
||||
|
||||
self.hpack = 'center';
|
||||
self.vpack = 'center';
|
||||
|
||||
if (anchor.includes('top') &&
|
||||
anchor.includes('bottom')) {
|
||||
self.vpack = 'center';
|
||||
}
|
||||
else if (anchor.includes('top')) {
|
||||
self.vpack = 'start';
|
||||
}
|
||||
else if (anchor.includes('bottom')) {
|
||||
self.vpack = 'end';
|
||||
}
|
||||
|
||||
if (anchor.includes('left') &&
|
||||
anchor.includes('right')) {
|
||||
self.hpack = 'center';
|
||||
}
|
||||
else if (anchor.includes('left')) {
|
||||
self.hpack = 'start';
|
||||
}
|
||||
else if (anchor.includes('right')) {
|
||||
self.hpack = 'end';
|
||||
}
|
||||
|
||||
if (anchor.length === MAX_ANCHORS) {
|
||||
self.hpack = 'center';
|
||||
self.vpack = 'center';
|
||||
}
|
||||
|
||||
if (needsAnticlipping) {
|
||||
const reorder_child = (position: number) => {
|
||||
// If unanchored, we have another anticlip widget
|
||||
// so we can't change the order
|
||||
if (anchor.length !== 0) {
|
||||
for (const ch of self.children) {
|
||||
if (ch !== Child.value) {
|
||||
self.reorder_child(ch, position);
|
||||
if (anchor.includes('top') &&
|
||||
anchor.includes('bottom')) {
|
||||
self.vpack = 'center';
|
||||
}
|
||||
else if (anchor.includes('top')) {
|
||||
self.vpack = 'start';
|
||||
}
|
||||
else if (anchor.includes('bottom')) {
|
||||
self.vpack = 'end';
|
||||
}
|
||||
|
||||
return;
|
||||
if (anchor.includes('left') &&
|
||||
anchor.includes('right')) {
|
||||
self.hpack = 'center';
|
||||
}
|
||||
else if (anchor.includes('left')) {
|
||||
self.hpack = 'start';
|
||||
}
|
||||
else if (anchor.includes('right')) {
|
||||
self.hpack = 'end';
|
||||
}
|
||||
|
||||
if (anchor.length === MAX_ANCHORS) {
|
||||
self.hpack = 'center';
|
||||
self.vpack = 'center';
|
||||
}
|
||||
|
||||
if (needsAnticlipping) {
|
||||
const reorder_child = (position: number) => {
|
||||
// If unanchored, we have another anticlip widget
|
||||
// so we can't change the order
|
||||
if (anchor.length !== 0) {
|
||||
for (const ch of self.children) {
|
||||
if (ch !== contentVar.value) {
|
||||
self.reorder_child(ch, position);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
self.hook(AntiClip, () => {
|
||||
if (transition === 'slide_down') {
|
||||
self.vertical = true;
|
||||
reorder_child(-1);
|
||||
}
|
||||
else if (transition === 'slide_up') {
|
||||
self.vertical = true;
|
||||
reorder_child(0);
|
||||
}
|
||||
else if (transition === 'slide_right') {
|
||||
self.vertical = false;
|
||||
reorder_child(-1);
|
||||
}
|
||||
else if (transition === 'slide_left') {
|
||||
self.vertical = false;
|
||||
reorder_child(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
self.hook(antiClip, () => {
|
||||
if (transition === 'slide_down') {
|
||||
self.vertical = true;
|
||||
reorder_child(-1);
|
||||
}
|
||||
else if (transition === 'slide_up') {
|
||||
self.vertical = true;
|
||||
reorder_child(0);
|
||||
}
|
||||
else if (transition === 'slide_right') {
|
||||
self.vertical = false;
|
||||
reorder_child(-1);
|
||||
}
|
||||
else if (transition === 'slide_left') {
|
||||
self.vertical = false;
|
||||
reorder_child(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
children: Child.bind().transform((v) => {
|
||||
if (needsAnticlipping) {
|
||||
return [
|
||||
// Add an anticlip widget when unanchored
|
||||
// to not have a weird animation
|
||||
anchor.length === 0 && Box({
|
||||
css: `
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
padding: 2px;
|
||||
`,
|
||||
visible: AntiClip.bind(),
|
||||
}),
|
||||
v,
|
||||
Box({
|
||||
css: `
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
padding: 2px;
|
||||
`,
|
||||
visible: AntiClip.bind(),
|
||||
}),
|
||||
];
|
||||
}
|
||||
else {
|
||||
return [v];
|
||||
}
|
||||
}) as Binding<any, any, Widget[]>,
|
||||
})],
|
||||
children: contentVar.bind().transform((v) => {
|
||||
if (needsAnticlipping) {
|
||||
return [
|
||||
// Add an anticlip widget when unanchored
|
||||
// to not have a weird animation
|
||||
anchor.length === 0 && Box({
|
||||
css: `
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
padding: 2px;
|
||||
`,
|
||||
visible: antiClip.bind(),
|
||||
}),
|
||||
v,
|
||||
Box({
|
||||
css: `
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
padding: 2px;
|
||||
`,
|
||||
visible: antiClip.bind(),
|
||||
}),
|
||||
];
|
||||
}
|
||||
else {
|
||||
return [v];
|
||||
}
|
||||
}) as PopupChild,
|
||||
})],
|
||||
|
||||
setup: (self) => {
|
||||
self.on('get-child-position', (_, ch) => {
|
||||
const overlay = (Child.value as Widget)
|
||||
.get_parent() as AgsOverlay;
|
||||
setup: (self) => {
|
||||
self.on('get-child-position', (_, ch) => {
|
||||
const overlay = contentVar.value
|
||||
.get_parent() as OverlayGeneric;
|
||||
|
||||
if (ch === overlay) {
|
||||
const alloc = overlay.get_allocation();
|
||||
if (ch === overlay) {
|
||||
const alloc = overlay.get_allocation();
|
||||
|
||||
(self.child as AgsBox).css = `
|
||||
(self.child as BoxGeneric).css = `
|
||||
min-height: ${alloc.height}px;
|
||||
min-width: ${alloc.width}px;
|
||||
`;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
child: Box({
|
||||
css: `
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
padding: 1px;
|
||||
`,
|
||||
child: Box({
|
||||
css: `
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
padding: 1px;
|
||||
`,
|
||||
|
||||
setup: (self) => {
|
||||
let currentTimeout: number;
|
||||
setup: (self) => {
|
||||
let currentTimeout: number;
|
||||
|
||||
self.hook(App, (_, currentName, isOpen) => {
|
||||
if (currentName === name) {
|
||||
const overlay = (Child.value as Widget)
|
||||
.get_parent() as AgsOverlay;
|
||||
self.hook(App, (_, currentName, isOpen) => {
|
||||
if (currentName === name) {
|
||||
const overlay = contentVar.value
|
||||
.get_parent() as OverlayGeneric;
|
||||
|
||||
const alloc = overlay.get_allocation();
|
||||
const height = needsAnticlipping ?
|
||||
alloc.height + 100 + 10 :
|
||||
alloc.height + 10;
|
||||
const alloc = overlay.get_allocation();
|
||||
const height = antiClip ?
|
||||
alloc.height + 100 + 10 :
|
||||
alloc.height + 10;
|
||||
|
||||
if (needsAnticlipping) {
|
||||
AntiClip.value = true;
|
||||
if (needsAnticlipping) {
|
||||
antiClip.value = true;
|
||||
|
||||
const thisTimeout = timeout(
|
||||
transition_duration,
|
||||
() => {
|
||||
// Only run the timeout if there isn't a newer timeout
|
||||
if (thisTimeout === currentTimeout) {
|
||||
AntiClip.value = false;
|
||||
}
|
||||
},
|
||||
);
|
||||
const thisTimeout = timeout(
|
||||
transition_duration,
|
||||
() => {
|
||||
// Only run the timeout if there isn't a newer timeout
|
||||
if (thisTimeout ===
|
||||
currentTimeout) {
|
||||
antiClip.value = false;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
currentTimeout = thisTimeout;
|
||||
}
|
||||
currentTimeout = thisTimeout;
|
||||
}
|
||||
|
||||
let css = '';
|
||||
let css = '';
|
||||
|
||||
/* Margin: top | right | bottom | left */
|
||||
switch (transition) {
|
||||
case 'slide_down':
|
||||
css = `margin:
|
||||
-${height}px
|
||||
0
|
||||
${height}px
|
||||
0
|
||||
;`;
|
||||
break;
|
||||
/* Margin: top | right | bottom | left */
|
||||
switch (transition) {
|
||||
case 'slide_down':
|
||||
css = `margin:
|
||||
-${height}px
|
||||
0
|
||||
${height}px
|
||||
0
|
||||
;`;
|
||||
break;
|
||||
|
||||
case 'slide_up':
|
||||
css = `margin:
|
||||
${height}px
|
||||
0
|
||||
-${height}px
|
||||
0
|
||||
;`;
|
||||
break;
|
||||
case 'slide_up':
|
||||
css = `margin:
|
||||
${height}px
|
||||
0
|
||||
-${height}px
|
||||
0
|
||||
;`;
|
||||
break;
|
||||
|
||||
case 'slide_left':
|
||||
css = `margin:
|
||||
0
|
||||
-${height}px
|
||||
0
|
||||
${height}px
|
||||
;`;
|
||||
break;
|
||||
case 'slide_left':
|
||||
css = `margin:
|
||||
0
|
||||
-${height}px
|
||||
0
|
||||
${height}px
|
||||
;`;
|
||||
break;
|
||||
|
||||
case 'slide_right':
|
||||
css = `margin:
|
||||
0
|
||||
${height}px
|
||||
0
|
||||
-${height}px
|
||||
;`;
|
||||
break;
|
||||
case 'slide_right':
|
||||
css = `margin:
|
||||
0
|
||||
${height}px
|
||||
0
|
||||
-${height}px
|
||||
;`;
|
||||
break;
|
||||
|
||||
case 'crossfade':
|
||||
css = `
|
||||
opacity: 0;
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
`;
|
||||
break;
|
||||
case 'crossfade':
|
||||
css = `
|
||||
opacity: 0;
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
`;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
on_open(window);
|
||||
if (isOpen) {
|
||||
on_open(this);
|
||||
|
||||
// To get the animation, we need to set the css
|
||||
// to hide the widget and then timeout to have
|
||||
// the animation
|
||||
overlay.css = css;
|
||||
timeout(10, () => {
|
||||
overlay.css = `
|
||||
// To get the animation, we need to set the css
|
||||
// to hide the widget and then timeout to have
|
||||
// the animation
|
||||
overlay.css = css;
|
||||
timeout(10, () => {
|
||||
overlay.css = `
|
||||
transition: margin
|
||||
${transition_duration}ms
|
||||
${bezier},
|
||||
|
||||
opacity
|
||||
${transition_duration}ms
|
||||
${bezier};
|
||||
`;
|
||||
});
|
||||
}
|
||||
else {
|
||||
timeout(transition_duration, () => {
|
||||
on_close(this);
|
||||
});
|
||||
|
||||
overlay.css = `${css}
|
||||
transition: margin
|
||||
${transition_duration}ms ${bezier},
|
||||
|
||||
opacity
|
||||
${transition_duration}ms ${bezier};
|
||||
`;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
timeout(transition_duration, () => {
|
||||
on_close(window);
|
||||
});
|
||||
|
||||
overlay.css = `${css}
|
||||
transition: margin
|
||||
${transition_duration}ms ${bezier},
|
||||
|
||||
opacity
|
||||
${transition_duration}ms ${bezier};
|
||||
`;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
return window;
|
||||
};
|
||||
this.#content = contentVar;
|
||||
this.#close_on_unfocus = close_on_unfocus;
|
||||
this.#needsAnticlipping = needsAnticlipping;
|
||||
this.#antiClip = antiClip;
|
||||
}
|
||||
|
||||
set_x_pos(
|
||||
alloc: Allocation,
|
||||
side = 'right' as 'left' | 'right',
|
||||
) {
|
||||
const width = this.get_display()
|
||||
.get_monitor_at_point(alloc.x, alloc.y)
|
||||
.get_geometry().width;
|
||||
|
||||
this.margins = [
|
||||
this.margins[0],
|
||||
|
||||
side === 'right' ?
|
||||
(width - alloc.x - alloc.width) :
|
||||
this.margins[1],
|
||||
|
||||
this.margins[2],
|
||||
|
||||
side === 'right' ?
|
||||
this.margins[3] :
|
||||
(alloc.x - alloc.width),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export default <Child extends Widget, Attr>(
|
||||
props: PopupWindowProps<Child, Attr>,
|
||||
) => new PopupWindow(props);
|
||||
|
|
|
@ -13,13 +13,19 @@ import CursorBox from '../misc/cursorbox.ts';
|
|||
|
||||
// Types
|
||||
import { Notification as NotifObj } from 'types/service/notifications.ts';
|
||||
import AgsEventBox from 'types/widgets/eventbox.ts';
|
||||
import AgsEventBox from 'types/widgets/eventbox';
|
||||
import { Widget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||
import { Client } from 'types/service/hyprland.ts';
|
||||
type NotificationWidget = {
|
||||
notif: NotifObj
|
||||
slideIn?: 'Left' | 'Right'
|
||||
command?(): void
|
||||
};
|
||||
import {
|
||||
EventBoxGeneric,
|
||||
CursorBox as CBox,
|
||||
} from 'global-types';
|
||||
|
||||
|
||||
const setTime = (time: number) => {
|
||||
return GLib.DateTime
|
||||
|
@ -27,13 +33,17 @@ const setTime = (time: number) => {
|
|||
.format('%H:%M');
|
||||
};
|
||||
|
||||
const getDragState = (box: AgsEventBox) => (box.get_parent()?.get_parent()
|
||||
?.get_parent()?.get_parent()?.get_parent() as AgsEventBox)
|
||||
const getDragState = (box: EventBoxGeneric) => (box
|
||||
.get_parent()
|
||||
?.get_parent()
|
||||
?.get_parent()
|
||||
?.get_parent()
|
||||
?.get_parent() as AgsEventBox<Widget, { dragging: boolean }>)
|
||||
?.attribute.dragging;
|
||||
|
||||
|
||||
const NotificationIcon = (notif: NotifObj) => {
|
||||
let iconCmd = (box: AgsEventBox):void => {
|
||||
let iconCmd = (box: CBox):void => {
|
||||
console.log(box);
|
||||
};
|
||||
|
||||
|
@ -89,7 +99,9 @@ const NotificationIcon = (notif: NotifObj) => {
|
|||
|
||||
if (notif.image) {
|
||||
return CursorBox({
|
||||
on_primary_click_release: iconCmd,
|
||||
on_primary_click_release: (self) => {
|
||||
iconCmd(self);
|
||||
},
|
||||
|
||||
child: Box({
|
||||
vpack: 'start',
|
||||
|
@ -120,7 +132,9 @@ const NotificationIcon = (notif: NotifObj) => {
|
|||
|
||||
|
||||
return CursorBox({
|
||||
on_primary_click_release: iconCmd,
|
||||
on_primary_click_release: (self) => {
|
||||
iconCmd(self);
|
||||
},
|
||||
|
||||
child: Box({
|
||||
vpack: 'start',
|
||||
|
@ -175,7 +189,7 @@ export const Notification = ({
|
|||
});
|
||||
|
||||
// Add body to notif
|
||||
(notifWidget.child as AgsEventBox).add(Box({
|
||||
(notifWidget.child as EventBoxGeneric).add(Box({
|
||||
class_name: `notification ${notif.urgency}`,
|
||||
vexpand: false,
|
||||
|
||||
|
|
|
@ -21,5 +21,5 @@ export const NotifCenter = () => PopupWindow({
|
|||
transition: 'slide_up',
|
||||
monitor: 1,
|
||||
|
||||
child: NotifCenterWidget(),
|
||||
content: NotifCenterWidget(),
|
||||
});
|
||||
|
|
|
@ -8,11 +8,11 @@ import { Notification, HasNotifs } from './base.ts';
|
|||
import CursorBox from '../misc/cursorbox.ts';
|
||||
|
||||
// Types
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import { Notification as NotifObj } from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||
import { BoxGeneric } from 'global-types';
|
||||
|
||||
|
||||
const addNotif = (box: AgsBox, notif: NotifObj) => {
|
||||
const addNotif = (box: BoxGeneric, notif: NotifObj) => {
|
||||
if (notif) {
|
||||
const NewNotif = Notification({
|
||||
notif,
|
||||
|
@ -53,7 +53,7 @@ const NotificationList = () => Box({
|
|||
}, 'notified')
|
||||
|
||||
.hook(Notifications, (box, id) => {
|
||||
const notif = (box.children as Array<AgsBox>)
|
||||
const notif = (box.children as BoxGeneric[])
|
||||
.find((ch) => ch.attribute.id === id);
|
||||
|
||||
if (notif?.sensitive) {
|
||||
|
@ -73,7 +73,7 @@ const ClearButton = () => CursorBox({
|
|||
|
||||
setup: (self) => {
|
||||
self.hook(HasNotifs, () => {
|
||||
self.attribute.disabled?.setValue(!HasNotifs.value);
|
||||
self.disabled = !HasNotifs.value;
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -18,5 +18,5 @@ export const NotifCenter = () => PopupWindow({
|
|||
anchor: ['top', 'right'],
|
||||
margins: [TOP_MARGIN, 0, 0, 0],
|
||||
|
||||
child: NotifCenterWidget(),
|
||||
content: NotifCenterWidget(),
|
||||
});
|
||||
|
|
|
@ -61,5 +61,5 @@ export default () => PopupWindow({
|
|||
transition: 'slide_up',
|
||||
transition_duration,
|
||||
bezier: 'ease',
|
||||
child: OSDs(),
|
||||
content: OSDs(),
|
||||
});
|
||||
|
|
|
@ -44,5 +44,5 @@ const PowermenuWidget = () => CenterBox({
|
|||
|
||||
export default () => PopupWindow({
|
||||
name: 'powermenu',
|
||||
child: PowermenuWidget(),
|
||||
content: PowermenuWidget(),
|
||||
});
|
||||
|
|
|
@ -54,5 +54,5 @@ export default () => PopupWindow({
|
|||
name: 'quick-settings',
|
||||
anchor: ['top', 'right'],
|
||||
margins: [TOP_MARGIN, 0, 0, 0],
|
||||
child: QuickSettingsWidget(),
|
||||
content: QuickSettingsWidget(),
|
||||
});
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"baseUrl": ".",
|
||||
"typeRoots": ["./types"],
|
||||
"typeRoots": [
|
||||
"./types",
|
||||
"./global-types.d.ts"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue