[gnome-shell/gbsneto/folders-as-dialogs: 1/3] appDisplay: Add folder title and entry to dialog



commit b5fbe0407c00500e3af48573ce3a3781808b2d7d
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Tue Dec 17 16:39:24 2019 -0300

    appDisplay: Add folder title and entry to dialog
    
    This allows editing the folder name, and keeps the folder title visible
    at all times.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896

 data/theme/gnome-shell-sass/_common.scss |  27 +++++++
 js/ui/appDisplay.js                      | 127 ++++++++++++++++++++++++++++++-
 2 files changed, 151 insertions(+), 3 deletions(-)
---
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
index cd41d81c91..5afac88b9b 100644
--- a/data/theme/gnome-shell-sass/_common.scss
+++ b/data/theme/gnome-shell-sass/_common.scss
@@ -1515,6 +1515,33 @@ StScrollBar {
     border-radius: 8px;
     spacing: 24px;
     background-color: transparentize(darken($osd_bg_color,10%), 0.4);
+
+    & .folder-name-container {
+      padding: 12px 18px;
+      spacing: 12px;
+
+      & .folder-name-label,
+      & .folder-name-entry {
+        font-size: 18pt;
+        font-weight: bold;
+      }
+
+      & .folder-name-entry { width: 300px }
+
+      /* FIXME: this is to keep the label in sync with the entry */
+      & .folder-name-label { padding: 5px 7px }
+
+      & .edit-folder-button {
+        @extend %button;
+
+        padding: 0;
+        width: 32px;
+        height: 32px;
+        border-radius: 16px;
+
+        & > StIcon { icon-size: 16px }
+      }
+    }
   }
   .app-folder-dialog-container {
     padding: 12px;
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 54bf9aebfc..9a9f8feb10 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -1359,7 +1359,7 @@ var FolderIcon = GObject.registerClass({
         if (this._dialog)
             return;
         if (!this._dialog) {
-            this._dialog = new AppFolderDialog(this);
+            this._dialog = new AppFolderDialog(this, this._folder);
             this._parentView.addFolderDialog(this._dialog);
             this._dialog.connect('open-state-changed', (popup, isOpen) => {
                 if (!isOpen)
@@ -1547,7 +1547,7 @@ var AppFolderDialog = GObject.registerClass({
         'open-state-changed': { param_types: [GObject.TYPE_BOOLEAN] },
     },
 }, class AppFolderDialog extends St.Widget {
-    _init(source) {
+    _init(source, folder) {
         super._init({
             layout_manager: new Clutter.BinLayout(),
             style_class: 'app-folder-dialog-container',
@@ -1562,6 +1562,7 @@ var AppFolderDialog = GObject.registerClass({
         }));
 
         this._source = source;
+        this._folder = folder;
         this._view = source.view;
 
         this._isOpen = false;
@@ -1573,8 +1574,11 @@ var AppFolderDialog = GObject.registerClass({
             y_expand: true,
             x_align: Clutter.ActorAlign.FILL,
             y_align: Clutter.ActorAlign.FILL,
+            vertical: true,
         });
         this.add_child(this._viewBox);
+
+        this._addFolderNameEntry();
         this._viewBox.add_child(this._view);
 
         this._viewBox.add_effect(new Shell.BlurEffect({
@@ -1593,6 +1597,117 @@ var AppFolderDialog = GObject.registerClass({
         this._needsZoomAndFade = false;
     }
 
+    _addFolderNameEntry() {
+        this._entryBox = new St.BoxLayout({
+            style_class: 'folder-name-container',
+        });
+        this._viewBox.add_child(this._entryBox);
+
+        let stack = new Shell.Stack({
+            x_expand: true,
+            x_align: Clutter.ActorAlign.CENTER,
+        });
+        this._entryBox.add_child(stack);
+
+        // Folder name label
+        this._folderNameLabel = new St.Label({
+            style_class: 'folder-name-label',
+            x_expand: true,
+            y_expand: true,
+            x_align: Clutter.ActorAlign.CENTER,
+            y_align: Clutter.ActorAlign.CENTER,
+        });
+
+        stack.add_child(this._folderNameLabel);
+
+        // Folder name entry
+        this._entry = new St.Entry({
+            style_class: 'folder-name-entry',
+            opacity: 0,
+            reactive: false,
+        });
+        this._entry.clutter_text.set({
+            x_expand: true,
+            x_align: Clutter.ActorAlign.CENTER,
+        });
+
+        stack.add_child(this._entry);
+
+        // Edit button
+        let button = new St.Button({
+            style_class: 'edit-folder-button',
+            button_mask: St.ButtonMask.ONE,
+            reactive: true,
+            can_focus: true,
+            x_align: Clutter.ActorAlign.END,
+            y_align: Clutter.ActorAlign.CENTER,
+            child: new St.Icon({
+                icon_name: 'document-edit-symbolic',
+                icon_size: 16,
+            }),
+        });
+
+        button.connect('clicked', () => {
+            if (this._entry.reactive)
+                this._showFolderLabel();
+            else
+                this._showFolderEntry();
+        });
+
+        this._entryBox.add_child(button);
+
+        this._folder.connect('changed::name', () => this._syncFolderName());
+        this._syncFolderName();
+    }
+
+    _syncFolderName() {
+        let newName = _getFolderName(this._folder);
+
+        this._folderNameLabel.text = newName;
+        this._entry.text = newName;
+    }
+
+    _switchActor(from, to) {
+        to.reactive = true;
+        to.ease({
+            opacity: 255,
+            duration: 300,
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+        });
+
+        from.ease({
+            opacity: 0,
+            duration: 300,
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+            onComplete: () => {
+                from.reactive = false;
+            },
+        });
+    }
+
+    _showFolderLabel() {
+        this._maybeUpdateFolderName();
+        this._switchActor(this._entry, this._folderNameLabel);
+    }
+
+    _showFolderEntry() {
+        this._switchActor(this._folderNameLabel, this._entry);
+
+        this._entry.clutter_text.set_selection(0, -1);
+        this._entry.clutter_text.grab_key_focus();
+    }
+
+    _maybeUpdateFolderName() {
+        let folderName = _getFolderName(this._folder);
+        let newFolderName = this._entry.text.trim();
+
+        if (newFolderName.length === 0 || newFolderName === folderName)
+            return;
+
+        this._folder.set_string('name', newFolderName);
+        this._folder.set_boolean('translate', false);
+    }
+
     _zoomAndFadeIn() {
         let [sourceX, sourceY] =
             this._source.get_transformed_position();
@@ -1675,7 +1790,12 @@ var AppFolderDialog = GObject.registerClass({
 
     vfunc_allocate(box, flags) {
         let contentBox = this.get_theme_node().get_content_box(box);
-        this._view.adaptToSize(contentBox.get_width(), contentBox.get_height());
+
+        let [, entryBoxHeight] = this._entryBox.get_size();
+        let spacing = this._viewBox.layout_manager.spacing;
+
+        this._view.adaptToSize(contentBox.get_width(),
+            contentBox.get_height() - entryBoxHeight - spacing);
 
         super.vfunc_allocate(box, flags);
 
@@ -1758,6 +1878,7 @@ var AppFolderDialog = GObject.registerClass({
             return;
 
         this._zoomAndFadeOut();
+        this._showFolderLabel();
 
         this._grabHelper.ungrab({ actor: this });
         this._isOpen = false;


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