[gnome-shell/gbsneto/40-stuff: 17/68] workspacesView: Use side-by-side layout
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/gbsneto/40-stuff: 17/68] workspacesView: Use side-by-side layout
- Date: Wed, 20 Jan 2021 22:41:07 +0000 (UTC)
commit 50d1831e264ef9e7ba1ca6bc5676bf71fb2f5b98
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Tue Dec 29 18:05:29 2020 -0300
workspacesView: Use side-by-side layout
Currently, WorkspacesView positions each workspace on a
per-page layout, each page with the allocated width and
height of WorkspaceView. This layout doesn't work well
with horizontal workspaces.
Layout workspaces side by side, instead of per page. The
layout is influenced by a "snap axis", which reflect the
different behaviors exposed in the mockup. This axis
represents which sides of the workspace will be used to
fill the available space. The vertical axis makes the
workspaces fill the available space vertically, event if
it means overflowing horizontally; and vice-versa.
The vertical snap axis is always used for now. Next commits
will make it switch to the horizontal snap axis when in the
app grid state, and when dragging windows.
The translation_{x,y} also needed to reflect the switch to
a side-by-side layout, and use the geometry of the workspaces
to determine the offset. Notice that, when the snap axis is
horizontal, there's no translation applied.
js/ui/workspacesView.js | 182 ++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 167 insertions(+), 15 deletions(-)
---
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
index 88fc593504..e9493da315 100644
--- a/js/ui/workspacesView.js
+++ b/js/ui/workspacesView.js
@@ -13,6 +13,9 @@ var SCROLL_TIMEOUT_TIME = 150;
const MUTTER_SCHEMA = 'org.gnome.mutter';
+const WORKSPACE_MIN_SPACING = 24;
+const WORKSPACE_MAX_SPACING = 80;
+
var WorkspacesViewBase = GObject.registerClass({
GTypeFlags: GObject.TypeFlags.ABSTRACT,
}, class WorkspacesViewBase extends St.Widget {
@@ -65,12 +68,17 @@ var WorkspacesViewBase = GObject.registerClass({
var WorkspacesView = GObject.registerClass(
class WorkspacesView extends WorkspacesViewBase {
- _init(monitorIndex, scrollAdjustment) {
+ _init(monitorIndex, scrollAdjustment, snapAdjustment) {
let workspaceManager = global.workspace_manager;
super._init(monitorIndex);
this.clip_to_allocation = true;
+ this._snapAdjustment = snapAdjustment;
+ this._snapNotifyId = this._snapAdjustment.connect('notify::value', () => {
+ this.queue_relayout();
+ });
+
this._animating = false; // tweening
this._gestureActive = false; // touch(pad) gestures
@@ -97,26 +105,148 @@ class WorkspacesView extends WorkspacesViewBase {
this._activeWorkspaceChanged.bind(this));
}
+ _getHorizontalSnapBox(box, spacing, vertical) {
+ const { nWorkspaces } = global.workspaceManager;
+ const [width, height] = box.get_size();
+ const [workspace] = this._workspaces;
+
+ const availableHeight = height - spacing * (nWorkspaces + 1);
+ const availableWidth = width - spacing * (nWorkspaces + 1);
+
+ const horizontalBox = new Clutter.ActorBox();
+
+ let x1 = box.x1;
+ let y1 = box.y1;
+
+ if (vertical) {
+ let workspaceHeight = availableHeight / nWorkspaces;
+ let [, workspaceWidth] =
+ workspace.get_preferred_width(workspaceHeight);
+
+ y1 = spacing;
+ if (workspaceWidth > width) {
+ [, workspaceHeight] = workspace.get_preferred_height(width);
+ y1 += Math.max((availableHeight - workspaceHeight * nWorkspaces) / 2, 0);
+ }
+
+ horizontalBox.set_size(width, workspaceHeight);
+ } else {
+ let workspaceWidth = availableWidth / nWorkspaces;
+ let [, workspaceHeight] =
+ workspace.get_preferred_height(workspaceWidth);
+
+ x1 = spacing;
+ if (workspaceHeight > height) {
+ [, workspaceWidth] = workspace.get_preferred_width(height);
+ x1 += Math.max((availableWidth - workspaceWidth * nWorkspaces) / 2, 0);
+ }
+
+ horizontalBox.set_size(workspaceWidth, height);
+ }
+
+ horizontalBox.set_origin(x1, y1);
+
+ return horizontalBox;
+ }
+
+ _getVerticalSnapBox(box, spacing, vertical) {
+ const [width, height] = box.get_size();
+ const [workspace] = this._workspaces;
+
+ // Snapped in the vertical axis also means horizontally centered
+ let x1 = box.x1;
+ let y1 = box.y1;
+ if (vertical) {
+ const [, workspaceHeight] = workspace.get_preferred_height(width);
+ y1 += (height - workspaceHeight) / 2;
+ } else {
+ const [, workspaceWidth] = workspace.get_preferred_width(height);
+ x1 += (width - workspaceWidth) / 2;
+ }
+
+ const verticalBox = new Clutter.ActorBox({ x1, y1 });
+
+ if (vertical) {
+ const [, workspaceHeight] = workspace.get_preferred_height(width);
+ verticalBox.set_size(width, workspaceHeight);
+ } else {
+ const [, workspaceWidth] = workspace.get_preferred_width(height);
+ verticalBox.set_size(workspaceWidth, height);
+ }
+
+ return verticalBox;
+ }
+
+ _getSpacing(box, snapAxis, vertical) {
+ const [width, height] = box.get_size();
+ const [workspace] = this._workspaces;
+
+ let availableSpace;
+ let workspaceSize;
+ if (vertical) {
+ [, workspaceSize] = workspace.get_preferred_height(width);
+ availableSpace = (height - workspaceSize) / 2;
+ } else {
+ [, workspaceSize] = workspace.get_preferred_width(height);
+ availableSpace = (width - workspaceSize) / 2;
+ }
+
+ const spacing = (availableSpace - workspaceSize * 0.05) * snapAxis;
+
+ return Math.clamp(spacing, WORKSPACE_MIN_SPACING, WORKSPACE_MAX_SPACING);
+ }
+
vfunc_allocate(box) {
this.set_allocation(box);
if (this.get_n_children() === 0)
return;
- const { workspaceManager } = global;
- const { nWorkspaces } = workspaceManager;
-
- const vertical = workspaceManager.layout_rows === -1;
+ const vertical = global.workspaceManager.layout_rows === -1;
const rtl = this.text_direction === Clutter.TextDirection.RTL;
- this._workspaces.forEach((child, index) => {
- if (rtl && !vertical)
- index = nWorkspaces - index - 1;
+ const snapProgress = this._snapAdjustment.value;
+
+ const horizontalSpacing =
+ this._getSpacing(box, Clutter.Orientation.HORIZONTAL, vertical);
+ const horizontalBox =
+ this._getHorizontalSnapBox(box, horizontalSpacing, vertical);
+
+ const verticalSpacing =
+ this._getSpacing(box, Clutter.Orientation.VERTICAL, vertical);
+ const verticalBox =
+ this._getVerticalSnapBox(box, verticalSpacing, vertical);
+
+ // Account for RTL locales by reversing the list
+ const workspaces = this._workspaces.slice();
+ if (rtl)
+ workspaces.reverse();
+
+ workspaces.forEach(child => {
+ if (snapProgress === 0)
+ box = horizontalBox;
+ else if (snapProgress === 1)
+ box = verticalBox;
+ else
+ box = horizontalBox.interpolate(verticalBox, snapProgress);
- box.set_origin(
- vertical ? 0 : index * this.width,
- vertical ? index * this.height : 0);
child.allocate_align_fill(box, 0.5, 0.5, false, false);
+
+ if (vertical) {
+ verticalBox.set_origin(
+ verticalBox.x1,
+ verticalBox.y1 + verticalBox.get_height() + verticalSpacing);
+ horizontalBox.set_origin(
+ horizontalBox.x1,
+ horizontalBox.y1 + horizontalBox.get_height() + horizontalSpacing);
+ } else {
+ verticalBox.set_origin(
+ verticalBox.x1 + verticalBox.get_width() + verticalSpacing,
+ verticalBox.y1);
+ horizontalBox.set_origin(
+ horizontalBox.x1 + horizontalBox.get_width() + horizontalSpacing,
+ horizontalBox.y1);
+ }
});
this._updateScrollPosition();
@@ -199,6 +329,7 @@ class WorkspacesView extends WorkspacesViewBase {
super._onDestroy();
this._scrollAdjustment.disconnect(this._onScrollId);
+ this._snapAdjustment.disconnect(this._snapNotifyId);
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
let workspaceManager = global.workspace_manager;
workspaceManager.disconnect(this._updateWorkspacesId);
@@ -258,14 +389,28 @@ class WorkspacesView extends WorkspacesViewBase {
const workspaceManager = global.workspace_manager;
const vertical = workspaceManager.layout_rows === -1;
const rtl = this.text_direction === Clutter.TextDirection.RTL;
- const progress = vertical || !rtl
+ const snapProgress = this._snapAdjustment.value;
+ let progress = vertical || !rtl
? adj.value : adj.upper - adj.value;
+ progress = progress / (adj.upper - 1) * snapProgress;
+
+ // Use workspaces geometry to determine the size to offset
+ const firstWorkspaceBox = rtl
+ ? this._workspaces[this._workspaces.length - 1].allocation
+ : this._workspaces[0].allocation;
+ const lastWorkspaceBox = rtl
+ ? this._workspaces[0].allocation
+ : this._workspaces[this._workspaces.length - 1].allocation;
+ const [workspaceWidth, workspaceHeight] = firstWorkspaceBox.get_size();
+ const size = vertical
+ ? lastWorkspaceBox.y2 - firstWorkspaceBox.y1 - workspaceHeight
+ : lastWorkspaceBox.x2 - firstWorkspaceBox.x1 - workspaceWidth;
for (const ws of this._workspaces) {
if (vertical)
- ws.translation_y = -progress * this.height;
+ ws.translation_y = -progress * size;
else
- ws.translation_x = -progress * this.width;
+ ws.translation_x = -progress * size;
}
}
});
@@ -311,6 +456,13 @@ class WorkspacesDisplay extends St.Widget {
});
this.connect('notify::allocation', this._updateWorkspacesActualGeometry.bind(this));
+ this._snapAdjustment = new St.Adjustment({
+ actor: this,
+ value: Clutter.Orientation.VERTICAL,
+ lower: Clutter.Orientation.HORIZONTAL,
+ upper: Clutter.Orientation.VERTICAL,
+ });
+
Main.overview.connect('relayout',
() => this._updateWorkspacesActualGeometry());
@@ -606,7 +758,7 @@ class WorkspacesDisplay extends St.Widget {
if (this._workspacesOnlyOnPrimary && i != this._primaryIndex)
view = new ExtraWorkspaceView(i);
else
- view = new WorkspacesView(i, this._scrollAdjustment);
+ view = new WorkspacesView(i, this._scrollAdjustment, this._snapAdjustment);
this._workspacesViews.push(view);
Main.layoutManager.overviewGroup.add_actor(view);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]