From 30d336cc33e26af877f7950b93f3b77d9c3a3bd3 Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Sat, 14 Mar 2015 12:21:03 -0400 Subject: [PATCH] TButton and TLabel --- Makefile | 14 +++ README.md | 4 +- demos/Demo1.java | 137 +++++++++++++++++++++-- src/jexer/TAction.java | 44 ++++++++ src/jexer/TButton.java | 245 +++++++++++++++++++++++++++++++++++++++++ src/jexer/TLabel.java | 100 +++++++++++++++++ src/jexer/TWidget.java | 64 +++++++++++ src/jexer/TWindow.java | 2 +- 8 files changed, 594 insertions(+), 16 deletions(-) create mode 100644 src/jexer/TAction.java create mode 100644 src/jexer/TButton.java create mode 100644 src/jexer/TLabel.java diff --git a/Makefile b/Makefile index c55438d..0ba0eb4 100644 --- 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 \ diff --git a/README.md b/README.md index f097e77..2e9ef73 100644 --- 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 diff --git a/demos/Demo1.java b/demos/Demo1.java index 4c7f631..5d5485a 100644 --- a/demos/Demo1.java +++ b/demos/Demo1.java @@ -34,6 +34,125 @@ 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 index 0000000..2ce8a39 --- /dev/null +++ b/src/jexer/TAction.java @@ -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 index 0000000..24ee94c --- /dev/null +++ b/src/jexer/TButton.java @@ -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 index 0000000..15d6376 --- /dev/null +++ b/src/jexer/TLabel.java @@ -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); + } + +} diff --git a/src/jexer/TWidget.java b/src/jexer/TWidget.java index d0c6b81..17f7849 100644 --- a/src/jexer/TWidget.java +++ b/src/jexer/TWidget.java @@ -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(); @@ -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); + } + + } diff --git a/src/jexer/TWindow.java b/src/jexer/TWindow.java index 8634b2a..d57b844 100644 --- a/src/jexer/TWindow.java +++ b/src/jexer/TWindow.java @@ -372,7 +372,7 @@ public class TWindow extends TWidget implements Comparable { * * @return the background color */ - private CellAttributes getBackground() { + public final CellAttributes getBackground() { if (!isModal() && (inWindowMove || inWindowResize || inKeyboardResize) ) { -- 2.27.0