This library implements a text-based windowing system reminiscient of
Borland's [Turbo Vision](http://en.wikipedia.org/wiki/Turbo_Vision)
system. (For those wishing to use the actual C++ Turbo Vision
-library, see [Sergio Sigala's C++ version based on the public domain
-sources released by Borland.](http://tvision.sourceforge.net/) )
+library, see [Sergio Sigala's C++ version based on the sources
+released by Borland,](http://tvision.sourceforge.net/) or consider
+Free Pascal's [Free Vision
+library.](http://wiki.freepascal.org/Free_Vision))
Jexer currently supports three backends:
Used by jexer.io.SwingScreen. Selects the cursor style to draw.
Valid values are: underline, block, outline. Default: underline.
+ jexer.Swing.tripleBuffer
+ ------------------------
+
+ Used by jexer.io.SwingScreen. If false, use naive Swing thread
+ drawing. This may be faster on slower systems, but will also be
+ more likely to have screen tearing. Default: true.
+
Known Issues / Arbitrary Decisions
<project name="jexer" basedir="." default="jar">
- <!-- <property name="build.compiler" value="gcj"/> -->
+ <!--
+ I am using GCJ deliberately to test against Java 1.5 features.
+ -->
+ <property name="build.compiler" value="gcj"/>
- <property name="version" value="0.0.4"/>
+ <property name="version" value="0.0.5"/>
<property name="src.dir" value="src"/>
<property name="resources.dir" value="resources"/>
<property name="build.dir" value="build"/>
0.0.5
- TEditor
+- Eliminate all Eclipse warnings
0.0.6
0.0.7
+- Refactor SwingBackend to be embeddable
+ - jexer.Swing.blockMousePointer: false = do not invert cell, true
+ (default) is current behavior
+ - Make Demo4 with two separate Swing demos in a single JFrame.
+ - Make Demo5 mixing Swing and Jexer components
+
- THelpWindow
- TText + clickable links
- Index
1.0.0
+- Maven artifact.
1.1.0 Wishlist
Release Checklist √
-------------------
+Eliminate all Eclipse warnings
+
Fix all marked TODOs in code
Eliminate DEBUG, System.err prints
Jexer Work Log
==============
+March 21, 2017
+
+I am starting to gear up for making Jexer a serious project now. I've
+created its SourceForge project, linked it back to GitHub, have most
+of its web page set up (looks like Qodem's), and released 0.0.4. And
+then this morning saw an out-of-bounds exception if you kill the main
+demo window. Glad I marked it Alpha on SourceForge...
+
+Yesterday I was digging around the other Turbo Vision derived projects
+while populating the about page, and made a sad/happy-ish realization:
+Embarcadero could probably get all of them shut down if it really
+wanted to, including Free Vision. I uncovered some hidden history in
+Free Vision, such that it appears that Graphics Vision had some
+licensed Borland code in it, so there might be enough mud in the air
+that Free Vision could be shut down the same way RHTVision was. But
+even worse is the SCOTUS ruling on Oracle vs Google: if APIs are
+copyrighted (regardless of their thoughts on fair use), then any
+software that matches the API of a proprietary project might find
+itself subject to an infringement case. So that too could shut down
+the other API-compatible TV clones.
+
+Fortunately, Jexer (and D-TUI) is completely new, and has no API
+compatibility with Turbo Vision. Jexer could be a new root to a whole
+generation of TUI applications.
+
March 18, 2017
TStatusBar is working, as is "smart" window placement. Overall this
// Draw each window in reverse Z order
List<TWindow> sorted = new LinkedList<TWindow>(windows);
Collections.sort(sorted);
- TWindow topLevel = sorted.get(0);
+ TWindow topLevel = null;
+ if (sorted.size() > 0) {
+ topLevel = sorted.get(0);
+ }
Collections.reverse(sorted);
for (TWindow window: sorted) {
window.drawChildren();
}
// Draw the status bar of the top-level window
- TStatusBar statusBar = topLevel.getStatusBar();
+ TStatusBar statusBar = null;
+ if (topLevel != null) {
+ statusBar = topLevel.getStatusBar();
+ }
if (statusBar != null) {
getScreen().resetClipping();
statusBar.setWidth(getScreen().getWidth());
*/
public class ReadTimeoutException extends IOException {
+ /**
+ * Serializable version.
+ */
+ private static final long serialVersionUID = 1;
+
/**
* Construct an instance with a message.
*
/**
* If true, use triple buffering thread.
*/
- private static final boolean tripleBuffer = true;
+ private static boolean tripleBuffer = true;
/**
* Cursor style to draw.
cursorStyle = CursorStyle.BLOCK;
}
+ if (System.getProperty("jexer.Swing.tripleBuffer").
+ equals("false")) {
+
+ SwingScreen.tripleBuffer = false;
+ }
+
setTitle("Jexer Application");
setBackground(Color.black);
}
// Generate glyph and draw it.
-
- image = new BufferedImage(textWidth, textHeight,
- BufferedImage.TYPE_INT_ARGB);
- Graphics2D gr2 = image.createGraphics();
- gr2.setFont(getFont());
+ Graphics2D gr2 = null;
+ int gr2x = xPixel;
+ int gr2y = yPixel;
+ if (tripleBuffer) {
+ image = new BufferedImage(textWidth, textHeight,
+ BufferedImage.TYPE_INT_ARGB);
+ gr2 = image.createGraphics();
+ gr2.setFont(getFont());
+ gr2x = 0;
+ gr2y = 0;
+ } else {
+ gr2 = (Graphics2D) gr;
+ }
Cell cellColor = new Cell();
cellColor.setTo(cell);
// Draw the background rectangle, then the foreground character.
gr2.setColor(attrToBackgroundColor(cellColor));
- gr2.fillRect(0, 0, textWidth, textHeight);
+ gr2.fillRect(gr2x, gr2y, textWidth, textHeight);
// Handle blink and underline
if (!cell.isBlink()
gr2.setColor(attrToForegroundColor(cellColor));
char [] chars = new char[1];
chars[0] = cell.getChar();
- gr2.drawChars(chars, 0, 1, 0 + textAdjustX,
- 0 + textHeight - maxDescent + textAdjustY);
+ gr2.drawChars(chars, 0, 1, gr2x + textAdjustX,
+ gr2y + textHeight - maxDescent + textAdjustY);
if (cell.isUnderline()) {
- gr2.fillRect(0, 0 + textHeight - 2, textWidth, 2);
+ gr2.fillRect(gr2x, gr2y + textHeight - 2, textWidth, 2);
}
}
- gr2.dispose();
- // We need a new key that will not be mutated by invertCell().
- Cell key = new Cell();
- key.setTo(cell);
- if (cell.isBlink() && !cursorBlinkVisible) {
- glyphCacheBlink.put(key, image);
- } else {
- glyphCache.put(key, image);
+ if (tripleBuffer) {
+ gr2.dispose();
+
+ // We need a new key that will not be mutated by
+ // invertCell().
+ Cell key = new Cell();
+ key.setTo(cell);
+ if (cell.isBlink() && !cursorBlinkVisible) {
+ glyphCacheBlink.put(key, image);
+ } else {
+ glyphCache.put(key, image);
+ }
+
+ gr.drawImage(image, xPixel, yPixel, this);
}
- gr.drawImage(image, xPixel, yPixel, this);
}
/**
try {
// How long do we sleep for, eh? For now we will go with 2
// millis.
- Thread.currentThread().sleep(2);
+ Thread.sleep(2);
} catch (InterruptedException e) {
// SQUASH
}
try {
// How long do we sleep for, eh? For now we will go with
// 2 millis.
- Thread.currentThread().sleep(2);
+ Thread.sleep(2);
} catch (InterruptedException e) {
// SQUASH
}
try {
// How long do we sleep for, eh? For now we will go with
// 2 millis.
- Thread.currentThread().sleep(2);
+ Thread.sleep(2);
} catch (InterruptedException e) {
// SQUASH
}