[gnome-shell/gbsneto/folders-as-dialogs: 1/8] appDisplay: Transform folder into a dialog
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/gbsneto/folders-as-dialogs: 1/8] appDisplay: Transform folder into a dialog
- Date: Thu, 9 Jan 2020 19:13:57 +0000 (UTC)
commit a6b130d0341e8e9c45c5cafe9e71fd5cd93d4891
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Thu Dec 12 15:54:18 2019 -0300
appDisplay: Transform folder into a dialog
Make the AppFolderPopup behave much more like a dialog than a
popup itself. To do that, remove the BoxPointer and replace it
by a StBoxLayout. The dialog is is also constrained to the
primary monitor.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896
data/theme/gnome-shell-sass/widgets/_app-grid.scss | 18 +-
js/ui/appDisplay.js | 223 +++++++++++----------
2 files changed, 123 insertions(+), 118 deletions(-)
---
diff --git a/data/theme/gnome-shell-sass/widgets/_app-grid.scss
b/data/theme/gnome-shell-sass/widgets/_app-grid.scss
index 83986cc83e..842d6ac05e 100644
--- a/data/theme/gnome-shell-sass/widgets/_app-grid.scss
+++ b/data/theme/gnome-shell-sass/widgets/_app-grid.scss
@@ -86,14 +86,16 @@ $app_grid_fg_color: #fff;
}
// expanded folder
-.app-folder-popup {
- -arrow-border-radius: 8px;
- -arrow-background-color: transparentize(darken($osd_bg_color,10%), 0.5);
- -arrow-base: 24px;
- -arrow-rise: 11px;
+.app-folder-dialog {
+ border-radius: 8px;
+ spacing: 24px;
+ background-color: transparentize(darken($osd_bg_color,10%), 0.4);
+}
+.app-folder-dialog-container {
+ padding: 12px;
+ width: 800px;
+ height: 600px;
}
-
-.app-folder-popup-bin { padding: $base_padding - 1px; }
.app-folder-icon {
padding: $base_padding;
@@ -205,4 +207,4 @@ $app_grid_fg_color: #fff;
&:last-child {
border-radius: 0 $base_border_radius $base_border_radius 0;
}
-}
\ No newline at end of file
+}
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 5c60a3ebbc..80b8064b8c 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -5,10 +5,10 @@ const { Clutter, Gio, GLib, GObject, Graphene, Meta, Shell, St } = imports.gi;
const Signals = imports.signals;
const AppFavorites = imports.ui.appFavorites;
-const BoxPointer = imports.ui.boxpointer;
const DND = imports.ui.dnd;
const GrabHelper = imports.ui.grabHelper;
const IconGrid = imports.ui.iconGrid;
+const Layout = imports.ui.layout;
const Main = imports.ui.main;
const PageIndicators = imports.ui.pageIndicators;
const PopupMenu = imports.ui.popupMenu;
@@ -40,6 +40,8 @@ var PAGE_SWITCH_TIME = 250;
var APP_ICON_SCALE_IN_TIME = 500;
var APP_ICON_SCALE_IN_DELAY = 700;
+const FOLDER_DIALOG_ANIMATION_TIME = 200;
+
const OVERSHOOT_THRESHOLD = 20;
const OVERSHOOT_TIMEOUT = 1000;
@@ -1422,10 +1424,10 @@ class FolderView extends BaseAppView {
this._scrollView.update_fade_effect(fadeOffset, 0);
// Set extra padding to avoid popup or close button being cut off
- this._grid.topPadding = Math.max(this._grid.topPadding - this._offsetForEachSide, 0);
- this._grid.bottomPadding = Math.max(this._grid.bottomPadding - this._offsetForEachSide, 0);
- this._grid.leftPadding = Math.max(this._grid.leftPadding - this._offsetForEachSide, 0);
- this._grid.rightPadding = Math.max(this._grid.rightPadding - this._offsetForEachSide, 0);
+ this._grid.topPadding = Math.max(this._grid.topPadding, 0);
+ this._grid.bottomPadding = Math.max(this._grid.bottomPadding, 0);
+ this._grid.leftPadding = Math.max(this._grid.leftPadding, 0);
+ this._grid.rightPadding = Math.max(this._grid.rightPadding, 0);
this.set_width(this.usedWidth());
this.set_height(this.usedHeight());
@@ -1440,7 +1442,7 @@ class FolderView extends BaseAppView {
let contentBox = this.get_theme_node().get_content_box(pageBox);
// We only can show icons inside the collection view boxPointer
// so we have to subtract the required padding etc of the boxpointer
- return [(contentBox.x2 - contentBox.x1) - 2 * this._offsetForEachSide, (contentBox.y2 -
contentBox.y1) - 2 * this._offsetForEachSide];
+ return [contentBox.x2 - contentBox.x1, contentBox.y2 - contentBox.y1];
}
usedWidth() {
@@ -1458,10 +1460,6 @@ class FolderView extends BaseAppView {
return Math.min(this._grid.nRows(availWidthPerPage), maxRows);
}
- setPaddingOffsets(offset) {
- this._offsetForEachSide = offset;
- }
-
_loadApps() {
let apps = [];
let excludedApps = this._folder.get_strv('excluded-apps');
@@ -1617,7 +1615,7 @@ var FolderIcon = GObject.registerClass({
this._removeMenuTimeout();
this._ensurePopup();
this.view._scrollView.vscroll.adjustment.value = 0;
- this._openSpaceForPopup();
+ this._popup.popup();
}
getAppIds() {
@@ -1712,65 +1710,21 @@ var FolderIcon = GObject.registerClass({
}
_popupHeight() {
- let usedHeight = this.view.usedHeight() + this._popup.getOffset(St.Side.TOP) +
this._popup.getOffset(St.Side.BOTTOM);
+ let usedHeight = this.view.usedHeight();
return usedHeight;
}
- _openSpaceForPopup() {
- this._spaceReadySignalId = this._parentView.connect('space-ready', () => {
- this._parentView.disconnect(this._spaceReadySignalId);
- this._spaceReadySignalId = 0;
- this._popup.popup();
- this._updatePopupPosition();
- });
- this._parentView.openSpaceForPopup(this, this._boxPointerArrowside,
this.view.nRowsDisplayedAtOnce());
- }
-
- _calculateBoxPointerArrowSide() {
- let spaceTop = this.y - this._parentView.getCurrentPageY();
- let spaceBottom = this._parentView.height - (spaceTop + this.height);
-
- return spaceTop > spaceBottom ? St.Side.BOTTOM : St.Side.TOP;
- }
-
- _updatePopupSize() {
- // StWidget delays style calculation until needed, make sure we use the correct values
- this.view._grid.ensure_style();
-
- let offsetForEachSide = Math.ceil((this._popup.getOffset(St.Side.TOP) +
- this._popup.getOffset(St.Side.BOTTOM) -
- this._popup.getCloseButtonOverlap()) / 2);
- // Add extra padding to prevent boxpointer decorations and close button being cut off
- this.view.setPaddingOffsets(offsetForEachSide);
- this.view.adaptToSize(this._parentAvailableWidth, this._parentAvailableHeight);
- }
-
- _updatePopupPosition() {
- if (!this._popup)
- return;
-
- if (this._boxPointerArrowside == St.Side.BOTTOM)
- this._popup.y = this.allocation.y1 + this.translation_y - this._popupHeight();
- else
- this._popup.y = this.allocation.y1 + this.translation_y + this.height;
- }
-
_ensurePopup() {
if (this._popup && !this._popupInvalidated)
return;
- this._boxPointerArrowside = this._calculateBoxPointerArrowSide();
if (!this._popup) {
- this._popup = new AppFolderPopup(this, this._boxPointerArrowside);
+ this._popup = new AppFolderPopup(this);
this._parentView.addFolderPopup(this._popup);
this._popup.connect('open-state-changed', (popup, isOpen) => {
if (!isOpen)
this.checked = false;
});
- } else {
- this._popup.updateArrowSide(this._boxPointerArrowside);
}
- this._updatePopupSize();
- this._updatePopupPosition();
this._popupInvalidated = false;
}
@@ -1961,43 +1915,35 @@ var AppFolderPopup = GObject.registerClass({
'open-state-changed': { param_types: [GObject.TYPE_BOOLEAN] },
},
}, class AppFolderPopup extends St.Widget {
- _init(source, side) {
+ _init(source) {
super._init({
layout_manager: new Clutter.BinLayout(),
+ style_class: 'app-folder-dialog-container',
visible: false,
- // We don't want to expand really, but look
- // at the layout manager of our parent...
- //
- // DOUBLE HACK: if you set one, you automatically
- // get the effect for the other direction too, so
- // we need to set the y_align
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
- y_align: Clutter.ActorAlign.START,
+ y_align: Clutter.ActorAlign.CENTER,
});
+ this.add_constraint(new Layout.MonitorConstraint({
+ primary: true,
+ }));
+
this._source = source;
this._view = source.view;
- this._arrowSide = side;
this._isOpen = false;
this.parentOffset = 0;
- this._boxPointer = new BoxPointer.BoxPointer(this._arrowSide, {
- style_class: 'app-folder-popup-bin',
+ this._viewBox = new St.BoxLayout({
+ style_class: 'app-folder-dialog',
x_expand: true,
+ y_expand: true,
+ x_align: Clutter.ActorAlign.FILL,
+ y_align: Clutter.ActorAlign.FILL,
});
-
- this._boxPointer.style_class = 'app-folder-popup';
- this.add_actor(this._boxPointer);
- this._boxPointer.bin.set_child(this._view);
-
- this.closeButton = Util.makeCloseButton(this._boxPointer);
- this.closeButton.connect('clicked', this.popdown.bind(this));
- this.add_actor(this.closeButton);
-
- this._boxPointer.bind_property('opacity', this.closeButton, 'opacity',
- GObject.BindingFlags.SYNC_CREATE);
+ this.add_child(this._viewBox);
+ this._viewBox.add_child(this._view);
global.focus_manager.add_group(this);
@@ -2006,6 +1952,75 @@ var AppFolderPopup = GObject.registerClass({
});
this._grabHelper.addActor(Main.layoutManager.overviewGroup);
this.connect('destroy', this._onDestroy.bind(this));
+
+ this._needsZoomAndFade = false;
+ }
+
+ _zoomAndFadeIn() {
+ let [sourceX, sourceY] =
+ this._source.get_transformed_position();
+ let [dialogX, dialogY] =
+ this.get_transformed_position();
+
+ this.set({
+ translation_x: sourceX - dialogX,
+ translation_y: sourceY - dialogY,
+ scale_x: this._source.width / this.width,
+ scale_y: this._source.height / this.height,
+ opacity: 0,
+ });
+
+ this.ease({
+ translation_x: 0,
+ translation_y: 0,
+ scale_x: 1,
+ scale_y: 1,
+ opacity: 255,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ });
+
+ this._needsZoomAndFade = false;
+
+ this._sourceMappedId = this._source.connect('notify::mapped',
+ this._zoomAndFadeOut.bind(this));
+ }
+
+ _zoomAndFadeOut() {
+ if (!this._isOpen)
+ return;
+
+ if (!this._source.mapped) {
+ this.hide();
+ return;
+ }
+
+ let [sourceX, sourceY] =
+ this._source.get_transformed_position();
+ let [dialogX, dialogY] =
+ this.get_transformed_position();
+
+ this.ease({
+ translation_x: sourceX - dialogX,
+ translation_y: sourceY - dialogY,
+ scale_x: this._source.width / this.width,
+ scale_y: this._source.height / this.height,
+ opacity: 0,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ onComplete: () => {
+ this.set({
+ translation_x: 0,
+ translation_y: 0,
+ scale_x: 1,
+ scale_y: 1,
+ opacity: 255,
+ });
+ this.hide();
+ },
+ });
+
+ this._needsZoomAndFade = false;
}
_onDestroy() {
@@ -2014,6 +2029,22 @@ var AppFolderPopup = GObject.registerClass({
this._grabHelper.ungrab({ actor: this });
this._grabHelper = null;
}
+
+ if (this._sourceMappedId) {
+ this._source.disconnect(this._sourceMappedId);
+ this._sourceMappedId = 0;
+ }
+ }
+
+ vfunc_allocate(box, flags) {
+ let contentBox = this.get_theme_node().get_content_box(box);
+ this._view.adaptToSize(contentBox.get_width(), contentBox.get_height());
+
+ super.vfunc_allocate(box, flags);
+
+ // We can only start zooming after receiving an allocation
+ if (this._needsZoomAndFade)
+ this._zoomAndFadeIn();
}
vfunc_key_press_event(keyEvent) {
@@ -2079,20 +2110,9 @@ var AppFolderPopup = GObject.registerClass({
if (!this._isOpen)
return;
+ this._needsZoomAndFade = true;
this.show();
- this._boxPointer.setArrowActor(this._source);
- // We need to hide the icons of the view until the boxpointer animation
- // is completed so we can animate the icons after as we like without
- // showing them while boxpointer is animating.
- this._view.opacity = 0;
- this._boxPointer.open(BoxPointer.PopupAnimation.FADE |
- BoxPointer.PopupAnimation.SLIDE,
- () => {
- this._view.opacity = 255;
- this._view.animate(IconGrid.AnimationDirection.IN);
- });
-
this.emit('open-state-changed', true);
}
@@ -2100,29 +2120,12 @@ var AppFolderPopup = GObject.registerClass({
if (!this._isOpen)
return;
- this._grabHelper.ungrab({ actor: this });
+ this._zoomAndFadeOut();
- this._boxPointer.close(BoxPointer.PopupAnimation.FADE |
- BoxPointer.PopupAnimation.SLIDE);
+ this._grabHelper.ungrab({ actor: this });
this._isOpen = false;
this.emit('open-state-changed', false);
}
-
- getCloseButtonOverlap() {
- return this.closeButton.get_theme_node().get_length('-shell-close-overlap-y');
- }
-
- getOffset(side) {
- let offset = this._boxPointer.getPadding(side);
- if (this._arrowSide == side)
- offset += this._boxPointer.getArrowHeight();
- return offset;
- }
-
- updateArrowSide(side) {
- this._arrowSide = side;
- this._boxPointer.updateArrowSide(side);
- }
});
var AppIcon = GObject.registerClass({
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]