ddd4fd9c24
Implement for barLevel an overdrive area. This is a zone represented via a different styling to indicate that you are bypassing the normal zone of a given level, without reaching yet the maximum limit. https://bugzilla.gnome.org/show_bug.cgi?id=790280.
211 lines
8.7 KiB
JavaScript
211 lines
8.7 KiB
JavaScript
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
|
const Atk = imports.gi.Atk;
|
|
const Cairo = imports.cairo;
|
|
const Clutter = imports.gi.Clutter;
|
|
const Lang = imports.lang;
|
|
const St = imports.gi.St;
|
|
const Signals = imports.signals;
|
|
|
|
var BarLevel = new Lang.Class({
|
|
Name: "BarLevel",
|
|
|
|
_init(value, params) {
|
|
if (isNaN(value))
|
|
// Avoid spreading NaNs around
|
|
throw TypeError('The bar level value must be a number');
|
|
this._maxValue = 1;
|
|
this._value = Math.max(Math.min(value, this._maxValue), 0);
|
|
this._overdriveStart = 1;
|
|
this._barLevelWidth = 0;
|
|
|
|
if (params == undefined)
|
|
params = {}
|
|
|
|
this.actor = new St.DrawingArea({ styleClass: params['styleClass'] || 'barlevel',
|
|
can_focus: params['canFocus'] || false,
|
|
reactive: params['reactive'] || false,
|
|
accessible_role: params['accessibleRole'] || Atk.Role.LEVEL_BAR });
|
|
this.actor.connect('repaint', this._barLevelRepaint.bind(this));
|
|
this.actor.connect('allocation-changed', (actor, box) => {
|
|
this._barLevelWidth = box.get_width();
|
|
});
|
|
|
|
this._customAccessible = St.GenericAccessible.new_for_actor(this.actor);
|
|
this.actor.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('value-changed', this._valueChanged.bind(this));
|
|
},
|
|
|
|
setValue(value) {
|
|
if (isNaN(value))
|
|
throw TypeError('The bar level value must be a number');
|
|
|
|
this._value = Math.max(Math.min(value, this._maxValue), 0);
|
|
this.actor.queue_repaint();
|
|
},
|
|
|
|
setMaximumValue(value) {
|
|
if (isNaN(value))
|
|
throw TypeError('The bar level max value must be a number');
|
|
|
|
this._maxValue = Math.max(value, 1);
|
|
this._overdriveStart = Math.min(this._overdriveStart, this._maxValue);
|
|
this.actor.queue_repaint();
|
|
},
|
|
|
|
setOverdriveStart(value) {
|
|
if (isNaN(value))
|
|
throw TypeError('The overdrive limit value must be a number');
|
|
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._value = Math.max(Math.min(value, this._maxValue), 0);
|
|
this.actor.queue_repaint();
|
|
},
|
|
|
|
_barLevelRepaint(area) {
|
|
let cr = area.get_context();
|
|
let themeNode = area.get_theme_node();
|
|
let [width, height] = area.get_surface_size();
|
|
|
|
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)
|
|
endX = barLevelBorderRadius + (width - 2 * barLevelBorderRadius) * this._value / this._maxValue;
|
|
|
|
let overdriveSeparatorX = barLevelBorderRadius + (width - 2 * barLevelBorderRadius) * this._overdriveStart / this._maxValue;
|
|
let overdriveActive = this._overdriveStart !== this._maxValue;
|
|
let overdriveSeparatorWidth = 0;
|
|
if (overdriveActive)
|
|
overdriveSeparatorWidth = themeNode.get_length('-barlevel-overdrive-separator-width');
|
|
|
|
/* background bar */
|
|
cr.arc(width - barLevelBorderRadius - barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * 3 / 4, TAU * 1 / 4);
|
|
cr.lineTo(endX, (height + barLevelHeight) / 2);
|
|
cr.lineTo(endX, (height - barLevelHeight) / 2);
|
|
cr.lineTo(width - barLevelBorderRadius - barLevelBorderWidth, (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 = Math.min(endX, overdriveSeparatorX - overdriveSeparatorWidth / 2);
|
|
cr.arc(barLevelBorderRadius + barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * 1 / 4, TAU * 3 / 4);
|
|
cr.lineTo(x, (height - barLevelHeight) / 2);
|
|
cr.lineTo(x, (height + barLevelHeight) / 2);
|
|
cr.lineTo(barLevelBorderRadius + barLevelBorderWidth, (height + barLevelHeight) / 2);
|
|
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
|
|
cr.fillPreserve();
|
|
Clutter.cairo_set_source_color(cr, barLevelActiveBorderColor);
|
|
cr.setLineWidth(barLevelBorderWidth);
|
|
cr.stroke();
|
|
|
|
/* overdrive progress barLevel */
|
|
x = Math.min(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 <= this._overdriveStart)
|
|
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
|
|
else
|
|
Clutter.cairo_set_source_color(cr, barLevelOverdriveColor);
|
|
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);
|
|
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(actor) {
|
|
return this._value;
|
|
},
|
|
|
|
_getOverdriveStart(actor) {
|
|
return this._overdriveStart;
|
|
},
|
|
|
|
_getMinimumValue(actor) {
|
|
return 0;
|
|
},
|
|
|
|
_getMaximumValue(actor) {
|
|
return this._maxValue;
|
|
},
|
|
|
|
_setCurrentValue(actor, value) {
|
|
this._value = value;
|
|
},
|
|
|
|
_valueChanged(barLevel, value, property) {
|
|
this._customAccessible.notify("accessible-value");
|
|
},
|
|
|
|
get value() {
|
|
return this._value;
|
|
}
|
|
});
|
|
|
|
Signals.addSignalMethods(BarLevel.prototype);
|