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:
Colin Walters 2009-09-01 14:07:31 -04:00
parent 3e54087e42
commit 1a834f7d8b

View File

@ -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;
if (!manualMode)
this.actor.connect('button-press-event', this.actor.connect('button-press-event',
Lang.bind(this, this._onButtonPress)); 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,16 +69,22 @@ _Draggable.prototype = {
return false; return false;
}, },
_onMotion : function (actor, event) { /**
let [stageX, stageY] = event.get_coords(); * 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);
// If we haven't begun a drag, see if the user has moved the this._dragStartX = stageX;
// mouse enough to trigger a drag this._dragStartY = stageY;
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
if (!this._dragActor &&
(Math.abs(stageX - this._dragStartX) > threshold ||
Math.abs(stageY - this._dragStartY) > threshold)) {
this.emit('drag-begin', event.get_time());
if (this.actor._delegate && this.actor._delegate.getDragActor) { if (this.actor._delegate && this.actor._delegate.getDragActor) {
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY); this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
@ -89,16 +98,24 @@ _Draggable.prototype = {
// around the pointer // around the pointer
let [sourceX, sourceY] = this._dragActorSource.get_transformed_position(); let [sourceX, sourceY] = this._dragActorSource.get_transformed_position();
let [sourceWidth, sourceHeight] = this._dragActorSource.get_transformed_size(); let [sourceWidth, sourceHeight] = this._dragActorSource.get_transformed_size();
let x, y;
if (stageX > sourceX && stageX <= sourceX + sourceWidth && if (stageX > sourceX && stageX <= sourceX + sourceWidth &&
stageY > sourceY && stageY <= sourceY + sourceHeight) stageY > sourceY && stageY <= sourceY + sourceHeight) {
this._dragActor.set_position(sourceX, sourceY); x = sourceX;
else y = sourceY;
this._dragActor.set_position(stageX - this._dragActor.width / 2, stageY - this._dragActor.height / 2); } else {
x = stageX - this._dragActor.width / 2;
y = stageY - this._dragActor.height / 2;
}
this._dragActor.set_position(x, y);
} else { } else {
this._dragActorSource = this.actor; this._dragActorSource = this.actor;
} }
this._dragOrigParent = undefined; this._dragOrigParent = undefined;
if (this._haveSourceGrab) {
this._haveSourceGrab = false;
this._ungrabActor(actor); this._ungrabActor(actor);
}
this._grabActor(this._dragActor); this._grabActor(this._dragActor);
this._dragOffsetX = this._dragActor.x - this._dragStartX; this._dragOffsetX = this._dragActor.x - this._dragStartX;
@ -124,6 +141,18 @@ _Draggable.prototype = {
this._dragActor.reparent(actor.get_stage()); this._dragActor.reparent(actor.get_stage());
this._dragActor.raise_top(); this._dragActor.raise_top();
},
_onMotion : function (actor, event) {
let [stageX, stageY] = event.get_coords();
// If we haven't begun a drag, see if the user has moved the
// mouse enough to trigger a drag
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
if (!this._dragActor &&
(Math.abs(stageX - this._dragStartX) > threshold ||
Math.abs(stageY - this._dragStartY) > threshold)) {
this.startDrag(actor, stageX, stageY, event.get_time());
} }
// If we are dragging, update the position // If we are dragging, update the position
@ -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);
} }