mirror of
https://gitlab.com/AutumnMeowMeow/jexer
synced 2024-09-19 11:50:19 -06:00
Translucent windows #88
This implements: * Translucent windows. See issue text for some discussion. Also a thank you to notcurses for the inspiration. * Selection of different window border styles. * Fixes for RGB output on ECMA48. * Other performance bug fixes.
This commit is contained in:
parent
f2f7eaeb0d
commit
e5145580e5
29 changed files with 2180 additions and 334 deletions
|
@ -402,6 +402,11 @@ public class TApplication implements Runnable {
|
|||
*/
|
||||
protected MousePointer customWidgetMousePointer;
|
||||
|
||||
/**
|
||||
* If true. enable translucency.
|
||||
*/
|
||||
protected boolean translucence = true;
|
||||
|
||||
/**
|
||||
* WidgetEventHandler is the main event consumer loop. There are at most
|
||||
* two such threads in existence: the primary for normal case and a
|
||||
|
@ -584,6 +589,21 @@ public class TApplication implements Runnable {
|
|||
*/
|
||||
private ArrayList<String> dirtyQueue = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* The number of updates pushed out in this second.
|
||||
*/
|
||||
private int framesPerSecond = 0;
|
||||
|
||||
/**
|
||||
* The last time a frame was rendered.
|
||||
*/
|
||||
private long lastFlushTime = 0;
|
||||
|
||||
/**
|
||||
* How long it took to render the last time in millis.
|
||||
*/
|
||||
private long lastFrameTime = 0;
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
|
@ -612,6 +632,7 @@ public class TApplication implements Runnable {
|
|||
* The update loop.
|
||||
*/
|
||||
private void runImpl() {
|
||||
int frameCount = 0;
|
||||
|
||||
// Loop forever
|
||||
while (!application.quit) {
|
||||
|
@ -620,7 +641,11 @@ public class TApplication implements Runnable {
|
|||
while (!application.quit) {
|
||||
synchronized (dirtyQueue) {
|
||||
if (dirtyQueue.size() > 0) {
|
||||
dirtyQueue.remove(dirtyQueue.size() - 1);
|
||||
// Collapse all the dirty requests into one
|
||||
// refresh.
|
||||
while (dirtyQueue.size() > 0) {
|
||||
dirtyQueue.remove(dirtyQueue.size() - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -641,7 +666,17 @@ public class TApplication implements Runnable {
|
|||
System.currentTimeMillis(), Thread.currentThread());
|
||||
}
|
||||
synchronized (getScreen()) {
|
||||
long before = System.currentTimeMillis();
|
||||
backend.flushScreen();
|
||||
long now = System.currentTimeMillis();
|
||||
lastFrameTime = now - before;
|
||||
if ((int) (now / 1000) == (int) (lastFlushTime / 1000)) {
|
||||
frameCount++;
|
||||
} else {
|
||||
framesPerSecond = frameCount;
|
||||
frameCount = 0;
|
||||
}
|
||||
lastFlushTime = now;
|
||||
}
|
||||
} // while (true) (main runnable loop)
|
||||
|
||||
|
@ -841,6 +876,11 @@ public class TApplication implements Runnable {
|
|||
hideMenuBar = true;
|
||||
}
|
||||
|
||||
// Translucent windows (!) option
|
||||
if (System.getProperty("jexer.translucence", "true").equals("false")) {
|
||||
translucence = false;
|
||||
}
|
||||
|
||||
theme = new ColorTheme();
|
||||
desktopTop = (hideMenuBar ? 0 : 1);
|
||||
desktopBottom = getScreen().getHeight() - 1 + (hideStatusBar ? 1 : 0);
|
||||
|
@ -1415,6 +1455,7 @@ public class TApplication implements Runnable {
|
|||
* @see #secondaryHandleEvent(TInputEvent event)
|
||||
*/
|
||||
private void primaryHandleEvent(final TInputEvent event) {
|
||||
assert (event != null);
|
||||
|
||||
if (debugEvents) {
|
||||
System.err.printf("%s primaryHandleEvent: %s\n",
|
||||
|
@ -1623,9 +1664,14 @@ public class TApplication implements Runnable {
|
|||
if (debugEvents) {
|
||||
System.err.printf("TApplication dispatch event: %s\n",
|
||||
event);
|
||||
System.err.printf(" Routed to: %s\n", window);
|
||||
System.err.flush();
|
||||
}
|
||||
window.handleEvent(event);
|
||||
if (doubleClick != null) {
|
||||
if (debugEvents) {
|
||||
System.err.printf(" -- DOUBLE CLICK --\n");
|
||||
}
|
||||
window.handleEvent(doubleClick);
|
||||
}
|
||||
if (mouse != null) {
|
||||
|
@ -1657,6 +1703,8 @@ public class TApplication implements Runnable {
|
|||
* @see #primaryHandleEvent(TInputEvent event)
|
||||
*/
|
||||
private void secondaryHandleEvent(final TInputEvent event) {
|
||||
assert (event != null);
|
||||
|
||||
TMouseEvent doubleClick = null;
|
||||
|
||||
if (debugEvents) {
|
||||
|
@ -1907,7 +1955,7 @@ public class TApplication implements Runnable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the color theme.
|
||||
* Get the global color theme.
|
||||
*
|
||||
* @return the theme
|
||||
*/
|
||||
|
@ -1915,6 +1963,60 @@ public class TApplication implements Runnable {
|
|||
return theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the translucence option.
|
||||
*
|
||||
* @return true if translucency is enabled
|
||||
*/
|
||||
public boolean hasTranslucence() {
|
||||
return translucence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the translucence option.
|
||||
*
|
||||
* @param enabled if true, windows will be translucent
|
||||
*/
|
||||
public void setTranslucence(final boolean enabled) {
|
||||
translucence = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the opacity of all windows. If opacity is 100, translucence is
|
||||
* also disabled for performance.
|
||||
*
|
||||
* @param opacity a number between 10 (nearly transparent) and 100 (fully
|
||||
* opaque)
|
||||
*/
|
||||
public void setWindowOpacity(final int opacity) {
|
||||
if ((opacity < 10) || (opacity > 100)) {
|
||||
return;
|
||||
}
|
||||
if (opacity == 100) {
|
||||
translucence = false;
|
||||
} else {
|
||||
translucence = true;
|
||||
}
|
||||
|
||||
int alpha = opacity * 255 / 100;
|
||||
for (TWindow window: windows) {
|
||||
window.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of frames that were emitted to output on the last
|
||||
* second.
|
||||
*
|
||||
* @return the frames per second
|
||||
*/
|
||||
public int getFramesPerSecond() {
|
||||
if (screenHandler != null) {
|
||||
return screenHandler.framesPerSecond;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the clipboard.
|
||||
*
|
||||
|
@ -1929,6 +2031,35 @@ public class TApplication implements Runnable {
|
|||
*/
|
||||
public void doRepaint() {
|
||||
repaint = true;
|
||||
synchronized (drainEventQueue) {
|
||||
if (fillEventQueue.size() > 0) {
|
||||
// User input is waiting, that will update the screen. Wake
|
||||
// the backend reader.
|
||||
if (debugEvents) {
|
||||
System.err.printf("Drop: input waiting in backend\n");
|
||||
}
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (screenHandler != null) {
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - screenHandler.lastFlushTime < screenHandler.lastFrameTime) {
|
||||
// We cannot update the screen this quickly. Drop this
|
||||
// request.
|
||||
if (debugEvents) {
|
||||
System.err.printf("Drop: %d millis to render, %d since\n",
|
||||
screenHandler.lastFrameTime,
|
||||
now - screenHandler.lastFlushTime);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// It's been enough time since the last frame, and no user input is
|
||||
// around, so allow a screen repaint.
|
||||
wakeEventHandler();
|
||||
}
|
||||
|
||||
|
@ -2416,6 +2547,42 @@ public class TApplication implements Runnable {
|
|||
getScreen().invertCell(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a translucent window with a shadow on the screen.
|
||||
*
|
||||
* @param screen the screen
|
||||
* @param window the window
|
||||
*/
|
||||
private void drawTranslucentWindow(final Screen screen,
|
||||
final TWindow window) {
|
||||
|
||||
// Alpha blending: have the window draw to a snapshot of the screen
|
||||
// without alpha, and then merge it on the screen with alpha.
|
||||
int windowX = window.getX();
|
||||
int windowY = window.getY();
|
||||
int windowWidth = window.getWidth();
|
||||
int windowHeight = window.getHeight();
|
||||
Screen oldSnapshot = screen.snapshot(windowX, windowY,
|
||||
windowWidth + 2, windowHeight + 1);
|
||||
window.drawChildren();
|
||||
Screen newSnapshot = screen.snapshot(windowX, windowY,
|
||||
windowWidth, windowHeight);
|
||||
screen.copyScreen(oldSnapshot, windowX, windowY,
|
||||
windowWidth, windowHeight);
|
||||
screen.blendScreen(newSnapshot, windowX, windowY,
|
||||
windowWidth, windowHeight, window.getAlpha(), true);
|
||||
screen.resetClipping();
|
||||
|
||||
// Recreate the shadow effect by blending a black rectangle over just
|
||||
// the shadow region.
|
||||
final int shadowOpacity = 30;
|
||||
final int shadowAlpha = shadowOpacity * 255 / 100;
|
||||
screen.blendRectangle(windowX + windowWidth, windowY + 1,
|
||||
2, windowHeight - 1, 0x000000, shadowAlpha);
|
||||
screen.blendRectangle(windowX + 2, windowY + windowHeight,
|
||||
windowWidth, 1, 0x000000, shadowAlpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw everything.
|
||||
*/
|
||||
|
@ -2528,7 +2695,11 @@ public class TApplication implements Runnable {
|
|||
Collections.reverse(sorted);
|
||||
for (TWindow window: sorted) {
|
||||
if (window.isShown()) {
|
||||
window.drawChildren();
|
||||
if (translucence) {
|
||||
drawTranslucentWindow(getScreen(), window);
|
||||
} else {
|
||||
window.drawChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2572,7 +2743,13 @@ public class TApplication implements Runnable {
|
|||
}
|
||||
|
||||
if (menu.isActive()) {
|
||||
((TWindow) menu).drawChildren();
|
||||
if (translucence) {
|
||||
drawTranslucentWindow(getScreen(), menu);
|
||||
} else {
|
||||
((TWindow) menu).drawChildren();
|
||||
}
|
||||
|
||||
|
||||
// Reset the screen clipping so we can draw the next title.
|
||||
getScreen().resetClipping();
|
||||
}
|
||||
|
@ -2582,7 +2759,12 @@ public class TApplication implements Runnable {
|
|||
for (TMenu menu: subMenus) {
|
||||
// Reset the screen clipping so we can draw the next sub-menu.
|
||||
getScreen().resetClipping();
|
||||
((TWindow) menu).drawChildren();
|
||||
if (translucence) {
|
||||
drawTranslucentWindow(getScreen(), menu);
|
||||
} else {
|
||||
((TWindow) menu).drawChildren();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hideMenuBar == false) {
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.io.IOException;
|
|||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.Color;
|
||||
import jexer.bits.ColorTheme;
|
||||
import jexer.bits.CellAttributes;
|
||||
|
@ -230,15 +231,23 @@ public class TEditColorThemeWindow extends TWindow {
|
|||
CellAttributes background = getWindow().getBackground();
|
||||
CellAttributes attr = new CellAttributes();
|
||||
|
||||
drawBox(0, 0, getWidth(), getHeight(), border, background, 1,
|
||||
false);
|
||||
BorderStyle borderStyle;
|
||||
borderStyle = BorderStyle.getStyle(System.getProperty(
|
||||
"jexer.TEditColorTheme.options.borderStyle", "single"));
|
||||
|
||||
drawBox(0, 0, getWidth(), getHeight(), border, background,
|
||||
borderStyle, false);
|
||||
|
||||
attr.setTo(getTheme().getColor("twindow.background.modal"));
|
||||
if (isActive()) {
|
||||
attr.setForeColor(getTheme().getColor("tlabel").getForeColor());
|
||||
attr.setBold(getTheme().getColor("tlabel").isBold());
|
||||
}
|
||||
putStringXY(1, 0, i18n.getString("foregroundLabel"), attr);
|
||||
if (borderStyle.equals(BorderStyle.NONE)) {
|
||||
putStringXY(0, 0, i18n.getString("foregroundLabel"), attr);
|
||||
} else {
|
||||
putStringXY(1, 0, i18n.getString("foregroundLabel"), attr);
|
||||
}
|
||||
|
||||
// Have to draw the colors manually because the int value matches
|
||||
// SGR, not CGA.
|
||||
|
@ -518,15 +527,23 @@ public class TEditColorThemeWindow extends TWindow {
|
|||
CellAttributes background = getWindow().getBackground();
|
||||
CellAttributes attr = new CellAttributes();
|
||||
|
||||
drawBox(0, 0, getWidth(), getHeight(), border, background, 1,
|
||||
false);
|
||||
BorderStyle borderStyle;
|
||||
borderStyle = BorderStyle.getStyle(System.getProperty(
|
||||
"jexer.TEditColorTheme.options.borderStyle", "single"));
|
||||
|
||||
drawBox(0, 0, getWidth(), getHeight(), border, background,
|
||||
borderStyle, false);
|
||||
|
||||
attr.setTo(getTheme().getColor("twindow.background.modal"));
|
||||
if (isActive()) {
|
||||
attr.setForeColor(getTheme().getColor("tlabel").getForeColor());
|
||||
attr.setBold(getTheme().getColor("tlabel").isBold());
|
||||
}
|
||||
putStringXY(1, 0, i18n.getString("backgroundLabel"), attr);
|
||||
if (borderStyle.equals(BorderStyle.NONE)) {
|
||||
putStringXY(0, 0, i18n.getString("backgroundLabel"), attr);
|
||||
} else {
|
||||
putStringXY(1, 0, i18n.getString("backgroundLabel"), attr);
|
||||
}
|
||||
|
||||
// Have to draw the colors manually because the int value matches
|
||||
// SGR, not CGA.
|
||||
|
@ -931,4 +948,77 @@ public class TEditColorThemeWindow extends TWindow {
|
|||
editTheme.setColor(colorName, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is the foreground window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TEditColorTheme.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleForeground(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TEditColorTheme.borderStyle",
|
||||
"double");
|
||||
super.setBorderStyleForeground(style);
|
||||
} else {
|
||||
super.setBorderStyleForeground(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is the modal window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TEditColorTheme.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleModal(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TEditColorTheme.borderStyle",
|
||||
"double");
|
||||
super.setBorderStyleModal(style);
|
||||
} else {
|
||||
super.setBorderStyleModal(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is an inactive/background
|
||||
* window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TEditColorTheme.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleInactive(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TEditColorTheme.borderStyle",
|
||||
"double");
|
||||
super.setBorderStyleInactive(style);
|
||||
} else {
|
||||
super.setBorderStyleInactive(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is being dragged/resize.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TEditColorTheme.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleMoving(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TEditColorTheme.borderStyle",
|
||||
"double");
|
||||
super.setBorderStyleMoving(style);
|
||||
} else {
|
||||
super.setBorderStyleMoving(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -118,6 +118,17 @@ public class TImageWindow extends TScrollableWindow {
|
|||
|
||||
setTitle(file.getName());
|
||||
|
||||
int opacity = 100;
|
||||
try {
|
||||
opacity = Integer.parseInt(System.getProperty(
|
||||
"jexer.TImage.opacity", "100"));
|
||||
opacity = Math.max(opacity, 10);
|
||||
opacity = Math.min(opacity, 100);
|
||||
} catch (NumberFormatException e) {
|
||||
// SQUASH
|
||||
}
|
||||
setAlpha(opacity * 255 / 100);
|
||||
|
||||
setupAfterImage();
|
||||
}
|
||||
|
||||
|
|
|
@ -203,8 +203,13 @@ public class TLabel extends TWidget {
|
|||
mnemonicColor.setTo(getTheme().getColor("tlabel.mnemonic"));
|
||||
if (useWindowBackground) {
|
||||
CellAttributes background = getWindow().getBackground();
|
||||
color.setBackColor(background.getBackColor());
|
||||
mnemonicColor.setBackColor(background.getBackColor());
|
||||
if (background.getBackColorRGB() == -1) {
|
||||
color.setBackColor(background.getBackColor());
|
||||
mnemonicColor.setBackColor(background.getBackColor());
|
||||
} else {
|
||||
color.setBackColorRGB(background.getBackColorRGB());
|
||||
mnemonicColor.setBackColorRGB(background.getBackColorRGB());
|
||||
}
|
||||
}
|
||||
putStringXY(0, 0, mnemonic.getRawLabel(), color);
|
||||
if (mnemonic.getScreenShortcutIdx() >= 0) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
*/
|
||||
package jexer;
|
||||
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.StringUtils;
|
||||
|
||||
|
@ -133,11 +134,19 @@ public class TRadioGroup extends TWidget {
|
|||
radioGroupColor = getTheme().getColor("tradiogroup.inactive");
|
||||
}
|
||||
|
||||
BorderStyle borderStyle;
|
||||
borderStyle = BorderStyle.getStyle(System.getProperty(
|
||||
"jexer.TRadioGroup.borderStyle", "singleVdoubleH"));
|
||||
|
||||
drawBox(0, 0, getWidth(), getHeight(), radioGroupColor, radioGroupColor,
|
||||
3, false);
|
||||
borderStyle, false);
|
||||
|
||||
hLineXY(1, 0, StringUtils.width(label) + 2, ' ', radioGroupColor);
|
||||
putStringXY(2, 0, label, radioGroupColor);
|
||||
if (borderStyle.equals(BorderStyle.NONE)) {
|
||||
putStringXY(1, 0, label, radioGroupColor);
|
||||
} else {
|
||||
putStringXY(2, 0, label, radioGroupColor);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.ResourceBundle;
|
|||
|
||||
import jexer.backend.ECMA48Terminal;
|
||||
import jexer.backend.SwingTerminal;
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.GraphicsChars;
|
||||
import jexer.event.TKeypressEvent;
|
||||
|
@ -137,6 +138,11 @@ public class TScreenOptionsWindow extends TWindow {
|
|||
*/
|
||||
private TCheckBox rgbColor;
|
||||
|
||||
/**
|
||||
* The window opacity.
|
||||
*/
|
||||
private TField windowOpacity;
|
||||
|
||||
/**
|
||||
* The original font size.
|
||||
*/
|
||||
|
@ -207,6 +213,11 @@ public class TScreenOptionsWindow extends TWindow {
|
|||
*/
|
||||
private boolean oldRgbColor = false;
|
||||
|
||||
/**
|
||||
* The original window opacity.
|
||||
*/
|
||||
private int oldWindowOpacity;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -231,6 +242,15 @@ public class TScreenOptionsWindow extends TWindow {
|
|||
ecmaTerminal = (ECMA48Terminal) getScreen();
|
||||
}
|
||||
|
||||
addLabel(i18n.getString("windowOpacity"), 1, 0, "ttext", false,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
if (windowOpacity != null) {
|
||||
windowOpacity.activate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
addLabel(i18n.getString("fontName"), 3, 2, "ttext", false,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
|
@ -296,6 +316,70 @@ public class TScreenOptionsWindow extends TWindow {
|
|||
}
|
||||
});
|
||||
|
||||
// Window opacity
|
||||
windowOpacity = addField(31, 0, 4, true,
|
||||
Integer.toString(getAlpha() * 100 / 255),
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
int currentOpacity = getAlpha() * 100 / 255;
|
||||
int newOpacity = currentOpacity;
|
||||
newOpacity = Math.max(newOpacity, 10);
|
||||
newOpacity = Math.min(newOpacity, 100);
|
||||
try {
|
||||
newOpacity = Integer.parseInt(windowOpacity.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
fontSize.setText(Integer.toString(currentOpacity));
|
||||
}
|
||||
if (newOpacity != currentOpacity) {
|
||||
getApplication().setWindowOpacity(newOpacity);
|
||||
System.setProperty("jexer.TWindow.opacity",
|
||||
Integer.toString(newOpacity));
|
||||
}
|
||||
}
|
||||
},
|
||||
null);
|
||||
|
||||
addSpinner(35, 0,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
int currentOpacity = getAlpha() * 100 / 255;
|
||||
int newOpacity = currentOpacity;
|
||||
try {
|
||||
newOpacity = Integer.parseInt(windowOpacity.getText());
|
||||
newOpacity++;
|
||||
newOpacity = Math.min(newOpacity, 100);
|
||||
} catch (NumberFormatException e) {
|
||||
windowOpacity.setText(Integer.toString(currentOpacity));
|
||||
}
|
||||
windowOpacity.setText(Integer.toString(newOpacity));
|
||||
if (newOpacity != currentOpacity) {
|
||||
getApplication().setWindowOpacity(newOpacity);
|
||||
System.setProperty("jexer.TWindow.opacity",
|
||||
Integer.toString(newOpacity));
|
||||
}
|
||||
}
|
||||
},
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
int currentOpacity = getAlpha() * 100 / 255;
|
||||
int newOpacity = currentOpacity;
|
||||
try {
|
||||
newOpacity = Integer.parseInt(windowOpacity.getText());
|
||||
newOpacity--;
|
||||
newOpacity = Math.max(newOpacity, 10);
|
||||
} catch (NumberFormatException e) {
|
||||
windowOpacity.setText(Integer.toString(currentOpacity));
|
||||
}
|
||||
windowOpacity.setText(Integer.toString(newOpacity));
|
||||
if (newOpacity != currentOpacity) {
|
||||
getApplication().setWindowOpacity(newOpacity);
|
||||
System.setProperty("jexer.TWindow.opacity",
|
||||
Integer.toString(newOpacity));
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
sixel = addCheckBox(3, 15, i18n.getString("sixel"),
|
||||
(ecmaTerminal != null ? ecmaTerminal.hasSixel() :
|
||||
System.getProperty("jexer.ECMA48.sixel",
|
||||
|
@ -849,6 +933,9 @@ public class TScreenOptionsWindow extends TWindow {
|
|||
ecmaTerminal.setWideCharImages(oldWideCharImages);
|
||||
ecmaTerminal.setRgbColor(oldRgbColor);
|
||||
}
|
||||
getApplication().setWindowOpacity(oldWindowOpacity);
|
||||
System.setProperty("jexer.TWindow.opacity",
|
||||
Integer.toString(oldWindowOpacity));
|
||||
getApplication().closeWindow(this);
|
||||
return;
|
||||
}
|
||||
|
@ -870,15 +957,35 @@ public class TScreenOptionsWindow extends TWindow {
|
|||
|
||||
int left = 34;
|
||||
|
||||
BorderStyle borderStyle;
|
||||
borderStyle = BorderStyle.getStyle(System.getProperty(
|
||||
"jexer.TScreenOptions.options.borderStyle", "single"));
|
||||
|
||||
CellAttributes color = getTheme().getColor("ttext");
|
||||
drawBox(2, 2, left + 24, 14, color, color);
|
||||
putStringXY(4, 2, i18n.getString("swingOptions"), color);
|
||||
drawBox(2, 2, left + 24, 14, color, color, borderStyle, false);
|
||||
if (borderStyle.equals(BorderStyle.NONE)) {
|
||||
putStringXY(3, 2, i18n.getString("swingOptions"), color);
|
||||
} else {
|
||||
putStringXY(4, 2, i18n.getString("swingOptions"), color);
|
||||
}
|
||||
|
||||
drawBox(2, 15, left + 12, 22, color, color);
|
||||
putStringXY(4, 15, i18n.getString("xtermOptions"), color);
|
||||
|
||||
drawBox(left + 2, 5, left + 22, 10, color, color, 3, false);
|
||||
putStringXY(left + 4, 5, i18n.getString("sample"), color);
|
||||
drawBox(2, 15, left + 12, 22, color, color, borderStyle, false);
|
||||
if (borderStyle.equals(BorderStyle.NONE)) {
|
||||
putStringXY(3, 15, i18n.getString("xtermOptions"), color);
|
||||
} else {
|
||||
putStringXY(4, 15, i18n.getString("xtermOptions"), color);
|
||||
}
|
||||
|
||||
borderStyle = BorderStyle.getStyle(System.getProperty(
|
||||
"jexer.TScreenOptions.grid.borderStyle", "singleVdoubleH"));
|
||||
|
||||
drawBox(left + 2, 5, left + 22, 10, color, color, borderStyle, false);
|
||||
if (borderStyle.equals(BorderStyle.NONE)) {
|
||||
putStringXY(left + 2, 5, i18n.getString("sample"), color);
|
||||
} else {
|
||||
putStringXY(left + 4, 5, i18n.getString("sample"), color);
|
||||
}
|
||||
for (int i = 6; i < 9; i++) {
|
||||
hLineXY(left + 3, i, 18, GraphicsChars.HATCH, color);
|
||||
}
|
||||
|
@ -889,4 +996,77 @@ public class TScreenOptionsWindow extends TWindow {
|
|||
// TScreenOptionsWindow ---------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is the foreground window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TScreenOptions.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleForeground(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TScreenOptions.borderStyle",
|
||||
"double");
|
||||
super.setBorderStyleForeground(style);
|
||||
} else {
|
||||
super.setBorderStyleForeground(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is the modal window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TScreenOptions.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleModal(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TScreenOptions.borderStyle",
|
||||
"double");
|
||||
super.setBorderStyleModal(style);
|
||||
} else {
|
||||
super.setBorderStyleModal(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is an inactive/background
|
||||
* window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TScreenOptions.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleInactive(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TScreenOptions.borderStyle",
|
||||
"double");
|
||||
super.setBorderStyleInactive(style);
|
||||
} else {
|
||||
super.setBorderStyleInactive(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is being dragged/resize.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TScreenOptions.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleMoving(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TScreenOptions.borderStyle",
|
||||
"double");
|
||||
super.setBorderStyleMoving(style);
|
||||
} else {
|
||||
super.setBorderStyleMoving(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,3 +32,6 @@ sixelPaletteSize=Sixel &palette size:
|
|||
sixelSharedPalette=Us&e shared sixel palette
|
||||
wideCharImages=D&raw fullwidth characters as images
|
||||
rgbColor=Use 24-bit R&GB for all colors
|
||||
|
||||
xtermOptions=\ Other\
|
||||
windowOpacity=W&indow opacity (translucence):
|
||||
|
|
|
@ -709,13 +709,11 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
if (reverse) {
|
||||
if (ch.getForeColorRGB() < 0) {
|
||||
newCell.setBackColor(ch.getForeColor());
|
||||
newCell.setBackColorRGB(-1);
|
||||
} else {
|
||||
newCell.setBackColorRGB(ch.getForeColorRGB());
|
||||
}
|
||||
if (ch.getBackColorRGB() < 0) {
|
||||
newCell.setForeColor(ch.getBackColor());
|
||||
newCell.setForeColorRGB(-1);
|
||||
} else {
|
||||
newCell.setForeColorRGB(ch.getBackColorRGB());
|
||||
}
|
||||
|
@ -1299,6 +1297,7 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
} else if (getScreen() instanceof ECMA48Terminal) {
|
||||
ECMA48Terminal terminal = (ECMA48Terminal) getScreen();
|
||||
|
||||
/* Always render double-width/height with images.
|
||||
if (!terminal.hasSixel()
|
||||
&& !terminal.hasJexerImages()
|
||||
&& !terminal.hasIterm2Images()
|
||||
|
@ -1309,13 +1308,17 @@ public class TTerminalWidget extends TScrollableWidget
|
|||
putCharXY(x + 1, y, ' ', cell);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
cursorBlinkVisible = blinkState;
|
||||
|
||||
/* Always render double-width/height with images.
|
||||
} else {
|
||||
// We don't know how to dray glyphs to this screen, draw them as
|
||||
// text and bail out.
|
||||
putCharXY(x, y, cell);
|
||||
putCharXY(x + 1, y, ' ', cell);
|
||||
return;
|
||||
*/
|
||||
}
|
||||
|
||||
if ((textWidth != lastTextWidth) || (textHeight != lastTextHeight)) {
|
||||
|
|
|
@ -160,6 +160,17 @@ public class TTerminalWindow extends TScrollableWindow {
|
|||
onShellExit();
|
||||
}
|
||||
});
|
||||
|
||||
int opacity = 95;
|
||||
try {
|
||||
opacity = Integer.parseInt(System.getProperty(
|
||||
"jexer.TTerminal.opacity", "95"));
|
||||
opacity = Math.max(opacity, 10);
|
||||
opacity = Math.min(opacity, 100);
|
||||
} catch (NumberFormatException e) {
|
||||
// SQUASH
|
||||
}
|
||||
setAlpha(opacity * 255 / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,6 +227,17 @@ public class TTerminalWindow extends TScrollableWindow {
|
|||
onShellExit();
|
||||
}
|
||||
});
|
||||
|
||||
int opacity = 95;
|
||||
try {
|
||||
opacity = Integer.parseInt(System.getProperty(
|
||||
"jexer.TTerminal.opacity", "95"));
|
||||
opacity = Math.max(opacity, 10);
|
||||
opacity = Math.min(opacity, 100);
|
||||
} catch (NumberFormatException e) {
|
||||
// SQUASH
|
||||
}
|
||||
setAlpha(opacity * 255 / 100);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
@ -366,13 +366,11 @@ public class TTextPicture extends TScrollableWidget
|
|||
if (reverse) {
|
||||
if (ch.getForeColorRGB() < 0) {
|
||||
newCell.setBackColor(ch.getForeColor());
|
||||
newCell.setBackColorRGB(-1);
|
||||
} else {
|
||||
newCell.setBackColorRGB(ch.getForeColorRGB());
|
||||
}
|
||||
if (ch.getBackColorRGB() < 0) {
|
||||
newCell.setForeColor(ch.getBackColor());
|
||||
newCell.setForeColorRGB(-1);
|
||||
} else {
|
||||
newCell.setForeColorRGB(ch.getBackColorRGB());
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.ArrayList;
|
|||
|
||||
import jexer.backend.Screen;
|
||||
import jexer.bits.Animation;
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.Cell;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.Clipboard;
|
||||
|
@ -1419,6 +1420,13 @@ public abstract class TWidget implements Comparable<TWidget> {
|
|||
* @return the ColorTheme
|
||||
*/
|
||||
public final ColorTheme getTheme() {
|
||||
if (this instanceof TWindow) {
|
||||
TWindow window = (TWindow) this;
|
||||
if (window.theme != null) {
|
||||
return window.theme;
|
||||
}
|
||||
}
|
||||
|
||||
if (window != null) {
|
||||
return window.getApplication().getTheme();
|
||||
}
|
||||
|
@ -2136,18 +2144,16 @@ public abstract class TWidget implements Comparable<TWidget> {
|
|||
* @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 borderStyle style of border
|
||||
* @param shadow if true, draw a "shadow" on the box
|
||||
*/
|
||||
public final 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) {
|
||||
final BorderStyle borderStyle, final boolean shadow) {
|
||||
|
||||
getScreen().drawBox(left, top, right, bottom, border, background,
|
||||
borderType, shadow);
|
||||
borderStyle, shadow);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,7 +32,9 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import jexer.backend.Screen;
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.ColorTheme;
|
||||
import jexer.bits.GraphicsChars;
|
||||
import jexer.bits.StringUtils;
|
||||
import jexer.event.TCommandEvent;
|
||||
|
@ -185,6 +187,13 @@ public class TWindow extends TWidget {
|
|||
*/
|
||||
boolean hidden = false;
|
||||
|
||||
/**
|
||||
* Widgets on this window can pull colors from this ColorTheme. Note
|
||||
* package private access: if null, TWidget.getTheme() will pull from
|
||||
* TApplication.
|
||||
*/
|
||||
ColorTheme theme;
|
||||
|
||||
/**
|
||||
* A window may have a status bar associated with it. TApplication will
|
||||
* draw this status bar last, and will also route events to it first
|
||||
|
@ -218,6 +227,31 @@ public class TWindow extends TWidget {
|
|||
*/
|
||||
protected Tackboard overlay = null;
|
||||
|
||||
/**
|
||||
* The border style for an active window.
|
||||
*/
|
||||
protected BorderStyle borderStyleActive = BorderStyle.DOUBLE;
|
||||
|
||||
/**
|
||||
* The border style for an active modal window.
|
||||
*/
|
||||
protected BorderStyle borderStyleActiveModal = BorderStyle.DOUBLE;
|
||||
|
||||
/**
|
||||
* The border style for an inactive window.
|
||||
*/
|
||||
protected BorderStyle borderStyleInactive = BorderStyle.SINGLE;
|
||||
|
||||
/**
|
||||
* The border style for a window being dragged/resized.
|
||||
*/
|
||||
protected BorderStyle borderStyleMoving = BorderStyle.SINGLE;
|
||||
|
||||
/**
|
||||
* The alpha blending value.
|
||||
*/
|
||||
private int alpha = 255;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -307,6 +341,23 @@ public class TWindow extends TWidget {
|
|||
|
||||
// Add me to the application
|
||||
application.addWindowToApplication(this);
|
||||
|
||||
// Set default borders
|
||||
setBorderStyleForeground(null);
|
||||
setBorderStyleInactive(null);
|
||||
setBorderStyleModal(null);
|
||||
setBorderStyleMoving(null);
|
||||
|
||||
int opacity = 95;
|
||||
try {
|
||||
opacity = Integer.parseInt(System.getProperty(
|
||||
"jexer.TWindow.opacity", "95"));
|
||||
opacity = Math.max(opacity, 10);
|
||||
opacity = Math.min(opacity, 100);
|
||||
} catch (NumberFormatException e) {
|
||||
// SQUASH
|
||||
}
|
||||
setAlpha(opacity * 255 / 100);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -359,6 +410,7 @@ public class TWindow extends TWidget {
|
|||
*/
|
||||
protected boolean mouseOnResize() {
|
||||
if (((flags & RESIZABLE) != 0)
|
||||
&& (getBorderStyle() != BorderStyle.NONE)
|
||||
&& !isModal()
|
||||
&& (mouse != null)
|
||||
&& (mouse.getAbsoluteY() == getY() + getHeight() - 1)
|
||||
|
@ -393,6 +445,12 @@ public class TWindow extends TWidget {
|
|||
getChildren().remove(w);
|
||||
}
|
||||
}
|
||||
if (underlay != null) {
|
||||
underlay.clear();
|
||||
}
|
||||
if (overlay != null) {
|
||||
overlay.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -662,9 +720,12 @@ public class TWindow extends TWidget {
|
|||
}
|
||||
|
||||
/*
|
||||
* Only permit keyboard resizing if the window was RESIZABLE.
|
||||
* Only permit keyboard resizing if the window was RESIZABLE and
|
||||
* there is a window border.
|
||||
*/
|
||||
if ((flags & RESIZABLE) != 0) {
|
||||
if (((flags & RESIZABLE) != 0)
|
||||
&& (getBorderStyle() != BorderStyle.NONE)
|
||||
) {
|
||||
|
||||
if (keypress.equals(kbShiftLeft)) {
|
||||
if ((getWidth() > minimumWindowWidth)
|
||||
|
@ -938,9 +999,9 @@ public class TWindow extends TWidget {
|
|||
// Draw the box and background first.
|
||||
CellAttributes border = getBorder();
|
||||
CellAttributes background = getBackground();
|
||||
int borderType = getBorderType();
|
||||
drawBox(0, 0, getWidth(), getHeight(), border, background, borderType,
|
||||
true);
|
||||
BorderStyle borderStyle = getBorderStyle();
|
||||
drawBox(0, 0, getWidth(), getHeight(), border, background, borderStyle,
|
||||
!getApplication().hasTranslucence());
|
||||
|
||||
if ((title != null) && (title.length() > 0)) {
|
||||
// Draw the title
|
||||
|
@ -952,11 +1013,17 @@ public class TWindow extends TWidget {
|
|||
}
|
||||
|
||||
if (isActive()) {
|
||||
int lBracket = '[';
|
||||
int rBracket = ']';
|
||||
if (borderStyle.equals(BorderStyle.SINGLE_ROUND)) {
|
||||
lBracket = '(';
|
||||
rBracket = ')';
|
||||
}
|
||||
|
||||
// Draw the close button
|
||||
if ((flags & NOCLOSEBOX) == 0) {
|
||||
putCharXY(2, 0, '[', border);
|
||||
putCharXY(4, 0, ']', border);
|
||||
putCharXY(2, 0, lBracket, border);
|
||||
putCharXY(4, 0, rBracket, border);
|
||||
if (mouseOnClose() && mouse.isMouse1()) {
|
||||
putCharXY(3, 0, GraphicsChars.CP437[0x0F],
|
||||
getBorderControls());
|
||||
|
@ -969,8 +1036,8 @@ public class TWindow extends TWidget {
|
|||
// Draw the maximize button
|
||||
if (!isModal() && ((flags & NOZOOMBOX) == 0)) {
|
||||
|
||||
putCharXY(getWidth() - 5, 0, '[', border);
|
||||
putCharXY(getWidth() - 3, 0, ']', border);
|
||||
putCharXY(getWidth() - 5, 0, lBracket, border);
|
||||
putCharXY(getWidth() - 3, 0, rBracket, border);
|
||||
if (mouseOnMaximize() && mouse.isMouse1()) {
|
||||
putCharXY(getWidth() - 4, 0, GraphicsChars.CP437[0x0F],
|
||||
getBorderControls());
|
||||
|
@ -986,12 +1053,15 @@ public class TWindow extends TWidget {
|
|||
}
|
||||
|
||||
// Draw the resize corner
|
||||
if (!isModal() && ((flags & RESIZABLE) != 0)) {
|
||||
if (!isModal()
|
||||
&& ((flags & RESIZABLE) != 0)
|
||||
&& (getBorderStyle() != BorderStyle.NONE)
|
||||
) {
|
||||
if ((flags & RESIZABLE) != 0) {
|
||||
putCharXY(getWidth() - 2, getHeight() - 1,
|
||||
GraphicsChars.SINGLE_BAR, getBorderControls());
|
||||
getBorderStyle().getHorizontal(), getBorderControls());
|
||||
putCharXY(getWidth() - 1, getHeight() - 1,
|
||||
GraphicsChars.LRCORNER, getBorderControls());
|
||||
getBorderStyle().getBottomRight(), getBorderControls());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1428,7 +1498,9 @@ public class TWindow extends TWidget {
|
|||
* @return true if this window is resizable
|
||||
*/
|
||||
public final boolean isResizable() {
|
||||
if ((flags & RESIZABLE) == 0) {
|
||||
if (((flags & RESIZABLE) == 0)
|
||||
|| (getBorderStyle() == BorderStyle.NONE)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1525,29 +1597,32 @@ public class TWindow extends TWidget {
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the border line type.
|
||||
* Retrieve the border line style.
|
||||
*
|
||||
* @return the border line type
|
||||
* @return the border line style
|
||||
*/
|
||||
private int getBorderType() {
|
||||
public BorderStyle getBorderStyle() {
|
||||
if (!isModal()
|
||||
&& (inWindowMove || inWindowResize || inKeyboardResize)
|
||||
) {
|
||||
assert (isActive());
|
||||
return 1;
|
||||
return borderStyleMoving;
|
||||
} else if (isModal() && inWindowMove) {
|
||||
assert (isActive());
|
||||
return 1;
|
||||
// Modals cannot be resized, hence the separate check.
|
||||
return borderStyleMoving;
|
||||
} else if (isModal()) {
|
||||
if (isActive()) {
|
||||
return 2;
|
||||
return borderStyleActiveModal;
|
||||
} else {
|
||||
return 1;
|
||||
// One can stack modals, so an inactive but modal window is
|
||||
// possible.
|
||||
return borderStyleInactive;
|
||||
}
|
||||
} else if (isActive()) {
|
||||
return 2;
|
||||
return borderStyleActive;
|
||||
} else {
|
||||
return 1;
|
||||
return borderStyleInactive;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1631,4 +1706,158 @@ public class TWindow extends TWidget {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is the foreground window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TWindow.borderStyleForeground.
|
||||
*/
|
||||
public void setBorderStyleForeground(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TWindow.borderStyleForeground",
|
||||
"double");
|
||||
borderStyleActive = BorderStyle.getStyle(style);
|
||||
} else if (borderStyle.equals("default")) {
|
||||
borderStyleActive = BorderStyle.DOUBLE;
|
||||
} else {
|
||||
borderStyleActive = BorderStyle.getStyle(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the border style for the window when it is the foreground window.
|
||||
*
|
||||
* @return the border style
|
||||
*/
|
||||
public BorderStyle getBorderStyleForeground() {
|
||||
return borderStyleActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is the modal window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TWindow.borderStyleModal.
|
||||
*/
|
||||
public void setBorderStyleModal(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TWindow.borderStyleModal",
|
||||
"double");
|
||||
borderStyleActiveModal = BorderStyle.getStyle(style);
|
||||
} else if (borderStyle.equals("default")) {
|
||||
borderStyleActiveModal = BorderStyle.DOUBLE;
|
||||
} else {
|
||||
borderStyleActiveModal = BorderStyle.getStyle(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the border style for the window when it is the modal window.
|
||||
*
|
||||
* @return the border style
|
||||
*/
|
||||
public BorderStyle getBorderStyleModal() {
|
||||
return borderStyleActiveModal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is an inactive/background
|
||||
* window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TWindow.borderStyleInactive.
|
||||
*/
|
||||
public void setBorderStyleInactive(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TWindow.borderStyleInactive",
|
||||
"single");
|
||||
borderStyleInactive = BorderStyle.getStyle(style);
|
||||
} else if (borderStyle.equals("default")) {
|
||||
borderStyleInactive = BorderStyle.SINGLE;
|
||||
} else {
|
||||
borderStyleInactive = BorderStyle.getStyle(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the border style for the window when it is an inactive/background
|
||||
* window.
|
||||
*
|
||||
* @return the border style
|
||||
*/
|
||||
public BorderStyle getBorderStyleInactive() {
|
||||
return borderStyleInactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is being dragged/resize.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TWindow.borderStyleMoving.
|
||||
*/
|
||||
public void setBorderStyleMoving(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TWindow.borderStyleMoving",
|
||||
"single");
|
||||
borderStyleMoving = BorderStyle.getStyle(style);
|
||||
} else if (borderStyle.equals("default")) {
|
||||
borderStyleMoving = BorderStyle.SINGLE;
|
||||
} else {
|
||||
borderStyleMoving = BorderStyle.getStyle(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the border style for the window when it is being dragged/resize.
|
||||
*
|
||||
* @return the border style
|
||||
*/
|
||||
public BorderStyle getBorderStyleMoving() {
|
||||
return borderStyleMoving;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the custom color theme for this window.
|
||||
*
|
||||
* @return the color theme, or null if the window does not have a custom
|
||||
* color theme
|
||||
*/
|
||||
public final ColorTheme getWindowTheme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom color theme for this window.
|
||||
*
|
||||
* @param theme the custom theme, or null to use the application-level
|
||||
* color theme
|
||||
*/
|
||||
public final void setWindowTheme(final ColorTheme theme) {
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the alpha level for this window.
|
||||
*
|
||||
* @param alpha a value between 0 (fully transparent) and 255 (fully
|
||||
* opaque)
|
||||
*/
|
||||
public void setAlpha(final int alpha) {
|
||||
assert ((alpha >= 0) && (alpha <= 255));
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the alpha level for this window.
|
||||
*
|
||||
* @return a value between 0 (fully transparent) and 255 (fully opaque)
|
||||
*/
|
||||
public int getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -829,19 +829,31 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
}
|
||||
if (output != null) {
|
||||
if (hasSynchronizedOutput) {
|
||||
// Begin Synchronized Update (BSU)
|
||||
output.write("\033[?2026h");
|
||||
output.write(sb.toString());
|
||||
// End Synchronized Update (ESU)
|
||||
output.write("\033[?2026l");
|
||||
if (sb.length() > 0) {
|
||||
// Begin Synchronized Update (BSU)
|
||||
output.write("\033[?2026h");
|
||||
if (debugToStderr) {
|
||||
System.err.printf("Writing %d bytes to terminal (sync)\n",
|
||||
sb.length());
|
||||
}
|
||||
output.write(sb.toString());
|
||||
// End Synchronized Update (ESU)
|
||||
output.write("\033[?2026l");
|
||||
}
|
||||
if (debugToStderr) {
|
||||
System.err.printf("flushPhysical() \033[?2026h%s\033[?2026l\n",
|
||||
sb.toString());
|
||||
}
|
||||
} else {
|
||||
output.write(sb.toString());
|
||||
if (sb.length() > 0) {
|
||||
if (debugToStderr) {
|
||||
System.err.printf("Writing %d bytes to terminal\n",
|
||||
sb.length());
|
||||
}
|
||||
output.write(sb.toString());
|
||||
}
|
||||
}
|
||||
flush();
|
||||
output.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1073,24 +1085,41 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
char [] readBuffer = new char[128];
|
||||
List<TInputEvent> events = new ArrayList<TInputEvent>();
|
||||
|
||||
// boolean debugToStderr = true;
|
||||
|
||||
while (!done && !stopReaderThread) {
|
||||
try {
|
||||
// We assume that if inputStream has bytes available, then
|
||||
// input won't block on read().
|
||||
if (debugToStderr) {
|
||||
System.err.printf("Looking for input...");
|
||||
}
|
||||
|
||||
int n = inputStream.available();
|
||||
|
||||
/*
|
||||
System.err.printf("inputStream.available(): %d\n", n);
|
||||
System.err.flush();
|
||||
*/
|
||||
if (debugToStderr) {
|
||||
if (n == 0) {
|
||||
System.err.println("none.");
|
||||
}
|
||||
if (n < 0) {
|
||||
System.err.printf("WHAT?! n = %d\n", n);
|
||||
}
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
if (debugToStderr) {
|
||||
System.err.printf("%d bytes to read.\n", n);
|
||||
}
|
||||
|
||||
if (readBuffer.length < n) {
|
||||
// The buffer wasn't big enough, make it huger
|
||||
readBuffer = new char[readBuffer.length * 2];
|
||||
}
|
||||
|
||||
// System.err.printf("BEFORE read()\n"); System.err.flush();
|
||||
if (debugToStderr) {
|
||||
System.err.printf("B4 read(): readBuffer.length = %d\n",
|
||||
readBuffer.length);
|
||||
}
|
||||
|
||||
int rc = input.read(readBuffer, 0, readBuffer.length);
|
||||
|
||||
|
@ -1100,9 +1129,22 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
*/
|
||||
|
||||
if (rc == -1) {
|
||||
if (debugToStderr) {
|
||||
System.err.println(" ---- EOF ----");
|
||||
}
|
||||
|
||||
// This is EOF
|
||||
done = true;
|
||||
} else {
|
||||
if (debugToStderr) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < rc; i++) {
|
||||
sb.append(readBuffer[i]);
|
||||
}
|
||||
System.err.printf("%d rc = %d INPUT: ",
|
||||
System.currentTimeMillis(), rc);
|
||||
System.err.println(sb.toString());
|
||||
}
|
||||
for (int i = 0; i < rc; i++) {
|
||||
int ch = readBuffer[i];
|
||||
processChar(events, (char)ch);
|
||||
|
@ -1111,27 +1153,62 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
if (events.size() > 0) {
|
||||
// Add to the queue for the backend thread to
|
||||
// be able to obtain.
|
||||
if (debugToStderr) {
|
||||
System.err.printf("Checking eventQueue...");
|
||||
}
|
||||
|
||||
synchronized (eventQueue) {
|
||||
eventQueue.addAll(events);
|
||||
}
|
||||
if (debugToStderr) {
|
||||
System.err.printf("done.\n");
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
if (debugToStderr) {
|
||||
System.err.printf("Waking up listener...");
|
||||
}
|
||||
|
||||
synchronized (listener) {
|
||||
listener.notifyAll();
|
||||
}
|
||||
if (debugToStderr) {
|
||||
System.err.printf("done.\n");
|
||||
}
|
||||
|
||||
}
|
||||
events.clear();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (debugToStderr) {
|
||||
System.err.println("Looking for idle events");
|
||||
}
|
||||
getIdleEvents(events);
|
||||
if (events.size() > 0) {
|
||||
if (debugToStderr) {
|
||||
System.err.printf("Checking eventQueue...");
|
||||
}
|
||||
|
||||
synchronized (eventQueue) {
|
||||
eventQueue.addAll(events);
|
||||
}
|
||||
if (debugToStderr) {
|
||||
System.err.printf("done.\n");
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
if (debugToStderr) {
|
||||
System.err.printf("Waking up listener...");
|
||||
}
|
||||
|
||||
synchronized (listener) {
|
||||
listener.notifyAll();
|
||||
}
|
||||
if (debugToStderr) {
|
||||
System.err.printf("done.\n");
|
||||
}
|
||||
|
||||
}
|
||||
events.clear();
|
||||
}
|
||||
|
@ -1338,6 +1415,7 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
y, x, lastX, textEnd);
|
||||
System.err.printf(" lCell: %s\n", lCell);
|
||||
System.err.printf(" pCell: %s\n", pCell);
|
||||
System.err.printf(" lastAttr: %s\n", lastAttr);
|
||||
System.err.printf(" ==== \n");
|
||||
}
|
||||
|
||||
|
@ -1420,158 +1498,84 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
assert (!lCell.isImage());
|
||||
|
||||
// Now emit only the modified attributes
|
||||
if ((lCell.getForeColor() != lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() != lastAttr.getBackColor())
|
||||
&& (!lCell.isRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
// Both colors changed, attributes the same
|
||||
sb.append(color(lCell.isBold(),
|
||||
lCell.getForeColor(), lCell.getBackColor()));
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("1 Change only fore/back colors\n");
|
||||
}
|
||||
|
||||
} else if (lCell.isRGB()
|
||||
&& (lCell.getForeColorRGB() != lastAttr.getForeColorRGB())
|
||||
&& (lCell.getBackColorRGB() != lastAttr.getBackColorRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
// Both colors changed, attributes the same
|
||||
sb.append(colorRGB(lCell.getForeColorRGB(),
|
||||
lCell.getBackColorRGB()));
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("1 Change only fore/back colors (RGB)\n");
|
||||
}
|
||||
} else if ((lCell.getForeColor() != lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() != lastAttr.getBackColor())
|
||||
&& (!lCell.isRGB())
|
||||
&& (lCell.isBold() != lastAttr.isBold())
|
||||
&& (lCell.isReverse() != lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() != lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() != lastAttr.isBlink())
|
||||
) {
|
||||
// Everything is different
|
||||
sb.append(color(lCell.getForeColor(),
|
||||
lCell.getBackColor(),
|
||||
lCell.isBold(), lCell.isReverse(),
|
||||
lCell.isBlink(),
|
||||
lCell.isUnderline()));
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("2 Set all attributes\n");
|
||||
}
|
||||
} else if ((lCell.getForeColor() != lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() == lastAttr.getBackColor())
|
||||
&& (!lCell.isRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
|
||||
// Attributes same, foreColor different
|
||||
sb.append(color(lCell.isBold(),
|
||||
lCell.getForeColor(), true));
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("3 Change foreColor\n");
|
||||
}
|
||||
} else if (lCell.isRGB()
|
||||
&& (lCell.getForeColorRGB() != lastAttr.getForeColorRGB())
|
||||
&& (lCell.getBackColorRGB() == lastAttr.getBackColorRGB())
|
||||
&& (lCell.getForeColorRGB() >= 0)
|
||||
&& (lCell.getBackColorRGB() >= 0)
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
// Attributes same, foreColor different
|
||||
sb.append(colorRGB(lCell.getForeColorRGB(), true));
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("3 Change foreColor (RGB)\n");
|
||||
}
|
||||
} else if ((lCell.getForeColor() == lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() != lastAttr.getBackColor())
|
||||
&& (!lCell.isRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
// Attributes same, backColor different
|
||||
sb.append(color(lCell.isBold(),
|
||||
lCell.getBackColor(), false));
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("4 Change backColor\n");
|
||||
}
|
||||
} else if (lCell.isRGB()
|
||||
&& (lCell.getForeColorRGB() == lastAttr.getForeColorRGB())
|
||||
&& (lCell.getBackColorRGB() != lastAttr.getBackColorRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
// Attributes same, foreColor different
|
||||
sb.append(colorRGB(lCell.getBackColorRGB(), false));
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("5 Change backColor (RGB)\n");
|
||||
}
|
||||
} else if ((lCell.getForeColor() == lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() == lastAttr.getBackColor())
|
||||
&& (lCell.getForeColorRGB() == lastAttr.getForeColorRGB())
|
||||
&& (lCell.getBackColorRGB() == lastAttr.getBackColorRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
|
||||
// All attributes the same, just print the char
|
||||
// NOP
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("6 Only emit character\n");
|
||||
}
|
||||
} else {
|
||||
// Just reset everything again
|
||||
if (!lCell.isRGB()) {
|
||||
sb.append(color(lCell.getForeColor(),
|
||||
lCell.getBackColor(),
|
||||
lCell.isBold(),
|
||||
lCell.isReverse(),
|
||||
lCell.isBlink(),
|
||||
lCell.isUnderline()));
|
||||
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("7 Change all attributes\n");
|
||||
}
|
||||
StringBuilder attrSgr = new StringBuilder(8);
|
||||
if (lCell.isBold() != lastAttr.isBold()) {
|
||||
if (lCell.isBold()) {
|
||||
attrSgr.append(";1");
|
||||
} else {
|
||||
sb.append(colorRGB(lCell.getForeColorRGB(),
|
||||
lCell.getBackColorRGB(),
|
||||
lCell.isBold(),
|
||||
lCell.isReverse(),
|
||||
lCell.isBlink(),
|
||||
lCell.isUnderline()));
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.printf("8 Change all attributes (RGB)\n");
|
||||
}
|
||||
attrSgr.append(";22");
|
||||
}
|
||||
|
||||
}
|
||||
if (lCell.isUnderline() != lastAttr.isUnderline()) {
|
||||
if (lCell.isUnderline()) {
|
||||
attrSgr.append(";4");
|
||||
} else {
|
||||
attrSgr.append(";24");
|
||||
}
|
||||
}
|
||||
if (lCell.isBlink() != lastAttr.isBlink()) {
|
||||
if (lCell.isBlink()) {
|
||||
attrSgr.append(";5");
|
||||
} else {
|
||||
attrSgr.append(";25");
|
||||
}
|
||||
}
|
||||
if (lCell.isReverse() != lastAttr.isReverse()) {
|
||||
if (lCell.isReverse()) {
|
||||
attrSgr.append(";7");
|
||||
} else {
|
||||
attrSgr.append(";27");
|
||||
}
|
||||
}
|
||||
if (attrSgr.length() > 0) {
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.println("2 attr: " + attrSgr.substring(1));
|
||||
}
|
||||
sb.append("\033[");
|
||||
sb.append(attrSgr.substring(1));
|
||||
sb.append("m");
|
||||
}
|
||||
|
||||
if ((lCell.getForeColorRGB() >= 0)
|
||||
&& ((lCell.getForeColorRGB() != lastAttr.getForeColorRGB())
|
||||
|| (lastAttr.getForeColorRGB() < 0))
|
||||
) {
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.println("3 set foreColorRGB");
|
||||
}
|
||||
sb.append(colorRGB(lCell.getForeColorRGB(), true));
|
||||
} else {
|
||||
if ((lCell.getForeColorRGB() < 0)
|
||||
&& ((lastAttr.getForeColorRGB() >= 0)
|
||||
|| !lCell.getForeColor().equals(lastAttr.getForeColor()))
|
||||
) {
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.println("4 set foreColor");
|
||||
}
|
||||
sb.append(color(lCell.getForeColor(), true, true));
|
||||
}
|
||||
}
|
||||
|
||||
if ((lCell.getBackColorRGB() >= 0)
|
||||
&& ((lCell.getBackColorRGB() != lastAttr.getBackColorRGB())
|
||||
|| (lastAttr.getBackColorRGB() < 0))
|
||||
) {
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.println("5 set backColorRGB");
|
||||
}
|
||||
sb.append(colorRGB(lCell.getBackColorRGB(), false));
|
||||
} else {
|
||||
if ((lCell.getBackColorRGB() < 0)
|
||||
&& ((lastAttr.getBackColorRGB() >= 0)
|
||||
|| !lCell.getBackColor().equals(lastAttr.getBackColor()))
|
||||
) {
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.println("6 set backColor");
|
||||
}
|
||||
sb.append(color(lCell.getBackColor(), false, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the character
|
||||
if (wideCharImages
|
||||
// Don't emit the right-half of full-width chars.
|
||||
|
@ -2457,6 +2461,10 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// We have changed a system color. Redraw the entire screen.
|
||||
clearPhysical();
|
||||
reallyCleared = true;
|
||||
} catch (NumberFormatException e) {
|
||||
return;
|
||||
}
|
||||
|
@ -2489,7 +2497,7 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
boolean alt = false;
|
||||
boolean shift = false;
|
||||
|
||||
if (debugToStderr && false) {
|
||||
if (debugToStderr) {
|
||||
System.err.printf("state: %s ch %c\r\n", state, ch);
|
||||
}
|
||||
|
||||
|
@ -4341,6 +4349,59 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SGR parameter sequence for several attributes. This sequence
|
||||
* first resets all attributes to default, then sets attributes as per
|
||||
* the parameters.
|
||||
*
|
||||
* @param bold if true, set bold
|
||||
* @param reverse if true, set reverse
|
||||
* @param blink if true, set blink
|
||||
* @param underline if true, set underline
|
||||
* @return the string to emit to an ANSI / ECMA-style terminal,
|
||||
* e.g. "\033[0;1;5m"
|
||||
*/
|
||||
private String attributes(final boolean bold, final boolean reverse,
|
||||
final boolean blink, final boolean underline) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if ( bold && reverse && blink && !underline ) {
|
||||
sb.append("\033[0;1;7;5m");
|
||||
} else if ( bold && reverse && !blink && !underline ) {
|
||||
sb.append("\033[0;1;7m");
|
||||
} else if ( !bold && reverse && blink && !underline ) {
|
||||
sb.append("\033[0;7;5m");
|
||||
} else if ( bold && !reverse && blink && !underline ) {
|
||||
sb.append("\033[0;1;5m");
|
||||
} else if ( bold && !reverse && !blink && !underline ) {
|
||||
sb.append("\033[0;1m");
|
||||
} else if ( !bold && reverse && !blink && !underline ) {
|
||||
sb.append("\033[0;7m");
|
||||
} else if ( !bold && !reverse && blink && !underline) {
|
||||
sb.append("\033[0;5m");
|
||||
} else if ( bold && reverse && blink && underline ) {
|
||||
sb.append("\033[0;1;7;5;4m");
|
||||
} else if ( bold && reverse && !blink && underline ) {
|
||||
sb.append("\033[0;1;7;4m");
|
||||
} else if ( !bold && reverse && blink && underline ) {
|
||||
sb.append("\033[0;7;5;4m");
|
||||
} else if ( bold && !reverse && blink && underline ) {
|
||||
sb.append("\033[0;1;5;4m");
|
||||
} else if ( bold && !reverse && !blink && underline ) {
|
||||
sb.append("\033[0;1;4m");
|
||||
} else if ( !bold && reverse && !blink && underline ) {
|
||||
sb.append("\033[0;7;4m");
|
||||
} else if ( !bold && !reverse && blink && underline) {
|
||||
sb.append("\033[0;5;4m");
|
||||
} else if ( !bold && !reverse && !blink && underline) {
|
||||
sb.append("\033[0;4m");
|
||||
} else {
|
||||
assert (!bold && !reverse && !blink && !underline);
|
||||
sb.append("\033[0m");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SGR parameter sequence for foreground, background, and
|
||||
* several attributes. This sequence first resets all attributes to
|
||||
|
|
|
@ -28,13 +28,16 @@
|
|||
*/
|
||||
package jexer.backend;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import jexer.backend.GlyphMaker;
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.Cell;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.Clipboard;
|
||||
import jexer.bits.GraphicsChars;
|
||||
import jexer.bits.ImageUtils;
|
||||
import jexer.bits.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -142,12 +145,22 @@ public class LogicalScreen implements Screen {
|
|||
* Public constructor. Sets everything to not-bold, white-on-black.
|
||||
*/
|
||||
protected LogicalScreen() {
|
||||
offsetX = 0;
|
||||
offsetY = 0;
|
||||
width = 80;
|
||||
height = 24;
|
||||
logical = null;
|
||||
physical = null;
|
||||
this(80, 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public constructor. Sets everything to not-bold, white-on-black.
|
||||
*
|
||||
* @param width width in cells
|
||||
* @param height height in cells
|
||||
*/
|
||||
protected LogicalScreen(final int width, final int height) {
|
||||
offsetX = 0;
|
||||
offsetY = 0;
|
||||
this.width = 80;
|
||||
this.height = 24;
|
||||
logical = null;
|
||||
physical = null;
|
||||
reallocate(width, height);
|
||||
}
|
||||
|
||||
|
@ -748,7 +761,8 @@ public class LogicalScreen implements Screen {
|
|||
final int right, final int bottom,
|
||||
final CellAttributes border, final CellAttributes background) {
|
||||
|
||||
drawBox(left, top, right, bottom, border, background, 1, false);
|
||||
drawBox(left, top, right, bottom, border, background,
|
||||
BorderStyle.DEFAULT, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -760,57 +774,23 @@ public class LogicalScreen implements Screen {
|
|||
* @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 borderStyle style of border
|
||||
* @param shadow if true, draw a "shadow" on the box
|
||||
*/
|
||||
public final void drawBox(final int left, final int top,
|
||||
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) {
|
||||
final BorderStyle borderStyle, final boolean shadow) {
|
||||
|
||||
int boxWidth = right - left;
|
||||
int boxHeight = bottom - top;
|
||||
|
||||
char cTopLeft;
|
||||
char cTopRight;
|
||||
char cBottomLeft;
|
||||
char cBottomRight;
|
||||
char cHSide;
|
||||
char cVSide;
|
||||
|
||||
switch (borderType) {
|
||||
case 1:
|
||||
cTopLeft = GraphicsChars.ULCORNER;
|
||||
cTopRight = GraphicsChars.URCORNER;
|
||||
cBottomLeft = GraphicsChars.LLCORNER;
|
||||
cBottomRight = GraphicsChars.LRCORNER;
|
||||
cHSide = GraphicsChars.SINGLE_BAR;
|
||||
cVSide = GraphicsChars.WINDOW_SIDE;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
cTopLeft = GraphicsChars.WINDOW_LEFT_TOP_DOUBLE;
|
||||
cTopRight = GraphicsChars.WINDOW_RIGHT_TOP_DOUBLE;
|
||||
cBottomLeft = GraphicsChars.WINDOW_LEFT_BOTTOM_DOUBLE;
|
||||
cBottomRight = GraphicsChars.WINDOW_RIGHT_BOTTOM_DOUBLE;
|
||||
cHSide = GraphicsChars.DOUBLE_BAR;
|
||||
cVSide = GraphicsChars.WINDOW_SIDE_DOUBLE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
cTopLeft = GraphicsChars.WINDOW_LEFT_TOP;
|
||||
cTopRight = GraphicsChars.WINDOW_RIGHT_TOP;
|
||||
cBottomLeft = GraphicsChars.WINDOW_LEFT_BOTTOM;
|
||||
cBottomRight = GraphicsChars.WINDOW_RIGHT_BOTTOM;
|
||||
cHSide = GraphicsChars.WINDOW_TOP;
|
||||
cVSide = GraphicsChars.WINDOW_SIDE;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid border type: "
|
||||
+ borderType);
|
||||
}
|
||||
int cTopLeft = borderStyle.getTopLeft();
|
||||
int cTopRight = borderStyle.getTopRight();
|
||||
int cBottomLeft = borderStyle.getBottomLeft();
|
||||
int cBottomRight = borderStyle.getBottomRight();
|
||||
int cHSide = borderStyle.getHorizontal();
|
||||
int cVSide = borderStyle.getVertical();
|
||||
|
||||
// Place the corner characters
|
||||
putCharXY(left, top, cTopLeft, border);
|
||||
|
@ -1289,8 +1269,7 @@ public class LogicalScreen implements Screen {
|
|||
public Screen snapshot() {
|
||||
LogicalScreen other = null;
|
||||
synchronized (this) {
|
||||
other = new LogicalScreen();
|
||||
other.setDimensions(width, height);
|
||||
other = new LogicalScreen(width, height);
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
other.logical[col][row] = new Cell(logical[col][row]);
|
||||
|
@ -1300,6 +1279,83 @@ public class LogicalScreen implements Screen {
|
|||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a snapshot copy of a rectangular portion of the screen.
|
||||
*
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @return a copy of the screen's data from this rectangle. Any cells
|
||||
* outside the actual screen dimensions will be blank.
|
||||
*/
|
||||
public Screen snapshot(final int x, final int y, final int width,
|
||||
final int height) {
|
||||
|
||||
LogicalScreen other = null;
|
||||
synchronized (this) {
|
||||
other = new LogicalScreen(width, height);
|
||||
for (int row = y; (row < y + height) && (row < this.height); row++) {
|
||||
if (row < 0) {
|
||||
continue;
|
||||
}
|
||||
for (int col = x; (col < x + width) && (col < this.width); col++) {
|
||||
if (col < 0) {
|
||||
continue;
|
||||
}
|
||||
other.logical[col - x][row - y] = new Cell(logical[col][row]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all of screen's data to this screen.
|
||||
*
|
||||
* @param other the other screen
|
||||
*/
|
||||
public void copyScreen(final Screen other) {
|
||||
synchronized (this) {
|
||||
if ((other.getWidth() != width) || (other.getHeight() != height)) {
|
||||
setDimensions(other.getWidth(), other.getHeight());
|
||||
}
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
logical[col][row] = new Cell(other.getCharXY(col, row));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a rectangular portion of another screen to this one. Any cells
|
||||
* outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param other the other screen
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
*/
|
||||
public void copyScreen(final Screen other, final int x, final int y,
|
||||
final int width, final int height) {
|
||||
|
||||
synchronized (this) {
|
||||
for (int row = y; (row < y + height) && (row < this.height); row++) {
|
||||
if (row < 0) {
|
||||
continue;
|
||||
}
|
||||
for (int col = x; (col < x + width) && (col < this.width); col++) {
|
||||
if (col < 0) {
|
||||
continue;
|
||||
}
|
||||
logical[col][row] = new Cell(other.getCharXY(col - x, row - y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the backend to associated with this screen.
|
||||
*
|
||||
|
@ -1318,4 +1374,313 @@ public class LogicalScreen implements Screen {
|
|||
return backend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alpha-blend a rectangle with a specified color and alpha onto this
|
||||
* screen. Any cells outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @param color the RGB color to blend
|
||||
* @param alpha the alpha transparency level (0 - 255) to use for cells
|
||||
* from the other screen
|
||||
*/
|
||||
public void blendRectangle(final int x, final int y,
|
||||
final int width, final int height, final int color, final int alpha) {
|
||||
|
||||
// We just create a new blank screen and blend it.
|
||||
LogicalScreen rectangle = new LogicalScreen(width, height);
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
rectangle.logical[col][row].setBackColorRGB(color);
|
||||
}
|
||||
}
|
||||
|
||||
blendScreen(rectangle, x, y, width, height, alpha, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alpha-blend a rectangular portion of another screen onto this one.
|
||||
* Any cells outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param otherScreen the other screen
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @param alpha the alpha transparency level (0 - 255) to use for cells
|
||||
* from the other screen
|
||||
* @param filterHatch if true, prevent hatch-like characters from
|
||||
* showing through
|
||||
*/
|
||||
public void blendScreen(final Screen otherScreen, final int x, final int y,
|
||||
final int width, final int height, final int alpha,
|
||||
final boolean filterHatch) {
|
||||
|
||||
if (alpha == 255) {
|
||||
// This is a raw copy.
|
||||
copyScreen(otherScreen, x, y, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to blend the background colors of other's cells over the
|
||||
* cells of this screen (foreground and background), honoring our
|
||||
* alpha. We will create a bitmap of one pixel per cell, blend that
|
||||
* via AWT, and then set the cell RGBs and char's.
|
||||
*/
|
||||
synchronized (this) {
|
||||
|
||||
BufferedImage thisForeground = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage thisBackground = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage overBackground = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage thisOldBackground = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
final int OPAQUE = 0xFF000000;
|
||||
|
||||
for (int row = y; (row < y + height) && (row < this.height); row++) {
|
||||
if (row < 0) {
|
||||
continue;
|
||||
}
|
||||
for (int col = x; (col < x + width) && (col < this.width); col++) {
|
||||
if (col < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Cell cell = logical[col][row];
|
||||
int thisBg = cell.getBackColorRGB();
|
||||
if (thisBg < 0) {
|
||||
if (backend != null) {
|
||||
thisBg = backend.attrToBackgroundColor(cell).getRGB();
|
||||
} else {
|
||||
thisBg = SwingTerminal.attrToBackgroundColor(cell).getRGB();
|
||||
}
|
||||
}
|
||||
int thisFg = cell.getForeColorRGB();
|
||||
if (thisFg < 0) {
|
||||
if (backend != null) {
|
||||
thisFg = backend.attrToForegroundColor(cell).getRGB();
|
||||
} else {
|
||||
thisFg = SwingTerminal.attrToForegroundColor(cell).getRGB();
|
||||
}
|
||||
}
|
||||
|
||||
Cell over = otherScreen.getCharXY(col - x, row - y);
|
||||
int overBg = over.getBackColorRGB();
|
||||
if (overBg < 0) {
|
||||
if (backend != null) {
|
||||
overBg = backend.attrToBackgroundColor(over).getRGB();
|
||||
} else {
|
||||
overBg = SwingTerminal.attrToBackgroundColor(over).getRGB();
|
||||
}
|
||||
}
|
||||
thisFg |= OPAQUE;
|
||||
thisBg |= OPAQUE;
|
||||
overBg |= OPAQUE;
|
||||
|
||||
thisForeground.setRGB(col - x, row - y, thisFg);
|
||||
thisBackground.setRGB(col - x, row - y, thisBg);
|
||||
thisOldBackground.setRGB(col - x, row - y, thisBg);
|
||||
overBackground.setRGB(col - x, row - y, overBg);
|
||||
}
|
||||
}
|
||||
|
||||
// The three bitmaps are ready. We have skipped over
|
||||
// cells/pixels that cannot overlap. Now blit overBackground
|
||||
// over both thisForeground and thisBackground, and then assign
|
||||
// cell colors and cell chars/images.
|
||||
float fAlpha = (float) (alpha / 255.0);
|
||||
Graphics2D g2d = thisForeground.createGraphics();
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
fAlpha));
|
||||
g2d.drawImage(overBackground, 0, 0, null);
|
||||
g2d.dispose();
|
||||
|
||||
g2d = thisBackground.createGraphics();
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
fAlpha));
|
||||
g2d.drawImage(overBackground, 0, 0, null);
|
||||
g2d.dispose();
|
||||
|
||||
for (int row = y; (row < y + height) && (row < this.height); row++) {
|
||||
if (row < 0) {
|
||||
continue;
|
||||
}
|
||||
for (int col = x; (col < x + width) && (col < this.width); col++) {
|
||||
if (col < 0) {
|
||||
continue;
|
||||
}
|
||||
Cell thisCell = logical[col][row];
|
||||
Cell overCell = otherScreen.getCharXY(col - x, row - y);
|
||||
int thisFg = thisForeground.getRGB(col - x, row - y);
|
||||
int thisBg = thisBackground.getRGB(col - x, row - y);
|
||||
int thisOldBg = thisOldBackground.getRGB(col - x, row - y);
|
||||
int overBg = overBackground.getRGB(col - x, row - y);
|
||||
|
||||
thisCell.setBackColorRGB(thisBg | OPAQUE);
|
||||
thisCell.setForeColorRGB(thisFg | OPAQUE);
|
||||
|
||||
if (!overCell.isImage() && (overCell.getChar() == ' ')) {
|
||||
// The overlaying cell is invisible.
|
||||
|
||||
if (thisCell.isImage()) {
|
||||
// Our image will show through. We need to blend
|
||||
// otherBg at alpha < 255 over this image.
|
||||
Cell thisCopy = new Cell(thisCell);
|
||||
thisCopy.flattenImage(false, backend);
|
||||
BufferedImage image = thisCopy.getImage();
|
||||
BufferedImage newImage;
|
||||
newImage = new BufferedImage(image.getWidth(),
|
||||
image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
g2d = newImage.createGraphics();
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
fAlpha));
|
||||
g2d.setColor(new java.awt.Color(overBg));
|
||||
g2d.fillRect(0, 0, image.getWidth(),
|
||||
image.getHeight());
|
||||
g2d.dispose();
|
||||
thisCell.setImage(newImage);
|
||||
thisCell.setOpaqueImage();
|
||||
} else {
|
||||
// Our character will show through. If the
|
||||
// contrast between our foreground and background
|
||||
// is small, then drop the character.
|
||||
if (ImageUtils.rgbDistance(thisFg, thisBg) < 5) {
|
||||
thisCell.setChar(' ');
|
||||
}
|
||||
|
||||
if (filterHatch) {
|
||||
// Special case: the hatch characters are not
|
||||
// allowed to show through.
|
||||
int ch = thisCell.getChar();
|
||||
if ((ch == 0x2591)
|
||||
|| (ch == 0x2592)
|
||||
|| (ch == 0x2593)
|
||||
) {
|
||||
thisCell.setChar(' ');
|
||||
}
|
||||
}
|
||||
if (cursorVisible &&
|
||||
(col == cursorX) &&
|
||||
(row == cursorY)
|
||||
) {
|
||||
// Don't surface the character behind the
|
||||
// cursor.
|
||||
thisCell.setChar(' ');
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// The overlaying cell has a character, use it.
|
||||
thisCell.setChar(overCell.getChar());
|
||||
int fg = overCell.getForeColorRGB();
|
||||
if (fg < 0) {
|
||||
thisCell.setForeColor(overCell.getForeColor());
|
||||
} else {
|
||||
thisCell.setForeColorRGB(fg);
|
||||
}
|
||||
thisCell.setBold(overCell.isBold());
|
||||
thisCell.setBlink(overCell.isBlink());
|
||||
thisCell.setUnderline(overCell.isUnderline());
|
||||
thisCell.setProtect(overCell.isProtect());
|
||||
|
||||
if (!overCell.isImage()) {
|
||||
// If we had an image, destroy it. Text ALWAYS
|
||||
// overwrites images.
|
||||
thisCell.setImage(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (overCell.isImage() && !overCell.isTransparentImage()) {
|
||||
// The image from the new cell will fully cover this
|
||||
// cell's image.
|
||||
|
||||
// We need to blit overCell's image over thisOldBg at
|
||||
// alpha < 255.
|
||||
Cell overCopy = new Cell(overCell);
|
||||
overCopy.flattenImage(false, backend);
|
||||
BufferedImage image = overCopy.getImage();
|
||||
BufferedImage newImage;
|
||||
newImage = new BufferedImage(image.getWidth(),
|
||||
image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
g2d = newImage.createGraphics();
|
||||
g2d.setColor(new java.awt.Color(thisOldBg));
|
||||
g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
fAlpha));
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
g2d.dispose();
|
||||
thisCell.setImage(newImage);
|
||||
thisCell.setOpaqueImage();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thisCell.isImage()
|
||||
&& overCell.isImage()
|
||||
&& overCell.isTransparentImage()
|
||||
) {
|
||||
// We need to blit overCell's image over a rectangle
|
||||
// of otherBg at alpha = 255, and then blit that over
|
||||
// thisCell's image at alpha < 255.
|
||||
|
||||
Cell overCopy = new Cell(overCell);
|
||||
overCopy.flattenImage(false, backend);
|
||||
BufferedImage image = overCopy.getImage();
|
||||
BufferedImage newImage;
|
||||
newImage = new BufferedImage(image.getWidth(),
|
||||
image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
g2d = newImage.createGraphics();
|
||||
g2d.drawImage(thisCell.getImage(), 0, 0, null);
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
fAlpha));
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
g2d.dispose();
|
||||
thisCell.setImage(newImage);
|
||||
thisCell.setOpaqueImage();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!thisCell.isImage()
|
||||
&& overCell.isImage()
|
||||
&& overCell.isTransparentImage()
|
||||
) {
|
||||
// We need to blit overCell's image over a rectangle
|
||||
// of otherBg at alpha = 255, and blit that over
|
||||
// thisOldBg at alpha < 255.
|
||||
|
||||
Cell overCopy = new Cell(overCell);
|
||||
overCopy.flattenImage(false, backend);
|
||||
BufferedImage image = overCopy.getImage();
|
||||
BufferedImage newImage;
|
||||
newImage = new BufferedImage(image.getWidth(),
|
||||
image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
g2d = newImage.createGraphics();
|
||||
g2d.setColor(new java.awt.Color(thisOldBg));
|
||||
g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
fAlpha));
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
g2d.dispose();
|
||||
thisCell.setImage(newImage);
|
||||
thisCell.setOpaqueImage();
|
||||
continue;
|
||||
}
|
||||
|
||||
// There should be nothing to do now. We have set the
|
||||
// character, or set the image, and blended backgrounds
|
||||
// for each case.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ package jexer.backend;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.Cell;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.Clipboard;
|
||||
|
@ -608,7 +609,7 @@ public class MultiScreen implements Screen {
|
|||
/**
|
||||
* Draw a box with a border and empty background.
|
||||
*
|
||||
* @param left left column of box. 0 is the left-most row.
|
||||
* @param left left column of box. 0 is the left-most column.
|
||||
* @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
|
||||
|
@ -629,26 +630,24 @@ public class MultiScreen implements Screen {
|
|||
/**
|
||||
* Draw a box with a border and empty background.
|
||||
*
|
||||
* @param left left column of box. 0 is the left-most row.
|
||||
* @param left left column of box. 0 is the left-most column.
|
||||
* @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 borderStyle style of border
|
||||
* @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) {
|
||||
final BorderStyle borderStyle, final boolean shadow) {
|
||||
|
||||
synchronized (screens) {
|
||||
for (Screen screen: screens) {
|
||||
screen.drawBox(left, top, right, bottom, border, background,
|
||||
borderType, shadow);
|
||||
borderStyle, shadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -656,7 +655,7 @@ public class MultiScreen implements Screen {
|
|||
/**
|
||||
* Draw a box shadow.
|
||||
*
|
||||
* @param left left column of box. 0 is the left-most row.
|
||||
* @param left left column of box. 0 is the left-most column.
|
||||
* @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
|
||||
|
@ -952,6 +951,118 @@ public class MultiScreen implements Screen {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a snapshot copy of a rectangular portion of the screen.
|
||||
*
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @return a copy of the screen's data from this rectangle. Any cells
|
||||
* outside the actual screen dimensions will be blank.
|
||||
*/
|
||||
public Screen snapshot(final int x, final int y, final int width,
|
||||
final int height) {
|
||||
|
||||
synchronized (screens) {
|
||||
// Only copy from the first screen.
|
||||
if (screens.size() > 0) {
|
||||
return screens.get(0).snapshot(x, y, width, height);
|
||||
}
|
||||
|
||||
// No screens are defined, create a blank.
|
||||
|
||||
LogicalScreen other = null;
|
||||
|
||||
other = new LogicalScreen();
|
||||
int newWidth = x + width;
|
||||
int newHeight = y + 25;
|
||||
other.setDimensions(newWidth, newHeight);
|
||||
return other;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all of screen's data to this screen.
|
||||
*
|
||||
* @param other the other screen
|
||||
*/
|
||||
public void copyScreen(final Screen other) {
|
||||
synchronized (screens) {
|
||||
for (Screen screen: screens) {
|
||||
screen.copyScreen(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a rectangular portion of another screen to this one. Any cells
|
||||
* outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param other the other screen
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
*/
|
||||
public void copyScreen(final Screen other, final int x, final int y,
|
||||
final int width, final int height) {
|
||||
|
||||
synchronized (screens) {
|
||||
for (Screen screen: screens) {
|
||||
screen.copyScreen(other, x, y, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alpha-blend a rectangular portion of another screen onto this one.
|
||||
* Any cells outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param otherScreen the other screen
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @param alpha the alpha transparency level (0 - 255) to use for cells
|
||||
* from the other screen
|
||||
* @param filterHatch if true, prevent hatch-like characters from
|
||||
* showing through
|
||||
*/
|
||||
public void blendScreen(final Screen otherScreen, final int x, final int y,
|
||||
final int width, final int height, final int alpha,
|
||||
final boolean filterHatch) {
|
||||
|
||||
synchronized (screens) {
|
||||
for (Screen screen: screens) {
|
||||
screen.blendScreen(otherScreen, x, y, width, height, alpha,
|
||||
filterHatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alpha-blend a rectangle with a specified color and alpha onto this
|
||||
* screen. Any cells outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @param color the RGB color to blend
|
||||
* @param alpha the alpha transparency level (0 - 255) to use for cells
|
||||
* from the other screen
|
||||
*/
|
||||
public void blendRectangle(final int x, final int y,
|
||||
final int width, final int height, final int color, final int alpha) {
|
||||
|
||||
synchronized (screens) {
|
||||
for (Screen screen: screens) {
|
||||
screen.blendRectangle(x, y, width, height, color, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the backend to associated with this screen.
|
||||
*
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
*/
|
||||
package jexer.backend;
|
||||
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.Cell;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.Clipboard;
|
||||
|
@ -321,7 +322,7 @@ public interface Screen {
|
|||
/**
|
||||
* Draw a box with a border and empty background.
|
||||
*
|
||||
* @param left left column of box. 0 is the left-most row.
|
||||
* @param left left column of box. 0 is the left-most column.
|
||||
* @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
|
||||
|
@ -335,26 +336,24 @@ public interface Screen {
|
|||
/**
|
||||
* Draw a box with a border and empty background.
|
||||
*
|
||||
* @param left left column of box. 0 is the left-most row.
|
||||
* @param left left column of box. 0 is the left-most column.
|
||||
* @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 borderStyle style of border
|
||||
* @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);
|
||||
final BorderStyle borderStyle, final boolean shadow);
|
||||
|
||||
/**
|
||||
* Draw a box shadow.
|
||||
*
|
||||
* @param left left column of box. 0 is the left-most row.
|
||||
* @param left left column of box. 0 is the left-most column.
|
||||
* @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
|
||||
|
@ -490,6 +489,72 @@ public interface Screen {
|
|||
*/
|
||||
public Screen snapshot();
|
||||
|
||||
/**
|
||||
* Obtain a snapshot copy of a rectangular portion of the screen.
|
||||
*
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @return a copy of the screen's data from this rectangle. Any cells
|
||||
* outside the actual screen dimensions will be blank.
|
||||
*/
|
||||
public Screen snapshot(final int x, final int y, final int width,
|
||||
final int height);
|
||||
|
||||
/**
|
||||
* Copy all of screen's data to this screen.
|
||||
*
|
||||
* @param other the other screen
|
||||
*/
|
||||
public void copyScreen(final Screen other);
|
||||
|
||||
/**
|
||||
* Copy a rectangular portion of another screen to this one. Any cells
|
||||
* outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param other the other screen
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
*/
|
||||
public void copyScreen(final Screen other, final int x, final int y,
|
||||
final int width, final int height);
|
||||
|
||||
/**
|
||||
* Alpha-blend a rectangular portion of another screen onto this one.
|
||||
* Any cells outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param otherScreen the other screen
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @param alpha the alpha transparency level (0 - 255) to use for cells
|
||||
* from the other screen
|
||||
* @param filterHatch if true, prevent hatch-like characters from
|
||||
* showing through
|
||||
*/
|
||||
public void blendScreen(final Screen otherScreen, final int x, final int y,
|
||||
final int width, final int height, final int alpha,
|
||||
final boolean filterHatch);
|
||||
|
||||
/**
|
||||
* Alpha-blend a rectangle with a specified color and alpha onto this
|
||||
* screen. Any cells outside this screen's dimensions will be ignored.
|
||||
*
|
||||
* @param x left column of rectangle. 0 is the left-most column.
|
||||
* @param y top row of the rectangle. 0 is the top-most row.
|
||||
* @param width number of columns to copy
|
||||
* @param height number of rows to copy
|
||||
* @param color the RGB color to blend
|
||||
* @param alpha the alpha transparency level (0 - 255) to use for cells
|
||||
* from the other screen
|
||||
*/
|
||||
public void blendRectangle(final int x, final int y,
|
||||
final int width, final int height, final int color, final int alpha);
|
||||
|
||||
/**
|
||||
* Get the backend that instantiated this screen.
|
||||
*
|
||||
|
|
|
@ -119,7 +119,7 @@ public class SwingTerminal extends LogicalScreen
|
|||
* A value of 25 or more feels sluggish for input, but is sustainable for
|
||||
* the garbage collector.
|
||||
*/
|
||||
private static final long SYNC_MIN_MILLIS_SUSTAIN = 20;
|
||||
private static final long SYNC_MIN_MILLIS_SUSTAIN = 10;
|
||||
|
||||
/**
|
||||
* The number of frames that can be emitted quickly (at
|
||||
|
@ -1611,7 +1611,7 @@ public class SwingTerminal extends LogicalScreen
|
|||
xPixel -= textWidth;
|
||||
break;
|
||||
}
|
||||
gr.setColor(attrToForegroundColor(lCell));
|
||||
gr.setColor((Color.WHITE).darker());
|
||||
switch (cursorStyle) {
|
||||
default:
|
||||
// Fall through...
|
||||
|
|
277
src/jexer/bits/BorderStyle.java
Normal file
277
src/jexer/bits/BorderStyle.java
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Jexer - Java Text User Interface
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (C) 2022 Autumn 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 Autumn Lamonte ⚧ Trans Liberation Now
|
||||
* @version 1
|
||||
*/
|
||||
package jexer.bits;
|
||||
|
||||
/**
|
||||
* A text box border style.
|
||||
*/
|
||||
public class BorderStyle {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The default border style. Synonym for SINGLE.
|
||||
*/
|
||||
public static final BorderStyle DEFAULT;
|
||||
|
||||
/**
|
||||
* The "no-border" style.
|
||||
*/
|
||||
public static final BorderStyle NONE;
|
||||
|
||||
/**
|
||||
* A single-line border.
|
||||
*/
|
||||
public static final BorderStyle SINGLE;
|
||||
|
||||
/**
|
||||
* A double-line border.
|
||||
*/
|
||||
public static final BorderStyle DOUBLE;
|
||||
|
||||
/**
|
||||
* A single-line border on the vertical sections, double-line on the
|
||||
* horizontal sections.
|
||||
*/
|
||||
public static final BorderStyle SINGLE_V_DOUBLE_H;
|
||||
|
||||
/**
|
||||
* A double-line border on the vertical sections, single-line on the
|
||||
* horizontal sections.
|
||||
*/
|
||||
public static final BorderStyle SINGLE_H_DOUBLE_V;
|
||||
|
||||
/**
|
||||
* A single-line border with round corners.
|
||||
*/
|
||||
public static final BorderStyle SINGLE_ROUND;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The glyph for horizontal sections.
|
||||
*/
|
||||
private int horizontal;
|
||||
|
||||
/**
|
||||
* The glyph for vertical sections.
|
||||
*/
|
||||
private int vertical;
|
||||
|
||||
/**
|
||||
* The glyph for the top-left corner.
|
||||
*/
|
||||
private int topLeft;
|
||||
|
||||
/**
|
||||
* The glyph for the top-right corner.
|
||||
*/
|
||||
private int topRight;
|
||||
|
||||
/**
|
||||
* The glyph for the bottom-left corner.
|
||||
*/
|
||||
private int bottomLeft;
|
||||
|
||||
/**
|
||||
* The glyph for the bottom-right corner.
|
||||
*/
|
||||
private int bottomRight;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Static constructor.
|
||||
*/
|
||||
static {
|
||||
|
||||
NONE = new BorderStyle(' ', ' ', ' ', ' ', ' ', ' ');
|
||||
|
||||
SINGLE = new BorderStyle(GraphicsChars.SINGLE_BAR,
|
||||
GraphicsChars.WINDOW_SIDE,
|
||||
GraphicsChars.ULCORNER,
|
||||
GraphicsChars.URCORNER,
|
||||
GraphicsChars.LLCORNER,
|
||||
GraphicsChars.LRCORNER);
|
||||
|
||||
DOUBLE = new BorderStyle(GraphicsChars.DOUBLE_BAR,
|
||||
GraphicsChars.WINDOW_SIDE_DOUBLE,
|
||||
GraphicsChars.WINDOW_LEFT_TOP_DOUBLE,
|
||||
GraphicsChars.WINDOW_RIGHT_TOP_DOUBLE,
|
||||
GraphicsChars.WINDOW_LEFT_BOTTOM_DOUBLE,
|
||||
GraphicsChars.WINDOW_RIGHT_BOTTOM_DOUBLE);
|
||||
|
||||
SINGLE_V_DOUBLE_H = new BorderStyle(GraphicsChars.WINDOW_TOP,
|
||||
GraphicsChars.WINDOW_SIDE,
|
||||
GraphicsChars.WINDOW_LEFT_TOP,
|
||||
GraphicsChars.WINDOW_RIGHT_TOP,
|
||||
GraphicsChars.WINDOW_LEFT_BOTTOM,
|
||||
GraphicsChars.WINDOW_RIGHT_BOTTOM);
|
||||
|
||||
SINGLE_H_DOUBLE_V = new BorderStyle(GraphicsChars.SINGLE_BAR,
|
||||
GraphicsChars.WINDOW_SIDE_DOUBLE,
|
||||
0x2553,
|
||||
0x2556,
|
||||
0x2559,
|
||||
0x255C);
|
||||
|
||||
SINGLE_ROUND = new BorderStyle(GraphicsChars.SINGLE_BAR,
|
||||
GraphicsChars.WINDOW_SIDE,
|
||||
0x256D,
|
||||
0x256E,
|
||||
0x2570,
|
||||
0x256F);
|
||||
|
||||
DEFAULT = SINGLE;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to make the static BorderStyle instances.
|
||||
*
|
||||
* @param horizontal the horizontal section glyph
|
||||
* @param vertical the vertical section glyph
|
||||
* @param topLeft the top-left corner glyph
|
||||
* @param topRight the top-right corner glyph
|
||||
* @param bottomLeft the bottom-left corner glyph
|
||||
* @param bottomRight the bottom-right corner glyph
|
||||
*/
|
||||
private BorderStyle(final int horizontal, final int vertical,
|
||||
final int topLeft, final int topRight,
|
||||
final int bottomLeft, final int bottomRight) {
|
||||
|
||||
this.horizontal = horizontal;
|
||||
this.vertical = vertical;
|
||||
this.topLeft = topLeft;
|
||||
this.topRight = topRight;
|
||||
this.bottomLeft = bottomLeft;
|
||||
this.bottomRight = bottomRight;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// BorderStyle ------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Public constructor returns one of the static BorderStyle instances.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"
|
||||
* @return BorderStyle.SINGLE, BorderStyle.DOUBLE, etc.
|
||||
*/
|
||||
public static final BorderStyle getStyle(final String borderStyle) {
|
||||
String str = borderStyle.toLowerCase();
|
||||
|
||||
if (str.equals("none")) {
|
||||
return NONE;
|
||||
}
|
||||
if (str.equals("default")) {
|
||||
return SINGLE;
|
||||
}
|
||||
if (str.equals("single")) {
|
||||
return SINGLE;
|
||||
}
|
||||
if (str.equals("double")) {
|
||||
return DOUBLE;
|
||||
}
|
||||
if (str.equals("round")) {
|
||||
return SINGLE_ROUND;
|
||||
}
|
||||
if (str.equals("singlevdoubleh")) {
|
||||
return SINGLE_V_DOUBLE_H;
|
||||
}
|
||||
if (str.equals("singlehdoublev")) {
|
||||
return SINGLE_H_DOUBLE_V;
|
||||
}
|
||||
|
||||
// If they didn't get it right, return single.
|
||||
return SINGLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the glyph for horizontal sections.
|
||||
*
|
||||
* @return the glyph for horizontal sections.
|
||||
*/
|
||||
public final int getHorizontal() {
|
||||
return horizontal;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the glyph for vertical sections.
|
||||
* @return the glyph for vertical sections.
|
||||
*/
|
||||
public final int getVertical() {
|
||||
return vertical;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the glyph for the top-left corner.
|
||||
*
|
||||
* @return the glyph for the top-left corner.
|
||||
*/
|
||||
public final int getTopLeft() {
|
||||
return topLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the glyph for the top-right corner.
|
||||
*
|
||||
* @return the glyph for the top-right corner.
|
||||
*/
|
||||
public final int getTopRight() {
|
||||
return topRight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the glyph for the bottom-left corner.
|
||||
*
|
||||
* @return the glyph for the bottom-left corner.
|
||||
*/
|
||||
public final int getBottomLeft() {
|
||||
return bottomLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the glyph for the bottom-right corner.
|
||||
*
|
||||
* @return the glyph for the bottom-right corner.
|
||||
*/
|
||||
public final int getBottomRight() {
|
||||
return bottomRight;
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,7 @@ package jexer.bits;
|
|||
import java.awt.image.BufferedImage;
|
||||
import jexer.backend.Backend;
|
||||
import jexer.backend.GlyphMaker;
|
||||
import jexer.backend.SwingTerminal;
|
||||
|
||||
/**
|
||||
* This class represents a single text cell or bit of image on the screen.
|
||||
|
@ -184,7 +185,11 @@ public class Cell extends CellAttributes {
|
|||
public void setImage(final BufferedImage image) {
|
||||
this.image = image;
|
||||
hasTransparentPixels = 0;
|
||||
imageHashCode = image.hashCode();
|
||||
if (image == null) {
|
||||
imageHashCode = 0;
|
||||
} else {
|
||||
imageHashCode = image.hashCode();
|
||||
}
|
||||
width = Width.SINGLE;
|
||||
}
|
||||
|
||||
|
@ -255,7 +260,11 @@ public class Cell extends CellAttributes {
|
|||
BufferedImage newImage = new BufferedImage(textWidth,
|
||||
textHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
java.awt.Graphics gr = newImage.getGraphics();
|
||||
gr.setColor(backend.attrToBackgroundColor(this));
|
||||
if (backend != null) {
|
||||
gr.setColor(backend.attrToBackgroundColor(this));
|
||||
} else {
|
||||
gr.setColor(SwingTerminal.attrToBackgroundColor(this));
|
||||
}
|
||||
|
||||
if (overGlyph) {
|
||||
// Render this cell to a flat image. The bad news is that we
|
||||
|
@ -273,6 +282,38 @@ public class Cell extends CellAttributes {
|
|||
setImage(newImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten the image on this cell by rendering it either onto a
|
||||
* background color.
|
||||
*
|
||||
* @param background the background color to draw on
|
||||
*/
|
||||
private void flattenImage(final java.awt.Color background) {
|
||||
assert (isImage());
|
||||
|
||||
if (hasTransparentPixels == 2) {
|
||||
// The image already covers the entire cell.
|
||||
return;
|
||||
}
|
||||
|
||||
int textWidth = image.getWidth();
|
||||
int textHeight = image.getHeight();
|
||||
BufferedImage newImage = new BufferedImage(textWidth,
|
||||
textHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
java.awt.Graphics gr = newImage.getGraphics();
|
||||
gr.setColor(background);
|
||||
|
||||
// Put the background color behind the pixels.
|
||||
gr.fillRect(0, 0, newImage.getWidth(), newImage.getHeight());
|
||||
gr.drawImage(image, 0, 0, null, null);
|
||||
gr.dispose();
|
||||
|
||||
setImage(newImage);
|
||||
|
||||
// We know we are opaque now.
|
||||
hasTransparentPixels = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blit another cell's image on top of the image data for this cell.
|
||||
*
|
||||
|
@ -740,9 +781,11 @@ public class Cell extends CellAttributes {
|
|||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s fore: %s back: %s bold: %s blink: %s ch %c",
|
||||
return String.format("%s fore: %s RGB %06x back: %s RGB %06x bold: %s blink: %s ch %c",
|
||||
(isImage() ? "IMAGE" : ""),
|
||||
getForeColor(), getBackColor(), isBold(), isBlink(), ch);
|
||||
getForeColor(), getForeColorRGB(),
|
||||
getBackColor(), getBackColorRGB(),
|
||||
isBold(), isBlink(), ch);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -125,7 +125,7 @@ public class CellAttributes {
|
|||
* @return bold value
|
||||
*/
|
||||
public final boolean isBold() {
|
||||
return ((flags & BOLD) == 0 ? false : true);
|
||||
return ((flags & BOLD) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -268,7 +268,8 @@ public class CellAttributes {
|
|||
}
|
||||
|
||||
/**
|
||||
* Getter for foreColor RGB.
|
||||
* Getter for foreColor RGB. Note that this is always a RGB value,
|
||||
* i.e. alpha is 0.
|
||||
*
|
||||
* @return foreColor value. Negative means unset.
|
||||
*/
|
||||
|
@ -282,11 +283,13 @@ public class CellAttributes {
|
|||
* @param foreColorRGB new foreColor RGB value
|
||||
*/
|
||||
public final void setForeColorRGB(final int foreColorRGB) {
|
||||
this.foreColorRGB = foreColorRGB;
|
||||
this.foreColorRGB = foreColorRGB & 0xFFFFFF;
|
||||
this.foreColor = Color.WHITE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for backColor RGB.
|
||||
* Getter for backColor RGB. Note that this is always a RGB value,
|
||||
* i.e. alpha is 0.
|
||||
*
|
||||
* @return backColor value. Negative means unset.
|
||||
*/
|
||||
|
@ -300,7 +303,8 @@ public class CellAttributes {
|
|||
* @param backColorRGB new backColor RGB value
|
||||
*/
|
||||
public final void setBackColorRGB(final int backColorRGB) {
|
||||
this.backColorRGB = backColorRGB;
|
||||
this.backColorRGB = backColorRGB & 0xFFFFFF;
|
||||
this.backColor = Color.BLACK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -738,6 +738,68 @@ public class ColorTheme {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the theme to femme. I love pink. You can too! 💗
|
||||
*/
|
||||
public void setFemme() {
|
||||
setDefaultTheme();
|
||||
final int pink = 0xf7a8b8;
|
||||
final int blue = 0x55cdfc;
|
||||
|
||||
for (String key: colors.keySet()) {
|
||||
CellAttributes color = colors.get(key);
|
||||
|
||||
Color fg = color.getForeColor();
|
||||
Color bg = color.getBackColor();
|
||||
boolean bold = color.isBold();
|
||||
if (bg.equals(Color.WHITE) && fg.equals(Color.BLACK)) {
|
||||
color.setForeColor(Color.MAGENTA);
|
||||
color.setBackColorRGB(pink);
|
||||
} else if (bg.equals(Color.WHITE) && fg.equals(Color.WHITE)) {
|
||||
color.setForeColor(Color.MAGENTA);
|
||||
color.setBackColorRGB(pink);
|
||||
color.setBold(true);
|
||||
} else if (bg.equals(Color.WHITE) && fg.equals(Color.WHITE)) {
|
||||
color.setForeColorRGB(blue);
|
||||
color.setBackColorRGB(pink);
|
||||
color.setBold(true);
|
||||
} else if (bg.equals(Color.WHITE) && fg.equals(Color.GREEN)) {
|
||||
color.setForeColor(Color.BLUE);
|
||||
color.setBackColor(Color.BLACK);
|
||||
color.setBold(true);
|
||||
} else if (bg.equals(Color.WHITE) && fg.equals(Color.RED)) {
|
||||
color.setForeColorRGB(blue);
|
||||
color.setBackColorRGB(pink);
|
||||
color.setBold(true);
|
||||
} else if (bg.equals(Color.BLUE) && fg.equals(Color.CYAN)) {
|
||||
color.setForeColor(Color.RED);
|
||||
color.setBackColor(Color.MAGENTA);
|
||||
color.setBold(true);
|
||||
} else if (fg.equals(Color.BLUE) && bg.equals(Color.CYAN)) {
|
||||
color.setForeColor(Color.MAGENTA);
|
||||
color.setBackColor(Color.RED);
|
||||
color.setBold(true);
|
||||
} else if (bg.equals(Color.BLUE)) {
|
||||
color.setBackColor(Color.BLACK);
|
||||
} else if (bg.equals(Color.GREEN)) {
|
||||
color.setBackColor(Color.CYAN);
|
||||
} else if (fg.equals(Color.WHITE) && bold) {
|
||||
color.setForeColor(Color.RED);
|
||||
}
|
||||
|
||||
colors.put(key, color);
|
||||
}
|
||||
|
||||
/*
|
||||
CellAttributes color;
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.MAGENTA);
|
||||
color.setBackColorRGB(pink);
|
||||
color.setBold(false);
|
||||
colors.put("twindow.background.modal", color);
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Make human-readable description of this Cell.
|
||||
*
|
||||
|
|
|
@ -55,6 +55,8 @@ import org.w3c.dom.NodeList;
|
|||
* - Scale an image and preserve aspect ratio.
|
||||
*
|
||||
* - Open an animated image as an Animation.
|
||||
*
|
||||
* - Compute the distance between two colors in RGB space.
|
||||
*/
|
||||
public class ImageUtils {
|
||||
|
||||
|
@ -445,4 +447,24 @@ public class ImageUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the absolute distance in RGB space between two RGB colors.
|
||||
*
|
||||
* @param first the first color
|
||||
* @param second the second color
|
||||
* @return the distance
|
||||
*/
|
||||
public static int rgbDistance(final int first, final int second) {
|
||||
int red = (first >>> 16) & 0xFF;
|
||||
int green = (first >>> 8) & 0xFF;
|
||||
int blue = first & 0xFF;
|
||||
int red2 = (second >>> 16) & 0xFF;
|
||||
int green2 = (second >>> 8) & 0xFF;
|
||||
int blue2 = second & 0xFF;
|
||||
double diff = Math.pow(red2 - red, 2);
|
||||
diff += Math.pow(green2 - green, 2);
|
||||
diff += Math.pow(blue2 - blue, 2);
|
||||
return (int) Math.sqrt(diff);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -277,6 +277,7 @@ public class DemoPixelsWindow extends TWindow {
|
|||
*/
|
||||
@Override
|
||||
public void onClose() {
|
||||
super.onClose();
|
||||
getApplication().removeTimer(timer3);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import jexer.TApplication;
|
|||
import jexer.TKeypress;
|
||||
import jexer.TWidget;
|
||||
import jexer.TWindow;
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.GraphicsChars;
|
||||
import jexer.bits.MnemonicString;
|
||||
|
@ -200,6 +201,22 @@ public class TMenu extends TWindow {
|
|||
useIcons = true;
|
||||
}
|
||||
|
||||
// Set the border style from the system properties
|
||||
setBorderStyleForeground(null);
|
||||
setBorderStyleInactive(null);
|
||||
setBorderStyleModal(null);
|
||||
setBorderStyleMoving(null);
|
||||
|
||||
int opacity = 95;
|
||||
try {
|
||||
opacity = Integer.parseInt(System.getProperty(
|
||||
"jexer.TMenu.opacity", "95"));
|
||||
opacity = Math.max(opacity, 10);
|
||||
opacity = Math.min(opacity, 100);
|
||||
} catch (NumberFormatException e) {
|
||||
// SQUASH
|
||||
}
|
||||
setAlpha(opacity * 255 / 100);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -389,17 +406,13 @@ public class TMenu extends TWindow {
|
|||
}
|
||||
|
||||
// Draw the box
|
||||
char cTopLeft;
|
||||
char cTopRight;
|
||||
char cBottomLeft;
|
||||
char cBottomRight;
|
||||
char cHSide;
|
||||
|
||||
cTopLeft = GraphicsChars.ULCORNER;
|
||||
cTopRight = GraphicsChars.URCORNER;
|
||||
cBottomLeft = GraphicsChars.LLCORNER;
|
||||
cBottomRight = GraphicsChars.LRCORNER;
|
||||
cHSide = GraphicsChars.SINGLE_BAR;
|
||||
BorderStyle borderStyle = getBorderStyle();
|
||||
int cTopLeft = borderStyle.getTopLeft();
|
||||
int cTopRight = borderStyle.getTopRight();
|
||||
int cBottomLeft = borderStyle.getBottomLeft();
|
||||
int cBottomRight = borderStyle.getBottomRight();
|
||||
int cHSide = borderStyle.getHorizontal();
|
||||
int cVSide = borderStyle.getVertical();
|
||||
|
||||
// Place the corner characters
|
||||
putCharXY(1, 0, cTopLeft, background);
|
||||
|
@ -412,7 +425,9 @@ public class TMenu extends TWindow {
|
|||
hLineXY(1 + 1, getHeight() - 1, getWidth() - 4, cHSide, background);
|
||||
|
||||
// Draw a shadow
|
||||
drawBoxShadow(0, 0, getWidth(), getHeight());
|
||||
if (!getApplication().hasTranslucence()) {
|
||||
drawBoxShadow(0, 0, getWidth(), getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -919,4 +934,77 @@ public class TMenu extends TWindow {
|
|||
super.resetTabOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is the foreground window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TMenu.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleForeground(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TMenu.borderStyle",
|
||||
"single");
|
||||
super.setBorderStyleForeground(style);
|
||||
} else {
|
||||
super.setBorderStyleForeground(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is the modal window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TMenu.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleModal(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TMenu.borderStyle",
|
||||
"single");
|
||||
super.setBorderStyleModal(style);
|
||||
} else {
|
||||
super.setBorderStyleModal(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is an inactive/background
|
||||
* window.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TMenu.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleInactive(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TMenu.borderStyle",
|
||||
"single");
|
||||
super.setBorderStyleInactive(style);
|
||||
} else {
|
||||
super.setBorderStyleInactive(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border style for the window when it is being dragged/resize.
|
||||
*
|
||||
* @param borderStyle the border style string, one of: "default", "none",
|
||||
* "single", "double", "singleVdoubleH", "singleHdoubleV", or "round"; or
|
||||
* null to use the value from jexer.TMenu.borderStyle.
|
||||
*/
|
||||
@Override
|
||||
public void setBorderStyleMoving(final String borderStyle) {
|
||||
if (borderStyle == null) {
|
||||
String style = System.getProperty("jexer.TMenu.borderStyle",
|
||||
"single");
|
||||
super.setBorderStyleMoving(style);
|
||||
} else {
|
||||
super.setBorderStyleMoving(borderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ package jexer.menu;
|
|||
import jexer.TKeypress;
|
||||
import jexer.TWidget;
|
||||
import jexer.backend.Backend;
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.GraphicsChars;
|
||||
import jexer.bits.MnemonicString;
|
||||
|
@ -249,7 +250,8 @@ public class TMenuItem extends TWidget {
|
|||
|
||||
boolean useIcons = ((TMenu) getParent()).useIcons;
|
||||
|
||||
char cVSide = GraphicsChars.WINDOW_SIDE;
|
||||
BorderStyle borderStyle = ((TMenu) getParent()).getBorderStyle();
|
||||
int cVSide = borderStyle.getVertical();
|
||||
vLineXY(0, 0, 1, cVSide, background);
|
||||
vLineXY(getWidth() - 1, 0, 1, cVSide, background);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
*/
|
||||
package jexer.menu;
|
||||
|
||||
import jexer.bits.BorderStyle;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.GraphicsChars;
|
||||
|
||||
|
@ -65,9 +66,22 @@ public class TMenuSeparator extends TMenuItem {
|
|||
public void draw() {
|
||||
CellAttributes background = getTheme().getColor("tmenu");
|
||||
|
||||
putCharXY(0, 0, GraphicsChars.CP437[0xC3], background);
|
||||
putCharXY(getWidth() - 1, 0, GraphicsChars.CP437[0xB4], background);
|
||||
hLineXY(1, 0, getWidth() - 2, GraphicsChars.SINGLE_BAR, background);
|
||||
BorderStyle borderStyle = ((TMenu) getParent()).getBorderStyle();
|
||||
int cHSide = GraphicsChars.SINGLE_BAR;
|
||||
int left = GraphicsChars.CP437[0xC3];
|
||||
int right = GraphicsChars.CP437[0xB4];
|
||||
if (borderStyle.getVertical() == GraphicsChars.WINDOW_SIDE_DOUBLE) {
|
||||
left = 0x255F;
|
||||
right = 0x2562;
|
||||
}
|
||||
if (borderStyle.equals(BorderStyle.NONE)) {
|
||||
left = ' ';
|
||||
right = ' ';
|
||||
}
|
||||
|
||||
putCharXY(0, 0, left, background);
|
||||
putCharXY(getWidth() - 1, 0, right, background);
|
||||
hLineXY(1, 0, getWidth() - 2, cHSide, background);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -164,6 +164,19 @@ public class Bitmap extends TackboardItem {
|
|||
return renderedImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this item from its board. Subclasses can use this for cleanup
|
||||
* also.
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
|
||||
if (animation != null) {
|
||||
animation.stop();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Bitmap -----------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
@ -279,8 +279,10 @@ public class Tackboard {
|
|||
backImage = new BufferedImage(cellWidth,
|
||||
cellHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
java.awt.Graphics gr = backImage.getGraphics();
|
||||
gr.setColor(screen.getBackend().
|
||||
attrToBackgroundColor(oldCell));
|
||||
|
||||
java.awt.Color oldColor = screen.getBackend().
|
||||
attrToBackgroundColor(oldCell);
|
||||
gr.setColor(oldColor);
|
||||
gr.fillRect(0, 0, backImage.getWidth(),
|
||||
backImage.getHeight());
|
||||
gr.drawImage(newImage, 0, 0, null, null);
|
||||
|
|
|
@ -3735,9 +3735,7 @@ public class ECMA48 implements Runnable {
|
|||
// screen. We won't switch to a different buffer,
|
||||
// instead we will just clear the screen.
|
||||
currentState.attr.setForeColor(Color.WHITE);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
currentState.attr.setBackColor(Color.BLACK);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
eraseScreen(0, 0, height - 1, width - 1, false);
|
||||
scrollRegionTop = 0;
|
||||
scrollRegionBottom = height - 1;
|
||||
|
@ -4428,9 +4426,7 @@ public class ECMA48 implements Runnable {
|
|||
*/
|
||||
private void sgr() {
|
||||
for (int i = 0; i < collectBuffer.length(); i++) {
|
||||
if ((collectBuffer.charAt(i) == '>')
|
||||
|| (collectBuffer.charAt(i) == '>')
|
||||
) {
|
||||
if (collectBuffer.charAt(i) == '>') {
|
||||
// Private-mode sequence, disregard.
|
||||
return;
|
||||
}
|
||||
|
@ -4672,42 +4668,34 @@ public class ECMA48 implements Runnable {
|
|||
case 30:
|
||||
// Set black foreground
|
||||
currentState.attr.setForeColor(Color.BLACK);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 31:
|
||||
// Set red foreground
|
||||
currentState.attr.setForeColor(Color.RED);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 32:
|
||||
// Set green foreground
|
||||
currentState.attr.setForeColor(Color.GREEN);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 33:
|
||||
// Set yellow foreground
|
||||
currentState.attr.setForeColor(Color.YELLOW);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 34:
|
||||
// Set blue foreground
|
||||
currentState.attr.setForeColor(Color.BLUE);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 35:
|
||||
// Set magenta foreground
|
||||
currentState.attr.setForeColor(Color.MAGENTA);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 36:
|
||||
// Set cyan foreground
|
||||
currentState.attr.setForeColor(Color.CYAN);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 37:
|
||||
// Set white foreground
|
||||
currentState.attr.setForeColor(Color.WHITE);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 38:
|
||||
if (type == DeviceType.XTERM) {
|
||||
|
@ -4758,47 +4746,38 @@ public class ECMA48 implements Runnable {
|
|||
// Underscore off, default foreground color
|
||||
currentState.attr.setUnderline(false);
|
||||
currentState.attr.setForeColor(Color.WHITE);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 40:
|
||||
// Set black background
|
||||
currentState.attr.setBackColor(Color.BLACK);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 41:
|
||||
// Set red background
|
||||
currentState.attr.setBackColor(Color.RED);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 42:
|
||||
// Set green background
|
||||
currentState.attr.setBackColor(Color.GREEN);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 43:
|
||||
// Set yellow background
|
||||
currentState.attr.setBackColor(Color.YELLOW);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 44:
|
||||
// Set blue background
|
||||
currentState.attr.setBackColor(Color.BLUE);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 45:
|
||||
// Set magenta background
|
||||
currentState.attr.setBackColor(Color.MAGENTA);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 46:
|
||||
// Set cyan background
|
||||
currentState.attr.setBackColor(Color.CYAN);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 47:
|
||||
// Set white background
|
||||
currentState.attr.setBackColor(Color.WHITE);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 48:
|
||||
if (type == DeviceType.XTERM) {
|
||||
|
@ -4844,7 +4823,6 @@ public class ECMA48 implements Runnable {
|
|||
case 49:
|
||||
// Default background
|
||||
currentState.attr.setBackColor(Color.BLACK);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue