appIcon: Make AppIcon a drop target

Because the Dash icons are not drop targets themselves,
add a tiny DashIcon class, which is an AppDisplay.AppIcon
subclass, and disable all DND drop code from it.

Show a folder preview when dragging an app icon over another
app icon.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/671
This commit is contained in:
Georges Basile Stavracas Neto 2019-07-12 19:32:54 -03:00
parent be6ce3c5b4
commit ff3d32dd18
No known key found for this signature in database
GPG Key ID: 886C17EE170D1385
2 changed files with 126 additions and 3 deletions

View File

@ -1743,6 +1743,9 @@ var AppIcon = class AppIcon {
this.actor._delegate = this; this.actor._delegate = this;
this._hasDndHover = false;
this._folderPreviewId = 0;
// Get the isDraggable property without passing it on to the BaseIcon: // Get the isDraggable property without passing it on to the BaseIcon:
let appIconParams = Params.parse(iconParams, { isDraggable: true }, true); let appIconParams = Params.parse(iconParams, { isDraggable: true }, true);
let isDraggable = appIconParams['isDraggable']; let isDraggable = appIconParams['isDraggable'];
@ -1783,6 +1786,9 @@ var AppIcon = class AppIcon {
}); });
} }
Main.overview.connect('item-drag-begin', this._onDragBegin.bind(this));
Main.overview.connect('item-drag-end', this._onDragEnd.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this)); this.actor.connect('destroy', this._onDestroy.bind(this));
this._menuTimeoutId = 0; this._menuTimeoutId = 0;
@ -1793,6 +1799,10 @@ var AppIcon = class AppIcon {
} }
_onDestroy() { _onDestroy() {
if (this._folderPreviewId > 0) {
GLib.source_remove(this._folderPreviewId);
this._folderPreviewId = 0;
}
if (this._stateChangedId > 0) if (this._stateChangedId > 0)
this.app.disconnect(this._stateChangedId); this.app.disconnect(this._stateChangedId);
if (this._draggable && this._dragging) { if (this._draggable && this._dragging) {
@ -1992,6 +2002,97 @@ var AppIcon = class AppIcon {
opacity: 255 opacity: 255
}); });
} }
_showFolderPreview() {
this.icon.label.opacity = 0;
this.icon.icon.ease({
scale_x: FOLDER_SUBICON_FRACTION,
scale_y: FOLDER_SUBICON_FRACTION
});
}
_hideFolderPreview() {
this.icon.label.opacity = 255;
this.icon.icon.ease({
scale_x: 1.0,
scale_y: 1.0
});
}
_canAccept(source) {
let view = _getViewFromIcon(source);
return source != this &&
(source instanceof AppIcon) &&
(view instanceof AllView);
}
_setHoveringByDnd(hovering) {
if (hovering) {
if (this._folderPreviewId > 0)
return;
this._folderPreviewId =
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => {
this.actor.add_style_pseudo_class('drop');
this._showFolderPreview();
this._folderPreviewId = 0;
return GLib.SOURCE_REMOVE;
});
} else {
if (this._folderPreviewId > 0) {
GLib.source_remove(this._folderPreviewId);
this._folderPreviewId = 0;
}
this._hideFolderPreview();
this.actor.remove_style_pseudo_class('drop');
}
}
_onDragBegin() {
this._dragMonitor = {
dragMotion: this._onDragMotion.bind(this),
};
DND.addDragMonitor(this._dragMonitor);
}
_onDragMotion(dragEvent) {
let target = dragEvent.targetActor;
let isHovering = target == this.actor || this.actor.contains(target);
let canDrop = this._canAccept(dragEvent.source);
let hasDndHover = isHovering && canDrop;
if (this._hasDndHover != hasDndHover) {
this._setHoveringByDnd(hasDndHover);
this._hasDndHover = hasDndHover;
}
return DND.DragMotionResult.CONTINUE;
}
_onDragEnd() {
this.actor.remove_style_pseudo_class('drop');
DND.removeDragMonitor(this._dragMonitor);
}
handleDragOver(source) {
if (source == this)
return DND.DragMotionResult.NO_DROP;
if (!this._canAccept(source))
return DND.DragMotionResult.CONTINUE;
return DND.DragMotionResult.MOVE_DROP;
}
acceptDrop(source) {
this._setHoveringByDnd(false);
if (!this._canAccept(source))
return false;
return true;
}
}; };
Signals.addSignalMethods(AppIcon.prototype); Signals.addSignalMethods(AppIcon.prototype);

View File

@ -24,6 +24,30 @@ function getAppFromSource(source) {
} }
} }
var DashIcon = class DashIcon extends AppDisplay.AppIcon {
constructor(app) {
super(app, {
setSizeManually: true,
showLabel: false
});
}
// Disable all DnD methods
_onDragBegin() {
}
_onDragEnd() {
}
handleDragOver() {
return DND.DragMotionResult.CONTINUE;
}
acceptDrop() {
return false;
}
};
// A container like StBin, but taking the child's scale into account // A container like StBin, but taking the child's scale into account
// when requesting a size // when requesting a size
var DashItemContainer = GObject.registerClass( var DashItemContainer = GObject.registerClass(
@ -450,9 +474,7 @@ var Dash = class Dash {
} }
_createAppItem(app) { _createAppItem(app) {
let appIcon = new AppDisplay.AppIcon(app, let appIcon = new DashIcon(app);
{ setSizeManually: true,
showLabel: false });
appIcon.connect('menu-state-changed', appIcon.connect('menu-state-changed',
(appIcon, opened) => { (appIcon, opened) => {