307 lines
7.7 KiB
JavaScript
307 lines
7.7 KiB
JavaScript
'use strict';
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
const Gio = imports.gi.Gio;
|
|
const GLib = imports.gi.GLib;
|
|
const Pango = imports.gi.Pango;
|
|
const St = imports.gi.St;
|
|
|
|
const Main = imports.ui.main;
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
|
|
/**
|
|
* An StTooltip for ClutterActors
|
|
*
|
|
* Adapted from: https://github.com/RaphaelRochet/applications-overview-tooltip
|
|
* See also: https://github.com/GNOME/gtk/blob/master/gtk/gtktooltip.c
|
|
*/
|
|
var TOOLTIP_BROWSE_ID = 0;
|
|
var TOOLTIP_BROWSE_MODE = false;
|
|
|
|
var Tooltip = class Tooltip {
|
|
|
|
constructor(params) {
|
|
Object.assign(this, params);
|
|
|
|
this._hoverTimeoutId = 0;
|
|
this._showing = false;
|
|
|
|
this._destroyId = this.parent.connect(
|
|
'destroy',
|
|
this.destroy.bind(this)
|
|
);
|
|
|
|
this._hoverId = this.parent.connect(
|
|
'notify::hover',
|
|
this._onHover.bind(this)
|
|
);
|
|
|
|
this._buttonPressEventId = this.parent.connect(
|
|
'button-press-event',
|
|
this._hide.bind(this)
|
|
);
|
|
}
|
|
|
|
get custom() {
|
|
if (this._custom === undefined) {
|
|
this._custom = null;
|
|
}
|
|
|
|
return this._custom;
|
|
}
|
|
|
|
set custom(actor) {
|
|
this._custom = actor;
|
|
this._markup = null;
|
|
this._text = null;
|
|
this._update();
|
|
}
|
|
|
|
get gicon() {
|
|
if (this._gicon === undefined) {
|
|
this._gicon = null;
|
|
}
|
|
|
|
return this._gicon;
|
|
}
|
|
|
|
set gicon(gicon) {
|
|
this._gicon = gicon;
|
|
this._update();
|
|
}
|
|
|
|
get icon() {
|
|
return (this.gicon) ? this.gicon.name : null;
|
|
}
|
|
|
|
set icon(icon_name) {
|
|
if (!icon_name) {
|
|
this.gicon = null;
|
|
} else {
|
|
this.gicon = new Gio.ThemedIcon({
|
|
name: icon_name
|
|
});
|
|
}
|
|
}
|
|
|
|
get markup() {
|
|
if (this._markup === undefined) {
|
|
this._markup = null;
|
|
}
|
|
|
|
return this._markup;
|
|
}
|
|
|
|
set markup(text) {
|
|
this._markup = text;
|
|
this._text = null;
|
|
this._update();
|
|
}
|
|
|
|
get text() {
|
|
if (this._text === undefined) {
|
|
this._text = null;
|
|
}
|
|
|
|
return this._text;
|
|
}
|
|
|
|
set text(text) {
|
|
this._markup = null;
|
|
this._text = text;
|
|
this._update();
|
|
}
|
|
|
|
get x_offset() {
|
|
return (this._x_offset === undefined) ? 0 : this._x_offset;
|
|
}
|
|
|
|
set x_offset(offset) {
|
|
this._x_offset = (Number.isInteger(offset)) ? offset : 0;
|
|
}
|
|
|
|
get y_offset() {
|
|
return (this._y_offset === undefined) ? 0 : this._y_offset;
|
|
}
|
|
|
|
set y_offset(offset) {
|
|
this._y_offset = (Number.isInteger(offset)) ? offset : 0;
|
|
}
|
|
|
|
_update() {
|
|
if (this._showing) {
|
|
this._show();
|
|
}
|
|
}
|
|
|
|
_show() {
|
|
if (!this.text && !this.markup) {
|
|
this._hide();
|
|
return;
|
|
}
|
|
|
|
if (!this.bin) {
|
|
this.bin = new St.Bin({
|
|
style_class: 'osd-window gsconnect-tooltip',
|
|
opacity: 232
|
|
});
|
|
|
|
if (this.custom) {
|
|
this.bin.child = this.custom;
|
|
} else {
|
|
this.bin.child = new St.BoxLayout({vertical: false});
|
|
|
|
if (this.gicon) {
|
|
this.bin.child.icon = new St.Icon({
|
|
gicon: this.gicon,
|
|
y_align: St.Align.START
|
|
});
|
|
this.bin.child.icon.set_y_align(Clutter.ActorAlign.START);
|
|
this.bin.child.add_child(this.bin.child.icon);
|
|
}
|
|
|
|
this.label = new St.Label({text: this.markup || this.text});
|
|
this.label.clutter_text.line_wrap = true;
|
|
this.label.clutter_text.line_wrap_mode = Pango.WrapMode.WORD;
|
|
this.label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
|
this.label.clutter_text.use_markup = (this.markup);
|
|
this.bin.child.add_child(this.label);
|
|
}
|
|
|
|
Main.layoutManager.uiGroup.add_child(this.bin);
|
|
Main.layoutManager.uiGroup.set_child_above_sibling(this.bin, null);
|
|
} else if (this.custom) {
|
|
this.bin.child = this.custom;
|
|
} else {
|
|
if (this.bin.child.icon) {
|
|
this.bin.child.icon.destroy();
|
|
}
|
|
|
|
if (this.gicon) {
|
|
this.bin.child.icon = new St.Icon({gicon: this.gicon});
|
|
this.bin.child.insert_child_at_index(this.bin.child.icon, 0);
|
|
}
|
|
|
|
this.label.clutter_text.text = this.markup || this.text;
|
|
this.label.clutter_text.use_markup = (this.markup);
|
|
}
|
|
|
|
// Position tooltip
|
|
let [x, y] = this.parent.get_transformed_position();
|
|
x = (x + (this.parent.width / 2)) - Math.round(this.bin.width / 2);
|
|
|
|
x += this.x_offset;
|
|
y += this.y_offset;
|
|
|
|
// Show tooltip
|
|
if (this._showing) {
|
|
Tweener.addTween(this.bin, {
|
|
x: x,
|
|
y: y,
|
|
time: 0.15,
|
|
transition: 'easeOutQuad'
|
|
});
|
|
} else {
|
|
this.bin.set_position(x, y);
|
|
Tweener.addTween(this.bin, {
|
|
opacity: 232,
|
|
time: 0.15,
|
|
transition: 'easeOutQuad'
|
|
});
|
|
|
|
this._showing = true;
|
|
}
|
|
|
|
// Enable browse mode
|
|
TOOLTIP_BROWSE_MODE = true;
|
|
|
|
if (TOOLTIP_BROWSE_ID) {
|
|
GLib.source_remove(TOOLTIP_BROWSE_ID);
|
|
TOOLTIP_BROWSE_ID = 0;
|
|
}
|
|
|
|
if (this._hoverTimeoutId) {
|
|
GLib.source_remove(this._hoverTimeoutId);
|
|
this._hoverTimeoutId = 0;
|
|
}
|
|
}
|
|
|
|
_hide() {
|
|
if (this.bin) {
|
|
Tweener.addTween(this.bin, {
|
|
opacity: 0,
|
|
time: 0.10,
|
|
transition: 'easeOutQuad',
|
|
onComplete: () => {
|
|
Main.layoutManager.uiGroup.remove_actor(this.bin);
|
|
|
|
if (this.custom) {
|
|
this.bin.remove_child(this.custom);
|
|
}
|
|
|
|
this.bin.destroy();
|
|
delete this.bin;
|
|
}
|
|
});
|
|
}
|
|
|
|
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => {
|
|
TOOLTIP_BROWSE_MODE = false;
|
|
TOOLTIP_BROWSE_ID = 0;
|
|
return false;
|
|
});
|
|
|
|
if (this._hoverTimeoutId) {
|
|
GLib.source_remove(this._hoverTimeoutId);
|
|
this._hoverTimeoutId = 0;
|
|
}
|
|
|
|
this._showing = false;
|
|
this._hoverTimeoutId = 0;
|
|
}
|
|
|
|
_onHover() {
|
|
if (this.parent.hover) {
|
|
if (!this._hoverTimeoutId) {
|
|
if (this._showing) {
|
|
this._show();
|
|
} else {
|
|
this._hoverTimeoutId = GLib.timeout_add(
|
|
GLib.PRIORITY_DEFAULT,
|
|
(TOOLTIP_BROWSE_MODE) ? 60 : 500,
|
|
() => {
|
|
this._show();
|
|
this._hoverTimeoutId = 0;
|
|
return false;
|
|
}
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
this._hide();
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
this.parent.disconnect(this._destroyId);
|
|
this.parent.disconnect(this._hoverId);
|
|
this.parent.disconnect(this._buttonPressEventId);
|
|
|
|
if (this.custom) {
|
|
this.custom.destroy();
|
|
}
|
|
|
|
if (this.bin) {
|
|
Main.layoutManager.uiGroup.remove_actor(this.bin);
|
|
this.bin.destroy();
|
|
}
|
|
|
|
if (this._hoverTimeoutId) {
|
|
GLib.source_remove(this._hoverTimeoutId);
|
|
this._hoverTimeoutId = 0;
|
|
}
|
|
}
|
|
};
|
|
|