[gnome-shell/gbsneto/pagination: 29/32] Add pagination to the folder dialog



commit a0a7e42826eda71485d7c97ed0c15995b9940de5
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Wed May 20 19:20:15 2020 -0300

    Add pagination to the folder dialog
    
    Make the folder dialog's app grid horizontal, and add
    paginators to it as well. Add a new '_createGrid()'
    vfunc, so that FolderView can create its own FolderGrid
    instance.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1271

 data/theme/gnome-shell-sass/widgets/_app-grid.scss |  13 +
 js/ui/appDisplay.js                                | 369 ++++++++++++---------
 2 files changed, 219 insertions(+), 163 deletions(-)
---
diff --git a/data/theme/gnome-shell-sass/widgets/_app-grid.scss 
b/data/theme/gnome-shell-sass/widgets/_app-grid.scss
index 8d3ae62bde..c183cfeb09 100644
--- a/data/theme/gnome-shell-sass/widgets/_app-grid.scss
+++ b/data/theme/gnome-shell-sass/widgets/_app-grid.scss
@@ -67,6 +67,19 @@ $app_grid_fg_color: #fff;
       & > StIcon { icon-size: 16px }
     }
   }
+
+  & .icon-grid {
+    row-spacing: $base_spacing * 2;
+    column-spacing: $base_spacing * 5;
+  }
+
+  & .page-indicators {
+    margin-bottom: 18px;
+
+    .page-indicator {
+      padding: 15px 12px;
+    }
+  }
 }
 .app-folder-dialog-container {
   padding: 12px;
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 805acbac11..9f18f7b1fa 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -117,13 +117,64 @@ var BaseAppView = GObject.registerClass({
         'view-loaded': {},
     },
 }, class BaseAppView extends St.Widget {
-    _init(params = {}) {
+    _init(params = {}, orientation = Clutter.Orientation.VERTICAL) {
         super._init(params);
 
-        this._grid = new IconGrid.IconGrid();
+        this._grid = this._createGrid();
         // Standard hack for ClutterBinLayout
         this._grid.x_expand = true;
 
+        const vertical = orientation === Clutter.Orientation.VERTICAL;
+
+        // Scroll View
+        this._scrollView = new St.ScrollView({
+            clip_to_allocation: true,
+            x_expand: true,
+            y_expand: true,
+            reactive: true,
+        });
+        this._scrollView.set_policy(
+            vertical ? St.PolicyType.NEVER : St.PolicyType.EXTERNAL,
+            vertical ? St.PolicyType.EXTERNAL : St.PolicyType.NEVER);
+
+        this._canScroll = true; // limiting scrolling speed
+        this._scrollTimeoutId = 0;
+        this._scrollView.connect('scroll-event', this._onScroll.bind(this));
+
+        this._scrollView.add_actor(this._grid);
+
+        const scroll = vertical ? this._scrollView.vscroll : this._scrollView.hscroll;
+        this._adjustment = scroll.adjustment;
+        this._adjustment.connect('notify::value', adj => {
+            this._pageIndicators.setCurrentPosition(adj.value / adj.page_size);
+        });
+
+        // Page Indicators
+        if (vertical)
+            this._pageIndicators = new PageIndicators.AnimatedPageIndicators();
+        else
+            this._pageIndicators = new PageIndicators.PageIndicators(orientation);
+
+        this._pageIndicators.y_expand = vertical;
+        this._pageIndicators.connect('page-activated',
+            (indicators, pageIndex) => {
+                this.goToPage(pageIndex);
+            });
+        this._pageIndicators.connect('scroll-event', (actor, event) => {
+            this._scrollView.event(event, false);
+        });
+
+        // Swipe
+        this._swipeTracker = new SwipeTracker.SwipeTracker(this._scrollView,
+            Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP);
+        this._swipeTracker.orientation = orientation;
+        this._swipeTracker.connect('begin', this._swipeBegin.bind(this));
+        this._swipeTracker.connect('update', this._swipeUpdate.bind(this));
+        this._swipeTracker.connect('end', this._swipeEnd.bind(this));
+
+        this._availWidth = 0;
+        this._availHeight = 0;
+
         this._items = new Map();
         this._orderedItems = [];
 
@@ -138,6 +189,74 @@ var BaseAppView = GObject.registerClass({
         });
     }
 
+    _createGrid() {
+        return new IconGrid.IconGrid();
+    }
+
+    _onScroll(actor, event) {
+        if (this._swipeTracker.canHandleScrollEvent(event))
+            return Clutter.EVENT_PROPAGATE;
+
+        if (!this._canScroll)
+            return Clutter.EVENT_STOP;
+
+        switch (event.get_scroll_direction()) {
+        case Clutter.ScrollDirection.UP:
+        case Clutter.ScrollDirection.LEFT:
+            this.goToPage(this._grid.currentPage - 1);
+            break;
+
+        case Clutter.ScrollDirection.DOWN:
+        case Clutter.ScrollDirection.RIGHT:
+            this.goToPage(this._grid.currentPage + 1);
+            break;
+
+        case Clutter.ScrollDirection.SMOOTH:
+            return Clutter.EVENT_STOP;
+        }
+
+        this._canScroll = false;
+        this._scrollTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
+            SCROLL_TIMEOUT_TIME, () => {
+                this._canScroll = true;
+                this._scrollTimeoutId = 0;
+                return GLib.SOURCE_REMOVE;
+            });
+
+        return Clutter.EVENT_STOP;
+    }
+
+    _swipeBegin(tracker, monitor) {
+        if (monitor !== Main.layoutManager.primaryIndex)
+            return;
+
+        const adjustment = this._adjustment;
+        adjustment.remove_transition('value');
+
+        const progress = adjustment.value / adjustment.page_size;
+        const points = Array.from({ length: this._grid.nPages }, (v, i) => i);
+        const size = tracker.orientation === Clutter.Orientation.VERTICAL
+            ? this._scrollView.height : this._scrollView.width;
+
+        tracker.confirmSwipe(size, points, progress, Math.round(progress));
+    }
+
+    _swipeUpdate(tracker, progress) {
+        const adjustment = this._adjustment;
+        adjustment.value = progress * adjustment.page_size;
+    }
+
+    _swipeEnd(tracker, duration, endProgress) {
+        const adjustment = this._adjustment;
+        const value = endProgress * adjustment.page_size;
+
+        adjustment.ease(value, {
+            mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
+            duration,
+            onComplete: () => this.goToPage(endProgress, false),
+        });
+    }
+
     _redisplay() {
         let oldApps = this._orderedItems.slice();
         let oldAppIds = oldApps.map(icon => icon.id);
@@ -268,7 +387,22 @@ var BaseAppView = GObject.registerClass({
         }
     }
 
+    vfunc_allocate(box) {
+        const width = box.get_width();
+        const height = box.get_height();
+
+        this.adaptToSize(width, height);
+
+        super.vfunc_allocate(box);
+    }
+
+    vfunc_map() {
+        this._swipeTracker.enabled = true;
+        super.vfunc_map();
+    }
+
     vfunc_unmap() {
+        this._swipeTracker.enabled = false;
         this._clearAnimateLater();
         super.vfunc_unmap();
     }
@@ -294,8 +428,44 @@ var BaseAppView = GObject.registerClass({
         this._grid.ease(params);
     }
 
-    adaptToSize(_width, _height) {
-        throw new GObject.NotImplementedError('adaptToSize in %s'.format(this.constructor.name));
+    goToPage(pageNumber, animate = true) {
+        pageNumber = Math.clamp(pageNumber, 0, this._grid.nPages - 1);
+
+        if (this._grid.currentPage === pageNumber)
+            return;
+
+        this._grid.goToPage(pageNumber, animate);
+    }
+
+    adaptToSize(width, height) {
+        let box = new Clutter.ActorBox();
+        box.x1 = 0;
+        box.x2 = width;
+        box.y1 = 0;
+        box.y2 = height;
+        box = this._scrollView.get_theme_node().get_content_box(box);
+        box = this._grid.get_theme_node().get_content_box(box);
+
+        const availWidth = box.get_width();
+        const availHeight = box.get_height();
+        const oldNPages = this._grid.nPages;
+
+        this._grid.adaptToSize(availWidth, availHeight);
+
+        if (this._availWidth !== availWidth ||
+            this._availHeight !== availHeight ||
+            oldNPages !== this._grid.nPages) {
+            Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
+                this._adjustment.value = 0;
+                this._grid.currentPage = 0;
+                this._pageIndicators.setNPages(this._grid.nPages);
+                this._pageIndicators.setCurrentPosition(0);
+                return GLib.SOURCE_REMOVE;
+            });
+        }
+
+        this._availWidth = availWidth;
+        this._availHeight = availHeight;
     }
 });
 
@@ -310,59 +480,24 @@ class AppDisplay extends BaseAppView {
 
         this._grid._delegate = this;
 
+        this._scrollView.add_style_class_name('all-apps');
+
         this._stack = new St.Widget({
             layout_manager: new Clutter.BinLayout(),
             x_expand: true,
             y_expand: true,
         });
         this.add_actor(this._stack);
-
-        this._scrollView = new St.ScrollView({
-            style_class: 'all-apps',
-            x_expand: true,
-            y_expand: true,
-            reactive: true,
-        });
-        this._scrollView.add_actor(this._grid);
         this._stack.add_actor(this._scrollView);
 
-        this._scrollView.set_policy(St.PolicyType.NEVER,
-                                    St.PolicyType.EXTERNAL);
-        this._adjustment = this._scrollView.vscroll.adjustment;
-        this._adjustment.connect('notify::value', adj => {
-            this._pageIndicators.setCurrentPosition(adj.value / adj.page_size);
-        });
-
-        this._pageIndicators = new PageIndicators.AnimatedPageIndicators();
-        this._pageIndicators.connect('page-activated',
-            (indicators, pageIndex) => {
-                this.goToPage(pageIndex);
-            });
-        this._pageIndicators.connect('scroll-event', (actor, event) => {
-            this._scrollView.event(event, false);
-        });
         this.add_actor(this._pageIndicators);
 
         this._folderIcons = [];
 
-        this._scrollView.connect('scroll-event', this._onScroll.bind(this));
-
-        this._swipeTracker = new SwipeTracker.SwipeTracker(
-            this._scrollView, Shell.ActionMode.OVERVIEW);
-        this._swipeTracker.connect('begin', this._swipeBegin.bind(this));
-        this._swipeTracker.connect('update', this._swipeUpdate.bind(this));
-        this._swipeTracker.connect('end', this._swipeEnd.bind(this));
-
         this._currentDialog = null;
         this._displayingDialog = false;
         this._currentDialogDestroyId = 0;
 
-        this._canScroll = true; // limiting scrolling speed
-        this._scrollTimeoutId = 0;
-
-        this._availWidth = 0;
-        this._availHeight = 0;
-
         this._lastOvershootY = -1;
         this._lastOvershootTimeoutId = 0;
 
@@ -400,15 +535,6 @@ class AppDisplay extends BaseAppView {
         }
     }
 
-    vfunc_allocate(box) {
-        box = this.get_theme_node().get_content_box(box);
-        let availWidth = box.get_width();
-        let availHeight = box.get_height();
-        this.adaptToSize(availWidth, availHeight);
-
-        super.vfunc_allocate(box);
-    }
-
     _onDestroy() {
         if (this._scrollTimeoutId !== 0) {
             GLib.source_remove(this._scrollTimeoutId);
@@ -420,7 +546,6 @@ class AppDisplay extends BaseAppView {
         this._keyPressEventId =
             global.stage.connect('key-press-event',
                 this._onKeyPressEvent.bind(this));
-        this._swipeTracker.enabled = true;
         super.vfunc_map();
     }
 
@@ -429,7 +554,6 @@ class AppDisplay extends BaseAppView {
             global.stage.disconnect(this._keyPressEventId);
             this._keyPressEventId = 0;
         }
-        this._swipeTracker.enabled = false;
         super.vfunc_unmap();
     }
 
@@ -577,68 +701,14 @@ class AppDisplay extends BaseAppView {
         if (this._displayingDialog && this._currentDialog)
             this._currentDialog.popdown();
 
-        this._grid.goToPage(pageNumber, animate);
+        super.goToPage(pageNumber, animate);
     }
 
     _onScroll(actor, event) {
         if (this._displayingDialog || !this._scrollView.reactive)
             return Clutter.EVENT_STOP;
 
-        if (this._swipeTracker.canHandleScrollEvent(event))
-            return Clutter.EVENT_PROPAGATE;
-
-        if (!this._canScroll)
-            return Clutter.EVENT_STOP;
-
-        let direction = event.get_scroll_direction();
-        if (direction == Clutter.ScrollDirection.UP)
-            this.goToPage(this._grid.currentPage - 1);
-        else if (direction == Clutter.ScrollDirection.DOWN)
-            this.goToPage(this._grid.currentPage + 1);
-        else
-            return Clutter.EVENT_STOP;
-
-        this._canScroll = false;
-        this._scrollTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
-            SCROLL_TIMEOUT_TIME, () => {
-                this._canScroll = true;
-                this._scrollTimeoutId = 0;
-                return GLib.SOURCE_REMOVE;
-            });
-
-        return Clutter.EVENT_STOP;
-    }
-
-    _swipeBegin(tracker, monitor) {
-        if (monitor !== Main.layoutManager.primaryIndex)
-            return;
-
-        let adjustment = this._adjustment;
-        adjustment.remove_transition('value');
-
-        let progress = adjustment.value / adjustment.page_size;
-        let points = Array.from({ length: this._grid.nPages }, (v, i) => i);
-
-        tracker.confirmSwipe(this._scrollView.height,
-            points, progress, Math.round(progress));
-    }
-
-    _swipeUpdate(tracker, progress) {
-        let adjustment = this._adjustment;
-        adjustment.value = progress * adjustment.page_size;
-    }
-
-    _swipeEnd(tracker, duration, endProgress) {
-        let adjustment = this._adjustment;
-        let value = endProgress * adjustment.page_size;
-
-        adjustment.ease(value, {
-            mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
-            duration,
-            onComplete: () => {
-                this.goToPage(endProgress, false);
-            },
-        });
+        return super._onScroll(actor, event);
     }
 
     _onKeyPressEvent(actor, event) {
@@ -678,36 +748,6 @@ class AppDisplay extends BaseAppView {
     }
 
 
-    // Called before allocation to calculate dynamic spacing
-    adaptToSize(width, height) {
-        let box = new Clutter.ActorBox();
-        box.x1 = 0;
-        box.x2 = width;
-        box.y1 = 0;
-        box.y2 = height;
-        box = this.get_theme_node().get_content_box(box);
-        box = this._scrollView.get_theme_node().get_content_box(box);
-        box = this._grid.get_theme_node().get_content_box(box);
-        let availWidth = box.x2 - box.x1;
-        let availHeight = box.y2 - box.y1;
-        let oldNPages = this._grid.nPages;
-
-        this._grid.adaptToSize(availWidth, availHeight);
-
-        if (this._availWidth != availWidth || this._availHeight != availHeight || oldNPages != 
this._grid.nPages) {
-            Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
-                this._adjustment.value = 0;
-                this._grid.currentPage = 0;
-                this._pageIndicators.setNPages(this._grid.nPages);
-                this._pageIndicators.setCurrentPosition(0);
-                return GLib.SOURCE_REMOVE;
-            });
-        }
-
-        this._availWidth = availWidth;
-        this._availHeight = availHeight;
-    }
-
     _resetOvershoot() {
         if (this._lastOvershootTimeoutId)
             GLib.source_remove(this._lastOvershootTimeoutId);
@@ -945,6 +985,24 @@ var AppSearchProvider = class AppSearchProvider {
     }
 };
 
+var FolderGrid = GObject.registerClass(
+class FolderGrid extends IconGrid.IconGrid {
+    _init() {
+        super._init({
+            allow_incomplete_pages: false,
+            orientation: Clutter.Orientation.HORIZONTAL,
+            columns_per_page: 3,
+            rows_per_page: 3,
+            page_halign: Clutter.ActorAlign.CENTER,
+            page_valign: Clutter.ActorAlign.CENTER,
+        });
+    }
+
+    adaptToSize(width, height) {
+        this.layout_manager.adaptToSize(width, height);
+    }
+});
+
 var FolderView = GObject.registerClass(
 class FolderView extends BaseAppView {
     _init(folder, id, parentView) {
@@ -952,7 +1010,7 @@ class FolderView extends BaseAppView {
             layout_manager: new Clutter.BinLayout(),
             x_expand: true,
             y_expand: true,
-        });
+        }, Clutter.Orientation.HORIZONTAL);
 
         // If it not expand, the parent doesn't take into account its preferred_width when allocating
         // the second time it allocates, so we apply the "Standard hack for ClutterBinLayout"
@@ -962,22 +1020,15 @@ class FolderView extends BaseAppView {
         this._parentView = parentView;
         this._grid._delegate = this;
 
-        this._scrollView = new St.ScrollView({
-            overlay_scrollbars: true,
-            x_expand: true,
-            y_expand: true,
-        });
-        this._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL);
-        this.add_actor(this._scrollView);
-
-        let scrollableContainer = new St.BoxLayout({
+        const box = new St.BoxLayout({
             vertical: true,
             reactive: true,
             x_expand: true,
             y_expand: true,
         });
-        scrollableContainer.add_actor(this._grid);
-        this._scrollView.add_actor(scrollableContainer);
+        box.add_actor(this._scrollView);
+        box.add_actor(this._pageIndicators);
+        this.add_actor(box);
 
         let action = new Clutter.PanAction({ interpolate: true });
         action.connect('pan', this._onPan.bind(this));
@@ -986,16 +1037,8 @@ class FolderView extends BaseAppView {
         this._redisplay();
     }
 
-    vfunc_allocate(box) {
-        const node = this.get_theme_node();
-        const contentBox = node.get_content_box(box);
-
-        const [width, height] = contentBox.get_size();
-        this.adaptToSize(width, height);
-
-        this._grid.topPadding = 0;
-
-        super.vfunc_allocate(box);
+    _createGrid() {
+        return new FolderGrid();
     }
 
     // Overridden from BaseAppView
@@ -1034,10 +1077,10 @@ class FolderView extends BaseAppView {
     }
 
     adaptToSize(width, height) {
-        this._parentAvailableWidth = width;
-        this._parentAvailableHeight = height;
+        const [, indicatorHeight] = this._pageIndicators.get_preferred_height(-1);
+        height -= indicatorHeight;
 
-        this._grid.adaptToSize(width, height);
+        super.adaptToSize(width, height);
     }
 
     _loadApps() {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]