TButton and TLabel
authorKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 14 Mar 2015 16:21:03 +0000 (12:21 -0400)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 14 Mar 2015 16:21:03 +0000 (12:21 -0400)
Makefile
README.md
demos/Demo1.java
src/jexer/TAction.java [new file with mode: 0644]
src/jexer/TButton.java [new file with mode: 0644]
src/jexer/TLabel.java [new file with mode: 0644]
src/jexer/TWidget.java
src/jexer/TWindow.java

index c55438d32b371524fccd83ef8bef5be5e35fa952..0ba0eb4b3d61228c90d0cb576211b32694591afd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -39,6 +39,9 @@ ANT_TARGET_DIR = build
 TARGET_DIR = classes
 
 JEXER_SRC = $(SRC_DIR)/jexer/TApplication.java \
+       $(SRC_DIR)/jexer/TAction.java \
+       $(SRC_DIR)/jexer/TButton.java \
+       $(SRC_DIR)/jexer/TLabel.java \
        $(SRC_DIR)/jexer/TCommand.java \
        $(SRC_DIR)/jexer/TKeypress.java \
        $(SRC_DIR)/jexer/THScroller.java \
@@ -56,6 +59,10 @@ JEXER_SRC = $(SRC_DIR)/jexer/TApplication.java \
        $(SRC_DIR)/jexer/event/TMenuEvent.java \
        $(SRC_DIR)/jexer/event/TMouseEvent.java \
        $(SRC_DIR)/jexer/event/TResizeEvent.java \
+       $(SRC_DIR)/jexer/menu/TMenu.java \
+       $(SRC_DIR)/jexer/menu/TMenuItem.java \
+       $(SRC_DIR)/jexer/menu/TMenuSeparator.java \
+       $(SRC_DIR)/jexer/menu/TSubMenu.java \
        $(SRC_DIR)/jexer/session/SessionInfo.java \
        $(SRC_DIR)/jexer/session/TSessionInfo.java \
        $(SRC_DIR)/jexer/session/TTYSessionInfo.java \
@@ -66,6 +73,9 @@ JEXER_SRC = $(SRC_DIR)/jexer/TApplication.java \
        $(SRC_DIR)/jexer/backend/ECMA48Backend.java
 
 JEXER_BIN = $(TARGET_DIR)/jexer/TApplication.class \
+       $(TARGET_DIR)/jexer/TAction.class \
+       $(TARGET_DIR)/jexer/TButton.class \
+       $(TARGET_DIR)/jexer/TLabel.class \
        $(TARGET_DIR)/jexer/TCommand.class \
        $(TARGET_DIR)/jexer/TKeypress.class \
        $(TARGET_DIR)/jexer/THScroller.class \
@@ -83,6 +93,10 @@ JEXER_BIN = $(TARGET_DIR)/jexer/TApplication.class \
        $(TARGET_DIR)/jexer/event/TMenuEvent.class \
        $(TARGET_DIR)/jexer/event/TMouseEvent.class \
        $(TARGET_DIR)/jexer/event/TResizeEvent.class \
+       $(TARGET_DIR)/jexer/menu/TMenu.class \
+       $(TARGET_DIR)/jexer/menu/TMenuItem.class \
+       $(TARGET_DIR)/jexer/menu/TMenuSeparator.class \
+       $(TARGET_DIR)/jexer/menu/TSubMenu.class \
        $(TARGET_DIR)/jexer/session/SessionInfo.class \
        $(TARGET_DIR)/jexer/session/TSessionInfo.class \
        $(TARGET_DIR)/jexer/session/TTYSessionInfo.class \
index f097e77844ef40e149c469489008caffaf1a8c1c..2e9ef73bec5b45ab70e55807bffb0b93f1b76933 100644 (file)
--- a/README.md
+++ b/README.md
@@ -54,12 +54,10 @@ public class MyApplication extends TApplication {
 Roadmap
 -------
 
-This is a work in progress.  Many tasks remain before calling this
-version 1.0:
+Many tasks remain before calling this version 1.0:
 
 0.0.1:
 
-- TButton
 - TCheckbox
 - TDirectoryList
 - TField
index 4c7f631d042ba2f43295e486bfb1afd285709a58..5d5485a83fe4fb529bc751bcecb23cb30d2cb777 100644 (file)
 import jexer.*;
 import jexer.menu.*;
 
+class DemoMsgBoxWindow extends TWindow {
+    /*
+    private void openYNCMessageBox() {
+       application.messageBox("Yes/No/Cancel MessageBox",
+           q"EOS
+This is an example of a Yes/No/Cancel MessageBox.
+
+Note that the MessageBox text can span multiple
+lines.
+
+The default result (if someone hits the top-left
+close button) is CANCEL.
+EOS",
+       TMessageBox.Type.YESNOCANCEL);
+    }
+
+    private void openYNMessageBox() {
+       application.messageBox("Yes/No MessageBox",
+           q"EOS
+This is an example of a Yes/No MessageBox.
+
+Note that the MessageBox text can span multiple
+lines.
+
+The default result (if someone hits the top-left
+close button) is NO.
+EOS",
+       TMessageBox.Type.YESNO);
+    }
+
+    private void openOKCMessageBox() {
+       application.messageBox("OK/Cancel MessageBox",
+           q"EOS
+This is an example of a OK/Cancel MessageBox.
+
+Note that the MessageBox text can span multiple
+lines.
+
+The default result (if someone hits the top-left
+close button) is CANCEL.
+EOS",
+       TMessageBox.Type.OKCANCEL);
+    }
+
+    private void openOKMessageBox() {
+       application.messageBox("OK MessageBox",
+           q"EOS
+This is an example of a OK MessageBox.  This is the
+default MessageBox.
+
+Note that the MessageBox text can span multiple
+lines.
+
+The default result (if someone hits the top-left
+close button) is OK.
+EOS",
+       TMessageBox.Type.OK);
+    }
+
+     */
+
+    /**
+     * Constructor.
+     */
+    DemoMsgBoxWindow(final TApplication parent) {
+       this(parent, TWindow.CENTERED | TWindow.RESIZABLE);
+    }
+
+    /**
+     * Constructor.
+     */
+    DemoMsgBoxWindow(final TApplication parent, final int flags) {
+       // Construct a demo window.  X and Y don't matter because it
+       // will be centered on screen.
+       super(parent, "Message Boxes", 0, 0, 60, 15, flags);
+        /*
+       uint row = 1;
+
+       // Add some widgets
+       addLabel("Default OK message box", 1, row);
+       addButton("Open O&K MB", 35, row, &openOKMessageBox);
+       row += 2;
+
+       addLabel("OK/Cancel message box", 1, row);
+       addButton("O&pen OKC MB", 35, row, &openOKCMessageBox);
+       row += 2;
+
+       addLabel("Yes/No message box", 1, row);
+       addButton("Open &YN MB", 35, row, &openYNMessageBox);
+       row += 2;
+
+       addLabel("Yes/No/Cancel message box", 1, row);
+       addButton("Ope&n YNC MB", 35, row, &openYNCMessageBox);
+       row += 2;
+
+       addLabel("Input box", 1, row);
+       addButton("Open &input box", 35, row,
+           {
+               application.inputBox("Input Box",
+           q"EOS
+This is an example of an InputBox.
+
+Note that the InputBox text can span multiple
+lines.
+EOS",
+                   "some input text");
+           }
+       );
+
+       addButton("&Close Window", (width - 14) / 2, height - 4,
+           {
+               application.closeWindow(this);
+           }
+       );
+         */
+    }
+}
+
+
 class DemoMainWindow extends TWindow {
     /*
     // Timer that increments a number
@@ -83,20 +202,22 @@ class DemoMainWindow extends TWindow {
         // centered on screen.
         super(parent, "Demo Window", 0, 0, 60, 23, flags);
 
-        /*
         int row = 1;
 
         // Add some widgets
-        if (!isModal) {
+        if (!isModal()) {
             addLabel("Message Boxes", 1, row);
             addButton("&MessageBoxes", 35, row,
-                {
-                    new DemoMsgBoxWindow(application);
+                new TAction() {
+                    public void DO() {
+                        new DemoMsgBoxWindow(getApplication());
+                    }
                 }
             );
         }
         row += 2;
 
+        /*
         addLabel("Open me as modal", 1, row);
         addButton("W&indow", 35, row,
             {
@@ -192,14 +313,6 @@ class DemoApplication extends TApplication {
         super(null, null);
         new DemoMainWindow(this);
 
-        // TEMPORARY
-        TWindow window2 = new DemoMainWindow(this);
-        window2.setHeight(5);
-        window2.setWidth(25);
-        window2.setX(17);
-        window2.setY(6);
-        // TEMPORARY
-
         // Add the menus
         addFileMenu();
         addEditMenu();
diff --git a/src/jexer/TAction.java b/src/jexer/TAction.java
new file mode 100644 (file)
index 0000000..2ce8a39
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * License: LGPLv3 or later
+ *
+ * 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
+ *
+ * @author Kevin Lamonte [kevin.lamonte@gmail.com]
+ * @version 1
+ */
+package jexer;
+
+/**
+ * A TAction represents a simple action to perform in response to the user.
+ *
+ * @see TButton
+ */
+public abstract class TAction {
+    /**
+     * Various classes will call DO() when they are clicked/selected.
+     */
+    public abstract void DO();
+}
+
diff --git a/src/jexer/TButton.java b/src/jexer/TButton.java
new file mode 100644 (file)
index 0000000..24ee94c
--- /dev/null
@@ -0,0 +1,245 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * License: LGPLv3 or later
+ *
+ * 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
+ *
+ * @author Kevin Lamonte [kevin.lamonte@gmail.com]
+ * @version 1
+ */
+package jexer;
+
+import jexer.bits.CellAttributes;
+import jexer.bits.Color;
+import jexer.bits.GraphicsChars;
+import jexer.bits.MnemonicString;
+import jexer.event.TKeypressEvent;
+import jexer.event.TMouseEvent;
+import static jexer.TKeypress.*;
+
+/**
+ * TButton implements a simple button.  To make the button do something, pass
+ * a TAction class to its constructor.
+ *
+ * @see TAction#DO()
+ */
+public final class TButton extends TWidget {
+
+    /**
+     * The shortcut and button text.
+     */
+    private MnemonicString mnemonic;
+
+    /**
+     * Remember mouse state.
+     */
+    private TMouseEvent mouse;
+
+    /**
+     * True when the button is being pressed and held down.
+     */
+    private boolean inButtonPress = false;
+
+    /**
+     * The action to perform when the button is clicked.
+     */
+    private TAction action;
+
+    /**
+     * Private constructor.
+     *
+     * @param parent parent widget
+     * @param text label on the button
+     * @param x column relative to parent
+     * @param y row relative to parent
+     */
+    private TButton(final TWidget parent, final String text,
+        final int x, final int y) {
+
+        // Set parent and window
+        super(parent);
+
+        mnemonic = new MnemonicString(text);
+
+        setX(x);
+        setY(y);
+        setHeight(2);
+        setWidth(mnemonic.getRawLabel().length() + 3);
+    }
+
+    /**
+     * Public constructor.
+     *
+     * @param parent parent widget
+     * @param text label on the button
+     * @param x column relative to parent
+     * @param y row relative to parent
+     * @param action to call when button is pressed
+     */
+    public TButton(final TWidget parent, final String text,
+        final int x, final int y, final TAction action) {
+
+        this(parent, text, x, y);
+        this.action = action;
+    }
+
+    /**
+     * Returns true if the mouse is currently on the button.
+     *
+     * @return if true the mouse is currently on the button
+     */
+    private boolean mouseOnButton() {
+        int rightEdge = getWidth() - 1;
+        if (inButtonPress) {
+            rightEdge++;
+        }
+        if ((mouse != null)
+            && (mouse.getY() == 0)
+            && (mouse.getX() >= 0)
+            && (mouse.getX() < rightEdge)
+        ) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Draw a button with a shadow.
+     */
+    @Override
+    public void draw() {
+        CellAttributes buttonColor;
+        CellAttributes menuMnemonicColor;
+        CellAttributes shadowColor = new CellAttributes();
+        shadowColor.setTo(getWindow().getBackground());
+        shadowColor.setForeColor(Color.BLACK);
+        shadowColor.setBold(false);
+
+        if (!getEnabled()) {
+            buttonColor = getTheme().getColor("tbutton.disabled");
+            menuMnemonicColor = getTheme().getColor("tbutton.disabled");
+        } else if (getAbsoluteActive()) {
+            buttonColor = getTheme().getColor("tbutton.active");
+            menuMnemonicColor = getTheme().getColor("tbutton.mnemonic.highlighted");
+        } else {
+            buttonColor = getTheme().getColor("tbutton.inactive");
+            menuMnemonicColor = getTheme().getColor("tbutton.mnemonic");
+        }
+
+        if (inButtonPress) {
+            getScreen().putCharXY(1, 0, ' ', buttonColor);
+            getScreen().putStrXY(2, 0, mnemonic.getRawLabel(), buttonColor);
+            getScreen().putCharXY(getWidth() - 1, 0, ' ', buttonColor);
+        } else {
+            getScreen().putCharXY(0, 0, ' ', buttonColor);
+            getScreen().putStrXY(1, 0, mnemonic.getRawLabel(), buttonColor);
+            getScreen().putCharXY(getWidth() - 2, 0, ' ', buttonColor);
+
+            getScreen().putCharXY(getWidth() - 1, 0,
+                GraphicsChars.CP437[0xDC], shadowColor);
+            getScreen().hLineXY(1, 1, getWidth() - 1,
+                GraphicsChars.CP437[0xDF], shadowColor);
+        }
+        if (mnemonic.getShortcutIdx() >= 0) {
+            if (inButtonPress) {
+                getScreen().putCharXY(2 + mnemonic.getShortcutIdx(), 0,
+                    mnemonic.getShortcut(), menuMnemonicColor);
+            } else {
+                getScreen().putCharXY(1 + mnemonic.getShortcutIdx(), 0,
+                    mnemonic.getShortcut(), menuMnemonicColor);
+            }
+
+        }
+    }
+
+    /**
+     * Handle mouse button presses.
+     *
+     * @param mouse mouse button event
+     */
+    @Override
+    public void onMouseDown(final TMouseEvent mouse) {
+        this.mouse = mouse;
+
+        if ((mouseOnButton()) && (mouse.getMouse1())) {
+            // Begin button press
+            inButtonPress = true;
+        }
+    }
+
+    /**
+     * Handle mouse button releases.
+     *
+     * @param mouse mouse button release event
+     */
+    @Override
+    public void onMouseUp(final TMouseEvent mouse) {
+        this.mouse = mouse;
+
+        if (inButtonPress && mouse.getMouse1()) {
+            inButtonPress = false;
+            // Dispatch the event
+            if (action != null) {
+                action.DO();
+            }
+        }
+
+    }
+
+    /**
+     * Handle mouse movements.
+     *
+     * @param mouse mouse motion event
+     */
+    @Override
+    public void onMouseMotion(final TMouseEvent mouse) {
+        this.mouse = mouse;
+
+        if (!mouseOnButton()) {
+            inButtonPress = false;
+        }
+    }
+
+    /**
+     * Handle keystrokes.
+     *
+     * @param keypress keystroke event
+     */
+    @Override
+    public void onKeypress(final TKeypressEvent keypress) {
+        if (keypress.equals(kbEnter)
+            || keypress.equals(kbSpace)
+        ) {
+            // Dispatch
+            if (action != null) {
+                action.DO();
+            }
+            return;
+        }
+
+        // Pass to parent for the things we don't care about.
+        super.onKeypress(keypress);
+    }
+
+}
diff --git a/src/jexer/TLabel.java b/src/jexer/TLabel.java
new file mode 100644 (file)
index 0000000..15d6376
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * License: LGPLv3 or later
+ *
+ * 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
+ *
+ * @author Kevin Lamonte [kevin.lamonte@gmail.com]
+ * @version 1
+ */
+package jexer;
+
+import jexer.bits.CellAttributes;
+
+/**
+ * TLabel implements a simple label.
+ */
+public final class TLabel extends TWidget {
+
+    /**
+     * Label text.
+     */
+    private String text = "";
+
+    /**
+     * Label color.
+     */
+    private String colorKey;
+
+    /**
+     * Public constructor, using the default "tlabel" for colorKey.
+     *
+     * @param parent parent widget
+     * @param text label on the screen
+     * @param x column relative to parent
+     * @param y row relative to parent
+     */
+    public TLabel(final TWidget parent, final String text, final int x,
+        final int y) {
+
+        this(parent, text, x, y, "tlabel");
+    }
+
+    /**
+     * Public constructor.
+     *
+     * @param parent parent widget
+     * @param text label on the screen
+     * @param x column relative to parent
+     * @param y row relative to parent
+     * @param colorKey ColorTheme key color to use for foreground text
+     */
+    public TLabel(final TWidget parent, final String text, final int x,
+        final int y, final String colorKey) {
+
+        // Set parent and window
+        super(parent, false);
+
+        this.text = text;
+        setX(x);
+        setY(y);
+        setHeight(1);
+        setWidth(text.length());
+        this.colorKey = colorKey;
+    }
+
+    /**
+     * Draw a static label.
+     */
+    @Override public void draw() {
+        // Setup my color
+        CellAttributes color = new CellAttributes();
+        color.setTo(getTheme().getColor(colorKey));
+        CellAttributes background = getWindow().getBackground();
+        color.setBackColor(background.getBackColor());
+
+        getScreen().putStrXY(0, 0, text, color);
+    }
+
+}
index d0c6b8177dac3a818ea8a0554f86d813fb356d3b..17f7849631f5bd087f536cf48f4068bf211447b7 100644 (file)
@@ -158,6 +158,15 @@ public abstract class TWidget {
      */
     private TWindow window = null;
 
+    /**
+     * Get the window this widget is on.
+     *
+     * @return the window
+     */
+    public final TWindow getWindow() {
+        return window;
+    }
+
     /**
      * Absolute X position of the top-left corner.
      */
@@ -483,6 +492,17 @@ public abstract class TWidget {
      * @param parent parent widget
      */
     protected TWidget(final TWidget parent) {
+        this(parent, true);
+    }
+
+    /**
+     * Protected constructor used by subclasses that are disabled by default.
+     *
+     * @param parent parent widget
+     * @param enabled if true assume enabled
+     */
+    protected TWidget(final TWidget parent, final boolean enabled) {
+        this.enabled = enabled;
         this.parent = parent;
         this.window = parent.window;
         children = new LinkedList<TWidget>();
@@ -886,4 +906,48 @@ public abstract class TWidget {
         return false;
     }
 
+    /**
+     * Convenience function to add a label to this container/window.
+     *
+     * @param text label
+     * @param x column relative to parent
+     * @param y row relative to parent
+     * @return the new label
+     */
+    public final TLabel addLabel(final String text, final int x, final int y) {
+        return addLabel(text, x, y, "tlabel");
+    }
+
+    /**
+     * Convenience function to add a label to this container/window.
+     *
+     * @param text label
+     * @param x column relative to parent
+     * @param y row relative to parent
+     * @param colorKey ColorTheme key color to use for foreground text.
+     * Default is "tlabel"
+     * @return the new label
+     */
+    public final TLabel addLabel(final String text, final int x, final int y,
+        final String colorKey) {
+
+        return new TLabel(this, text, x, y, colorKey);
+    }
+
+    /**
+     * Convenience function to add a button to this container/window.
+     *
+     * @param text label on the button
+     * @param x column relative to parent
+     * @param y row relative to parent
+     * @param action to call when button is pressed
+     * @return the new button
+     */
+    public final TButton addButton(final String text, final int x, final int y,
+        final TAction action) {
+
+        return new TButton(this, text, x, y, action);
+    }
+
+
 }
index 8634b2a9227c2e1bb17ab0ae01b08fcbd5268fff..d57b844d7d4408c4c14c70e4076914782bc90f4a 100644 (file)
@@ -372,7 +372,7 @@ public class TWindow extends TWidget implements Comparable<TWindow> {
      *
      * @return the background color
      */
-    private CellAttributes getBackground() {
+    public final CellAttributes getBackground() {
         if (!isModal()
             && (inWindowMove || inWindowResize || inKeyboardResize)
         ) {