From bb913b0242706c96604cdeb239fc3cbb55c473c1 Mon Sep 17 00:00:00 2001 From: Brendan Robert Date: Sat, 16 May 2015 12:29:11 -0500 Subject: [PATCH 1/2] "Control Space" feature for quick tile selection --- .../badvision/outlaweditor/ui/UIAction.java | 127 +++++++++++++++++- 1 file changed, 124 insertions(+), 3 deletions(-) diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/UIAction.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/UIAction.java index 3836b6be..0defe2cb 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/UIAction.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/UIAction.java @@ -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 callback) { + if (currentTileSelector != null) { + return; + } + currentTileSelector = new AnchorPane(); + + int TILE_WIDTH = Application.currentPlatform.tileRenderer.getWidth(); + int TILE_HEIGHT = Application.currentPlatform.tileRenderer.getHeight(); + + List 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 cancelTileSelectMouseHandler = (MouseEvent e) -> { + if (! (e.getSource() instanceof ImageView)) { + e.consume(); + } + closeCurrentTileSelector(); + }; + + private static final EventHandler 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 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(); } } From b12d9cec7d72ebc3812ab53be42cd41701a0ebb1 Mon Sep 17 00:00:00 2001 From: Brendan Robert Date: Sat, 16 May 2015 12:31:22 -0500 Subject: [PATCH 2/2] Control Space hooked up as well as new eraser tool --- .../org/badvision/outlaweditor/MapEditor.java | 62 +++++++++++++++++-- .../ui/MapEditorTabController.java | 3 + .../ui/impl/MapEditorTabControllerImpl.java | 9 ++- .../src/main/resources/mapEditorTab.fxml | 1 + 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/MapEditor.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/MapEditor.java index 225e3388..e81d66f8 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/MapEditor.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/MapEditor.java @@ -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 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 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 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 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 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 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 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 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 implements EventH lastDrawMode = drawMode; lastTile = getCurrentTile(); switch (drawMode) { + case Eraser: { + if (canSkip) { + return; + } + plot(x,y,null); + redraw(); + break; + } case Pencil1px: if (canSkip) { return; diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/MapEditorTabController.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/MapEditorTabController.java index f0115818..d648f107 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/MapEditorTabController.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/MapEditorTabController.java @@ -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); diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/MapEditorTabControllerImpl.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/MapEditorTabControllerImpl.java index dcbc1cc3..212b89fd 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/MapEditorTabControllerImpl.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/MapEditorTabControllerImpl.java @@ -40,6 +40,13 @@ public class MapEditorTabControllerImpl extends MapEditorTabController { final TransferHelper