gnome-shell/js/ui/pageIndicators.js
Florian Müllner 476816732f cleanup: Use milliseconds for animation times
The different units - seconds for Tweener and milliseconds for
timeouts - are not a big issue currently, as there is little
overlap. However this will change when we start using Clutter's
own animation framework (which uses milliseconds as well), in
particular where constants are shared between modules.

In order to prepare for the transition, define all animation times
as milliseconds and adjust them when passing them to Tweener.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/663
2019-08-05 21:55:20 +00:00

142 lines
5.3 KiB
JavaScript

// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported PageIndicators, AnimatedPageIndicators */
const { Clutter, GObject, St } = imports.gi;
const Tweener = imports.ui.tweener;
const { ANIMATION_TIME_OUT, ANIMATION_MAX_DELAY_OUT_FOR_ITEM, AnimationDirection } = imports.ui.iconGrid;
var INDICATORS_BASE_TIME = 250;
var INDICATORS_BASE_TIME_OUT = 125;
var INDICATORS_ANIMATION_DELAY = 125;
var INDICATORS_ANIMATION_DELAY_OUT = 62.5;
var INDICATORS_ANIMATION_MAX_TIME = 750;
var SWITCH_TIME = 400;
var INDICATORS_ANIMATION_MAX_TIME_OUT =
Math.min (SWITCH_TIME,
ANIMATION_TIME_OUT + ANIMATION_MAX_DELAY_OUT_FOR_ITEM);
var ANIMATION_DELAY = 100;
var PageIndicators = GObject.registerClass({
Signals: { 'page-activated': { param_types: [GObject.TYPE_INT] } }
}, class PageIndicators extends St.BoxLayout {
_init(vertical = true) {
super._init({ style_class: 'page-indicators',
vertical,
x_expand: true, y_expand: true,
x_align: vertical ? Clutter.ActorAlign.END : Clutter.ActorAlign.CENTER,
y_align: vertical ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.END,
reactive: true,
clip_to_allocation: true });
this._nPages = 0;
this._currentPage = undefined;
this._reactive = true;
this._reactive = true;
}
vfunc_get_preferred_height(forWidth) {
// We want to request the natural height of all our children as our
// natural height, so we chain up to St.BoxLayout, but we only request 0
// as minimum height, since it's not that important if some indicators
// are not shown
let [, natHeight] = super.vfunc_get_preferred_height(forWidth);
return [0, natHeight];
}
setReactive(reactive) {
let children = this.get_children();
for (let i = 0; i < children.length; i++)
children[i].reactive = reactive;
this._reactive = reactive;
}
setNPages(nPages) {
if (this._nPages == nPages)
return;
let diff = nPages - this._nPages;
if (diff > 0) {
for (let i = 0; i < diff; i++) {
let pageIndex = this._nPages + i;
let indicator = new St.Button({ style_class: 'page-indicator',
button_mask: St.ButtonMask.ONE |
St.ButtonMask.TWO |
St.ButtonMask.THREE,
toggle_mode: true,
reactive: this._reactive,
checked: pageIndex == this._currentPage });
indicator.child = new St.Widget({ style_class: 'page-indicator-icon' });
indicator.connect('clicked', () => {
this.emit('page-activated', pageIndex);
});
this.add_actor(indicator);
}
} else {
let children = this.get_children().splice(diff);
for (let i = 0; i < children.length; i++)
children[i].destroy();
}
this._nPages = nPages;
this.visible = (this._nPages > 1);
}
setCurrentPage(currentPage) {
this._currentPage = currentPage;
let children = this.get_children();
for (let i = 0; i < children.length; i++)
children[i].set_checked(i == this._currentPage);
}
});
var AnimatedPageIndicators = GObject.registerClass(
class AnimatedPageIndicators extends PageIndicators {
_init() {
super._init(true);
this.connect('notify::mapped', () => {
this.animateIndicators(AnimationDirection.IN);
});
}
animateIndicators(animationDirection) {
if (!this.mapped)
return;
let children = this.get_children();
if (children.length == 0)
return;
for (let i = 0; i < this._nPages; i++)
Tweener.removeTweens(children[i]);
let offset;
if (this.get_text_direction() == Clutter.TextDirection.RTL)
offset = -children[0].width;
else
offset = children[0].width;
let isAnimationIn = animationDirection == AnimationDirection.IN;
let delay = isAnimationIn ? INDICATORS_ANIMATION_DELAY :
INDICATORS_ANIMATION_DELAY_OUT;
let baseTime = isAnimationIn ? INDICATORS_BASE_TIME : INDICATORS_BASE_TIME_OUT;
let totalAnimationTime = baseTime + delay * this._nPages;
let maxTime = isAnimationIn ? INDICATORS_ANIMATION_MAX_TIME :
INDICATORS_ANIMATION_MAX_TIME_OUT;
if (totalAnimationTime > maxTime)
delay -= (totalAnimationTime - maxTime) / this._nPages;
for (let i = 0; i < this._nPages; i++) {
children[i].translation_x = isAnimationIn ? offset : 0;
Tweener.addTween(children[i], {
translation_x: isAnimationIn ? 0 : offset,
time: (baseTime + delay * i) / 1000,
transition: 'easeInOutQuad',
delay: isAnimationIn ? ANIMATION_DELAY / 1000 : 0
});
}
}
});