From c6940ed922d1c4e06bf30fd57a50e43f0720e60c Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Sun, 15 Mar 2015 19:34:47 -0400 Subject: [PATCH 1/1] message box and input box --- README.md | 2 - src/jexer/TApplication.java | 299 +++++++++++++++++++++++++-------- src/jexer/TInputBox.java | 106 ++++++++++++ src/jexer/TMessageBox.java | 320 ++++++++++++++++++++++++++++++++++++ src/jexer/TWidget.java | 61 ++++++- src/jexer/demos/Demo1.java | 163 +++++++++--------- 6 files changed, 794 insertions(+), 157 deletions(-) create mode 100644 src/jexer/TInputBox.java create mode 100644 src/jexer/TMessageBox.java diff --git a/README.md b/README.md index e2af305..353fc47 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,6 @@ Many tasks remain before calling this version 1.0: 0.0.1: -- TMessageBox -- TInputBox - AWTBackend 0.0.2: diff --git a/src/jexer/TApplication.java b/src/jexer/TApplication.java index 8786e69..f4b7997 100644 --- a/src/jexer/TApplication.java +++ b/src/jexer/TApplication.java @@ -36,6 +36,7 @@ import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -62,6 +63,107 @@ import static jexer.TKeypress.*; */ public class TApplication { + /** + * WidgetEventHandler is the main event consumer loop. There are at most + * two such threads in existence: the primary for normal case and a + * secondary that is used for TMessageBox, TInputBox, and similar. + */ + private class WidgetEventHandler implements Runnable { + /** + * The main application. + */ + private TApplication application; + + /** + * Whether or not this WidgetEventHandler is the primary or secondary + * thread. + */ + private boolean primary = true; + + /** + * Public constructor. + * + * @param application the main application + * @param primary if true, this is the primary event handler thread + */ + public WidgetEventHandler(final TApplication application, + final boolean primary) { + + this.application = application; + this.primary = primary; + } + + /** + * The consumer loop. + */ + public void run() { + + // Loop forever + while (!application.quit) { + + // Wait until application notifies me + while (!application.quit) { + try { + synchronized (application.drainEventQueue) { + if (application.drainEventQueue.size() > 0) { + break; + } + } + synchronized (application) { + application.wait(); + if ((!primary) + && (application.secondaryEventReceiver == null) + ) { + // Secondary thread, time to exit + return; + } + break; + } + } catch (InterruptedException e) { + // SQUASH + } + } + + // Pull all events off the queue + for (;;) { + TInputEvent event = null; + synchronized (application.drainEventQueue) { + if (application.drainEventQueue.size() == 0) { + break; + } + event = application.drainEventQueue.remove(0); + } + if (primary) { + primaryHandleEvent(event); + } else { + secondaryHandleEvent(event); + } + if ((!primary) + && (application.secondaryEventReceiver == null) + ) { + // Secondary thread, time to exit + return; + } + } + } // while (true) (main runnable loop) + } + } + + /** + * The primary event handler thread. + */ + private WidgetEventHandler primaryEventHandler; + + /** + * The secondary event handler thread. + */ + private WidgetEventHandler secondaryEventHandler; + + /** + * The widget receiving events from the secondary event handler thread. + */ + private TWidget secondaryEventReceiver; + /** * Access to the physical screen, keyboard, and mouse. */ @@ -212,13 +314,17 @@ public class TApplication { backend = new ECMA48Backend(input, output); theme = new ColorTheme(); desktopBottom = getScreen().getHeight() - 1; - fillEventQueue = new LinkedList(); - drainEventQueue = new LinkedList(); + fillEventQueue = new ArrayList(); + drainEventQueue = new ArrayList(); windows = new LinkedList(); menus = new LinkedList(); subMenus = new LinkedList(); timers = new LinkedList(); accelerators = new HashMap(); + + // Setup the main consumer thread + primaryEventHandler = new WidgetEventHandler(this, true); + (new Thread(primaryEventHandler)).start(); } /** @@ -378,25 +484,11 @@ public class TApplication { drawAll(); } - /* - - // Shutdown the fibers - eventQueue.length = 0; - if (secondaryEventFiber !is null) { - assert(secondaryEventReceiver !is null); - secondaryEventReceiver = null; - if (secondaryEventFiber.state == Fiber.State.HOLD) { - // Wake up the secondary handler so that it can exit. - secondaryEventFiber.call(); - } + // Shutdown the consumer threads + synchronized (this) { + this.notifyAll(); } - if (primaryEventFiber.state == Fiber.State.HOLD) { - // Wake up the primary handler so that it can exit. - primaryEventFiber.call(); - } - */ - backend.shutdown(); } @@ -452,29 +544,17 @@ public class TApplication { } } - // TODO: change to two separate threads - primaryHandleEvent(event); - - /* - // Put into the main queue - addEvent(event); - - // Have one of the two consumer Fibers peel the events off - // the queue. - if (secondaryEventFiber !is null) { - assert(secondaryEventFiber.state == Fiber.State.HOLD); - - // Wake up the secondary handler for these events - secondaryEventFiber.call(); - } else { - assert(primaryEventFiber.state == Fiber.State.HOLD); - - // Wake up the primary handler for these events - primaryEventFiber.call(); - } - */ + synchronized (drainEventQueue) { + drainEventQueue.add(event); + } + // Wake all threads: primary thread will either be consuming events + // again or waiting in yield(), and secondary thread will either not + // exist or consuming events. + synchronized (this) { + this.notifyAll(); + } } /** @@ -595,7 +675,40 @@ public class TApplication { * @see #primaryHandleEvent(TInputEvent event) */ private void secondaryHandleEvent(final TInputEvent event) { - // TODO + secondaryEventReceiver.handleEvent(event); + } + + /** + * Enable a widget to override the primary event thread. + * + * @param widget widget that will receive events + */ + public final void enableSecondaryEventReceiver(final TWidget widget) { + assert (secondaryEventReceiver == null); + assert (secondaryEventHandler == null); + assert (widget instanceof TMessageBox); + secondaryEventReceiver = widget; + secondaryEventHandler = new WidgetEventHandler(this, false); + (new Thread(secondaryEventHandler)).start(); + + // Refresh + repaint = true; + } + + /** + * Yield to the secondary thread. + */ + public final void yield() { + assert (secondaryEventReceiver != null); + while (secondaryEventReceiver != null) { + synchronized (this) { + try { + this.wait(); + } catch (InterruptedException e) { + // SQUASH + } + } + } } /** @@ -608,7 +721,7 @@ public class TApplication { for (TTimer timer: timers) { if (timer.getNextTick().getTime() < now.getTime()) { timer.tick(); - if (timer.recurring == true) { + if (timer.recurring) { keepTimers.add(timer); } } else { @@ -677,32 +790,20 @@ public class TApplication { // Refresh screen repaint = true; - /* - TODO - - // Check if we are closing a TMessageBox or similar - if (secondaryEventReceiver !is null) { - assert(secondaryEventFiber !is null); + if (secondaryEventReceiver != null) { + assert (secondaryEventHandler != null); // Do not send events to the secondaryEventReceiver anymore, the // window is closed. secondaryEventReceiver = null; - // Special case: if this is called while executing on a - // secondaryEventFiber, call it so that widgetEventHandler() can - // terminate. - if (secondaryEventFiber.state == Fiber.State.HOLD) { - secondaryEventFiber.call(); - } - secondaryEventFiber = null; - - // Unfreeze the logic in handleEvent() - if (primaryEventFiber.state == Fiber.State.HOLD) { - primaryEventFiber.call(); + // Wake all threads: primary thread will be consuming events + // again, and secondary thread will exit. + synchronized (this) { + this.notifyAll(); } } - */ } /** @@ -993,23 +1094,24 @@ public class TApplication { * @return if true, this event was consumed */ protected boolean onCommand(final TCommandEvent command) { - /* - TODO // Default: handle cmExit if (command.equals(cmExit)) { if (messageBox("Confirmation", "Exit application?", - TMessageBox.Type.YESNO).result == TMessageBox.Result.YES) { + TMessageBox.Type.YESNO).getResult() == TMessageBox.Result.YES) { quit = true; } repaint = true; return true; } + /* + TODO if (command.equals(cmShell)) { openTerminal(0, 0, TWindow.Flag.RESIZABLE); repaint = true; return true; } + */ if (command.equals(cmTile)) { tileWindows(); @@ -1026,7 +1128,7 @@ public class TApplication { repaint = true; return true; } - */ + return false; } @@ -1041,19 +1143,13 @@ public class TApplication { // Default: handle MID_EXIT if (menu.getId() == TMenu.MID_EXIT) { - /* - TODO if (messageBox("Confirmation", "Exit application?", - TMessageBox.Type.YESNO).result == TMessageBox.Result.YES) { + TMessageBox.Type.YESNO).getResult() == TMessageBox.Result.YES) { quit = true; } // System.err.printf("onMenu MID_EXIT result: quit = %s\n", quit); repaint = true; return true; - */ - quit = true; - repaint = true; - return true; } /* @@ -1213,7 +1309,7 @@ public class TApplication { * * @return the new menu */ - final public TMenu addWindowMenu() { + public final TMenu addWindowMenu() { TMenu windowMenu = addMenu("&Window"); windowMenu.addDefaultItem(TMenu.MID_TILE); windowMenu.addDefaultItem(TMenu.MID_CASCADE); @@ -1330,6 +1426,7 @@ public class TApplication { * @param duration number of milliseconds to wait between ticks * @param recurring if true, re-schedule this timer after every tick * @param action function to call when button is pressed + * @return the timer */ public final TTimer addTimer(final long duration, final boolean recurring, final TAction action) { @@ -1352,4 +1449,62 @@ public class TApplication { } } + /** + * Convenience function to spawn a message box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @return the new message box + */ + public final TMessageBox messageBox(final String title, + final String caption) { + + return new TMessageBox(this, title, caption, TMessageBox.Type.OK); + } + + /** + * Convenience function to spawn a message box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param type one of the TMessageBox.Type constants. Default is + * Type.OK. + * @return the new message box + */ + public final TMessageBox messageBox(final String title, + final String caption, final TMessageBox.Type type) { + + return new TMessageBox(this, title, caption, type); + } + + /** + * Convenience function to spawn an input box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @return the new input box + */ + public final TInputBox inputBox(final String title, final String caption) { + + return new TInputBox(this, title, caption); + } + + /** + * Convenience function to spawn an input box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param text initial text to seed the field with + * @return the new input box + */ + public final TInputBox inputBox(final String title, final String caption, + final String text) { + + return new TInputBox(this, title, caption, text); + } + } diff --git a/src/jexer/TInputBox.java b/src/jexer/TInputBox.java new file mode 100644 index 0000000..7f030d7 --- /dev/null +++ b/src/jexer/TInputBox.java @@ -0,0 +1,106 @@ +/** + * 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; + +/** + * TInputBox is a system-modal dialog with an OK button and a text input + * field. Call it like: + * + *

+ *

+ * {@code
+ *     box = application.inputBox(title, caption);
+ *     if (box.getText().equals("yes")) {
+ *         ... the user entered "yes", do stuff ...
+ *     }
+ * }
+ * 
+ * + */ +public final class TInputBox extends TMessageBox { + + /** + * The input field. + */ + private TField field; + + /** + * Retrieve the answer text. + * + * @return the answer text + */ + public String getText() { + return field.getText(); + } + + /** + * Public constructor. The input box will be centered on screen. + * + * @param application TApplication that manages this window + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + */ + public TInputBox(final TApplication application, final String title, + final String caption) { + + this(application, title, caption, ""); + } + + /** + * Public constructor. The input box will be centered on screen. + * + * @param application TApplication that manages this window + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param text initial text to seed the field with + */ + public TInputBox(final TApplication application, final String title, + final String caption, final String text) { + + super(application, title, caption, Type.OK, false); + + for (TWidget widget: getChildren()) { + if (widget instanceof TButton) { + widget.setY(widget.getY() + 2); + } + } + + setHeight(getHeight() + 2); + field = addField(1, getHeight() - 6, getWidth() - 4, false, text); + + // Yield to the secondary thread. When I come back from the + // constructor response will already be set. + getApplication().yield(); + } + +} diff --git a/src/jexer/TMessageBox.java b/src/jexer/TMessageBox.java new file mode 100644 index 0000000..44ab5e3 --- /dev/null +++ b/src/jexer/TMessageBox.java @@ -0,0 +1,320 @@ +/** + * 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 java.util.ArrayList; +import java.util.List; + +/** + * TMessageBox is a system-modal dialog with buttons for OK, Cancel, Yes, or + * No. Call it like: + * + *

+ *

+ * {@code
+ *     box = application.messageBox(title, caption,
+ *         TMessageBox.Type.OK | TMessageBox.Type.CANCEL);
+ *
+ *     if (box.getResult() == TMessageBox.OK) {
+ *         ... the user pressed OK, do stuff ...
+ *     }
+ * }
+ * 
+ * + */ +public class TMessageBox extends TWindow { + + /** + * Message boxes have these supported types. + */ + public enum Type { + /** + * Show an OK button. + */ + OK, + + /** + * Show both OK and Cancel buttons. + */ + OKCANCEL, + + /** + * Show both Yes and No buttons. + */ + YESNO, + + /** + * Show Yes, No, and Cancel buttons. + */ + YESNOCANCEL + }; + + /** + * Message boxes have these possible results. + */ + public enum Result { + /** + * User clicked "OK". + */ + OK, + + /** + * User clicked "Cancel". + */ + CANCEL, + + /** + * User clicked "Yes". + */ + YES, + + /** + * User clicked "No". + */ + NO + }; + + + /** + * Which button was clicked: OK, CANCEL, YES, or NO. + */ + private Result result = Result.OK; + + /** + * Get the result. + * + * @return the result: OK, CANCEL, YES, or NO. + */ + public final Result getResult() { + return result; + } + + /** + * Public constructor. The message box will be centered on screen. + * + * @param application TApplication that manages this window + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + */ + public TMessageBox(final TApplication application, final String title, + final String caption) { + + this(application, title, caption, Type.OK, true); + } + + /** + * Public constructor. The message box will be centered on screen. + * + * @param application TApplication that manages this window + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param type one of the Type constants. Default is Type.OK. + */ + public TMessageBox(final TApplication application, final String title, + final String caption, final Type type) { + + this(application, title, caption, type, true); + } + + /** + * Public constructor. The message box will be centered on screen. + * + * @param application TApplication that manages this window + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param type one of the Type constants. Default is Type.OK. + * @param yield if true, yield this Thread. Subclasses need to set this + * to false and yield at their end of their constructor intead. + */ + protected TMessageBox(final TApplication application, final String title, + final String caption, final Type type, final boolean yield) { + + // Start as 50x50 at (1, 1). These will be changed later. + super(application, title, 1, 1, 100, 100, CENTERED | MODAL); + + // Determine width and height + String [] lines = caption.split("\n"); + int width = title.length() + 12; + setHeight(6 + lines.length); + for (String line: lines) { + if (line.length() + 4 > width) { + width = line.length() + 4; + } + } + setWidth(width); + if (getWidth() > getScreen().getWidth()) { + setWidth(getScreen().getWidth()); + } + // Re-center window to get an appropriate (x, y) + center(); + + // Now add my elements + int lineI = 1; + for (String line: lines) { + addLabel(line, 1, lineI, "twindow.background.modal"); + lineI++; + } + + // The button line + lineI++; + List buttons = new ArrayList(); + + int buttonX = 0; + + // Setup button actions + switch (type) { + + case OK: + result = Result.OK; + if (getWidth() < 15) { + setWidth(15); + } + buttonX = (getWidth() - 11) / 2; + buttons.add(addButton(" &OK ", buttonX, lineI, + new TAction() { + public void DO() { + result = Result.OK; + getApplication().closeWindow(TMessageBox.this); + } + } + ) + ); + break; + + case OKCANCEL: + result = Result.CANCEL; + if (getWidth() < 26) { + setWidth(26); + } + buttonX = (getWidth() - 22) / 2; + buttons.add(addButton(" &OK ", buttonX, lineI, + new TAction() { + public void DO() { + result = Result.OK; + getApplication().closeWindow(TMessageBox.this); + } + } + ) + ); + buttonX += 8 + 4; + buttons.add(addButton("&Cancel", buttonX, lineI, + new TAction() { + public void DO() { + result = Result.CANCEL; + getApplication().closeWindow(TMessageBox.this); + } + } + ) + ); + break; + + case YESNO: + result = Result.NO; + if (getWidth() < 20) { + setWidth(20); + } + buttonX = (getWidth() - 16) / 2; + buttons.add(addButton("&Yes", buttonX, lineI, + new TAction() { + public void DO() { + result = Result.YES; + getApplication().closeWindow(TMessageBox.this); + } + } + ) + ); + buttonX += 5 + 4; + buttons.add(addButton("&No", buttonX, lineI, + new TAction() { + public void DO() { + result = Result.NO; + getApplication().closeWindow(TMessageBox.this); + } + } + ) + ); + break; + + case YESNOCANCEL: + result = Result.CANCEL; + if (getWidth() < 31) { + setWidth(31); + } + buttonX = (getWidth() - 27) / 2; + buttons.add(addButton("&Yes", buttonX, lineI, + new TAction() { + public void DO() { + result = Result.YES; + getApplication().closeWindow(TMessageBox.this); + } + } + ) + ); + buttonX += 5 + 4; + buttons.add(addButton("&No", buttonX, lineI, + new TAction() { + public void DO() { + result = Result.NO; + getApplication().closeWindow(TMessageBox.this); + } + } + ) + ); + buttonX += 4 + 4; + buttons.add(addButton("&Cancel", buttonX, lineI, + new TAction() { + public void DO() { + result = Result.CANCEL; + getApplication().closeWindow(TMessageBox.this); + } + } + ) + ); + break; + + default: + throw new IllegalArgumentException("Invalid message box type: " + type); + } + + // Set the secondaryThread to run me + getApplication().enableSecondaryEventReceiver(this); + + if (yield) { + // Yield to the secondary thread. When I come back from the + // constructor response will already be set. + getApplication().yield(); + } + } + +} diff --git a/src/jexer/TWidget.java b/src/jexer/TWidget.java index 84277a8..7d3e41b 100644 --- a/src/jexer/TWidget.java +++ b/src/jexer/TWidget.java @@ -1109,7 +1109,7 @@ public abstract class TWidget implements Comparable { * @param colorKey ColorTheme key color to use for foreground text * @return the new text box */ - public TText addText(final String text, final int x, + public final TText addText(final String text, final int x, final int y, final int width, final int height, final String colorKey) { return new TText(this, text, x, y, width, height, colorKey); @@ -1126,11 +1126,68 @@ public abstract class TWidget implements Comparable { * @param height height of text area * @return the new text box */ - public TText addText(final String text, final int x, final int y, + public final TText addText(final String text, final int x, final int y, final int width, final int height) { return new TText(this, text, x, y, width, height, "ttext"); } + /** + * Convenience function to spawn a message box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @return the new message box + */ + public final TMessageBox messageBox(final String title, + final String caption) { + + return getApplication().messageBox(title, caption, TMessageBox.Type.OK); + } + + /** + * Convenience function to spawn a message box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param type one of the TMessageBox.Type constants. Default is + * Type.OK. + * @return the new message box + */ + public final TMessageBox messageBox(final String title, + final String caption, final TMessageBox.Type type) { + + return getApplication().messageBox(title, caption, type); + } + + /** + * Convenience function to spawn an input box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @return the new input box + */ + public final TInputBox inputBox(final String title, final String caption) { + + return getApplication().inputBox(title, caption); + } + + /** + * Convenience function to spawn an input box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param text initial text to seed the field with + * @return the new input box + */ + public final TInputBox inputBox(final String title, final String caption, + final String text) { + + return getApplication().inputBox(title, caption, text); + } } diff --git a/src/jexer/demos/Demo1.java b/src/jexer/demos/Demo1.java index 1e482d4..8f92b2f 100644 --- a/src/jexer/demos/Demo1.java +++ b/src/jexer/demos/Demo1.java @@ -153,65 +153,6 @@ class DemoCheckboxWindow extends TWindow { * This window demonstates the TMessageBox and TInputBox widgets. */ 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. @@ -232,46 +173,106 @@ EOS", // 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; + + int row = 1; // Add some widgets addLabel("Default OK message box", 1, row); - addButton("Open O&K MB", 35, row, &openOKMessageBox); + addButton("Open O&K MB", 35, row, + new TAction() { + public void DO() { + getApplication().messageBox("OK MessageBox", +"This is an example of a OK MessageBox. This is the\n" + +"default MessageBox.\n" + +"\n" + +"Note that the MessageBox text can span multiple\n" + +"lines.\n" + +"\n" + +"The default result (if someone hits the top-left\n" + +"close button) is OK.\n", + TMessageBox.Type.OK); + } + } + ); row += 2; addLabel("OK/Cancel message box", 1, row); - addButton("O&pen OKC MB", 35, row, &openOKCMessageBox); + addButton("O&pen OKC MB", 35, row, + new TAction() { + public void DO() { + getApplication().messageBox("OK/Cancel MessageBox", +"This is an example of a OK/Cancel MessageBox.\n" + +"\n" + +"Note that the MessageBox text can span multiple\n" + +"lines.\n" + +"\n" + +"The default result (if someone hits the top-left\n" + +"close button) is CANCEL.\n", + TMessageBox.Type.OKCANCEL); + } + } + ); row += 2; addLabel("Yes/No message box", 1, row); - addButton("Open &YN MB", 35, row, &openYNMessageBox); + addButton("Open &YN MB", 35, row, + new TAction() { + public void DO() { + getApplication().messageBox("Yes/No MessageBox", +"This is an example of a Yes/No MessageBox.\n" + +"\n" + +"Note that the MessageBox text can span multiple\n" + +"lines.\n" + +"\n" + +"The default result (if someone hits the top-left\n" + +"close button) is NO.\n", + TMessageBox.Type.YESNO); + } + } + ); row += 2; addLabel("Yes/No/Cancel message box", 1, row); - addButton("Ope&n YNC MB", 35, row, &openYNCMessageBox); + addButton("Ope&n YNC MB", 35, row, + new TAction() { + public void DO() { + getApplication().messageBox("Yes/No/Cancel MessageBox", +"This is an example of a Yes/No/Cancel MessageBox.\n" + +"\n" + +"Note that the MessageBox text can span multiple\n" + +"lines.\n" + +"\n" + +"The default result (if someone hits the top-left\n" + +"close button) is CANCEL.\n", + TMessageBox.Type.YESNOCANCEL); + } + } + ); 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"); + new TAction() { + public void DO() { + TInputBox in = getApplication().inputBox("Input Box", +"This is an example of an InputBox.\n" + +"\n" + +"Note that the InputBox text can span multiple\n" + +"lines.\n", + "some input text"); + getApplication().messageBox("Your InputBox Answer", + "You entered: " + in.getText()); + } } ); - addButton("&Close Window", (width - 14) / 2, height - 4, - { - application.closeWindow(this); + addButton("&Close Window", (getWidth() - 14) / 2, getHeight() - 4, + new TAction() { + public void DO() { + getApplication().closeWindow(DemoMsgBoxWindow.this); + } } ); - */ } } @@ -293,7 +294,7 @@ class DemoMainWindow extends TWindow { // do this kind of logic on their own. private TWindow modalWindow; private void openModalWindow() { - modalWindow = application.addWindow("Demo Modal Window", 0, 0, + modalWindow = getApplication().addWindow("Demo Modal Window", 0, 0, 58, 15, TWindow.Flag.MODAL); modalWindow.addLabel("This is an example of a very braindead modal window.", 1, 1); modalWindow.addLabel("Modal windows are centered by default.", 1, 2); @@ -301,7 +302,7 @@ class DemoMainWindow extends TWindow { modalWindow.height - 4, &modalWindowClose); } private void modalWindowClose() { - application.closeWindow(modalWindow); + getApplication().closeWindow(modalWindow); } */ @@ -424,7 +425,7 @@ class DemoMainWindow extends TWindow { addLabel("Terminal", 1, row); addButton("Termi&nal", 35, row, { - application.openTerminal(0, 0); + getApplication().openTerminal(0, 0); } ); } -- 2.27.0