Skip to content

Commit

Permalink
improve widget subclasses
Browse files Browse the repository at this point in the history
  • Loading branch information
Aylur committed Feb 29, 2024
1 parent f905abf commit 1c57316
Show file tree
Hide file tree
Showing 36 changed files with 919 additions and 297 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,30 @@
- add: Utils.watch
- custom hookable objects
- add: App.config
- impove widget subclasses
- Calendar.on_day_selected
- ColorButton.on_color_set
- DrawingArea.draw_fn
- FileChooserButton.on_file_set
- FontButton.on_font_set
- LevelBar.vertical
- LevelBar.bar_mode
- Separator.vertical
- SpinButton.on_value_changed
- Spinner starts based on visibility
- Switch.on_activate
- ToggleButton.on_toggled

## Fixes

- Widget.attribute assign falsy values
- Overlay child type

## Breaking Changes

- revert: hyprland service: workspace and monitor signal emit number
- types: Label's and Icon's Props type renamed to LabelProps, IconProps
- FileChooser renamed to FileChooserButton

# 1.7.7

Expand Down
17 changes: 16 additions & 1 deletion src/com.github.Aylur.ags.src.gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,37 @@
<file>widget.js</file>

<file>widgets/widget.js</file>
<file>widgets/etc.js</file>
<file>widgets/box.js</file>
<file>widgets/button.js</file>
<file>widgets/calendar.js</file>
<file>widgets/centerbox.js</file>
<file>widgets/circularprogress.js</file>
<file>widgets/colorbutton.js</file>
<file>widgets/drawingarea.js</file>
<file>widgets/entry.js</file>
<file>widgets/eventbox.js</file>
<file>widgets/filechooserbutton.js</file>
<file>widgets/fixed.js</file>
<file>widgets/flowbox.js</file>
<file>widgets/fontbutton.js</file>
<file>widgets/icon.js</file>
<file>widgets/label.js</file>
<file>widgets/levelbar.js</file>
<file>widgets/listbox.js</file>
<file>widgets/menu.js</file>
<file>widgets/menubar.js</file>
<file>widgets/menuitem.js</file>
<file>widgets/overlay.js</file>
<file>widgets/progressbar.js</file>
<file>widgets/revealer.js</file>
<file>widgets/scrollable.js</file>
<file>widgets/separator.js</file>
<file>widgets/slider.js</file>
<file>widgets/spinbutton.js</file>
<file>widgets/spinner.js</file>
<file>widgets/stack.js</file>
<file>widgets/switch.js</file>
<file>widgets/togglebutton.js</file>
<file>widgets/window.js</file>

<file>service/applications.js</file>
Expand Down
163 changes: 90 additions & 73 deletions src/widget.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,49 @@
/* eslint-disable max-len */
import Gtk from 'gi://Gtk?version=3.0';
import { register as registerClass, type BaseProps, type Widget as TWidget } from './widgets/widget.js';
import { Box as BoxClass, type BoxProps } from './widgets/box.js';
import { CenterBox as CenterBoxClass, type CenterBoxProps } from './widgets/centerbox.js';
import { EventBox as EventBoxClass, type EventBoxProps } from './widgets/eventbox.js';
import { Icon as IconClass, type IconProps } from './widgets/icon.js';
import { Label as LabelClass, type LabelProps } from './widgets/label.js';
import { Button as ButtonClass, type ButtonProps } from './widgets/button.js';
import { Slider as SliderClass, type SliderProps } from './widgets/slider.js';
import { Scrollable as ScrollableClass, type ScrollableProps } from './widgets/scrollable.js';
import { Stack as StackClass, type StackProps } from './widgets/stack.js';
import { Overlay as OverlayClass, type OverlayProps } from './widgets/overlay.js';
import { Revealer as RevealerClass, type RevealerProps } from './widgets/revealer.js';
import { ProgressBar as ProgressBarClass, type ProgressBarProps } from './widgets/progressbar.js';
import { Entry as EntryClass, type EntryProps } from './widgets/entry.js';
import { Menu as MenuClass, type MenuProps, MenuItem as MenuItemClass, type MenuItemProps } from './widgets/menu.js';
import { Window as WindowClass, type WindowProps } from './widgets/window.js';
import { CircularProgress as CircularProgressClass, type CircularProgressProps } from './widgets/circularprogress.js';
import * as Etc from './widgets/etc.js';

export const Window = <Child extends Gtk.Widget, Attr = unknown>(props?: WindowProps<Child, Attr>, child?: Child) => new WindowClass(props, child);
export const Box = <Child extends Gtk.Widget, Attr = unknown>(props?: BoxProps<Child, Attr> | Child[], ...children: Gtk.Widget[]) => new BoxClass(props, ...children);
export const Button = <Child extends Gtk.Widget, Attr = unknown>(props?: ButtonProps<Child, Attr>, child?: Child) => new ButtonClass(props, child);
export const CenterBox = <StartWidget extends Gtk.Widget, CenterWidget extends Gtk.Widget, EndWidget extends Gtk.Widget, Attr = unknown>(props?: CenterBoxProps<StartWidget, CenterWidget, EndWidget, Attr>, startWidget?: StartWidget, centerWidget?: CenterWidget, endWidget?: EndWidget) => new CenterBoxClass(props, startWidget, centerWidget, endWidget);
export const CircularProgress = <Child extends Gtk.Widget, Attr = unknown>(props?: CircularProgressProps<Child, Attr>, child?: Child) => new CircularProgressClass(props, child);
export const Entry = <Attr>(props?: EntryProps<Attr>) => new EntryClass(props);
export const EventBox = <Child extends Gtk.Widget, Attr = unknown>(props?: EventBoxProps<Child, Attr>, child?: Child) => new EventBoxClass(props, child);
export const Icon = <Attr>(props?: IconProps<Attr>) => new IconClass(props);
export const Label = <Attr>(props?: LabelProps<Attr>) => new LabelClass(props);
export const Menu = <Child extends Gtk.MenuItem, Attr = unknown>(props?: MenuProps<Child, Attr>, ...children: Gtk.MenuItem[]) => new MenuClass(props, ...children);
export const MenuItem = <Child extends Gtk.Widget, Attr = unknown>(props?: MenuItemProps<Child, Attr>, child?: Child) => new MenuItemClass(props, child);
export const Overlay = <Child extends Gtk.Widget, Attr = unknown>(props?: OverlayProps<Child, Attr>, ...children: Gtk.Widget[]) => new OverlayClass(props, ...children);
export const ProgressBar = <Attr>(props?: ProgressBarProps<Attr>) => new ProgressBarClass(props);
export const Revealer = <Child extends Gtk.Widget, Attr = unknown>(props?: RevealerProps<Child, Attr>, child?: Child) => new RevealerClass(props, child);
export const Scrollable = <Child extends Gtk.Widget, Attr = unknown>(props?: ScrollableProps<Child, Attr>, child?: Child) => new ScrollableClass(props, child);
export const Slider = <Attr>(props?: SliderProps<Attr>) => new SliderClass(props);
export const Stack = <Children extends { [name: string]: Gtk.Widget }, Attr = unknown>(props?: StackProps<Children, Attr>, children?: Children) => new StackClass(props, children);

export const Calendar = <Attr>(props?: Etc.CalendarProps<Attr>) => new Etc.Calendar(props);
export const ColorButton = <Attr>(props?: Etc.ColorButtonProps<Attr>) => new Etc.ColorButton(props);
export const DrawingArea = <Attr>(props?: Etc.DrawingAreaProps<Attr>) => new Etc.DrawingArea(props);
export const FileChooserButton = <Attr>(props?: Etc.FileChooserButtonProps<Attr>) => new Etc.FileChooserButton(props);
export const Fixed = <Attr>(props?: Etc.FixedProps<Attr>) => new Etc.Fixed(props);
export const FlowBox = <Attr>(props?: Etc.FlowBoxProps<Attr>) => new Etc.FlowBox(props);
export const FontButton = <Attr>(props?: Etc.FontButtonProps<Attr>) => new Etc.FontButton(props);
export const LevelBar = <Attr>(props?: Etc.LevelBarProps<Attr>) => new Etc.LevelBar(props);
export const ListBox = <Attr>(props?: Etc.ListBoxProps<Attr>) => new Etc.ListBox(props);
export const MenuBar = <Attr>(props?: Etc.MenuBarProps<Attr>) => new Etc.MenuBar(props);
export const Separator = <Attr>(props?: Etc.SeparatorProps<Attr>) => new Etc.Separator(props);
export const SpinButton = <Attr>(props?: Etc.SpinButtonProps<Attr>) => new Etc.SpinButton(props);
export const Spinner = <Attr>(props?: Etc.SpinnerProps<Attr>) => new Etc.Spinner(props);
export const Switch = <Attr>(props?: Etc.SwitchProps<Attr>) => new Etc.Switch(props);
export const ToggleButton = <Child extends Gtk.Widget, Attr = unknown>(props?: Etc.ToggleButtonProps<Child, Attr>) => new Etc.ToggleButton(props);
import { register, type BaseProps, type Widget as TWidget } from './widgets/widget.js';
import { newBox as Box } from './widgets/box.js';
import { newButton as Button } from './widgets/button.js';
import { newCalendar as Calendar } from './widgets/calendar.js';
import { newCenterBox as CenterBox } from './widgets/centerbox.js';
import { newCircularProgress as CircularProgress } from './widgets/circularprogress.js';
import { newColorButton as ColorButton } from './widgets/colorbutton.js';
import { newDrawingArea as DrawingArea } from './widgets/drawingarea.js';
import { newEntry as Entry } from './widgets/entry.js';
import { newEventBox as EventBox } from './widgets/eventbox.js';
import { newFileChooserButton as FileChooserButton } from './widgets/filechooserbutton.js';
import { newFixed as Fixed } from './widgets/fixed.js';
import { newFlowBox as FlowBox } from './widgets/flowbox.js';
import { newFontButton as FontButton } from './widgets/fontbutton.js';
import { newIcon as Icon } from './widgets/icon.js';
import { newLabel as Label } from './widgets/label.js';
import { newLevelBar as LevelBar } from './widgets/levelbar.js';
import { newListBox as ListBox } from './widgets/listbox.js';
import { newMenu as Menu } from './widgets/menu.js';
import { newMenuBar as MenuBar } from './widgets/menubar.js';
import { newMenuItem as MenuItem } from './widgets/menuitem.js';
import { newOverlay as Overlay } from './widgets/overlay.js';
import { newProgressBar as ProgressBar } from './widgets/progressbar.js';
import { newRevealer as Revealer } from './widgets/revealer.js';
import { newScrollable as Scrollable } from './widgets/scrollable.js';
import { newSeparator as Separator } from './widgets/separator.js';
import { newSlider as Slider } from './widgets/slider.js';
import { newSpinButton as SpinButton } from './widgets/spinbutton.js';
import { newSpinner as Spinner } from './widgets/spinner.js';
import { newStack as Stack } from './widgets/stack.js';
import { newSwitch as Switch } from './widgets/switch.js';
import { newToggleButton as ToggleButton } from './widgets/togglebutton.js';
import { newWindow as Window } from './widgets/window.js';

// ts can't compile export default { subclass, Box, Button ... }
// so we use a function and add members to it instead
// to bundle everything in a default export
export default function W<T extends { new(...args: any[]): Gtk.Widget }, Props>(Base: T, typename = Base.name) {
export default function W<
T extends { new(...args: any[]): Gtk.Widget },
Props,
>(
Base: T, typename = Base.name,
) {
class Subclassed extends Base {
static { registerClass(this, { typename }); }
static { register(this, { typename }); }
constructor(...params: any[]) { super(...params); }
}
type Instance<Attr> = InstanceType<typeof Subclassed> & TWidget<Attr>;
Expand All @@ -67,42 +52,74 @@ export default function W<T extends { new(...args: any[]): Gtk.Widget }, Props>(
};
}

export const Widget = W;
export const register = registerClass;
export {
register,
W as subclass,
Box,
Button,
Calendar,
CenterBox,
CircularProgress,
ColorButton,
DrawingArea,
Entry,
EventBox,
FileChooserButton,
Fixed,
FlowBox,
FontButton,
Icon,
Label,
LevelBar,
ListBox,
Menu,
MenuBar,
MenuItem,
Overlay,
ProgressBar,
Revealer,
Scrollable,
Separator,
Slider,
SpinButton,
Spinner,
Stack,
Switch,
ToggleButton,
Window,
};

W.register = register;
export const subclass = W;
W.subclass = W;

W.Box = Box;
W.Button = Button;
W.Calendar = Calendar;
W.CenterBox = CenterBox;
W.CircularProgress = CircularProgress;
W.ColorButton = ColorButton;
W.DrawingArea = DrawingArea;
W.Entry = Entry;
W.EventBox = EventBox;
W.FileChooserButton = FileChooserButton;
W.Fixed = Fixed;
W.FlowBox = FlowBox;
W.FontButton = FontButton;
W.Icon = Icon;
W.Label = Label;
W.LevelBar = LevelBar;
W.ListBox = ListBox;
W.Menu = Menu;
W.MenuBar = MenuBar;
W.MenuItem = MenuItem;
W.Overlay = Overlay;
W.ProgressBar = ProgressBar;
W.Revealer = Revealer;
W.Scrollable = Scrollable;
W.Slider = Slider;
W.Stack = Stack;
W.Window = Window;

W.Calendar = Calendar;
W.ColorButton = ColorButton;
W.DrawingArea = DrawingArea;
W.FileChooserButton = FileChooserButton;
W.Fixed = Fixed;
W.FlowBox = FlowBox;
W.FontButton = FontButton;
W.LevelBar = LevelBar;
W.ListBox = ListBox;
W.MenuBar = MenuBar;
W.Separator = Separator;
W.Slider = Slider;
W.SpinButton = SpinButton;
W.Spinner = Spinner;
W.Stack = Stack;
W.Switch = Switch;
W.ToggleButton = ToggleButton;
W.Window = Window;
7 changes: 7 additions & 0 deletions src/widgets/box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ export type BoxProps<
vertical?: boolean
}, Attr>;

export function newBox<
Child extends Gtk.Widget = Gtk.Widget,
Attr = unknown
>(...props: ConstructorParameters<typeof Box<Child, Attr>>) {
return new Box(...props);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export interface Box<Child, Attr> extends Widget<Attr> { }
export class Box<Child extends Gtk.Widget, Attr> extends Gtk.Box {
Expand Down
7 changes: 7 additions & 0 deletions src/widgets/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ export type ButtonProps<
on_secondary_click_release?: EventHandler<Self>
}, Attr>;

export function newButton<
Child extends Gtk.Widget = Gtk.Widget,
Attr = unknown,
>(...props: ConstructorParameters<typeof Button<Child, Attr>>) {
return new Button(...props);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export interface Button<Child, Attr> extends Widget<Attr> { }
export class Button<Child extends Gtk.Widget, Attr> extends Gtk.Button {
Expand Down
45 changes: 45 additions & 0 deletions src/widgets/calendar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { register, type BaseProps, type Widget } from './widget.js';
import Gtk from 'gi://Gtk?version=3.0';

type Event<Self> = (self: Self) => void

export type CalendarProps<
Attr = unknown,
Self = Calendar<Attr>,
> = BaseProps<Self, Gtk.Calendar.ConstructorProperties & {
on_day_selected?: Event<Self>
}, Attr>;

export function newCalendar<
Attr = unknown
>(...props: ConstructorParameters<typeof Calendar<Attr>>) {
return new Calendar(...props);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export interface Calendar<Attr> extends Widget<Attr> { }
export class Calendar<Attr> extends Gtk.Calendar {
static {
register(this, {
properties: {
'date': ['jsobject', 'r'],
'on-day-selected': ['jsobject', 'rw'],
},
});
}

constructor(props: CalendarProps<Attr> = {}) {
super(props as Gtk.Calendar.ConstructorProperties);
this.connect('notify::day', () => this.notify('date'));
this.connect('notify::month', () => this.notify('date'));
this.connect('notify::year', () => this.notify('date'));
this.connect('day-selected', this.on_day_selected.bind(this));
}

get date() { return this.get_date(); }

get on_day_selected() { return this._get('on-day-selected') || (() => false); }
set on_day_selected(callback: Event<this>) { this._set('on-day-selected', callback); }
}

export default Calendar;
9 changes: 9 additions & 0 deletions src/widgets/centerbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ export type CenterBoxProps<
end_widget?: EndWidget
}, Attr>;

export function newCenterBox<
StartWidget extends Gtk.Widget = Gtk.Widget,
CenterWidget extends Gtk.Widget = Gtk.Widget,
EndWidget extends Gtk.Widget = Gtk.Widget,
Attr = unknown,
>(...props: ConstructorParameters<typeof CenterBox<StartWidget, CenterWidget, EndWidget, Attr>>) {
return new CenterBox(...props);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export interface CenterBox<StartWidget, CenterWidget, EndWidget, Attr> extends Widget<Attr> { }
export class CenterBox<
Expand Down
7 changes: 7 additions & 0 deletions src/widgets/circularprogress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ export type CircularProgressProps<
end_at?: number
}, Attr>

export function newCircularProgress<
Child extends Gtk.Widget = Gtk.Widget,
Attr = unknown,
>(...props: ConstructorParameters<typeof CircularProgress<Child, Attr>>) {
return new CircularProgress(...props);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export interface CircularProgress<Child, Attr> extends Widget<Attr> { }
export class CircularProgress<
Expand Down
Loading

0 comments on commit 1c57316

Please sign in to comment.