package com.clearlyspam23.GLE.basic.layers.tile.gui;
import java.awt.BasicStroke;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import org.piccolo2d.PCamera;
import org.piccolo2d.PNode;
import org.piccolo2d.activities.PActivity;
import com.clearlyspam23.GLE.GUI.util.Animatable;
import com.clearlyspam23.GLE.GUI.util.AnimatedOutlineRectNode;
import com.clearlyspam23.GLE.GUI.util.FixedWidthOutlineRectNode;
import com.clearlyspam23.GLE.GUI.util.FixedWidthStroke;
import com.clearlyspam23.GLE.GUI.util.LineNode;
import com.clearlyspam23.GLE.basic.layers.tile.Tile;
import com.clearlyspam23.GLE.basic.layers.tile.TileLocation;
public class MovableTileSelection implements TileSelection, Animatable{
/**
* this class needs to hold a reference to both a box above the current tile layer, and the nodes below that box
* in order to allow saving when regions are selected, this box will leave nodes below it unchanged, until they are moved by this box
* @author clearlyspam23
*
*/
public class SelectionPNode extends TileLayerPNode{
/**
*
*/
private static final long serialVersionUID = 1L;
private TileLayerPNode lowerLayer;
public SelectionPNode(TileLayerPNode lowerLayer) {
super(lowerLayer.getGridWidth(), lowerLayer.getGridHeight(), lowerLayer.getLayer(), lowerLayer.getBase());
this.lowerLayer = lowerLayer;
}
public TileLayerPNode getLowerLayer(){
return lowerLayer;
}
public void setToTiles(List<Tile> tiles){
clearAllTiles();
int lowestX = Integer.MAX_VALUE;
int lowestY = Integer.MAX_VALUE;
int highestX = 0;
int highestY = 0;
for(Tile t : tiles){
lowestX = Math.min(lowestX, t.relativeLocation.gridX);
lowestY = Math.min(lowestY, t.relativeLocation.gridY);
highestX = Math.max(highestX, t.relativeLocation.gridX);
highestY = Math.max(highestY, t.relativeLocation.gridY);
}
double width = Math.min(lowerLayer.getWidth(), (highestX-lowestX+1)*getGridWidth());
double height = Math.min(lowerLayer.getHeight(), (highestY-lowestY+1)*getGridHeight());
this.setBounds(getX(), getY(), width, height);
silentlyIgnoreInput(true);
setTilesPickable(false);
for(Tile t : tiles){
if(!isValidLocation(t.relativeLocation.gridX-lowestX, t.relativeLocation.gridY-lowestY))
continue;
TilePNode node = getNodeAt(t.relativeLocation.gridX-lowestX, t.relativeLocation.gridY-lowestY);
node.silentlyIgnoreInput(false);
node.setPickable(true);
node.setTileset(t);
}
calculateBoundingRect();
}
private void calculateBoundingRect(){
List<FixedWidthOutlineRectNode> boundingRect = new ArrayList<FixedWidthOutlineRectNode>();
boundingRect.clear();
TilePNode[][] grid = getNodeGrid();
int[][] sideGrid = new int[grid.length][(grid.length>0 ? grid[0].length : 0)];
for(int i = 0; i < grid.length; i++){
sideGrid[i] = new int[grid[i].length];
for(int j = 0; j < grid[i].length; j++){
sideGrid[i][j] = AnimatedOutlineRectNode.NONE;
if(!grid[i][j].getTileData().isValid())
continue;
//perform edge detection, if any edges are detected, create a node
if(i-1<0||!grid[i-1][j].getTileData().isValid())
sideGrid[i][j]|=AnimatedOutlineRectNode.LEFT;
if(i+1>=grid.length||!grid[i+1][j].getTileData().isValid())
sideGrid[i][j]|=AnimatedOutlineRectNode.RIGHT;
if(j-1<0||!grid[i][j-1].getTileData().isValid())
sideGrid[i][j]|=AnimatedOutlineRectNode.TOP;
if(j+1>=grid[i].length||!grid[i][j+1].getTileData().isValid())
sideGrid[i][j]|=AnimatedOutlineRectNode.BOTTOM;
}
}
//try to build the largest lines possible
List<Line2D> lines = new ArrayList<Line2D>();
for(int i = 0; i < sideGrid.length; i++){
for(int j = 0; j < sideGrid[i].length; j++){
if((sideGrid[i][j]&AnimatedOutlineRectNode.LEFT)==AnimatedOutlineRectNode.LEFT){
int k = 0;
for(; k + j < sideGrid[i].length&&(sideGrid[i][k+j]&AnimatedOutlineRectNode.LEFT)==AnimatedOutlineRectNode.LEFT; k++){
sideGrid[i][j+k] &=~AnimatedOutlineRectNode.LEFT;
}
lines.add(new Line2D.Double(i, j, i, j+k));
}
if((sideGrid[i][j]&AnimatedOutlineRectNode.RIGHT)==AnimatedOutlineRectNode.RIGHT){
int k = 0;
for(; k + j < sideGrid[i].length&&(sideGrid[i][k+j]&AnimatedOutlineRectNode.RIGHT)==AnimatedOutlineRectNode.RIGHT; k++){
sideGrid[i][j+k] &=~AnimatedOutlineRectNode.RIGHT;
}
lines.add(new Line2D.Double(i+1, j, i+1, j+k));
}
if((sideGrid[i][j]&AnimatedOutlineRectNode.TOP)==AnimatedOutlineRectNode.TOP){
int k = 0;
for(; k + i < sideGrid.length&&(sideGrid[i+k][j]&AnimatedOutlineRectNode.TOP)==AnimatedOutlineRectNode.TOP; k++){
sideGrid[i+k][j] &=~AnimatedOutlineRectNode.TOP;
}
lines.add(new Line2D.Double(i, j, i+k, j));
}
if((sideGrid[i][j]&AnimatedOutlineRectNode.BOTTOM)==AnimatedOutlineRectNode.BOTTOM){
int k = 0;
for(; k + i < sideGrid.length&&(sideGrid[i+k][j]&AnimatedOutlineRectNode.BOTTOM)==AnimatedOutlineRectNode.BOTTOM; k++){
sideGrid[i+k][j] &=~AnimatedOutlineRectNode.BOTTOM;
}
lines.add(new Line2D.Double(i, j+1, i+k, j+1));
}
}
}
linesNode.setLines(lines);
linesNode.setBounds(getX(), getY(), getWidth(),getHeight());
}
public void setToOffset(TileLocation location){
if(location.gridX<0)
location.gridX = 0;
else if(location.gridX+getNodeGridWidth()>=lowerLayer.getNodeGridWidth())
location.gridX = lowerLayer.getNodeGridWidth()-getNodeGridWidth();
if(location.gridY<0)
location.gridY = 0;
else if(location.gridY+getNodeGridHeight()>=lowerLayer.getNodeGridHeight())
location.gridY = lowerLayer.getNodeGridHeight()-getNodeGridHeight();
setGridOffset(location);
double x = location.gridX*getGridWidth();
double y = location.gridY*getGridHeight();
double width = Math.min(getNodeGridWidth()*getGridWidth(), lowerLayer.getWidth()-x);
double height = Math.min(getNodeGridHeight()*getGridHeight(), lowerLayer.getHeight()-y);
this.setBounds(0, 0, width, height);
this.setOffset(x, y);
linesNode.setBounds(x, y, width, height);
}
}
public class AnimateLines extends PActivity{
public AnimateLines() {
super(-1, 100);
}
protected void activityStep(long elapsedTime) {
super.activityStep(elapsedTime);
currentStroke = (currentStroke+1)%strokes.length;
linesNode.setStroke(strokes[currentStroke]);
linesNode.repaint();
}
}
private AnimateLines animationActivity = new AnimateLines();
private LineNode linesNode;
private FixedWidthStroke[] strokes = new FixedWidthStroke[12];
private int currentStroke;
private SelectionPNode selectionNode;
private PNode overlayNode = new PNode();
private List<Tile> lowerAnchored = new ArrayList<Tile>();
public MovableTileSelection(PCamera camera, TileLayerPNode lowerLayer, List<Tile> tiles, TileLocation location){
for(int i =0 ; i < strokes.length; i++){
strokes[i] = new FixedWidthStroke(2, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 1.0f, new float[]{6, 6}, i, camera);
}
lowerLayer.silentlyIgnoreInput(true);
linesNode = new LineNode(strokes[currentStroke]);
linesNode.setPickable(false);
overlayNode.addChild(linesNode);
selectionNode = new SelectionPNode(lowerLayer);
selectionNode.setToTiles(tiles);
selectionNode.setToOffset(location);
Animatable.registerAnimation(selectionNode, this);
}
public void setToOffset(TileLocation offset){
selectionNode.setToOffset(offset);
}
@Override
public List<Tile> onCopy() {
List<Tile> out = new ArrayList<Tile>();
for(TilePNode[] ap : selectionNode.getNodeGrid()){
for(TilePNode p : ap){
if(!p.isSilentlyIgnoringInput())
out.add(p.getTile());
}
}
return out;
}
@Override
public int getTileWidth() {
return selectionNode.getNodeGrid().length;
}
@Override
public int getTileHeight() {
return selectionNode.getNodeGrid()[0].length;
}
@Override
public void onRemove() {
selectionNode.lowerLayer.silentlyIgnoreInput(false);
}
@Override
public boolean isNodeInSelection(TilePNode node) {
return selectionNode.isValidLocation(node.getTileLocation());
}
@Override
public void onAnchor() {
lowerAnchored.clear();
for(TilePNode[] ap : selectionNode.getNodeGrid()){
for(TilePNode p : ap){
if(!p.isSilentlyIgnoringInput()){
lowerAnchored.add(selectionNode.getLowerLayer().getNodeAt(p.getTileLocation()).getTile());
System.out.println(p.getTileLocation());
selectionNode.getLowerLayer().getNodeAt(p.getTileLocation()).setTilesetHard(p.getTileData());
}
}
}
}
@Override
public void onLift() {
for(Tile t : lowerAnchored){
System.out.println(t.getLocation());
selectionNode.lowerLayer.setTile(t);
}
}
@Override
public PNode getSelectionNode() {
return selectionNode;
}
@Override
public PNode getOverlayNode() {
return overlayNode;
}
@Override
public void onClear() {
for(TilePNode[] ap : selectionNode.getNodeGrid()){
for(TilePNode p : ap){
p.resetTileset();
}
}
}
@Override
public PActivity getAnimationActivity() {
return animationActivity;
}
public TileLocation getOffset(){
return selectionNode.getGridOffset().copy();
}
@Override
public int getTileCount() {
int count = 0;
for(TilePNode[] ap : selectionNode.getNodeGrid()){
for(TilePNode p : ap){
if(!p.isSilentlyIgnoringInput()){
count++;
}
}
}
return count;
}
@Override
public void setToTiles(List<Tile> tiles) {
for(Tile t : tiles){
selectionNode.setTile(t);
}
}
}