From 4b01bb6f9995f3012fcf6033e633ba10572a68f6 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Thu, 21 Feb 2019 08:44:34 +0100 Subject: [PATCH] ripples: Add a new class ripples So we can use the same code for both the ripples in overview and the pointer location. https://gitlab.gnome.org/GNOME/gnome-shell/issues/981 https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/413 https://gitlab.gnome.org/GNOME/mutter/merge_requests/453 https://gitlab.gnome.org/GNOME/gsettings-desktop-schemas/merge_requests/19 https://gitlab.gnome.org/GNOME/gnome-settings-daemon/merge_requests/86 --- js/js-resources.gresource.xml | 1 + js/ui/ripples.js | 97 +++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 js/ui/ripples.js diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml index 836d1c674..135b8e885 100644 --- a/js/js-resources.gresource.xml +++ b/js/js-resources.gresource.xml @@ -84,6 +84,7 @@ ui/pointerWatcher.js ui/popupMenu.js ui/remoteSearch.js + ui/ripples.js ui/runDialog.js ui/screenShield.js ui/screencast.js diff --git a/js/ui/ripples.js b/js/ui/ripples.js new file mode 100644 index 000000000..37d7362de --- /dev/null +++ b/js/ui/ripples.js @@ -0,0 +1,97 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const { Clutter, St } = imports.gi; +const Tweener = imports.ui.tweener; + +// Shamelessly copied from the layout "hotcorner" ripples implementation +var Ripples = class Ripples { + constructor(px, py, styleClass) { + this._x = 0; + this._y = 0; + + this._px = px; + this._py = py; + + this._ripple1 = new St.BoxLayout({ style_class: styleClass, + opacity: 0, + can_focus: false, + reactive: false, + visible: false }); + this._ripple1.set_pivot_point(px, py); + + this._ripple2 = new St.BoxLayout({ style_class: styleClass, + opacity: 0, + can_focus: false, + reactive: false, + visible: false }); + this._ripple2.set_pivot_point(px, py); + + this._ripple3 = new St.BoxLayout({ style_class: styleClass, + opacity: 0, + can_focus: false, + reactive: false, + visible: false }); + this._ripple3.set_pivot_point(px, py); + } + + _animRipple(ripple, delay, time, startScale, startOpacity, finalScale) { + // We draw a ripple by using a source image and animating it scaling + // outwards and fading away. We want the ripples to move linearly + // or it looks unrealistic, but if the opacity of the ripple goes + // linearly to zero it fades away too quickly, so we use Tweener's + // 'onUpdate' to give a non-linear curve to the fade-away and make + // it more visible in the middle section. + + ripple.x = this._x; + ripple.y = this._y; + ripple._opacity = startOpacity; + ripple.visible = true; + ripple.opacity = 255 * Math.sqrt(startOpacity); + ripple.scale_x = ripple.scale_y = startScale; + ripple.set_translation( - this._px * ripple.width, - this._py * ripple.height, 0.0); + + Tweener.addTween(ripple, { _opacity: 0, + scale_x: finalScale, + scale_y: finalScale, + delay: delay, + time: time, + transition: 'linear', + onUpdate() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); }, + onComplete() { ripple.visible = false; } }); + } + + addTo(stage) { + if (this._stage !== undefined) { + throw new Error('Ripples already added'); + return; + } + + this._stage = stage; + this._stage.add_actor(this._ripple1); + this._stage.add_actor(this._ripple2); + this._stage.add_actor(this._ripple3); + } + + playAnimation(x, y) { + if (this._stage === undefined) { + throw new Error('Ripples not added'); + return; + } + + this._x = x; + this._y = y; + + this._stage.set_child_above_sibling(this._ripple1, null); + this._stage.set_child_above_sibling(this._ripple2, this._ripple1); + this._stage.set_child_above_sibling(this._ripple3, this._ripple2); + + // Show three concentric ripples expanding outwards; the exact + // parameters were found by trial and error, so don't look + // for them to make perfect sense mathematically + + // delay time scale opacity => scale + this._animRipple(this._ripple1, 0.0, 0.83, 0.25, 1.0, 1.5); + this._animRipple(this._ripple2, 0.05, 1.0, 0.0, 0.7, 1.25); + this._animRipple(this._ripple3, 0.35, 1.0, 0.0, 0.3, 1); + } +};