package io.github.jgkamat.ViPaint.VimBar; import io.github.jgkamat.ViPaint.Canvas.CursorCanvas; import io.github.jgkamat.ViPaint.Canvas.PaintCanvas; import io.github.jgkamat.ViPaint.Handlers.SetVariable; import io.github.jgkamat.ViPaint.Handlers.SettingManager; import io.github.jgkamat.ViPaint.Tools.KeyTool; import io.github.jgkamat.ViPaint.ViPaint; import javafx.embed.swing.SwingFXUtils; import javafx.geometry.VPos; import javafx.scene.canvas.GraphicsContext; import javafx.scene.image.Image; import javafx.scene.image.WritableImage; import javafx.scene.paint.Color; import javafx.scene.text.TextAlignment; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.nio.file.Files; import java.nio.file.FileSystems; import java.nio.file.Path; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.function.Function; /** * A class to store, and parse vim bar commands. * * The function takes in a CommandManager Object, * which will provide needed things that could possibly be changed. */ public class CommandManager { private Map<String, Function<PropertyHolder, String>> commandList; private CursorCanvas textOut; private VimBar vimBar; private ArrayList<String> history; private int historyPointer; private ViPaint layout; private PaintCanvas drawCanvas; public static final String introText = "ViP - ViPaint\n\nVersion " + ViPaint.version + "\nby Jay Kamat" + "\nViPaint is open source and freely distributable" + "\n\nHelp poor children in CS1100!\n" + "Type :help cs1100<Enter> to help!" + "\n\ntype :q<Enter> to quit" + "\ntype :help<Enter> for help"; /** * A class to handle all commands * @param textOut The canvas where any help will be printed to * @param vimBar The vimbar, in case we need to update its status */ public CommandManager(CursorCanvas textOut, PaintCanvas drawCanvas, ViPaint layout, VimBar vimBar) { commandList = new HashMap<>(); this.layout = layout; this.textOut = textOut; this.vimBar = vimBar; this.drawCanvas = drawCanvas; addDefaultCommands(); history = new ArrayList<>(); } /** * Adds normal commands! Dont forget to run this! */ private void addDefaultCommands() { //command not found function <most important> commandList.put("cnf", (PropertyHolder holder) -> { return "Command \'" + holder.args[0] + "\' not found!"; }); // quit functions commandList.put("quit", (PropertyHolder holder) -> { System.exit(0); // shouldn't happen but lets go for it. return "--NORMAL--"; }); commandList.put("q", commandList.get("quit")); //help function commandList.put("help", (PropertyHolder holder) -> { if (holder.args.length == 1) { holder.printToGraphics("Welcome to ViPaint!\n\n" + "Vi/ViM knowlege is helpful but not required for ViPaint " + "usage!\n\n" + "ViPaint has a MODAL interface. This means that to " + "switch to\n" + "another command, you need to press ESC to getModeTool back to " + "normal mode!\n\n" + "Check which mode you are in in the lower left\n" + "Here is a short list of currently supported modes:\n\n" + "ESC - Normal Mode (Movement with H,J,K,L)\n" + "I - Insert Mode. A pen tool.\n" + "D - Delete Mode. An eraser.\n" + "R - Rectangle Tool. Move around, then press ESC to " + "confirm rectangle.\n" + "-/+ - Change size of cursor. Useful!\n" + "n - Line tool. Move around, press ESC to confirm!\n" + ":q to quit. Like I said earlier!" + "\n\nHelp is needed to add more tools! " + "(and ex commands)\n " + "Please submit a pull request!"); } else if (holder.args[1].equalsIgnoreCase("cs1100")) { holder.printToGraphics("The people in CS1100 are in distress\n\n" + "If you are a TA or anyone else in authority you should\n" + "probably go and do something about it!\n\n" + "Go and take action at www.zombo.com"); } else { Optional<? extends KeyTool> toHelp = holder.layout.getKeyToolClasses().stream() .filter((KeyTool tool) -> tool.getName().equalsIgnoreCase(holder.args[1])) .findFirst(); if (toHelp.isPresent()) { holder.printToGraphics(toHelp.get().getHelp()); return ""; } return "Help page \'" + holder.args[1] + "\' not found!"; } return ""; }); // ??? commandList.put("moo", (PropertyHolder holder) -> { StringBuilder b = new StringBuilder(); for(int i = 0; i < 1000; i++) { for(int j = 0; j < 1000; j++) { b.append("Uh Oh. "); } b.append('\n'); } holder.printToGraphics(b.toString()); return "Moo."; }); //intro command commandList.put("intro", (PropertyHolder holder) -> { holder.printToGraphics(introText); return ""; }); PropertyHolder dummyHolder = new PropertyHolder(null, layout, textOut, drawCanvas, vimBar); // set command SetVariable graphics = new SetVariable(false, dummyHolder, (holder) -> {holder.layout.toggleButtons(true); return true;}, (holder) -> {holder.layout.toggleButtons(false); return true;}); SettingManager.put("graphical", graphics); SettingManager.put("g", graphics); commandList.put("set", (PropertyHolder holder) -> { if (holder.args.length <= 1) { return "No argument specified!"; } String str = holder.args[1]; if (str.indexOf("no") == 0) { str = str.substring(2); } Object arg1 = SettingManager.get(str); if (arg1 == null || !(arg1 instanceof SetVariable)) { return "Bool value \'" + holder.args[1] + "\' not found!"; } SetVariable arg = (SetVariable) arg1; if (holder.args[1].indexOf("no") != 0) { arg.set(); } else { arg.unSet(); } return ""; }); commandList.put("write", (PropertyHolder holder) -> { if (holder.args.length < 2 || holder.args[1].equals("")) { return "Incorrect Argument Specified!"; } File file = new File(holder.args[1]); try { WritableImage writableImage = new WritableImage((int) Math.round(holder.drawCanvas.getWidth()), (int) Math.round(holder.drawCanvas.getHeight())); holder.drawCanvas.snapshot(null, writableImage); RenderedImage renderedImage = SwingFXUtils.fromFXImage(writableImage, null); ImageIO.write(renderedImage, "png", file); } catch (IOException ex) { // System.out.println("FILE WRITE ERROR!"); return "File writing failed!"; } return ""; }); commandList.put("w", (holder) -> commandList.get("write").apply(holder)); commandList.put("clear", (holder) -> { holder.drawCanvas.getGraphicsContext2D().clearRect(0, 0, Short.MAX_VALUE, Short.MAX_VALUE); return ""; }); commandList.put("cls", (holder) -> commandList.get("clear").apply(holder)); commandList.put("open", (PropertyHolder holder) -> { if (holder.args.length < 2 || holder.args[1].equals("")) { return "Incorrect Argument Specified!"; } File file = new File(holder.args[1]); try { // other text files can go in here if (file.getName().matches(".*\\.(raw|txt|java|c|cpp|py)$")) { holder.drawCanvas.clear(); holder.textOut.clear(); double width = RawConverter.getWidth(file); width *= (int) SettingManager.get("rawthickness"); // Assume raw images are square holder.layout.setSize(width, width); RawConverter.writeToCanvas(holder.drawCanvas, file); return "Opened \'" + holder.args[1] + "\' as a raw image"; } BufferedImage img = ImageIO.read(file); if (img == null) { return "File '" + holder.args[1] + "' not supported!"; } Image toCanvas = SwingFXUtils.toFXImage(img, null); if (toCanvas.isError()) { return "File '" + holder.args[1] + "' not found!"; } holder.drawCanvas.clear(); holder.textOut.clear(); holder.layout.setSize(toCanvas.getRequestedWidth(), toCanvas.getRequestedHeight()); holder.drawCanvas.getGraphicsContext2D() .drawImage(toCanvas, 0, 0, toCanvas.getRequestedWidth(), toCanvas.getRequestedHeight()); } catch (IOException ex) { ex.printStackTrace(); return "File \'" + holder.args[1] + "\' not found!"; } return ""; }); commandList.put("o", (holder) -> commandList.get("open").apply(holder)); commandList.put("let", (PropertyHolder holder) -> { if (holder.args.length < 2 || holder.args[1].equals("")) { return "Incorrect Argument Specified!"; } Object value = SettingManager.mappings.get(holder.args[1]); if (value == null) { return "Setting '" + holder.args[1] + "' not found!"; } if (value instanceof Integer) { // matches an int if (holder.args[2].matches("-?\\d+")) { SettingManager.mappings.put(holder.args[1], Integer.parseInt(holder.args[2])); return "Setting changed!"; } else { return "Setting '" + holder.args[1] + "' is incorrect format!"; } } else if (value instanceof Color) { // matches a color try { SettingManager.mappings.put(holder.args[1], Color.valueOf(holder.args[2].toUpperCase())); // nasty way of changing color. // TODO change to a more elegant option if (textOut != null) { textOut.getGraphicsContext2D().setFill((Color) SettingManager.mappings.get("color")); textOut.getLowerWindow().getGraphicsContext2D() .setFill((Color) SettingManager.mappings.get("color")); textOut.getLowerWindow().getLowerWindow().getGraphicsContext2D() .setFill((Color) SettingManager.mappings.get("color")); textOut.getGraphicsContext2D().setStroke((Color) SettingManager.mappings.get("color")); textOut.getLowerWindow().getGraphicsContext2D() .setStroke((Color) SettingManager.mappings.get("color")); textOut.getLowerWindow().getLowerWindow().getGraphicsContext2D() .setStroke((Color) SettingManager.mappings.get("color")); } return "Color changed to '" + holder.args[2] + "'"; } catch (IllegalArgumentException e) { return "Color '" + holder.args[2] + "' not found!"; } } return "Unsupported Operation"; // plz implement me }); commandList.put("source", (PropertyHolder holder) -> { if (holder.args.length < 1 || holder.args[1].equals("")) { return "Incorrect Argument Specified!"; } String rawpath = holder.args[1]; // Make it easy to source ~/.viprc if (rawpath.indexOf("~") == 0) { rawpath = System.getProperty("user.home") + rawpath.substring(1); } Path path = FileSystems.getDefault().getPath(rawpath); try { Files.lines(path).forEach((toEval) -> { if (!toEval.equals("")) { parseCommand(toEval); } }); } catch (IOException e) { return "File '" + rawpath + "' was not found!"; } // The file was sourced correctly. Clear things. return ""; }); } /** * Parses a command! * @param commandName The name of the command to run */ public void parseCommand(String commandName) { history.add(commandName); restartHistory(); // Deal with comments int commentLoc = commandName.indexOf('"'); if (commentLoc >= 0) { commandName = commandName.substring(0, commentLoc); } if (commandName.equals("")) { return; } commandName = commandName.trim(); String[] args = commandName.split("[\\s=]+"); Function<PropertyHolder, String> toRun = commandList.get(args[0]); if(toRun == null) { toRun = commandList.get("cnf"); } if (vimBar != null) { vimBar.setText(toRun.apply(new PropertyHolder(args, layout, textOut, drawCanvas, vimBar))); } else { toRun.apply(new PropertyHolder(args, layout, textOut, drawCanvas, vimBar)); } } /** * Gets the previous element of history * @return previous element */ public String getPrevious() { if(historyPointer > 0) { return history.get(--historyPointer); } else if(history.size() > 0) { return history.get(historyPointer); } else { return ""; } } /** * Gets the next element of history * @return next element */ public String getNext() { if(historyPointer < history.size() - 1) { return history.get(++historyPointer); } else { return ""; } } /** * This method restarts the history to the latest point! */ private void restartHistory() { historyPointer = history.size(); } /** * A class that is passed around to command functions so they can use it! */ public class PropertyHolder { public CursorCanvas textOut; public GraphicsContext gTextOut; public String[] args; public VimBar vimBar; public ViPaint layout; public PaintCanvas drawCanvas; public PropertyHolder(String[] args, ViPaint layout, CursorCanvas textOut, PaintCanvas drawCanvas, VimBar vimBar) { this.args = args; this.textOut = textOut; if (this.textOut != null) this.gTextOut = this.textOut.getGraphicsContext2D(); this.vimBar = vimBar; this.layout = layout; this.drawCanvas = drawCanvas; } public void printToGraphics(String toPrint) { if (this.textOut == null) { System.err.println("Could not display to graphics, as null was supplied"); return; } gTextOut.clearRect(0, 0, Short.MAX_VALUE, Short.MAX_VALUE); gTextOut.setTextAlign(TextAlignment.CENTER); gTextOut.setTextBaseline(VPos.CENTER); gTextOut.fillText((toPrint), Math.round(textOut.getWidth() / 2), Math.round(textOut.getHeight() / 2)); textOut.setHelpOn(); } } }