From 88a99379dca67603ee80819cb31716e52aa72362 Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Mon, 7 Aug 2017 19:36:42 -0400 Subject: [PATCH] MultiBackend and MultiScreen --- README.md | 7 + src/jexer/backend/Backend.java | 8 + src/jexer/backend/ECMA48Backend.java | 53 +-- src/jexer/backend/ECMA48Terminal.java | 10 + src/jexer/backend/GenericBackend.java | 44 ++- src/jexer/backend/MultiBackend.java | 157 ++++++++ src/jexer/backend/MultiScreen.java | 534 ++++++++++++++++++++++++++ src/jexer/backend/SwingBackend.java | 64 +-- src/jexer/backend/SwingComponent.java | 2 +- src/jexer/backend/TerminalReader.java | 8 + src/jexer/demos/Demo5.java | 5 +- src/jexer/demos/Demo6.java | 66 ++++ 12 files changed, 841 insertions(+), 117 deletions(-) create mode 100644 src/jexer/backend/MultiBackend.java create mode 100644 src/jexer/backend/MultiScreen.java create mode 100644 src/jexer/demos/Demo6.java diff --git a/README.md b/README.md index b4114f3..b84a1f6 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,13 @@ follows: * 'java -cp jexer.jar jexer.demos.Demo4' . This demonstrates hidden windows and a custom TDesktop. + * 'java -cp jexer.jar jexer.demos.Demo5' . This demonstrates two + demo applications using different fonts in the same Swing frame. + + * 'java -cp jexer.jar jexer.demos.Demo6' . This demonstrates one + application performing I/O to two screens: an xterm screen and a + Swing screen. + More Screenshots diff --git a/src/jexer/backend/Backend.java b/src/jexer/backend/Backend.java index 2793ab0..d186328 100644 --- a/src/jexer/backend/Backend.java +++ b/src/jexer/backend/Backend.java @@ -81,4 +81,12 @@ public interface Backend { */ public void setTitle(final String title); + /** + * Set listener to a different Object. + * + * @param listener the new listening object that run() wakes up on new + * input + */ + public void setListener(final Object listener); + } diff --git a/src/jexer/backend/ECMA48Backend.java b/src/jexer/backend/ECMA48Backend.java index ee7a103..db390fb 100644 --- a/src/jexer/backend/ECMA48Backend.java +++ b/src/jexer/backend/ECMA48Backend.java @@ -33,9 +33,6 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.UnsupportedEncodingException; -import java.util.List; - -import jexer.event.TInputEvent; /** * This class uses an xterm/ANSI X3.64/ECMA-48 type terminal to provide a @@ -43,11 +40,6 @@ import jexer.event.TInputEvent; */ public final class ECMA48Backend extends GenericBackend { - /** - * Input events are processed by this Terminal. - */ - private ECMA48Terminal terminal; - /** * Public constructor. * @@ -70,10 +62,10 @@ public final class ECMA48Backend extends GenericBackend { terminal = new ECMA48Terminal(listener, input, output); // Keep the terminal's sessionInfo so that TApplication can see it - sessionInfo = terminal.getSessionInfo(); + sessionInfo = ((ECMA48Terminal) terminal).getSessionInfo(); // ECMA48Terminal is the screen too - screen = terminal; + screen = (ECMA48Terminal) terminal; } /** @@ -99,10 +91,10 @@ public final class ECMA48Backend extends GenericBackend { setRawMode); // Keep the terminal's sessionInfo so that TApplication can see it - sessionInfo = terminal.getSessionInfo(); + sessionInfo = ((ECMA48Terminal) terminal).getSessionInfo(); // ECMA48Terminal is the screen too - screen = terminal; + screen = (ECMA48Terminal) terminal; } /** @@ -122,42 +114,5 @@ public final class ECMA48Backend extends GenericBackend { this(listener, input, reader, writer, false); } - /** - * Sync the logical screen to the physical device. - */ - @Override - public void flushScreen() { - screen.flushPhysical(); - } - - /** - * Get keyboard, mouse, and screen resize events. - * - * @param queue list to append new events to - */ - @Override - public void getEvents(final List queue) { - if (terminal.hasEvents()) { - terminal.getEvents(queue); - } - } - - /** - * Close the I/O, restore the console, etc. - */ - @Override - public void shutdown() { - terminal.closeTerminal(); - } - - /** - * Set the window title. - * - * @param title the new title - */ - @Override - public void setTitle(final String title) { - screen.setTitle(title); - } } diff --git a/src/jexer/backend/ECMA48Terminal.java b/src/jexer/backend/ECMA48Terminal.java index 1370415..6303f4f 100644 --- a/src/jexer/backend/ECMA48Terminal.java +++ b/src/jexer/backend/ECMA48Terminal.java @@ -195,6 +195,16 @@ public final class ECMA48Terminal extends LogicalScreen */ private Object listener; + /** + * Set listener to a different Object. + * + * @param listener the new listening object that run() wakes up on new + * input + */ + public void setListener(final Object listener) { + this.listener = listener; + } + /** * Get the output writer. * diff --git a/src/jexer/backend/GenericBackend.java b/src/jexer/backend/GenericBackend.java index d96f7a9..bf27e94 100644 --- a/src/jexer/backend/GenericBackend.java +++ b/src/jexer/backend/GenericBackend.java @@ -68,30 +68,52 @@ public abstract class GenericBackend implements Backend { } /** - * Subclasses must provide an implementation that syncs the logical - * screen to the physical device. + * Sync the logical screen to the physical device. */ - public abstract void flushScreen(); + public void flushScreen() { + screen.flushPhysical(); + } + + /** + * Input events are processed by this Terminal. + */ + protected TerminalReader terminal; /** - * Subclasses must provide an implementation to get keyboard, mouse, and - * screen resize events. + * Get keyboard, mouse, and screen resize events. * * @param queue list to append new events to */ - public abstract void getEvents(List queue); + public void getEvents(final List queue) { + if (terminal.hasEvents()) { + terminal.getEvents(queue); + } + } /** - * Subclasses must provide an implementation that closes sockets, - * restores console, etc. + * Close the I/O, restore the console, etc. */ - public abstract void shutdown(); + public void shutdown() { + terminal.closeTerminal(); + } /** - * Subclasses must provide an implementation that sets the window title. + * Set the window title. * * @param title the new title */ - public abstract void setTitle(final String title); + public void setTitle(final String title) { + screen.setTitle(title); + } + + /** + * Set listener to a different Object. + * + * @param listener the new listening object that run() wakes up on new + * input + */ + public void setListener(final Object listener) { + terminal.setListener(listener); + } } diff --git a/src/jexer/backend/MultiBackend.java b/src/jexer/backend/MultiBackend.java new file mode 100644 index 0000000..a397c65 --- /dev/null +++ b/src/jexer/backend/MultiBackend.java @@ -0,0 +1,157 @@ +/* + * Jexer - Java Text User Interface + * + * The MIT License (MIT) + * + * Copyright (C) 2017 Kevin Lamonte + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @author Kevin Lamonte [kevin.lamonte@gmail.com] + * @version 1 + */ +package jexer.backend; + +import java.util.LinkedList; +import java.util.List; + +import jexer.event.TInputEvent; + +/** + * MultiBackend mirrors its I/O to several backends. + */ +public class MultiBackend implements Backend { + + /** + * The screen to use. + */ + private MultiScreen multiScreen; + + /** + * The list of backends to use. + */ + private List backends = new LinkedList(); + + /** + * Public constructor requires one backend. Note that this backend's + * screen will be replaced with a MultiScreen. + * + * @param backend the backend to add + */ + public MultiBackend(final Backend backend) { + backends.add(backend); + multiScreen = new MultiScreen(backend.getScreen()); + } + + /** + * Add a backend to the list. + * + * @param backend the backend to add + */ + public void addBackend(final Backend backend) { + backends.add(backend); + multiScreen.addScreen(backend.getScreen()); + } + + /** + * Remove a backend from the list. + * + * @param backend the backend to remove + */ + public void removeBackend(final Backend backend) { + if (backends.size() > 1) { + multiScreen.removeScreen(backend.getScreen()); + backends.remove(backend); + } + } + + /** + * Getter for sessionInfo. + * + * @return the SessionInfo + */ + public final SessionInfo getSessionInfo() { + return backends.get(0).getSessionInfo(); + } + + /** + * Getter for screen. + * + * @return the Screen + */ + public final Screen getScreen() { + return multiScreen; + } + + /** + * Subclasses must provide an implementation that syncs the logical + * screen to the physical device. + */ + public void flushScreen() { + for (Backend backend: backends) { + backend.flushScreen(); + } + } + + /** + * Subclasses must provide an implementation to get keyboard, mouse, and + * screen resize events. + * + * @param queue list to append new events to + */ + public void getEvents(List queue) { + for (Backend backend: backends) { + backend.getEvents(queue); + } + } + + /** + * Subclasses must provide an implementation that closes sockets, + * restores console, etc. + */ + public void shutdown() { + for (Backend backend: backends) { + backend.shutdown(); + } + } + + /** + * Subclasses must provide an implementation that sets the window title. + * + * @param title the new title + */ + public void setTitle(final String title) { + for (Backend backend: backends) { + backend.setTitle(title); + } + } + + /** + * Set listener to a different Object. + * + * @param listener the new listening object that run() wakes up on new + * input + */ + public void setListener(final Object listener) { + for (Backend backend: backends) { + backend.setListener(listener); + } + } + +} diff --git a/src/jexer/backend/MultiScreen.java b/src/jexer/backend/MultiScreen.java new file mode 100644 index 0000000..f7b61dd --- /dev/null +++ b/src/jexer/backend/MultiScreen.java @@ -0,0 +1,534 @@ +/* + * Jexer - Java Text User Interface + * + * The MIT License (MIT) + * + * Copyright (C) 2017 Kevin Lamonte + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @author Kevin Lamonte [kevin.lamonte@gmail.com] + * @version 1 + */ +package jexer.backend; + +import java.util.LinkedList; +import java.util.List; + +import jexer.bits.Cell; +import jexer.bits.CellAttributes; + +/** + * MultiScreen mirrors its I/O to several screens. + */ +public class MultiScreen implements Screen { + + /** + * The list of screens to use. + */ + private List screens = new LinkedList(); + + /** + * Public constructor requires one screen. + * + * @param screen the screen to add + */ + public MultiScreen(final Screen screen) { + screens.add(screen); + } + + /** + * Add a screen to the list. + * + * @param screen the screen to add + */ + public void addScreen(final Screen screen) { + screens.add(screen); + } + + /** + * Remove a screen from the list. + * + * @param screen the screen to remove + */ + public void removeScreen(final Screen screen) { + if (screens.size() > 1) { + screens.remove(screen); + } + } + + /** + * Set drawing offset for x. + * + * @param offsetX new drawing offset + */ + public void setOffsetX(final int offsetX) { + for (Screen screen: screens) { + screen.setOffsetX(offsetX); + } + } + + /** + * Set drawing offset for y. + * + * @param offsetY new drawing offset + */ + public void setOffsetY(final int offsetY) { + for (Screen screen: screens) { + screen.setOffsetY(offsetY); + } + } + + /** + * Get right drawing clipping boundary. + * + * @return drawing boundary + */ + public int getClipRight() { + return screens.get(0).getClipRight(); + } + + /** + * Set right drawing clipping boundary. + * + * @param clipRight new boundary + */ + public void setClipRight(final int clipRight) { + for (Screen screen: screens) { + screen.setClipRight(clipRight); + } + } + + /** + * Get bottom drawing clipping boundary. + * + * @return drawing boundary + */ + public int getClipBottom() { + return screens.get(0).getClipBottom(); + } + + /** + * Set bottom drawing clipping boundary. + * + * @param clipBottom new boundary + */ + public void setClipBottom(final int clipBottom) { + for (Screen screen: screens) { + screen.setClipBottom(clipBottom); + } + } + + /** + * Get left drawing clipping boundary. + * + * @return drawing boundary + */ + public int getClipLeft() { + return screens.get(0).getClipLeft(); + } + + /** + * Set left drawing clipping boundary. + * + * @param clipLeft new boundary + */ + public void setClipLeft(final int clipLeft) { + for (Screen screen: screens) { + screen.setClipLeft(clipLeft); + } + } + + /** + * Get top drawing clipping boundary. + * + * @return drawing boundary + */ + public int getClipTop() { + return screens.get(0).getClipTop(); + } + + /** + * Set top drawing clipping boundary. + * + * @param clipTop new boundary + */ + public void setClipTop(final int clipTop) { + for (Screen screen: screens) { + screen.setClipTop(clipTop); + } + } + + /** + * Get dirty flag. + * + * @return if true, the logical screen is not in sync with the physical + * screen + */ + public boolean isDirty() { + return screens.get(0).isDirty(); + } + + /** + * 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(final int x, final int y) { + return screens.get(0).getAttrXY(x, y); + } + + /** + * 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) + */ + public void putAttrXY(final int x, final int y, + final CellAttributes attr) { + + for (Screen screen: screens) { + screen.putAttrXY(x, y, 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(final int x, final int y, + final CellAttributes attr, final boolean clip) { + + for (Screen screen: screens) { + screen.putAttrXY(x, y, attr, clip); + } + } + + /** + * 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(final char ch, final CellAttributes attr) { + for (Screen screen: screens) { + screen.putAll(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(final int x, final int y, final Cell ch) { + for (Screen screen: screens) { + screen.putCharXY(x, y, 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(final int x, final int y, final char ch, + final CellAttributes attr) { + + for (Screen screen: screens) { + screen.putCharXY(x, y, ch, attr); + } + } + + /** + * 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(final int x, final int y, final char ch) { + for (Screen screen: screens) { + screen.putCharXY(x, y, 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 putStringXY(final int x, final int y, final String str, + final CellAttributes attr) { + + for (Screen screen: screens) { + screen.putStringXY(x, y, str, attr); + } + } + + /** + * 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 putStringXY(final int x, final int y, final String str) { + for (Screen screen: screens) { + screen.putStringXY(x, y, str); + } + } + + /** + * 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(final int x, final int y, final int n, + final char ch, final CellAttributes attr) { + + for (Screen screen: screens) { + screen.vLineXY(x, y, n, 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(final int x, final int y, final int n, + final char ch, final CellAttributes attr) { + + for (Screen screen: screens) { + screen.hLineXY(x, y, n, ch, attr); + } + } + + /** + * Change the width. Everything on-screen will be destroyed and must be + * redrawn. + * + * @param width new screen width + */ + public void setWidth(final int width) { + for (Screen screen: screens) { + screen.setWidth(width); + } + } + + /** + * Change the height. Everything on-screen will be destroyed and must be + * redrawn. + * + * @param height new screen height + */ + public void setHeight(final int height) { + for (Screen screen: screens) { + screen.setHeight(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(final int width, final int height) { + for (Screen screen: screens) { + screen.setDimensions(width, height); + } + } + + /** + * Get the height. + * + * @return current screen height + */ + public int getHeight() { + return screens.get(0).getHeight(); + } + + /** + * Get the width. + * + * @return current screen width + */ + public int getWidth() { + return screens.get(0).getWidth(); + } + + /** + * Reset screen to not-bold, white-on-black. Also flushes the offset and + * clip variables. + */ + public void reset() { + for (Screen screen: screens) { + screen.reset(); + } + } + + /** + * Flush the offset and clip variables. + */ + public void resetClipping() { + for (Screen screen: screens) { + screen.resetClipping(); + } + } + + /** + * Clear the logical screen. + */ + public void clear() { + for (Screen screen: screens) { + screen.clear(); + } + } + + /** + * 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 + * @param background attributes to use for the background + */ + public void drawBox(final int left, final int top, + final int right, final int bottom, + final CellAttributes border, final CellAttributes background) { + + for (Screen screen: screens) { + screen.drawBox(left, top, right, bottom, border, background); + } + } + + /** + * 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 + * @param background attributes to use for the background + * @param borderType if 1, draw a single-line border; if 2, draw a + * double-line border; if 3, draw double-line top/bottom edges and + * single-line left/right edges (like Qmodem) + * @param shadow if true, draw a "shadow" on the box + */ + public void drawBox(final int left, final int top, + final int right, final int bottom, + final CellAttributes border, final CellAttributes background, + final int borderType, final boolean shadow) { + + for (Screen screen: screens) { + screen.drawBox(left, top, right, bottom, border, background, + borderType, shadow); + } + } + + /** + * 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(final int left, final int top, + final int right, final int bottom) { + + for (Screen screen: screens) { + screen.drawBoxShadow(left, top, right, bottom); + } + } + + /** + * Classes must provide an implementation to push the logical screen to + * the physical device. + */ + public void flushPhysical() { + for (Screen screen: screens) { + screen.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(final boolean visible, final int x, final int y) { + for (Screen screen: screens) { + screen.putCursor(visible, x, y); + } + } + + /** + * Hide the cursor. + */ + public void hideCursor() { + for (Screen screen: screens) { + screen.hideCursor(); + } + } + + /** + * Set the window title. + * + * @param title the new title + */ + public void setTitle(final String title) { + for (Screen screen: screens) { + screen.setTitle(title); + } + } + +} diff --git a/src/jexer/backend/SwingBackend.java b/src/jexer/backend/SwingBackend.java index 876015e..fc77968 100644 --- a/src/jexer/backend/SwingBackend.java +++ b/src/jexer/backend/SwingBackend.java @@ -28,22 +28,15 @@ */ package jexer.backend; -import java.util.List; +import java.awt.Font; import javax.swing.JComponent; -import jexer.event.TInputEvent; - /** * This class uses standard Swing calls to handle screen, keyboard, and mouse * I/O. */ public final class SwingBackend extends GenericBackend { - /** - * Input events are processed by this Terminal. - */ - private SwingTerminal terminal; - /** * Public constructor. The window will be 80x25 with font size 20 pts. * @@ -72,10 +65,10 @@ public final class SwingBackend extends GenericBackend { listener); // Hang onto the session info - this.sessionInfo = terminal.getSessionInfo(); + this.sessionInfo = ((SwingTerminal) terminal).getSessionInfo(); // SwingTerminal is the screen too - screen = terminal; + screen = (SwingTerminal) terminal; } /** @@ -97,58 +90,19 @@ public final class SwingBackend extends GenericBackend { fontSize, listener); // Hang onto the session info - this.sessionInfo = terminal.getSessionInfo(); + this.sessionInfo = ((SwingTerminal) terminal).getSessionInfo(); // SwingTerminal is the screen too - screen = terminal; - } - - /** - * Sync the logical screen to the physical device. - */ - @Override - public void flushScreen() { - screen.flushPhysical(); - } - - /** - * Get keyboard, mouse, and screen resize events. - * - * @param queue list to append new events to - */ - @Override - public void getEvents(final List queue) { - if (terminal.hasEvents()) { - terminal.getEvents(queue); - } - } - - /** - * Close the I/O, restore the console, etc. - */ - @Override - public void shutdown() { - terminal.closeTerminal(); - } - - /** - * Set the window title. - * - * @param title the new title - */ - @Override - public void setTitle(final String title) { - screen.setTitle(title); + screen = (SwingTerminal) terminal; } /** - * Set listener to a different Object. + * Set to a new font, and resize the screen to match its dimensions. * - * @param listener the new listening object that run() wakes up on new - * input + * @param font the new font */ - public void setListener(final Object listener) { - terminal.setListener(listener); + public void setFont(final Font font) { + ((SwingTerminal) terminal).setFont(font); } } diff --git a/src/jexer/backend/SwingComponent.java b/src/jexer/backend/SwingComponent.java index 84e1472..48e4a44 100644 --- a/src/jexer/backend/SwingComponent.java +++ b/src/jexer/backend/SwingComponent.java @@ -55,7 +55,7 @@ class SwingComponent { /** * If true, use triple buffering when drawing to a JFrame. */ - public static boolean tripleBuffer = false; + public static boolean tripleBuffer = true; /** * Get the BufferStrategy object needed for triple-buffering. diff --git a/src/jexer/backend/TerminalReader.java b/src/jexer/backend/TerminalReader.java index 48e4043..6900732 100644 --- a/src/jexer/backend/TerminalReader.java +++ b/src/jexer/backend/TerminalReader.java @@ -58,4 +58,12 @@ public interface TerminalReader { */ public void closeTerminal(); + /** + * Set listener to a different Object. + * + * @param listener the new listening object that run() wakes up on new + * input + */ + public void setListener(final Object listener); + } diff --git a/src/jexer/demos/Demo5.java b/src/jexer/demos/Demo5.java index 88d6a7c..8763aa1 100644 --- a/src/jexer/demos/Demo5.java +++ b/src/jexer/demos/Demo5.java @@ -28,6 +28,7 @@ */ package jexer.demos; +import java.awt.Font; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JFrame; @@ -143,7 +144,9 @@ public class Demo5 implements WindowListener { SwingBackend app2Backend = new SwingBackend(app2Panel, new Object(), 80, 25, 18); app2 = new DemoApplication(app2Backend); - app1Backend.setListener(app2); + Font font = new Font(Font.MONOSPACED, Font.PLAIN, 18); + app2Backend.setFont(font); + app2Backend.setListener(app2); (new Thread(app1)).start(); (new Thread(app2)).start(); diff --git a/src/jexer/demos/Demo6.java b/src/jexer/demos/Demo6.java new file mode 100644 index 0000000..fba67a0 --- /dev/null +++ b/src/jexer/demos/Demo6.java @@ -0,0 +1,66 @@ +/* + * Jexer - Java Text User Interface + * + * The MIT License (MIT) + * + * Copyright (C) 2017 Kevin Lamonte + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @author Kevin Lamonte [kevin.lamonte@gmail.com] + * @version 1 + */ +package jexer.demos; + +import jexer.backend.*; + +/** + * This class shows off the use of MultiBackend and MultiScreen. + */ +public class Demo6 { + + /** + * Main entry point. + * + * @param args Command line arguments + */ + public static void main(final String [] args) { + try { + /* + * Spin up a Swing backend to match the ECMA48 backend on + * System.in/out. + */ + ECMA48Backend ecmaBackend = new ECMA48Backend(new Object(), null, + null); + MultiBackend multiBackend = new MultiBackend(ecmaBackend); + DemoApplication demoApp = new DemoApplication(multiBackend); + Screen multiScreen = multiBackend.getScreen(); + + SwingBackend swingBackend = new SwingBackend(new Object(), + multiScreen.getWidth(), multiScreen.getHeight(), 16); + multiBackend.addBackend(swingBackend); + multiBackend.setListener(demoApp); + + (new Thread(demoApp)).start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} -- 2.27.0