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
This commit is contained in:
Georges Basile Stavracas Neto 2019-12-17 16:39:24 -03:00
parent 1dad5f3ffa
commit 973c920284
2 changed files with 169 additions and 3 deletions

View File

@ -90,6 +90,33 @@ $app_grid_fg_color: #fff;
border-radius: 8px;
spacing: 24px;
background-color: transparentize(darken($osd_bg_color,10%), 0.05);
& .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: 36px;
height: 36px;
border-radius: 18px;
& > StIcon { icon-size: 16px }
}
}
}
.app-folder-dialog-container {
padding: 12px;

View File

@ -1629,7 +1629,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)
@ -1817,7 +1817,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',
@ -1833,6 +1833,7 @@ var AppFolderDialog = GObject.registerClass({
}));
this._source = source;
this._folder = folder;
this._view = source.view;
this._isOpen = false;
@ -1844,8 +1845,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);
global.focus_manager.add_group(this);
@ -1860,6 +1864,134 @@ var AppFolderDialog = GObject.registerClass({
this._needsZoomAndFade = false;
}
_addFolderNameEntry() {
this._entryBox = new St.BoxLayout({
style_class: 'folder-name-container',
});
this._viewBox.add_child(this._entryBox);
// Empty actor to center the title
let ghostButton = new Clutter.Actor();
this._entryBox.add_child(ghostButton);
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,
});
this._entry.clutter_text.connect('activate', () => {
this._showFolderLabel();
});
stack.add_child(this._entry);
// Edit button
this._editButton = new St.Button({
style_class: 'edit-folder-button',
button_mask: St.ButtonMask.ONE,
toggle_mode: true,
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,
}),
});
this._editButton.connect('notify::checked', () => {
if (this._editButton.checked)
this._showFolderEntry();
else
this._showFolderLabel();
});
this._entryBox.add_child(this._editButton);
ghostButton.add_constraint(new Clutter.BindConstraint({
source: this._editButton,
coordinate: Clutter.BindCoordinate.SIZE,
}));
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() {
if (this._editButton.checked)
this._editButton.checked = false;
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();
@ -1944,7 +2076,13 @@ 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);
@ -2027,6 +2165,7 @@ var AppFolderDialog = GObject.registerClass({
return;
this._zoomAndFadeOut();
this._showFolderLabel();
this._grabHelper.ungrab({ actor: this });
this._isOpen = false;