/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Big = imports.gi.Big; const Clutter = imports.gi.Clutter; const Lang = imports.lang; const Mainloop = imports.mainloop; const Shell = imports.gi.Shell; const Signals = imports.signals; const Tweener = imports.ui.tweener; const DEFAULT_BUTTON_COLOR = new Clutter.Color(); DEFAULT_BUTTON_COLOR.from_pixel(0xeeddcc66); const DEFAULT_PRESSED_BUTTON_COLOR = new Clutter.Color(); DEFAULT_PRESSED_BUTTON_COLOR.from_pixel(0xccbbaa66); const DEFAULT_TEXT_COLOR = new Clutter.Color(); DEFAULT_TEXT_COLOR.from_pixel(0x000000ff); const DEFAULT_FONT = 'Sans Bold 16px'; // Padding on the left and right side of the button. const SIDE_PADDING = 14; function Button(widget, buttonColor, pressedButtonColor, textColor, font) { this._init(widget, buttonColor, pressedButtonColor, textColor, font); } Button.prototype = { _init : function(widgetOrText, buttonColor, pressedButtonColor, textColor, font) { let me = this; this._buttonColor = buttonColor if (buttonColor == null) this._buttonColor = DEFAULT_BUTTON_COLOR; this._pressedButtonColor = pressedButtonColor if (pressedButtonColor == null) this._pressedButtonColor = DEFAULT_PRESSED_BUTTON_COLOR; this._textColor = textColor; if (textColor == null) this._textColor = DEFAULT_TEXT_COLOR; this._font = font; if (font == null) this._font = DEFAULT_FONT; this._isBetweenPressAndRelease = false; this._mouseIsOverButton = false; this.actor = new Shell.ButtonBox({ reactive: true, corner_radius: 5, padding_left: SIDE_PADDING, padding_right: SIDE_PADDING, orientation: Big.BoxOrientation.HORIZONTAL, y_align: Big.BoxAlignment.CENTER }); if (typeof widgetOrText == 'string') { this._widget = new Clutter.Text({ font_name: this._font, color: this._textColor, text: widgetOrText }); } else { this._widget = widgetOrText; } this.actor.append(this._widget, Big.BoxPackFlags.EXPAND); this.actor.connect('notify::hover', Lang.bind(this, this._updateColors)); this.actor.connect('notify::pressed', Lang.bind(this, this._updateColors)); this.actor.connect('notify::active', Lang.bind(this, this._updateColors)); }, _updateColors : function() { if (this.actor.active || this.actor.pressed) this.actor.backgroundColor = this._pressedButtonColor; else if (this.actor.hover) this.actor.backgroundColor = this._buttonColor; else this.actor.backgroundColor = null; } }; Signals.addSignalMethods(Button.prototype); /* Delay before the icon should appear, in seconds after the pointer has entered the parent */ const ANIMATION_TIME = 0.25; /* This is an icon button that fades in/out when mouse enters/leaves the parent. * A delay is used before the fading starts. You can force it to be shown if needed. * * parent -- used to show/hide the button depending on mouse entering/leaving it * size -- size in pixels of both the button and the icon it contains * texture -- optional, must be used if the texture for the icon is already created (else, use setIconFromName) */ function iconButton(parent, size, texture) { this._init(parent, size, texture); } iconButton.prototype = { _init : function(parent, size, texture) { this._size = size; if (texture) this.actor = texture; else this.actor = new Clutter.Texture({ width: this._size, height: this._size }); this.actor.set_reactive(true); this.actor.set_opacity(0); parent.connect("enter-event", Lang.bind(this, function(actor, event) { this._shouldHide = false; // Nothing to do if the cursor has come back from a child of the parent actor if (actor.get_children().indexOf(Shell.get_event_related(event)) != -1) return; this._fadeIn(); })); parent.connect("leave-event", Lang.bind(this, function(actor, event) { // Nothing to do if the cursor has merely entered a child of the parent actor if (actor.get_children().indexOf(Shell.get_event_related(event)) != -1) return; // Remember that we should not be visible to hide the button if forceShow is unset if (this._forceShow) { this._shouldHide = true; return; } this._fadeOut(); })); }, /// Private methods /// setIconFromName : function(iconName) { let iconTheme = Gtk.IconTheme.get_default(); let iconInfo = iconTheme.lookup_icon(iconName, this._size, 0); if (!iconInfo) return; let iconPath = iconInfo.get_filename(); this.actor.set_from_file(iconPath); }, // Useful if we want to show the button immediately, // e.g. in case the mouse is already in the parent when the button is created show : function() { this.actor.set_opacity(255); }, // If show is true, prevents the button from fading out forceShow : function(show) { this._forceShow = show; // Hide the button if it should have been hidden under normal conditions if (!this._forceShow && this._shouldHide) { this._fadeOut(); } }, /// Private methods /// _fadeIn : function() { Tweener.removeTweens(this.actor); Tweener.addTween(this.actor, { opacity: 255, time: ANIMATION_TIME, transition :"easeInQuad" }); }, _fadeOut : function() { Tweener.removeTweens(this.actor); Tweener.addTween(this.actor, { opacity: 0, time: ANIMATION_TIME, transition :"easeOutQuad" }); } };