in designer/src/com/android/tools/idea/uibuilder/surface/interaction/DragDropInteraction.java [297:414]
private void moveTo(@SwingCoordinate int x, @SwingCoordinate int y, @InputEventMask final int modifiers, boolean commit) {
mySceneView = myDesignSurface.getSceneViewAtOrPrimary(x, y);
if (mySceneView == null) {
return;
}
myDoesAcceptDropAtLastPosition = true;
myDesignSurface.getLayeredPane().scrollRectToVisible(
new Rectangle(x - NlConstants.DEFAULT_SCREEN_OFFSET_X, y - NlConstants.DEFAULT_SCREEN_OFFSET_Y,
2 * NlConstants.DEFAULT_SCREEN_OFFSET_X, 2 * NlConstants.DEFAULT_SCREEN_OFFSET_Y));
@AndroidCoordinate final int ax = Coordinates.getAndroidX(mySceneView, x);
@AndroidCoordinate final int ay = Coordinates.getAndroidY(mySceneView, y);
Project project = mySceneView.getSceneManager().getModel().getProject();
ViewGroupHandler handler = findViewGroupHandlerAt(x, y);
SceneContext sceneContext = mySceneView.getContext();
SceneComponent viewgroup =
mySceneView.getScene().findComponent(sceneContext,
Coordinates.getAndroidXDip(mySceneView, x),
Coordinates.getAndroidYDip(mySceneView, y));
while (viewgroup != null && !NlComponentHelperKt.isOrHasSuperclass(viewgroup.getNlComponent(), SdkConstants.CLASS_VIEWGROUP)) {
viewgroup = viewgroup.getParent();
}
// No need to change Handler when using CommonDragHandler.
if (!(myDragHandler instanceof CommonDragHandler) && (handler != myCurrentHandler || myCurrentViewgroup != viewgroup)) {
if (myCurrentViewgroup != null) {
myCurrentViewgroup.setDrawState(SceneComponent.DrawState.NORMAL);
}
myCurrentViewgroup = viewgroup;
if (myCurrentViewgroup != null) {
myCurrentViewgroup.setDrawState(SceneComponent.DrawState.DRAG);
}
if (myDragHandler != null) {
myDragHandler.cancel();
myDragHandler = null;
myDesignSurface.repaint();
}
myCurrentHandler = handler;
if (myCurrentHandler != null) {
assert myDragReceiver != null;
String error = null;
ViewHandlerManager viewHandlerManager = ViewHandlerManager.get(project);
for (NlComponent component : myDraggedComponents) {
boolean constraintHelper =
AndroidXConstants.CLASS_CONSTRAINT_LAYOUT_GUIDELINE.isEquals(component.getTagName()) ||
AndroidXConstants.CLASS_CONSTRAINT_LAYOUT_BARRIER.isEquals(component.getTagName()) ||
AndroidXConstants.CLASS_CONSTRAINT_LAYOUT_FLOW.isEquals(component.getTagName()) ||
AndroidXConstants.CLASS_CONSTRAINT_LAYOUT_GROUP.isEquals(component.getTagName()) ||
AndroidXConstants.CLASS_CONSTRAINT_LAYOUT_LAYER.isEquals(component.getTagName()) ||
AndroidXConstants.CLASS_CONSTRAINT_LAYOUT_IMAGE_FILTER_VIEW.isEquals(component.getTagName()) ||
AndroidXConstants.CLASS_CONSTRAINT_LAYOUT_IMAGE_FILTER_BUTTON.isEquals(component.getTagName()) ||
AndroidXConstants.CLASS_CONSTRAINT_LAYOUT_MOCK_VIEW.isEquals(component.getTagName());
boolean acceptableHandler =
(myCurrentHandler instanceof ConstraintLayoutHandler) ||
(myCurrentHandler instanceof ConstraintLayoutHandler.ConstraintLayoutSupported);
if (constraintHelper && !acceptableHandler) {
error = String.format(
"<%1$s> does not accept <%2$s> as a child", myDragReceiver.getNlComponent().getTagName(), component.getTagName());
myDoesAcceptDropAtLastPosition = false;
break;
}
if (!myCurrentHandler.acceptsChild(myDragReceiver, component, ax, ay)) {
error = String.format(
"<%1$s> does not accept <%2$s> as a child", myDragReceiver.getNlComponent().getTagName(), component.getTagName());
myDoesAcceptDropAtLastPosition = false;
break;
}
ViewHandler viewHandler = viewHandlerManager.getHandler(component, () -> {});
if (viewHandler != null && !viewHandler.acceptsParent(myDragReceiver.getNlComponent(), component)) {
error = String.format(
"<%1$s> does not accept <%2$s> as a parent", component.getTagName(), myDragReceiver.getNlComponent().getTagName());
myDoesAcceptDropAtLastPosition = false;
break;
}
}
if (error == null) {
ViewEditorImpl editorImpl = new ViewEditorImpl(mySceneView);
myDragHandler = myCurrentHandler.createDragHandler(editorImpl, myDragReceiver, myDraggedComponents, myType);
if (myDragHandler != null) {
myDragHandler
.start(Coordinates.getAndroidXDip(mySceneView, myStartInfo.getX()),
Coordinates.getAndroidYDip(mySceneView, myStartInfo.getY()),
myStartInfo.getModifiersEx());
}
}
else {
myCurrentHandler = null;
}
}
}
if ((myDragHandler instanceof CommonDragHandler) || (myDragHandler != null && myCurrentHandler != null)) {
String error = myDragHandler.update(Coordinates.pxToDp(mySceneView, ax), Coordinates.pxToDp(mySceneView, ay), modifiers, sceneContext);
final List<NlComponent> added = new ArrayList<>();
if (commit && error == null) {
added.addAll(myDraggedComponents);
final NlModel model = mySceneView.getSceneManager().getModel();
InsertType insertType = model.getTreeWriter().determineInsertType(myType, myTransferItem, false /* not for preview */, true /* generateIds */);
// TODO: Run this *after* making a copy
myDragHandler.commit(ax, ay, modifiers, insertType);
model.notifyModified(ChangeType.DND_COMMIT);
// Do not select the created component at this point see b/124231532.
// The commit above is executed asynchronously and may not have completed yet.
// The selection should not be moved before the components are properly created and placed under its new parent.
// Other tools like the attributes panel may rely on the component being fully completed.
// Move the focus to the design area in case this component is created from the palette see b/69394814
myDesignSurface.getLayeredPane().requestFocus();
}
mySceneView.getSurface().repaint();
}
}