This commit is contained in:
David Schmenk 2014-05-14 08:17:14 -07:00
commit ebf69c7c61
22 changed files with 1728 additions and 1347 deletions

View File

@ -0,0 +1,51 @@
package org.badvision.outlaweditor;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
/**
*
* @author blurry
*/
public abstract class ApplicationMenuController {
@FXML
abstract public void onChangePlatformAppleDHGRSolid(ActionEvent event);
@FXML
abstract public void onChangePlatformAppleDHGRText(ActionEvent event);
@FXML
abstract public void onChangePlatformAppleSolid(ActionEvent event);
@FXML
abstract public void onChangePlatformAppleText(ActionEvent event);
@FXML
abstract public void onChangePlatformC64(ActionEvent event);
@FXML
abstract public void onEditCopy(ActionEvent event);
@FXML
abstract public void onEditPaste(ActionEvent event);
@FXML
abstract public void onEditSelect(ActionEvent event);
@FXML
abstract public void onFileOpen(ActionEvent event);
@FXML
abstract public void onFileQuit(ActionEvent event);
@FXML
abstract public void onFileSave(ActionEvent event);
@FXML
abstract public void onFileSaveAs(ActionEvent event);
@FXML
abstract public void onHelpAbout(ActionEvent event);
}

View File

@ -0,0 +1,116 @@
package org.badvision.outlaweditor;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import org.badvision.outlaweditor.apple.AppleTileRenderer;
/**
*
* @author blurry
*/
public class ApplicationMenuControllerImpl extends ApplicationMenuController {
@Override
public void onChangePlatformAppleSolid(ActionEvent event) {
AppleTileRenderer.useSolidPalette = true;
Application.currentPlatform = Platform.AppleII;
ApplicationUIController.getController().platformChange();
}
@Override
public void onChangePlatformAppleText(ActionEvent event) {
AppleTileRenderer.useSolidPalette = false;
Application.currentPlatform = Platform.AppleII;
ApplicationUIController.getController().platformChange();
}
@Override
public void onChangePlatformAppleDHGRSolid(ActionEvent event) {
AppleTileRenderer.useSolidPalette = true;
Application.currentPlatform = Platform.AppleII_DHGR;
ApplicationUIController.getController().platformChange();
}
@Override
public void onChangePlatformAppleDHGRText(ActionEvent event) {
AppleTileRenderer.useSolidPalette = false;
Application.currentPlatform = Platform.AppleII_DHGR;
ApplicationUIController.getController().platformChange();
}
@Override
public void onChangePlatformC64(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onEditCopy(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
if (mainController.getVisibleEditor() != null) {
mainController.getVisibleEditor().copy();
}
}
@Override
public void onEditPaste(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
if (mainController.getVisibleEditor() != null) {
mainController.getVisibleEditor().paste();
}
}
@Override
public void onEditSelect(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
if (mainController.getVisibleEditor() != null) {
mainController.getVisibleEditor().select();
}
}
@Override
public void onFileOpen(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
try {
UIAction.actionPerformed(UIAction.MAIN_ACTIONS.Load);
mainController.rebuildImageSelector();
mainController.mapController.rebuildMapSelectors();
mainController.rebuildTileSelectors();
} catch (IOException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void onFileQuit(ActionEvent event) {
UIAction.quit();
}
@Override
public void onFileSave(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
mainController.completeInflightOperations();
try {
UIAction.actionPerformed(UIAction.MAIN_ACTIONS.Save);
} catch (IOException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void onFileSaveAs(ActionEvent event) {
try {
UIAction.actionPerformed(UIAction.MAIN_ACTIONS.Save_as);
} catch (IOException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void onHelpAbout(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

View File

@ -5,21 +5,33 @@ import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import org.badvision.outlaweditor.data.xml.Image;
import org.badvision.outlaweditor.data.xml.Map;
import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Tile;
public abstract class ApplicationUIController {
public static ApplicationUIController getController() {
return Application.instance.controller;
}
abstract void rebuildTileSelectors();
abstract void rebuildImageSelector();
abstract Editor getVisibleEditor();
@FXML // ResourceBundle that was given to the FXMLLoader
protected ResourceBundle resources;
@FXML
ApplicationMenuController menuController;
@FXML
TileEditorTabController tileController;
@FXML
MapEditorTabController mapController;
@FXML // URL location of the FXML file that was given to the FXMLLoader
protected URL location;
@FXML // fx:id="imageCategoryField"
@ -36,38 +48,8 @@ public abstract class ApplicationUIController {
protected ComboBox<Image> imageSelector; // Value injected by FXMLLoader
@FXML // fx:id="imageWidthField"
protected TextField imageWidthField; // Value injected by FXMLLoader
@FXML // fx:id="mapEditorAnchorPane"
protected AnchorPane mapEditorAnchorPane; // Value injected by FXMLLoader
@FXML // fx:id="mapHeightField"
protected TextField mapHeightField; // Value injected by FXMLLoader
@FXML // fx:id="mapNameField"
protected TextField mapNameField; // Value injected by FXMLLoader
@FXML // fx:id="mapScriptsList"
protected ListView<Script> mapScriptsList; // Value injected by FXMLLoader
@FXML // fx:id="mapSelect"
protected ComboBox<Map> mapSelect; // Value injected by FXMLLoader
@FXML
protected Menu mapSelectTile;
@FXML // fx:id="mapWidthField"
protected TextField mapWidthField; // Value injected by FXMLLoader
@FXML // fx:id="mapWrapAround"
protected CheckBox mapWrapAround; // Value injected by FXMLLoader
@FXML // fx:id="tileCategoryField"
protected TextField tileCategoryField; // Value injected by FXMLLoader
@FXML // fx:id="tileEditorAnchorPane"
protected AnchorPane tileEditorAnchorPane; // Value injected by FXMLLoader
@FXML // fx:id="tileIdField"
protected TextField tileIdField; // Value injected by FXMLLoader
@FXML // fx:id="tileNameField"
protected TextField tileNameField; // Value injected by FXMLLoader
@FXML // fx:id="tileObstructionField"
protected CheckBox tileObstructionField; // Value injected by FXMLLoader
@FXML // fx:id="tilePatternMenu"
protected Menu tilePatternMenu; // Value injected by FXMLLoader
@FXML // fx:id="tileSelector"
protected ComboBox<Tile> tileSelector; // Value injected by FXMLLoader
// Handler for MenuItem[javafx.scene.control.MenuItem@3a4bc91a] onAction
@FXML
abstract public void imageBitMode(ActionEvent event);
@ -87,9 +69,6 @@ public abstract class ApplicationUIController {
@FXML
abstract public void imageShift(ActionEvent event);
@FXML
abstract public void imageTabActivated(Event event);
// Handler for MenuItem[javafx.scene.control.MenuItem@547638c0] onAction
@FXML
abstract public void imageTogglePanZoom(ActionEvent event);
@ -102,75 +81,6 @@ public abstract class ApplicationUIController {
@FXML
abstract public void imageZoomOut(ActionEvent event);
@FXML
abstract public void mapDraw1(ActionEvent event);
@FXML
abstract public void mapDraw3(ActionEvent event);
@FXML
abstract public void mapDraw5(ActionEvent event);
@FXML
abstract public void mapDrawFilledRectMode(ActionEvent event);
@FXML
abstract public void mapTabActivated(Event event);
@FXML
abstract public void mapTogglePanZoom(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button zoomInButton]] onAction
@FXML
abstract public void mapZoomIn(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button zoomOutButton]] onAction
@FXML
abstract public void mapZoomOut(ActionEvent event);
// Handler for ComboBox[fx:id="tileSelector"] onAction
@FXML
abstract public void onCurrentTileSelected(ActionEvent event);
@FXML
abstract public void onChangePlatformAppleSolid(ActionEvent event);
@FXML
abstract public void onChangePlatformAppleText(ActionEvent event);
@FXML
abstract public void onChangePlatformAppleDHGRSolid(ActionEvent event);
@FXML
abstract public void onChangePlatformAppleDHGRText(ActionEvent event);
@FXML
abstract public void onChangePlatformC64(ActionEvent event);
@FXML
abstract public void onEditCopy(ActionEvent event);
@FXML
abstract public void onEditPaste(ActionEvent event);
@FXML
abstract public void onEditSelect(ActionEvent event);
@FXML
abstract public void onFileOpen(ActionEvent event);
@FXML
abstract public void onFileQuit(ActionEvent event);
@FXML
abstract public void onFileSave(ActionEvent event);
@FXML
abstract public void onFileSaveAs(ActionEvent event);
@FXML
abstract public void onHelpAbout(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onImageClonePressed(ActionEvent event);
@ -191,56 +101,7 @@ public abstract class ApplicationUIController {
@FXML
abstract public void onImageSelected(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapClonePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapCreatePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapDeletePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapExportPressed(ActionEvent event);
@FXML
abstract public void onMapPreviewPressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapScriptAddPressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapScriptClonePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapScriptDeletePressed(ActionEvent event);
// Handler for ComboBox[id="tileSelect"] onAction
@FXML
abstract public void onMapSelected(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onTileClonePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onTileCreatePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onTileDeletePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onTileExportPressed(ActionEvent event);
abstract public void platformChange();
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
@ -258,43 +119,17 @@ public abstract class ApplicationUIController {
@FXML
abstract public void scrollImageUp(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
abstract public void scrollMapDown(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
abstract public void scrollMapLeft(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
abstract public void scrollMapRight(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
abstract public void scrollMapUp(ActionEvent event);
// Handler for MenuItem[javafx.scene.control.MenuItem@3b007e44] onAction
@FXML
abstract public void tileBitMode(ActionEvent event);
// Handler for MenuItem[javafx.scene.control.MenuItem@4771c0b8] onAction
@FXML
abstract public void tileDraw1BitMode(ActionEvent event);
// Handler for MenuItem[javafx.scene.control.MenuItem@766bd19d] onAction
@FXML
abstract public void tileDraw3BitMode(ActionEvent event);
@FXML
abstract public void imageDraw5BitMode(ActionEvent event);
@FXML
abstract public void tileTabActivated(Event event);
// Handler for MenuItem[javafx.scene.control.MenuItem@622410f1] onAction
@FXML
abstract public void tileShift(ActionEvent event);
abstract public void mapTabActivated(Event event);
@FXML
abstract public void imageTabActivated(Event event);
@FXML // This method is called by the FXMLLoader when initialization is complete
public void initialize() {
@ -305,23 +140,9 @@ public abstract class ApplicationUIController {
assert imagePatternMenu != null : "fx:id=\"imagePatternMenu\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert imageSelector != null : "fx:id=\"imageSelector\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert imageWidthField != null : "fx:id=\"imageWidthField\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert mapEditorAnchorPane != null : "fx:id=\"mapEditorAnchorPane\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert mapHeightField != null : "fx:id=\"mapHeightField\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert mapNameField != null : "fx:id=\"mapNameField\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert mapScriptsList != null : "fx:id=\"mapScriptsList\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert mapSelect != null : "fx:id=\"mapSelect\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert mapSelectTile != null : "fx:id=\"mapSelectTile\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert mapWidthField != null : "fx:id=\"mapWidthField\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert mapWrapAround != null : "fx:id=\"mapWrapAround\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert tileCategoryField != null : "fx:id=\"tileCategoryField\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert tileEditorAnchorPane != null : "fx:id=\"tileEditorAnchorPane\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert tileIdField != null : "fx:id=\"tileIdField\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert tileNameField != null : "fx:id=\"tileNameField\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert tileObstructionField != null : "fx:id=\"tileObstructionField\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert tilePatternMenu != null : "fx:id=\"tilePatternMenu\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
assert tileSelector != null : "fx:id=\"tileSelector\" was not injected: check your FXML file 'ApplicationUI.fxml'.";
// Initialize your logic here: all @FXML variables will have been injected
}
abstract void completeInflightOperations();
}

View File

@ -1,37 +1,23 @@
package org.badvision.outlaweditor;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.ComboBoxListCell;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.util.Callback;
import static org.badvision.outlaweditor.Application.currentPlatform;
import static org.badvision.outlaweditor.Application.gameData;
import static org.badvision.outlaweditor.UIAction.*;
import org.badvision.outlaweditor.apple.AppleTileRenderer;
import static org.badvision.outlaweditor.data.PropertyHelper.*;
import org.badvision.outlaweditor.data.TileUtils;
import org.badvision.outlaweditor.data.TilesetUtils;
import org.badvision.outlaweditor.data.xml.Image;
import org.badvision.outlaweditor.data.xml.PlatformData;
import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Tile;
/**
@ -41,10 +27,6 @@ import org.badvision.outlaweditor.data.xml.Tile;
*/
public class ApplicationUIControllerImpl extends ApplicationUIController {
public Tile currentTile = null;
public TileEditor currentTileEditor = null;
public org.badvision.outlaweditor.data.xml.Map currentMap = null;
public MapEditor currentMapEditor = null;
public Image currentImage = null;
public ImageEditor currentImageEditor = null;
@ -58,60 +40,6 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
rebuildTileSelectors();
}
});
tileSelector.setButtonCell(new ComboBoxListCell<Tile>() {
{
super.setPrefWidth(125);
}
@Override
public void updateItem(Tile item, boolean empty) {
textProperty().unbind();
super.updateItem(item, empty);
if (item != null) {
textProperty().bind(tileNameField.textProperty());
} else {
setText(null);
}
}
});
tileSelector.setCellFactory(new Callback<ListView<Tile>, ListCell<Tile>>() {
@Override
public ListCell<Tile> call(ListView<Tile> param) {
return new EntitySelectorCell<Tile>(tileNameField) {
@Override
public void finishUpdate(Tile item) {
setGraphic(new ImageView(TileUtils.getImage(item, Application.currentPlatform)));
}
};
}
});
mapSelect.setButtonCell(new ComboBoxListCell<org.badvision.outlaweditor.data.xml.Map>() {
{
super.setPrefWidth(125);
}
@Override
public void updateItem(org.badvision.outlaweditor.data.xml.Map item, boolean empty) {
textProperty().unbind();
super.updateItem(item, empty);
if (item != null) {
textProperty().bind(mapNameField.textProperty());
} else {
setText(null);
}
}
});
mapSelect.setCellFactory(new Callback<ListView<org.badvision.outlaweditor.data.xml.Map>, ListCell<org.badvision.outlaweditor.data.xml.Map>>() {
@Override
public ListCell<org.badvision.outlaweditor.data.xml.Map> call(ListView<org.badvision.outlaweditor.data.xml.Map> param) {
return new EntitySelectorCell<org.badvision.outlaweditor.data.xml.Map>(mapNameField) {
@Override
public void finishUpdate(org.badvision.outlaweditor.data.xml.Map item) {
}
};
}
});
imageSelector.setButtonCell(new ComboBoxListCell<Image>() {
{
@ -204,170 +132,6 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
}
}
@Override
public void mapDraw1(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.setDrawMode(MapEditor.DrawMode.Pencil1px);
}
}
@Override
public void mapDraw3(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.setDrawMode(MapEditor.DrawMode.Pencil3px);
}
}
@Override
public void mapDraw5(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.setDrawMode(MapEditor.DrawMode.Pencil5px);
}
}
@Override
public void mapDrawFilledRectMode(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.setDrawMode(MapEditor.DrawMode.FilledRect);
}
}
@Override
public void mapTogglePanZoom(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.togglePanZoom();
}
}
@Override
public void mapZoomIn(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.zoomIn();
}
}
@Override
public void mapZoomOut(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.zoomOut();
}
}
@Override
public void onCurrentTileSelected(ActionEvent event) {
setCurrentTile(tileSelector.getSelectionModel().getSelectedItem());
}
@Override
public void onChangePlatformAppleSolid(ActionEvent event) {
AppleTileRenderer.useSolidPalette = true;
Application.currentPlatform = Platform.AppleII;
platformChange();
}
@Override
public void onChangePlatformAppleText(ActionEvent event) {
AppleTileRenderer.useSolidPalette = false;
Application.currentPlatform = Platform.AppleII;
platformChange();
}
@Override
public void onChangePlatformAppleDHGRSolid(ActionEvent event) {
AppleTileRenderer.useSolidPalette = true;
Application.currentPlatform = Platform.AppleII_DHGR;
platformChange();
}
@Override
public void onChangePlatformAppleDHGRText(ActionEvent event) {
AppleTileRenderer.useSolidPalette = false;
Application.currentPlatform = Platform.AppleII_DHGR;
platformChange();
}
private void platformChange() {
for (Tile t : Application.gameData.getTile()) {
TileUtils.redrawTile(t);
}
Tile tile = currentTile;
rebuildTileSelectors();
setCurrentTile(tile);
if (currentMapEditor != null) {
currentMapEditor.redraw();
}
rebuildImageSelector();
}
@Override
public void onChangePlatformC64(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onEditCopy(ActionEvent event) {
if (getVisibleEditor() != null) {
getVisibleEditor().copy();
}
}
@Override
public void onEditPaste(ActionEvent event) {
if (getVisibleEditor() != null) {
getVisibleEditor().paste();
}
}
@Override
public void onEditSelect(ActionEvent event) {
if (getVisibleEditor() != null) {
getVisibleEditor().select();
}
}
@Override
public void onFileOpen(ActionEvent event) {
try {
UIAction.actionPerformed(UIAction.MAIN_ACTIONS.Load);
rebuildImageSelector();
rebuildMapSelectors();
rebuildTileSelectors();
} catch (IOException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void onFileQuit(ActionEvent event) {
UIAction.quit();
}
@Override
public void onFileSave(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.currentMap.updateBackingMap();
}
try {
UIAction.actionPerformed(UIAction.MAIN_ACTIONS.Save);
} catch (IOException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void onFileSaveAs(ActionEvent event) {
try {
UIAction.actionPerformed(UIAction.MAIN_ACTIONS.Save_as);
} catch (IOException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void onHelpAbout(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onImageClonePressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
@ -411,123 +175,17 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
}
@Override
public void onMapClonePressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onMapCreatePressed(ActionEvent event) {
org.badvision.outlaweditor.data.xml.Map m = new org.badvision.outlaweditor.data.xml.Map();
m.setName("Untitled");
gameData.getMap().add(m);
m.setWidth(512);
m.setHeight(512);
setCurrentMap(m);
rebuildMapSelectors();
}
@Override
public void onMapDeletePressed(ActionEvent event) {
if (currentMap == null) {
return;
public void platformChange() {
for (Tile t : Application.gameData.getTile()) {
TileUtils.redrawTile(t);
}
confirm("Delete map '" + currentMap.getName() + "'. Are you sure?", new Runnable() {
@Override
public void run() {
org.badvision.outlaweditor.data.xml.Map del = currentMap;
setCurrentMap(null);
Application.gameData.getMap().remove(del);
rebuildMapSelectors();
}
}, null);
}
@Override
public void onMapExportPressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onMapPreviewPressed(ActionEvent event) {
if (currentMapEditor == null) {
return;
}
currentMapEditor.showPreview();
}
@Override
public void onMapScriptAddPressed(ActionEvent event) {
createAndEditScript();
}
@Override
public void onMapScriptClonePressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onMapScriptDeletePressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onMapSelected(ActionEvent event) {
setCurrentMap(mapSelect.getSelectionModel().getSelectedItem());
}
@Override
public void onTileClonePressed(ActionEvent event) {
if (currentTile == null) {
return;
}
Tile t = new Tile();
TileUtils.getId(t);
t.setName(currentTile.getName() + " (clone)");
t.setObstruction(currentTile.isObstruction());
t.getCategory().addAll(currentTile.getCategory());
for (PlatformData d : currentTile.getDisplayData()) {
PlatformData p = new PlatformData();
p.setHeight(d.getHeight());
p.setWidth(d.getWidth());
p.setPlatform(d.getPlatform());
p.setValue(Arrays.copyOf(d.getValue(), d.getValue().length));
t.getDisplayData().add(p);
}
TilesetUtils.add(t);
Tile tile = tileController.getCurrentTile();
rebuildTileSelectors();
setCurrentTile(t);
}
@Override
public void onTileCreatePressed(ActionEvent event) {
Tile t = TileUtils.newTile();
t.setName("Untitled");
TilesetUtils.add(t);
rebuildTileSelectors();
setCurrentTile(t);
}
@Override
public void onTileDeletePressed(ActionEvent event) {
if (currentTile == null) {
return;
tileController.setCurrentTile(tile);
if (mapController.getCurrentEditor() != null) {
mapController.getCurrentEditor().redraw();
}
confirm("Delete tile '" + currentTile.getName() + "'. Are you sure?", new Runnable() {
@Override
public void run() {
Tile del = currentTile;
setCurrentTile(null);
Application.gameData.getTile().remove(del);
rebuildTileSelectors();
}
}, null);
}
@Override
public void onTileExportPressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
rebuildImageSelector();
}
@Override
@ -559,194 +217,9 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
}
@Override
public void scrollMapDown(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.scrollBy(0, 1);
}
}
@Override
public void scrollMapLeft(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.scrollBy(-1, 0);
}
}
@Override
public void scrollMapRight(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.scrollBy(1, 0);
}
}
@Override
public void scrollMapUp(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.scrollBy(0, -1);
}
}
@Override
public void tileBitMode(ActionEvent event) {
if (currentTileEditor != null) {
currentTileEditor.setDrawMode(TileEditor.DrawMode.Toggle);
}
}
@Override
public void tileDraw1BitMode(ActionEvent event) {
if (currentTileEditor != null) {
currentTileEditor.setDrawMode(TileEditor.DrawMode.Pencil1px);
}
}
@Override
public void tileDraw3BitMode(ActionEvent event) {
if (currentTileEditor != null) {
currentTileEditor.setDrawMode(TileEditor.DrawMode.Pencil3px);
}
}
@Override
public void tileShift(ActionEvent event) {
if (currentTileEditor != null) {
currentTileEditor.showShiftUI();
}
}
private void setCurrentTileEditor(TileEditor editor) {
if (editor != null) {
editor.buildEditorUI(tileEditorAnchorPane);
editor.buildPatternSelector(tilePatternMenu);
}
currentTileEditor = editor;
}
public Tile getCurrentTile() {
return currentTile;
}
public void setCurrentTile(Tile t) {
tileSelector.getSelectionModel().select(t);
if (t != null && t.equals(currentTile)) {
return;
}
tileEditorAnchorPane.getChildren().clear();
if (t == null) {
bind(tileIdField.textProperty(), null);
bind(tileCategoryField.textProperty(), null);
bind(tileObstructionField.selectedProperty(), null);
bind(tileNameField.textProperty(), null);
tileIdField.setDisable(true);
tileCategoryField.setDisable(true);
tileObstructionField.setDisable(true);
tileNameField.setDisable(true);
setCurrentTileEditor(null);
} else {
if (t.isObstruction() == null) {
t.setObstruction(false);
}
try {
tileIdField.setDisable(false);
tileCategoryField.setDisable(false);
tileObstructionField.setDisable(false);
tileNameField.setDisable(false);
bind(tileIdField.textProperty(), stringProp(t, "id"));
bind(tileCategoryField.textProperty(), categoryProp(t, "category"));
bind(tileObstructionField.selectedProperty(), boolProp(t, "obstruction"));
bind(tileNameField.textProperty(), stringProp(t, "name"));
TileEditor editor = Application.currentPlatform.tileEditor.newInstance();
editor.setEntity(t);
setCurrentTileEditor(editor);
} catch (NoSuchMethodException ex) {
Logger.getLogger(ApplicationUIController.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
currentTile = t;
}
public void rebuildTileSelectors() {
tileSelector.getItems().clear();
tileSelector.getItems().addAll(Application.gameData.getTile());
tileSelector.getSelectionModel().select(getCurrentTile());
mapSelectTile.getItems().clear();
for (final Tile t : Application.gameData.getTile()) {
WritableImage img = TileUtils.getImage(t, currentPlatform);
ImageView iv = new ImageView(img);
MenuItem mapSelectItem = new MenuItem(t.getName(), iv);
mapSelectItem.setGraphic(new ImageView(TileUtils.getImage(t, currentPlatform)));
mapSelectItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if (currentMapEditor != null) {
currentMapEditor.setCurrentTile(t);
}
}
});
mapSelectTile.getItems().add(mapSelectItem);
}
}
public void setCurrentMap(org.badvision.outlaweditor.data.xml.Map m) {
if (currentMap != null && currentMap.equals(m)) {
return;
}
// mapEditorAnchorPane.getChildren().clear();
currentMap = m;
if (currentMapEditor != null) {
currentMapEditor.unregister();
}
if (m == null) {
bind(mapHeightField.textProperty(), null);
bind(mapNameField.textProperty(), null);
bind(mapWidthField.textProperty(), null);
bind(mapWrapAround.selectedProperty(), null);
mapHeightField.setDisable(true);
mapNameField.setDisable(true);
mapWidthField.setDisable(true);
mapWrapAround.setDisable(true);
currentMapEditor = null;
} else {
if (m.getHeight() == null) {
m.setHeight(512);
}
if (m.getWidth() == null) {
m.setWidth(512);
}
if (m.getName() == null) {
m.setName("Untitled");
}
try {
mapHeightField.setDisable(false);
mapNameField.setDisable(false);
mapWidthField.setDisable(false);
mapWrapAround.setDisable(false);
// bind(mapHeightField.textProperty(), intProp(m, "height"));
bind(mapNameField.textProperty(), stringProp(m, "name"));
// bind(mapWidthField.textProperty(), intProp(m, "width"));
// bind(mapWrapAround.selectedProperty(),boolProp(m, "wrap"));
} catch (NoSuchMethodException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
currentMapEditor = new MapEditor();
currentMapEditor.setEntity(m);
currentMapEditor.buildEditorUI(mapEditorAnchorPane);
}
redrawMapScripts();
}
public void rebuildMapSelectors() {
mapSelect.getItems().clear();
mapSelect.getItems().addAll(Application.gameData.getMap());
mapSelect.getSelectionModel().select(getCurrentMap());
}
public org.badvision.outlaweditor.data.xml.Map getCurrentMap() {
return currentMap;
tileController.rebuildTileSelectors();
mapController.rebuildTileSelectors();
}
private void setCurrentImage(Image i) {
@ -797,13 +270,21 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
return currentImage;
}
private void rebuildImageSelector() {
@Override
public void rebuildImageSelector() {
Image i = getCurrentImage();
imageSelector.getItems().clear();
imageSelector.getItems().addAll(Application.gameData.getImage());
imageSelector.getSelectionModel().select(i);
}
@Override
public void completeInflightOperations() {
if (mapController.getCurrentEditor() != null) {
mapController.getCurrentEditor().currentMap.updateBackingMap();
}
}
public static enum TABS {
image, map, tile
@ -825,51 +306,20 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
currentTab = TABS.tile;
}
@Override
public Editor getVisibleEditor() {
switch (currentTab) {
case image:
return currentImageEditor;
case map:
return currentMapEditor;
return mapController.getCurrentEditor();
case tile:
return currentTileEditor;
return tileController.getCurrentTileEditor();
}
return null;
}
public static final DataFormat SCRIPT_DATA_FORMAT = new DataFormat("MythosScript");
public void redrawMapScripts() {
mapScriptsList.setOnEditStart(new EventHandler<ListView.EditEvent<Script>>() {
@Override
public void handle(ListView.EditEvent<Script> event) {
UIAction.editScript(event.getSource().getItems().get(event.getIndex()));
}
});
final TransferHelper<Script> scriptDragDrop = new TransferHelper<>(Script.class);
mapScriptsList.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());
scriptDragDrop.registerDragSupport(this, item);
}
}
};
return cell;
}
});
if (currentMap == null) {
mapScriptsList.getItems().clear();
} else {
mapScriptsList.getItems().setAll(currentMap.getScripts().getScript());
}
}
abstract public static class EntitySelectorCell<T> extends ComboBoxListCell<T> {
@ -915,4 +365,5 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
public void finishUpdate(T item) {
}
};
}

View File

@ -0,0 +1,134 @@
package org.badvision.outlaweditor;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import org.badvision.outlaweditor.data.xml.Map;
import org.badvision.outlaweditor.data.xml.Script;
/**
*
* @author blurry
*/
public abstract class MapEditorTabController {
private MapEditor currentEditor;
public MapEditor getCurrentEditor() {
return currentEditor;
}
public void setCurrentEditor(MapEditor editor) {
currentEditor = editor;
}
public abstract Map getCurrentMap();
public abstract void setCurrentMap(Map m);
public abstract void rebuildMapSelectors();
public abstract void redrawMapScripts();
@FXML // fx:id="mapEditorAnchorPane"
protected AnchorPane mapEditorAnchorPane; // Value injected by FXMLLoader
@FXML // fx:id="mapHeightField"
protected TextField mapHeightField; // Value injected by FXMLLoader
@FXML // fx:id="mapNameField"
protected TextField mapNameField; // Value injected by FXMLLoader
@FXML // fx:id="mapScriptsList"
protected ListView<Script> mapScriptsList; // Value injected by FXMLLoader
@FXML // fx:id="mapSelect"
protected ComboBox<Map> mapSelect; // Value injected by FXMLLoader
@FXML
protected Menu mapSelectTile;
@FXML // fx:id="mapWidthField"
protected TextField mapWidthField; // Value injected by FXMLLoader
@FXML // fx:id="mapWrapAround"
protected CheckBox mapWrapAround; // Value injected by FXMLLoader
@FXML
abstract public void mapDraw1(ActionEvent event);
@FXML
abstract public void mapDraw3(ActionEvent event);
@FXML
abstract public void mapDraw5(ActionEvent event);
@FXML
abstract public void mapDrawFilledRectMode(ActionEvent event);
@FXML
abstract public void mapTogglePanZoom(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button zoomInButton]] onAction
@FXML
abstract public void mapZoomIn(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button zoomOutButton]] onAction
@FXML
abstract public void mapZoomOut(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapClonePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapCreatePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapDeletePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapExportPressed(ActionEvent event);
@FXML
abstract public void onMapPreviewPressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapScriptAddPressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapScriptClonePressed(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button]] onAction
@FXML
abstract public void onMapScriptDeletePressed(ActionEvent event);
// Handler for ComboBox[id="tileSelect"] onAction
@FXML
abstract public void onMapSelected(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
abstract public void scrollMapDown(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
abstract public void scrollMapLeft(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
abstract public void scrollMapRight(ActionEvent event);
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
@FXML
abstract public void scrollMapUp(ActionEvent event);
protected void initalize() {
assert mapEditorAnchorPane != null : "fx:id=\"mapEditorAnchorPane\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapHeightField != null : "fx:id=\"mapHeightField\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapNameField != null : "fx:id=\"mapNameField\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapScriptsList != null : "fx:id=\"mapScriptsList\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapSelect != null : "fx:id=\"mapSelect\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapSelectTile != null : "fx:id=\"mapSelectTile\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapWidthField != null : "fx:id=\"mapWidthField\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
assert mapWrapAround != null : "fx:id=\"mapWrapAround\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
}
abstract void rebuildTileSelectors();
}

View File

@ -0,0 +1,327 @@
package org.badvision.outlaweditor;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.cell.ComboBoxListCell;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.util.Callback;
import static org.badvision.outlaweditor.Application.currentPlatform;
import static org.badvision.outlaweditor.Application.gameData;
import static org.badvision.outlaweditor.UIAction.confirm;
import static org.badvision.outlaweditor.UIAction.createAndEditScript;
import static org.badvision.outlaweditor.data.PropertyHelper.bind;
import static org.badvision.outlaweditor.data.PropertyHelper.stringProp;
import org.badvision.outlaweditor.data.TileUtils;
import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Tile;
import org.badvision.outlaweditor.data.xml.Map;
/**
*
* @author blurry
*/
public class MapEditorTabControllerImpl extends MapEditorTabController {
@Override
public void mapDraw1(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().setDrawMode(MapEditor.DrawMode.Pencil1px);
}
}
@Override
public void mapDraw3(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().setDrawMode(MapEditor.DrawMode.Pencil3px);
}
}
@Override
public void mapDraw5(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().setDrawMode(MapEditor.DrawMode.Pencil5px);
}
}
@Override
public void mapDrawFilledRectMode(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().setDrawMode(MapEditor.DrawMode.FilledRect);
}
}
@Override
public void mapTogglePanZoom(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().togglePanZoom();
}
}
@Override
public void mapZoomIn(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().zoomIn();
}
}
@Override
public void mapZoomOut(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().zoomOut();
}
}
@Override
public void onMapClonePressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onMapCreatePressed(ActionEvent event) {
org.badvision.outlaweditor.data.xml.Map m = new org.badvision.outlaweditor.data.xml.Map();
m.setName("Untitled");
gameData.getMap().add(m);
m.setWidth(512);
m.setHeight(512);
setCurrentMap(m);
rebuildMapSelectors();
}
@Override
public void onMapDeletePressed(ActionEvent event) {
final Map currentMap = getCurrentMap();
if (currentMap == null) {
return;
}
confirm("Delete map '" + currentMap.getName() + "'. Are you sure?", new Runnable() {
@Override
public void run() {
org.badvision.outlaweditor.data.xml.Map del = currentMap;
setCurrentMap(null);
Application.gameData.getMap().remove(del);
rebuildMapSelectors();
}
}, null);
}
@Override
public void onMapExportPressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onMapPreviewPressed(ActionEvent event) {
if (getCurrentEditor() == null) {
return;
}
getCurrentEditor().showPreview();
}
@Override
public void onMapScriptAddPressed(ActionEvent event) {
createAndEditScript();
}
@Override
public void onMapScriptClonePressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onMapScriptDeletePressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void onMapSelected(ActionEvent event) {
setCurrentMap(mapSelect.getSelectionModel().getSelectedItem());
}
@Override
public void scrollMapDown(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().scrollBy(0, 1);
}
}
@Override
public void scrollMapLeft(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().scrollBy(-1, 0);
}
}
@Override
public void scrollMapRight(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().scrollBy(1, 0);
}
}
@Override
public void scrollMapUp(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().scrollBy(0, -1);
}
}
@Override
public Map getCurrentMap() {
if (getCurrentEditor() == null) {
return null;
} else {
return getCurrentEditor().currentMap.getBackingMap();
}
}
@Override
public void setCurrentMap(Map m) {
if (getCurrentMap() != null && getCurrentMap().equals(m)) {
return;
}
// mapEditorAnchorPane.getChildren().clear();
if (getCurrentEditor() != null) {
getCurrentEditor().unregister();
}
if (m == null) {
bind(mapHeightField.textProperty(), null);
bind(mapNameField.textProperty(), null);
bind(mapWidthField.textProperty(), null);
bind(mapWrapAround.selectedProperty(), null);
mapHeightField.setDisable(true);
mapNameField.setDisable(true);
mapWidthField.setDisable(true);
mapWrapAround.setDisable(true);
setCurrentEditor(null);
} else {
if (m.getHeight() == null) {
m.setHeight(512);
}
if (m.getWidth() == null) {
m.setWidth(512);
}
if (m.getName() == null) {
m.setName("Untitled");
}
try {
mapHeightField.setDisable(false);
mapNameField.setDisable(false);
mapWidthField.setDisable(false);
mapWrapAround.setDisable(false);
// bind(mapHeightField.textProperty(), intProp(m, "height"));
bind(mapNameField.textProperty(), stringProp(m, "name"));
// bind(mapWidthField.textProperty(), intProp(m, "width"));
// bind(mapWrapAround.selectedProperty(),boolProp(m, "wrap"));
} catch (NoSuchMethodException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
MapEditor e = new MapEditor();
e.setEntity(m);
e.buildEditorUI(mapEditorAnchorPane);
setCurrentEditor(e);
}
redrawMapScripts();
}
@Override
public void rebuildMapSelectors() {
mapSelect.getItems().clear();
mapSelect.getItems().addAll(Application.gameData.getMap());
mapSelect.getSelectionModel().select(getCurrentMap());
}
@Override
protected void initalize() {
super.initalize();
mapSelect.setButtonCell(new ComboBoxListCell<org.badvision.outlaweditor.data.xml.Map>() {
{
super.setPrefWidth(125);
}
@Override
public void updateItem(org.badvision.outlaweditor.data.xml.Map item, boolean empty) {
textProperty().unbind();
super.updateItem(item, empty);
if (item != null) {
textProperty().bind(mapNameField.textProperty());
} else {
setText(null);
}
}
});
mapSelect.setCellFactory(new Callback<ListView<org.badvision.outlaweditor.data.xml.Map>, ListCell<org.badvision.outlaweditor.data.xml.Map>>() {
@Override
public ListCell<org.badvision.outlaweditor.data.xml.Map> call(ListView<org.badvision.outlaweditor.data.xml.Map> param) {
return new ApplicationUIControllerImpl.EntitySelectorCell<org.badvision.outlaweditor.data.xml.Map>(mapNameField) {
@Override
public void finishUpdate(org.badvision.outlaweditor.data.xml.Map item) {
}
};
}
});
}
@Override
void rebuildTileSelectors() {
mapSelectTile.getItems().clear();
for (final Tile t : Application.gameData.getTile()) {
WritableImage img = TileUtils.getImage(t, currentPlatform);
ImageView iv = new ImageView(img);
MenuItem mapSelectItem = new MenuItem(t.getName(), iv);
mapSelectItem.setGraphic(new ImageView(TileUtils.getImage(t, currentPlatform)));
mapSelectItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if (getCurrentEditor() != null) {
getCurrentEditor().setCurrentTile(t);
}
}
});
mapSelectTile.getItems().add(mapSelectItem);
}
}
@Override
public void redrawMapScripts() {
mapScriptsList.setOnEditStart(new EventHandler<ListView.EditEvent<Script>>() {
@Override
public void handle(ListView.EditEvent<Script> event) {
UIAction.editScript(event.getSource().getItems().get(event.getIndex()));
}
});
final TransferHelper<Script> scriptDragDrop = new TransferHelper<>(Script.class);
mapScriptsList.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());
scriptDragDrop.registerDragSupport(this, item);
}
}
};
return cell;
}
});
if (getCurrentMap() == null) {
mapScriptsList.getItems().clear();
} else {
if (mapScriptsList.getItems() != null && getCurrentMap().getScripts() != null) {
mapScriptsList.getItems().setAll(getCurrentMap().getScripts().getScript());
} else {
mapScriptsList.getItems().clear();
}
}
}
}

View File

@ -135,6 +135,6 @@ public class MythosEditor {
}
script.setName(name);
System.out.println("Function title changed! >> "+name);
Application.instance.controller.redrawMapScripts();
Application.instance.controller.mapController.redrawMapScripts();
}
}

View File

@ -0,0 +1,83 @@
/*
* 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;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Menu;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import org.badvision.outlaweditor.data.xml.Tile;
/**
*
* @author blurry
*/
public abstract class TileEditorTabController {
private Tile currentTile;
public Tile getCurrentTile() {
return currentTile;
}
public void setCurrentTile(Tile tile) {
currentTile = tile;
}
private TileEditor currentEditor;
public TileEditor getCurrentTileEditor() {
return currentEditor;
}
public void setCurrentTileEditor(TileEditor editor) {
currentEditor = editor;
}
@FXML // fx:id="tileCategoryField"
protected TextField tileCategoryField; // Value injected by FXMLLoader
@FXML // fx:id="tileEditorAnchorPane"
protected AnchorPane tileEditorAnchorPane; // Value injected by FXMLLoader
@FXML // fx:id="tileIdField"
protected TextField tileIdField; // Value injected by FXMLLoader
@FXML // fx:id="tileNameField"
protected TextField tileNameField; // Value injected by FXMLLoader
@FXML // fx:id="tileObstructionField"
protected CheckBox tileObstructionField; // Value injected by FXMLLoader
@FXML // fx:id="tilePatternMenu"
protected Menu tilePatternMenu; // Value injected by FXMLLoader
@FXML // fx:id="tileSelector"
protected ComboBox<Tile> tileSelector; // Value injected by FXMLLoader
@FXML
abstract public void onCurrentTileSelected(ActionEvent event);
@FXML
abstract public void onTileCreatePressed(ActionEvent event);
@FXML
abstract public void onTileExportPressed(ActionEvent event);
@FXML
abstract public void onTileClonePressed(ActionEvent event);
@FXML
abstract public void onTileDeletePressed(ActionEvent event);
@FXML
abstract public void tileBitMode(ActionEvent event);
@FXML
abstract public void tileDraw1BitMode(ActionEvent event);
@FXML
abstract public void tileDraw3BitMode(ActionEvent event);
@FXML
abstract public void tileShift(ActionEvent event);
abstract public void rebuildTileSelectors();
}

View File

@ -0,0 +1,224 @@
package org.badvision.outlaweditor;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.ComboBoxListCell;
import javafx.scene.image.ImageView;
import javafx.util.Callback;
import static org.badvision.outlaweditor.UIAction.confirm;
import static org.badvision.outlaweditor.data.PropertyHelper.bind;
import static org.badvision.outlaweditor.data.PropertyHelper.boolProp;
import static org.badvision.outlaweditor.data.PropertyHelper.categoryProp;
import static org.badvision.outlaweditor.data.PropertyHelper.stringProp;
import org.badvision.outlaweditor.data.TileUtils;
import org.badvision.outlaweditor.data.TilesetUtils;
import org.badvision.outlaweditor.data.xml.PlatformData;
import org.badvision.outlaweditor.data.xml.Tile;
/**
* FXML Controller class for tile editor tab
*
* @author blurry
*/
public class TileEditorTabControllerImpl extends TileEditorTabController {
@Override
public void onCurrentTileSelected(ActionEvent event) {
setCurrentTile(tileSelector.getSelectionModel().getSelectedItem());
}
@Override
public void onTileClonePressed(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
if (getCurrentTile() == null) {
return;
}
Tile t = new Tile();
TileUtils.getId(t);
t.setName(getCurrentTile().getName() + " (clone)");
t.setObstruction(getCurrentTile().isObstruction());
t.getCategory().addAll(getCurrentTile().getCategory());
for (PlatformData d : getCurrentTile().getDisplayData()) {
PlatformData p = new PlatformData();
p.setHeight(d.getHeight());
p.setWidth(d.getWidth());
p.setPlatform(d.getPlatform());
p.setValue(Arrays.copyOf(d.getValue(), d.getValue().length));
t.getDisplayData().add(p);
}
TilesetUtils.add(t);
mainController.rebuildTileSelectors();
setCurrentTile(t);
}
@Override
public void onTileCreatePressed(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
Tile t = TileUtils.newTile();
t.setName("Untitled");
TilesetUtils.add(t);
mainController.rebuildTileSelectors();
setCurrentTile(t);
}
@Override
public void onTileDeletePressed(ActionEvent event) {
final ApplicationUIController mainController = ApplicationUIController.getController();
if (getCurrentTile() == null) {
return;
}
confirm("Delete tile '" + getCurrentTile().getName() + "'. Are you sure?", new Runnable() {
@Override
public void run() {
Tile del = getCurrentTile();
setCurrentTile(null);
Application.gameData.getTile().remove(del);
mainController.rebuildTileSelectors();
}
}, null);
}
@Override
public void tileBitMode(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
if (getCurrentTileEditor() != null) {
getCurrentTileEditor().setDrawMode(TileEditor.DrawMode.Toggle);
}
}
@Override
public void tileDraw1BitMode(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
if (getCurrentTileEditor() != null) {
getCurrentTileEditor().setDrawMode(TileEditor.DrawMode.Pencil1px);
}
}
@Override
public void tileDraw3BitMode(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
if (getCurrentTileEditor() != null) {
getCurrentTileEditor().setDrawMode(TileEditor.DrawMode.Pencil3px);
}
}
@Override
public void tileShift(ActionEvent event) {
ApplicationUIController mainController = ApplicationUIController.getController();
if (getCurrentTileEditor() != null) {
getCurrentTileEditor().showShiftUI();
}
}
@Override
public void onTileExportPressed(ActionEvent event) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
* Initializes the controller class.
*/
public void initialize() {
assert tileCategoryField != null : "fx:id=\"tileCategoryField\" was not injected: check your FXML file 'tileEditorTab.fxml'.";
assert tileEditorAnchorPane != null : "fx:id=\"tileEditorAnchorPane\" was not injected: check your FXML file 'tileEditorTab.fxml'.";
assert tileIdField != null : "fx:id=\"tileIdField\" was not injected: check your FXML file 'tileEditorTab.fxml'.";
assert tileNameField != null : "fx:id=\"tileNameField\" was not injected: check your FXML file 'tileEditorTab.fxml'.";
assert tileObstructionField != null : "fx:id=\"tileObstructionField\" was not injected: check your FXML file 'tileEditorTab.fxml'.";
assert tilePatternMenu != null : "fx:id=\"tilePatternMenu\" was not injected: check your FXML file 'tileEditorTab.fxml'.";
assert tileSelector != null : "fx:id=\"tileSelector\" was not injected: check your FXML file 'tileEditorTab.fxml'.";
tileSelector.setButtonCell(new ComboBoxListCell<Tile>() {
{
super.setPrefWidth(125);
}
@Override
public void updateItem(Tile item, boolean empty) {
textProperty().unbind();
super.updateItem(item, empty);
if (item != null) {
textProperty().bind(tileNameField.textProperty());
} else {
setText(null);
}
}
});
tileSelector.setCellFactory(new Callback<ListView<Tile>, ListCell<Tile>>() {
@Override
public ListCell<Tile> call(ListView<Tile> param) {
return new ApplicationUIControllerImpl.EntitySelectorCell<Tile>(tileNameField) {
@Override
public void finishUpdate(Tile item) {
setGraphic(new ImageView(TileUtils.getImage(item, Application.currentPlatform)));
}
};
}
});
}
@Override
public void setCurrentTileEditor(TileEditor editor) {
if (editor != null) {
editor.buildEditorUI(tileEditorAnchorPane);
editor.buildPatternSelector(tilePatternMenu);
}
super.setCurrentTileEditor(editor);
}
@Override
public void setCurrentTile(Tile t) {
tileSelector.getSelectionModel().select(t);
if (t != null && t.equals(getCurrentTile())) {
return;
}
tileEditorAnchorPane.getChildren().clear();
if (t == null) {
bind(tileIdField.textProperty(), null);
bind(tileCategoryField.textProperty(), null);
bind(tileObstructionField.selectedProperty(), null);
bind(tileNameField.textProperty(), null);
tileIdField.setDisable(true);
tileCategoryField.setDisable(true);
tileObstructionField.setDisable(true);
tileNameField.setDisable(true);
setCurrentTileEditor(null);
} else {
if (t.isObstruction() == null) {
t.setObstruction(false);
}
try {
tileIdField.setDisable(false);
tileCategoryField.setDisable(false);
tileObstructionField.setDisable(false);
tileNameField.setDisable(false);
bind(tileIdField.textProperty(), stringProp(t, "id"));
bind(tileCategoryField.textProperty(), categoryProp(t, "category"));
bind(tileObstructionField.selectedProperty(), boolProp(t, "obstruction"));
bind(tileNameField.textProperty(), stringProp(t, "name"));
TileEditor editor = Application.currentPlatform.tileEditor.newInstance();
editor.setEntity(t);
setCurrentTileEditor(editor);
} catch (NoSuchMethodException ex) {
Logger.getLogger(ApplicationUIController.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(ApplicationUIControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
super.setCurrentTile(t);
}
@Override
public void rebuildTileSelectors() {
tileSelector.getItems().clear();
tileSelector.getItems().addAll(Application.gameData.getTile());
tileSelector.getSelectionModel().select(getCurrentTile());
}
}

View File

@ -81,12 +81,12 @@ public class UIAction {
}
currentSaveFile = f;
GameData newData = JAXB.unmarshal(currentSaveFile, GameData.class);
Application.instance.controller.setCurrentMap(null);
Application.instance.controller.setCurrentTile(null);
Application.instance.controller.mapController.setCurrentMap(null);
Application.instance.controller.tileController.setCurrentTile(null);
TilesetUtils.clear();
Application.gameData = newData;
Application.instance.controller.rebuildTileSelectors();
Application.instance.controller.rebuildMapSelectors();
Application.instance.controller.mapController.rebuildMapSelectors();
break;
case Quit:
quit();
@ -201,10 +201,10 @@ public class UIAction {
public static Script createAndEditScript() {
Script script = new Script();
script.setName("New Script");
if (Application.instance.controller.currentMap.getScripts() == null) {
Application.instance.controller.currentMap.setScripts(new Map.Scripts());
if (Application.instance.controller.mapController.getCurrentMap().getScripts() == null) {
Application.instance.controller.mapController.getCurrentMap().setScripts(new Map.Scripts());
}
Application.instance.controller.currentMap.getScripts().getScript().add(script);
Application.instance.controller.mapController.getCurrentMap().getScripts().getScript().add(script);
return editScript(script);
}

View File

@ -6,190 +6,21 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="575.0" prefWidth="1000.0" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ApplicationUIControllerImpl">
<AnchorPane id="AnchorPane" prefHeight="575.0" prefWidth="1000.0" styleClass="outlawApp" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ApplicationUIControllerImpl">
<children>
<VBox prefHeight="500.0" prefWidth="800.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<MenuBar>
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" onAction="#onFileOpen" text="Open" />
<MenuItem mnemonicParsing="false" onAction="#onFileSave" text="Save" />
<MenuItem mnemonicParsing="false" onAction="#onFileSaveAs" text="Save As..." />
<MenuItem mnemonicParsing="false" onAction="#onFileQuit" text="Quit" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" onAction="#onEditSelect" text="Select" />
<MenuItem mnemonicParsing="false" onAction="#onEditCopy" text="Copy" />
<MenuItem mnemonicParsing="false" onAction="#onEditPaste" text="Paste" />
<Menu mnemonicParsing="false" text="Change Platform">
<items>
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformAppleSolid" text="Apple (solid)" />
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformAppleText" text="Apple (text-friendly)" />
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformAppleDHGRSolid" text="Apple (DHGR solid)" />
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformAppleDHGRText" text="Apple (DHGR text)" />
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformC64" text="C64" />
</items>
</Menu>
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" onAction="#onHelpAbout" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
<fx:include fx:id="menu" source="Menubar.fxml"/>
<TabPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="455.0" prefWidth="676.9998779296875" tabClosingPolicy="UNAVAILABLE" VBox.vgrow="ALWAYS">
<tabs>
<Tab onSelectionChanged="#tileTabActivated" text="Tiles">
<content>
<AnchorPane id="tilesTab" minHeight="0.0" minWidth="0.0" prefHeight="420.0000999999975" prefWidth="677.0">
<children>
<VBox prefHeight="420.0000999999975" prefWidth="677.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ToolBar prefWidth="686.0">
<items>
<Label text="Tile:" />
<ComboBox fx:id="tileSelector" minWidth="125.0" onAction="#onCurrentTileSelected">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Item 1" />
<String fx:value="Item 2" />
<String fx:value="Item 3" />
</FXCollections>
</items>
</ComboBox>
<Button mnemonicParsing="false" onAction="#onTileCreatePressed" text="Create new" />
<Button mnemonicParsing="false" onAction="#onTileExportPressed" text="Export" />
<Button mnemonicParsing="false" onAction="#onTileClonePressed" prefWidth="64.9998779296875" text="Clone" />
<Button mnemonicParsing="false" onAction="#onTileDeletePressed" text="Delete" />
<MenuButton mnemonicParsing="false" text="Tools">
<items>
<Menu fx:id="tilePatternMenu" mnemonicParsing="false" text="Pattern" />
<Menu mnemonicParsing="false" text="Draw mode">
<items>
<MenuItem mnemonicParsing="false" onAction="#tileBitMode" text="Bit Toggle" />
<MenuItem mnemonicParsing="false" onAction="#tileDraw1BitMode" text="1 bit-wide" />
<MenuItem mnemonicParsing="false" onAction="#tileDraw3BitMode" text="3 bit wide" />
</items>
</Menu>
<MenuItem mnemonicParsing="false" onAction="#tileShift" text="Shift..." />
</items>
</MenuButton>
</items>
</ToolBar>
<HBox prefHeight="387.0" prefWidth="677.0" VBox.vgrow="ALWAYS">
<children>
<AnchorPane id="imageDetailsPane" prefHeight="200.0" prefWidth="200.0">
<children>
<Label layoutX="5.0" layoutY="5.0" prefHeight="29.0" prefWidth="37.0" text="Name" />
<TextField id="" fx:id="tileNameField" layoutX="54.0" layoutY="5.0" prefWidth="147.0" />
<Label layoutX="5.0" layoutY="33.0" prefHeight="29.0" prefWidth="46.0" text="ID" />
<TextField fx:id="tileIdField" layoutX="54.0" layoutY="36.0" prefWidth="147.0" />
<Label layoutX="5.0" layoutY="72.0" text="Category" />
<TextField fx:id="tileCategoryField" layoutX="64.0" layoutY="67.0" prefHeight="26.0" prefWidth="137.0" />
<CheckBox fx:id="tileObstructionField" layoutX="6.0" layoutY="98.0" mnemonicParsing="false" text="Physical Obstruction" />
</children>
</AnchorPane>
<AnchorPane fx:id="tileEditorAnchorPane" prefHeight="387.0" prefWidth="477.0000999999975" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
<fx:include fx:id="tile" source="tileEditorTab.fxml"/>
</content>
</Tab>
<Tab onSelectionChanged="#mapTabActivated" text="Maps">
<content>
<AnchorPane id="mapsTab" minHeight="0.0" minWidth="0.0">
<children>
<VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ToolBar prefWidth="677.0">
<items>
<Label text="Map:" />
<ComboBox fx:id="mapSelect" minWidth="125.0" onAction="#onMapSelected">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Item 1" />
<String fx:value="Item 2" />
<String fx:value="Item 3" />
</FXCollections>
</items>
</ComboBox>
<Button mnemonicParsing="false" onAction="#onMapCreatePressed" text="Create new" />
<Button mnemonicParsing="false" onAction="#onMapClonePressed" text="Clone" />
<Button mnemonicParsing="false" onAction="#onMapExportPressed" text="Export" />
<Button mnemonicParsing="false" onAction="#onMapDeletePressed" text="Delete" />
<Button mnemonicParsing="false" onAction="#onMapPreviewPressed" text="Preview" />
<MenuButton mnemonicParsing="false" text="Tools">
<items>
<Menu fx:id="mapSelectTile" mnemonicParsing="false" text="Change tile" />
<Menu mnemonicParsing="false" text="Draw mode">
<items>
<MenuItem mnemonicParsing="false" onAction="#mapDraw1" text="Radius 1" />
<MenuItem mnemonicParsing="false" onAction="#mapDraw3" text="Radius 3" />
<MenuItem mnemonicParsing="false" onAction="#mapDraw5" text="Radius 5" />
<MenuItem mnemonicParsing="false" onAction="#mapDrawFilledRectMode" text="Filled Rectangle" />
</items>
</Menu>
<MenuItem mnemonicParsing="false" onAction="#mapTogglePanZoom" text="Toggle pan/zoom controls" />
</items>
</MenuButton>
</items>
</ToolBar>
<HBox prefHeight="389.0" prefWidth="677.0" VBox.vgrow="ALWAYS">
<children>
<AnchorPane prefHeight="200.0" prefWidth="200.0" HBox.hgrow="NEVER">
<children>
<Label text="Name" AnchorPane.leftAnchor="4.0" AnchorPane.topAnchor="14.0" />
<TextField id="mapNameFiled" fx:id="mapNameField" layoutX="53.0" layoutY="11.0" prefWidth="147.0" />
<TextField fx:id="mapWidthField" layoutX="53.0" layoutY="33.0" prefWidth="147.0" />
<Label layoutX="4.0" layoutY="36.0" text="Width" />
<TextField fx:id="mapHeightField" layoutX="53.0" layoutY="55.0" prefWidth="147.0" />
<Label layoutX="4.0" layoutY="58.0" text="Height" />
<CheckBox fx:id="mapWrapAround" contentDisplay="RIGHT" layoutX="4.0" layoutY="77.0" mnemonicParsing="false" text="Wrap at edges" />
<Separator layoutX="4.0" layoutY="101.0" prefWidth="189.0" />
<Label layoutX="4.0" layoutY="108.0" text="Scripts" />
<ScrollPane fitToHeight="true" fitToWidth="true" prefHeight="232.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="157.0">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0">
<children>
<ListView fx:id="mapScriptsList" editable="true" prefHeight="217.0" prefWidth="199.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
</ScrollPane>
<ToolBar layoutY="124.0" prefWidth="200.0">
<items>
<Button mnemonicParsing="false" onAction="#onMapScriptAddPressed" text="+" />
<Button mnemonicParsing="false" onAction="#onMapScriptDeletePressed" text="-" />
<Button mnemonicParsing="false" onAction="#onMapScriptClonePressed" text="Clone" />
</items>
</ToolBar>
</children>
</AnchorPane>
<AnchorPane fx:id="mapEditorAnchorPane" prefHeight="389.0" prefWidth="477.0000999999975" HBox.hgrow="SOMETIMES">
<children>
<Button alignment="TOP_CENTER" layoutX="265.0" mnemonicParsing="false" onAction="#scrollMapUp" styleClass="moveButton" text="Up" AnchorPane.topAnchor="5.0" />
<Button layoutY="185.0" mnemonicParsing="false" onAction="#scrollMapLeft" rotate="270.0" styleClass="moveButton" text="Left" AnchorPane.leftAnchor="-20.0" />
<Button layoutX="265.0" mnemonicParsing="false" onAction="#scrollMapDown" rotate="180.0" styleClass="moveButton" text="Down" AnchorPane.bottomAnchor="5.0" />
<Button layoutY="175.0" mnemonicParsing="false" onAction="#scrollMapRight" rotate="90.0" styleClass="moveButton" text="Right" AnchorPane.rightAnchor="-15.0" />
<Button mnemonicParsing="false" onAction="#mapZoomIn" styleClass="zoomInButton" text="+" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="5.0" />
<Button mnemonicParsing="false" onAction="#mapZoomOut" prefHeight="23.999908447265625" styleClass="zoomOutButton" text="-" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="30.0" />
</children>
</AnchorPane>
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
<fx:include fx:id="map" source="mapEditorTab.fxml"/>
</content>
</Tab>
<Tab onSelectionChanged="#imageTabActivated" text="Images">

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<MenuBar styleClass="menu" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ApplicationMenuControllerImpl">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" onAction="#onFileOpen" text="Open" />
<MenuItem mnemonicParsing="false" onAction="#onFileSave" text="Save" />
<MenuItem mnemonicParsing="false" onAction="#onFileSaveAs" text="Save As..." />
<MenuItem mnemonicParsing="false" onAction="#onFileQuit" text="Quit" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" onAction="#onEditSelect" text="Select" />
<MenuItem mnemonicParsing="false" onAction="#onEditCopy" text="Copy" />
<MenuItem mnemonicParsing="false" onAction="#onEditPaste" text="Paste" />
<Menu mnemonicParsing="false" text="Change Platform">
<items>
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformAppleSolid" text="Apple (solid)" />
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformAppleText" text="Apple (text-friendly)" />
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformAppleDHGRSolid" text="Apple (DHGR solid)" />
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformAppleDHGRText" text="Apple (DHGR text)" />
<MenuItem mnemonicParsing="false" onAction="#onChangePlatformC64" text="C64" />
</items>
</Menu>
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" onAction="#onHelpAbout" text="About" />
</items>
</Menu>
</menus>
</MenuBar>

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="mapsTab" minHeight="0.0" minWidth="0.0" prefHeight="420.0000999999975" prefWidth="677.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.MapEditorTabControllerImpl">
<children>
<VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ToolBar prefWidth="677.0">
<items>
<Label text="Map:" />
<ComboBox fx:id="mapSelect" minWidth="125.0" onAction="#onMapSelected"/>
<Button mnemonicParsing="false" onAction="#onMapCreatePressed" text="Create new" />
<Button mnemonicParsing="false" onAction="#onMapClonePressed" text="Clone" />
<Button mnemonicParsing="false" onAction="#onMapExportPressed" text="Export" />
<Button mnemonicParsing="false" onAction="#onMapDeletePressed" text="Delete" />
<Button mnemonicParsing="false" onAction="#onMapPreviewPressed" text="Preview" />
<MenuButton mnemonicParsing="false" text="Tools">
<items>
<Menu fx:id="mapSelectTile" mnemonicParsing="false" text="Change tile" />
<Menu mnemonicParsing="false" text="Draw mode">
<items>
<MenuItem mnemonicParsing="false" onAction="#mapDraw1" text="Radius 1" />
<MenuItem mnemonicParsing="false" onAction="#mapDraw3" text="Radius 3" />
<MenuItem mnemonicParsing="false" onAction="#mapDraw5" text="Radius 5" />
<MenuItem mnemonicParsing="false" onAction="#mapDrawFilledRectMode" text="Filled Rectangle" />
</items>
</Menu>
<MenuItem mnemonicParsing="false" onAction="#mapTogglePanZoom" text="Toggle pan/zoom controls" />
</items>
</MenuButton>
</items>
</ToolBar>
<HBox prefHeight="389.0" prefWidth="677.0" VBox.vgrow="ALWAYS">
<children>
<AnchorPane prefHeight="200.0" prefWidth="200.0" HBox.hgrow="NEVER">
<children>
<Label text="Name" AnchorPane.leftAnchor="4.0" AnchorPane.topAnchor="14.0" />
<TextField id="mapNameFiled" fx:id="mapNameField" layoutX="53.0" layoutY="11.0" prefWidth="147.0" />
<TextField fx:id="mapWidthField" layoutX="53.0" layoutY="33.0" prefWidth="147.0" />
<Label layoutX="4.0" layoutY="36.0" text="Width" />
<TextField fx:id="mapHeightField" layoutX="53.0" layoutY="55.0" prefWidth="147.0" />
<Label layoutX="4.0" layoutY="58.0" text="Height" />
<CheckBox fx:id="mapWrapAround" contentDisplay="RIGHT" layoutX="4.0" layoutY="77.0" mnemonicParsing="false" text="Wrap at edges" />
<Separator layoutX="4.0" layoutY="101.0" prefWidth="189.0" />
<Label layoutX="4.0" layoutY="108.0" text="Scripts" />
<ScrollPane fitToHeight="true" fitToWidth="true" prefHeight="232.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="157.0">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0">
<children>
<ListView fx:id="mapScriptsList" editable="true" prefHeight="217.0" prefWidth="199.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
</ScrollPane>
<ToolBar layoutY="124.0" prefWidth="200.0">
<items>
<Button mnemonicParsing="false" onAction="#onMapScriptAddPressed" text="+" />
<Button mnemonicParsing="false" onAction="#onMapScriptDeletePressed" text="-" />
<Button mnemonicParsing="false" onAction="#onMapScriptClonePressed" text="Clone" />
</items>
</ToolBar>
</children>
</AnchorPane>
<AnchorPane fx:id="mapEditorAnchorPane" prefHeight="389.0" prefWidth="477.0000999999975" HBox.hgrow="SOMETIMES">
<children>
<Button alignment="TOP_CENTER" layoutX="265.0" mnemonicParsing="false" onAction="#scrollMapUp" styleClass="moveButton" text="Up" AnchorPane.topAnchor="5.0" />
<Button layoutY="185.0" mnemonicParsing="false" onAction="#scrollMapLeft" rotate="270.0" styleClass="moveButton" text="Left" AnchorPane.leftAnchor="-20.0" />
<Button layoutX="265.0" mnemonicParsing="false" onAction="#scrollMapDown" rotate="180.0" styleClass="moveButton" text="Down" AnchorPane.bottomAnchor="5.0" />
<Button layoutY="175.0" mnemonicParsing="false" onAction="#scrollMapRight" rotate="90.0" styleClass="moveButton" text="Right" AnchorPane.rightAnchor="-15.0" />
<Button mnemonicParsing="false" onAction="#mapZoomIn" styleClass="zoomInButton" text="+" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="5.0" />
<Button mnemonicParsing="false" onAction="#mapZoomOut" prefHeight="23.999908447265625" styleClass="zoomOutButton" text="-" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="30.0" />
</children>
</AnchorPane>
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.collections.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="tilesTab" minHeight="0.0" minWidth="0.0" prefHeight="420.0000999999975" prefWidth="677.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.TileEditorTabControllerImpl">
<children>
<VBox prefHeight="420.0000999999975" prefWidth="677.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ToolBar prefWidth="686.0">
<items>
<Label text="Tile:" />
<ComboBox fx:id="tileSelector" minWidth="125.0" onAction="#onCurrentTileSelected"/>
<Button mnemonicParsing="false" onAction="#onTileCreatePressed" text="Create new" />
<Button mnemonicParsing="false" onAction="#onTileExportPressed" text="Export" />
<Button mnemonicParsing="false" onAction="#onTileClonePressed" prefWidth="64.9998779296875" text="Clone" />
<Button mnemonicParsing="false" onAction="#onTileDeletePressed" text="Delete" />
<MenuButton mnemonicParsing="false" text="Tools">
<items>
<Menu fx:id="tilePatternMenu" mnemonicParsing="false" text="Pattern" />
<Menu mnemonicParsing="false" text="Draw mode">
<items>
<MenuItem mnemonicParsing="false" onAction="#tileBitMode" text="Bit Toggle" />
<MenuItem mnemonicParsing="false" onAction="#tileDraw1BitMode" text="1 bit-wide" />
<MenuItem mnemonicParsing="false" onAction="#tileDraw3BitMode" text="3 bit wide" />
</items>
</Menu>
<MenuItem mnemonicParsing="false" onAction="#tileShift" text="Shift..." />
</items>
</MenuButton>
</items>
</ToolBar>
<HBox prefHeight="387.0" prefWidth="677.0" VBox.vgrow="ALWAYS">
<children>
<AnchorPane id="imageDetailsPane" prefHeight="200.0" prefWidth="200.0">
<children>
<Label layoutX="5.0" layoutY="5.0" prefHeight="29.0" prefWidth="37.0" text="Name" />
<TextField id="" fx:id="tileNameField" layoutX="54.0" layoutY="5.0" prefWidth="147.0" />
<Label layoutX="5.0" layoutY="33.0" prefHeight="29.0" prefWidth="46.0" text="ID" />
<TextField fx:id="tileIdField" layoutX="54.0" layoutY="36.0" prefWidth="147.0" />
<Label layoutX="5.0" layoutY="72.0" text="Category" />
<TextField fx:id="tileCategoryField" layoutX="64.0" layoutY="67.0" prefHeight="26.0" prefWidth="137.0" />
<CheckBox fx:id="tileObstructionField" layoutX="6.0" layoutY="98.0" mnemonicParsing="false" text="Physical Obstruction" />
</children>
</AnchorPane>
<AnchorPane fx:id="tileEditorAnchorPane" prefHeight="387.0" prefWidth="477.0000999999975" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>

View File

@ -11,7 +11,7 @@ All three systems were implemented using stack architecture. Pascal and Java we
##A New Approach
PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. The stack is purposely not split between low and high values so as to allow reading and writing addresses stored directly on the stack. The trade off is that the stack pointer has to be incremented and decremented by two for every push/pop operation. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision.
PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision.
The PLASMA low level operations are defined as:
@ -100,9 +100,15 @@ Hexadecimal constants are preceded with a $ to identify them as such.
###Constants, Variables and Functions
The source code of a PLASMA module first defines constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways.
The source code of a PLASMA module first defines imports, constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways.
```
;
; Import standard library functions.
;
import stdlib
predef putc, puts, getc, gets, cls, memcpy, memset, memclr
end
;
; Constants used for hardware and flags
;
@ -135,9 +141,9 @@ Strings are defined like Pascal strings, a length byte followed by the string ch
byte txtfile[64] = "UNTITLED"
```
Functions are defined after all constants, variables and data. Functions can be forward declared with a func type in the constant and variable declarations. Functions have optional parameters and always return a value. By using one of three function declarations (def, deft and defn) you can have the function loaded as interpreted bytecode, threaded calls into the interpreter, or natively compiled code. There are space and time tradeoffs between the three choices. Bytecode is the best choice for the majority of functions. It has decent performance and is extremely compact. Threaded code would be the choice for functions that are called often but are not leaf routines, i.e. they themselves call other functions. Native code is a good choice for small, leaf functions that are called often and need the highest performance. Simply altering the definition is all that is required to set the function code implementation. Functions can have their own variable declarations. However, unlike the global declarations, no data can be predeclared, only storage space. There is also a limit of 256 bytes of local storage. Each parameter takes two bytes of local storage, plus two bytes for the previous frame pointer. If a function has no parameters or local variables, no local frame will be created, improving performance. A function can specify a value to return. If no return value is specified, a default of 0 will be returned.
Functions are defined after all constants, variables and data. Functions can be forward declared with a *predef* type in the constant and variable declarations. Functions have optional parameters and always return a value. Functions can have their own variable declarations. However, unlike the global declarations, no data can be predeclared, only storage space. There is also a limit of 254 bytes of local storage. Each parameter takes two bytes of local storage, plus two bytes for the previous frame pointer. If a function has no parameters or local variables, no local frame will be created, improving performance. A function can specify a value to return. If no return value is specified, a default of 0 will be returned.
After functions are defined, the main code for the module follows. There is no option to declare how the main code is loaded - it is always bytecode. The last statement in the module must be done, or else a compile error is issued.
After functions are defined, the main code for the module follows. The main code will be executed as soon as the module is loaded. For library modules, this is a good place to do any runtime initialization, before any of the exported functions are called. The last statement in the module must be done, or else a compile error is issued.
There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a . character denotes a byte type, a : character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the . or : and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers. Multiple brackets can follow the . or : type identifier, but all but the last index will be treated as a pointer to an array.
@ -312,16 +318,16 @@ Lastly, the repeat/until statement will continue looping as long as the until ex
PLASMA includes a very minimal runtime that nevertheless provides a great deal of functionality to the system. Two system calls are provided to access native 6502 routines (usually in ROM) and ProDOS.
call6502(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte structure containing the A,X,Y and STATUS register results.
romcall(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte structure containing the A,X,Y and STATUS register results.
```
const xreg = 1
const getlin = $FD6A
numchars = (call6502(0, 0, 0, 0, getlin)).xreg ; return char count in X reg
numchars = (romcall(0, 0, 0, 0, getlin)).xreg ; return char count in X reg
```
prodos(cmd, params) calls ProDOS, returning the status value.
syscall(cmd, params) calls ProDOS, returning the status value.
```
def read(refnum, buff, len)
@ -331,31 +337,38 @@ prodos(cmd, params) calls ProDOS, returning the status value.
params.1 = refnum
params:2 = buff
params:4 = len
perr = prodos($CA, @params)
perr = syscall($CA, @params)
return params:6
end
```
cout(char), prstr(string), prstrz(stringz) are handy utility routines for printing to the standard Apple II COUT routine.
putc(char), puts(string), home, gotoxy(x,y), getc() and gets() are other handy utility routines for interacting with the console.
```
cout('.')
putc('.')
byte okstr[] = "OK"
prstr(@okstr)
puts(@okstr)
```
memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(dstaddr, srcaddr, len) will copy memory from one address to another, taking care to copy in the proper direction.
memset(addr, len, val) will fill memory with a 16 bit value. memcpy(dstaddr, srcaddr, len) will copy memory from one address to another, taking care to copy in the proper direction.
```
byte nullstr[] = ""
memset(@nullstr, strlinbuf, maxfill * 2) ; fill line buff with pointer to null string
memset(strlinbuf, maxfill * 2, @nullstr) ; fill line buff with pointer to null string
memcpy(scrnptr, strptr + ofst + 1, numchars)
```
##Implementation Details
###The Original PLASMA
The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density.
The VM was constructed such that code generation could ouput native 6502 code, threaded code into the opcode functions, or interpreted bytecodes. This gave a level of control over speed vs memory.
###The Lawless Legends PLASMA
This version of PLASMA has dispensed with the native/threaded/bytecode code generation from the original version to focus on code density and the ability to interpret bytecode from AUX memory, should it be available. By focussing on the bytecode interpreter, certain optimizations were implemented that weren't posssible when allowing for threaded/native code. With theses optimizations, the interpreted bytecode is about the same performance level as the threaded code, with the benefit of code compaction.
Dynamically loadable modules, a backward compatible extension to the .REL format introduced by EDASM, is the new, main feature for this version of PLASMA. A game like Lawless Legends will push the capabilities of the Apple II well beyond anything before it. A powerful OS + language + VM environment is required to achieve the goals set out.
## References
B Programming Language User Manual http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html

File diff suppressed because it is too large Load Diff

View File

@ -70,12 +70,12 @@ int idglobal_lookup(char *name, int len)
}
int idconst_add(char *name, int len, int value)
{
char c = name[len];
if (consts > 1024)
{
printf("Constant count overflow\n");
return (0);
}
char c = name[len];
name[len] = '\0';
emit_idconst(name, value);
name[len] = c;
@ -89,12 +89,12 @@ int idconst_add(char *name, int len, int value)
}
int idlocal_add(char *name, int len, int type, int size)
{
char c = name[len];
if (localsize > 255)
{
printf("Local variable size overflow\n");
return (0);
}
char c = name[len];
name[len] = '\0';
emit_idlocal(name, localsize);
name[len] = c;
@ -110,12 +110,12 @@ int idlocal_add(char *name, int len, int type, int size)
}
int idglobal_add(char *name, int len, int type, int size)
{
char c = name[len];
if (globals > 1024)
{
printf("Global variable count overflow\n");
return (0);
}
char c = name[len];
name[len] = '\0';
name[len] = c;
idglobal_name[globals][0] = len;

View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "tokens.h"
#include "symbols.h"

View File

@ -49,8 +49,8 @@ TESTLIB: testlib.pla $(PLVM) $(PLASM)
test: test.pla TESTLIB $(PLVM) $(PLASM)
./$(PLASM) -AM < test.pla > test.a
acme --setpc 4096 -o TEST.BIN test.a
./$(PLVM) TEST.BIN MAIN
acme --setpc 4096 -o TEST.REL test.a
./$(PLVM) TEST.REL MAIN
debug: test.pla TESTLIB $(PLVM) $(PLASM)
./$(PLASM) -AM < test.pla > test.a

View File

@ -1,7 +1,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
typedef unsigned char code;
typedef unsigned char byte;
@ -99,7 +101,7 @@ uword mark_heap(void)
{
return heap;
}
int release_heap(uword newheap)
uword release_heap(uword newheap)
{
heap = newheap;
return fp - heap;
@ -146,13 +148,14 @@ uword lookup_tbl(byte *dci, byte *tbl)
}
return 0;
}
int add_tbl(byte *dci, int val, byte **last)
uword add_tbl(byte *dci, int val, byte **last)
{
while (*dci & 0x80)
*(*last)++ = *dci++;
*(*last)++ = *dci++;
*(*last)++ = val;
*(*last)++ = val >> 8;
return 0;
}
/*
@ -167,7 +170,7 @@ uword lookup_sym(byte *sym)
{
return lookup_tbl(sym, symtbl);
}
int add_sym(byte *sym, int addr)
uword add_sym(byte *sym, int addr)
{
return add_tbl(sym, addr, &lastsym);
}
@ -184,18 +187,18 @@ uword lookup_mod(byte *mod)
{
return lookup_tbl(mod, modtbl);
}
int add_mod(byte *mod, int addr)
uword add_mod(byte *mod, int addr)
{
return add_tbl(mod, addr, &lastmod);
}
defcall_add(int bank, int addr)
uword defcall_add(int bank, int addr)
{
mem_data[lastdef] = bank ? 2 : 1;
mem_data[lastdef + 1] = addr;
mem_data[lastdef + 2] = addr >> 8;
return lastdef++;
}
int def_lookup(byte *cdd, int defaddr)
uword def_lookup(byte *cdd, int defaddr)
{
int i, calldef = 0;
for (i = 0; cdd[i * 4] == 0x02; i++)
@ -208,7 +211,7 @@ int def_lookup(byte *cdd, int defaddr)
}
return calldef;
}
int extern_lookup(byte *esd, int index)
uword extern_lookup(byte *esd, int index)
{
byte *sym;
char string[32];
@ -225,16 +228,18 @@ int extern_lookup(byte *esd, int index)
}
int load_mod(byte *mod)
{
unsigned int len, size, end, magic, bytecode, fixup, addr, sysflags, defcnt = 0, init = 0, modaddr = mark_heap();
uword len, size, end, magic, bytecode, fixup, addr, sysflags, defcnt = 0, init = 0, modaddr = mark_heap();
byte *moddep, *rld, *esd, *cdd, *sym;
byte header[128];
int fd;
char filename[32], string[17];
dcitos(mod, filename);
printf("Load module %s\n", filename);
int fd = open(filename, O_RDONLY, 0);
fd = open(filename, O_RDONLY, 0);
if ((fd > 0) && (len = read(fd, header, 128)) > 0)
{
modaddr = mark_heap();
magic = header[2] | (header[3] << 8);
if (magic == 0xDA7E)
{
@ -342,7 +347,6 @@ int load_mod(byte *mod)
if (show_state) printf("BYTE");
mem_data[addr] = fixup;
}
}
if (show_state) printf("@$%04X\n", addr);
rld += 4;
@ -406,7 +410,8 @@ void call(uword pc)
interp(mem_data + (mem_data[pc] + (mem_data[pc + 1] << 8)));
break;
case 3: // LIBRARY STDLIB::VIEWPORT
printf("Set Window %d, %d, %d, %d/n", POP, POP, POP, POP);
printf("Set Viewport %d, %d, %d, %d\n", esp[3], esp[2], esp[1], esp[0]);
esp += 4;
PUSH(0);
break;
case 4: // LIBRARY STDLIB::PUTC
@ -430,7 +435,7 @@ void call(uword pc)
break;
case 6: // LIBRARY STDLIB::PUTSZ
s = POP;
while (c = mem_data[s++])
while ((c = mem_data[s++]))
{
if (c == 0x0D)
c = '\n';
@ -443,9 +448,8 @@ void call(uword pc)
break;
case 8: // LIBRARY STDLIB::GETS
gets(sz);
i = 0;
while (sz[i])
mem_data[0x200 + i++] = sz[i];
for (i = 0; sz[i]; i++)
mem_data[0x200 + i] = sz[i];
mem_data[0x200 + i] = 0;
mem_data[0x1FF] = i;
PUSH(i);
@ -462,6 +466,11 @@ void call(uword pc)
fflush(stdout);
PUSH(0);
break;
case 11: // LIBRARY STDLIB::PUTNL
putchar('\n');
fflush(stdout);
PUSH(0);
break;
default:
printf("Bad call code\n");
}
@ -847,7 +856,9 @@ char *stdlib_exp[] = {
"GETC",
"GETS",
"CLS",
"GOTOXY"
"GOTOXY",
"PUTNL",
0
};
byte stdlib[] = {
@ -873,7 +884,7 @@ int main(int argc, char **argv)
*/
stodci("STDLIB", dci);
add_mod(dci, 0xFFFF);
for (i = 0; i < 8; i++)
for (i = 0; stdlib_exp[i]; i++)
{
mem_data[i] = i + 3;
stodci(stdlib_exp[i], dci);

View File

@ -4,13 +4,20 @@
;*
;**********************************************************
;*
;* MONITOR SPECIAL LOCATIONS AND PRODOS MLI
;* MONITOR SPECIAL LOCATIONS
;*
CSWL = $36
CSWH = $37
PROMPT = $33
;*
;* PRODOS
;*
PRODOS = $BF00
MACHID = $BF98
DEVCNT = $BF31 ; GLOBAL PAGE DEVICE COUNT
DEVLST = $BF32 ; GLOBAL PAGE DEVICE LIST
MACHID = $BF98 ; GLOBAL PAGE MACHINE ID BYTE
RAMSLOT = $BF26 ; SLOT 3, DRIVE 2 IS /RAM'S DRIVER VECTOR
NODEV = $BF10
;*
;* HARDWARE ADDRESSES
;*
@ -50,6 +57,39 @@ ESP = DST+2
LDX #$FF
TXS
;*
;* DISCONNECT /RAM
;*
SEI ; DISABLE /RAM
LDA MACHID
AND #$30
CMP #$30
BNE RAMDONE
LDA RAMSLOT
CMP NODEV
BNE RAMCONT
LDA RAMSLOT+1
CMP NODEV+1
BEQ RAMDONE
RAMCONT LDY DEVCNT
RAMLOOP LDA DEVLST,Y
AND #$F3
CMP #$B3
BEQ GETLOOP
DEY
BPL RAMLOOP
BMI RAMDONE
GETLOOP LDA DEVLST+1,Y
STA DEVLST,Y
BEQ RAMEXIT
INY
BNE GETLOOP
RAMEXIT LDA NODEV
STA RAMSLOT
LDA NODEV+1
STA RAMSLOT+1
DEC DEVCNT
RAMDONE CLI
;*
;* INSTALL PAGE 3 VECTORS
;*
LDY #$20
@ -152,17 +192,6 @@ PAGE3 = *
VMCORE = *
!PSEUDOPC $D000 {
;*
;* OPCODE TABLE
;*
OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E
!WORD NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E
!WORD LNOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E
!WORD DROP,DUP,PUSH,PULL,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E
!WORD ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E
!WORD BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,NEXTOP ; 50 52 54 56 58 5A 5C 5E
!WORD LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E
!WORD SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E
;*
;* OPXCODE TABLE
;*
OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0A 0C 0E
@ -174,6 +203,17 @@ OPXTBL !WORD ZEROX,ADDX,SUBX,MULX,DIVX,MODX,INCRX,DECRX ; 00 02 04 06 08 0
!WORD LBX,LWX,LLBX,LLWX,LABX,LAWX,DLBX,DLWX ; 60 62 64 66 68 6A 6C 6E
!WORD SBX,SWX,SLBX,SLWX,SABX,SAWX,DABX,DAWX ; 70 72 74 76 78 7A 7C 7E
;*
;* OPCODE TABLE
;*
OPTBL !WORD ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E
!WORD NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E
!WORD LNOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E
!WORD DROP,DUP,PUSH,PULL,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E
!WORD ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E
!WORD BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,NEXTOP ; 50 52 54 56 58 5A 5C 5E
!WORD LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E
!WORD SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E
;*
;* 'BYE' COMMAND PROCESSING
;*
!PSEUDOPC $1000 {
@ -258,7 +298,6 @@ IINTRP STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD
LDA (TMP),Y
STA IPL
DEY
LDY #$00
BEQ FETCHOP
IINTRPX STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD
STA LCRWEN+LCBNK2
@ -273,9 +312,21 @@ IINTRPX STA LCRWEN+LCBNK2 ; WRITE ENABLE LANGUAGE CARD
LDA (TMP),Y
STA IPL
DEY
LDY #$00
BEQ FETCHOPX
;*
;* INTERP BYTECODE IN AUX MEM
;*
NEXTOPHX INC IPH
BNE FETCHOPX
DROPX INX
NEXTOPX INY
BEQ NEXTOPHX
FETCHOPX ;SEI
STA ALTRDON
LDA (IP),Y
STA *+4
JMP (OPXTBL)
;*
;* INTERP BYTECODE IN MAIN MEM
;*
NEXTOPH INC IPH
@ -284,24 +335,10 @@ DROP INX
NEXTOP INY
BEQ NEXTOPH
FETCHOP LDA (IP),Y
ORA #$80 ; SELECT OP OPCODES
STA *+4
JMP (OPTBL)
;*
;* INTERP BYTECODE IN AUX MEM
;*
NEXTOPHX INC IPH
BNE FETCHOPX
DROPX INX
NEXTOPX CLI
INY
BEQ NEXTOPHX
FETCHOPX SEI
STA ALTRDON
LDA (IP),Y
ORA #$80 ; SELECT OPX OPCODES
STA *+4
JMP (OPXTBL)
;*
;* INDIRECT JUMP TO (TMP)
;*
JMPTMP JMP (TMP)
@ -1033,7 +1070,7 @@ LLBX +INC_IP
LDA #$00
STA ESTKH,X
LDY IPY
JMP NEXTOP
JMP NEXTOPX
LLWX +INC_IP
LDA (IP),Y
STY IPY
@ -1046,7 +1083,7 @@ LLWX +INC_IP
LDA (IFP),Y
STA ESTKH,X
LDY IPY
JMP NEXTOP
JMP NEXTOPX
;*
;* LOAD VALUE FROM ABSOLUTE ADDRESS
;*
@ -1756,7 +1793,7 @@ CALLX +INC_IP
PHA
TYA
PHA
CLI
;CLI
JSR JMPTMP
PLA
TAY
@ -1804,7 +1841,7 @@ ICALX LDA ESTKL,X
TYA
PHA
STA ALTRDOFF
CLI
;CLI
JSR JMPTMP
PLA
TAY
@ -1864,7 +1901,6 @@ ENTERX +INC_IP
LDA (IP),Y
STA NPARMS
STY IPY
STA ALTRDOFF
LDA IFPL
PHA
SEC
@ -1874,6 +1910,7 @@ ENTERX +INC_IP
PHA
SBC #$00
STA IFPH
STA ALTRDOFF
LDY #$01
PLA
STA (IFP),Y
@ -1918,10 +1955,10 @@ LEAVEX STA ALTRDOFF
STA IFPL
PLA
STA IFPH
CLI
;CLI
RTS
RETX STA ALTRDOFF
CLI
;CLI
RTS
VMEND = *
}

View File

@ -2,7 +2,7 @@
; Declare all imported modules and their data/functions.
;
import stdlib
predef cls, gotoxy, puts, putc
predef cls, gotoxy, viewport, puts, putc, putnl, getc
end
import testlib
@ -15,7 +15,7 @@ predef main
;
; Declare all global variables for this module.
;
byte hello[] = "Hello, world.\n\n"
byte hello[] = "Hello, world.\n"
word defptr = main
;
; Define functions.
@ -31,14 +31,16 @@ def nums
word i
for i = -10 to 10
puti(i)
putc('\n')
putnl
next
end
export def main
cls
nums
viewport(12, 12, 16, 8)
ascii
viewport(0, 0, 40, 24)
gotoxy(15,5)
puts(@hello)
end