package com.christophdietze.jack.client.view; import java.util.HashMap; import java.util.Map; import com.allen_sauer.gwt.dnd.client.AbstractDragController; import com.allen_sauer.gwt.dnd.client.DragEndEvent; import com.allen_sauer.gwt.dnd.client.DragHandlerAdapter; import com.allen_sauer.gwt.dnd.client.DragStartEvent; import com.allen_sauer.gwt.dnd.client.util.DOMUtil; import com.allen_sauer.gwt.log.client.Log; import com.christophdietze.jack.client.presenter.DragAndDropPresenter; import com.christophdietze.jack.client.resources.MyClientBundle; import com.christophdietze.jack.client.resources.MyCss; import com.christophdietze.jack.client.resources.PieceImageBundle; import com.christophdietze.jack.client.resources.PieceImageProvider; import com.christophdietze.jack.shared.board.ChessUtils; import com.christophdietze.jack.shared.board.Piece; import com.christophdietze.jack.shared.board.Position; import com.google.gwt.dom.client.StyleInjector; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.RootLayoutPanel; import com.google.gwt.user.client.ui.RootPanel; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton public class DragAndDropView implements DragAndDropPresenter.View { private static MyCss CSS = MyClientBundle.CSS; static { StyleInjector.inject(MyClientBundle.INSTANCE.gwtDndOverrides().getText()); CSS.ensureInjected(); } private DragAndDropPresenter model; private BoardPanel boardPanel; private Map<Image, Integer> imageMap = new HashMap<Image, Integer>(); /** java.util.BitSet is not available in GWT */ private boolean[] draggablesBitSet = new boolean[64]; private MyDragController dragController; private boolean enabled = true; @Inject public DragAndDropView(DragAndDropPresenter model, BoardPanel boardPanel) { this.model = model; this.boardPanel = boardPanel; dragController = new MyDragController(); dragController.setBehaviorDragStartSensitivity(3); initImageMap(); updateDraggables(); // initSelectionMove(); model.bindView(this); Log.debug(this.getClass().getName() + " initialized"); } private void initImageMap() { for (int index = 0; index < 64; ++index) { Image image = boardPanel.getSquares()[index].getImage(); imageMap.put(image, index); } } @Override public void update() { updateDraggables(); } private void updateDraggables() { if (!enabled) { return; } Position position = model.getGame().getPosition(); for (int index = 0; index < 64; ++index) { int viewIndex = model.getGame().isWhiteAtBottom() ? index : 63 - index; if (position.getPiece(index).isPiece() && !draggablesBitSet[viewIndex]) { draggablesBitSet[viewIndex] = true; Image image = boardPanel.getSquares()[viewIndex].getImage(); dragController.makeDraggable(image); } if (!position.getPiece(index).isPiece() && draggablesBitSet[viewIndex]) { draggablesBitSet[viewIndex] = false; Image image = boardPanel.getSquares()[viewIndex].getImage(); dragController.makeNotDraggable(image); } } } @Override public void setEnabled(boolean enabled) { this.enabled = enabled; if (enabled) { updateDraggables(); } else { for (int index = 0; index < 64; ++index) { if (draggablesBitSet[index]) { dragController.makeNotDraggable(boardPanel.getSquares()[index].getImage()); draggablesBitSet[index] = false; } } } } private class MyDragController extends AbstractDragController { private Image draggingImage = new Image(); public MyDragController() { super(RootPanel.get()); draggingImage.setResource(PieceImageBundle.INSTANCE.empty()); draggingImage.addStyleName(CSS.draggingImage()); draggingImage.setVisible(false); RootLayoutPanel.get().add(draggingImage); this.addDragHandler(new DragHandlerAdapter() { @Override public void onDragStart(DragStartEvent event) { draggingImage.setVisible(true); Image image = (Image) event.getContext().draggable; int index = imageMap.get(image); if (!model.getGame().isWhiteAtBottom()) { index = 63 - index; } Piece piece = model.getGame().getPosition().getPiece(index); draggingImage.setResource(PieceImageProvider.getImageResource(piece)); } @Override public void onDragEnd(DragEndEvent event) { draggingImage.setVisible(false); Image srcImage = (Image) event.getContext().draggable; int fromIndex = imageMap.get(srcImage); int toIndex = calcIndexOfMouse(); if (toIndex < 0) { return; } if (!model.getGame().isWhiteAtBottom()) { fromIndex = 63 - fromIndex; toIndex = 63 - toIndex; } model.makeMove(fromIndex, toIndex); } }); } @Override public void dragMove() { int desiredLeft = context.desiredDraggableX; int desiredTop = context.desiredDraggableY; DOMUtil.fastSetElementPosition(draggingImage.getElement(), desiredLeft, desiredTop); } private int calcIndexOfMouse() { int squareWidth = boardPanel.getSquares()[0].getOffsetWidth(); int leftMost = boardPanel.getSquares()[0].getAbsoluteLeft(); int file = (context.mouseX - leftMost) / squareWidth; if (context.mouseX < leftMost || file >= 8) { return -1; } int squareHeight = boardPanel.getSquares()[0].getOffsetHeight(); int bottom = boardPanel.getSquares()[0].getAbsoluteTop() + squareHeight; int rank = context.mouseY > bottom ? 100 : (bottom - context.mouseY) / squareHeight; if (context.mouseY > bottom || rank >= 8) { return -1; } return ChessUtils.toIndex(file, rank); } } }