[dnd] Add monitoring hooks for motion/drop events
Sometimes it is desirable to be able to react to DND events that happen outside a target actor's bounds, e.g. to implement reactive screen edges. Add a simple interface which allows to hook into drag motion and drop handling without jumping through ugly hoops. https://bugzilla.gnome.org/show_bug.cgi?id=620504
This commit is contained in:
parent
6e09cc5fc8
commit
c50e324366
72
js/ui/dnd.js
72
js/ui/dnd.js
@ -17,8 +17,22 @@ const SNAP_BACK_ANIMATION_TIME = 0.25;
|
|||||||
// Time to animate to original position on success
|
// Time to animate to original position on success
|
||||||
const REVERT_ANIMATION_TIME = 0.75;
|
const REVERT_ANIMATION_TIME = 0.75;
|
||||||
|
|
||||||
|
const DragMotionResult = {
|
||||||
|
NO_DROP: 0,
|
||||||
|
COPY_DROP: 1,
|
||||||
|
MOVE_DROP: 2,
|
||||||
|
CONTINUE: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const DragDropResult = {
|
||||||
|
FAILURE: 0,
|
||||||
|
SUCCESS: 1,
|
||||||
|
CONTINUE: 2
|
||||||
|
};
|
||||||
|
|
||||||
let eventHandlerActor = null;
|
let eventHandlerActor = null;
|
||||||
let currentDraggable = null;
|
let currentDraggable = null;
|
||||||
|
let dragMonitors = [];
|
||||||
|
|
||||||
function _getEventHandlerActor() {
|
function _getEventHandlerActor() {
|
||||||
if (!eventHandlerActor) {
|
if (!eventHandlerActor) {
|
||||||
@ -36,6 +50,18 @@ function _getEventHandlerActor() {
|
|||||||
return eventHandlerActor;
|
return eventHandlerActor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addDragMonitor(monitor) {
|
||||||
|
dragMonitors.push(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeMonitor(monitor) {
|
||||||
|
for (let i = 0; i < dragMonitors.length; i++)
|
||||||
|
if (dragMonitors[i] == monitor) {
|
||||||
|
dragMonitors.splice(i, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function _Draggable(actor, params) {
|
function _Draggable(actor, params) {
|
||||||
this._init(actor, params);
|
this._init(actor, params);
|
||||||
}
|
}
|
||||||
@ -294,12 +320,37 @@ _Draggable.prototype = {
|
|||||||
if (this._dragActor) {
|
if (this._dragActor) {
|
||||||
this._dragActor.set_position(stageX + this._dragOffsetX,
|
this._dragActor.set_position(stageX + this._dragOffsetX,
|
||||||
stageY + this._dragOffsetY);
|
stageY + this._dragOffsetY);
|
||||||
|
|
||||||
// Because we want to find out what other actor is located at the current position of this._dragActor,
|
// Because we want to find out what other actor is located at the current position of this._dragActor,
|
||||||
// we have to temporarily hide this._dragActor.
|
// we have to temporarily hide this._dragActor.
|
||||||
this._dragActor.hide();
|
this._dragActor.hide();
|
||||||
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||||
stageX, stageY);
|
stageX, stageY);
|
||||||
this._dragActor.show();
|
this._dragActor.show();
|
||||||
|
|
||||||
|
// We call observers only once per motion with the innermost
|
||||||
|
// target actor. If necessary, the observer can walk the
|
||||||
|
// parent itself.
|
||||||
|
let dragEvent = {
|
||||||
|
x: stageX,
|
||||||
|
y: stageY,
|
||||||
|
dragActor: this._dragActor,
|
||||||
|
targetActor: target
|
||||||
|
};
|
||||||
|
for (let i = 0; i < dragMonitors.length; i++) {
|
||||||
|
let motionFunc = dragMonitors[i].dragMotion;
|
||||||
|
if (motionFunc)
|
||||||
|
switch (motionFunc(dragEvent)) {
|
||||||
|
case DragMotionResult.NO_DROP:
|
||||||
|
case DragMotionResult.COPY_DROP:
|
||||||
|
case DragMotionResult.MOVE_DROP:
|
||||||
|
// TODO: set a special cursor or something ;)
|
||||||
|
return true;
|
||||||
|
case DragMotionResult.CONTINUE:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (target) {
|
while (target) {
|
||||||
if (target._delegate && target._delegate.handleDragOver) {
|
if (target._delegate && target._delegate.handleDragOver) {
|
||||||
let [r, targX, targY] = target.transform_stage_point(stageX, stageY);
|
let [r, targX, targY] = target.transform_stage_point(stageX, stageY);
|
||||||
@ -327,6 +378,27 @@ _Draggable.prototype = {
|
|||||||
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||||
dropX, dropY);
|
dropX, dropY);
|
||||||
this._dragActor.show();
|
this._dragActor.show();
|
||||||
|
|
||||||
|
// We call observers only once per motion with the innermost
|
||||||
|
// target actor. If necessary, the observer can walk the
|
||||||
|
// parent itself.
|
||||||
|
let dropEvent = {
|
||||||
|
dropActor: this._dragActor,
|
||||||
|
targetActor: target,
|
||||||
|
clutterEvent: event
|
||||||
|
};
|
||||||
|
for (let i = 0; i < dragMonitors.length; i++) {
|
||||||
|
let dropFunc = dragMonitors[i].dragDrop;
|
||||||
|
if (dropFunc)
|
||||||
|
switch (dropFunc(dropEvent)) {
|
||||||
|
case DragDropResult.FAILURE:
|
||||||
|
case DragDropResult.SUCCESS:
|
||||||
|
return true;
|
||||||
|
case DragDropResult.CONTINUE:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (target) {
|
while (target) {
|
||||||
if (target._delegate && target._delegate.acceptDrop) {
|
if (target._delegate && target._delegate.acceptDrop) {
|
||||||
let [r, targX, targY] = target.transform_stage_point(dropX, dropY);
|
let [r, targX, targY] = target.transform_stage_point(dropX, dropY);
|
||||||
|
Loading…
Reference in New Issue
Block a user