diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/data/DataUtilities.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/data/DataUtilities.java index 1a37feab..880fc2b4 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/data/DataUtilities.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/data/DataUtilities.java @@ -1,42 +1,42 @@ package org.badvision.outlaweditor.data; +import java.util.List; import org.badvision.outlaweditor.Application; import org.badvision.outlaweditor.data.xml.Global; -import org.badvision.outlaweditor.data.xml.Scripts; -import org.badvision.outlaweditor.data.xml.Variables; +import org.badvision.outlaweditor.data.xml.NamedEntity; public class DataUtilities { - public static void sortScripts(Scripts s) { - if (s == null || s.getScript() == null) { - return; - } - s.getScript().sort((a, b) -> { - if (a.getName().equalsIgnoreCase("init")) { - return -1; - } else if (b.getName().equalsIgnoreCase("init")) { - return 1; - } - return a.getName().compareTo(b.getName()); - }); - } - public static void ensureGlobalExists() { if (Application.gameData.getGlobal() == null) { Application.gameData.setGlobal(new Global()); } } - public static void sortVariables(Variables vars) { - if (vars == null || vars.getVariable()== null) { + public static void sortNamedEntities(List entities) { + if (entities == null) { return; } - vars.getVariable().sort((a, b) -> { - if (a.getName().equalsIgnoreCase("init")) { - return -1; - } else if (b.getName().equalsIgnoreCase("init")) { - return 1; - } - return a.getName().compareTo(b.getName()); + entities.sort((a,b)->{ + String nameA = a == null ? "" : nullSafe(a.getName()); + String nameB = b == null ? "" : nullSafe(b.getName()); + if (nameA.equalsIgnoreCase("init")) return -1; + if (nameB.equalsIgnoreCase("init")) return 1; + return nameA.compareTo(nameB); }); } + + public static String nullSafe(String str) { + if (str == null) return ""; + return str; + } + + public static String uppercaseFirst(String str) { + StringBuilder b = new StringBuilder(str); + int i = 0; + do { + b.replace(i, i + 1, b.substring(i, i + 1).toUpperCase()); + i = b.indexOf(" ", i) + 1; + } while (i > 0 && i < b.length()); + return b.toString(); + } } diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/GlobalEditorTabController.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/GlobalEditorTabController.java index c7709abc..a94a84f8 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/GlobalEditorTabController.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/GlobalEditorTabController.java @@ -32,7 +32,7 @@ public abstract class GlobalEditorTabController { @FXML abstract protected void onDataTypeDeletePressed(ActionEvent event); @FXML - abstract protected void onDeleteClonePressed(ActionEvent event); + abstract protected void onDataTypeClonePressed(ActionEvent event); @FXML abstract protected void onVariableAddPressed(ActionEvent event); @FXML diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/ModalEditor.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/ModalEditor.java index 5d58d5ff..141c07f6 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/ModalEditor.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/ModalEditor.java @@ -1,28 +1,39 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package org.badvision.outlaweditor.ui; +import com.sun.glass.ui.Application; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; import javafx.application.Platform; +import javafx.beans.property.adapter.JavaBeanStringPropertyBuilder; +import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.geometry.Insets; +import javafx.scene.Node; +import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.Control; import javafx.scene.control.Dialog; import javafx.scene.control.Label; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.util.Callback; +import static org.badvision.outlaweditor.data.DataUtilities.uppercaseFirst; /** * @@ -32,7 +43,7 @@ public class ModalEditor { public static interface EditControl { - public Control getControl(); + public Node getControl(); public V getValue(); @@ -59,6 +70,86 @@ public class ModalEditor { } } + static class TableControl implements EditControl> { + + Map, TableCell>> cols; + Class rowType; + ObservableList rows; + TableView table; + VBox control; + + public TableControl(Map, TableCell>> cols, Class rowType) { + this.cols = cols; + this.rowType = rowType; + rows = FXCollections.observableArrayList(); + + table = new TableView(rows); + cols.forEach((String colName, Callback, TableCell> factory) -> { + TableColumn col = new TableColumn<>(uppercaseFirst(colName)); + col.setCellValueFactory((TableColumn.CellDataFeatures param) -> { + try { + return (ObservableValue) new JavaBeanStringPropertyBuilder().bean(param.getValue()).name(colName).build(); + } catch (NoSuchMethodException ex) { + Logger.getLogger(ModalEditor.class.getName()).log(Level.SEVERE, null, ex); + throw new RuntimeException(ex); + } + }); + col.setCellFactory(factory); + col.setPrefWidth(150); + table.getColumns().add(col); + }); + table.setPlaceholder(new Label("Click + to add one or more attributes")); + table.setEditable(true); + table.setPrefWidth(cols.size() * 150 + 5); + + Button addButton = new Button("+"); + addButton.setOnAction((event) -> { + try { + rows.add(rowType.newInstance()); + Application.invokeLater(() -> { + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + Logger.getLogger(ModalEditor.class.getName()).log(Level.SEVERE, null, ex); + } + table.edit(rows.size() - 1, table.getColumns().get(0)); + }); + } catch (InstantiationException | IllegalAccessException ex) { + Logger.getLogger(ModalEditor.class.getName()).log(Level.SEVERE, null, ex); + } + }); + Button removeButton = new Button("-"); + removeButton.setOnAction((event) -> { + rows.removeAll(table.getSelectionModel().getSelectedItems()); + }); + addButton.setPrefWidth(25); + removeButton.setPrefWidth(25); + control = new VBox( + table, + new HBox( + 10, + addButton, + removeButton + ) + ); + } + + @Override + public Node getControl() { + return control; + } + + @Override + public List getValue() { + return rows; + } + + @Override + public void setValue(List value) { + rows.setAll(value); + } + } + public PropertyDescriptor getPropertyDescriptor(PropertyDescriptor[] descriptors, String propertyName) { for (PropertyDescriptor descriptor : descriptors) { if (descriptor.getName().equalsIgnoreCase(propertyName)) { @@ -81,7 +172,7 @@ public class ModalEditor { GridPane grid = new GridPane(); grid.setHgap(10); grid.setVgap(10); - grid.setPadding(new Insets(20, 150, 10, 10)); + grid.setPadding(new Insets(20, 50, 10, 10)); final AtomicInteger row = new AtomicInteger(0); obj.forEach((String property, EditControl control) -> { @@ -105,9 +196,18 @@ public class ModalEditor { obj.forEach((String property, EditControl control) -> { PropertyDescriptor descriptor = getPropertyDescriptor(info.getPropertyDescriptors(), property); try { - descriptor.getWriteMethod().invoke(sourceObject, control.getValue()); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { - Logger.getLogger(ModalEditor.class.getName()).log(Level.SEVERE, null, ex); + if (descriptor.getWriteMethod() != null) { + descriptor.getWriteMethod().invoke(sourceObject, control.getValue()); + } else { + Object val = descriptor.getReadMethod().invoke(sourceObject); + if (val instanceof List) { + List sourceList = (List) val; + sourceList.clear(); + sourceList.addAll((Collection) control.getValue()); + } + } + } catch (NullPointerException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + Logger.getLogger(ModalEditor.class.getName()).log(Level.SEVERE, "Error updating property " + property, ex); } }); return sourceObject; @@ -117,14 +217,4 @@ public class ModalEditor { return dialog.showAndWait(); } - - private String uppercaseFirst(String str) { - StringBuilder b = new StringBuilder(str); - int i = 0; - do { - b.replace(i, i + 1, b.substring(i, i + 1).toUpperCase()); - i = b.indexOf(" ", i) + 1; - } while (i > 0 && i < b.length()); - return b.toString(); - } } 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 c0715048..3c97f2cf 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/UIAction.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/UIAction.java @@ -29,6 +29,10 @@ import javafx.scene.control.Button; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuItem; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +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; @@ -50,6 +54,7 @@ import javafx.stage.Modality; import javafx.stage.Stage; import javafx.util.Callback; import javafx.util.Duration; +import javafx.util.converter.DefaultStringConverter; import javax.xml.bind.JAXB; import org.badvision.outlaweditor.Application; import static org.badvision.outlaweditor.Application.currentPlatform; @@ -64,6 +69,7 @@ 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.Tile; +import org.badvision.outlaweditor.data.xml.UserType; import org.badvision.outlaweditor.data.xml.Variable; import org.badvision.outlaweditor.data.xml.Variables; import org.badvision.outlaweditor.ui.impl.ImageConversionWizardController; @@ -203,7 +209,7 @@ public class UIAction { public static void confirm(String message, Runnable yes, Runnable no) { choose(message, new Choice("Yes", yes), new Choice("No", no)); } - + public static void alert(String message) { choose(message, new Choice("Ok", null)); } @@ -247,7 +253,7 @@ public class UIAction { editor.show(); return script; } - + public static void createAndEditVariable(Scope scope) throws IntrospectionException { Variable newVariable = new Variable(); newVariable.setName("changeme"); @@ -261,7 +267,7 @@ public class UIAction { scope.getVariables().getVariable().add(var.get()); } } - + public static void editVariable(Variable var, Global global) { try { editAndGetVariable(var); @@ -277,9 +283,55 @@ public class UIAction { controls.put("name", new ModalEditor.TextControl()); controls.put("type", new ModalEditor.TextControl()); controls.put("comment", new ModalEditor.TextControl()); - + return editor.editObject(v, controls, Variable.class, "Variable", "Edit and press OK, or Cancel to abort"); - } + } + + public static void createAndEditUserType() throws IntrospectionException { + UserType type = new UserType(); + if (editAndGetUserType(type).isPresent()) { + if (Application.gameData.getGlobal().getUserTypes() == null) { + Application.gameData.getGlobal().setUserTypes(new Global.UserTypes()); + } + Application.gameData.getGlobal().getUserTypes().getUserType().add(type); + } + } + + public static void editUserType(UserType type) { + try { + editAndGetUserType(type); + } catch (IntrospectionException ex) { + Logger.getLogger(UIAction.class.getName()).log(Level.SEVERE, null, ex); + } + } + + public static Optional editAndGetUserType(UserType type) throws IntrospectionException { + ModalEditor editor = new ModalEditor(); + Map controls = new LinkedHashMap<>(); + + Map, TableCell>> attributeControls = new LinkedHashMap<>(); + + attributeControls.put("name", TextFieldTableCell.forTableColumn(new DefaultStringConverter() { + @Override + public String toString(String value) { + return value == null ? "Change Me" : value; + } + })); + attributeControls.put("type", ComboBoxTableCell.forTableColumn(new DefaultStringConverter() { + @Override + public String toString(String value) { + return value == null ? "String" : value; + } + }, "String","Boolean","Number")); + attributeControls.put("comment", TextFieldTableCell.forTableColumn(new DefaultStringConverter())); + + controls.put("name", new ModalEditor.TextControl()); + controls.put("attribute", new ModalEditor.TableControl(attributeControls, Variable.class)); + controls.put("comment", new ModalEditor.TextControl()); + + return editor.editObject(type, controls, UserType.class, "User Type", "Edit and press OK, or Cancel to abort"); + } public static ImageConversionWizardController openImageConversionModal(Image image, ImageDitherEngine ditherEngine, int targetWidth, int targetHeight, ImageConversionPostAction postAction) { FXMLLoader fxmlLoader = new FXMLLoader(UIAction.class.getResource("/imageConversionWizard.fxml")); @@ -305,7 +357,7 @@ public class UIAction { public static final int MAX_TILES_PER_ROW = 16; public static AnchorPane currentTileSelector; - public static void showTileSelectModal(Pane anchorPane, String category, Callback callback) { + public static void showTileSelectModal(Pane anchorPane, String category, Callback callback) { if (currentTileSelector != null) { return; } @@ -359,19 +411,19 @@ public class UIAction { 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)); + 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)) { + if (!(e.getSource() instanceof ImageView)) { e.consume(); } closeCurrentTileSelector(); }; - + private static final EventHandler cancelTileSelectKeyHandler = (KeyEvent e) -> { if (e.getCode() == KeyCode.ESCAPE) { closeCurrentTileSelector(); diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/ApplicationUIControllerImpl.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/ApplicationUIControllerImpl.java index f8449090..5d833b6a 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/ApplicationUIControllerImpl.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/ApplicationUIControllerImpl.java @@ -55,6 +55,8 @@ public class ApplicationUIControllerImpl extends ApplicationUIController { rebuildImageSelectors(); rebuildMapSelectors(); rebuildTileSelectors(); + globalController.redrawGlobalDataTypes(); + globalController.redrawGlobalVariables(); redrawScripts(); } @@ -66,11 +68,8 @@ public class ApplicationUIControllerImpl extends ApplicationUIController { @Override public void redrawScripts() { - if (currentTab == TABS.map) { - mapController.redrawMapScripts(); - } else { - globalController.redrawGlobalScripts(); - } + mapController.redrawMapScripts(); + globalController.redrawGlobalScripts(); } @Override diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/GlobalEditorTabControllerImpl.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/GlobalEditorTabControllerImpl.java index 5c94b184..1dbef10c 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/GlobalEditorTabControllerImpl.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/GlobalEditorTabControllerImpl.java @@ -16,6 +16,7 @@ import org.badvision.outlaweditor.Application; import org.badvision.outlaweditor.TransferHelper; import org.badvision.outlaweditor.data.DataUtilities; import org.badvision.outlaweditor.data.xml.Script; +import org.badvision.outlaweditor.data.xml.UserType; import org.badvision.outlaweditor.data.xml.Variable; import org.badvision.outlaweditor.ui.GlobalEditorTabController; import org.badvision.outlaweditor.ui.UIAction; @@ -26,9 +27,75 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController { @Override public void initialize() { super.initialize(); + variableList.setOnEditStart((ListView.EditEvent event) -> { + UIAction.editVariable(event.getSource().getItems().get(event.getIndex()), Application.gameData.getGlobal()); + variableList.getSelectionModel().clearSelection(); + }); + variableList.setCellFactory(new Callback, ListCell>() { + @Override + public ListCell call(ListView param) { + final ListCell cell = new ListCell() { + @Override + protected void updateItem(Variable item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setText(""); + } else { + setText(item.getName()); + if (item.getComment() != null && !(item.getComment().isEmpty())) { + setTooltip(new Tooltip(item.getComment())); + } + setFont(Font.font(null, FontWeight.BOLD, 12.0)); + } + } + }; + return cell; + } + }); + globalScriptList.setOnEditStart((ListView.EditEvent