[gnome-shell/gbsneto/icon-grid-part3: 4/5] appIcon: Make AppIcon a drop target
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/gbsneto/icon-grid-part3: 4/5] appIcon: Make AppIcon a drop target
- Date: Thu, 8 Aug 2019 00:36:23 +0000 (UTC)
commit 0255a2c57f2c3df7faa4bbd46488670302dfd144
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Fri Jul 12 19:32:54 2019 -0300
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
js/ui/appDisplay.js | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++
js/ui/dash.js | 28 ++++++++++++--
2 files changed, 130 insertions(+), 3 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 437de4c3c3..ab56abadb8 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -1739,6 +1739,9 @@ var AppIcon = class AppIcon {
this.actor._delegate = this;
+ this._hasDndHover = false;
+ this._folderPreviewId = 0;
+
// Get the isDraggable property without passing it on to the BaseIcon:
let appIconParams = Params.parse(iconParams, { isDraggable: true }, true);
let isDraggable = appIconParams['isDraggable'];
@@ -1779,6 +1782,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._menuTimeoutId = 0;
@@ -1789,6 +1795,10 @@ var AppIcon = class AppIcon {
}
_onDestroy() {
+ if (this._folderPreviewId > 0) {
+ GLib.source_remove(this._folderPreviewId);
+ this._folderPreviewId = 0;
+ }
if (this._stateChangedId > 0)
this.app.disconnect(this._stateChangedId);
if (this._draggable && this._dragging) {
@@ -2000,6 +2010,101 @@ var AppIcon = class AppIcon {
opacity: 255
});
}
+
+ _showFolderPreview() {
+ // HACK!!!
+ this.icon.label.opacity = 0;
+ this.icon._iconBin.ease({
+ scale_x: FOLDER_SUBICON_FRACTION,
+ scale_y: FOLDER_SUBICON_FRACTION
+ });
+ }
+
+ _hideFolderPreview() {
+ // HACK!!!
+ this.icon.label.opacity = 255;
+ this.icon._iconBin.ease({
+ scale_x: 1.0,
+ scale_y: 1.0
+ });
+ }
+
+ _canAccept(source) {
+ let view = source.actor.get_parent()._delegate;
+
+ 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) {
+ source.undoScaleAndFade();
+
+ this._setHoveringByDnd(false);
+
+ if (!this._canAccept(source))
+ return false;
+
+ return true;
+ }
};
Signals.addSignalMethods(AppIcon.prototype);
diff --git a/js/ui/dash.js b/js/ui/dash.js
index b7ed5874c2..c866dabbfa 100644
--- a/js/ui/dash.js
+++ b/js/ui/dash.js
@@ -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
// when requesting a size
var DashItemContainer = GObject.registerClass(
@@ -450,9 +474,7 @@ var Dash = class Dash {
}
_createAppItem(app) {
- let appIcon = new AppDisplay.AppIcon(app,
- { setSizeManually: true,
- showLabel: false });
+ let appIcon = new DashIcon(app);
appIcon.connect('menu-state-changed',
(appIcon, opened) => {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]