This commit is contained in:
Martin Haye 2015-05-16 11:00:35 -07:00
commit b2b922aa7c
5 changed files with 193 additions and 9 deletions

View File

@ -16,14 +16,19 @@ import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.Clipboard;
import javafx.scene.input.DataFormat;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.FillRule;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import static org.badvision.outlaweditor.Application.currentPlatform;
@ -33,6 +38,7 @@ import org.badvision.outlaweditor.data.xml.Map;
import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Tile;
import org.badvision.outlaweditor.ui.ToolType;
import org.badvision.outlaweditor.ui.UIAction;
/**
*
@ -75,6 +81,10 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
@Override
public void setDrawMode(DrawMode drawMode) {
this.drawMode = drawMode;
if (drawMode == DrawMode.Eraser) {
ImageCursor cursor = new ImageCursor(new Image("images/eraser.png"));
drawCanvas.setCursor(cursor);
}
}
@Override
@ -85,10 +95,24 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
@Override
public void buildEditorUI(Pane tileEditorAnchorPane) {
anchorPane = tileEditorAnchorPane;
Application.getPrimaryStage().getScene().addEventHandler(KeyEvent.KEY_PRESSED, this::keyPressed);
initCanvas();
redraw();
}
private void keyPressed(KeyEvent e) {
if (e.isControlDown() && e.getCode() == KeyCode.SPACE) {
e.consume();
String category = null;
if (currentTile != null) {
category = currentTile.getCategory();
}
if (this.equals(Application.getInstance().getController().getVisibleEditor())) {
UIAction.showTileSelectModal((AnchorPane) anchorPane, category, this::setCurrentTile);
}
}
}
public void initCanvas() {
if (drawCanvas != null) {
anchorPane.getChildren().remove(drawCanvas);
@ -218,7 +242,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
}
private synchronized void doRedraw() {
drawCanvas.getGraphicsContext2D().clearRect(0, 0, drawCanvas.getWidth(), drawCanvas.getHeight());
clearCanvas();
int cols = (int) (drawCanvas.getWidth() / tileWidth);
int rows = (int) (drawCanvas.getHeight() / tileHeight);
for (int x = 0; x <= cols; x++) {
@ -238,13 +262,27 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
anchorPane.getChildren().get(4).setLayoutY((drawCanvas.getHeight() - 30) / 2);
}
public void clearCanvas() {
boolean oddEvenColumn = false;
boolean oddEven;
for (int x=0; x < drawCanvas.getWidth(); x += 10) {
oddEven = oddEvenColumn;
for (int y=0; y < drawCanvas.getHeight(); y += 10) {
drawCanvas.getGraphicsContext2D().setFill(oddEven ? Color.BLACK : Color.NAVY);
drawCanvas.getGraphicsContext2D().fillRect(x, y, 10, 10);
oddEven = !oddEven;
}
oddEvenColumn = !oddEvenColumn;
}
}
private void doDraw(int x, int y, Tile tile) {
double xx = x * tileWidth;
double yy = y * tileHeight;
if (tile != null) {
drawCanvas.getGraphicsContext2D().drawImage(TileUtils.getImage(tile, currentPlatform), xx, yy, tileWidth, tileHeight);
} else {
drawCanvas.getGraphicsContext2D().clearRect(xx, yy, tileWidth, tileHeight);
// drawCanvas.getGraphicsContext2D().clearRect(xx, yy, tileWidth, tileHeight);
}
}
@ -342,6 +380,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
drawCanvas.heightProperty().unbind();
anchorPane.getChildren().remove(drawCanvas);
currentMap.updateBackingMap();
Application.getPrimaryStage().getScene().removeEventHandler(KeyEvent.KEY_PRESSED, this::keyPressed);
}
/**
@ -353,11 +392,16 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
/**
* @param currentTile the currentTile to set
* @return Same tile (necessary for callback support)
*/
public void setCurrentTile(Tile currentTile) {
public Tile setCurrentTile(Tile currentTile) {
if (drawMode == DrawMode.Eraser) {
drawMode = DrawMode.Pencil1px;
}
this.currentTile = currentTile;
ImageCursor cursor = new ImageCursor(TileUtils.getImage(currentTile, currentPlatform), 2, 2);
drawCanvas.setCursor(cursor);
return currentTile;
}
public void showPreview() {
@ -406,7 +450,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
public static enum DrawMode {
Pencil1px, Pencil3px, Pencil5px, FilledRect
Pencil1px, Pencil3px, Pencil5px, FilledRect, Eraser
};
public void plot(final int x, final int y, final Tile t) {
@ -488,7 +532,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
@Override
public void handle(MouseEvent t) {
if (getCurrentTile() == null) {
if (getCurrentTile() == null && drawMode != DrawMode.Eraser) {
System.out.println("No tile selected, ignoring");
return;
}
@ -504,6 +548,14 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
lastDrawMode = drawMode;
lastTile = getCurrentTile();
switch (drawMode) {
case Eraser: {
if (canSkip) {
return;
}
plot(x,y,null);
redraw();
break;
}
case Pencil1px:
if (canSkip) {
return;

View File

@ -56,6 +56,9 @@ public abstract class MapEditorTabController {
@FXML
protected Button scriptEraseTool;
@FXML
abstract public void mapEraser(ActionEvent event);
@FXML
abstract public void mapDraw1(ActionEvent event);

View File

@ -10,32 +10,53 @@ import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javafx.animation.FadeTransition;
import javafx.animation.ScaleTransition;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBoxBuilder;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.Duration;
import javax.xml.bind.JAXB;
import org.badvision.outlaweditor.Application;
import static org.badvision.outlaweditor.Application.currentPlatform;
import org.badvision.outlaweditor.FileUtils;
import org.badvision.outlaweditor.MythosEditor;
import org.badvision.outlaweditor.apple.ImageDitherEngine;
import org.badvision.outlaweditor.data.TileUtils;
import org.badvision.outlaweditor.data.TilesetUtils;
import org.badvision.outlaweditor.data.xml.GameData;
import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Tile;
import org.badvision.outlaweditor.ui.impl.ImageConversionWizardController;
/**
@ -141,7 +162,7 @@ public class UIAction {
public static void quit() {
confirm("Quit? Are you sure?", UIAction::quitWithoutConfirming, null);
}
public static void quitWithoutConfirming() {
Platform.runLater(Platform::exit);
}
@ -212,7 +233,7 @@ public class UIAction {
editor.show();
return script;
}
public static ImageConversionWizardController openImageConversionModal(Image image, ImageDitherEngine ditherEngine, int targetWidth, int targetHeight, ImageConversionPostAction postAction) {
FXMLLoader fxmlLoader = new FXMLLoader(UIAction.class.getResource("/imageConversionWizard.fxml"));
try {
@ -230,6 +251,106 @@ public class UIAction {
return controller;
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}
public static final int GRID_SPACING = 7;
public static final int MAX_TILES_PER_ROW = 16;
public static AnchorPane currentTileSelector;
public static void showTileSelectModal(Pane anchorPane, String category, Callback<Tile,?> callback) {
if (currentTileSelector != null) {
return;
}
currentTileSelector = new AnchorPane();
int TILE_WIDTH = Application.currentPlatform.tileRenderer.getWidth();
int TILE_HEIGHT = Application.currentPlatform.tileRenderer.getHeight();
List<Tile> tiles = Application.gameData.getTile().stream().filter((Tile t) -> {
return category == null || t.getCategory().equals(category);
}).collect(Collectors.toList());
int tilesPerRow = (int) Math.min(tiles.size(), Math.min(MAX_TILES_PER_ROW, anchorPane.getWidth() / (TILE_WIDTH + GRID_SPACING)));
int numRows = (tiles.size() + tilesPerRow - 1) / tilesPerRow;
int prefWidth = tilesPerRow * (TILE_WIDTH + GRID_SPACING) + GRID_SPACING;
currentTileSelector.setPrefWidth(prefWidth);
currentTileSelector.setPrefHeight(Math.min(numRows * (TILE_HEIGHT + GRID_SPACING) + GRID_SPACING, prefWidth));
for (int i = 0; i < tiles.size(); i++) {
final Tile tile = tiles.get(i);
ImageView tileIcon = new ImageView(TileUtils.getImage(tile, currentPlatform));
currentTileSelector.getChildren().add(tileIcon);
tileIcon.setOnMouseClicked((e) -> {
e.consume();
callback.call(tile);
closeCurrentTileSelector();
});
tileIcon.setOnMouseEntered((e) -> {
tileIcon.setEffect(new DropShadow(BlurType.GAUSSIAN, Color.CORNSILK, 5.0, 0.5, 0, 0));
ScaleTransition st = new ScaleTransition(Duration.millis(150), tileIcon);
st.setAutoReverse(false);
st.setToX(1.25);
st.setToY(1.25);
st.play();
});
tileIcon.setOnMouseExited((e) -> {
tileIcon.setEffect(null);
ScaleTransition st = new ScaleTransition(Duration.millis(150), tileIcon);
st.setAutoReverse(false);
st.setToX(1);
st.setToY(1);
st.play();
});
tileIcon.setLayoutX(GRID_SPACING + (i % tilesPerRow) * (TILE_WIDTH + GRID_SPACING));
tileIcon.setLayoutY(GRID_SPACING + (i / tilesPerRow) * (TILE_HEIGHT + GRID_SPACING));
}
currentTileSelector.setLayoutX((anchorPane.getWidth() - currentTileSelector.getPrefWidth()) / 2);
currentTileSelector.setLayoutY((anchorPane.getHeight() - currentTileSelector.getPrefHeight()) / 2);
currentTileSelector.setBackground(
new Background(
new BackgroundFill(
new Color(0.7, 0.7, 0.9, 0.75),
new CornerRadii(10.0),
null)));
currentTileSelector.setEffect(new DropShadow(5.0, 1.0, 1.0, Color.BLACK));
anchorPane.getChildren().add(currentTileSelector);
Application.getPrimaryStage().getScene().addEventHandler(KeyEvent.KEY_PRESSED, cancelTileSelectKeyHandler);
Application.getPrimaryStage().getScene().addEventFilter(MouseEvent.MOUSE_PRESSED, cancelTileSelectMouseHandler);
}
private static final EventHandler<MouseEvent> cancelTileSelectMouseHandler = (MouseEvent e) -> {
if (! (e.getSource() instanceof ImageView)) {
e.consume();
}
closeCurrentTileSelector();
};
private static final EventHandler<KeyEvent> cancelTileSelectKeyHandler = (KeyEvent e) -> {
if (e.getCode() == KeyCode.ESCAPE) {
closeCurrentTileSelector();
}
};
public static void closeCurrentTileSelector() {
Application.getPrimaryStage().getScene().removeEventHandler(KeyEvent.KEY_PRESSED, cancelTileSelectKeyHandler);
Application.getPrimaryStage().getScene().removeEventFilter(MouseEvent.MOUSE_PRESSED, cancelTileSelectMouseHandler);
fadeOut(currentTileSelector, (ActionEvent ev) -> {
if (currentTileSelector != null) {
Pane parent = (Pane) currentTileSelector.getParent();
parent.getChildren().remove(currentTileSelector);
currentTileSelector = null;
}
});
}
public static void fadeOut(Node node, EventHandler<ActionEvent> callback) {
FadeTransition ft = new FadeTransition(Duration.millis(250), node);
ft.setFromValue(1.0);
ft.setToValue(0.0);
ft.setCycleCount(1);
ft.setAutoReverse(false);
ft.setOnFinished(callback);
ft.play();
}
}

View File

@ -40,6 +40,13 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
final TransferHelper<Script> scriptDragDrop = new TransferHelper<>(Script.class);
final TransferHelper<ToolType> toolDragDrop = new TransferHelper<>(ToolType.class);
@Override
public void mapEraser(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().setDrawMode(MapEditor.DrawMode.Eraser);
}
}
@Override
public void mapDraw1(ActionEvent event) {
if (getCurrentEditor() != null) {
@ -284,7 +291,7 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
});
toolDragDrop.registerDragSupport(scriptEraseTool, ToolType.ERASER);
}
@Override
public void rebuildTileSelectors() {
mapSelectTile.getItems().clear();

View File

@ -26,6 +26,7 @@
<MenuItem mnemonicParsing="false" onAction="#mapDraw3" text="Radius 3" />
<MenuItem mnemonicParsing="false" onAction="#mapDraw5" text="Radius 5" />
<MenuItem mnemonicParsing="false" onAction="#mapDrawFilledRectMode" text="Filled Rectangle" />
<MenuItem mnemonicParsing="false" onAction="#mapEraser" text="Eraser" />
</items>
</Menu>
<MenuItem mnemonicParsing="false" onAction="#mapTogglePanZoom" text="Toggle pan/zoom controls" />