2018-02-08 18:04:42 +00:00
|
|
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
import Atk from 'gi://Atk';
|
|
|
|
import Clutter from 'gi://Clutter';
|
|
|
|
import GObject from 'gi://GObject';
|
|
|
|
import St from 'gi://St';
|
2019-07-25 16:53:00 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export const BarLevel = GObject.registerClass({
|
2019-07-25 16:53:00 +00:00
|
|
|
Properties: {
|
|
|
|
'value': GObject.ParamSpec.double(
|
|
|
|
'value', 'value', 'value',
|
|
|
|
GObject.ParamFlags.READWRITE,
|
2019-08-07 12:33:08 +00:00
|
|
|
0, 2, 0),
|
2019-07-25 16:53:00 +00:00
|
|
|
'maximum-value': GObject.ParamSpec.double(
|
|
|
|
'maximum-value', 'maximum-value', 'maximum-value',
|
|
|
|
GObject.ParamFlags.READWRITE,
|
|
|
|
1, 2, 1),
|
|
|
|
'overdrive-start': GObject.ParamSpec.double(
|
|
|
|
'overdrive-start', 'overdrive-start', 'overdrive-start',
|
|
|
|
GObject.ParamFlags.READWRITE,
|
2019-08-20 21:43:54 +00:00
|
|
|
1, 2, 1),
|
|
|
|
},
|
2019-07-25 16:53:00 +00:00
|
|
|
}, class BarLevel extends St.DrawingArea {
|
|
|
|
_init(params) {
|
2018-02-09 13:02:21 +00:00
|
|
|
this._maxValue = 1;
|
2019-07-25 16:53:00 +00:00
|
|
|
this._value = 0;
|
2018-07-31 13:49:06 +00:00
|
|
|
this._overdriveStart = 1;
|
2018-02-08 18:04:42 +00:00
|
|
|
this._barLevelWidth = 0;
|
|
|
|
|
2019-07-25 16:53:00 +00:00
|
|
|
let defaultParams = {
|
|
|
|
style_class: 'barlevel',
|
2019-08-20 21:43:54 +00:00
|
|
|
accessible_role: Atk.Role.LEVEL_BAR,
|
2019-07-25 16:53:00 +00:00
|
|
|
};
|
|
|
|
super._init(Object.assign(defaultParams, params));
|
2020-05-09 19:37:18 +00:00
|
|
|
this.connect('notify::allocation', () => {
|
|
|
|
this._barLevelWidth = this.allocation.get_width();
|
2018-02-08 18:04:42 +00:00
|
|
|
});
|
|
|
|
|
2019-07-25 16:53:00 +00:00
|
|
|
this._customAccessible = St.GenericAccessible.new_for_actor(this);
|
|
|
|
this.set_accessible(this._customAccessible);
|
2018-02-08 18:04:42 +00:00
|
|
|
|
|
|
|
this._customAccessible.connect('get-current-value', this._getCurrentValue.bind(this));
|
|
|
|
this._customAccessible.connect('get-minimum-value', this._getMinimumValue.bind(this));
|
|
|
|
this._customAccessible.connect('get-maximum-value', this._getMaximumValue.bind(this));
|
|
|
|
this._customAccessible.connect('set-current-value', this._setCurrentValue.bind(this));
|
|
|
|
|
2019-07-25 16:53:00 +00:00
|
|
|
this.connect('notify::value', this._valueChanged.bind(this));
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2019-07-25 15:33:00 +00:00
|
|
|
get value() {
|
|
|
|
return this._value;
|
|
|
|
}
|
|
|
|
|
|
|
|
set value(value) {
|
2019-02-02 17:01:56 +00:00
|
|
|
value = Math.max(Math.min(value, this._maxValue), 0);
|
|
|
|
|
2023-08-07 00:51:19 +00:00
|
|
|
if (this._value === value)
|
2019-02-02 17:01:56 +00:00
|
|
|
return;
|
|
|
|
|
2019-07-25 16:53:00 +00:00
|
|
|
this._value = value;
|
|
|
|
this.notify('value');
|
|
|
|
this.queue_repaint();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-02-09 13:02:21 +00:00
|
|
|
|
2021-01-30 01:03:07 +00:00
|
|
|
get maximumValue() {
|
2019-07-25 15:33:00 +00:00
|
|
|
return this._maxValue;
|
|
|
|
}
|
|
|
|
|
2021-01-30 01:03:07 +00:00
|
|
|
set maximumValue(value) {
|
2019-02-02 17:01:56 +00:00
|
|
|
value = Math.max(value, 1);
|
|
|
|
|
2023-08-07 00:51:19 +00:00
|
|
|
if (this._maxValue === value)
|
2019-02-02 17:01:56 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
this._maxValue = value;
|
2018-07-31 13:49:06 +00:00
|
|
|
this._overdriveStart = Math.min(this._overdriveStart, this._maxValue);
|
2019-07-25 16:53:00 +00:00
|
|
|
this.notify('maximum-value');
|
|
|
|
this.queue_repaint();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-07-31 13:49:06 +00:00
|
|
|
|
2021-01-30 01:03:07 +00:00
|
|
|
get overdriveStart() {
|
2019-07-25 15:33:00 +00:00
|
|
|
return this._overdriveStart;
|
|
|
|
}
|
|
|
|
|
2021-01-30 01:03:07 +00:00
|
|
|
set overdriveStart(value) {
|
2023-08-07 00:51:19 +00:00
|
|
|
if (this._overdriveStart === value)
|
2019-02-02 17:01:56 +00:00
|
|
|
return;
|
|
|
|
|
2019-08-20 00:51:42 +00:00
|
|
|
if (value > this._maxValue) {
|
2018-07-31 13:49:06 +00:00
|
|
|
throw new Error(`Tried to set overdrive value to ${value}, ` +
|
|
|
|
`which is a number greater than the maximum allowed value ${this._maxValue}`);
|
2019-08-20 00:51:42 +00:00
|
|
|
}
|
2018-07-31 13:49:06 +00:00
|
|
|
|
|
|
|
this._overdriveStart = value;
|
2019-07-25 16:53:00 +00:00
|
|
|
this.notify('overdrive-start');
|
|
|
|
this.queue_repaint();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2019-07-25 16:53:00 +00:00
|
|
|
vfunc_repaint() {
|
|
|
|
let cr = this.get_context();
|
|
|
|
let themeNode = this.get_theme_node();
|
|
|
|
let [width, height] = this.get_surface_size();
|
2023-09-06 11:33:10 +00:00
|
|
|
const rtl = this.get_text_direction() === Clutter.TextDirection.RTL;
|
2018-02-08 18:04:42 +00:00
|
|
|
|
|
|
|
let barLevelHeight = themeNode.get_length('-barlevel-height');
|
|
|
|
let barLevelBorderRadius = Math.min(width, barLevelHeight) / 2;
|
|
|
|
let fgColor = themeNode.get_foreground_color();
|
|
|
|
|
|
|
|
let barLevelColor = themeNode.get_color('-barlevel-background-color');
|
|
|
|
let barLevelActiveColor = themeNode.get_color('-barlevel-active-background-color');
|
2018-07-31 13:49:06 +00:00
|
|
|
let barLevelOverdriveColor = themeNode.get_color('-barlevel-overdrive-color');
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2018-02-08 18:22:29 +00:00
|
|
|
let barLevelBorderWidth = Math.min(themeNode.get_length('-barlevel-border-width'), 1);
|
|
|
|
let [hasBorderColor, barLevelBorderColor] =
|
|
|
|
themeNode.lookup_color('-barlevel-border-color', false);
|
|
|
|
if (!hasBorderColor)
|
|
|
|
barLevelBorderColor = barLevelColor;
|
|
|
|
let [hasActiveBorderColor, barLevelActiveBorderColor] =
|
|
|
|
themeNode.lookup_color('-barlevel-active-border-color', false);
|
|
|
|
if (!hasActiveBorderColor)
|
|
|
|
barLevelActiveBorderColor = barLevelActiveColor;
|
2018-07-31 13:49:06 +00:00
|
|
|
let [hasOverdriveBorderColor, barLevelOverdriveBorderColor] =
|
|
|
|
themeNode.lookup_color('-barlevel-overdrive-border-color', false);
|
|
|
|
if (!hasOverdriveBorderColor)
|
|
|
|
barLevelOverdriveBorderColor = barLevelOverdriveColor;
|
2018-02-08 18:04:42 +00:00
|
|
|
|
|
|
|
const TAU = Math.PI * 2;
|
|
|
|
|
2018-02-09 13:02:21 +00:00
|
|
|
let endX = 0;
|
2023-09-06 11:33:10 +00:00
|
|
|
if (this._maxValue > 0) {
|
|
|
|
let progress = this._value / this._maxValue;
|
|
|
|
if (rtl)
|
|
|
|
progress = 1 - progress;
|
|
|
|
endX = barLevelBorderRadius + (width - 2 * barLevelBorderRadius) * progress;
|
|
|
|
}
|
|
|
|
|
|
|
|
let overdriveRatio = this._overdriveStart / this._maxValue;
|
|
|
|
if (rtl)
|
|
|
|
overdriveRatio = 1 - overdriveRatio;
|
|
|
|
let overdriveSeparatorX = barLevelBorderRadius + (width - 2 * barLevelBorderRadius) * overdriveRatio;
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2018-07-31 13:49:06 +00:00
|
|
|
let overdriveActive = this._overdriveStart !== this._maxValue;
|
|
|
|
let overdriveSeparatorWidth = 0;
|
|
|
|
if (overdriveActive)
|
|
|
|
overdriveSeparatorWidth = themeNode.get_length('-barlevel-overdrive-separator-width');
|
|
|
|
|
2023-09-06 11:33:10 +00:00
|
|
|
let xcArcStart = barLevelBorderRadius + barLevelBorderWidth;
|
|
|
|
let xcArcEnd = width - xcArcStart;
|
|
|
|
if (rtl)
|
|
|
|
[xcArcStart, xcArcEnd] = [xcArcEnd, xcArcStart];
|
|
|
|
|
2018-02-08 18:04:42 +00:00
|
|
|
/* background bar */
|
2023-09-06 11:33:10 +00:00
|
|
|
if (!rtl)
|
|
|
|
cr.arc(xcArcEnd, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4));
|
|
|
|
else
|
|
|
|
cr.arcNegative(xcArcEnd, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4));
|
2018-02-08 18:04:42 +00:00
|
|
|
cr.lineTo(endX, (height + barLevelHeight) / 2);
|
|
|
|
cr.lineTo(endX, (height - barLevelHeight) / 2);
|
2023-09-06 11:33:10 +00:00
|
|
|
cr.lineTo(xcArcEnd, (height - barLevelHeight) / 2);
|
2018-02-08 18:04:42 +00:00
|
|
|
Clutter.cairo_set_source_color(cr, barLevelColor);
|
|
|
|
cr.fillPreserve();
|
|
|
|
Clutter.cairo_set_source_color(cr, barLevelBorderColor);
|
|
|
|
cr.setLineWidth(barLevelBorderWidth);
|
|
|
|
cr.stroke();
|
|
|
|
|
|
|
|
/* normal progress bar */
|
2023-09-06 11:33:10 +00:00
|
|
|
let x = 0;
|
|
|
|
if (!rtl) {
|
|
|
|
x = Math.min(endX, overdriveSeparatorX - overdriveSeparatorWidth / 2);
|
|
|
|
cr.arc(xcArcStart, height / 2, barLevelBorderRadius, TAU * (1 / 4), TAU * (3 / 4));
|
|
|
|
} else {
|
|
|
|
x = Math.max(endX, overdriveSeparatorX + overdriveSeparatorWidth / 2);
|
|
|
|
cr.arcNegative(xcArcStart, height / 2, barLevelBorderRadius, TAU * (1 / 4), TAU * (3 / 4));
|
|
|
|
}
|
2018-07-31 13:49:06 +00:00
|
|
|
cr.lineTo(x, (height - barLevelHeight) / 2);
|
|
|
|
cr.lineTo(x, (height + barLevelHeight) / 2);
|
2023-09-06 11:33:10 +00:00
|
|
|
cr.lineTo(xcArcStart, (height + barLevelHeight) / 2);
|
2019-02-02 16:01:29 +00:00
|
|
|
if (this._value > 0)
|
2019-01-29 19:36:54 +00:00
|
|
|
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
|
2018-02-08 18:04:42 +00:00
|
|
|
cr.fillPreserve();
|
|
|
|
Clutter.cairo_set_source_color(cr, barLevelActiveBorderColor);
|
|
|
|
cr.setLineWidth(barLevelBorderWidth);
|
|
|
|
cr.stroke();
|
|
|
|
|
2018-07-31 13:49:06 +00:00
|
|
|
/* overdrive progress barLevel */
|
2023-09-06 11:33:10 +00:00
|
|
|
if (!rtl)
|
|
|
|
x = Math.min(endX, overdriveSeparatorX) + overdriveSeparatorWidth / 2;
|
|
|
|
else
|
|
|
|
x = Math.max(endX, overdriveSeparatorX) - overdriveSeparatorWidth / 2;
|
2018-07-31 13:49:06 +00:00
|
|
|
if (this._value > this._overdriveStart) {
|
|
|
|
cr.moveTo(x, (height - barLevelHeight) / 2);
|
|
|
|
cr.lineTo(endX, (height - barLevelHeight) / 2);
|
|
|
|
cr.lineTo(endX, (height + barLevelHeight) / 2);
|
|
|
|
cr.lineTo(x, (height + barLevelHeight) / 2);
|
|
|
|
cr.lineTo(x, (height - barLevelHeight) / 2);
|
|
|
|
Clutter.cairo_set_source_color(cr, barLevelOverdriveColor);
|
|
|
|
cr.fillPreserve();
|
|
|
|
Clutter.cairo_set_source_color(cr, barLevelOverdriveBorderColor);
|
|
|
|
cr.setLineWidth(barLevelBorderWidth);
|
|
|
|
cr.stroke();
|
|
|
|
}
|
|
|
|
|
2018-02-08 18:04:42 +00:00
|
|
|
/* end progress bar arc */
|
2019-02-02 16:01:29 +00:00
|
|
|
if (this._value > 0) {
|
2019-01-29 19:36:54 +00:00
|
|
|
if (this._value <= this._overdriveStart)
|
|
|
|
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
|
|
|
|
else
|
|
|
|
Clutter.cairo_set_source_color(cr, barLevelOverdriveColor);
|
2023-09-06 11:33:10 +00:00
|
|
|
if (!rtl) {
|
|
|
|
cr.arc(endX, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4));
|
|
|
|
cr.lineTo(Math.floor(endX), (height + barLevelHeight) / 2);
|
|
|
|
cr.lineTo(Math.floor(endX), (height - barLevelHeight) / 2);
|
|
|
|
} else {
|
|
|
|
cr.arcNegative(endX, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4));
|
|
|
|
cr.lineTo(Math.ceil(endX), (height + barLevelHeight) / 2);
|
|
|
|
cr.lineTo(Math.ceil(endX), (height - barLevelHeight) / 2);
|
|
|
|
}
|
2019-01-29 19:36:54 +00:00
|
|
|
cr.lineTo(endX, (height - barLevelHeight) / 2);
|
|
|
|
cr.fillPreserve();
|
|
|
|
cr.setLineWidth(barLevelBorderWidth);
|
|
|
|
cr.stroke();
|
2019-02-02 16:01:29 +00:00
|
|
|
}
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2018-07-31 13:49:06 +00:00
|
|
|
/* draw overdrive separator */
|
|
|
|
if (overdriveActive) {
|
|
|
|
cr.moveTo(overdriveSeparatorX - overdriveSeparatorWidth / 2, (height - barLevelHeight) / 2);
|
|
|
|
cr.lineTo(overdriveSeparatorX + overdriveSeparatorWidth / 2, (height - barLevelHeight) / 2);
|
|
|
|
cr.lineTo(overdriveSeparatorX + overdriveSeparatorWidth / 2, (height + barLevelHeight) / 2);
|
|
|
|
cr.lineTo(overdriveSeparatorX - overdriveSeparatorWidth / 2, (height + barLevelHeight) / 2);
|
|
|
|
cr.lineTo(overdriveSeparatorX - overdriveSeparatorWidth / 2, (height - barLevelHeight) / 2);
|
|
|
|
if (this._value <= this._overdriveStart)
|
|
|
|
Clutter.cairo_set_source_color(cr, fgColor);
|
|
|
|
else
|
|
|
|
Clutter.cairo_set_source_color(cr, barLevelColor);
|
|
|
|
cr.fill();
|
|
|
|
}
|
|
|
|
|
2018-02-08 18:04:42 +00:00
|
|
|
cr.$dispose();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_getCurrentValue() {
|
2018-02-08 18:04:42 +00:00
|
|
|
return this._value;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_getOverdriveStart() {
|
2018-07-31 13:49:06 +00:00
|
|
|
return this._overdriveStart;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-07-31 13:49:06 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_getMinimumValue() {
|
2018-02-08 18:04:42 +00:00
|
|
|
return 0;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_getMaximumValue() {
|
2018-02-09 13:02:21 +00:00
|
|
|
return this._maxValue;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2019-01-31 14:08:10 +00:00
|
|
|
_setCurrentValue(_actor, value) {
|
2018-02-08 18:04:42 +00:00
|
|
|
this._value = value;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-02-08 18:04:42 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_valueChanged() {
|
2023-08-06 22:34:20 +00:00
|
|
|
this._customAccessible.notify('accessible-value');
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2019-07-25 16:53:00 +00:00
|
|
|
});
|