switch: Make handle draggable
Listen to state changes for switch menu items, since they can also be changed without activating them now. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2717>
This commit is contained in:
parent
71f2355b8a
commit
946ee93692
@ -339,11 +339,13 @@ export const Switch = GObject.registerClass({
|
|||||||
}, class Switch extends St.Widget {
|
}, class Switch extends St.Widget {
|
||||||
_init(state) {
|
_init(state) {
|
||||||
this._state = false;
|
this._state = false;
|
||||||
|
this._dragging = false;
|
||||||
|
|
||||||
super._init({
|
super._init({
|
||||||
style_class: 'toggle-switch',
|
style_class: 'toggle-switch',
|
||||||
accessible_role: Atk.Role.CHECK_BOX,
|
accessible_role: Atk.Role.CHECK_BOX,
|
||||||
track_hover: true,
|
track_hover: true,
|
||||||
|
reactive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const box = new St.BoxLayout({
|
const box = new St.BoxLayout({
|
||||||
@ -380,12 +382,16 @@ export const Switch = GObject.registerClass({
|
|||||||
coordinate: Clutter.BindCoordinate.HEIGHT,
|
coordinate: Clutter.BindCoordinate.HEIGHT,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
this.bind_property('reactive', this._handle, 'reactive', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
|
||||||
this._handleAlignConstraint = new Clutter.AlignConstraint({
|
this._handleAlignConstraint = new Clutter.AlignConstraint({
|
||||||
name: 'align',
|
name: 'align',
|
||||||
align_axis: Clutter.AlignAxis.X_AXIS,
|
align_axis: Clutter.AlignAxis.X_AXIS,
|
||||||
source: this,
|
source: this,
|
||||||
});
|
});
|
||||||
this._handle.add_constraint(this._handleAlignConstraint);
|
this._handle.add_constraint(this._handleAlignConstraint);
|
||||||
|
this._handle.connect('button-press-event', (actor, event) => this._startDragging(event));
|
||||||
|
this._handle.connect('touch-event', this._touchDragging.bind(this));
|
||||||
this.add_child(this._handle);
|
this.add_child(this._handle);
|
||||||
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
@ -413,9 +419,6 @@ export const Switch = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
set state(state) {
|
set state(state) {
|
||||||
if (this._state === state)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let handleAlignFactor;
|
let handleAlignFactor;
|
||||||
// Calling get_theme_node() while unmapped is an error, avoid that
|
// Calling get_theme_node() while unmapped is an error, avoid that
|
||||||
const duration = this._handle.mapped
|
const duration = this._handle.mapped
|
||||||
@ -434,13 +437,98 @@ export const Switch = GObject.registerClass({
|
|||||||
duration,
|
duration,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this._state !== state) {
|
||||||
this._state = state;
|
this._state = state;
|
||||||
this.notify('state');
|
this.notify('state');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
this.state = !this.state;
|
this.state = !this.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_startDragging(event) {
|
||||||
|
if (this._dragging)
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
|
this._dragging = true;
|
||||||
|
[this._initialGrabX] = event.get_coords();
|
||||||
|
let device = event.get_device();
|
||||||
|
let sequence = event.get_event_sequence();
|
||||||
|
|
||||||
|
this._grab = global.stage.grab(this);
|
||||||
|
|
||||||
|
this._grabbedDevice = device;
|
||||||
|
this._grabbedSequence = sequence;
|
||||||
|
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfunc_motion_event() {
|
||||||
|
if (this._dragging && !this._grabbedSequence)
|
||||||
|
return this._motionEvent(this, Clutter.get_current_event());
|
||||||
|
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfunc_button_release_event() {
|
||||||
|
if (this._dragging && !this._grabbedSequence)
|
||||||
|
return this._endDragging();
|
||||||
|
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_touchDragging(actor, event) {
|
||||||
|
let sequence = event.get_event_sequence();
|
||||||
|
|
||||||
|
if (!this._dragging &&
|
||||||
|
event.type() === Clutter.EventType.TOUCH_BEGIN) {
|
||||||
|
this.startDragging(event);
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
} else if (this._grabbedSequence &&
|
||||||
|
sequence.get_slot() === this._grabbedSequence.get_slot()) {
|
||||||
|
if (event.type() === Clutter.EventType.TOUCH_UPDATE)
|
||||||
|
return this._motionEvent(this, event);
|
||||||
|
else if (event.type() === Clutter.EventType.TOUCH_END)
|
||||||
|
return this._endDragging();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_endDragging() {
|
||||||
|
if (!this._dragging)
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
|
if (this._grab) {
|
||||||
|
this._grab.dismiss();
|
||||||
|
this._grab = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._dragged)
|
||||||
|
this.state = this._handleAlignConstraint.get_factor() > 0.5;
|
||||||
|
else
|
||||||
|
this.toggle();
|
||||||
|
|
||||||
|
this._dragged = false;
|
||||||
|
this._grabbedSequence = null;
|
||||||
|
this._grabbedDevice = null;
|
||||||
|
this._dragging = false;
|
||||||
|
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
_motionEvent(actor, event) {
|
||||||
|
this._dragged = true;
|
||||||
|
|
||||||
|
let [absX] = event.get_coords();
|
||||||
|
let factorDiff = (absX - this._initialGrabX) / (this.get_width() - this._handle.get_width());
|
||||||
|
let factor = factorDiff + (this.state ? 1.0 : 0.0);
|
||||||
|
|
||||||
|
this._handleAlignConstraint.set_factor(Math.clamp(factor, 0, 1));
|
||||||
|
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PopupSwitchMenuItem = GObject.registerClass({
|
export const PopupSwitchMenuItem = GObject.registerClass({
|
||||||
@ -454,7 +542,10 @@ export const PopupSwitchMenuItem = GObject.registerClass({
|
|||||||
y_expand: true,
|
y_expand: true,
|
||||||
y_align: Clutter.ActorAlign.CENTER,
|
y_align: Clutter.ActorAlign.CENTER,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._switch = new Switch(active);
|
this._switch = new Switch(active);
|
||||||
|
this._switch.connect('notify::state', this._onToggled.bind(this));
|
||||||
|
this.bind_property('reactive', this._switch, 'reactive', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
|
||||||
this.accessible_role = Atk.Role.CHECK_MENU_ITEM;
|
this.accessible_role = Atk.Role.CHECK_MENU_ITEM;
|
||||||
this.checkAccessibleState();
|
this.checkAccessibleState();
|
||||||
@ -506,8 +597,6 @@ export const PopupSwitchMenuItem = GObject.registerClass({
|
|||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
this._switch.toggle();
|
this._switch.toggle();
|
||||||
this.emit('toggled', this._switch.state);
|
|
||||||
this.checkAccessibleState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get state() {
|
get state() {
|
||||||
@ -519,6 +608,11 @@ export const PopupSwitchMenuItem = GObject.registerClass({
|
|||||||
this.checkAccessibleState();
|
this.checkAccessibleState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onToggled(sw, state) {
|
||||||
|
this.emit('toggled', state);
|
||||||
|
this.checkAccessibleState();
|
||||||
|
}
|
||||||
|
|
||||||
checkAccessibleState() {
|
checkAccessibleState() {
|
||||||
switch (this.accessible_role) {
|
switch (this.accessible_role) {
|
||||||
case Atk.Role.CHECK_MENU_ITEM:
|
case Atk.Role.CHECK_MENU_ITEM:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user