Merge branch 'subtree'
[fanfix.git] / src / jexer / TEditorWindow.java
index 9f1ae67aeb8eec6151ef79cca8ba861e3a0b8ef4..a28376ba3a18e8fcdfd75a300a32c180c2946385 100644 (file)
@@ -3,7 +3,7 @@
  *
  * The MIT License (MIT)
  *
- * Copyright (C) 2017 Kevin Lamonte
+ * Copyright (C) 2019 Kevin Lamonte
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -44,8 +44,10 @@ import jexer.bits.CellAttributes;
 import jexer.bits.GraphicsChars;
 import jexer.event.TCommandEvent;
 import jexer.event.TKeypressEvent;
+import jexer.event.TMenuEvent;
 import jexer.event.TMouseEvent;
 import jexer.event.TResizeEvent;
+import jexer.menu.TMenu;
 import static jexer.TCommand.*;
 import static jexer.TKeypress.*;
 
@@ -59,6 +61,10 @@ public class TEditorWindow extends TScrollableWindow {
      */
     private static final ResourceBundle i18n = ResourceBundle.getBundle(TEditorWindow.class.getName());
 
+    // ------------------------------------------------------------------------
+    // Variables --------------------------------------------------------------
+    // ------------------------------------------------------------------------
+
     /**
      * Hang onto my TEditor so I can resize it with the window.
      */
@@ -70,28 +76,19 @@ public class TEditorWindow extends TScrollableWindow {
     private String filename = "";
 
     /**
-     * Setup other fields after the editor is created.
+     * If true, hide the mouse after typing a keystroke.
      */
-    private void setupAfterEditor() {
-        hScroller = new THScroller(this, 17, getHeight() - 2, getWidth() - 20);
-        vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
-        setMinimumWindowWidth(25);
-        setMinimumWindowHeight(10);
-        setTopValue(1);
-        setBottomValue(editField.getMaximumRowNumber());
-        setLeftValue(1);
-        setRightValue(editField.getMaximumColumnNumber());
+    private boolean hideMouseWhenTyping = true;
 
-        statusBar = newStatusBar(i18n.getString("statusBar"));
-        statusBar.addShortcutKeypress(kbF1, cmHelp,
-            i18n.getString("statusBarHelp"));
-        statusBar.addShortcutKeypress(kbF2, cmSave,
-            i18n.getString("statusBarSave"));
-        statusBar.addShortcutKeypress(kbF3, cmOpen,
-            i18n.getString("statusBarOpen"));
-        statusBar.addShortcutKeypress(kbF10, cmMenu,
-            i18n.getString("statusBarMenu"));
-    }
+    /**
+     * If true, the mouse should not be displayed because a keystroke was
+     * typed.
+     */
+    private boolean typingHidMouse = false;
+
+    // ------------------------------------------------------------------------
+    // Constructors -----------------------------------------------------------
+    // ------------------------------------------------------------------------
 
     /**
      * Public constructor sets window title.
@@ -102,7 +99,7 @@ public class TEditorWindow extends TScrollableWindow {
     public TEditorWindow(final TApplication parent, final String title) {
 
         super(parent, title, 0, 0, parent.getScreen().getWidth(),
-            parent.getScreen().getHeight() - 2, RESIZABLE);
+            parent.getDesktopBottom() - parent.getDesktopTop(), RESIZABLE);
 
         editField = addEditor("", 0, 0, getWidth() - 2, getHeight() - 2);
         setupAfterEditor();
@@ -119,7 +116,7 @@ public class TEditorWindow extends TScrollableWindow {
         final String contents) {
 
         super(parent, title, 0, 0, parent.getScreen().getWidth(),
-            parent.getScreen().getHeight() - 2, RESIZABLE);
+            parent.getDesktopBottom() - parent.getDesktopTop(), RESIZABLE);
 
         filename = title;
         editField = addEditor(contents, 0, 0, getWidth() - 2, getHeight() - 2);
@@ -137,7 +134,7 @@ public class TEditorWindow extends TScrollableWindow {
         final File file) throws IOException {
 
         super(parent, file.getName(), 0, 0, parent.getScreen().getWidth(),
-            parent.getScreen().getHeight() - 2, RESIZABLE);
+            parent.getDesktopBottom() - parent.getDesktopTop(), RESIZABLE);
 
         filename = file.getName();
         String contents = readFileData(file);
@@ -154,76 +151,28 @@ public class TEditorWindow extends TScrollableWindow {
         this(parent, i18n.getString("newTextDocument"));
     }
 
-    /**
-     * Read file data into a string.
-     *
-     * @param file the file to open
-     * @return the file contents
-     * @throws IOException if a java.io operation throws
-     */
-    private String readFileData(final File file) throws IOException {
-        StringBuilder fileContents = new StringBuilder();
-        Scanner scanner = new Scanner(file);
-        String EOL = System.getProperty("line.separator");
-
-        try {
-            while (scanner.hasNextLine()) {
-                fileContents.append(scanner.nextLine() + EOL);
-            }
-            return fileContents.toString();
-        } finally {
-            scanner.close();
-        }
-    }
-
-    /**
-     * Read file data into a string.
-     *
-     * @param filename the file to open
-     * @return the file contents
-     * @throws IOException if a java.io operation throws
-     */
-    private String readFileData(final String filename) throws IOException {
-        return readFileData(new File(filename));
-    }
+    // ------------------------------------------------------------------------
+    // Event handlers ---------------------------------------------------------
+    // ------------------------------------------------------------------------
 
     /**
-     * Draw the window.
+     * Called by application.switchWindow() when this window gets the
+     * focus, and also by application.addWindow().
      */
-    @Override
-    public void draw() {
-        // Draw as normal.
-        super.draw();
-
-        // Add the row:col on the bottom row
-        CellAttributes borderColor = getBorder();
-        String location = String.format(" %d:%d ",
-            editField.getEditingRowNumber(),
-            editField.getEditingColumnNumber());
-        int colon = location.indexOf(':');
-        putStringXY(10 - colon, getHeight() - 1, location, borderColor);
-
-        if (editField.isDirty()) {
-            putCharXY(2, getHeight() - 1, GraphicsChars.OCTOSTAR, borderColor);
-        }
+    public void onFocus() {
+        super.onFocus();
+        getApplication().enableMenuItem(TMenu.MID_UNDO);
+        getApplication().enableMenuItem(TMenu.MID_REDO);
     }
 
     /**
-     * Check if a mouse press/release/motion event coordinate is over the
-     * editor.
-     *
-     * @param mouse a mouse-based event
-     * @return whether or not the mouse is on the editor
+     * Called by application.switchWindow() when another window gets the
+     * focus.
      */
-    private final boolean mouseOnEditor(final TMouseEvent mouse) {
-        if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1)
-            && (mouse.getAbsoluteX() <  getAbsoluteX() + getWidth() - 1)
-            && (mouse.getAbsoluteY() >= getAbsoluteY() + 1)
-            && (mouse.getAbsoluteY() <  getAbsoluteY() + getHeight() - 1)
-        ) {
-            return true;
-        }
-        return false;
+    public void onUnfocus() {
+        super.onUnfocus();
+        getApplication().disableMenuItem(TMenu.MID_UNDO);
+        getApplication().disableMenuItem(TMenu.MID_REDO);
     }
 
     /**
@@ -236,6 +185,10 @@ public class TEditorWindow extends TScrollableWindow {
         // Use TWidget's code to pass the event to the children.
         super.onMouseDown(mouse);
 
+        if (hideMouseWhenTyping) {
+            typingHidMouse = false;
+        }
+
         if (mouseOnEditor(mouse)) {
             // The editor might have changed, update the scollbars.
             setBottomValue(editField.getMaximumRowNumber());
@@ -260,12 +213,19 @@ public class TEditorWindow extends TScrollableWindow {
         // Use TWidget's code to pass the event to the children.
         super.onMouseUp(mouse);
 
+        if (hideMouseWhenTyping) {
+            typingHidMouse = false;
+        }
+
         if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
             // Clicked on vertical scrollbar
             editField.setVisibleRowNumber(getVerticalValue());
         }
-
-        // TODO: horizontal scrolling
+        if (mouse.isMouse1() && mouseOnHorizontalScroller(mouse)) {
+            // Clicked on horizontal scrollbar
+            editField.setVisibleColumnNumber(getHorizontalValue());
+            setHorizontalValue(editField.getVisibleColumnNumber());
+        }
     }
 
     /**
@@ -278,6 +238,10 @@ public class TEditorWindow extends TScrollableWindow {
         // Use TWidget's code to pass the event to the children.
         super.onMouseMotion(mouse);
 
+        if (hideMouseWhenTyping) {
+            typingHidMouse = false;
+        }
+
         if (mouseOnEditor(mouse) && mouse.isMouse1()) {
             // The editor might have changed, update the scollbars.
             setBottomValue(editField.getMaximumRowNumber());
@@ -289,8 +253,11 @@ public class TEditorWindow extends TScrollableWindow {
                 // Clicked/dragged on vertical scrollbar
                 editField.setVisibleRowNumber(getVerticalValue());
             }
-
-            // TODO: horizontal scrolling
+            if (mouse.isMouse1() && mouseOnHorizontalScroller(mouse)) {
+                // Clicked/dragged on horizontal scrollbar
+                editField.setVisibleColumnNumber(getHorizontalValue());
+                setHorizontalValue(editField.getVisibleColumnNumber());
+            }
         }
 
     }
@@ -302,6 +269,10 @@ public class TEditorWindow extends TScrollableWindow {
      */
     @Override
     public void onKeypress(final TKeypressEvent keypress) {
+        if (hideMouseWhenTyping) {
+            typingHidMouse = true;
+        }
+
         // Use TWidget's code to pass the event to the children.
         super.onKeypress(keypress);
 
@@ -381,4 +352,144 @@ public class TEditorWindow extends TScrollableWindow {
         super.onCommand(command);
     }
 
+    /**
+     * Handle posted menu events.
+     *
+     * @param menu menu event
+     */
+    @Override
+    public void onMenu(final TMenuEvent menu) {
+        switch (menu.getId()) {
+        case TMenu.MID_UNDO:
+            editField.undo();
+            break;
+        case TMenu.MID_REDO:
+            editField.redo();
+            break;
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // TWindow ----------------------------------------------------------------
+    // ------------------------------------------------------------------------
+
+    /**
+     * Draw the window.
+     */
+    @Override
+    public void draw() {
+        // Draw as normal.
+        super.draw();
+
+        // Add the row:col on the bottom row
+        CellAttributes borderColor = getBorder();
+        String location = String.format(" %d:%d ",
+            editField.getEditingRowNumber(),
+            editField.getEditingColumnNumber());
+        int colon = location.indexOf(':');
+        putStringXY(10 - colon, getHeight() - 1, location, borderColor);
+
+        if (editField.isDirty()) {
+            putCharXY(2, getHeight() - 1, GraphicsChars.OCTOSTAR, borderColor);
+        }
+    }
+
+    /**
+     * Returns true if this window does not want the application-wide mouse
+     * cursor drawn over it.
+     *
+     * @return true if this window does not want the application-wide mouse
+     * cursor drawn over it
+     */
+    @Override
+    public boolean hasHiddenMouse() {
+        return (super.hasHiddenMouse() || typingHidMouse);
+    }
+
+    // ------------------------------------------------------------------------
+    // TEditorWindow ----------------------------------------------------------
+    // ------------------------------------------------------------------------
+
+    /**
+     * Setup other fields after the editor is created.
+     */
+    private void setupAfterEditor() {
+        hScroller = new THScroller(this, 17, getHeight() - 2, getWidth() - 20);
+        vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
+        setMinimumWindowWidth(25);
+        setMinimumWindowHeight(10);
+        setTopValue(1);
+        setBottomValue(editField.getMaximumRowNumber());
+        setLeftValue(1);
+        setRightValue(editField.getMaximumColumnNumber());
+
+        statusBar = newStatusBar(i18n.getString("statusBar"));
+        statusBar.addShortcutKeypress(kbF1, cmHelp,
+            i18n.getString("statusBarHelp"));
+        statusBar.addShortcutKeypress(kbF2, cmSave,
+            i18n.getString("statusBarSave"));
+        statusBar.addShortcutKeypress(kbF3, cmOpen,
+            i18n.getString("statusBarOpen"));
+        statusBar.addShortcutKeypress(kbF10, cmMenu,
+            i18n.getString("statusBarMenu"));
+
+        // Hide mouse when typing option
+        if (System.getProperty("jexer.TEditor.hideMouseWhenTyping",
+                "true").equals("false")) {
+
+            hideMouseWhenTyping = false;
+        }
+    }
+
+    /**
+     * Read file data into a string.
+     *
+     * @param file the file to open
+     * @return the file contents
+     * @throws IOException if a java.io operation throws
+     */
+    private String readFileData(final File file) throws IOException {
+        StringBuilder fileContents = new StringBuilder();
+        Scanner scanner = new Scanner(file);
+        String EOL = System.getProperty("line.separator");
+
+        try {
+            while (scanner.hasNextLine()) {
+                fileContents.append(scanner.nextLine() + EOL);
+            }
+            return fileContents.toString();
+        } finally {
+            scanner.close();
+        }
+    }
+
+    /**
+     * Read file data into a string.
+     *
+     * @param filename the file to open
+     * @return the file contents
+     * @throws IOException if a java.io operation throws
+     */
+    private String readFileData(final String filename) throws IOException {
+        return readFileData(new File(filename));
+    }
+
+    /**
+     * Check if a mouse press/release/motion event coordinate is over the
+     * editor.
+     *
+     * @param mouse a mouse-based event
+     * @return whether or not the mouse is on the editor
+     */
+    private boolean mouseOnEditor(final TMouseEvent mouse) {
+        if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1)
+            && (mouse.getAbsoluteX() <  getAbsoluteX() + getWidth() - 1)
+            && (mouse.getAbsoluteY() >= getAbsoluteY() + 1)
+            && (mouse.getAbsoluteY() <  getAbsoluteY() + getHeight() - 1)
+        ) {
+            return true;
+        }
+        return false;
+    }
+
 }