[dnd] Optionally restore the drag actor

Currently, the drag and drop code assumes that on a successful drop
the target will either consume the drag actor or that it is otherwise
OK to destroy the actor.
As the drag behavior for window preview was changed, dropping a preview
on the dash now results in the preview being swallowed - to fix, add an
option to restore the actor in case of a successful drop as well.

https://bugzilla.gnome.org/show_bug.cgi?id=619203
This commit is contained in:
Florian Müllner 2010-05-20 16:44:45 +02:00
parent a0be7fa455
commit 3e2a9a57a1
3 changed files with 53 additions and 19 deletions

View File

@ -14,6 +14,8 @@ const Params = imports.misc.params;
const SCALE_ANIMATION_TIME = 0.25; const SCALE_ANIMATION_TIME = 0.25;
// Time to animate to original position on cancel // Time to animate to original position on cancel
const SNAP_BACK_ANIMATION_TIME = 0.25; const SNAP_BACK_ANIMATION_TIME = 0.25;
// Time to animate to original position on success
const REVERT_ANIMATION_TIME = 0.75;
let eventHandlerActor = null; let eventHandlerActor = null;
let currentDraggable = null; let currentDraggable = null;
@ -41,6 +43,7 @@ function _Draggable(actor, params) {
_Draggable.prototype = { _Draggable.prototype = {
_init : function(actor, params) { _init : function(actor, params) {
params = Params.parse(params, { manualMode: false, params = Params.parse(params, { manualMode: false,
restoreOnSuccess: false,
dragActorMaxSize: undefined, dragActorMaxSize: undefined,
dragActorOpacity: undefined }); dragActorOpacity: undefined });
@ -54,12 +57,13 @@ _Draggable.prototype = {
})); }));
this._onEventId = null; this._onEventId = null;
this._restoreOnSuccess = params.restoreOnSuccess;
this._dragActorMaxSize = params.dragActorMaxSize; this._dragActorMaxSize = params.dragActorMaxSize;
this._dragActorOpacity = params.dragActorOpacity; this._dragActorOpacity = params.dragActorOpacity;
this._buttonDown = false; // The mouse button has been pressed and has not yet been released. this._buttonDown = false; // The mouse button has been pressed and has not yet been released.
this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet. this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
this._snapBackInProgress = false; // The drag has been cancelled and the item is in the process of snapping back. this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
}, },
_onButtonPress : function (actor, event) { _onButtonPress : function (actor, event) {
@ -125,7 +129,7 @@ _Draggable.prototype = {
this._buttonDown = false; this._buttonDown = false;
if (this._dragInProgress) { if (this._dragInProgress) {
return this._dragActorDropped(event); return this._dragActorDropped(event);
} else if (this._dragActor != null && !this._snapBackInProgress) { } else if (this._dragActor != null && !this._animationInProgress) {
// Drag must have been cancelled with Esc. // Drag must have been cancelled with Esc.
this._dragComplete(); this._dragComplete();
return true; return true;
@ -330,9 +334,14 @@ _Draggable.prototype = {
(dropY - targY) / target.scale_y, (dropY - targY) / target.scale_y,
event.get_time())) { event.get_time())) {
// If it accepted the drop without taking the actor, // If it accepted the drop without taking the actor,
// destroy it. // handle it ourselves.
if (this._dragActor.get_parent() == this._dragActor.get_stage()) if (this._dragActor.get_parent() == this._dragActor.get_stage()) {
this._dragActor.destroy(); if (this._restoreOnSuccess) {
this._restoreDragActor(event.get_time());
return true;
} else
this._dragActor.destroy();
}
this._dragInProgress = false; this._dragInProgress = false;
this.emit('drag-end', event.get_time(), true); this.emit('drag-end', event.get_time(), true);
@ -348,18 +357,23 @@ _Draggable.prototype = {
return true; return true;
}, },
// Get position of the drag actor's source if the source is still around,
// or return the original location if the actor itself was being dragged
// or the source is no longer around.
_getRestoreLocation: function() {
let locX = this._snapBackX;
let locY = this._snapBackY;
if (this._dragActorSource && this._dragActorSource.visible)
[locX, locY] = this._dragActorSource.get_transformed_position();
return [locX, locY];
},
_cancelDrag: function(eventTime) { _cancelDrag: function(eventTime) {
this._dragInProgress = false; this._dragInProgress = false;
// Snap back to the actor source if the source is still around, snap back let [snapBackX, snapBackY] = this._getRestoreLocation();
// to the original location if the actor itself was being dragged or the
// source is no longer around.
let snapBackX = this._snapBackX;
let snapBackY = this._snapBackY;
if (this._dragActorSource && this._dragActorSource.visible) {
[snapBackX, snapBackY] = this._dragActorSource.get_transformed_position();
}
this._snapBackInProgress = true; this._animationInProgress = true;
// No target, so snap back // No target, so snap back
Tweener.addTween(this._dragActor, Tweener.addTween(this._dragActor,
{ x: snapBackX, { x: snapBackX,
@ -369,13 +383,33 @@ _Draggable.prototype = {
opacity: this._dragOrigOpacity, opacity: this._dragOrigOpacity,
time: SNAP_BACK_ANIMATION_TIME, time: SNAP_BACK_ANIMATION_TIME,
transition: 'easeOutQuad', transition: 'easeOutQuad',
onComplete: this._onSnapBackComplete, onComplete: this._onAnimationComplete,
onCompleteScope: this, onCompleteScope: this,
onCompleteParams: [this._dragActor, eventTime] onCompleteParams: [this._dragActor, eventTime]
}); });
}, },
_onSnapBackComplete : function (dragActor, eventTime) { _restoreDragActor: function(eventTime) {
this._dragInProgress = false;
[restoreX, restoreY] = this._getRestoreLocation();
// fade the actor back in at its original location
this._dragActor.set_position(restoreX, restoreY);
this._dragActor.set_scale(this._snapBackScale, this._snapBackScale);
this._dragActor.opacity = 0;
this._animationInProgress = true;
Tweener.addTween(this._dragActor,
{ opacity: this._dragOrigOpacity,
time: REVERT_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._onAnimationComplete,
onCompleteScope: this,
onCompleteParams: [this._dragActor, eventTime]
});
},
_onAnimationComplete : function (dragActor, eventTime) {
if (this._dragOrigParent) { if (this._dragOrigParent) {
dragActor.reparent(this._dragOrigParent); dragActor.reparent(this._dragOrigParent);
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale); dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
@ -385,7 +419,7 @@ _Draggable.prototype = {
} }
this.emit('drag-end', eventTime, false); this.emit('drag-end', eventTime, false);
this._snapBackInProgress = false; this._animationInProgress = false;
if (!this._buttonDown) if (!this._buttonDown)
this._dragComplete(); this._dragComplete();
}, },

View File

@ -125,7 +125,8 @@ WindowClone.prototype = {
Lang.bind(this, this._onLeave)); Lang.bind(this, this._onLeave));
this._draggable = DND.makeDraggable(this.actor, this._draggable = DND.makeDraggable(this.actor,
{ dragActorMaxSize: WINDOW_DND_SIZE, { restoreOnSuccess: true,
dragActorMaxSize: WINDOW_DND_SIZE,
dragActorOpacity: DRAGGING_WINDOW_OPACITY }); dragActorOpacity: DRAGGING_WINDOW_OPACITY });
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin)); this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd)); this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));

View File

@ -1244,7 +1244,6 @@ SingleView.prototype = {
this._timeoutId = 0; this._timeoutId = 0;
} }
this._dropGroup.lower_bottom(); this._dropGroup.lower_bottom();
actor.opacity = 255;
this._inDrag = false; this._inDrag = false;
this._computeWorkspacePositions(); this._computeWorkspacePositions();
this._updateWorkspaceActors(true); this._updateWorkspaceActors(true);