This commit is contained in:
Martin Haye 2015-07-06 17:09:30 -07:00
commit e3b9387719
11 changed files with 405 additions and 196 deletions

View File

@ -1,42 +1,42 @@
package org.badvision.outlaweditor.data; package org.badvision.outlaweditor.data;
import java.util.List;
import org.badvision.outlaweditor.Application; import org.badvision.outlaweditor.Application;
import org.badvision.outlaweditor.data.xml.Global; import org.badvision.outlaweditor.data.xml.Global;
import org.badvision.outlaweditor.data.xml.Scripts; import org.badvision.outlaweditor.data.xml.NamedEntity;
import org.badvision.outlaweditor.data.xml.Variables;
public class DataUtilities { 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() { public static void ensureGlobalExists() {
if (Application.gameData.getGlobal() == null) { if (Application.gameData.getGlobal() == null) {
Application.gameData.setGlobal(new Global()); Application.gameData.setGlobal(new Global());
} }
} }
public static void sortVariables(Variables vars) { public static void sortNamedEntities(List<? extends NamedEntity> entities) {
if (vars == null || vars.getVariable()== null) { if (entities == null) {
return; return;
} }
vars.getVariable().sort((a, b) -> { entities.sort((a,b)->{
if (a.getName().equalsIgnoreCase("init")) { String nameA = a == null ? "" : nullSafe(a.getName());
return -1; String nameB = b == null ? "" : nullSafe(b.getName());
} else if (b.getName().equalsIgnoreCase("init")) { if (nameA.equalsIgnoreCase("init")) return -1;
return 1; if (nameB.equalsIgnoreCase("init")) return 1;
} return nameA.compareTo(nameB);
return a.getName().compareTo(b.getName());
}); });
} }
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();
}
} }

View File

@ -32,7 +32,7 @@ public abstract class GlobalEditorTabController {
@FXML @FXML
abstract protected void onDataTypeDeletePressed(ActionEvent event); abstract protected void onDataTypeDeletePressed(ActionEvent event);
@FXML @FXML
abstract protected void onDeleteClonePressed(ActionEvent event); abstract protected void onDataTypeClonePressed(ActionEvent event);
@FXML @FXML
abstract protected void onVariableAddPressed(ActionEvent event); abstract protected void onVariableAddPressed(ActionEvent event);
@FXML @FXML

View File

@ -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; package org.badvision.outlaweditor.ui;
import com.sun.glass.ui.Application;
import java.beans.BeanInfo; import java.beans.BeanInfo;
import java.beans.IntrospectionException; import java.beans.IntrospectionException;
import java.beans.Introspector; import java.beans.Introspector;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javafx.application.Platform; 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.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
import javafx.scene.control.Control; import javafx.scene.control.Control;
import javafx.scene.control.Dialog; import javafx.scene.control.Dialog;
import javafx.scene.control.Label; 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.control.TextField;
import javafx.scene.layout.GridPane; 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<V> { public static interface EditControl<V> {
public Control getControl(); public Node getControl();
public V getValue(); public V getValue();
@ -59,6 +70,86 @@ public class ModalEditor {
} }
} }
static class TableControl<T, S> implements EditControl<List<T>> {
Map<String, Callback<TableColumn<T, S>, TableCell<T, S>>> cols;
Class<T> rowType;
ObservableList<T> rows;
TableView<T> table;
VBox control;
public TableControl(Map<String, Callback<TableColumn<T, S>, TableCell<T, S>>> cols, Class<T> rowType) {
this.cols = cols;
this.rowType = rowType;
rows = FXCollections.observableArrayList();
table = new TableView(rows);
cols.forEach((String colName, Callback<TableColumn<T, S>, TableCell<T, S>> factory) -> {
TableColumn<T, S> col = new TableColumn<>(uppercaseFirst(colName));
col.setCellValueFactory((TableColumn.CellDataFeatures<T, S> param) -> {
try {
return (ObservableValue<S>) 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<T> getValue() {
return rows;
}
@Override
public void setValue(List<T> value) {
rows.setAll(value);
}
}
public PropertyDescriptor getPropertyDescriptor(PropertyDescriptor[] descriptors, String propertyName) { public PropertyDescriptor getPropertyDescriptor(PropertyDescriptor[] descriptors, String propertyName) {
for (PropertyDescriptor descriptor : descriptors) { for (PropertyDescriptor descriptor : descriptors) {
if (descriptor.getName().equalsIgnoreCase(propertyName)) { if (descriptor.getName().equalsIgnoreCase(propertyName)) {
@ -81,7 +172,7 @@ public class ModalEditor {
GridPane grid = new GridPane(); GridPane grid = new GridPane();
grid.setHgap(10); grid.setHgap(10);
grid.setVgap(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); final AtomicInteger row = new AtomicInteger(0);
obj.forEach((String property, EditControl control) -> { obj.forEach((String property, EditControl control) -> {
@ -105,9 +196,18 @@ public class ModalEditor {
obj.forEach((String property, EditControl control) -> { obj.forEach((String property, EditControl control) -> {
PropertyDescriptor descriptor = getPropertyDescriptor(info.getPropertyDescriptors(), property); PropertyDescriptor descriptor = getPropertyDescriptor(info.getPropertyDescriptors(), property);
try { try {
descriptor.getWriteMethod().invoke(sourceObject, control.getValue()); if (descriptor.getWriteMethod() != null) {
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { descriptor.getWriteMethod().invoke(sourceObject, control.getValue());
Logger.getLogger(ModalEditor.class.getName()).log(Level.SEVERE, null, ex); } 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; return sourceObject;
@ -117,14 +217,4 @@ public class ModalEditor {
return dialog.showAndWait(); 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();
}
} }

View File

@ -29,6 +29,10 @@ import javafx.scene.control.Button;
import javafx.scene.control.Menu; import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar; import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem; 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.BlurType;
import javafx.scene.effect.DropShadow; import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image; import javafx.scene.image.Image;
@ -50,6 +54,7 @@ import javafx.stage.Modality;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.util.Callback; import javafx.util.Callback;
import javafx.util.Duration; import javafx.util.Duration;
import javafx.util.converter.DefaultStringConverter;
import javax.xml.bind.JAXB; import javax.xml.bind.JAXB;
import org.badvision.outlaweditor.Application; import org.badvision.outlaweditor.Application;
import static org.badvision.outlaweditor.Application.currentPlatform; 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.Scope;
import org.badvision.outlaweditor.data.xml.Script; import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Tile; 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.Variable;
import org.badvision.outlaweditor.data.xml.Variables; import org.badvision.outlaweditor.data.xml.Variables;
import org.badvision.outlaweditor.ui.impl.ImageConversionWizardController; import org.badvision.outlaweditor.ui.impl.ImageConversionWizardController;
@ -203,7 +209,7 @@ public class UIAction {
public static void confirm(String message, Runnable yes, Runnable no) { public static void confirm(String message, Runnable yes, Runnable no) {
choose(message, new Choice("Yes", yes), new Choice("No", no)); choose(message, new Choice("Yes", yes), new Choice("No", no));
} }
public static void alert(String message) { public static void alert(String message) {
choose(message, new Choice("Ok", null)); choose(message, new Choice("Ok", null));
} }
@ -247,7 +253,7 @@ public class UIAction {
editor.show(); editor.show();
return script; return script;
} }
public static void createAndEditVariable(Scope scope) throws IntrospectionException { public static void createAndEditVariable(Scope scope) throws IntrospectionException {
Variable newVariable = new Variable(); Variable newVariable = new Variable();
newVariable.setName("changeme"); newVariable.setName("changeme");
@ -261,7 +267,7 @@ public class UIAction {
scope.getVariables().getVariable().add(var.get()); scope.getVariables().getVariable().add(var.get());
} }
} }
public static void editVariable(Variable var, Global global) { public static void editVariable(Variable var, Global global) {
try { try {
editAndGetVariable(var); editAndGetVariable(var);
@ -277,9 +283,55 @@ public class UIAction {
controls.put("name", new ModalEditor.TextControl()); controls.put("name", new ModalEditor.TextControl());
controls.put("type", new ModalEditor.TextControl()); controls.put("type", new ModalEditor.TextControl());
controls.put("comment", 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"); 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<UserType> editAndGetUserType(UserType type) throws IntrospectionException {
ModalEditor editor = new ModalEditor();
Map<String, ModalEditor.EditControl> controls = new LinkedHashMap<>();
Map<String, Callback<TableColumn<
Variable, String>, TableCell<Variable, String>>> attributeControls = new LinkedHashMap<>();
attributeControls.put("name", TextFieldTableCell.<Variable, String>forTableColumn(new DefaultStringConverter() {
@Override
public String toString(String value) {
return value == null ? "Change Me" : value;
}
}));
attributeControls.put("type", ComboBoxTableCell.<Variable, String>forTableColumn(new DefaultStringConverter() {
@Override
public String toString(String value) {
return value == null ? "String" : value;
}
}, "String","Boolean","Number"));
attributeControls.put("comment", TextFieldTableCell.<Variable, String>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) { public static ImageConversionWizardController openImageConversionModal(Image image, ImageDitherEngine ditherEngine, int targetWidth, int targetHeight, ImageConversionPostAction postAction) {
FXMLLoader fxmlLoader = new FXMLLoader(UIAction.class.getResource("/imageConversionWizard.fxml")); 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 final int MAX_TILES_PER_ROW = 16;
public static AnchorPane currentTileSelector; public static AnchorPane currentTileSelector;
public static void showTileSelectModal(Pane anchorPane, String category, Callback<Tile,?> callback) { public static void showTileSelectModal(Pane anchorPane, String category, Callback<Tile, ?> callback) {
if (currentTileSelector != null) { if (currentTileSelector != null) {
return; return;
} }
@ -359,19 +411,19 @@ public class UIAction {
new Color(0.7, 0.7, 0.9, 0.75), new Color(0.7, 0.7, 0.9, 0.75),
new CornerRadii(10.0), new CornerRadii(10.0),
null))); 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); anchorPane.getChildren().add(currentTileSelector);
Application.getPrimaryStage().getScene().addEventHandler(KeyEvent.KEY_PRESSED, cancelTileSelectKeyHandler); Application.getPrimaryStage().getScene().addEventHandler(KeyEvent.KEY_PRESSED, cancelTileSelectKeyHandler);
Application.getPrimaryStage().getScene().addEventFilter(MouseEvent.MOUSE_PRESSED, cancelTileSelectMouseHandler); Application.getPrimaryStage().getScene().addEventFilter(MouseEvent.MOUSE_PRESSED, cancelTileSelectMouseHandler);
} }
private static final EventHandler<MouseEvent> cancelTileSelectMouseHandler = (MouseEvent e) -> { private static final EventHandler<MouseEvent> cancelTileSelectMouseHandler = (MouseEvent e) -> {
if (! (e.getSource() instanceof ImageView)) { if (!(e.getSource() instanceof ImageView)) {
e.consume(); e.consume();
} }
closeCurrentTileSelector(); closeCurrentTileSelector();
}; };
private static final EventHandler<KeyEvent> cancelTileSelectKeyHandler = (KeyEvent e) -> { private static final EventHandler<KeyEvent> cancelTileSelectKeyHandler = (KeyEvent e) -> {
if (e.getCode() == KeyCode.ESCAPE) { if (e.getCode() == KeyCode.ESCAPE) {
closeCurrentTileSelector(); closeCurrentTileSelector();

View File

@ -55,6 +55,8 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
rebuildImageSelectors(); rebuildImageSelectors();
rebuildMapSelectors(); rebuildMapSelectors();
rebuildTileSelectors(); rebuildTileSelectors();
globalController.redrawGlobalDataTypes();
globalController.redrawGlobalVariables();
redrawScripts(); redrawScripts();
} }
@ -66,11 +68,8 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
@Override @Override
public void redrawScripts() { public void redrawScripts() {
if (currentTab == TABS.map) { mapController.redrawMapScripts();
mapController.redrawMapScripts(); globalController.redrawGlobalScripts();
} else {
globalController.redrawGlobalScripts();
}
} }
@Override @Override

View File

@ -16,6 +16,7 @@ import org.badvision.outlaweditor.Application;
import org.badvision.outlaweditor.TransferHelper; import org.badvision.outlaweditor.TransferHelper;
import org.badvision.outlaweditor.data.DataUtilities; import org.badvision.outlaweditor.data.DataUtilities;
import org.badvision.outlaweditor.data.xml.Script; 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.data.xml.Variable;
import org.badvision.outlaweditor.ui.GlobalEditorTabController; import org.badvision.outlaweditor.ui.GlobalEditorTabController;
import org.badvision.outlaweditor.ui.UIAction; import org.badvision.outlaweditor.ui.UIAction;
@ -26,9 +27,75 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController {
@Override @Override
public void initialize() { public void initialize() {
super.initialize(); super.initialize();
variableList.setOnEditStart((ListView.EditEvent<Variable> event) -> {
UIAction.editVariable(event.getSource().getItems().get(event.getIndex()), Application.gameData.getGlobal());
variableList.getSelectionModel().clearSelection();
});
variableList.setCellFactory(new Callback<ListView<Variable>, ListCell<Variable>>() {
@Override
public ListCell<Variable> call(ListView<Variable> param) {
final ListCell<Variable> cell = new ListCell<Variable>() {
@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<Script> event) -> {
UIAction.editScript(event.getSource().getItems().get(event.getIndex()), Application.gameData.getGlobal());
globalScriptList.getSelectionModel().clearSelection();
});
globalScriptList.setCellFactory(new Callback<ListView<Script>, ListCell<Script>>() {
@Override
public ListCell<Script> call(ListView<Script> param) {
final ListCell<Script> cell = new ListCell<Script>() {
@Override
protected void updateItem(Script item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
} else {
setText(item.getName());
setFont(Font.font(null, FontWeight.BOLD, 12.0));
}
}
};
return cell;
}
});
dataTypeList.setOnEditStart((ListView.EditEvent<UserType> event) -> {
UIAction.editUserType(event.getSource().getItems().get(event.getIndex()));
dataTypeList.getSelectionModel().clearSelection();
});
dataTypeList.setCellFactory((listView) -> new ListCell<UserType>() {
@Override
protected void updateItem(UserType 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));
}
}
});
} }
@Override @Override
protected void onScriptAddPressed(ActionEvent event) { protected void onScriptAddPressed(ActionEvent event) {
UIAction.createAndEditScript(Application.gameData.getGlobal()); UIAction.createAndEditScript(Application.gameData.getGlobal());
@ -70,14 +137,31 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController {
@Override @Override
protected void onDataTypeAddPressed(ActionEvent event) { protected void onDataTypeAddPressed(ActionEvent event) {
try {
UIAction.createAndEditUserType();
redrawGlobalDataTypes();
} catch (IntrospectionException ex) {
Logger.getLogger(GlobalEditorTabControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
} }
@Override @Override
protected void onDataTypeDeletePressed(ActionEvent event) { protected void onDataTypeDeletePressed(ActionEvent event) {
UserType type = dataTypeList.getSelectionModel().getSelectedItem();
if (type != null) {
UIAction.confirm(
"Are you sure you want to delete the user-defined type "
+ type.getName()
+ "? There is no undo for this!",
() -> {
Application.gameData.getGlobal().getUserTypes().getUserType().remove(type);
redrawGlobalDataTypes();
}, null);
}
} }
@Override @Override
protected void onDeleteClonePressed(ActionEvent event) { protected void onDataTypeClonePressed(ActionEvent event) {
} }
@Override @Override
@ -132,30 +216,8 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController {
@Override @Override
public void redrawGlobalScripts() { public void redrawGlobalScripts() {
DataUtilities.ensureGlobalExists(); DataUtilities.ensureGlobalExists();
globalScriptList.setOnEditStart((ListView.EditEvent<Script> event) -> {
UIAction.editScript(event.getSource().getItems().get(event.getIndex()), Application.gameData.getGlobal());
});
globalScriptList.setCellFactory(new Callback<ListView<Script>, ListCell<Script>>() {
@Override
public ListCell<Script> call(ListView<Script> param) {
final ListCell<Script> cell = new ListCell<Script>() {
@Override
protected void updateItem(Script item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
} else {
setText(item.getName());
setFont(Font.font(null, FontWeight.BOLD, 12.0));
}
}
};
return cell;
}
});
if (globalScriptList.getItems() != null && Application.gameData.getGlobal().getScripts() != null) { if (globalScriptList.getItems() != null && Application.gameData.getGlobal().getScripts() != null) {
DataUtilities.sortScripts(Application.gameData.getGlobal().getScripts()); DataUtilities.sortNamedEntities(Application.gameData.getGlobal().getScripts().getScript());
globalScriptList.getItems().setAll(Application.gameData.getGlobal().getScripts().getScript()); globalScriptList.getItems().setAll(Application.gameData.getGlobal().getScripts().getScript());
} else { } else {
globalScriptList.getItems().clear(); globalScriptList.getItems().clear();
@ -165,41 +227,22 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController {
@Override @Override
public void redrawGlobalVariables() { public void redrawGlobalVariables() {
DataUtilities.ensureGlobalExists(); DataUtilities.ensureGlobalExists();
variableList.setOnEditStart((ListView.EditEvent<Variable> event) -> { if (variableList.getItems() != null && Application.gameData.getGlobal().getVariables() != null) {
UIAction.editVariable(event.getSource().getItems().get(event.getIndex()), Application.gameData.getGlobal()); DataUtilities.sortNamedEntities(Application.gameData.getGlobal().getVariables().getVariable());
});
variableList.setCellFactory(new Callback<ListView<Variable>, ListCell<Variable>>() {
@Override
public ListCell<Variable> call(ListView<Variable> param) {
final ListCell<Variable> cell = new ListCell<Variable>() {
@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;
}
});
if (variableList.getItems() != null && Application.gameData.getGlobal().getVariables()!= null) {
DataUtilities.sortVariables(Application.gameData.getGlobal().getVariables());
variableList.getItems().setAll(Application.gameData.getGlobal().getVariables().getVariable()); variableList.getItems().setAll(Application.gameData.getGlobal().getVariables().getVariable());
} else { } else {
variableList.getItems().clear(); variableList.getItems().clear();
} }
} }
@Override @Override
public void redrawGlobalDataTypes() { public void redrawGlobalDataTypes() {
DataUtilities.ensureGlobalExists(); DataUtilities.ensureGlobalExists();
if (dataTypeList.getItems() != null && Application.gameData.getGlobal().getUserTypes() != null) {
DataUtilities.sortNamedEntities(Application.gameData.getGlobal().getUserTypes().getUserType());
dataTypeList.getItems().setAll(Application.gameData.getGlobal().getUserTypes().getUserType());
} else {
dataTypeList.getItems().clear();
}
} }
} }

View File

@ -279,7 +279,7 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
mapWrapAround.setDisable(true); mapWrapAround.setDisable(true);
setCurrentEditor(null); setCurrentEditor(null);
} else { } else {
DataUtilities.sortScripts(m.getScripts()); DataUtilities.sortNamedEntities(m.getScripts().getScript());
if (m.getHeight() == null) { if (m.getHeight() == null) {
m.setHeight(512); m.setHeight(512);
} }
@ -426,7 +426,7 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
mapScriptsList.getItems().clear(); mapScriptsList.getItems().clear();
} else { } else {
if (mapScriptsList.getItems() != null && getCurrentMap().getScripts() != null) { if (mapScriptsList.getItems() != null && getCurrentMap().getScripts() != null) {
DataUtilities.sortScripts(getCurrentMap().getScripts()); DataUtilities.sortNamedEntities(getCurrentMap().getScripts().getScript());
mapScriptsList.getItems().setAll(getCurrentMap().getScripts().getScript()); mapScriptsList.getItems().setAll(getCurrentMap().getScripts().getScript());
} else { } else {
mapScriptsList.getItems().clear(); mapScriptsList.getItems().clear();

View File

@ -40,7 +40,7 @@
<items> <items>
<Button mnemonicParsing="false" onAction="#onDataTypeAddPressed" text="+" /> <Button mnemonicParsing="false" onAction="#onDataTypeAddPressed" text="+" />
<Button mnemonicParsing="false" onAction="#onDataTypeDeletePressed" text="-" /> <Button mnemonicParsing="false" onAction="#onDataTypeDeletePressed" text="-" />
<Button mnemonicParsing="false" onAction="#onDeleteClonePressed" text="Clone" /> <Button mnemonicParsing="false" onAction="#onDataTypeClonePressed" text="Clone" />
</items> </items>
</ToolBar> </ToolBar>
<ScrollPane fitToHeight="true" fitToWidth="true" prefHeight="419.0" prefWidth="201.0"> <ScrollPane fitToHeight="true" fitToWidth="true" prefHeight="419.0" prefWidth="201.0">

View File

@ -2,12 +2,19 @@
<xs:schema version="1.0" <xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" targetNamespace="outlaw" xmlns:tns="outlaw" attributeFormDefault="unqualified"> elementFormDefault="qualified" targetNamespace="outlaw" xmlns:tns="outlaw" attributeFormDefault="unqualified">
<xs:complexType name="namedEntity">
<xs:attribute name="name" use="required" type="xs:NCName"/>
<xs:attribute name="comment" type="xs:string"/>
</xs:complexType>
<xs:complexType name="image"> <xs:complexType name="image">
<xs:sequence> <xs:complexContent>
<xs:element name="displayData" type="tns:platformData" minOccurs="0" maxOccurs="unbounded"/> <xs:extension base="tns:namedEntity">
</xs:sequence> <xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN"/> <xs:element name="displayData" type="tns:platformData" minOccurs="0" maxOccurs="unbounded"/>
<xs:attribute name="category" type="xs:string"/> </xs:sequence>
<xs:attribute name="category" type="xs:string"/>
</xs:extension>
</xs:complexContent>
</xs:complexType> </xs:complexType>
<xs:complexType name="tile"> <xs:complexType name="tile">
<xs:complexContent> <xs:complexContent>
@ -29,26 +36,29 @@
</xs:simpleContent> </xs:simpleContent>
</xs:complexType> </xs:complexType>
<xs:complexType name="script"> <xs:complexType name="script">
<xs:sequence> <xs:complexContent>
<xs:element name="name" type="xs:string"/> <xs:extension base="tns:namedEntity">
<xs:element name="description" type="xs:string" minOccurs="0"/> <xs:sequence>
<xs:element name="category" type="xs:string" minOccurs="0"/> <xs:element name="description" type="xs:string" minOccurs="0"/>
<xs:element name="block" type="tns:block"/> <xs:element name="category" type="xs:string" minOccurs="0"/>
<xs:element name="locationTrigger" minOccurs="0" maxOccurs="unbounded"> <xs:element name="block" type="tns:block"/>
<xs:complexType> <xs:element name="locationTrigger" minOccurs="0" maxOccurs="unbounded">
<xs:attribute name="x" type="xs:int"/> <xs:complexType>
<xs:attribute name="y" type="xs:int"/> <xs:attribute name="x" type="xs:int"/>
</xs:complexType> <xs:attribute name="y" type="xs:int"/>
</xs:element> </xs:complexType>
<xs:element name="intervalTrigger" minOccurs="0" maxOccurs="unbounded"> </xs:element>
<xs:complexType> <xs:element name="intervalTrigger" minOccurs="0" maxOccurs="unbounded">
<xs:attribute name="start" type="xs:int" use="optional"/> <xs:complexType>
<xs:attribute name="end" type="xs:int" use="optional"/> <xs:attribute name="start" type="xs:int" use="optional"/>
<xs:attribute name="period" type="xs:int" use="optional"/> <xs:attribute name="end" type="xs:int" use="optional"/>
<xs:attribute name="ifTrue" type="xs:string" use="optional"/> <xs:attribute name="period" type="xs:int" use="optional"/>
</xs:complexType> <xs:attribute name="ifTrue" type="xs:string" use="optional"/>
</xs:element> </xs:complexType>
</xs:sequence> </xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType> </xs:complexType>
<xs:complexType name="scripts"> <xs:complexType name="scripts">
<xs:sequence> <xs:sequence>
@ -56,9 +66,11 @@
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
<xs:complexType name="variable"> <xs:complexType name="variable">
<xs:attribute name="name" use="required" type="xs:NCName"/> <xs:complexContent>
<xs:attribute name="type" use="required" type="xs:NMTOKEN"/> <xs:extension base="tns:namedEntity">
<xs:attribute name="comment" type="xs:string"/> <xs:attribute name="type" use="required" type="xs:NMTOKEN"/>
</xs:extension>
</xs:complexContent>
</xs:complexType> </xs:complexType>
<xs:complexType name="variables"> <xs:complexType name="variables">
<xs:sequence> <xs:sequence>
@ -105,17 +117,13 @@
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
<xs:complexType name="userType"> <xs:complexType name="userType">
<xs:sequence> <xs:complexContent>
<xs:element name="attribute" minOccurs="1" maxOccurs="unbounded"> <xs:extension base="tns:namedEntity">
<xs:complexType> <xs:sequence>
<xs:attribute name="name" use="required" type="xs:NCName"/> <xs:element name="attribute" minOccurs="1" maxOccurs="unbounded" type="tns:variable"/>
<xs:attribute name="type" use="required" type="xs:NMTOKEN"/> </xs:sequence>
<xs:attribute name="comment" type="xs:string"/> </xs:extension>
</xs:complexType> </xs:complexContent>
</xs:element>
</xs:sequence>
<xs:attribute name="name" use="required" type="xs:NCName"/>
<xs:attribute name="comment" use="required" type="xs:string"/>
</xs:complexType> </xs:complexType>
<xs:complexType name="scope"> <xs:complexType name="scope">
<xs:sequence> <xs:sequence>

View File

@ -74,7 +74,7 @@
<block type="text_getboolean"></block> <block type="text_getboolean"></block>
<block type="text_getcharacter"></block> <block type="text_getcharacter"></block>
</category> </category>
<category var="customTypes" name="Custom Types"> <category id="customTypes" name="Custom Types">
</category> </category>
<category name="Graphics"> <category name="Graphics">
<block type="graphics_set_portrait"></block> <block type="graphics_set_portrait"></block>

View File

@ -63,52 +63,69 @@ if (typeof Mythos === "undefined") {
Mythos.buildCustomTypeBlocks(userType); Mythos.buildCustomTypeBlocks(userType);
}); });
}, },
buildCustomType: function (userType) { buildCustomTypeBlocks: function (userType) {
Blockly.Blocks['userType_' + userType.getName()] = { Blockly.Blocks['userType_' + userType.getName()] = {
init: function () { init: function () {
var typeConstructor = this; try {
typeConstructor.setColour(200); var typeConstructor = this;
typeConstructor.appendDummyInput() typeConstructor.setPreviousStatement(false);
.appendField("Create " + userType.getName()); typeConstructor.setNextStatement(false);
Mythos.each(userType.getAttribute(), function (attribute) { typeConstructor.setOutput(true, null);
typeConstructor.appendValueInput(attribute.getName()) typeConstructor.setColour(200);
.setAlign(Blockly.ALIGN_RIGHT) typeConstructor.setTooltip(userType.getComment());
.setCheck(attribute.getType()) typeConstructor.appendDummyInput()
.appendField(attribute.getName()); .appendField("Create " + userType.getName());
}); Mythos.each(userType.getAttribute(), function (attribute) {
typeConstructor.setPreviousStatement(true); typeConstructor.appendValueInput(attribute.getName())
typeConstructor.setNextStatement(true); .setAlign(Blockly.ALIGN_RIGHT)
typeConstructor.setOutput(true, userType.getName()); .setCheck(attribute.getType())
.appendField(attribute.getName())
});
} catch (error) {
Mythos.editor.log(error);
}
} }
}; };
Blockly.Blocks['set_' + userType.getName()] = { Blockly.Blocks['set_' + userType.getName()] = {
init: function () { init: function () {
var typeSetter = this; try {
typeSetter.setColour(200); var typeSetter = this;
typeSetter.appendValueInput("Set ") typeSetter.setColour(200);
.setAlign(Blockly.ALIGN_LEFT) typeSetter.setPreviousStatement(true);
.setCheck(null) typeSetter.setNextStatement(true);
.appendField(Mythos.getVariableDropdown(userType), "VAR") typeSetter.setOutput(false);
.appendField(".") typeSetter.setTooltip(userType.getComment());
.appendField(Mythos.getAttributeDropdown(userType), "ATTR"); typeSetter.appendValueInput()
typeSetter.setPreviousStatement(true); .setAlign(Blockly.ALIGN_LEFT)
typeSetter.setNextStatement(true); .appendField("Set")
typeSetter.setOutput(false); .appendField(new Blockly.FieldVariable(userType.getName()), "VAR")
.appendField(".")
.appendField(Mythos.getAttributeDropdown(userType), "ATTR")
.appendField("to");
} catch (error) {
Mythos.editor.log(error);
}
} }
}; };
Blockly.Blocks['get_' + userType.getName()] = { Blockly.Blocks['get_' + userType.getName()] = {
init: function () { init: function () {
var typeGetter = this; try {
typeGetter.setColour(200); var typeGetter = this;
typeGetter.appendDummyInput() typeGetter.setColour(200);
.setAlign(Blockly.ALIGN_LEFT) typeGetter.setPreviousStatement(false);
.setCheck(null) typeGetter.setNextStatement(false);
.appendField(Mythos.getVariableDropdown(userType), "VAR") typeGetter.setOutput(true, null);
.appendField(".") typeGetter.setTooltip(userType.getComment());
.appendField(Mythos.getAttributeDropdown(userType), "ATTR"); typeGetter.appendDummyInput()
typeGetter.setPreviousStatement(false); .setAlign(Blockly.ALIGN_LEFT)
typeGetter.setNextStatement(false); .appendField("Get")
typeGetter.setOutput(true, null); .appendField(new Blockly.FieldVariable(userType.getName()), "VAR")
.appendField(".")
.appendField(Mythos.getAttributeDropdown(userType), "ATTR");
} catch (error) {
Mythos.editor.log(error);
}
} }
}; };
}, },
@ -118,16 +135,16 @@ if (typeof Mythos === "undefined") {
Mythos.each(variables, function (variable) { Mythos.each(variables, function (variable) {
options.push([variable.getName(), variable.getName()]); options.push([variable.getName(), variable.getName()]);
}); });
return Blockly.FieldDropdown(options); return new Blockly.FieldDropdown(options);
}, },
getAttributeDropdown: function (userType) { getAttributeDropdown: function (userType) {
var options = []; var options = [];
Mythos.each(userType.getAttribute(), function (attribute) { Mythos.each(userType.getAttribute(), function (attribute) {
options.push([attribute.getName(), attribute.getName()]); options.push([attribute.getName(), attribute.getName()]);
}); });
return Blockly.FieldDropdown(options); return new Blockly.FieldDropdown(options);
}, },
addFunctionsFromScope: function(target, prefix, functions) { addFunctionsFromScope: function (target, prefix, functions) {
Mythos.each(functions, function (func) { Mythos.each(functions, function (func) {
var scriptNode = document.createElement("block"); var scriptNode = document.createElement("block");
scriptNode.setAttribute("type", prefix + "_" + func.getName()); scriptNode.setAttribute("type", prefix + "_" + func.getName());
@ -168,7 +185,7 @@ if (typeof Mythos === "undefined") {
}); });
} }
}; };
}); });
}, },
addFunctionsFromGlobalScope: function () { addFunctionsFromGlobalScope: function () {
var toolbarCategory = document.getElementById("globalFunctions"); var toolbarCategory = document.getElementById("globalFunctions");