2011-07-12 16:12:28 -04:00
|
|
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2019-01-31 09:07:06 -05:00
|
|
|
/* exported Slider */
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-07-25 12:53:00 -04:00
|
|
|
const { Atk, Clutter, GObject } = imports.gi;
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2018-02-08 13:04:42 -05:00
|
|
|
const BarLevel = imports.ui.barLevel;
|
|
|
|
|
2017-07-18 13:47:27 -04:00
|
|
|
var SLIDER_SCROLL_STEP = 0.02; /* Slider scrolling step in % */
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-07-25 12:53:00 -04:00
|
|
|
var Slider = GObject.registerClass({
|
|
|
|
Signals: {
|
|
|
|
'drag-begin': {},
|
2019-08-20 17:43:54 -04:00
|
|
|
'drag-end': {},
|
|
|
|
},
|
2019-07-25 12:53:00 -04:00
|
|
|
}, class Slider extends BarLevel.BarLevel {
|
|
|
|
_init(value) {
|
|
|
|
super._init({
|
|
|
|
value,
|
|
|
|
style_class: 'slider',
|
|
|
|
can_focus: true,
|
2018-02-08 13:04:42 -05:00
|
|
|
reactive: true,
|
2019-10-21 14:44:00 -04:00
|
|
|
accessible_role: Atk.Role.SLIDER,
|
|
|
|
x_expand: true,
|
2019-07-25 12:53:00 -04:00
|
|
|
});
|
2018-02-08 13:04:42 -05:00
|
|
|
|
2019-09-10 01:42:48 -04:00
|
|
|
this._releaseId = 0;
|
2011-07-12 16:12:28 -04:00
|
|
|
this._dragging = false;
|
2013-08-22 17:15:35 -04:00
|
|
|
|
2017-12-01 19:27:35 -05:00
|
|
|
this._customAccessible.connect('get-minimum-increment', this._getMinimumIncrement.bind(this));
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-07-25 12:53:00 -04:00
|
|
|
vfunc_repaint() {
|
|
|
|
super.vfunc_repaint();
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2018-02-08 13:04:42 -05:00
|
|
|
// Add handle
|
2019-07-25 12:53:00 -04:00
|
|
|
let cr = this.get_context();
|
|
|
|
let themeNode = this.get_theme_node();
|
|
|
|
let [width, height] = this.get_surface_size();
|
2011-07-12 16:12:28 -04:00
|
|
|
|
|
|
|
let handleRadius = themeNode.get_length('-slider-handle-radius');
|
|
|
|
|
|
|
|
let handleBorderWidth = themeNode.get_length('-slider-handle-border-width');
|
|
|
|
let [hasHandleColor, handleBorderColor] =
|
|
|
|
themeNode.lookup_color('-slider-handle-border-color', false);
|
|
|
|
|
2020-03-01 08:01:14 -05:00
|
|
|
const ceiledHandleRadius = Math.ceil(handleRadius + handleBorderWidth);
|
|
|
|
const handleX = ceiledHandleRadius +
|
|
|
|
(width - 2 * ceiledHandleRadius) * this._value / this._maxValue;
|
|
|
|
const handleY = height / 2;
|
2011-07-12 16:12:28 -04:00
|
|
|
|
|
|
|
let color = themeNode.get_foreground_color();
|
2013-06-21 14:24:06 -04:00
|
|
|
Clutter.cairo_set_source_color(cr, color);
|
2011-07-12 16:12:28 -04:00
|
|
|
cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
|
|
|
|
cr.fillPreserve();
|
|
|
|
if (hasHandleColor && handleBorderWidth) {
|
2013-06-21 14:24:06 -04:00
|
|
|
Clutter.cairo_set_source_color(cr, handleBorderColor);
|
|
|
|
cr.setLineWidth(handleBorderWidth);
|
|
|
|
cr.stroke();
|
2011-07-12 16:12:28 -04:00
|
|
|
}
|
|
|
|
cr.$dispose();
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-09-10 01:42:48 -04:00
|
|
|
vfunc_button_press_event() {
|
|
|
|
return this.startDragging(Clutter.get_current_event());
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2013-06-11 23:39:56 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
startDragging(event) {
|
2013-06-11 23:43:04 -04:00
|
|
|
if (this._dragging)
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2011-07-12 16:12:28 -04:00
|
|
|
|
|
|
|
this._dragging = true;
|
|
|
|
|
2013-06-11 23:43:04 -04:00
|
|
|
let device = event.get_device();
|
2014-07-22 06:37:06 -04:00
|
|
|
let sequence = event.get_event_sequence();
|
|
|
|
|
|
|
|
if (sequence != null)
|
2019-07-25 12:53:00 -04:00
|
|
|
device.sequence_grab(sequence, this);
|
2014-07-22 06:37:06 -04:00
|
|
|
else
|
2019-07-25 12:53:00 -04:00
|
|
|
device.grab(this);
|
2014-07-22 06:37:06 -04:00
|
|
|
|
2013-06-11 23:43:04 -04:00
|
|
|
this._grabbedDevice = device;
|
2014-07-22 06:37:06 -04:00
|
|
|
this._grabbedSequence = sequence;
|
|
|
|
|
2016-01-27 17:35:11 -05:00
|
|
|
// We need to emit 'drag-begin' before moving the handle to make
|
2019-07-25 12:53:00 -04:00
|
|
|
// sure that no 'notify::value' signal is emitted before this one.
|
2016-01-27 17:35:11 -05:00
|
|
|
this.emit('drag-begin');
|
|
|
|
|
2011-07-12 16:12:28 -04:00
|
|
|
let absX, absY;
|
|
|
|
[absX, absY] = event.get_coords();
|
|
|
|
this._moveHandle(absX, absY);
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_endDragging() {
|
2011-07-12 16:12:28 -04:00
|
|
|
if (this._dragging) {
|
2019-09-22 07:31:02 -04:00
|
|
|
if (this._releaseId) {
|
2019-07-25 12:53:00 -04:00
|
|
|
this.disconnect(this._releaseId);
|
2019-09-22 07:31:02 -04:00
|
|
|
this._releaseId = 0;
|
|
|
|
}
|
|
|
|
|
2014-07-22 06:37:06 -04:00
|
|
|
if (this._grabbedSequence != null)
|
|
|
|
this._grabbedDevice.sequence_ungrab(this._grabbedSequence);
|
|
|
|
else
|
|
|
|
this._grabbedDevice.ungrab();
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2014-07-22 06:37:06 -04:00
|
|
|
this._grabbedSequence = null;
|
2013-06-11 23:43:04 -04:00
|
|
|
this._grabbedDevice = null;
|
2011-07-12 16:12:28 -04:00
|
|
|
this._dragging = false;
|
|
|
|
|
|
|
|
this.emit('drag-end');
|
|
|
|
}
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-09-10 01:42:48 -04:00
|
|
|
vfunc_button_release_event() {
|
|
|
|
if (this._dragging && !this._grabbedSequence)
|
|
|
|
return this._endDragging();
|
|
|
|
|
|
|
|
return Clutter.EVENT_PROPAGATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
vfunc_touch_event() {
|
|
|
|
let event = Clutter.get_current_event();
|
2014-07-22 06:37:06 -04:00
|
|
|
let device = event.get_device();
|
|
|
|
let sequence = event.get_event_sequence();
|
|
|
|
|
|
|
|
if (!this._dragging &&
|
|
|
|
event.type() == Clutter.EventType.TOUCH_BEGIN) {
|
|
|
|
this.startDragging(event);
|
|
|
|
return Clutter.EVENT_STOP;
|
2019-09-10 01:42:48 -04:00
|
|
|
} else if (device.sequence_get_grabbed_actor(sequence) == this) {
|
2014-07-22 06:37:06 -04:00
|
|
|
if (event.type() == Clutter.EventType.TOUCH_UPDATE)
|
2019-09-10 01:42:48 -04:00
|
|
|
return this._motionEvent(this, event);
|
2014-07-22 06:37:06 -04:00
|
|
|
else if (event.type() == Clutter.EventType.TOUCH_END)
|
|
|
|
return this._endDragging();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2014-07-22 06:37:06 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
scroll(event) {
|
2011-07-12 16:12:28 -04:00
|
|
|
let direction = event.get_scroll_direction();
|
|
|
|
let delta;
|
|
|
|
|
|
|
|
if (event.is_pointer_emulated())
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2011-07-12 16:12:28 -04:00
|
|
|
|
|
|
|
if (direction == Clutter.ScrollDirection.DOWN) {
|
|
|
|
delta = -SLIDER_SCROLL_STEP;
|
|
|
|
} else if (direction == Clutter.ScrollDirection.UP) {
|
2019-01-29 18:01:21 -05:00
|
|
|
delta = SLIDER_SCROLL_STEP;
|
2011-07-12 16:12:28 -04:00
|
|
|
} else if (direction == Clutter.ScrollDirection.SMOOTH) {
|
2019-02-01 08:41:55 -05:00
|
|
|
let [, dy] = event.get_scroll_delta();
|
2011-07-12 16:12:28 -04:00
|
|
|
// Even though the slider is horizontal, use dy to match
|
|
|
|
// the UP/DOWN above.
|
2015-01-10 07:12:48 -05:00
|
|
|
delta = -dy * SLIDER_SCROLL_STEP;
|
2011-07-12 16:12:28 -04:00
|
|
|
}
|
|
|
|
|
2019-08-12 11:40:54 -04:00
|
|
|
this.value = Math.min(Math.max(0, this._value + delta), this._maxValue);
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-09-10 01:42:48 -04:00
|
|
|
vfunc_scroll_event() {
|
|
|
|
return this.scroll(Clutter.get_current_event());
|
|
|
|
}
|
|
|
|
|
|
|
|
vfunc_motion_event() {
|
|
|
|
if (this._dragging && !this._grabbedSequence)
|
|
|
|
return this._motionEvent(this, Clutter.get_current_event());
|
|
|
|
|
|
|
|
return Clutter.EVENT_PROPAGATE;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2017-10-30 20:03:21 -04:00
|
|
|
_motionEvent(actor, event) {
|
2011-07-12 16:12:28 -04:00
|
|
|
let absX, absY;
|
|
|
|
[absX, absY] = event.get_coords();
|
|
|
|
this._moveHandle(absX, absY);
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-09-10 01:42:48 -04:00
|
|
|
vfunc_key_press_event(keyPressEvent) {
|
|
|
|
let key = keyPressEvent.keyval;
|
2011-07-12 16:12:28 -04:00
|
|
|
if (key == Clutter.KEY_Right || key == Clutter.KEY_Left) {
|
|
|
|
let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
|
2019-08-12 11:40:54 -04:00
|
|
|
this.value = Math.max(0, Math.min(this._value + delta, this._maxValue));
|
2013-11-29 13:17:34 -05:00
|
|
|
return Clutter.EVENT_STOP;
|
2011-07-12 16:12:28 -04:00
|
|
|
}
|
2020-03-26 18:40:38 -04:00
|
|
|
return super.vfunc_key_press_event(keyPressEvent);
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-01-31 09:08:10 -05:00
|
|
|
_moveHandle(absX, _absY) {
|
2019-01-31 09:04:56 -05:00
|
|
|
let relX, sliderX;
|
2019-07-25 12:53:00 -04:00
|
|
|
[sliderX] = this.get_transformed_position();
|
2011-07-12 16:12:28 -04:00
|
|
|
relX = absX - sliderX;
|
|
|
|
|
2018-02-08 13:04:42 -05:00
|
|
|
let width = this._barLevelWidth;
|
2019-07-25 12:53:00 -04:00
|
|
|
let handleRadius = this.get_theme_node().get_length('-slider-handle-radius');
|
2011-07-12 16:12:28 -04:00
|
|
|
|
|
|
|
let newvalue;
|
|
|
|
if (relX < handleRadius)
|
|
|
|
newvalue = 0;
|
|
|
|
else if (relX > width - handleRadius)
|
|
|
|
newvalue = 1;
|
|
|
|
else
|
|
|
|
newvalue = (relX - handleRadius) / (width - 2 * handleRadius);
|
2019-08-12 11:40:54 -04:00
|
|
|
this.value = newvalue * this._maxValue;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2011-07-12 16:12:28 -04:00
|
|
|
|
2019-02-04 06:30:53 -05:00
|
|
|
_getMinimumIncrement() {
|
2013-08-22 17:15:35 -04:00
|
|
|
return 0.1;
|
2017-10-30 21:19:44 -04:00
|
|
|
}
|
2019-07-25 12:53:00 -04:00
|
|
|
});
|