appDisplay: Allow editing folder names
Add a new popover with a regular entry + button to rename folders. The layout is similar to other GNOME applications. The popup is implemented as a PopupMenu subclass, leaving the grab management to PopupMenuManager. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/675
This commit is contained in:
parent
1e68e78d8e
commit
dfc0ef56f6
@ -611,6 +611,14 @@ StScrollBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Rename popup
|
||||||
|
|
||||||
|
.rename-folder-popup-box {
|
||||||
|
spacing: 6px;
|
||||||
|
margin-left: 12px;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
// Background menu
|
// Background menu
|
||||||
.background-menu { -boxpointer-gap: 4px; -arrow-rise: 0px; }
|
.background-menu { -boxpointer-gap: 4px; -arrow-rise: 0px; }
|
||||||
|
|
||||||
|
@ -1438,6 +1438,13 @@ var FolderIcon = class FolderIcon {
|
|||||||
this._itemDragEndId = Main.overview.connect(
|
this._itemDragEndId = Main.overview.connect(
|
||||||
'item-drag-end', this._onDragEnd.bind(this));
|
'item-drag-end', this._onDragEnd.bind(this));
|
||||||
|
|
||||||
|
this._popupTimeoutId = 0;
|
||||||
|
|
||||||
|
this.actor.connect('leave-event', this._onLeaveEvent.bind(this));
|
||||||
|
this.actor.connect('button-press-event', this._onButtonPress.bind(this));
|
||||||
|
this.actor.connect('touch-event', this._onTouchEvent.bind(this));
|
||||||
|
this.actor.connect('popup-menu', this._popupRenamePopup.bind(this));
|
||||||
|
|
||||||
this.actor.connect('clicked', this.open.bind(this));
|
this.actor.connect('clicked', this.open.bind(this));
|
||||||
this.actor.connect('destroy', this.onDestroy.bind(this));
|
this.actor.connect('destroy', this.onDestroy.bind(this));
|
||||||
this.actor.connect('notify::mapped', () => {
|
this.actor.connect('notify::mapped', () => {
|
||||||
@ -1462,9 +1469,12 @@ var FolderIcon = class FolderIcon {
|
|||||||
|
|
||||||
if (this._popup)
|
if (this._popup)
|
||||||
this._popup.actor.destroy();
|
this._popup.actor.destroy();
|
||||||
|
|
||||||
|
this._removeMenuTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
open() {
|
open() {
|
||||||
|
this._removeMenuTimeout();
|
||||||
this._ensurePopup();
|
this._ensurePopup();
|
||||||
this.view.actor.vscroll.adjustment.value = 0;
|
this.view.actor.vscroll.adjustment.value = 0;
|
||||||
this._openSpaceForPopup();
|
this._openSpaceForPopup();
|
||||||
@ -1627,6 +1637,76 @@ var FolderIcon = class FolderIcon {
|
|||||||
this._popupInvalidated = false;
|
this._popupInvalidated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_removeMenuTimeout() {
|
||||||
|
if (this._popupTimeoutId > 0) {
|
||||||
|
Mainloop.source_remove(this._popupTimeoutId);
|
||||||
|
this._popupTimeoutId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_setPopupTimeout() {
|
||||||
|
this._removeMenuTimeout();
|
||||||
|
this._popupTimeoutId = Mainloop.timeout_add(MENU_POPUP_TIMEOUT, () => {
|
||||||
|
this._popupTimeoutId = 0;
|
||||||
|
this._popupRenamePopup();
|
||||||
|
return GLib.SOURCE_REMOVE;
|
||||||
|
});
|
||||||
|
GLib.Source.set_name_by_id(this._popupTimeoutId,
|
||||||
|
'[gnome-shell] this._popupRenamePopup');
|
||||||
|
}
|
||||||
|
|
||||||
|
_onLeaveEvent(_actor, _event) {
|
||||||
|
this.actor.fake_release();
|
||||||
|
this._removeMenuTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onButtonPress(_actor, event) {
|
||||||
|
let button = event.get_button();
|
||||||
|
if (button == 1) {
|
||||||
|
this._setPopupTimeout();
|
||||||
|
} else if (button == 3) {
|
||||||
|
this._popupRenamePopup();
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onTouchEvent(actor, event) {
|
||||||
|
if (event.type() == Clutter.EventType.TOUCH_BEGIN)
|
||||||
|
this._setPopupTimeout();
|
||||||
|
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_popupRenamePopup() {
|
||||||
|
this._removeMenuTimeout();
|
||||||
|
this.actor.fake_release();
|
||||||
|
|
||||||
|
if (!this._menu) {
|
||||||
|
this._menuManager = new PopupMenu.PopupMenuManager(this.actor);
|
||||||
|
|
||||||
|
this._menu = new RenameFolderMenu(this, this._folder);
|
||||||
|
this._menuManager.addMenu(this._menu);
|
||||||
|
|
||||||
|
this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
|
||||||
|
if (!isPoppedUp)
|
||||||
|
this.actor.sync_hover();
|
||||||
|
});
|
||||||
|
let id = Main.overview.connect('hiding', () => {
|
||||||
|
this._menu.close();
|
||||||
|
});
|
||||||
|
this.actor.connect('destroy', () => {
|
||||||
|
Main.overview.disconnect(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._menuManager.addMenu(this._menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.actor.set_hover(true);
|
||||||
|
this._menu.popup();
|
||||||
|
this._menuManager.ignoreRelease();
|
||||||
|
}
|
||||||
|
|
||||||
adaptToSize(width, height) {
|
adaptToSize(width, height) {
|
||||||
this._parentAvailableWidth = width;
|
this._parentAvailableWidth = width;
|
||||||
this._parentAvailableHeight = height;
|
this._parentAvailableHeight = height;
|
||||||
@ -1637,6 +1717,90 @@ var FolderIcon = class FolderIcon {
|
|||||||
};
|
};
|
||||||
Signals.addSignalMethods(FolderIcon.prototype);
|
Signals.addSignalMethods(FolderIcon.prototype);
|
||||||
|
|
||||||
|
var RenameFolderMenu = class RenameFolderMenu extends PopupMenu.PopupMenu {
|
||||||
|
constructor(source, folder) {
|
||||||
|
super(source.actor, 0.5, St.Side.BOTTOM);
|
||||||
|
|
||||||
|
this._source = source;
|
||||||
|
this._folder = folder;
|
||||||
|
|
||||||
|
// We want to keep the item hovered while the menu is up
|
||||||
|
this.blockSourceEvents = true;
|
||||||
|
|
||||||
|
let box = new St.BoxLayout({ style_class: 'rename-folder-popup-box' });
|
||||||
|
this.box.add_child(box);
|
||||||
|
|
||||||
|
// Entry
|
||||||
|
this._entry = new St.Entry({
|
||||||
|
x_expand: true,
|
||||||
|
width: 200,
|
||||||
|
});
|
||||||
|
box.add_child(this._entry);
|
||||||
|
|
||||||
|
this._entry.clutter_text.connect('notify::text',
|
||||||
|
this._validate.bind(this));
|
||||||
|
this._entry.clutter_text.connect('activate',
|
||||||
|
this._updateFolderName.bind(this));
|
||||||
|
|
||||||
|
// Rename button
|
||||||
|
this._button = new St.Button({
|
||||||
|
style_class: 'button',
|
||||||
|
reactive: true,
|
||||||
|
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
|
||||||
|
can_focus: true,
|
||||||
|
label: _("Rename"),
|
||||||
|
});
|
||||||
|
box.add_child(this._button);
|
||||||
|
|
||||||
|
this._button.connect('clicked', this._updateFolderName.bind(this));
|
||||||
|
|
||||||
|
// Chain our visibility and lifecycle to that of the source
|
||||||
|
this._sourceMappedId = source.actor.connect('notify::mapped', () => {
|
||||||
|
if (!source.actor.mapped)
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
|
source.actor.connect('destroy', () => {
|
||||||
|
source.actor.disconnect(this._sourceMappedId);
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
Main.uiGroup.add_actor(this.actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
popup() {
|
||||||
|
let folderName = _getFolderName(this._folder);
|
||||||
|
|
||||||
|
this._entry.text = folderName;
|
||||||
|
this._entry.clutter_text.set_selection(0, folderName.length);
|
||||||
|
|
||||||
|
this.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
_isValidFolderName() {
|
||||||
|
let folderName = _getFolderName(this._folder);
|
||||||
|
let newFolderName = this._entry.text.trim();
|
||||||
|
|
||||||
|
return newFolderName.length > 0 && newFolderName != folderName;
|
||||||
|
}
|
||||||
|
|
||||||
|
_validate() {
|
||||||
|
let isValid = this._isValidFolderName();
|
||||||
|
|
||||||
|
this._button.reactive = isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateFolderName() {
|
||||||
|
if (!this._isValidFolderName())
|
||||||
|
return;
|
||||||
|
|
||||||
|
let newFolderName = this._entry.text.trim();
|
||||||
|
this._folder.set_string('name', newFolderName);
|
||||||
|
this._folder.set_boolean('translate', false);
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Signals.addSignalMethods(RenameFolderMenu.prototype);
|
||||||
|
|
||||||
var AppFolderPopup = class AppFolderPopup {
|
var AppFolderPopup = class AppFolderPopup {
|
||||||
constructor(source, side) {
|
constructor(source, side) {
|
||||||
this._source = source;
|
this._source = source;
|
||||||
|
Loading…
Reference in New Issue
Block a user