Custom user types are now working, and a few other cleanups in the code were made along the way to support this massive change.

This commit is contained in:
Brendan Robert 2015-07-05 22:54:23 -05:00
parent 1becc7d61b
commit 736ab81061
11 changed files with 403 additions and 196 deletions

View File

@ -1,42 +1,40 @@
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<? extends NamedEntity> 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());
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();
}
}

View File

@ -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

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;
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<V> {
public Control getControl();
public Node getControl();
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) {
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();
}
}

View File

@ -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<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) {
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<Tile,?> callback) {
public static void showTileSelectModal(Pane anchorPane, String category, Callback<Tile, ?> 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<MouseEvent> cancelTileSelectMouseHandler = (MouseEvent e) -> {
if (! (e.getSource() instanceof ImageView)) {
if (!(e.getSource() instanceof ImageView)) {
e.consume();
}
closeCurrentTileSelector();
};
private static final EventHandler<KeyEvent> cancelTileSelectKeyHandler = (KeyEvent e) -> {
if (e.getCode() == KeyCode.ESCAPE) {
closeCurrentTileSelector();

View File

@ -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

View File

@ -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<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
protected void onScriptAddPressed(ActionEvent event) {
UIAction.createAndEditScript(Application.gameData.getGlobal());
@ -70,14 +137,31 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController {
@Override
protected void onDataTypeAddPressed(ActionEvent event) {
try {
UIAction.createAndEditUserType();
redrawGlobalDataTypes();
} catch (IntrospectionException ex) {
Logger.getLogger(GlobalEditorTabControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
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
protected void onDeleteClonePressed(ActionEvent event) {
protected void onDataTypeClonePressed(ActionEvent event) {
}
@Override
@ -132,30 +216,8 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController {
@Override
public void redrawGlobalScripts() {
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) {
DataUtilities.sortScripts(Application.gameData.getGlobal().getScripts());
DataUtilities.sortNamedEntities(Application.gameData.getGlobal().getScripts().getScript());
globalScriptList.getItems().setAll(Application.gameData.getGlobal().getScripts().getScript());
} else {
globalScriptList.getItems().clear();
@ -165,41 +227,22 @@ public class GlobalEditorTabControllerImpl extends GlobalEditorTabController {
@Override
public void redrawGlobalVariables() {
DataUtilities.ensureGlobalExists();
variableList.setOnEditStart((ListView.EditEvent<Variable> event) -> {
UIAction.editVariable(event.getSource().getItems().get(event.getIndex()), Application.gameData.getGlobal());
});
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());
if (variableList.getItems() != null && Application.gameData.getGlobal().getVariables() != null) {
DataUtilities.sortNamedEntities(Application.gameData.getGlobal().getVariables().getVariable());
variableList.getItems().setAll(Application.gameData.getGlobal().getVariables().getVariable());
} else {
variableList.getItems().clear();
}
}
}
@Override
public void redrawGlobalDataTypes() {
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);
setCurrentEditor(null);
} else {
DataUtilities.sortScripts(m.getScripts());
DataUtilities.sortNamedEntities(m.getScripts().getScript());
if (m.getHeight() == null) {
m.setHeight(512);
}
@ -426,7 +426,7 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
mapScriptsList.getItems().clear();
} else {
if (mapScriptsList.getItems() != null && getCurrentMap().getScripts() != null) {
DataUtilities.sortScripts(getCurrentMap().getScripts());
DataUtilities.sortNamedEntities(getCurrentMap().getScripts().getScript());
mapScriptsList.getItems().setAll(getCurrentMap().getScripts().getScript());
} else {
mapScriptsList.getItems().clear();

View File

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

View File

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

View File

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

View File

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