base data structures
authorKevin Lamonte <kevin.lamonte@gmail.com>
Mon, 9 Mar 2015 12:03:14 +0000 (08:03 -0400)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Mon, 9 Mar 2015 12:03:14 +0000 (08:03 -0400)
15 files changed:
.gitignore
Makefile
src/jexer/TCommand.java [new file with mode: 0644]
src/jexer/TKeypress.java [new file with mode: 0644]
src/jexer/backend/Backend.java [new file with mode: 0644]
src/jexer/bits/MnemonicString.java [new file with mode: 0644]
src/jexer/event/TCommandEvent.java [new file with mode: 0644]
src/jexer/event/TInputEvent.java [new file with mode: 0644]
src/jexer/event/TKeypressEvent.java [new file with mode: 0644]
src/jexer/event/TMenuEvent.java [new file with mode: 0644]
src/jexer/event/TMouseEvent.java [new file with mode: 0644]
src/jexer/event/TResizeEvent.java [new file with mode: 0644]
src/jexer/io/Screen.java [new file with mode: 0644]
src/jexer/session/SessionInfo.java [new file with mode: 0644]
src/jexer/session/TSessionInfo.java [new file with mode: 0644]

index 32858aad3c383ed1ff0a0f9bdf231d54a00c9e88..8184903d3d1a2f0d342979ceb7953be144711037 100644 (file)
@@ -10,3 +10,8 @@
 
 # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
 hs_err_pid*
+
+# Editor backup files
+*.java~
+*.xml~
+*Makefile~
index 34e264e72f911bf3edfef00b0896a98c1a5bbe2f..490814a334be40c65471389610cbb31ee30c1f4d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -39,18 +39,44 @@ ANT_TARGET_DIR = build
 TARGET_DIR = classes
 
 JEXER_SRC = $(SRC_DIR)/jexer/TApplication.java \
+       $(SRC_DIR)/jexer/TCommand.java \
+       $(SRC_DIR)/jexer/TKeypress.java \
        $(SRC_DIR)/jexer/bits/GraphicsChars.java \
        $(SRC_DIR)/jexer/bits/Color.java \
        $(SRC_DIR)/jexer/bits/CellAttributes.java \
        $(SRC_DIR)/jexer/bits/Cell.java \
-       $(SRC_DIR)/jexer/bits/ColorTheme.java
+       $(SRC_DIR)/jexer/bits/ColorTheme.java \
+       $(SRC_DIR)/jexer/bits/MnemonicString.java \
+       $(SRC_DIR)/jexer/event/TInputEvent.java \
+       $(SRC_DIR)/jexer/event/TCommandEvent.java \
+       $(SRC_DIR)/jexer/event/TKeypressEvent.java \
+       $(SRC_DIR)/jexer/event/TMenuEvent.java \
+       $(SRC_DIR)/jexer/event/TMouseEvent.java \
+       $(SRC_DIR)/jexer/event/TResizeEvent.java \
+       $(SRC_DIR)/jexer/session/SessionInfo.java \
+       $(SRC_DIR)/jexer/session/TSessionInfo.java \
+       $(SRC_DIR)/jexer/io/Screen.java \
+       $(SRC_DIR)/jexer/backend/Backend.java
 
 JEXER_BIN = $(TARGET_DIR)/jexer/TApplication.class \
+       $(TARGET_DIR)/jexer/TCommand.class \
+       $(TARGET_DIR)/jexer/TKeypress.class \
        $(TARGET_DIR)/jexer/bits/GraphicsChars.class \
        $(TARGET_DIR)/jexer/bits/Color.class \
        $(TARGET_DIR)/jexer/bits/CellAttributes.class \
        $(TARGET_DIR)/jexer/bits/Cell.class \
-       $(TARGET_DIR)/jexer/bits/ColorTheme.class
+       $(TARGET_DIR)/jexer/bits/ColorTheme.class \
+       $(TARGET_DIR)/jexer/bits/MnemonicString.class \
+       $(TARGET_DIR)/jexer/event/TInputEvent.class \
+       $(TARGET_DIR)/jexer/event/TCommandEvent.class \
+       $(TARGET_DIR)/jexer/event/TKeypressEvent.class \
+       $(TARGET_DIR)/jexer/event/TMenuEvent.class \
+       $(TARGET_DIR)/jexer/event/TMouseEvent.class \
+       $(TARGET_DIR)/jexer/event/TResizeEvent.class \
+       $(TARGET_DIR)/jexer/session/SessionInfo.class \
+       $(TARGET_DIR)/jexer/session/TSessionInfo.class \
+       $(TARGET_DIR)/jexer/io/Screen.class \
+       $(TARGET_DIR)/jexer/backend/Backend.class
 
 JAVAC = javac
 JAVAFLAGS = -g -deprecation
diff --git a/src/jexer/TCommand.java b/src/jexer/TCommand.java
new file mode 100644 (file)
index 0000000..0a38903
--- /dev/null
@@ -0,0 +1,165 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer;
+
+/**
+ * This class encapsulates several kinds of user commands.  A user command
+ * can be generated by a menu action or keyboard accelerator.
+ */
+public class TCommand {
+
+    public enum Type {
+       /**
+        * Immediately abort the application (e.g. remote side closed
+        * connection)
+        */
+       ABORT,
+
+       /**
+        * File open dialog
+        */
+       OPEN,
+
+       /**
+        * Exit application
+        */
+       EXIT,
+
+       /**
+        * Spawn OS shell window
+        */
+       SHELL,
+
+       /**
+        * Cut selected text and copy to the clipboard
+        */
+       CUT,
+
+       /**
+        * Copy selected text to clipboard
+        */
+       COPY,
+
+       /**
+        * Paste from clipboard
+        */
+       PASTE,
+
+       /**
+        * Clear selected text without copying it to the clipboard
+        */
+       CLEAR,
+
+       /**
+        * Tile windows
+        */
+       TILE,
+
+       /**
+        * Cascade windows
+        */
+       CASCADE,
+
+       /**
+        * Close all windows
+        */
+       CLOSE_ALL,
+
+       /**
+        * Move (move/resize) window
+        */
+       WINDOW_MOVE,
+
+       /**
+        * Zoom (maximize/restore) window
+        */
+       WINDOW_ZOOM,
+
+       /**
+        * Next window (like Alt-TAB)
+        */
+       WINDOW_NEXT,
+
+       /**
+        * Previous window (like Shift-Alt-TAB)
+        */
+       WINDOW_PREVIOUS,
+
+       /**
+        * Close window
+        */
+       WINDOW_CLOSE,
+
+    }
+
+    /**
+     * Type of command, one of EXIT, CASCADE, etc.
+     */
+    public Type type;
+
+    /**
+     * Public contructor
+     *
+     * @param type the Type of command, one of EXIT, CASCADE, etc.
+     */
+    public TCommand(Type type) {
+       this.type = type;
+    }
+
+    /**
+     * Make human-readable description of this event
+     */
+    @Override
+    public String toString() {
+       return String.format("%s", type);
+    }
+
+    static public final TCommand cmAbort      = new TCommand(TCommand.Type.ABORT);
+    static public final TCommand cmExit       = new TCommand(TCommand.Type.EXIT);
+    static public final TCommand cmQuit       = new TCommand(TCommand.Type.EXIT);
+    static public final TCommand cmOpen       = new TCommand(TCommand.Type.OPEN);
+    static public final TCommand cmShell      = new TCommand(TCommand.Type.SHELL);
+    static public final TCommand cmCut        = new TCommand(TCommand.Type.CUT);
+    static public final TCommand cmCopy       = new TCommand(TCommand.Type.COPY);
+    static public final TCommand cmPaste      = new TCommand(TCommand.Type.PASTE);
+    static public final TCommand cmClear      = new TCommand(TCommand.Type.CLEAR);
+    static public final TCommand cmTile       = new TCommand(TCommand.Type.TILE);
+    static public final TCommand cmCascade    = new TCommand(TCommand.Type.CASCADE);
+    static public final TCommand cmCloseAll   = new TCommand(TCommand.Type.CLOSE_ALL);
+    static public final TCommand cmWindowMove = new TCommand(TCommand.Type.WINDOW_MOVE);
+    static public final TCommand cmWindowZoom = new TCommand(TCommand.Type.WINDOW_ZOOM);
+    static public final TCommand cmWindowNext = new TCommand(TCommand.Type.WINDOW_NEXT);
+    static public final TCommand cmWindowPrevious = new TCommand(TCommand.Type.WINDOW_PREVIOUS);
+    static public final TCommand cmWindowClose = new TCommand(TCommand.Type.WINDOW_CLOSE);
+
+}
diff --git a/src/jexer/TKeypress.java b/src/jexer/TKeypress.java
new file mode 100644 (file)
index 0000000..4f5f0af
--- /dev/null
@@ -0,0 +1,862 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer;
+
+/**
+ * This class represents keystrokes.
+ */
+public class TKeypress {
+
+    // Various special keystrokes
+
+    /**
+     * "No key"
+     */
+    static public final int NONE       = 255;
+
+    /**
+     * Function key F1
+     */
+    static public final int F1         = 1;
+
+    /**
+     * Function key F2
+     */
+    static public final int F2         = 2;
+
+    /**
+     * Function key F3
+     */
+    static public final int F3         = 3;
+
+    /**
+     * Function key F4
+     */
+    static public final int F4         = 4;
+
+    /**
+     * Function key F5
+     */
+    static public final int F5         = 5;
+
+    /**
+     * Function key F6
+     */
+    static public final int F6         = 6;
+
+    /**
+     * Function key F7
+     */
+    static public final int F7         = 7;
+
+    /**
+     * Function key F8
+     */
+    static public final int F8         = 8;
+
+    /**
+     * Function key F9
+     */
+    static public final int F9         = 9;
+
+    /**
+     * Function key F10
+     */
+    static public final int F10                = 10;
+
+    /**
+     * Function key F11
+     */
+    static public final int F11                = 11;
+
+    /**
+     * Function key F12
+     */
+    static public final int F12                = 12;
+
+    /**
+     * Home
+     */
+    static public final int HOME       = 20;
+
+    /**
+     * End
+     */
+    static public final int END                = 21;
+
+    /**
+     * Page up
+     */
+    static public final int PGUP       = 22;
+
+    /**
+     * Page down
+     */
+    static public final int PGDN       = 23;
+
+    /**
+     * Insert
+     */
+    static public final int INS                = 24;
+
+    /**
+     * Delete
+     */
+    static public final int DEL                = 25;
+
+    /**
+     * Right arrow
+     */
+    static public final int RIGHT      = 30;
+
+    /**
+     * Left arrow
+     */
+    static public final int LEFT       = 31;
+
+    /**
+     * Up arrow
+     */
+    static public final int UP         = 32;
+
+    /**
+     * Down arrow
+     */
+    static public final int DOWN       = 33;
+
+    /**
+     * Tab
+     */
+    static public final int TAB                = 40;
+
+    /**
+     * Back-tab (shift-tab)
+     */
+    static public final int BTAB       = 41;
+
+    /**
+     * Enter
+     */
+    static public final int ENTER      = 42;
+
+    /**
+     * Escape
+     */
+    static public final int ESC                = 43;
+
+    /**
+     * If true, ch is meaningless, use fnKey instead.
+     */
+    public boolean isKey;
+
+    /**
+     * Will be set to F1, F2, HOME, END, etc. if isKey is true.
+     */
+    public int fnKey;
+
+    /**
+     * Keystroke modifier ALT
+     */
+    public boolean alt;
+
+    /**
+     * Keystroke modifier CTRL
+     */
+    public boolean ctrl;
+
+    /**
+     * Keystroke modifier SHIFT
+     */
+    public boolean shift;
+
+    /**
+     * The character received
+     */
+    public char ch;
+
+    /**
+     * Convenience constructor for immutable instances
+     *
+     * @param isKey is true, this is a function key
+     * @param fnKey the function key code (only valid if isKey is true)
+     * @param ch the character (only valid if fnKey is false)
+     * @param alt if true, ALT was pressed with this keystroke
+     * @param ctrl if true, CTRL was pressed with this keystroke
+     * @param shift if true, SHIFT was pressed with this keystroke
+     */
+    public TKeypress(boolean isKey, int fnKey, char ch,
+       boolean alt, boolean ctrl, boolean shift) {
+
+       this.isKey = isKey;
+       this.fnKey = fnKey;
+       this.ch    = ch;
+       this.alt   = alt;
+       this.ctrl  = ctrl;
+       this.shift = shift;
+    }
+
+    /**
+     * Make human-readable description of this Keystroke.
+     */
+    @Override
+    public String toString() {
+       if (isKey) {
+           switch (fnKey) {
+           case F1:
+               return String.format("%s%s%sF1",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F2:
+               return String.format("%s%s%sF2",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F3:
+               return String.format("%s%s%sF3",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F4:
+               return String.format("%s%s%sF4",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F5:
+               return String.format("%s%s%sF5",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F6:
+               return String.format("%s%s%sF6",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F7:
+               return String.format("%s%s%sF7",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F8:
+               return String.format("%s%s%sF8",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F9:
+               return String.format("%s%s%sF9",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F10:
+               return String.format("%s%s%sF10",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F11:
+               return String.format("%s%s%sF11",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case F12:
+               return String.format("%s%s%sF12",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case HOME:
+               return String.format("%s%s%sHOME",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case END:
+               return String.format("%s%s%sEND",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case PGUP:
+               return String.format("%s%s%sPGUP",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case PGDN:
+               return String.format("%s%s%sPGDN",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case INS:
+               return String.format("%s%s%sINS",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case DEL:
+               return String.format("%s%s%sDEL",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case RIGHT:
+               return String.format("%s%s%sRIGHT",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case LEFT:
+               return String.format("%s%s%sLEFT",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case UP:
+               return String.format("%s%s%sUP",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case DOWN:
+               return String.format("%s%s%sDOWN",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case TAB:
+               return String.format("%s%s%sTAB",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case BTAB:
+               return String.format("%s%s%sBTAB",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case ENTER:
+               return String.format("%s%s%sENTER",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           case ESC:
+               return String.format("%s%s%sESC",
+                   ctrl ? "Ctrl+" : "",
+                   alt ? "Alt+" : "",
+                   shift ? "Shift+" : "");
+           default:
+               return String.format("--UNKNOWN--");
+           }
+       } else {
+           if (alt && !shift && !ctrl) {
+               // Alt-X
+               return String.format("Alt+%c", Character.toUpperCase(ch));
+           } else if (!alt && shift && !ctrl) {
+               // Shift-X
+               return String.format("%c", ch);
+           } else if (!alt && !shift && ctrl) {
+               // Ctrl-X
+               return String.format("Ctrl+%c", ch);
+           } else if (alt && shift && !ctrl) {
+               // Alt-Shift-X
+               return String.format("Alt+Shift+%c", ch);
+           } else if (!alt && shift && ctrl) {
+               // Ctrl-Shift-X
+               return String.format("Ctrl+Shift+%c", ch);
+           } else if (alt && !shift && ctrl) {
+               // Ctrl-Alt-X
+               return String.format("Ctrl+Alt+%c", Character.toUpperCase(ch));
+           } else if (alt && shift && ctrl) {
+               // Ctrl-Alt-Shift-X
+               return String.format("Ctrl+Alt+Shift+%c",
+                   Character.toUpperCase(ch));
+           } else {
+               // X
+               return String.format("%c", ch);
+           }
+       }
+    }
+
+    /**
+     * Convert a keypress to lowercase.  Function keys and ctrl keys are not
+     * converted.
+     *
+     * @param key keypress to convert
+     * @return a new instance with the key converted
+     */
+    static public TKeypress toLower(TKeypress key) {
+       TKeypress newKey = new TKeypress(key.isKey, key.fnKey, key.ch,
+           key.alt, key.ctrl, key.shift);
+       if (!(key.isKey) && (key.ch >= 'A') && (key.ch <= 'Z') && (!key.ctrl)) {
+           newKey.shift = false;
+           newKey.ch += 32;
+       }
+       return newKey;
+    }
+
+    /**
+     * Convert a keypress to uppercase.  Function keys and ctrl keys are not
+     * converted.
+     *
+     * @param key keypress to convert
+     * @return a new instance with the key converted
+     */
+    static public TKeypress toUpper(TKeypress key) {
+       TKeypress newKey = new TKeypress(key.isKey, key.fnKey, key.ch,
+           key.alt, key.ctrl, key.shift);
+       if (!(key.isKey) && (key.ch >= 'a') && (key.ch <= 'z') && (!key.ctrl)) {
+           newKey.shift = true;
+           newKey.ch -= 32;
+       }
+       return newKey;
+    }
+
+    // Special "no-key" keypress, used to ignore undefined keystrokes
+    static public final TKeypress kbNoKey = new TKeypress(true,
+       TKeypress.NONE, ' ', false, false, false);
+
+    // Normal keys
+    static public final TKeypress kbF1 = new TKeypress(true,
+       TKeypress.F1, ' ', false, false, false);
+    static public final TKeypress kbF2 = new TKeypress(true,
+       TKeypress.F2, ' ', false, false, false);
+    static public final TKeypress kbF3 = new TKeypress(true,
+       TKeypress.F3, ' ', false, false, false);
+    static public final TKeypress kbF4 = new TKeypress(true,
+       TKeypress.F4, ' ', false, false, false);
+    static public final TKeypress kbF5 = new TKeypress(true,
+       TKeypress.F5, ' ', false, false, false);
+    static public final TKeypress kbF6 = new TKeypress(true,
+       TKeypress.F6, ' ', false, false, false);
+    static public final TKeypress kbF7 = new TKeypress(true,
+       TKeypress.F7, ' ', false, false, false);
+    static public final TKeypress kbF8 = new TKeypress(true,
+       TKeypress.F8, ' ', false, false, false);
+    static public final TKeypress kbF9 = new TKeypress(true,
+       TKeypress.F9, ' ', false, false, false);
+    static public final TKeypress kbF10 = new TKeypress(true,
+       TKeypress.F10, ' ', false, false, false);
+    static public final TKeypress kbF11 = new TKeypress(true,
+       TKeypress.F11, ' ', false, false, false);
+    static public final TKeypress kbF12 = new TKeypress(true,
+       TKeypress.F12, ' ', false, false, false);
+    static public final TKeypress kbAltF1 = new TKeypress(true,
+       TKeypress.F1, ' ', true, false, false);
+    static public final TKeypress kbAltF2 = new TKeypress(true,
+       TKeypress.F2, ' ', true, false, false);
+    static public final TKeypress kbAltF3 = new TKeypress(true,
+       TKeypress.F3, ' ', true, false, false);
+    static public final TKeypress kbAltF4 = new TKeypress(true,
+       TKeypress.F4, ' ', true, false, false);
+    static public final TKeypress kbAltF5 = new TKeypress(true,
+       TKeypress.F5, ' ', true, false, false);
+    static public final TKeypress kbAltF6 = new TKeypress(true,
+       TKeypress.F6, ' ', true, false, false);
+    static public final TKeypress kbAltF7 = new TKeypress(true,
+       TKeypress.F7, ' ', true, false, false);
+    static public final TKeypress kbAltF8 = new TKeypress(true,
+       TKeypress.F8, ' ', true, false, false);
+    static public final TKeypress kbAltF9 = new TKeypress(true,
+       TKeypress.F9, ' ', true, false, false);
+    static public final TKeypress kbAltF10 = new TKeypress(true,
+       TKeypress.F10, ' ', true, false, false);
+    static public final TKeypress kbAltF11 = new TKeypress(true,
+       TKeypress.F11, ' ', true, false, false);
+    static public final TKeypress kbAltF12 = new TKeypress(true,
+       TKeypress.F12, ' ', true, false, false);
+    static public final TKeypress kbCtrlF1 = new TKeypress(true,
+       TKeypress.F1, ' ', false, true, false);
+    static public final TKeypress kbCtrlF2 = new TKeypress(true,
+       TKeypress.F2, ' ', false, true, false);
+    static public final TKeypress kbCtrlF3 = new TKeypress(true,
+       TKeypress.F3, ' ', false, true, false);
+    static public final TKeypress kbCtrlF4 = new TKeypress(true,
+       TKeypress.F4, ' ', false, true, false);
+    static public final TKeypress kbCtrlF5 = new TKeypress(true,
+       TKeypress.F5, ' ', false, true, false);
+    static public final TKeypress kbCtrlF6 = new TKeypress(true,
+       TKeypress.F6, ' ', false, true, false);
+    static public final TKeypress kbCtrlF7 = new TKeypress(true,
+       TKeypress.F7, ' ', false, true, false);
+    static public final TKeypress kbCtrlF8 = new TKeypress(true,
+       TKeypress.F8, ' ', false, true, false);
+    static public final TKeypress kbCtrlF9 = new TKeypress(true,
+       TKeypress.F9, ' ', false, true, false);
+    static public final TKeypress kbCtrlF10 = new TKeypress(true,
+       TKeypress.F10, ' ', false, true, false);
+    static public final TKeypress kbCtrlF11 = new TKeypress(true,
+       TKeypress.F11, ' ', false, true, false);
+    static public final TKeypress kbCtrlF12 = new TKeypress(true,
+       TKeypress.F12, ' ', false, true, false);
+    static public final TKeypress kbShiftF1 = new TKeypress(true,
+       TKeypress.F1, ' ', false, false, true);
+    static public final TKeypress kbShiftF2 = new TKeypress(true,
+       TKeypress.F2, ' ', false, false, true);
+    static public final TKeypress kbShiftF3 = new TKeypress(true,
+       TKeypress.F3, ' ', false, false, true);
+    static public final TKeypress kbShiftF4 = new TKeypress(true,
+       TKeypress.F4, ' ', false, false, true);
+    static public final TKeypress kbShiftF5 = new TKeypress(true,
+       TKeypress.F5, ' ', false, false, true);
+    static public final TKeypress kbShiftF6 = new TKeypress(true,
+       TKeypress.F6, ' ', false, false, true);
+    static public final TKeypress kbShiftF7 = new TKeypress(true,
+       TKeypress.F7, ' ', false, false, true);
+    static public final TKeypress kbShiftF8 = new TKeypress(true,
+       TKeypress.F8, ' ', false, false, true);
+    static public final TKeypress kbShiftF9 = new TKeypress(true,
+       TKeypress.F9, ' ', false, false, true);
+    static public final TKeypress kbShiftF10 = new TKeypress(true,
+       TKeypress.F10, ' ', false, false, true);
+    static public final TKeypress kbShiftF11 = new TKeypress(true,
+       TKeypress.F11, ' ', false, false, true);
+    static public final TKeypress kbShiftF12 = new TKeypress(true,
+       TKeypress.F12, ' ', false, false, true);
+    static public final TKeypress kbEnter = new TKeypress(true,
+       TKeypress.ENTER, ' ', false, false, false);
+    static public final TKeypress kbTab = new TKeypress(true,
+       TKeypress.TAB, ' ', false, false, false);
+    static public final TKeypress kbEsc = new TKeypress(true,
+       TKeypress.ESC, ' ', false, false, false);
+    static public final TKeypress kbHome = new TKeypress(true,
+       TKeypress.HOME, ' ', false, false, false);
+    static public final TKeypress kbEnd = new TKeypress(true,
+       TKeypress.END, ' ', false, false, false);
+    static public final TKeypress kbPgUp = new TKeypress(true,
+       TKeypress.PGUP, ' ', false, false, false);
+    static public final TKeypress kbPgDn = new TKeypress(true,
+       TKeypress.PGDN, ' ', false, false, false);
+    static public final TKeypress kbIns = new TKeypress(true,
+       TKeypress.INS, ' ', false, false, false);
+    static public final TKeypress kbDel = new TKeypress(true,
+       TKeypress.DEL, ' ', false, false, false);
+    static public final TKeypress kbUp = new TKeypress(true,
+       TKeypress.UP, ' ', false, false, false);
+    static public final TKeypress kbDown = new TKeypress(true,
+       TKeypress.DOWN, ' ', false, false, false);
+    static public final TKeypress kbLeft = new TKeypress(true,
+       TKeypress.LEFT, ' ', false, false, false);
+    static public final TKeypress kbRight = new TKeypress(true,
+       TKeypress.RIGHT, ' ', false, false, false);
+    static public final TKeypress kbAltEnter = new TKeypress(true,
+       TKeypress.ENTER, ' ', true, false, false);
+    static public final TKeypress kbAltTab = new TKeypress(true,
+       TKeypress.TAB, ' ', true, false, false);
+    static public final TKeypress kbAltEsc = new TKeypress(true,
+       TKeypress.ESC, ' ', true, false, false);
+    static public final TKeypress kbAltHome = new TKeypress(true,
+       TKeypress.HOME, ' ', true, false, false);
+    static public final TKeypress kbAltEnd = new TKeypress(true,
+       TKeypress.END, ' ', true, false, false);
+    static public final TKeypress kbAltPgUp = new TKeypress(true,
+       TKeypress.PGUP, ' ', true, false, false);
+    static public final TKeypress kbAltPgDn = new TKeypress(true,
+       TKeypress.PGDN, ' ', true, false, false);
+    static public final TKeypress kbAltIns = new TKeypress(true,
+       TKeypress.INS, ' ', true, false, false);
+    static public final TKeypress kbAltDel = new TKeypress(true,
+       TKeypress.DEL, ' ', true, false, false);
+    static public final TKeypress kbAltUp = new TKeypress(true,
+       TKeypress.UP, ' ', true, false, false);
+    static public final TKeypress kbAltDown = new TKeypress(true,
+       TKeypress.DOWN, ' ', true, false, false);
+    static public final TKeypress kbAltLeft = new TKeypress(true,
+       TKeypress.LEFT, ' ', true, false, false);
+    static public final TKeypress kbAltRight = new TKeypress(true,
+       TKeypress.RIGHT, ' ', true, false, false);
+    static public final TKeypress kbCtrlEnter = new TKeypress(true,
+       TKeypress.ENTER, ' ', false, true, false);
+    static public final TKeypress kbCtrlTab = new TKeypress(true,
+       TKeypress.TAB, ' ', false, true, false);
+    static public final TKeypress kbCtrlEsc = new TKeypress(true,
+       TKeypress.ESC, ' ', false, true, false);
+    static public final TKeypress kbCtrlHome = new TKeypress(true,
+       TKeypress.HOME, ' ', false, true, false);
+    static public final TKeypress kbCtrlEnd = new TKeypress(true,
+       TKeypress.END, ' ', false, true, false);
+    static public final TKeypress kbCtrlPgUp = new TKeypress(true,
+       TKeypress.PGUP, ' ', false, true, false);
+    static public final TKeypress kbCtrlPgDn = new TKeypress(true,
+       TKeypress.PGDN, ' ', false, true, false);
+    static public final TKeypress kbCtrlIns = new TKeypress(true,
+       TKeypress.INS, ' ', false, true, false);
+    static public final TKeypress kbCtrlDel = new TKeypress(true,
+       TKeypress.DEL, ' ', false, true, false);
+    static public final TKeypress kbCtrlUp = new TKeypress(true,
+       TKeypress.UP, ' ', false, true, false);
+    static public final TKeypress kbCtrlDown = new TKeypress(true,
+       TKeypress.DOWN, ' ', false, true, false);
+    static public final TKeypress kbCtrlLeft = new TKeypress(true,
+       TKeypress.LEFT, ' ', false, true, false);
+    static public final TKeypress kbCtrlRight = new TKeypress(true,
+       TKeypress.RIGHT, ' ', false, true, false);
+    static public final TKeypress kbShiftEnter = new TKeypress(true,
+       TKeypress.ENTER, ' ', false, false, true);
+    static public final TKeypress kbShiftTab = new TKeypress(true,
+       TKeypress.TAB, ' ', false, false, true);
+    static public final TKeypress kbBackTab = new TKeypress(true,
+       TKeypress.BTAB, ' ', false, false, false);
+    static public final TKeypress kbShiftEsc = new TKeypress(true,
+       TKeypress.ESC, ' ', false, false, true);
+    static public final TKeypress kbShiftHome = new TKeypress(true,
+       TKeypress.HOME, ' ', false, false, true);
+    static public final TKeypress kbShiftEnd = new TKeypress(true,
+       TKeypress.END, ' ', false, false, true);
+    static public final TKeypress kbShiftPgUp = new TKeypress(true,
+       TKeypress.PGUP, ' ', false, false, true);
+    static public final TKeypress kbShiftPgDn = new TKeypress(true,
+       TKeypress.PGDN, ' ', false, false, true);
+    static public final TKeypress kbShiftIns = new TKeypress(true,
+       TKeypress.INS, ' ', false, false, true);
+    static public final TKeypress kbShiftDel = new TKeypress(true,
+       TKeypress.DEL, ' ', false, false, true);
+    static public final TKeypress kbShiftUp = new TKeypress(true,
+       TKeypress.UP, ' ', false, false, true);
+    static public final TKeypress kbShiftDown = new TKeypress(true,
+       TKeypress.DOWN, ' ', false, false, true);
+    static public final TKeypress kbShiftLeft = new TKeypress(true,
+       TKeypress.LEFT, ' ', false, false, true);
+    static public final TKeypress kbShiftRight = new TKeypress(true,
+       TKeypress.RIGHT, ' ', false, false, true);
+    static public final TKeypress kbA = new TKeypress(false,
+       0, 'a', false, false, false);
+    static public final TKeypress kbB = new TKeypress(false,
+       0, 'b', false, false, false);
+    static public final TKeypress kbC = new TKeypress(false,
+       0, 'c', false, false, false);
+    static public final TKeypress kbD = new TKeypress(false,
+       0, 'd', false, false, false);
+    static public final TKeypress kbE = new TKeypress(false,
+       0, 'e', false, false, false);
+    static public final TKeypress kbF = new TKeypress(false,
+       0, 'f', false, false, false);
+    static public final TKeypress kbG = new TKeypress(false,
+       0, 'g', false, false, false);
+    static public final TKeypress kbH = new TKeypress(false,
+       0, 'h', false, false, false);
+    static public final TKeypress kbI = new TKeypress(false,
+       0, 'i', false, false, false);
+    static public final TKeypress kbJ = new TKeypress(false,
+       0, 'j', false, false, false);
+    static public final TKeypress kbK = new TKeypress(false,
+       0, 'k', false, false, false);
+    static public final TKeypress kbL = new TKeypress(false,
+       0, 'l', false, false, false);
+    static public final TKeypress kbM = new TKeypress(false,
+       0, 'm', false, false, false);
+    static public final TKeypress kbN = new TKeypress(false,
+       0, 'n', false, false, false);
+    static public final TKeypress kbO = new TKeypress(false,
+       0, 'o', false, false, false);
+    static public final TKeypress kbP = new TKeypress(false,
+       0, 'p', false, false, false);
+    static public final TKeypress kbQ = new TKeypress(false,
+       0, 'q', false, false, false);
+    static public final TKeypress kbR = new TKeypress(false,
+       0, 'r', false, false, false);
+    static public final TKeypress kbS = new TKeypress(false,
+       0, 's', false, false, false);
+    static public final TKeypress kbT = new TKeypress(false,
+       0, 't', false, false, false);
+    static public final TKeypress kbU = new TKeypress(false,
+       0, 'u', false, false, false);
+    static public final TKeypress kbV = new TKeypress(false,
+       0, 'v', false, false, false);
+    static public final TKeypress kbW = new TKeypress(false,
+       0, 'w', false, false, false);
+    static public final TKeypress kbX = new TKeypress(false,
+       0, 'x', false, false, false);
+    static public final TKeypress kbY = new TKeypress(false,
+       0, 'y', false, false, false);
+    static public final TKeypress kbZ = new TKeypress(false,
+       0, 'z', false, false, false);
+    static public final TKeypress kbSpace = new TKeypress(false,
+       0, ' ', false, false, false);
+    static public final TKeypress kbAltA = new TKeypress(false,
+       0, 'a', true, false, false);
+    static public final TKeypress kbAltB = new TKeypress(false,
+       0, 'b', true, false, false);
+    static public final TKeypress kbAltC = new TKeypress(false,
+       0, 'c', true, false, false);
+    static public final TKeypress kbAltD = new TKeypress(false,
+       0, 'd', true, false, false);
+    static public final TKeypress kbAltE = new TKeypress(false,
+       0, 'e', true, false, false);
+    static public final TKeypress kbAltF = new TKeypress(false,
+       0, 'f', true, false, false);
+    static public final TKeypress kbAltG = new TKeypress(false,
+       0, 'g', true, false, false);
+    static public final TKeypress kbAltH = new TKeypress(false,
+       0, 'h', true, false, false);
+    static public final TKeypress kbAltI = new TKeypress(false,
+       0, 'i', true, false, false);
+    static public final TKeypress kbAltJ = new TKeypress(false,
+       0, 'j', true, false, false);
+    static public final TKeypress kbAltK = new TKeypress(false,
+       0, 'k', true, false, false);
+    static public final TKeypress kbAltL = new TKeypress(false,
+       0, 'l', true, false, false);
+    static public final TKeypress kbAltM = new TKeypress(false,
+       0, 'm', true, false, false);
+    static public final TKeypress kbAltN = new TKeypress(false,
+       0, 'n', true, false, false);
+    static public final TKeypress kbAltO = new TKeypress(false,
+       0, 'o', true, false, false);
+    static public final TKeypress kbAltP = new TKeypress(false,
+       0, 'p', true, false, false);
+    static public final TKeypress kbAltQ = new TKeypress(false,
+       0, 'q', true, false, false);
+    static public final TKeypress kbAltR = new TKeypress(false,
+       0, 'r', true, false, false);
+    static public final TKeypress kbAltS = new TKeypress(false,
+       0, 's', true, false, false);
+    static public final TKeypress kbAltT = new TKeypress(false,
+       0, 't', true, false, false);
+    static public final TKeypress kbAltU = new TKeypress(false,
+       0, 'u', true, false, false);
+    static public final TKeypress kbAltV = new TKeypress(false,
+       0, 'v', true, false, false);
+    static public final TKeypress kbAltW = new TKeypress(false,
+       0, 'w', true, false, false);
+    static public final TKeypress kbAltX = new TKeypress(false,
+       0, 'x', true, false, false);
+    static public final TKeypress kbAltY = new TKeypress(false,
+       0, 'y', true, false, false);
+    static public final TKeypress kbAltZ = new TKeypress(false,
+       0, 'z', true, false, false);
+    static public final TKeypress kbCtrlA = new TKeypress(false,
+       0, 'A', false, true, false);
+    static public final TKeypress kbCtrlB = new TKeypress(false,
+       0, 'B', false, true, false);
+    static public final TKeypress kbCtrlC = new TKeypress(false,
+       0, 'C', false, true, false);
+    static public final TKeypress kbCtrlD = new TKeypress(false,
+       0, 'D', false, true, false);
+    static public final TKeypress kbCtrlE = new TKeypress(false,
+       0, 'E', false, true, false);
+    static public final TKeypress kbCtrlF = new TKeypress(false,
+       0, 'F', false, true, false);
+    static public final TKeypress kbCtrlG = new TKeypress(false,
+       0, 'G', false, true, false);
+    static public final TKeypress kbCtrlH = new TKeypress(false,
+       0, 'H', false, true, false);
+    static public final TKeypress kbCtrlI = new TKeypress(false,
+       0, 'I', false, true, false);
+    static public final TKeypress kbCtrlJ = new TKeypress(false,
+       0, 'J', false, true, false);
+    static public final TKeypress kbCtrlK = new TKeypress(false,
+       0, 'K', false, true, false);
+    static public final TKeypress kbCtrlL = new TKeypress(false,
+       0, 'L', false, true, false);
+    static public final TKeypress kbCtrlM = new TKeypress(false,
+       0, 'M', false, true, false);
+    static public final TKeypress kbCtrlN = new TKeypress(false,
+       0, 'N', false, true, false);
+    static public final TKeypress kbCtrlO = new TKeypress(false,
+       0, 'O', false, true, false);
+    static public final TKeypress kbCtrlP = new TKeypress(false,
+       0, 'P', false, true, false);
+    static public final TKeypress kbCtrlQ = new TKeypress(false,
+       0, 'Q', false, true, false);
+    static public final TKeypress kbCtrlR = new TKeypress(false,
+       0, 'R', false, true, false);
+    static public final TKeypress kbCtrlS = new TKeypress(false,
+       0, 'S', false, true, false);
+    static public final TKeypress kbCtrlT = new TKeypress(false,
+       0, 'T', false, true, false);
+    static public final TKeypress kbCtrlU = new TKeypress(false,
+       0, 'U', false, true, false);
+    static public final TKeypress kbCtrlV = new TKeypress(false,
+       0, 'V', false, true, false);
+    static public final TKeypress kbCtrlW = new TKeypress(false,
+       0, 'W', false, true, false);
+    static public final TKeypress kbCtrlX = new TKeypress(false,
+       0, 'X', false, true, false);
+    static public final TKeypress kbCtrlY = new TKeypress(false,
+       0, 'Y', false, true, false);
+    static public final TKeypress kbCtrlZ = new TKeypress(false,
+       0, 'Z', false, true, false);
+    static public final TKeypress kbAltShiftA = new TKeypress(false,
+       0, 'A', true, false, true);
+    static public final TKeypress kbAltShiftB = new TKeypress(false,
+       0, 'B', true, false, true);
+    static public final TKeypress kbAltShiftC = new TKeypress(false,
+       0, 'C', true, false, true);
+    static public final TKeypress kbAltShiftD = new TKeypress(false,
+       0, 'D', true, false, true);
+    static public final TKeypress kbAltShiftE = new TKeypress(false,
+       0, 'E', true, false, true);
+    static public final TKeypress kbAltShiftF = new TKeypress(false,
+       0, 'F', true, false, true);
+    static public final TKeypress kbAltShiftG = new TKeypress(false,
+       0, 'G', true, false, true);
+    static public final TKeypress kbAltShiftH = new TKeypress(false,
+       0, 'H', true, false, true);
+    static public final TKeypress kbAltShiftI = new TKeypress(false,
+       0, 'I', true, false, true);
+    static public final TKeypress kbAltShiftJ = new TKeypress(false,
+       0, 'J', true, false, true);
+    static public final TKeypress kbAltShiftK = new TKeypress(false,
+       0, 'K', true, false, true);
+    static public final TKeypress kbAltShiftL = new TKeypress(false,
+       0, 'L', true, false, true);
+    static public final TKeypress kbAltShiftM = new TKeypress(false,
+       0, 'M', true, false, true);
+    static public final TKeypress kbAltShiftN = new TKeypress(false,
+       0, 'N', true, false, true);
+    static public final TKeypress kbAltShiftO = new TKeypress(false,
+       0, 'O', true, false, true);
+    static public final TKeypress kbAltShiftP = new TKeypress(false,
+       0, 'P', true, false, true);
+    static public final TKeypress kbAltShiftQ = new TKeypress(false,
+       0, 'Q', true, false, true);
+    static public final TKeypress kbAltShiftR = new TKeypress(false,
+       0, 'R', true, false, true);
+    static public final TKeypress kbAltShiftS = new TKeypress(false,
+       0, 'S', true, false, true);
+    static public final TKeypress kbAltShiftT = new TKeypress(false,
+       0, 'T', true, false, true);
+    static public final TKeypress kbAltShiftU = new TKeypress(false,
+       0, 'U', true, false, true);
+    static public final TKeypress kbAltShiftV = new TKeypress(false,
+       0, 'V', true, false, true);
+    static public final TKeypress kbAltShiftW = new TKeypress(false,
+       0, 'W', true, false, true);
+    static public final TKeypress kbAltShiftX = new TKeypress(false,
+       0, 'X', true, false, true);
+    static public final TKeypress kbAltShiftY = new TKeypress(false,
+       0, 'Y', true, false, true);
+    static public final TKeypress kbAltShiftZ = new TKeypress(false,
+       0, 'Z', true, false, true);
+
+    /**
+     * Backspace as ^H
+     */
+    static public final TKeypress kbBackspace = new TKeypress(false,
+       0, 'H', false, true, false);
+
+    /**
+     * Backspace as ^?
+     */
+    static public final TKeypress kbBackspaceDel = new TKeypress(false,
+       0, (char)0x7F, false, false, false);
+
+}
diff --git a/src/jexer/backend/Backend.java b/src/jexer/backend/Backend.java
new file mode 100644 (file)
index 0000000..15fcf62
--- /dev/null
@@ -0,0 +1,78 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.backend;
+
+import jexer.event.TInputEvent;
+import jexer.io.Screen;
+import jexer.session.SessionInfo;
+
+/**
+ * This abstract class provides a screen, keyboard, and mouse to
+ * TApplication.  It also exposes session information as gleaned from lower
+ * levels of the communication stack.
+ */
+public abstract class Backend {
+
+    /**
+     * The session information
+     */
+    public SessionInfo session;
+
+    /**
+     * The screen to draw on
+     */
+    public Screen screen;
+
+    /**
+     * Subclasses must provide an implementation that syncs the logical
+     * screen to the physical device.
+     */
+    abstract public void flushScreen();
+
+    /**
+     * Subclasses must provide an implementation to get keyboard, mouse, and
+     * screen resize events.
+     *
+     * @param timeout maximum amount of time to wait for an event
+     * @return events received, or an empty list if the timeout was reached
+     */
+    abstract public TInputEvent [] getEvents(int timeout);
+
+    /**
+     * Subclasses must provide an implementation that closes sockets,
+     * restores console, etc.
+     */
+    abstract public void shutdown();
+
+}
+
diff --git a/src/jexer/bits/MnemonicString.java b/src/jexer/bits/MnemonicString.java
new file mode 100644 (file)
index 0000000..0567c99
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.bits;
+
+/**
+ * MnemonicString is used to render a string like "&File" into a highlighted
+ * 'F' and the rest of 'ile'.  To insert a literal '&', use two '&&'
+ * characters, e.g. "&File && Stuff" would be "File & Stuff" with the first
+ * 'F' highlighted.
+ */
+public class MnemonicString {
+
+    /**
+     * Keyboard shortcut to activate this item
+     */
+    public char shortcut;
+
+    /**
+     * Location of the highlighted character
+     */
+    public int shortcutIdx = -1;
+
+    /**
+     * The raw (uncolored) string
+     */
+    public String rawLabel;
+
+    /**
+     * Public constructor
+     *
+     * @param label widget label or title.  Label must contain a keyboard
+     * shortcut, denoted by prefixing a letter with "&", e.g. "&File"
+     */
+    public MnemonicString(String label) {
+
+       // Setup the menu shortcut
+       String newLabel = "";
+       boolean foundAmp = false;
+       boolean foundShortcut = false;
+       int shortcutIdx = 0;
+       for (int i = 0; i < label.length(); i++) {
+           char c = label.charAt(i);
+           if (c == '&') {
+               if (foundAmp == true) {
+                   newLabel += '&';
+                   shortcutIdx++;
+               } else {
+                   foundAmp = true;
+               }
+           } else {
+               newLabel += c;
+               if (foundAmp == true) {
+                   if (foundShortcut == false) {
+                       shortcut = c;
+                       foundAmp = false;
+                       foundShortcut = true;
+                       this.shortcutIdx = shortcutIdx;
+                   }
+               } else {
+                   shortcutIdx++;
+               }
+           }
+       }
+       this.rawLabel = newLabel;
+    }
+}
+
diff --git a/src/jexer/event/TCommandEvent.java b/src/jexer/event/TCommandEvent.java
new file mode 100644 (file)
index 0000000..d27c7ea
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.event;
+
+import jexer.TCommand;
+
+/**
+ * This class encapsulates a user command event.
+ */
+public class TCommandEvent extends TInputEvent {
+
+    /**
+     * Command dispatched
+     */
+    public TCommand cmd;
+
+    /**
+     * Public contructor
+     *
+     * @param cmd the TCommand dispatched
+     */
+    public TCommandEvent(TCommand cmd) {
+       this.cmd = cmd;
+    }
+
+    /**
+     * Make human-readable description of this event
+     */
+    @Override
+    public String toString() {
+       return String.format("CommandEvent: %s", cmd.toString());
+    }
+}
+
diff --git a/src/jexer/event/TInputEvent.java b/src/jexer/event/TInputEvent.java
new file mode 100644 (file)
index 0000000..aa6c478
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.event;
+
+import java.util.Date;
+
+/**
+ * This is the parent class of all events received from the Terminal.
+ */
+public class TInputEvent {
+
+    /**
+     * Time at which event was generated
+     */
+    public Date timestamp;
+
+    /**
+     * Public contructor
+     */
+    public TInputEvent() {
+       // Save the current time
+       timestamp = new Date();
+    }
+}
diff --git a/src/jexer/event/TKeypressEvent.java b/src/jexer/event/TKeypressEvent.java
new file mode 100644 (file)
index 0000000..4f54df9
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.event;
+
+import jexer.TKeypress;
+
+/**
+ * This class encapsulates a keyboard input event.
+ */
+public class TKeypressEvent extends TInputEvent {
+
+    /**
+     * Keystroke received
+     */
+    public TKeypress key;
+
+    /**
+     * Public contructor
+     */
+    public TKeypressEvent() {
+       key = new TKeypress(false, 0, ' ', false, false, false);
+    }
+
+    /**
+     * Public contructor
+     *
+     * @param key the TKeypress received
+     */
+    public TKeypressEvent(TKeypress key) {
+       this.key = key;
+    }
+
+    /**
+     * Make human-readable description of this event
+     */
+    @Override
+    public String toString() {
+       return String.format("Keypress: %s", key.toString());
+    }
+}
diff --git a/src/jexer/event/TMenuEvent.java b/src/jexer/event/TMenuEvent.java
new file mode 100644 (file)
index 0000000..38ec852
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.event;
+
+/**
+ * This class encapsulates a menu selection event.
+ * TApplication.getMenuItem(id) can be used to obtain the TMenuItem itself,
+ * say for setting enabled/disabled/checked/etc.
+ */
+public class TMenuEvent extends TInputEvent {
+
+    /**
+     * MenuItem ID
+     */
+    public short id;
+
+    /**
+     * Public contructor
+     *
+     * @param id the MenuItem ID
+     */
+    public TMenuEvent(short id) {
+       this.id = id;
+    }
+
+    /**
+     * Make human-readable description of this event
+     */
+    @Override
+    public String toString() {
+       return String.format("MenuEvent: %d", id);
+    }
+}
+
diff --git a/src/jexer/event/TMouseEvent.java b/src/jexer/event/TMouseEvent.java
new file mode 100644 (file)
index 0000000..2e953eb
--- /dev/null
@@ -0,0 +1,133 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.event;
+
+/**
+ * This class encapsulates several kinds of mouse input events.
+ */
+public class TMouseEvent extends TInputEvent {
+
+    enum Type {
+       /**
+        * Mouse motion.  X and Y will have screen coordinates.
+        */
+       MOUSE_MOTION,
+
+       /**
+        * Mouse button down.  X and Y will have screen coordinates.
+        */
+       MOUSE_DOWN,
+
+       /**
+        * Mouse button up.  X and Y will have screen coordinates.
+        */
+       MOUSE_UP
+    }
+
+    /**
+     * Type of event, one of MOUSE_MOTION, MOUSE_UP, or MOUSE_DOWN, or
+     * KEYPRESS
+     */
+    public Type type;
+
+    /**
+     * Mouse X - relative coordinates
+     */
+    public int x;
+
+    /**
+     * Mouse Y - relative coordinates
+     */
+    public int y;
+
+    /**
+     * Mouse X - absolute screen coordinates
+     */
+    public int absoluteX;
+
+    /**
+     * Mouse Y - absolute screen coordinate
+     */
+    public int absoluteY;
+
+    /**
+     * Mouse button 1 (left button)
+     */
+    public boolean mouse1;
+
+    /**
+     * Mouse button 2 (right button)
+     */
+    public boolean mouse2;
+
+    /**
+     * Mouse button 3 (middle button)
+     */
+    public boolean mouse3;
+
+    /**
+     * Mouse wheel UP (button 4)
+     */
+    public boolean mouseWheelUp;
+
+    /**
+     * Mouse wheel DOWN (button 5)
+     */
+    public boolean mouseWheelDown;
+
+    /**
+     * Public contructor
+     *
+     * @param type the type of event, MOUSE_MOTION, MOUSE_DOWN, or MOUSE_UP
+     */
+    public TMouseEvent(Type type) {
+       this.type = type;
+    }
+
+    /**
+     * Make human-readable description of this event
+     */
+    @Override
+    public String toString() {
+       return String.format("Mouse: %s x %d y %d absoluteX %d absoluteY %d 1 %s 2 %s 3 %s DOWN %s UP %s",
+           type,
+           x, y,
+           absoluteX, absoluteY,
+           mouse1,
+           mouse2,
+           mouse3,
+           mouseWheelUp,
+           mouseWheelDown);
+    }
+
+}
diff --git a/src/jexer/event/TResizeEvent.java b/src/jexer/event/TResizeEvent.java
new file mode 100644 (file)
index 0000000..aabf051
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.event;
+
+/**
+ * This class encapsulates a screen or window resize event.
+ */
+public class TResizeEvent extends TInputEvent {
+
+    /**
+     * Resize events can be generated for either a total screen resize or a
+     * widget/window resize.
+     */
+    public enum Type {
+       Screen,
+       Widget
+    }
+
+    /**
+     * The type of resize
+     */
+    public Type type;
+
+    /**
+     * New width
+     */
+    public int width;
+
+    /**
+     * New height
+     */
+    public int height;
+
+    /**
+     * Public contructor
+     *
+     * @param type the Type of resize, Screen or Widget
+     * @param width the new width
+     * @param width the new height
+     */
+    public TResizeEvent(Type type, int width, int height) {
+       this.type   = type;
+       this.width  = width;
+       this.height = height;
+    }
+
+    /**
+     * Make human-readable description of this event
+     */
+    @Override
+    public String toString() {
+       return String.format("Resize: %s width = %d height = %d",
+           type, width, height);
+    }
+
+}
diff --git a/src/jexer/io/Screen.java b/src/jexer/io/Screen.java
new file mode 100644 (file)
index 0000000..6910a66
--- /dev/null
@@ -0,0 +1,646 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.io;
+
+import jexer.bits.Cell;
+import jexer.bits.CellAttributes;
+import jexer.bits.GraphicsChars;
+
+/**
+ * This class represents a text-based screen.  Drawing operations write to a
+ * logical screen.
+ */
+public abstract class Screen {
+
+    /**
+     * Emit debugging to stderr
+     */
+    public boolean debugToStderr;
+
+    /**
+     * Width of the visible window
+     */
+    protected int width;
+
+    /**
+     * Height of the visible window
+     */
+    protected int height;
+
+    /**
+     * Drawing offset for x
+     */
+    public int offsetX;
+
+    /**
+     * Drawing offset for y
+     */
+    public int offsetY;
+
+    /**
+     * Ignore anything drawn right of clipRight
+     */
+    public int clipRight;
+
+    /**
+     * Ignore anything drawn below clipBottom
+     */
+    public int clipBottom;
+
+    /**
+     * Ignore anything drawn left of clipLeft
+     */
+    public int clipLeft;
+
+    /**
+     * Ignore anything drawn above clipTop
+     */
+    public int clipTop;
+
+    /**
+     * The physical screen last sent out on flush()
+     */
+    protected Cell [][] physical;
+
+    /**
+     * The logical screen being rendered to
+     */
+    protected Cell [][] logical;
+
+    /**
+     * When true, logical != physical
+     */
+    public boolean dirty;
+
+    /**
+     * Set if the user explicitly wants to redraw everything starting with a
+     * ECMATerminal.clearAll()
+     */
+    protected boolean reallyCleared;
+
+    /**
+     * If true, the cursor is visible and should be placed onscreen at
+     * (cursorX, cursorY) during a call to flushPhysical()
+     */
+    protected boolean cursorVisible;
+
+    /**
+     * Cursor X position if visible
+     */
+    protected int cursorX;
+
+    /**
+     * Cursor Y position if visible
+     */
+    protected int cursorY;
+
+    /**
+     * Get the attributes at one location.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @return attributes at (x, y)
+     */
+    public CellAttributes getAttrXY(int x, int y) {
+       CellAttributes attr = new CellAttributes();
+       attr.setTo(logical[x][y]);
+       return attr;
+    }
+
+    /**
+     * Set the attributes at one location.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param attr attributes to use (bold, foreColor, backColor)
+     * @param clip if true, honor clipping/offset
+     */
+    public void putAttrXY(int x, int y, CellAttributes attr) {
+       putAttrXY(x, y, attr, true);
+    }
+    
+    /**
+     * Set the attributes at one location.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param attr attributes to use (bold, foreColor, backColor)
+     * @param clip if true, honor clipping/offset
+     */
+    public void putAttrXY(int x, int y, CellAttributes attr, boolean clip) {
+
+       int X = x;
+       int Y = y;
+
+       if (clip) {
+           if ((x < clipLeft) || (x >= clipRight) ||
+               (y < clipTop) || (y >= clipBottom)) {
+               return;
+           }
+           X += offsetX;
+           Y += offsetY;
+       }
+
+       if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
+           dirty = true;
+           logical[X][Y].foreColor = attr.foreColor;
+           logical[X][Y].backColor = attr.backColor;
+           logical[X][Y].bold = attr.bold;
+           logical[X][Y].blink = attr.blink;
+           logical[X][Y].reverse = attr.reverse;
+           logical[X][Y].underline = attr.underline;
+           logical[X][Y].protect = attr.protect;
+       }
+    }
+
+    /**
+     * Fill the entire screen with one character with attributes.
+     *
+     * @param ch character to draw
+     * @param attr attributes to use (bold, foreColor, backColor)
+     */
+    public void putAll(char ch, CellAttributes attr) {
+       for (int x = 0; x < width; x++) {
+           for (int y = 0; y < height; y++) {
+               putCharXY(x, y, ch, attr);
+           }
+       }
+    }
+
+    /**
+     * Render one character with attributes.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param ch character + attributes to draw
+     */
+    public void putCharXY(int x, int y, Cell ch) {
+       putCharXY(x, y, ch.ch, ch);
+    }
+
+    /**
+     * Render one character with attributes.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param ch character to draw
+     * @param attr attributes to use (bold, foreColor, backColor)
+     */
+    public void putCharXY(int x, int y, char ch, CellAttributes attr) {
+       if ((x < clipLeft) || (x >= clipRight) ||
+           (y < clipTop) || (y >= clipBottom)) {
+           return;
+       }
+
+       int X = x + offsetX;
+       int Y = y + offsetY;
+
+       // stderr.writefln("putCharXY: %d, %d, %c", X, Y, ch);
+
+       if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
+           dirty = true;
+
+           // Do not put control characters on the display
+           assert(ch >= 0x20);
+           assert(ch != 0x7F);
+
+           logical[X][Y].ch = ch;
+           logical[X][Y].foreColor = attr.foreColor;
+           logical[X][Y].backColor = attr.backColor;
+           logical[X][Y].bold = attr.bold;
+           logical[X][Y].blink = attr.blink;
+           logical[X][Y].reverse = attr.reverse;
+           logical[X][Y].underline = attr.underline;
+           logical[X][Y].protect = attr.protect;
+       }
+    }
+
+    /**
+     * Render one character without changing the underlying attributes.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param ch character to draw
+     */
+    public void putCharXY(int x, int y, char ch) {
+       if ((x < clipLeft) || (x >= clipRight) ||
+           (y < clipTop) || (y >= clipBottom)) {
+           return;
+       }
+
+       int X = x + offsetX;
+       int Y = y + offsetY;
+
+       // stderr.writefln("putCharXY: %d, %d, %c", X, Y, ch);
+
+       if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
+           dirty = true;
+           logical[X][Y].ch = ch;
+       }
+    }
+
+    /**
+     * Render a string.  Does not wrap if the string exceeds the line.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param str string to draw
+     * @param attr attributes to use (bold, foreColor, backColor)
+     */
+    public void putStrXY(int x, int y, String str, CellAttributes attr) {
+       int i = x;
+       for (int j = 0; j < str.length(); j++) {
+           char ch = str.charAt(j);
+           putCharXY(i, y, ch, attr);
+           i++;
+           if (i == width) {
+               break;
+           }
+       }
+    }
+
+    /**
+     * Render a string without changing the underlying attribute.  Does not
+     * wrap if the string exceeds the line.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param str string to draw
+     */
+    public void putStrXY(int x, int y, String str) {
+       int i = x;
+       for (int j = 0; j < str.length(); j++) {
+           char ch = str.charAt(j);
+           putCharXY(i, y, ch);
+           i++;
+           if (i == width) {
+               break;
+           }
+       }
+    }
+
+    /**
+     * Draw a vertical line from (x, y) to (x, y + n)
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param n number of characters to draw
+     * @param ch character to draw
+     * @param attr attributes to use (bold, foreColor, backColor)
+     */
+    public void vLineXY(int x, int y, int n, char ch, CellAttributes attr) {
+       for (int i = y; i < y + n; i++) {
+           putCharXY(x, i, ch, attr);
+       }
+    }
+
+    /**
+     * Draw a horizontal line from (x, y) to (x + n, y)
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @param n number of characters to draw
+     * @param ch character to draw
+     * @param attr attributes to use (bold, foreColor, backColor)
+     */
+    public void hLineXY(int x, int y, int n, char ch, CellAttributes attr) {
+       for (int i = x; i < x + n; i++) {
+           putCharXY(i, y, ch, attr);
+       }
+    }
+
+    /**
+     * Reallocate screen buffers.
+     *
+     * @param width new width
+     * @param height new height
+     */
+    private void reallocate(int width, int height) {
+       if (logical != null) {
+           for (int row = 0; row < this.height; row++) {
+               for (int col = 0; col < this.width; col++) {
+                   logical[col][row] = null;
+               }
+           }
+           logical = null;
+       }
+       logical = new Cell[width][height];
+       if (physical != null) {
+           for (int row = 0; row < this.height; row++) {
+               for (int col = 0; col < this.width; col++) {
+                   physical[col][row] = null;
+               }
+           }
+           physical = null;
+       }
+       physical = new Cell[width][height];
+
+       for (int row = 0; row < height; row++) {
+           for (int col = 0; col < width; col++) {
+               physical[col][row] = new Cell();
+               logical[col][row] = new Cell();
+           }
+       }
+
+       this.width = width;
+       this.height = height;
+
+       clipLeft = 0;
+       clipTop = 0;
+       clipRight = width;
+       clipBottom = height;
+
+       reallyCleared = true;
+       dirty = true;
+    }
+
+    /**
+     * Change the width.  Everything on-screen will be destroyed and must be
+     * redrawn.
+     * 
+     * @param width new screen width
+     */
+    public void setWidth(int width) {
+       reallocate(width, this.height);
+    }
+
+    /**
+     * Change the height.  Everything on-screen will be destroyed and must be
+     * redrawn.
+     *
+     * @param height new screen height
+     */
+    public void setHeight(int height) {
+       reallocate(this.width, height);
+    }
+
+    /**
+     * Change the width and height.  Everything on-screen will be destroyed
+     * and must be redrawn.
+     *
+     * @param width new screen width
+     * @param height new screen height
+     */
+    public void setDimensions(int width, int height) {
+       reallocate(width, height);
+    }
+
+    /**
+     * Get the height.
+     *
+     * @return current screen height
+     */
+    public int getHeight() {
+       return this.height;
+    }
+
+    /**
+     * Get the width.
+     *
+     * @return current screen width
+     */
+    public int getWidth() {
+       return this.width;
+    }
+
+    /**
+     * Public constructor.  Sets everything to not-bold, white-on-black.
+     */
+    public Screen() {
+       debugToStderr = false;
+
+       offsetX  = 0;
+       offsetY  = 0;
+       width    = 80;
+       height   = 24;
+       logical  = null;
+       physical = null;
+       reallocate(width, height);
+    }
+
+    /**
+     * Reset screen to not-bold, white-on-black.  Also flushes the offset and
+     * clip variables.
+     */
+    public void reset() {
+       dirty = true;
+       for (int row = 0; row < height; row++) {
+           for (int col = 0; col < width; col++) {
+               logical[col][row].reset();
+           }
+       }
+       resetClipping();
+    }
+
+    /**
+     * Flush the offset and clip variables.
+     */
+    public void resetClipping() {
+       offsetX    = 0;
+       offsetY    = 0;
+       clipLeft   = 0;
+       clipTop    = 0;
+       clipRight  = width;
+       clipBottom = height;
+    }
+
+    /**
+     * Force the screen to be fully cleared and redrawn on the next flush().
+     */
+    public void clear() {
+       reset();
+    }
+
+    /**
+     * Draw a box with a border and empty background.
+     *
+     * @param left left column of box.  0 is the left-most row.
+     * @param top top row of the box.  0 is the top-most row.
+     * @param right right column of box
+     * @param bottom bottom row of the box
+     * @param border attributes to use for the border (bold, foreColor, backColor)
+     * @param background attributes to use for the background
+     */
+    public void drawBox(int left, int top, int right, int bottom,
+       CellAttributes border, CellAttributes background) {
+       drawBox(left, top, right, bottom, border, background, 1, false);
+    }
+
+    /**
+     * Draw a box with a border and empty background.
+     *
+     * @param left left column of box.  0 is the left-most row.
+     * @param top top row of the box.  0 is the top-most row.
+     * @param right right column of box
+     * @param bottom bottom row of the box
+     * @param border attributes to use for the border (bold, foreColor, backColor)
+     * @param background attributes to use for the background
+     * @param borderType = 1: single-line border
+     *                 2: double-line borders
+     *                 3: double-line top/bottom edges and single-line left/right edges
+     * @param shadow if true, draw a "shadow" on the box
+     */
+    public void drawBox(int left, int top, int right, int bottom,
+       CellAttributes border, CellAttributes background, int borderType,
+       boolean shadow) {
+
+       int boxTop = top;
+       int boxLeft = left;
+       int boxWidth = right - left;
+       int boxHeight = bottom - top;
+
+       char cTopLeft;
+       char cTopRight;
+       char cBottomLeft;
+       char cBottomRight;
+       char cHSide;
+       char cVSide;
+
+       switch (borderType) {
+       case 1:
+           cTopLeft = GraphicsChars.ULCORNER;
+           cTopRight = GraphicsChars.URCORNER;
+           cBottomLeft = GraphicsChars.LLCORNER;
+           cBottomRight = GraphicsChars.LRCORNER;
+           cHSide = GraphicsChars.SINGLE_BAR;
+           cVSide = GraphicsChars.WINDOW_SIDE;
+           break;
+
+       case 2:
+           cTopLeft = GraphicsChars.WINDOW_LEFT_TOP_DOUBLE;
+           cTopRight = GraphicsChars.WINDOW_RIGHT_TOP_DOUBLE;
+           cBottomLeft = GraphicsChars.WINDOW_LEFT_BOTTOM_DOUBLE;
+           cBottomRight = GraphicsChars.WINDOW_RIGHT_BOTTOM_DOUBLE;
+           cHSide = GraphicsChars.DOUBLE_BAR;
+           cVSide = GraphicsChars.WINDOW_SIDE_DOUBLE;
+           break;
+
+       case 3:
+           cTopLeft = GraphicsChars.WINDOW_LEFT_TOP;
+           cTopRight = GraphicsChars.WINDOW_RIGHT_TOP;
+           cBottomLeft = GraphicsChars.WINDOW_LEFT_BOTTOM;
+           cBottomRight = GraphicsChars.WINDOW_RIGHT_BOTTOM;
+           cHSide = GraphicsChars.WINDOW_TOP;
+           cVSide = GraphicsChars.WINDOW_SIDE;
+           break;
+       default:
+           throw new IllegalArgumentException("Invalid border type: " + borderType);
+       }
+
+       // Place the corner characters
+       putCharXY(left, top, cTopLeft, border);
+       putCharXY(left + boxWidth - 1, top, cTopRight, border);
+       putCharXY(left, top + boxHeight - 1, cBottomLeft, border);
+       putCharXY(left + boxWidth - 1, top + boxHeight - 1, cBottomRight,
+           border);
+
+       // Draw the box lines
+       hLineXY(left + 1, top, boxWidth - 2, cHSide, border);
+       vLineXY(left, top + 1, boxHeight - 2, cVSide, border);
+       hLineXY(left + 1, top + boxHeight - 1, boxWidth - 2, cHSide, border);
+       vLineXY(left + boxWidth - 1, top + 1, boxHeight - 2, cVSide, border);
+
+       // Fill in the interior background
+       for (int i = 1; i < boxHeight - 1; i++) {
+           hLineXY(1 + left, i + top, boxWidth - 2, ' ', background);
+       }
+
+       if (shadow) {
+           // Draw a shadow
+           drawBoxShadow(left, top, right, bottom);
+       }
+    }
+
+    /**
+     * Draw a box shadow
+     *
+     * @param left left column of box.  0 is the left-most row.
+     * @param top top row of the box.  0 is the top-most row.
+     * @param right right column of box
+     * @param bottom bottom row of the box
+     */
+    public void drawBoxShadow(int left, int top, int right, int bottom) {
+
+       int boxTop = top;
+       int boxLeft = left;
+       int boxWidth = right - left;
+       int boxHeight = bottom - top;
+       CellAttributes shadowAttr = new CellAttributes();
+
+       // Shadows do not honor clipping but they DO honor offset.
+       int oldClipRight = clipRight;
+       int oldClipBottom = clipBottom;
+       /*
+       clipRight = boxWidth + 2;
+       clipBottom = boxHeight + 1;
+       */
+       clipRight = width;
+       clipBottom = height;
+
+       for (int i = 0; i < boxHeight; i++) {
+           putAttrXY(boxLeft + boxWidth, boxTop + 1 + i, shadowAttr);
+           putAttrXY(boxLeft + boxWidth + 1, boxTop + 1 + i, shadowAttr);
+       }
+       for (int i = 0; i < boxWidth; i++) {
+           putAttrXY(boxLeft + 2 + i, boxTop + boxHeight, shadowAttr);
+       }
+       clipRight = oldClipRight;
+       clipBottom = oldClipBottom;
+    }
+
+    /**
+     * Subclasses must provide an implementation to push the logical screen
+     * to the physical device.
+     */
+    abstract public void flushPhysical();
+
+    /**
+     * Put the cursor at (x,y).
+     *
+     * @param visible if true, the cursor should be visible
+     * @param x column coordinate to put the cursor on
+     * @param y row coordinate to put the cursor on
+     */
+    public void putCursor(boolean visible, int x, int y) {
+       cursorVisible = visible;
+       cursorX = x;
+       cursorY = y;
+    }
+
+    /**
+     * Hide the cursor
+     */
+    public void hideCursor() {
+       cursorVisible = false;
+    }
+}
diff --git a/src/jexer/session/SessionInfo.java b/src/jexer/session/SessionInfo.java
new file mode 100644 (file)
index 0000000..0c10637
--- /dev/null
@@ -0,0 +1,78 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.session;
+
+/**
+ * SessionInfo is used to store per-session properties that are determined at
+ * different layers of the communication stack.
+ */
+public interface SessionInfo {
+
+    /**
+     * Username getter
+     *
+     * @return the username
+     */
+    public String getUsername();
+
+    /**
+     * Username setter
+     *
+     * @param username the value
+     */
+    public void setUsername(String username);
+
+    /**
+     * Language getter
+     *
+     * @return the language
+     */
+    public String getLanguage();
+
+    /**
+     * Language setter
+     *
+     * @param language the value
+     */
+    public void setLanguage(String language);
+
+    /**
+     * Text window width getter
+     */
+    public int getWindowWidth();
+
+    /**
+     * Text window height getter
+     */
+    public int getWindowHeight();
+}
diff --git a/src/jexer/session/TSessionInfo.java b/src/jexer/session/TSessionInfo.java
new file mode 100644 (file)
index 0000000..a0dc75c
--- /dev/null
@@ -0,0 +1,110 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * Version: $Id$
+ *
+ * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
+ *
+ * License: LGPLv3 or later
+ *
+ * Copyright: This module is licensed under the GNU Lesser General
+ * Public License Version 3.  Please see the file "COPYING" in this
+ * directory for more information about the GNU Lesser General Public
+ * License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package jexer.session;
+
+/**
+ * TSessionInfo provides a default session implementation.  The username is
+ * blank, language is "en_US", with a 80x24 text window.
+ */
+public class TSessionInfo implements SessionInfo {
+
+    /**
+     * User name
+     */
+    private String username = "";
+
+    /**
+     * Language
+     */
+    private String language = "en_US";
+
+    /**
+     * Text window width
+     */
+    private int windowWidth = 80;
+
+    /**
+     * Text window height
+     */
+    private int windowHeight = 24;
+
+    /**
+     * Username getter
+     *
+     * @return the username
+     */
+    public String getUsername() {
+       return this.username;
+    }
+
+    /**
+     * Username setter
+     *
+     * @param username the value
+     */
+    public void setUsername(String username) {
+       this.username = username;
+    }
+
+    /**
+     * Language getter
+     *
+     * @return the language
+     */
+    public String getLanguage() {
+       return this.language;
+    }
+
+    /**
+     * Language setter
+     *
+     * @param language the value
+     */
+    public void setLanguage(String language) {
+       this.language = language;
+    }
+
+    /**
+     * Text window width getter
+     */
+    public int getWindowWidth() {
+       return windowWidth;
+    }
+
+    /**
+     * Text window height getter
+     */
+    public int getWindowHeight() {
+       return windowHeight;
+    }
+}