private void drag(RenderableBlock renderable, int dx, int dy,
			WorkspaceWidget widget, boolean isTopLevelBlock) {
		if (!renderable.pickedUp) {
			throw new RuntimeException("dragging without prior pickup");
		}
		// mark this as being dragged
		renderable.dragging = true;
		// move the block by drag amount
		if (!isTopLevelBlock) {
			renderable.setLocation(renderable.getX() + dx, renderable.getY()
					+ dy);
		}
		// send blockEntered/blockExited/blogDragged as appropriate
		if (widget != null) {
			if (!widget.equals(renderable.lastDragWidget)) {
				widget.blockEntered(renderable);
				if (renderable.lastDragWidget != null) {
					renderable.lastDragWidget.blockExited(renderable);
				}
			}
			widget.blockDragged(renderable);
			renderable.lastDragWidget = widget;
		}

		// translate highlight along with the block - this would happen
		// automatically,
		// but putting the call here takes out any lag.
		renderable.highlighter.repaint();
		// Propagate the drag event to anything plugged into this block
		for (BlockConnector socket : BlockLinkChecker
				.getSocketEquivalents(renderable.getBlock())) {
			if (socket.hasBlock()) {
				drag(workspace.getEnv().getRenderableBlock(socket.getBlockID()),
						dx, dy, widget, false);
			}
		}
	}