Added tile copy/export and a few other minor refactorings

This commit is contained in:
Brendan Robert 2016-07-06 00:54:20 -05:00
parent ba0b04ce0e
commit 63881d948f
8 changed files with 222 additions and 113 deletions

View File

@ -49,6 +49,7 @@ import org.badvision.outlaweditor.data.xml.Map;
import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Scripts;
import org.badvision.outlaweditor.data.xml.Tile;
import org.badvision.outlaweditor.ui.TileSelectModal;
import org.badvision.outlaweditor.ui.ToolType;
import org.badvision.outlaweditor.ui.UIAction;
@ -127,7 +128,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
category = currentTile.getCategory();
}
if (this.equals(ApplicationState.getInstance().getController().getVisibleEditor())) {
UIAction.showTileSelectModal(anchorPane, category, this::setCurrentTile);
TileSelectModal.showTileSelectModal(anchorPane, category, this::setCurrentTile);
}
}
}

View File

@ -7,12 +7,15 @@
* ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.badvision.outlaweditor.apple;
import java.util.Arrays;
import java.util.HashMap;
import javafx.scene.Group;
import javafx.scene.control.Menu;
import javafx.scene.image.WritableImage;
import javafx.scene.input.Clipboard;
import javafx.scene.input.DataFormat;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
@ -21,6 +24,7 @@ import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import org.badvision.outlaweditor.api.Platform;
import org.badvision.outlaweditor.TileEditor;
import org.badvision.outlaweditor.data.DataUtilities;
import org.badvision.outlaweditor.data.TileUtils;
import org.badvision.outlaweditor.data.xml.Tile;
@ -215,8 +219,8 @@ public class AppleTileEditor extends TileEditor {
} else {
grid[x][y].setStroke(
isHiBit
? (x % 2 == 1) ? Color.CHOCOLATE : Color.CORNFLOWERBLUE
: (x % 2 == 1) ? Color.GREEN : Color.VIOLET);
? (x % 2 == 1) ? Color.CHOCOLATE : Color.CORNFLOWERBLUE
: (x % 2 == 1) ? Color.GREEN : Color.VIOLET);
}
}
}
@ -224,7 +228,11 @@ public class AppleTileEditor extends TileEditor {
@Override
public void copy() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
java.util.Map<DataFormat, Object> clip = new HashMap<>();
clip.put(DataFormat.IMAGE, TileUtils.getImage(getEntity(), Platform.AppleII));
clip.put(DataFormat.PLAIN_TEXT, DataUtilities.hexDump(TileUtils.getPlatformData(getEntity(), Platform.AppleII)));
clip.put(DataFormat.HTML, buildHtmlExport());
Clipboard.getSystemClipboard().setContent(clip);
}
@Override
@ -248,4 +256,43 @@ public class AppleTileEditor extends TileEditor {
TileUtils.redrawTile(getEntity());
}
}
private String buildHtmlExport() {
StringBuilder export = new StringBuilder("<table>");
export.append("<tr><th>H</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th>")
.append("<th>H</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th>")
.append("<th>B1</th><th>B2</th></tr>");
byte[] data = TileUtils.getPlatformData(getEntity(), Platform.AppleII);
for (int row = 0; row < 16; row++) {
export.append("<tr>");
for (int col = 0; col < 2; col++) {
int b = data[row * 2 + col] & 0x0ff;
export.append("<td>")
.append(b>>7)
.append("</td>");
for (int bit = 0; bit < 7; bit++) {
export.append("<td style='background:#")
.append(getHexColor((Color) grid[bit + col * 7][row].getFill()))
.append("'>")
.append(b&1)
.append("</td>");
b >>=1;
}
}
export.append("<td>")
.append(DataUtilities.getHexValueFromByte(data[row*2]))
.append("</td><td>")
.append(DataUtilities.getHexValueFromByte(data[row*2+1]))
.append("</td>");
export.append("</tr>");
}
export.append("</table>");
return export.toString();
}
private String getHexColor(Color color) {
return DataUtilities.getHexValue((int) (color.getRed() * 255))
+ DataUtilities.getHexValue((int) (color.getGreen() * 255))
+ DataUtilities.getHexValue((int) (color.getBlue() * 255));
}
}

View File

@ -216,6 +216,30 @@ public class DataUtilities {
return "???";
}
}
public static String hexDump(byte[] data) {
StringBuilder dump = new StringBuilder();
for (int i=0; i < data.length; i++) {
if (i > 0) {
dump.append(",");
}
dump.append(getHexValueFromByte(data[i]));
}
return dump.toString();
}
public static String getHexValueFromByte(byte val) {
return getHexValue(val & 0x0ff);
}
public static String getHexValue(int val) {
if (val < 16) {
return "0" + Integer.toHexString(val);
} else {
return Integer.toHexString(val);
}
}
//------------------------------ String comparators
/**
* Rank two strings similarity in terms of distance The lower the number,

View File

@ -0,0 +1,139 @@
/*
* Copyright 2016 org.badvision.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.badvision.outlaweditor.ui;
import java.util.List;
import java.util.stream.Collectors;
import javafx.animation.ScaleTransition;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
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.Pane;
import javafx.scene.paint.Color;
import javafx.util.Callback;
import javafx.util.Duration;
import org.badvision.outlaweditor.api.ApplicationState;
import org.badvision.outlaweditor.data.TileUtils;
import org.badvision.outlaweditor.data.xml.Tile;
import static org.badvision.outlaweditor.ui.UIAction.fadeOut;
/**
* Create and manage a tile selection modal
* @author blurry
*/
public class TileSelectModal {
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 = ApplicationState.getInstance().getCurrentPlatform().tileRenderer.getWidth();
int TILE_HEIGHT = ApplicationState.getInstance().getCurrentPlatform().tileRenderer.getHeight();
List<Tile> tiles = ApplicationState.getInstance().getGameData().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, ApplicationState.getInstance().getCurrentPlatform()));
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);
ApplicationState.getInstance().getPrimaryStage().getScene().addEventHandler(KeyEvent.KEY_PRESSED, cancelTileSelectKeyHandler);
ApplicationState.getInstance().getPrimaryStage().getScene().addEventFilter(MouseEvent.MOUSE_PRESSED, cancelTileSelectMouseHandler);
}
public static void closeCurrentTileSelector() {
ApplicationState.getInstance().getPrimaryStage().getScene().removeEventHandler(KeyEvent.KEY_PRESSED, cancelTileSelectKeyHandler);
ApplicationState.getInstance().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;
}
});
}
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();
}
};
private TileSelectModal() {
}
}

View File

@ -19,9 +19,7 @@ import java.util.Map;
import java.util.Optional;
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;
@ -39,22 +37,12 @@ import javafx.scene.control.TableColumn;
import javafx.scene.control.TextInputDialog;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.control.cell.TextFieldTableCell;
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;
@ -69,14 +57,12 @@ import org.badvision.outlaweditor.SheetEditor;
import org.badvision.outlaweditor.api.ApplicationState;
import org.badvision.outlaweditor.apple.ImageDitherEngine;
import org.badvision.outlaweditor.data.DataUtilities;
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.Global;
import org.badvision.outlaweditor.data.xml.Scope;
import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Sheet;
import org.badvision.outlaweditor.data.xml.Tile;
import org.badvision.outlaweditor.data.xml.UserType;
import org.badvision.outlaweditor.data.xml.Variable;
import org.badvision.outlaweditor.data.xml.Variables;
@ -396,96 +382,6 @@ public class UIAction {
}
}
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 = ApplicationState.getInstance().getCurrentPlatform().tileRenderer.getWidth();
int TILE_HEIGHT = ApplicationState.getInstance().getCurrentPlatform().tileRenderer.getHeight();
List<Tile> tiles = ApplicationState.getInstance().getGameData().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, ApplicationState.getInstance().getCurrentPlatform()));
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);
ApplicationState.getInstance().getPrimaryStage().getScene().addEventHandler(KeyEvent.KEY_PRESSED, cancelTileSelectKeyHandler);
ApplicationState.getInstance().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() {
ApplicationState.getInstance().getPrimaryStage().getScene().removeEventHandler(KeyEvent.KEY_PRESSED, cancelTileSelectKeyHandler);
ApplicationState.getInstance().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);

View File

@ -13,6 +13,7 @@ import java.beans.IntrospectionException;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.ListCell;
import javafx.scene.control.Tooltip;
@ -115,6 +116,7 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController {
@Override
public void startEdit() {
Platform.runLater(sheetList.getSelectionModel()::clearSelection);
UIAction.editSheet(getItem());
cancelEdit();
updateItem(getItem(), false);

View File

@ -32,7 +32,6 @@ import javafx.scene.control.TextField;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.FileChooser;
import javafx.util.converter.DefaultStringConverter;
import javax.xml.namespace.QName;
import org.badvision.outlaweditor.SheetEditor;
import org.badvision.outlaweditor.data.DataUtilities;
import static org.badvision.outlaweditor.data.DataUtilities.getValue;
@ -49,7 +48,7 @@ public class SheetEditorControllerImpl extends SheetEditorController {
private SheetEditor editor;
private ObservableList<Row> tableData;
private ListChangeListener columnChangeListener = c -> syncData();
private final ListChangeListener columnChangeListener = c -> syncData();
/**
* Initializes the controller class.

View File

@ -20,7 +20,6 @@ import javafx.event.ActionEvent;
import javafx.scene.control.ListView;
import javafx.scene.image.ImageView;
import javafx.util.StringConverter;
import org.badvision.outlaweditor.Application;
import org.badvision.outlaweditor.TileEditor;
import org.badvision.outlaweditor.api.ApplicationState;
import static org.badvision.outlaweditor.data.PropertyHelper.bind;
@ -33,6 +32,7 @@ import org.badvision.outlaweditor.data.xml.Tile;
import org.badvision.outlaweditor.ui.ApplicationUIController;
import org.badvision.outlaweditor.ui.EntitySelectorCell;
import org.badvision.outlaweditor.ui.TileEditorTabController;
import org.badvision.outlaweditor.ui.UIAction;
import static org.badvision.outlaweditor.ui.UIAction.confirm;
/**
@ -131,7 +131,8 @@ public class TileEditorTabControllerImpl extends TileEditorTabController {
@Override
public void onTileExportPressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
getCurrentTileEditor().copy();
UIAction.alert("Tile copied to the clipboard; use Paste Special in your target application to import this tile as an image, data, or a styled table (HTML)");
}
/**