package com.kartoflane.superluminal2.tools;
import java.util.ArrayList;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import com.kartoflane.superluminal2.core.Grid;
import com.kartoflane.superluminal2.core.LayeredPainter;
import com.kartoflane.superluminal2.core.Manager;
import com.kartoflane.superluminal2.core.Grid.Snapmodes;
import com.kartoflane.superluminal2.core.LayeredPainter.Layers;
import com.kartoflane.superluminal2.ftl.RoomObject;
import com.kartoflane.superluminal2.mvc.controllers.AbstractController;
import com.kartoflane.superluminal2.mvc.controllers.RoomController;
import com.kartoflane.superluminal2.ui.EditorWindow;
import com.kartoflane.superluminal2.ui.OverviewWindow;
import com.kartoflane.superluminal2.ui.ShipContainer;
import com.kartoflane.superluminal2.ui.sidebar.RoomToolComposite;
import com.kartoflane.superluminal2.undo.UndoableCreateEdit;
public class RoomTool extends Tool {
public static final int COLLISION_TOLERANCE = ShipContainer.CELL_SIZE / 2;
// Room creation helper variables
private Point createOrigin;
private Rectangle createBounds;
private boolean canCreate = false;
/** A flag indicating whether or not the user is in the process of creating a new room */
private boolean creating = false;
public RoomTool(EditorWindow window) {
super(window);
createBounds = new Rectangle(0, 0, 0, 0);
}
@Override
public void select() {
cursor.setSize(ShipContainer.CELL_SIZE, ShipContainer.CELL_SIZE);
cursor.setSnapMode(Snapmodes.CELL);
cursor.updateView();
cursor.setVisible(false);
CreationTool ctool = (CreationTool) Manager.getTool(Tools.CREATOR);
ctool.getToolComposite(null).clearDataContainer();
Composite dataC = ctool.getToolComposite(null).getDataContainer();
createToolComposite(dataC);
dataC.layout(true);
}
@Override
public void deselect() {
cursor.updateView();
cursor.setVisible(false);
CreationTool ctool = (CreationTool) Manager.getTool(Tools.CREATOR);
ctool.getToolComposite(null).clearDataContainer();
}
@Override
public RoomToolComposite getToolComposite(Composite parent) {
return (RoomToolComposite) super.getToolComposite(parent);
}
@Override
public RoomToolComposite createToolComposite(Composite parent) {
if (parent == null)
throw new IllegalArgumentException("Parent must not be null.");
compositeInstance = new RoomToolComposite(parent);
return (RoomToolComposite) compositeInstance;
}
public boolean isCreating() {
return creating;
}
public boolean canCreate() {
return canCreate;
}
@Override
public void mouseDoubleClick(MouseEvent e) {
}
@Override
public void mouseDown(MouseEvent e) {
// Check the conditions again in case the variable is outdated
canCreate = canCreate(cursor.getDimensions());
if (e.button == 1 && EditorWindow.getInstance().isFocusControl()) {
// room creation begin
if (Grid.getInstance().isLocAccessible(e.x, e.y)) {
createOrigin = Grid.getInstance().snapToGrid(e.x, e.y, Snapmodes.CORNER_TL);
createBounds.x = createOrigin.x;
createBounds.y = createOrigin.y;
createBounds.width = ShipContainer.CELL_SIZE;
createBounds.height = ShipContainer.CELL_SIZE;
creating = true;
cursor.updateView();
}
} else if (e.button == 3) {
// room creation abort
if (creating) {
creating = false;
canCreate = canCreate(cursor.getDimensions());
cursor.updateView();
cursor.resize(ShipContainer.CELL_SIZE, ShipContainer.CELL_SIZE);
cursor.reposition(Grid.getInstance().snapToGrid(e.x, e.y, cursor.getSnapMode()));
cursor.setVisible(!Manager.leftMouseDown);
}
}
}
@Override
public void mouseUp(MouseEvent e) {
if (e.button == 1) {
if (creating) {
// room creation finalize
createBounds = cursor.getBounds();
if (canCreate) {
// if the area is clear, create the room
ShipContainer container = Manager.getCurrentShip();
RoomObject object = new RoomObject();
RoomController roomController = RoomController.newInstance(container, object);
// round the size to match grid cell size (bounds are usually off by a pixel or two as an error margin)
Point p = Grid.getInstance().snapToGrid(createBounds.width, createBounds.height, Snapmodes.CROSS);
createBounds.width = p.x;
createBounds.height = p.y;
p = Grid.getInstance().snapToGrid(createBounds.x, createBounds.y, Snapmodes.CROSS);
createBounds.x = p.x;
createBounds.y = p.y;
p = Grid.getInstance().snapToGrid(createBounds.x + createBounds.width / 2,
createBounds.y + createBounds.height / 2, roomController.getSnapMode());
roomController.setSize(createBounds.width, createBounds.height);
roomController.setLocation(p.x, p.y);
container.add(roomController);
container.store(roomController);
roomController.updateFollowOffset();
container.updateBoundingArea();
window.canvasRedraw(createBounds);
OverviewWindow.staticUpdate(roomController);
container.postEdit(new UndoableCreateEdit(roomController));
} else {
// if collided with a room, just redraw the area (cursor isn't visible)
window.canvasRedraw(createBounds);
}
creating = false;
canCreate = canCreate(cursor.getDimensions());
}
cursor.updateView();
cursor.resize(ShipContainer.CELL_SIZE, ShipContainer.CELL_SIZE);
cursor.reposition(Grid.getInstance().snapToGrid(e.x, e.y, cursor.getSnapMode()));
cursor.setVisible(true);
}
}
@Override
public void mouseMove(MouseEvent e) {
if (creating) {
// update room creation rectangle
if (!Grid.getInstance().isLocAccessible(e.x, e.y))
return;
Snapmodes snapmode = (e.x >= createOrigin.x && e.y >= createOrigin.y ? Snapmodes.CORNER_BR :
(e.x >= createOrigin.x && e.y < createOrigin.y ? Snapmodes.CORNER_TR :
(e.x < createOrigin.x && e.y >= createOrigin.y ? Snapmodes.CORNER_BL :
Snapmodes.CORNER_TL)));
Point cursor = Grid.getInstance().snapToGrid(e.x + 1, e.y + 1, snapmode);
Point anchor = new Point(0, 0);
anchor.x = createOrigin.x + (cursor.x < createOrigin.x ? ShipContainer.CELL_SIZE : 0);
anchor.y = createOrigin.y + (cursor.y < createOrigin.y ? ShipContainer.CELL_SIZE : 0);
anchor = Grid.getInstance().snapToGrid(anchor.x, anchor.y, Snapmodes.CROSS);
Rectangle oldCreateBounds = this.cursor.getBounds();
createBounds.x = Math.min(anchor.x, cursor.x);
createBounds.y = Math.min(anchor.y, cursor.y);
createBounds.width = Math.max(Math.abs(anchor.x - cursor.x), ShipContainer.CELL_SIZE);
createBounds.height = Math.max(Math.abs(anchor.y - cursor.y), ShipContainer.CELL_SIZE);
// only redraw when we actually have to
if (!oldCreateBounds.equals(createBounds)) {
canCreate = canCreate(createBounds);
this.cursor.updateView();
this.cursor.setSize(createBounds.width, createBounds.height);
this.cursor.reposition(createBounds.x + createBounds.width / 2, createBounds.y + createBounds.height / 2);
window.canvasRedraw(oldCreateBounds);
}
} else {
// move the cursor around to follow mouse
if (Grid.getInstance().isLocAccessible(e.x, e.y)) {
cursor.setVisible(!Manager.leftMouseDown);
Point p = Grid.getInstance().snapToGrid(e.x, e.y, cursor.getSnapMode());
// always redraw it: prevents an odd visual bug where the box sometimes doesn't register it was moved
cursor.reposition(p.x, p.y);
} else if (cursor.isVisible()) {
cursor.setVisible(false);
cursor.redraw();
}
canCreate = canCreate(cursor.getDimensions());
}
cursor.updateView();
}
@Override
public void mouseEnter(MouseEvent e) {
cursor.setVisible(!Manager.leftMouseDown);
cursor.redraw();
}
@Override
public void mouseExit(MouseEvent e) {
cursor.setVisible(false);
cursor.redraw();
}
@Override
public void mouseHover(MouseEvent e) {
}
private boolean canCreate(Rectangle createBounds) {
ShipContainer container = Manager.getCurrentShip();
if (!container.isRoomsVisible())
return false;
Rectangle anchorBounds = container.getShipController().getBounds();
if (createBounds.x <= anchorBounds.x || createBounds.y <= anchorBounds.y)
return false;
boolean collided = false;
ArrayList<AbstractController> layer = LayeredPainter.getInstance().getLayerMap().get(Layers.ROOM);
for (int i = 0; i < layer.size() && !collided; i++) {
AbstractController c = layer.get(i);
if (c.isVisible() && c.collides(createBounds.x + COLLISION_TOLERANCE, createBounds.y + COLLISION_TOLERANCE,
createBounds.width - 2 * COLLISION_TOLERANCE, createBounds.height - 2 * COLLISION_TOLERANCE))
collided = true;
}
return !collided;
}
}