Add API to programmatically initiate a drag
For some use cases we have other behavior on mouse press and want to manually control when a drag starts. Split out the drag initiation code into startDrag.
This commit is contained in:
parent
3e54087e42
commit
1a834f7d8b
150
js/ui/dnd.js
150
js/ui/dnd.js
@ -8,15 +8,17 @@ const Tweener = imports.ui.tweener;
|
|||||||
|
|
||||||
const SNAP_BACK_ANIMATION_TIME = 0.25;
|
const SNAP_BACK_ANIMATION_TIME = 0.25;
|
||||||
|
|
||||||
function _Draggable(actor) {
|
function _Draggable(actor, manualMode) {
|
||||||
this._init(actor);
|
this._init(actor, manualMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
_Draggable.prototype = {
|
_Draggable.prototype = {
|
||||||
_init : function(actor) {
|
_init : function(actor, manualMode) {
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
this.actor.connect('button-press-event',
|
if (!manualMode)
|
||||||
Lang.bind(this, this._onButtonPress));
|
this.actor.connect('button-press-event',
|
||||||
|
Lang.bind(this, this._onButtonPress));
|
||||||
|
this._haveSourceGrab = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onButtonPress : function (actor, event) {
|
_onButtonPress : function (actor, event) {
|
||||||
@ -25,6 +27,7 @@ _Draggable.prototype = {
|
|||||||
if (Tweener.getTweenCount(actor))
|
if (Tweener.getTweenCount(actor))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
this._haveSourceGrab = true;
|
||||||
this._grabActor(actor);
|
this._grabActor(actor);
|
||||||
|
|
||||||
let [stageX, stageY] = event.get_coords();
|
let [stageX, stageY] = event.get_coords();
|
||||||
@ -66,6 +69,80 @@ _Draggable.prototype = {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* startDrag:
|
||||||
|
* @actor: Origin actor for drag and drop
|
||||||
|
* @stageX: X coordinate of event
|
||||||
|
* @stageY: Y coordinate of event
|
||||||
|
* @time: Event timestamp
|
||||||
|
*
|
||||||
|
* Directly initiate a drag and drop operation from the given actor.
|
||||||
|
* This function is useful to call if you've specified manualMode
|
||||||
|
* for the draggable.
|
||||||
|
*/
|
||||||
|
startDrag: function (actor, stageX, stageY, time) {
|
||||||
|
this.emit('drag-begin', time);
|
||||||
|
|
||||||
|
this._dragStartX = stageX;
|
||||||
|
this._dragStartY = stageY;
|
||||||
|
|
||||||
|
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
||||||
|
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
||||||
|
// Drag actor does not always have to be the same as actor. For example drag actor
|
||||||
|
// can be an image that's part of the actor. So to perform "snap back" correctly we need
|
||||||
|
// to know what was the drag actor source.
|
||||||
|
if (this.actor._delegate.getDragActorSource) {
|
||||||
|
this._dragActorSource = this.actor._delegate.getDragActorSource();
|
||||||
|
// If the user dragged from the source, then position
|
||||||
|
// the dragActor over it. Otherwise, center it
|
||||||
|
// around the pointer
|
||||||
|
let [sourceX, sourceY] = this._dragActorSource.get_transformed_position();
|
||||||
|
let [sourceWidth, sourceHeight] = this._dragActorSource.get_transformed_size();
|
||||||
|
let x, y;
|
||||||
|
if (stageX > sourceX && stageX <= sourceX + sourceWidth &&
|
||||||
|
stageY > sourceY && stageY <= sourceY + sourceHeight) {
|
||||||
|
x = sourceX;
|
||||||
|
y = sourceY;
|
||||||
|
} else {
|
||||||
|
x = stageX - this._dragActor.width / 2;
|
||||||
|
y = stageY - this._dragActor.height / 2;
|
||||||
|
}
|
||||||
|
this._dragActor.set_position(x, y);
|
||||||
|
} else {
|
||||||
|
this._dragActorSource = this.actor;
|
||||||
|
}
|
||||||
|
this._dragOrigParent = undefined;
|
||||||
|
if (this._haveSourceGrab) {
|
||||||
|
this._haveSourceGrab = false;
|
||||||
|
this._ungrabActor(actor);
|
||||||
|
}
|
||||||
|
this._grabActor(this._dragActor);
|
||||||
|
|
||||||
|
this._dragOffsetX = this._dragActor.x - this._dragStartX;
|
||||||
|
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
||||||
|
} else {
|
||||||
|
this._dragActor = actor;
|
||||||
|
this._dragActorSource = undefined;
|
||||||
|
this._dragOrigParent = actor.get_parent();
|
||||||
|
this._dragOrigX = this._dragActor.x;
|
||||||
|
this._dragOrigY = this._dragActor.y;
|
||||||
|
this._dragOrigScale = this._dragActor.scale_x;
|
||||||
|
|
||||||
|
let [actorStageX, actorStageY] = actor.get_transformed_position();
|
||||||
|
this._dragOffsetX = actorStageX - this._dragStartX;
|
||||||
|
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||||
|
|
||||||
|
// Set the actor's scale such that it will keep the same
|
||||||
|
// transformed size when it's reparented to the stage
|
||||||
|
let [scaledWidth, scaledHeight] = actor.get_transformed_size();
|
||||||
|
actor.set_scale(scaledWidth / actor.width,
|
||||||
|
scaledHeight / actor.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dragActor.reparent(actor.get_stage());
|
||||||
|
this._dragActor.raise_top();
|
||||||
|
},
|
||||||
|
|
||||||
_onMotion : function (actor, event) {
|
_onMotion : function (actor, event) {
|
||||||
let [stageX, stageY] = event.get_coords();
|
let [stageX, stageY] = event.get_coords();
|
||||||
|
|
||||||
@ -75,55 +152,7 @@ _Draggable.prototype = {
|
|||||||
if (!this._dragActor &&
|
if (!this._dragActor &&
|
||||||
(Math.abs(stageX - this._dragStartX) > threshold ||
|
(Math.abs(stageX - this._dragStartX) > threshold ||
|
||||||
Math.abs(stageY - this._dragStartY) > threshold)) {
|
Math.abs(stageY - this._dragStartY) > threshold)) {
|
||||||
this.emit('drag-begin', event.get_time());
|
this.startDrag(actor, stageX, stageY, event.get_time());
|
||||||
|
|
||||||
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
|
||||||
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
|
||||||
// Drag actor does not always have to be the same as actor. For example drag actor
|
|
||||||
// can be an image that's part of the actor. So to perform "snap back" correctly we need
|
|
||||||
// to know what was the drag actor source.
|
|
||||||
if (this.actor._delegate.getDragActorSource) {
|
|
||||||
this._dragActorSource = this.actor._delegate.getDragActorSource();
|
|
||||||
// If the user dragged from the source, then position
|
|
||||||
// the dragActor over it. Otherwise, center it
|
|
||||||
// around the pointer
|
|
||||||
let [sourceX, sourceY] = this._dragActorSource.get_transformed_position();
|
|
||||||
let [sourceWidth, sourceHeight] = this._dragActorSource.get_transformed_size();
|
|
||||||
if (stageX > sourceX && stageX <= sourceX + sourceWidth &&
|
|
||||||
stageY > sourceY && stageY <= sourceY + sourceHeight)
|
|
||||||
this._dragActor.set_position(sourceX, sourceY);
|
|
||||||
else
|
|
||||||
this._dragActor.set_position(stageX - this._dragActor.width / 2, stageY - this._dragActor.height / 2);
|
|
||||||
} else {
|
|
||||||
this._dragActorSource = this.actor;
|
|
||||||
}
|
|
||||||
this._dragOrigParent = undefined;
|
|
||||||
this._ungrabActor(actor);
|
|
||||||
this._grabActor(this._dragActor);
|
|
||||||
|
|
||||||
this._dragOffsetX = this._dragActor.x - this._dragStartX;
|
|
||||||
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
|
||||||
} else {
|
|
||||||
this._dragActor = actor;
|
|
||||||
this._dragActorSource = undefined;
|
|
||||||
this._dragOrigParent = actor.get_parent();
|
|
||||||
this._dragOrigX = this._dragActor.x;
|
|
||||||
this._dragOrigY = this._dragActor.y;
|
|
||||||
this._dragOrigScale = this._dragActor.scale_x;
|
|
||||||
|
|
||||||
let [actorStageX, actorStageY] = actor.get_transformed_position();
|
|
||||||
this._dragOffsetX = actorStageX - this._dragStartX;
|
|
||||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
|
||||||
|
|
||||||
// Set the actor's scale such that it will keep the same
|
|
||||||
// transformed size when it's reparented to the stage
|
|
||||||
let [scaledWidth, scaledHeight] = actor.get_transformed_size();
|
|
||||||
actor.set_scale(scaledWidth / actor.width,
|
|
||||||
scaledHeight / actor.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._dragActor.reparent(actor.get_stage());
|
|
||||||
this._dragActor.raise_top();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are dragging, update the position
|
// If we are dragging, update the position
|
||||||
@ -149,7 +178,7 @@ _Draggable.prototype = {
|
|||||||
event.get_time());
|
event.get_time());
|
||||||
}
|
}
|
||||||
target = target.get_parent();
|
target = target.get_parent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -225,6 +254,13 @@ _Draggable.prototype = {
|
|||||||
|
|
||||||
Signals.addSignalMethods(_Draggable.prototype);
|
Signals.addSignalMethods(_Draggable.prototype);
|
||||||
|
|
||||||
function makeDraggable(actor) {
|
/**
|
||||||
return new _Draggable(actor);
|
* makeDraggable:
|
||||||
|
* @actor: Source actor
|
||||||
|
* @manualMode: If given, do not automatically start drag and drop on click
|
||||||
|
*
|
||||||
|
* Create an object which controls drag and drop for the given actor.
|
||||||
|
*/
|
||||||
|
function makeDraggable(actor, manualMode) {
|
||||||
|
return new _Draggable(actor, manualMode);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user