gnome-shell/js/ui/pageIndicators.js
Carlos Garnacho fab390826e appDisplay: Separate PageIndicators to a separate file
In order to cater for emoji panel usage, we want something like PageIndicators
except:
- It should have horizontal disposition
- It should not be animatable (?)
- It should not be reactive

Separated PageIndicators into a base, non-animated widget, and an
AnimatedPageIndicators that can be used on appDisplay.js. Reactiveness is
set through an extra method, and layout is set as a construct argument.
2019-02-05 16:25:54 +01:00

143 lines
5.3 KiB
JavaScript

// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GObject = imports.gi.GObject;
const St = imports.gi.St;
const Tweener = imports.ui.tweener;
const { ANIMATION_TIME_OUT, ANIMATION_MAX_DELAY_OUT_FOR_ITEM, AnimationDirection } = imports.ui.iconGrid;
var INDICATORS_BASE_TIME = 0.25;
var INDICATORS_BASE_TIME_OUT = 0.125;
var INDICATORS_ANIMATION_DELAY = 0.125;
var INDICATORS_ANIMATION_DELAY_OUT = 0.0625;
var INDICATORS_ANIMATION_MAX_TIME = 0.75;
var SWITCH_TIME = 0.4;
var INDICATORS_ANIMATION_MAX_TIME_OUT =
Math.min (SWITCH_TIME,
ANIMATION_TIME_OUT + ANIMATION_MAX_DELAY_OUT_FOR_ITEM);
var ANIMATION_DELAY = 0.1;
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,
transition: 'easeInOutQuad',
delay: isAnimationIn ? ANIMATION_DELAY : 0
});
}
}
});