summaryrefslogtreecommitdiffstats
path: root/js/ui/barLevel.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/ui/barLevel.js262
1 files changed, 262 insertions, 0 deletions
diff --git a/js/ui/barLevel.js b/js/ui/barLevel.js
new file mode 100644
index 0000000..da5b34a
--- /dev/null
+++ b/js/ui/barLevel.js
@@ -0,0 +1,262 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* exported BarLevel */
+
+const { Atk, Clutter, GObject, St } = imports.gi;
+
+var BarLevel = GObject.registerClass({
+ Properties: {
+ 'value': GObject.ParamSpec.double(
+ 'value', 'value', 'value',
+ GObject.ParamFlags.READWRITE,
+ 0, 2, 0),
+ '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,
+ 1, 2, 1),
+ },
+}, class BarLevel extends St.DrawingArea {
+ _init(params) {
+ this._maxValue = 1;
+ this._value = 0;
+ this._overdriveStart = 1;
+ this._barLevelWidth = 0;
+
+ let defaultParams = {
+ style_class: 'barlevel',
+ accessible_role: Atk.Role.LEVEL_BAR,
+ };
+ super._init(Object.assign(defaultParams, params));
+ this.connect('notify::allocation', () => {
+ this._barLevelWidth = this.allocation.get_width();
+ });
+
+ this._customAccessible = St.GenericAccessible.new_for_actor(this);
+ this.set_accessible(this._customAccessible);
+
+ 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));
+
+ this.connect('notify::value', this._valueChanged.bind(this));
+ }
+
+ get value() {
+ return this._value;
+ }
+
+ set value(value) {
+ value = Math.max(Math.min(value, this._maxValue), 0);
+
+ if (this._value == value)
+ return;
+
+ this._value = value;
+ this.notify('value');
+ this.queue_repaint();
+ }
+
+ get maximumValue() {
+ return this._maxValue;
+ }
+
+ set maximumValue(value) {
+ value = Math.max(value, 1);
+
+ if (this._maxValue == value)
+ return;
+
+ this._maxValue = value;
+ this._overdriveStart = Math.min(this._overdriveStart, this._maxValue);
+ this.notify('maximum-value');
+ this.queue_repaint();
+ }
+
+ get overdriveStart() {
+ return this._overdriveStart;
+ }
+
+ set overdriveStart(value) {
+ if (this._overdriveStart == value)
+ return;
+
+ if (value > this._maxValue) {
+ throw new Error(`Tried to set overdrive value to ${value}, ` +
+ `which is a number greater than the maximum allowed value ${this._maxValue}`);
+ }
+
+ this._overdriveStart = value;
+ this.notify('overdrive-start');
+ this.queue_repaint();
+ }
+
+ vfunc_repaint() {
+ let cr = this.get_context();
+ let themeNode = this.get_theme_node();
+ let [width, height] = this.get_surface_size();
+ const rtl = this.get_text_direction() === Clutter.TextDirection.RTL;
+
+ 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');
+ let barLevelOverdriveColor = themeNode.get_color('-barlevel-overdrive-color');
+
+ 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;
+ let [hasOverdriveBorderColor, barLevelOverdriveBorderColor] =
+ themeNode.lookup_color('-barlevel-overdrive-border-color', false);
+ if (!hasOverdriveBorderColor)
+ barLevelOverdriveBorderColor = barLevelOverdriveColor;
+
+ const TAU = Math.PI * 2;
+
+ let endX = 0;
+ 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;
+
+ let overdriveActive = this._overdriveStart !== this._maxValue;
+ let overdriveSeparatorWidth = 0;
+ if (overdriveActive)
+ overdriveSeparatorWidth = themeNode.get_length('-barlevel-overdrive-separator-width');
+
+ let xcArcStart = barLevelBorderRadius + barLevelBorderWidth;
+ let xcArcEnd = width - xcArcStart;
+ if (rtl)
+ [xcArcStart, xcArcEnd] = [xcArcEnd, xcArcStart];
+
+ /* background bar */
+ 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));
+ cr.lineTo(endX, (height + barLevelHeight) / 2);
+ cr.lineTo(endX, (height - barLevelHeight) / 2);
+ cr.lineTo(xcArcEnd, (height - barLevelHeight) / 2);
+ Clutter.cairo_set_source_color(cr, barLevelColor);
+ cr.fillPreserve();
+ Clutter.cairo_set_source_color(cr, barLevelBorderColor);
+ cr.setLineWidth(barLevelBorderWidth);
+ cr.stroke();
+
+ /* normal progress bar */
+ 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));
+ }
+ cr.lineTo(x, (height - barLevelHeight) / 2);
+ cr.lineTo(x, (height + barLevelHeight) / 2);
+ cr.lineTo(xcArcStart, (height + barLevelHeight) / 2);
+ if (this._value > 0)
+ Clutter.cairo_set_source_color(cr, barLevelActiveColor);
+ cr.fillPreserve();
+ Clutter.cairo_set_source_color(cr, barLevelActiveBorderColor);
+ cr.setLineWidth(barLevelBorderWidth);
+ cr.stroke();
+
+ /* overdrive progress barLevel */
+ if (!rtl)
+ x = Math.min(endX, overdriveSeparatorX) + overdriveSeparatorWidth / 2;
+ else
+ x = Math.max(endX, overdriveSeparatorX) - overdriveSeparatorWidth / 2;
+ 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();
+ }
+
+ /* end progress bar arc */
+ if (this._value > 0) {
+ if (this._value <= this._overdriveStart)
+ Clutter.cairo_set_source_color(cr, barLevelActiveColor);
+ else
+ Clutter.cairo_set_source_color(cr, barLevelOverdriveColor);
+ 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);
+ }
+ cr.lineTo(endX, (height - barLevelHeight) / 2);
+ cr.fillPreserve();
+ cr.setLineWidth(barLevelBorderWidth);
+ cr.stroke();
+ }
+
+ /* 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();
+ }
+
+ cr.$dispose();
+ }
+
+ _getCurrentValue() {
+ return this._value;
+ }
+
+ _getOverdriveStart() {
+ return this._overdriveStart;
+ }
+
+ _getMinimumValue() {
+ return 0;
+ }
+
+ _getMaximumValue() {
+ return this._maxValue;
+ }
+
+ _setCurrentValue(_actor, value) {
+ this._value = value;
+ }
+
+ _valueChanged() {
+ this._customAccessible.notify("accessible-value");
+ }
+});