Sigala's updated version](http://tvision.sourceforge.net/) that runs
on many more platforms.
-Two backends are available:
+Three backends are available:
* System.in/out to a command-line ECMA-48 / ANSI X3.64 type terminal
(tested on Linux + xterm). I/O is handled through terminal escape
are supported. For the demo application, this is the default
backend on non-Windows platforms.
+* The same command-line ECMA-48 / ANSI X3.64 type terminal as above,
+ but to any general InputStream/OutputStream. See the file
+ jexer.demos.Demo2 for an example of running the demo over a TCP
+ socket.
+
* Java Swing UI. This backend can be selected by setting
jexer.Swing=true. The default window size for Swing is 132x40,
which is set in jexer.session.SwingSession. For the demo
application, this is the default backend on Windows platforms.
The demo application showing the existing UI controls is available via
-'java -jar jexer.jar' or 'java -Djexer.Swing=true -jar jexer.jar' .
+'java -jar jexer.jar', 'java -Djexer.Swing=true -jar jexer.jar', or
+'java -cp jexer.jar jexer.demos.Demo2 PORT' (where PORT is a number to
+run the TCP daemon on).
Additional backends can be created by subclassing
jexer.backend.Backend and passing it into the TApplication
}
```
-See the file demos/Demo1.java for detailed examples.
+See the files in jexer.demos for more detailed examples.
ioctl(TIOCGWINSZ) but without requiring a native library.
- jexer.io.ECMA48Terminal calls 'stty' to perform the equivalent of
- cfmakeraw(). The terminal is (blindly!) put back in 'stty sane
- cooked' mode when exiting.
+ cfmakeraw() when using System.in/out. System.out is also
+ (blindly!) put in 'stty sane cooked' mode when exiting.
+
System Properties
Many tasks remain before calling this version 1.0:
-0.0.2: STABILIZE EXISTING
-
-- ECMA48Backend running on socket
-
0.0.3: FINISH PORTING
- TTreeView
// Check to see if the shell has died.
if (!emulator.isReading() && (shell != null)) {
- // The emulator exited on its own, all is fine
- setTitle(String.format("%s [Completed - %d]",
- getTitle(), shell.exitValue()));
- shell = null;
- emulator.close();
+ try {
+ int rc = shell.exitValue();
+ // The emulator exited on its own, all is fine
+ setTitle(String.format("%s [Completed - %d]",
+ getTitle(), shell.exitValue()));
+ shell = null;
+ emulator.close();
+ } catch (IllegalThreadStateException e) {
+ // The emulator thread has exited, but the shell Process
+ // hasn't figured that out yet. Do nothing, we will see
+ // this in a future tick.
+ }
} else if (emulator.isReading() && (shell != null)) {
// The shell might be dead, let's check
try {
--- /dev/null
+/*
+ * 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.demos;
+
+import java.net.*;
+
+/**
+ * This class is the main driver for a simple demonstration of Jexer's
+ * capabilities. Rather than run locally, it serves a Jexer UI over a TCP
+ * port.
+ */
+public class Demo2 {
+
+ /**
+ * Main entry point.
+ *
+ * @param args Command line arguments
+ */
+ public static void main(final String [] args) {
+ try {
+ if (args.length == 0) {
+ System.err.printf("USAGE: java -cp jexer.jar jexer.demos.Demo2 port\n");
+ return;
+ }
+
+ int port = Integer.parseInt(args[0]);
+ ServerSocket server = new ServerSocket(port);
+ while (true) {
+ Socket socket = server.accept();
+ System.out.printf("New connection: %s\n", socket);
+ DemoApplication app = new DemoApplication(socket.getInputStream(),
+ socket.getOutputStream());
+ (new Thread(app)).start();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
*/
package jexer.demos;
+import java.io.*;
+
import jexer.*;
import jexer.event.*;
import jexer.menu.*;
class DemoApplication extends TApplication {
/**
- * Public constructor.
- *
- * @param backendType one of the TApplication.BackendType values
- * @throws Exception if TApplication can't instantiate the Backend.
+ * Add all the widgets of the demo.
*/
- public DemoApplication(BackendType backendType) throws Exception {
- super(backendType);
+ private void addAllWidgets() {
new DemoMainWindow(this);
// Add the menus
item = subMenu.addItem(2002, "&Normal (sub)");
addWindowMenu();
-
+ }
+
+ /**
+ * Public constructor.
+ *
+ * @param input an InputStream connected to the remote user, or null for
+ * System.in. If System.in is used, then on non-Windows systems it will
+ * be put in raw mode; shutdown() will (blindly!) put System.in in cooked
+ * mode. input is always converted to a Reader with UTF-8 encoding.
+ * @param output an OutputStream connected to the remote user, or null
+ * for System.out. output is always converted to a Writer with UTF-8
+ * encoding.
+ * @throws UnsupportedEncodingException if an exception is thrown when
+ * creating the InputStreamReader
+ */
+ public DemoApplication(final InputStream input,
+ final OutputStream output) throws UnsupportedEncodingException {
+ super(input, output);
+ addAllWidgets();
+ }
+
+ /**
+ * Public constructor.
+ *
+ * @param backendType one of the TApplication.BackendType values
+ * @throws Exception if TApplication can't instantiate the Backend.
+ */
+ public DemoApplication(BackendType backendType) throws Exception {
+ super(backendType);
+ addAllWidgets();
}
}
// Enable mouse reporting and metaSendsEscape
this.output.printf("%s%s", mouse(true), xtermMetaSendsEscape(true));
+ this.output.flush();
// Hang onto the window size
windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN,
Cell lCell = screen.logical[x][y];
Cell pCell = screen.physical[x][y];
- if (!lCell.equals(pCell) || reallyCleared) {
+ if (!lCell.equals(pCell)
+ || lCell.isBlink()
+ || reallyCleared) {
- /*
- * TODO:
- * reverse
- * blink
- * underline
- */
+ Cell lCellColor = new Cell();
+ lCellColor.setTo(lCell);
+
+ // Check for reverse
+ if (lCell.isReverse()) {
+ lCellColor.setForeColor(lCell.getBackColor());
+ lCellColor.setBackColor(lCell.getForeColor());
+ }
// Draw the background rectangle, then the
// foreground character.
- gr.setColor(attrToBackgroundColor(lCell));
+ gr.setColor(attrToBackgroundColor(lCellColor));
gr.fillRect(xPixel, yPixel, textWidth, textHeight);
- gr.setColor(attrToForegroundColor(lCell));
- char [] chars = new char[1];
- chars[0] = lCell.getChar();
- gr.drawChars(chars, 0, 1, xPixel,
- yPixel + textHeight - maxDescent);
+
+ // Handle blink and underline
+ if (!lCell.isBlink()
+ || (lCell.isBlink() && cursorBlinkVisible)
+ ) {
+ gr.setColor(attrToForegroundColor(lCellColor));
+ char [] chars = new char[1];
+ chars[0] = lCell.getChar();
+ gr.drawChars(chars, 0, 1, xPixel,
+ yPixel + textHeight - maxDescent);
+ if (lCell.isUnderline()) {
+ gr.fillRect(xPixel, yPixel + textHeight - 2,
+ textWidth, 2);
+ }
+ }
// Physical is always updated
physical[x][y].setTo(lCell);
|| ((x == cursorX)
&& (y == cursorY)
&& cursorVisible)
+ || lCell.isBlink()
) {
if (xPixel < xMin) {
xMin = xPixel;