✨ ags: new window management system, adjustments, use adwaita sans
This commit is contained in:
@@ -3,6 +3,7 @@ import { PopupWindow, PopupWindowProps } from "./PopupWindow";
|
||||
import { Astal, Gtk, Widget } from "astal/gtk3";
|
||||
import { Separator } from "./Separator";
|
||||
import { tr } from "../i18n/intl";
|
||||
import { Windows } from "../windows";
|
||||
|
||||
export type AskPopupProps = {
|
||||
title?: string | Binding<string | undefined>;
|
||||
@@ -17,15 +18,16 @@ export type AskPopupProps = {
|
||||
* A Popup Widget that asks yes or no to a certain question.
|
||||
* Runs onAccept() when user accepts or else onDecline() when
|
||||
* user doesn't accept or closes window.
|
||||
* This window isn't registered in this shell windowing stuff.
|
||||
*/
|
||||
export function AskPopup(props: AskPopupProps) {
|
||||
export function AskPopup(props: AskPopupProps): Gtk.Window {
|
||||
const buttons = [
|
||||
new Widget.Button({
|
||||
className: "cancel",
|
||||
hexpand: true,
|
||||
label: props.cancelText || tr("ask_popup.options.cancel") || "Cancel",
|
||||
onClick: (_) => {
|
||||
window.destroy();
|
||||
window.close();
|
||||
props.onCancel && props.onCancel();
|
||||
}
|
||||
} as Widget.ButtonProps),
|
||||
@@ -34,15 +36,14 @@ export function AskPopup(props: AskPopupProps) {
|
||||
hexpand: true,
|
||||
label: props.acceptText || tr("ask_popup.options.accept") || "Ok",
|
||||
onClick: (_) => {
|
||||
window.destroy();
|
||||
window.close();
|
||||
props.onAccept && props.onAccept();
|
||||
}
|
||||
} as Widget.ButtonProps)
|
||||
];
|
||||
|
||||
const window = PopupWindow({
|
||||
const window = Windows.createWindowForFocusedMonitor(PopupWindow({
|
||||
namespace: "ask-popup",
|
||||
visible: true,
|
||||
className: "ask-popup",
|
||||
exclusivity: Astal.Exclusivity.IGNORE,
|
||||
widthRequest: 350,
|
||||
@@ -80,5 +81,7 @@ export function AskPopup(props: AskPopupProps) {
|
||||
} as Widget.BoxProps)
|
||||
]
|
||||
} as Widget.BoxProps)
|
||||
} as PopupWindowProps);
|
||||
} as PopupWindowProps))();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Binding } from "astal";
|
||||
import { Astal, Gdk, Gtk, Widget } from "astal/gtk3";
|
||||
|
||||
|
||||
const { TOP, BOTTOM, LEFT, RIGHT }: typeof Astal.WindowAnchor = Astal.WindowAnchor;
|
||||
const { TOP, BOTTOM, LEFT, RIGHT } = Astal.WindowAnchor;
|
||||
|
||||
export type PopupWindowProps = Pick<Widget.WindowProps,
|
||||
"namespace"
|
||||
@@ -16,27 +16,26 @@ export type PopupWindowProps = Pick<Widget.WindowProps,
|
||||
| "layer"
|
||||
| "widthRequest"
|
||||
| "heightRequest"
|
||||
| "child"
|
||||
| "monitor"
|
||||
| "setup"
|
||||
| "exclusivity"> & {
|
||||
child?: (Gtk.Widget | Binding<Gtk.Widget | undefined>);
|
||||
children?: (Array<Gtk.Widget | Binding<Gtk.Widget | undefined>>);
|
||||
marginTop?: number;
|
||||
marginLeft?: number;
|
||||
marginBottom?: number;
|
||||
marginRight?: number;
|
||||
onKeyPressEvent?: (self: Widget.Window, event: Gdk.Event) => void;
|
||||
/** Do something else instead of hiding window on close action(clicking outside conent / pressing Escape)
|
||||
/** Do something else instead of closing window on close action(clicking outside conent/pressing Escape)
|
||||
* Observation: onClose() function will still be ran after close action if defined.
|
||||
*/
|
||||
closeAction?: (self: Widget.Window) => void;
|
||||
onClose?: (self: Widget.Window) => void;
|
||||
};
|
||||
|
||||
export function PopupWindow(props: PopupWindowProps): Widget.Window {
|
||||
export const PopupWindow = (props: PopupWindowProps): Widget.Window => {
|
||||
if(!props.closeAction)
|
||||
props.closeAction = (window) => {
|
||||
window.hide();
|
||||
};
|
||||
props.closeAction = (window) => window.close();
|
||||
|
||||
return new Widget.Window({
|
||||
namespace: props?.namespace || "popup-window",
|
||||
@@ -47,9 +46,8 @@ export function PopupWindow(props: PopupWindowProps): Widget.Window {
|
||||
keymode: Astal.Keymode.EXCLUSIVE,
|
||||
layer: props?.layer || Astal.Layer.OVERLAY,
|
||||
focusOnMap: true,
|
||||
visible: props?.visible,
|
||||
monitor: props?.monitor || 0,
|
||||
setup: props.setup,
|
||||
monitor: props.monitor || 0,
|
||||
onButtonPressEvent: (_, event: Gdk.Event) => {
|
||||
const [, posX, posY] = event.get_coords();
|
||||
const childAllocation = _.get_child()!.get_allocation();
|
||||
@@ -88,7 +86,8 @@ export function PopupWindow(props: PopupWindowProps): Widget.Window {
|
||||
widthRequest: props.widthRequest,
|
||||
heightRequest: props.heightRequest,
|
||||
onButtonPressEvent: () => true,
|
||||
child: props.child
|
||||
...(props.child ? { child: props.child } : {}),
|
||||
...(props.children ? { children: props.children } : {})
|
||||
} as Widget.BoxProps)
|
||||
} as Widget.WindowProps);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Windows } from "../../windows";
|
||||
|
||||
export function Apps(): Gtk.Widget {
|
||||
return new Widget.EventBox({
|
||||
onClickRelease: () => Windows.getWindow("apps-window")?.show(),
|
||||
onClickRelease: () => Windows.open("apps-window"),
|
||||
className: "apps",
|
||||
child: new Widget.Box({
|
||||
child: new Widget.Icon({
|
||||
|
||||
@@ -2,14 +2,13 @@ import { Gtk, Widget } from "astal/gtk3";
|
||||
import { getDateTime } from "../../scripts/time";
|
||||
import { bind, GLib } from "astal";
|
||||
import { Windows } from "../../windows";
|
||||
import { CenterWindow } from "../../window/CenterWindow";
|
||||
|
||||
export function Clock(): Gtk.Widget {
|
||||
return new Widget.Box({
|
||||
className: bind(CenterWindow, "visible").as((visible: boolean) =>
|
||||
visible ? "clock open" : "clock"),
|
||||
className: bind(Windows, "openWindows").as((openWins) =>
|
||||
Object.hasOwn(openWins, "center-window") ? "open clock" : "clock"),
|
||||
child: new Widget.Button({
|
||||
onClick: () => Windows.toggle(CenterWindow),
|
||||
onClick: () => Windows.toggle("center-window"),
|
||||
label: getDateTime().as((dateTime: GLib.DateTime) => {
|
||||
return dateTime.format("%A %d, %H:%M")
|
||||
})
|
||||
|
||||
@@ -71,9 +71,8 @@ export function Media(): Gtk.Widget {
|
||||
|
||||
const mediaWidget = new Widget.EventBox({
|
||||
className: "media-eventbox",
|
||||
visible: bind(mpris, "players").as((players: Array<AstalMpris.Player>) => {
|
||||
return players[0] && players[0].get_available() || CenterWindow.is_visible();
|
||||
}),
|
||||
visible: bind(mpris, "players").as((players: Array<AstalMpris.Player>) =>
|
||||
players[0] && players[0].get_available()),
|
||||
onDestroy: (_) => {
|
||||
hoverConnectionId !== undefined &&
|
||||
_.disconnect(hoverConnectionId);
|
||||
@@ -81,7 +80,7 @@ export function Media(): Gtk.Widget {
|
||||
hoverLostConnectionId !== undefined &&
|
||||
_.disconnect(hoverLostConnectionId);
|
||||
},
|
||||
onClick: () => Windows.toggle(CenterWindow),
|
||||
onClick: () => Windows.toggle("center-window"),
|
||||
child: new Widget.Box({
|
||||
className: "media",
|
||||
children: [
|
||||
|
||||
@@ -5,16 +5,15 @@ import AstalWp from "gi://AstalWp";
|
||||
import { bind, Variable } from "astal";
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
import { Wireplumber } from "../../scripts/volume";
|
||||
import { ControlCenter } from "../../window/ControlCenter";
|
||||
import { Notifications } from "../../scripts/notifications";
|
||||
import { Windows } from "../../windows";
|
||||
|
||||
|
||||
export function Status(): Gtk.Widget {
|
||||
return new Widget.EventBox({
|
||||
className: bind(ControlCenter, "visible").as((visible: boolean) =>
|
||||
visible ? "status open" : "status"),
|
||||
onClick: () => Windows.toggle(ControlCenter!),
|
||||
className: bind(Windows, "openWindows").as((openWins) =>
|
||||
Object.hasOwn(openWins, "control-center") ? "open status" : "status"),
|
||||
onClick: () => Windows.toggle("control-center"),
|
||||
child: new Widget.Box({
|
||||
children: [
|
||||
volumeStatusSlider({
|
||||
@@ -63,6 +62,7 @@ function volumeStatusSlider(props: { className?: string, endpoint: AstalWp.Endpo
|
||||
|
||||
revealer.add(new Widget.Slider({
|
||||
className: "slider",
|
||||
setup: (slider) => slider.set_value(Math.floor(props.endpoint.get_volume() * 100)),
|
||||
onDragged: (slider) => props.endpoint.set_volume(slider.value / 100),
|
||||
value: bind(props.endpoint, "volume").as((volume) =>
|
||||
Math.floor(volume * 100)),
|
||||
|
||||
@@ -2,9 +2,10 @@ import { AstalIO, bind, Binding, execAsync, GLib, timeout } from "astal";
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
import AstalMpris from "gi://AstalMpris";
|
||||
|
||||
let dragTimer: (AstalIO.Time|undefined);
|
||||
|
||||
export function BigMedia(): Gtk.Widget {
|
||||
let dragTimer: (AstalIO.Time|undefined);
|
||||
|
||||
return new Widget.Box({
|
||||
className: "big-media",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
|
||||
@@ -4,7 +4,7 @@ import { HistoryNotification, Notifications } from "../../scripts/notifications"
|
||||
import { NotificationWidget } from "../Notification";
|
||||
|
||||
|
||||
export const NotifHistory: Gtk.Widget = new Widget.Box({
|
||||
export const NotifHistory = () => new Widget.Box({
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
className: "history",
|
||||
visible: bind(Notifications.getDefault(), "history").as(history => history.length > 0),
|
||||
|
||||
@@ -2,20 +2,29 @@ import { timeout, Variable } from "astal";
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
import { Page } from "./pages/Page";
|
||||
|
||||
const currentPage = new Variable<Page|undefined>(undefined);
|
||||
const currentPage = new Variable<Page | undefined>(undefined);
|
||||
let pagesInstance: (Widget.Revealer | undefined);
|
||||
|
||||
export const PagesWidget: Widget.Revealer = new Widget.Revealer({
|
||||
revealChild: false,
|
||||
className: "pages",
|
||||
transitionType: Gtk.RevealerTransitionType.SLIDE_DOWN,
|
||||
transitionDuration: 360,
|
||||
child: currentPage((page: (Page|undefined)) =>
|
||||
!page ? new Widget.Box() : page.getPage())
|
||||
} as Widget.RevealerProps);
|
||||
export const PagesWidget = () => {
|
||||
const revealer = new Widget.Revealer({
|
||||
revealChild: false,
|
||||
className: "pages",
|
||||
transitionType: Gtk.RevealerTransitionType.SLIDE_DOWN,
|
||||
transitionDuration: 360,
|
||||
child: currentPage((page: (Page|undefined)) =>
|
||||
!page ? new Widget.Box() : page.getPage())
|
||||
} as Widget.RevealerProps);
|
||||
|
||||
pagesInstance = revealer;
|
||||
|
||||
return revealer;
|
||||
}
|
||||
|
||||
export function showPages(page: Page): void {
|
||||
if(!pagesInstance) return;
|
||||
|
||||
currentPage.set(page);
|
||||
PagesWidget.set_reveal_child(true);
|
||||
pagesInstance.set_reveal_child(true);
|
||||
page.props.onOpen && page.props.onOpen();
|
||||
}
|
||||
|
||||
@@ -24,7 +33,9 @@ export function getPage(): (Page|undefined) {
|
||||
}
|
||||
|
||||
export function togglePage(page: Page): void {
|
||||
if(!PagesWidget.revealChild) {
|
||||
if(!pagesInstance) return;
|
||||
|
||||
if(!pagesInstance.revealChild) {
|
||||
showPages(page);
|
||||
return;
|
||||
}
|
||||
@@ -33,10 +44,12 @@ export function togglePage(page: Page): void {
|
||||
}
|
||||
|
||||
export function hidePages() {
|
||||
PagesWidget.set_reveal_child(false);
|
||||
if(!pagesInstance) return;
|
||||
|
||||
pagesInstance.set_reveal_child(false);
|
||||
if(!currentPage.get()) return;
|
||||
|
||||
timeout(500, () => {
|
||||
timeout(pagesInstance.transitionDuration || 500, () => {
|
||||
if(currentPage.get() && currentPage.get()?.props.onClose)
|
||||
currentPage.get()!.props.onClose!();
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ function LogoutButton(): Widget.Button {
|
||||
} as Widget.ButtonProps);
|
||||
}
|
||||
|
||||
export const QuickActions: Widget.Box = new Widget.Box({
|
||||
export const QuickActions = () => new Widget.Box({
|
||||
className: "quickactions",
|
||||
children: [
|
||||
new Widget.Box({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { bind } from "astal";
|
||||
import { Gtk, Widget } from "astal/gtk3";
|
||||
import { Wireplumber } from "../../scripts/volume";
|
||||
|
||||
export const Sliders: Gtk.Widget = new Widget.Box({
|
||||
export const Sliders = () => new Widget.Box({
|
||||
className: "sliders",
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
expand: true,
|
||||
@@ -17,6 +17,7 @@ export const Sliders: Gtk.Widget = new Widget.Box({
|
||||
new Widget.Slider({
|
||||
drawValue: false,
|
||||
hexpand: true,
|
||||
setup: (slider) => slider.set_value(Wireplumber.getDefault().getSinkVolume()),
|
||||
value: bind(Wireplumber.getDefault().getDefaultSink(), "volume").as((volume: number) =>
|
||||
Math.floor(volume * 100)),
|
||||
max: Wireplumber.getDefault().getMaxSinkVolume(),
|
||||
@@ -34,6 +35,7 @@ export const Sliders: Gtk.Widget = new Widget.Box({
|
||||
new Widget.Slider({
|
||||
drawValue: false,
|
||||
hexpand: true,
|
||||
setup: (slider) => slider.set_value(Wireplumber.getDefault().getSourceVolume()),
|
||||
value: bind(Wireplumber.getDefault().getDefaultSource(), "volume").as((volume: number) =>
|
||||
Math.floor(volume * 100)),
|
||||
max: Wireplumber.getDefault().getMaxSourceVolume(),
|
||||
|
||||
@@ -3,13 +3,13 @@ import { TileNetwork } from "./tiles/Network";
|
||||
import { TileBluetooth } from "./tiles/Bluetooth";
|
||||
import { TileDND } from "./tiles/DoNotDisturb";
|
||||
|
||||
export const tileList: Array<any> = [
|
||||
export const tileList: Array<() => Gtk.Widget> = [
|
||||
TileNetwork,
|
||||
TileBluetooth,
|
||||
TileDND
|
||||
];
|
||||
|
||||
export function TilesWidget(): Gtk.Widget {
|
||||
export function Tiles(): Gtk.Widget {
|
||||
const tilesFlowBox: Gtk.FlowBox = new Gtk.FlowBox({
|
||||
visible: true,
|
||||
orientation: Gtk.Orientation.HORIZONTAL,
|
||||
@@ -21,13 +21,11 @@ export function TilesWidget(): Gtk.Widget {
|
||||
homogeneous: true,
|
||||
} as Gtk.FlowBox.ConstructorProps);
|
||||
|
||||
tileList.map((item: Gtk.Widget) =>
|
||||
tilesFlowBox.insert(item, -1));
|
||||
tileList.map((item: (() => Gtk.Widget)) =>
|
||||
tilesFlowBox.insert(item(), -1));
|
||||
|
||||
return new Widget.Box({
|
||||
className: "tiles-container",
|
||||
child: tilesFlowBox
|
||||
} as Widget.BoxProps);
|
||||
}
|
||||
|
||||
export const Tiles: Gtk.Widget = TilesWidget();
|
||||
|
||||
@@ -6,7 +6,7 @@ import { togglePage } from "../Pages";
|
||||
import { PageNetwork } from "../pages/Network";
|
||||
import { tr } from "../../../i18n/intl";
|
||||
|
||||
export const TileNetwork = new Widget.Box({
|
||||
export const TileNetwork = () => new Widget.Box({
|
||||
child: Variable.derive([
|
||||
bind(AstalNetwork.get_default(), "primary"),
|
||||
bind(AstalNetwork.get_default(), "wired"),
|
||||
@@ -36,7 +36,7 @@ export const TileNetwork = new Widget.Box({
|
||||
icon: "",
|
||||
iconSize: 16,
|
||||
toggleState: bind(wifi, "enabled")
|
||||
} as TileProps);
|
||||
} as TileProps)();
|
||||
|
||||
} else if(primary === AstalNetwork.Primary.WIRED) {
|
||||
return Tile({
|
||||
@@ -69,7 +69,7 @@ export const TileNetwork = new Widget.Box({
|
||||
internet === AstalNetwork.Internet.CONNECTING
|
||||
|| internet === AstalNetwork.Internet.CONNECTED
|
||||
)
|
||||
} as TileProps);
|
||||
} as TileProps)();
|
||||
}
|
||||
|
||||
return Tile({
|
||||
@@ -82,6 +82,6 @@ export const TileNetwork = new Widget.Box({
|
||||
iconSize: 16,
|
||||
toggleState: bind(wired, "internet").as((internet: AstalNetwork.Internet) =>
|
||||
internet === AstalNetwork.Internet.CONNECTING || internet === AstalNetwork.Internet.CONNECTED)
|
||||
} as TileProps);
|
||||
} as TileProps)();
|
||||
})()
|
||||
} as Widget.BoxProps);
|
||||
|
||||
@@ -15,7 +15,7 @@ export type TileProps = {
|
||||
onClickMore?: () => void;
|
||||
}
|
||||
|
||||
export function Tile(props: TileProps): Widget.EventBox {
|
||||
export function Tile(props: TileProps): (() => Widget.EventBox) {
|
||||
const toggled = new Variable<boolean>(props.toggleState instanceof Binding ?
|
||||
(props.toggleState.get() || false) : (props.toggleState || false));
|
||||
|
||||
@@ -24,7 +24,7 @@ export function Tile(props: TileProps): Widget.EventBox {
|
||||
if(props?.toggleState instanceof Binding)
|
||||
subscription = props.toggleState.subscribe(val => toggled.set(val || false));
|
||||
|
||||
return new Widget.EventBox({
|
||||
return () => new Widget.EventBox({
|
||||
className: toggled().as((state: boolean) =>
|
||||
state ? "tile-eventbox toggled" : "tile-eventbox"),
|
||||
expand: true,
|
||||
@@ -39,7 +39,7 @@ export function Tile(props: TileProps): Widget.EventBox {
|
||||
toggled.set(true);
|
||||
props.onToggledOn && props.onToggledOn();
|
||||
},
|
||||
onDestroy: () => subscription(),
|
||||
onDestroy: () => subscription?.(),
|
||||
child: new Widget.Box({
|
||||
className: (props.className instanceof Binding) ?
|
||||
props.className.as((clsName: (string|undefined)) =>
|
||||
|
||||
Reference in New Issue
Block a user