2024-01-29 18:54:07 -05:00
|
|
|
import Gtk from 'gi://Gtk?version=3.0';
|
|
|
|
import Gdk from 'gi://Gdk?version=3.0';
|
2023-11-21 01:29:46 -05:00
|
|
|
|
2024-01-29 18:54:07 -05:00
|
|
|
// Types
|
2024-01-30 11:29:07 -05:00
|
|
|
import { BaseProps, Widget as AgsWidget } from 'types/widgets/widget';
|
2024-01-29 18:54:07 -05:00
|
|
|
type EventHandler<Self> = (self: Self, event: Gdk.Event) => boolean | unknown;
|
2023-10-02 12:06:35 -04:00
|
|
|
|
2024-01-29 18:54:07 -05:00
|
|
|
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>
|
2023-09-04 22:27:34 -04:00
|
|
|
|
2024-01-29 18:54:07 -05:00
|
|
|
on_scroll_up?: EventHandler<Self>
|
|
|
|
on_scroll_down?: EventHandler<Self>
|
2024-01-13 11:15:08 -05:00
|
|
|
|
2024-01-29 18:54:07 -05:00
|
|
|
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
|
2024-01-30 11:29:07 -05:00
|
|
|
export interface CursorBox<Child, Attr> extends AgsWidget<Attr> { }
|
2024-01-29 18:54:07 -05:00
|
|
|
|
|
|
|
|
|
|
|
export class CursorBox<Child extends Gtk.Widget, Attr> extends Gtk.EventBox {
|
|
|
|
static {
|
2024-01-30 11:29:07 -05:00
|
|
|
Widget.register(this, {
|
2024-01-29 18:54:07 -05:00
|
|
|
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
|
2024-05-15 15:13:24 -04:00
|
|
|
const gesture = Gtk.GestureMultiPress.new(this);
|
2024-01-29 18:54:07 -05:00
|
|
|
|
2024-05-15 15:13:24 -04:00
|
|
|
this.hook(gesture, (_, _n, x, y) => {
|
|
|
|
if (!x || !y) {
|
2024-01-29 18:54:07 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-11 02:18:59 -05:00
|
|
|
this.#canRun.setValue(!(
|
2024-01-29 18:54:07 -05:00
|
|
|
x > this.get_allocated_width() ||
|
2024-05-15 15:13:24 -04:00
|
|
|
x <= 0 ||
|
|
|
|
y > this.get_allocated_height() ||
|
|
|
|
y <= 0
|
2024-02-11 02:18:59 -05:00
|
|
|
));
|
2024-05-15 15:13:24 -04:00
|
|
|
}, 'released');
|
2024-01-29 18:54:07 -05:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|
2024-02-18 13:08:50 -05:00
|
|
|
|
|
|
|
this.hook(this.#disabled, () => {
|
|
|
|
this.toggleClassName('disabled', this.#disabled.value);
|
|
|
|
});
|
2024-01-29 18:54:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#display = Gdk.Display.get_default();
|
2024-01-13 11:15:08 -05:00
|
|
|
|
2023-11-16 14:37:09 -05:00
|
|
|
// Make this variable to know if the function should
|
|
|
|
// be executed depending on where the click is released
|
2024-01-29 18:54:07 -05:00
|
|
|
#canRun = Variable(true);
|
|
|
|
#disabled = Variable(false);
|
|
|
|
|
|
|
|
get disabled() {
|
|
|
|
return this.#disabled.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
set disabled(value: boolean) {
|
2024-02-11 02:18:59 -05:00
|
|
|
this.#disabled.setValue(value);
|
2024-01-29 18:54:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
get child() {
|
|
|
|
return super.child as Child;
|
|
|
|
}
|
|
|
|
|
|
|
|
set child(child: Child) {
|
|
|
|
super.child = child;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
get on_hover() {
|
|
|
|
return this._get('on-hover');
|
|
|
|
}
|
|
|
|
|
|
|
|
set on_hover(callback: EventHandler<this>) {
|
|
|
|
this._set('on-hover', callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
get on_hover_lost() {
|
|
|
|
return this._get('on-hover-lost');
|
|
|
|
}
|
|
|
|
|
|
|
|
set on_hover_lost(callback: EventHandler<this>) {
|
|
|
|
this._set('on-hover-lost', callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
get on_scroll_up() {
|
|
|
|
return this._get('on-scroll-up');
|
|
|
|
}
|
|
|
|
|
|
|
|
set on_scroll_up(callback: EventHandler<this>) {
|
|
|
|
this._set('on-scroll-up', callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
get on_scroll_down() {
|
|
|
|
return this._get('on-scroll-down');
|
|
|
|
}
|
|
|
|
|
|
|
|
set on_scroll_down(callback: EventHandler<this>) {
|
|
|
|
this._set('on-scroll-down', callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ?? {});
|