import groovy.lang.Closure;
/**
- * Returned by onDropEnter/Move and passed to over onDropXyz methods.
+ * Structure returned by onDropEnter/Move and passed to over onDropXyz methods.
*/
public class DropFeedback {
/**
* User data that the rule can use in any way it wants to carry state from one
* operation to another.
+ * <p/>
+ * Filled and owned by the groovy view rule.
*/
public Object userData;
/**
* If true the next screen update will invoke the paint closure.
+ * <p/>
+ * Filled by the groovy view rule to request a paint, and reset by the canvas
+ * after the paint occurred.
*/
public boolean requestPaint;
/**
+ * Set to false by the engine when entering a new view target.
+ * The groovy view rule should set this to true if the current view target is not
+ * a valid drop zone.
+ * <p/>
+ * When set to true, the onDropped() method will not be called if the user releases
+ * the mouse button. Depending on the platform or implementation, the mouse cursor
+ * <em>may</em> reflect that the drop operation is invalid.
+ * <p/>
+ * Rationale: an operation like onDropEnter() is called each time the mouse enters
+ * a new view target and is supposed to return null when the drop cannot happen
+ * <em>at all</em> in that target. However a layout like RelativeLayout decorates
+ * potential targets with "hot spots" that are suitable drop zones, whereas some
+ * other parts of the view are not suitable drop zones. In this case the onDropEnter()
+ * or onDropMove() operation would return a {@link DropFeedback} with
+ * <code>invalidTarget=true</code>.
+ */
+ public boolean invalidTarget;
+
+ /**
* Closure invoked by the canvas to paint the feedback.
+ * <p/>
* The closure will receive 3 arguments: <br/>
* - The {@link IGraphics} context to use for painting. Must not be cached. <br/>
* - The {@link INode} target node last used in a onDropEnter or onDropMove call. <br/>
* - The {@link DropFeedback} returned by the last onDropEnter or onDropMove call. <br/>
+ * <p/>
+ * Filled by the groovy view rule, called by the engine.
*/
public Closure paintClosure;
* <p/>
* When the mouse is captured, drop events will keep going to the rule that started the
* capture and the current INode proxy will not change.
+ * <p/>
+ * Filled by the groovy view rule, read by the engine.
*/
public Rect captureArea;
* Set to true by the drag'n'drop engine when the current drag operation is a copy.
* When false the operation is a move and <em>after</em> a successful drop the source
* elements will be deleted.
+ * <p/>
+ * Filled by the engine, read by groovy view rule.
*/
public boolean isCopy;
/**
* Set to true when the drag'n'drop starts and ends in the same canvas of the
* same Eclipse instance.
+ * <p/>
+ * Filled by the engine, read by groovy view rule.
*/
public boolean sameCanvas;
mCurrentView = mLeaveView;
}
+ if (mFeedback != null && mFeedback.invalidTarget) {
+ // The script said we can't drop here.
+ event.detail = DND.DROP_NONE;
+ }
+
if (mLeaveTargetNode == null || event.detail == DND.DROP_NONE) {
clearDropInfo();
}
df.isCopy = event.detail == DND.DROP_COPY;
}
df.sameCanvas = mCanvas == mGlobalDragInfo.getSourceCanvas();
+ df.invalidTarget = false;
}
/**
*/
public void paintFeedback(GCWrapper gCWrapper) {
if (mTargetNode != null && mFeedback != null && mFeedback.requestPaint) {
- mFeedback.requestPaint = false;
mCanvas.getRulesEngine().callDropFeedbackPaint(gCWrapper, mTargetNode, mFeedback);
+ mFeedback.requestPaint = false;
}
}
}
}
- if (df != null && targetNode != mTargetNode) {
+ if (df == null) {
+ // Provide visual feedback that we are refusing the drop
+ event.detail = DND.DROP_NONE;
+ clearDropInfo();
+
+ } else if (targetNode != mTargetNode) {
// We found a new target node for the drag'n'drop.
// Release the previous one, if any.
callDropLeave();
- // If we previously provided visual feedback that we were refusing
- // the drop, we now need to change it to mean we're accepting it.
- if (event.detail == DND.DROP_NONE) {
- event.detail = DND.DROP_DEFAULT;
- recomputeDragType(event);
- }
-
// And assign the new one
mTargetNode = targetNode;
mFeedback = df;
// We don't need onDropMove in this case
isMove = false;
-
- } else if (df == null) {
- // Provide visual feedback that we are refusing the drop
- event.detail = DND.DROP_NONE;
- clearDropInfo();
}
}
updateDropFeedback(mFeedback, event);
DropFeedback df = mCanvas.getRulesEngine().callOnDropMove(
mTargetNode, mCurrentDragElements, mFeedback, p2);
+
if (df == null) {
// The target is no longer interested in the drop move.
+ event.detail = DND.DROP_NONE;
callDropLeave();
+
} else if (df != mFeedback) {
mFeedback = df;
}
}
+ if (mFeedback != null) {
+ if (event.detail == DND.DROP_NONE && !mFeedback.invalidTarget) {
+ // If we previously provided visual feedback that we were refusing
+ // the drop, we now need to change it to mean we're accepting it.
+ event.detail = DND.DROP_DEFAULT;
+ recomputeDragType(event);
+
+ } else if (mFeedback.invalidTarget) {
+ // Provide visual feedback that we are refusing the drop
+ event.detail = DND.DROP_NONE;
+ }
+ }
+
if (needRedraw || (mFeedback != null && mFeedback.requestPaint)) {
mCanvas.redraw();
}