gnome-shell/js/ui/overviewControls.js
Georges Basile Stavracas Neto b6337a7bf1 overviewControls: Ease main adjustment when animating to/from overview
Instead of delegating it to ViewSelector, make the transition to and from
overview ease the main state adjustment.

This commit temporarily breaks these animations, but on the other hand
introduces an important feature: ViewSelector is always allocated to the
actual size. This will finally allow for adding WorkspacesView as a child
of WorkspacesDisplay, and finally remove the actual geometry hack, which
is what next commit is about.

This commit also effectively reverts b64103efc.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1624>
2021-02-11 15:50:31 +00:00

208 lines
6.6 KiB
JavaScript

// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported ControlsManager */
const { Clutter, GObject, St } = imports.gi;
const Dash = imports.ui.dash;
const Overview = imports.ui.overview;
const ViewSelector = imports.ui.viewSelector;
var SIDE_CONTROLS_ANIMATION_TIME = Overview.ANIMATION_TIME;
var ControlsState = {
HIDDEN: 0,
WINDOW_PICKER: 1,
APP_GRID: 2,
};
var ControlsManagerLayout = GObject.registerClass(
class ControlsManagerLayout extends Clutter.BoxLayout {
_init(searchEntry, viewSelector, dash, stateAdjustment) {
super._init({ orientation: Clutter.Orientation.VERTICAL });
this._stateAdjustment = stateAdjustment;
this._searchEntry = searchEntry;
this._viewSelector = viewSelector;
this._dash = dash;
stateAdjustment.connect('notify::value', () => this.layout_changed());
}
vfunc_set_container(container) {
this._container = container;
this.hookup_style(container);
}
vfunc_allocate(container, box) {
const childBox = new Clutter.ActorBox();
const { spacing } = this;
const [width, height] = box.get_size();
let availableHeight = height;
// Search entry
const [searchHeight] = this._searchEntry.get_preferred_height(width);
childBox.set_origin(0, 0);
childBox.set_size(width, searchHeight);
this._searchEntry.allocate(childBox);
availableHeight -= searchHeight + spacing;
// Dash
const [, dashHeight] = this._dash.get_preferred_height(width);
childBox.set_origin(0, height - dashHeight);
childBox.set_size(width, dashHeight);
this._dash.allocate(childBox);
availableHeight -= dashHeight + spacing;
// ViewSelector
const initialBox = new Clutter.ActorBox();
initialBox.set_origin(0, 0);
initialBox.set_size(width, height);
childBox.set_origin(0, searchHeight + spacing);
childBox.set_size(width, availableHeight);
const page = this._viewSelector.getActivePage();
const progress = page === ViewSelector.ViewPage.SEARCH
? 1 : Math.min(this._stateAdjustment.value, 1);
const viewSelectorBox = initialBox.interpolate(childBox, progress);
this._viewSelector.allocate(viewSelectorBox);
}
});
var ControlsManager = GObject.registerClass(
class ControlsManager extends St.Widget {
_init() {
super._init({
style_class: 'controls-manager',
x_expand: true,
y_expand: true,
clip_to_allocation: true,
});
this._ignoreShowAppsButtonToggle = false;
this._searchEntry = new St.Entry({
style_class: 'search-entry',
/* Translators: this is the text displayed
in the search entry when no search is
active; it should not exceed ~30
characters. */
hint_text: _('Type to search'),
track_hover: true,
can_focus: true,
});
this._searchEntry.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
const searchEntryBin = new St.Bin({
child: this._searchEntry,
x_align: Clutter.ActorAlign.CENTER,
});
this.dash = new Dash.Dash();
let workspaceManager = global.workspace_manager;
let activeWorkspaceIndex = workspaceManager.get_active_workspace_index();
this._workspaceAdjustment = new St.Adjustment({
actor: this,
value: activeWorkspaceIndex,
lower: 0,
page_increment: 1,
page_size: 1,
step_increment: 0,
upper: workspaceManager.n_workspaces,
});
this._stateAdjustment = new St.Adjustment({
actor: this,
value: ControlsState.WINDOW_PICKER,
lower: ControlsState.HIDDEN,
upper: ControlsState.APP_GRID,
});
this._nWorkspacesNotifyId =
workspaceManager.connect('notify::n-workspaces',
this._updateAdjustment.bind(this));
this.viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
this._workspaceAdjustment,
this.dash.showAppsButton,
this._stateAdjustment);
this.add_child(searchEntryBin);
this.add_child(this.dash);
this.add_child(this.viewSelector);
this.layout_manager = new ControlsManagerLayout(searchEntryBin,
this.viewSelector, this.dash, this._stateAdjustment);
this.dash.showAppsButton.connect('notify::checked',
this._onShowAppsButtonToggled.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
}
_onShowAppsButtonToggled() {
if (this._ignoreShowAppsButtonToggle)
return;
const checked = this.dash.showAppsButton.checked;
const value = checked
? ControlsState.APP_GRID : ControlsState.WINDOW_PICKER;
this._stateAdjustment.remove_transition('value');
this._stateAdjustment.ease(value, {
duration: SIDE_CONTROLS_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
}
_onDestroy() {
global.workspace_manager.disconnect(this._nWorkspacesNotifyId);
}
_updateAdjustment() {
let workspaceManager = global.workspace_manager;
let newNumWorkspaces = workspaceManager.n_workspaces;
let activeIndex = workspaceManager.get_active_workspace_index();
this._workspaceAdjustment.upper = newNumWorkspaces;
// A workspace might have been inserted or removed before the active
// one, causing the adjustment to go out of sync, so update the value
this._workspaceAdjustment.remove_transition('value');
this._workspaceAdjustment.value = activeIndex;
}
animateToOverview() {
this.viewSelector.animateToOverview();
this._stateAdjustment.value = ControlsState.HIDDEN;
this._stateAdjustment.ease(ControlsState.WINDOW_PICKER, {
duration: Overview.ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
}
animateFromOverview() {
this._ignoreShowAppsButtonToggle = true;
this.viewSelector.animateFromOverview();
this._stateAdjustment.ease(ControlsState.HIDDEN, {
duration: Overview.ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onStopped: () => {
this.dash.showAppsButton.checked = false;
this._ignoreShowAppsButtonToggle = false;
},
});
}
get searchEntry() {
return this._searchEntry;
}
});