Use terminal colors for image background

This commit is contained in:
Autumn Lamonte 2022-01-03 19:39:59 -06:00
parent 50fcfc3ea0
commit 48dd72ea1b
18 changed files with 591 additions and 63 deletions

View file

@ -379,7 +379,7 @@ public class TImage extends TWidget implements EditMenuUser {
* @param always if true, always resize the cells
*/
private void sizeToImage(final boolean always) {
scaleBackColor = jexer.backend.SwingTerminal.attrToBackgroundColor(getWindow().getBackground());
scaleBackColor = getApplication().getBackend().attrToBackgroundColor(getWindow().getBackground());
int textWidth = getScreen().getTextWidth();
int textHeight = getScreen().getTextHeight();
@ -437,7 +437,7 @@ public class TImage extends TWidget implements EditMenuUser {
if (!ImageUtils.isFullyTransparent(newImage)) {
cell.setImage(newImage);
cell.flattenImage(false);
cell.flattenImage(false, getApplication().getBackend());
}
cells[x][y] = cell;
}

View file

@ -1335,10 +1335,10 @@ public class TTerminalWidget extends TScrollableWidget
Cell newCell = new Cell(cell);
newCell.setUnderline(false);
image = doubleFont.getImage(newCell, textWidth * 2, textHeight * 2,
cursorBlinkVisible);
getApplication().getBackend(), cursorBlinkVisible);
} else {
image = doubleFont.getImage(cell, textWidth * 2, textHeight * 2,
cursorBlinkVisible);
getApplication().getBackend(), cursorBlinkVisible);
}
// Now that we have the double-wide glyph drawn, copy the right

View file

@ -442,10 +442,10 @@ public class TTextPicture extends TScrollableWidget
Cell newCell = new Cell(cell);
newCell.setUnderline(false);
image = doubleFont.getImage(newCell, textWidth * 2, textHeight * 2,
cursorBlinkVisible);
getApplication().getBackend(), cursorBlinkVisible);
} else {
image = doubleFont.getImage(cell, textWidth * 2, textHeight * 2,
cursorBlinkVisible);
getApplication().getBackend(), cursorBlinkVisible);
}
// Now that we have the double-wide glyph drawn, copy the right

View file

@ -30,6 +30,7 @@ package jexer.backend;
import java.util.List;
import jexer.bits.CellAttributes;
import jexer.event.TInputEvent;
/**
@ -146,4 +147,20 @@ public interface Backend {
*/
public void setMouseStyle(final String mouseStyle);
/**
* Convert a CellAttributes foreground color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToForegroundColor(final CellAttributes attr);
/**
* Convert a CellAttributes background color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToBackgroundColor(final CellAttributes attr);
}

View file

@ -34,6 +34,8 @@ import java.io.PrintWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import jexer.bits.CellAttributes;
/**
* This class uses an xterm/ANSI X3.64/ECMA-48 type terminal to provide a
* screen, keyboard, and mouse to TApplication.
@ -83,6 +85,7 @@ public class ECMA48Backend extends GenericBackend {
// Create a terminal and explicitly set stdin into raw mode
terminal = new ECMA48Terminal(this, listener, input, output,
windowWidth, windowHeight);
((ECMA48Terminal) terminal).setBackend(this);
// Keep the terminal's sessionInfo so that TApplication can see it
sessionInfo = ((ECMA48Terminal) terminal).getSessionInfo();
@ -136,6 +139,7 @@ public class ECMA48Backend extends GenericBackend {
// Create a terminal and explicitly set stdin into raw mode
terminal = new ECMA48Terminal(this, listener, input, output);
((ECMA48Terminal) terminal).setBackend(this);
// Keep the terminal's sessionInfo so that TApplication can see it
sessionInfo = ((ECMA48Terminal) terminal).getSessionInfo();
@ -165,6 +169,7 @@ public class ECMA48Backend extends GenericBackend {
// Create a terminal and explicitly set stdin into raw mode
terminal = new ECMA48Terminal(this, listener, input, reader, writer,
setRawMode);
((ECMA48Terminal) terminal).setBackend(this);
// Keep the terminal's sessionInfo so that TApplication can see it
sessionInfo = ((ECMA48Terminal) terminal).getSessionInfo();
@ -235,4 +240,24 @@ public class ECMA48Backend extends GenericBackend {
((ECMA48Terminal) terminal).setMouseStyle(mouseStyle);
}
/**
* Convert a CellAttributes foreground color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToForegroundColor(final CellAttributes attr) {
return ((ECMA48Terminal) terminal).attrToForegroundColor(attr);
}
/**
* Convert a CellAttributes background color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToBackgroundColor(final CellAttributes attr) {
return ((ECMA48Terminal) terminal).attrToBackgroundColor(attr);
}
}

View file

@ -83,6 +83,7 @@ public class ECMA48Terminal extends LogicalScreen
CSI_ENTRY,
CSI_PARAM,
XTVERSION,
OSC,
MOUSE,
MOUSE_SGR,
}
@ -291,6 +292,11 @@ public class ECMA48Terminal extends LogicalScreen
*/
private StringBuilder xtversionResponse = new StringBuilder();
/**
* The string being built by OSC.
*/
private StringBuilder oscResponse = new StringBuilder();
/**
* If true, draw text glyphs underneath images on cells. This is
* expensive.
@ -342,22 +348,22 @@ public class ECMA48Terminal extends LogicalScreen
private Object listener;
// Colors to map DOS colors to AWT colors.
private static java.awt.Color MYBLACK;
private static java.awt.Color MYRED;
private static java.awt.Color MYGREEN;
private static java.awt.Color MYYELLOW;
private static java.awt.Color MYBLUE;
private static java.awt.Color MYMAGENTA;
private static java.awt.Color MYCYAN;
private static java.awt.Color MYWHITE;
private static java.awt.Color MYBOLD_BLACK;
private static java.awt.Color MYBOLD_RED;
private static java.awt.Color MYBOLD_GREEN;
private static java.awt.Color MYBOLD_YELLOW;
private static java.awt.Color MYBOLD_BLUE;
private static java.awt.Color MYBOLD_MAGENTA;
private static java.awt.Color MYBOLD_CYAN;
private static java.awt.Color MYBOLD_WHITE;
private java.awt.Color MYBLACK;
private java.awt.Color MYRED;
private java.awt.Color MYGREEN;
private java.awt.Color MYYELLOW;
private java.awt.Color MYBLUE;
private java.awt.Color MYMAGENTA;
private java.awt.Color MYCYAN;
private java.awt.Color MYWHITE;
private java.awt.Color MYBOLD_BLACK;
private java.awt.Color MYBOLD_RED;
private java.awt.Color MYBOLD_GREEN;
private java.awt.Color MYBOLD_YELLOW;
private java.awt.Color MYBOLD_BLUE;
private java.awt.Color MYBOLD_MAGENTA;
private java.awt.Color MYBOLD_CYAN;
private java.awt.Color MYBOLD_WHITE;
/**
* ImageCache is a least-recently-used cache that hangs on to the
@ -620,6 +626,9 @@ public class ECMA48Terminal extends LogicalScreen
// Request xterm report SGR-Pixel mouse support
this.output.printf("%s", xtermQueryMode(1016));
// Request xterm report its ANSI colors
this.output.printf("%s", xtermQueryAnsiColors());
this.output.flush();
// Query the screen size
@ -730,6 +739,9 @@ public class ECMA48Terminal extends LogicalScreen
// Request xterm report SGR-Pixel mouse support
this.output.printf("%s", xtermQueryMode(1016));
// Request xterm report its ANSI colors
this.output.printf("%s", xtermQueryAnsiColors());
this.output.flush();
// Query the screen size
@ -1649,10 +1661,11 @@ public class ECMA48Terminal extends LogicalScreen
// if imagesOverText is disabled then we will quietly
// continue on. Otherwise render a text character
// under the image.
assert (backend != null);
if (imagesOverText == true) {
logical[x + i][y].flattenImage(true);
logical[x + i][y].flattenImage(true, backend);
} else {
logical[x + i][y].flattenImage(false);
logical[x + i][y].flattenImage(false, backend);
}
}
assert (!logical[x + i][y].isTransparentImage());
@ -1748,6 +1761,7 @@ public class ECMA48Terminal extends LogicalScreen
decPrivateModeFlag = false;
decDollarModeFlag = false;
xtversionResponse.setLength(0);
oscResponse.setLength(0);
}
/**
@ -2275,6 +2289,162 @@ public class ECMA48Terminal extends LogicalScreen
}
}
/**
* Process an OSC response.
*
* @param text the OSC response string
*/
private void oscResponse(final String text) {
if (debugToStderr) {
System.err.println("oscResponse(): '" + text + "'");
}
String [] Ps = text.split(";");
if (Ps.length == 0) {
return;
}
if (Ps[0].equals("4")) {
// RGB response
if (Ps.length != 3) {
return;
}
try {
int color = Integer.parseInt(Ps[1]);
String rgb = Ps[2];
if (!rgb.startsWith("rgb:")) {
return;
}
rgb = rgb.substring(4);
if (debugToStderr) {
System.err.println(" Color " + color + " is " + rgb);
}
String [] rgbs = rgb.split("/");
if (rgbs.length != 3) {
return;
}
int red = Integer.parseInt(rgbs[0], 16);
int green = Integer.parseInt(rgbs[1], 16);
int blue = Integer.parseInt(rgbs[2], 16);
if (rgbs[0].length() == 4) {
red = red >> 8;
}
if (rgbs[1].length() == 4) {
green = green >> 8;
}
if (rgbs[2].length() == 4) {
blue = blue >> 8;
}
if (debugToStderr) {
System.err.printf(" RGB %02x%02x%02x\n",
red, green, blue);
}
switch (color) {
case 0:
MYBLACK = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BLACK");
}
break;
case 1:
MYRED = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set RED");
}
break;
case 2:
MYGREEN = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set GREEN");
}
break;
case 3:
MYYELLOW = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set YELLOW");
}
break;
case 4:
MYBLUE = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BLUE");
}
break;
case 5:
MYMAGENTA = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set MAGENTA");
}
break;
case 6:
MYCYAN = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set CYAN");
}
break;
case 7:
MYWHITE = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set WHITE");
}
break;
case 8:
MYBOLD_BLACK = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BOLD BLACK");
}
break;
case 9:
MYBOLD_RED = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BOLD RED");
}
break;
case 10:
MYBOLD_GREEN = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BOLD GREEN");
}
break;
case 11:
MYBOLD_YELLOW = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BOLD YELLOW");
}
break;
case 12:
MYBOLD_BLUE = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BOLD BLUE");
}
break;
case 13:
MYBOLD_MAGENTA = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BOLD MAGENTA");
}
break;
case 14:
MYBOLD_CYAN = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BOLD CYAN");
}
break;
case 15:
MYBOLD_WHITE = new java.awt.Color(red, green, blue);
if (debugToStderr) {
System.err.println(" Set BOLD WHITE");
}
break;
default:
break;
}
} catch (NumberFormatException e) {
return;
}
}
}
/**
* Parses the next character of input to see if an InputEvent is
* fully here.
@ -2341,6 +2511,12 @@ public class ECMA48Terminal extends LogicalScreen
}
xtversionQuery = false;
if (ch == ']') {
state = ParseState.OSC;
oscResponse.setLength(0);
return;
}
if (ch <= 0x1F) {
// ALT-Control character
events.add(controlChar(ch, true));
@ -2842,6 +3018,22 @@ public class ECMA48Terminal extends LogicalScreen
xtversionResponse.append(ch);
return;
case OSC:
if ((ch == '\\') &&
(oscResponse.length() > 0) &&
(oscResponse.charAt(oscResponse.length() - 1)
== 0x1B)
) {
// This is ST, end of the line.
oscResponse(oscResponse.substring(0, oscResponse.length() - 1));
resetParser();
return;
}
// Continue collecting until we see ST.
oscResponse.append(ch);
return;
default:
break;
}
@ -3741,6 +3933,100 @@ public class ECMA48Terminal extends LogicalScreen
return color;
}
/**
* Convert a CellAttributes foreground color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToForegroundColor(final CellAttributes attr) {
int rgb = attr.getForeColorRGB();
if (rgb >= 0) {
int red = (rgb >>> 16) & 0xFF;
int green = (rgb >>> 8) & 0xFF;
int blue = rgb & 0xFF;
return new java.awt.Color(red, green, blue);
}
if (attr.isBold()) {
if (attr.getForeColor().equals(Color.BLACK)) {
return MYBOLD_BLACK;
} else if (attr.getForeColor().equals(Color.RED)) {
return MYBOLD_RED;
} else if (attr.getForeColor().equals(Color.BLUE)) {
return MYBOLD_BLUE;
} else if (attr.getForeColor().equals(Color.GREEN)) {
return MYBOLD_GREEN;
} else if (attr.getForeColor().equals(Color.YELLOW)) {
return MYBOLD_YELLOW;
} else if (attr.getForeColor().equals(Color.CYAN)) {
return MYBOLD_CYAN;
} else if (attr.getForeColor().equals(Color.MAGENTA)) {
return MYBOLD_MAGENTA;
} else if (attr.getForeColor().equals(Color.WHITE)) {
return MYBOLD_WHITE;
}
} else {
if (attr.getForeColor().equals(Color.BLACK)) {
return MYBLACK;
} else if (attr.getForeColor().equals(Color.RED)) {
return MYRED;
} else if (attr.getForeColor().equals(Color.BLUE)) {
return MYBLUE;
} else if (attr.getForeColor().equals(Color.GREEN)) {
return MYGREEN;
} else if (attr.getForeColor().equals(Color.YELLOW)) {
return MYYELLOW;
} else if (attr.getForeColor().equals(Color.CYAN)) {
return MYCYAN;
} else if (attr.getForeColor().equals(Color.MAGENTA)) {
return MYMAGENTA;
} else if (attr.getForeColor().equals(Color.WHITE)) {
return MYWHITE;
}
}
throw new IllegalArgumentException("Invalid color: " +
attr.getForeColor().getValue());
}
/**
* Convert a CellAttributes background color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToBackgroundColor(final CellAttributes attr) {
int rgb = attr.getBackColorRGB();
if (rgb >= 0) {
int red = (rgb >>> 16) & 0xFF;
int green = (rgb >>> 8) & 0xFF;
int blue = rgb & 0xFF;
return new java.awt.Color(red, green, blue);
}
if (attr.getBackColor().equals(Color.BLACK)) {
return MYBLACK;
} else if (attr.getBackColor().equals(Color.RED)) {
return MYRED;
} else if (attr.getBackColor().equals(Color.BLUE)) {
return MYBLUE;
} else if (attr.getBackColor().equals(Color.GREEN)) {
return MYGREEN;
} else if (attr.getBackColor().equals(Color.YELLOW)) {
return MYYELLOW;
} else if (attr.getBackColor().equals(Color.CYAN)) {
return MYCYAN;
} else if (attr.getBackColor().equals(Color.MAGENTA)) {
return MYMAGENTA;
} else if (attr.getBackColor().equals(Color.WHITE)) {
return MYWHITE;
}
throw new IllegalArgumentException("Invalid color: " +
attr.getBackColor().getValue());
}
/**
* Create a T.416 RGB parameter sequence for a custom system color.
*
@ -4269,4 +4555,17 @@ public class ECMA48Terminal extends LogicalScreen
return "";
}
/**
* Request (u)xterm report the RGB values of its ANSI colors.
*
* @return the string to emit to xterm
*/
private String xtermQueryAnsiColors() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 16; i++) {
sb.append(String.format("\033]4;%d;?\033\\", i));
}
return sb.toString();
}
}

View file

@ -172,12 +172,14 @@ class GlyphMakerFont {
* @param cell the character to draw
* @param cellWidth the width of the text cell to draw into
* @param cellHeight the height of the text cell to draw into
* @param backend the backend that can obtain the correct background
* color
* @return the glyph as an image
*/
public BufferedImage getImage(final Cell cell, final int cellWidth,
final int cellHeight) {
final int cellHeight, final Backend backend) {
return getImage(cell, cellWidth, cellHeight, true);
return getImage(cell, cellWidth, cellHeight, backend, true);
}
/**
@ -186,11 +188,30 @@ class GlyphMakerFont {
* @param cell the character to draw
* @param cellWidth the width of the text cell to draw into
* @param cellHeight the height of the text cell to draw into
* @return the glyph as an image
*/
/*
public BufferedImage getImage(final Cell cell, final int cellWidth,
final int cellHeight) {
return getImage(cell, cellWidth, cellHeight, true);
}
*/
/**
* Get a glyph image.
*
* @param cell the character to draw
* @param cellWidth the width of the text cell to draw into
* @param cellHeight the height of the text cell to draw into
* @param backend the backend that can obtain the correct background
* color
* @param blinkVisible if true, the cell is visible if it is blinking
* @return the glyph as an image
*/
public BufferedImage getImage(final Cell cell, final int cellWidth,
final int cellHeight, final boolean blinkVisible) {
final int cellHeight, final Backend backend,
final boolean blinkVisible) {
if (gotFontDimensions == false) {
// Lazy-load the text width/height and adjustments.
@ -227,14 +248,14 @@ class GlyphMakerFont {
}
// Draw the background rectangle, then the foreground character.
gr2.setColor(SwingTerminal.attrToBackgroundColor(cellColor));
gr2.setColor(backend.attrToBackgroundColor(cellColor));
gr2.fillRect(0, 0, cellWidth, cellHeight);
// Handle blink and underline
if (!cell.isBlink()
|| (cell.isBlink() && blinkVisible)
) {
gr2.setColor(SwingTerminal.attrToForegroundColor(cellColor));
gr2.setColor(backend.attrToForegroundColor(cellColor));
char [] chars = Character.toChars(cell.getChar());
gr2.drawChars(chars, 0, chars.length, textAdjustX,
cellHeight - maxDescent + textAdjustY);
@ -427,12 +448,14 @@ public class GlyphMaker {
* @param cell the character to draw
* @param cellWidth the width of the text cell to draw into
* @param cellHeight the height of the text cell to draw into
* @param backend the backend that can obtain the correct background
* color
* @return the glyph as an image
*/
public BufferedImage getImage(final Cell cell, final int cellWidth,
final int cellHeight) {
final int cellHeight, final Backend backend) {
return getImage(cell, cellWidth, cellHeight, true);
return getImage(cell, cellWidth, cellHeight, backend, true);
}
/**
@ -441,34 +464,37 @@ public class GlyphMaker {
* @param cell the character to draw
* @param cellWidth the width of the text cell to draw into
* @param cellHeight the height of the text cell to draw into
* @param backend the backend that can obtain the correct background
* color
* @param blinkVisible if true, the cell is visible if it is blinking
* @return the glyph as an image
*/
public BufferedImage getImage(final Cell cell, final int cellWidth,
final int cellHeight, final boolean blinkVisible) {
final int cellHeight, final Backend backend,
final boolean blinkVisible) {
int ch = cell.getChar();
if (StringUtils.isCjk(ch)) {
if (makerCjk.canDisplay(ch)) {
return makerCjk.getImage(cell, cellWidth, cellHeight,
return makerCjk.getImage(cell, cellWidth, cellHeight, backend,
blinkVisible);
}
}
if (StringUtils.isEmoji(ch)) {
if (makerEmoji.canDisplay(ch)) {
// System.err.println("emoji: " + String.format("0x%x", ch));
return makerEmoji.getImage(cell, cellWidth, cellHeight,
return makerEmoji.getImage(cell, cellWidth, cellHeight, backend,
blinkVisible);
}
}
// When all else fails, use the default.
if (makerMono.canDisplay(ch)) {
return makerMono.getImage(cell, cellWidth, cellHeight,
return makerMono.getImage(cell, cellWidth, cellHeight, backend,
blinkVisible);
}
return makerFallback.getImage(cell, cellWidth, cellHeight,
return makerFallback.getImage(cell, cellWidth, cellHeight, backend,
blinkVisible);
}

View file

@ -30,6 +30,7 @@ package jexer.backend;
import java.util.List;
import jexer.bits.CellAttributes;
import jexer.event.TInputEvent;
/**
@ -190,4 +191,26 @@ public class HeadlessBackend extends LogicalScreen implements Backend {
// NOP
}
/**
* Convert a CellAttributes foreground color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToForegroundColor(final CellAttributes attr) {
// Use Swing colors.
return SwingTerminal.attrToForegroundColor(attr);
}
/**
* Convert a CellAttributes background color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToBackgroundColor(final CellAttributes attr) {
// Use Swing colors.
return SwingTerminal.attrToBackgroundColor(attr);
}
}

View file

@ -46,6 +46,11 @@ public class LogicalScreen implements Screen {
// Variables --------------------------------------------------------------
// ------------------------------------------------------------------------
/**
* The backend associated with this screen.
*/
private Backend backend;
/**
* Width of the visible window.
*/
@ -1049,7 +1054,7 @@ public class LogicalScreen implements Screen {
lastTextHeight = cellHeight;
}
BufferedImage image = glyphMaker.getImage(cell, cellWidth * 2,
cellHeight);
cellHeight, backend);
BufferedImage leftImage = image.getSubimage(0, 0, cellWidth,
cellHeight);
BufferedImage rightImage = image.getSubimage(cellWidth, 0, cellWidth,
@ -1295,4 +1300,22 @@ public class LogicalScreen implements Screen {
return other;
}
/**
* Set the backend to associated with this screen.
*
* @param backend the backend
*/
public final void setBackend(final Backend backend) {
this.backend = backend;
}
/**
* Get the backend that instantiated this screen.
*
* @return the backend
*/
public final Backend getBackend() {
return backend;
}
}

View file

@ -31,6 +31,7 @@ package jexer.backend;
import java.util.ArrayList;
import java.util.List;
import jexer.bits.CellAttributes;
import jexer.event.TCommandEvent;
import jexer.event.TInputEvent;
import static jexer.TCommand.*;
@ -373,4 +374,26 @@ public class MultiBackend implements Backend {
}
}
/**
* Convert a CellAttributes foreground color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToForegroundColor(final CellAttributes attr) {
// Use Swing colors.
return SwingTerminal.attrToForegroundColor(attr);
}
/**
* Convert a CellAttributes background color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToBackgroundColor(final CellAttributes attr) {
// Use Swing colors.
return SwingTerminal.attrToBackgroundColor(attr);
}
}

View file

@ -44,6 +44,11 @@ public class MultiScreen implements Screen {
// Variables --------------------------------------------------------------
// ------------------------------------------------------------------------
/**
* The backend associated with this screen.
*/
private Backend backend;
/**
* The list of screens to use.
*/
@ -947,4 +952,22 @@ public class MultiScreen implements Screen {
}
}
/**
* Set the backend to associated with this screen.
*
* @param backend the backend
*/
public final void setBackend(final Backend backend) {
this.backend = backend;
}
/**
* Get the backend that instantiated this screen.
*
* @return the backend
*/
public final Backend getBackend() {
return backend;
}
}

View file

@ -490,4 +490,11 @@ public interface Screen {
*/
public Screen snapshot();
/**
* Get the backend that instantiated this screen.
*
* @return the backend
*/
public Backend getBackend();
}

View file

@ -31,6 +31,8 @@ package jexer.backend;
import java.awt.Font;
import javax.swing.JComponent;
import jexer.bits.CellAttributes;
/**
* This class uses standard Swing calls to handle screen, keyboard, and mouse
* I/O.
@ -98,6 +100,7 @@ public class SwingBackend extends GenericBackend {
// Create a Swing backend using a JFrame
terminal = new SwingTerminal(this, windowWidth, windowHeight, fontSize,
listener);
((SwingTerminal) terminal).setBackend(this);
// Hang onto the session info
this.sessionInfo = ((SwingTerminal) terminal).getSessionInfo();
@ -123,6 +126,7 @@ public class SwingBackend extends GenericBackend {
// Create a Swing backend using a JComponent
terminal = new SwingTerminal(this, component, windowWidth, windowHeight,
fontSize, listener);
((SwingTerminal) terminal).setBackend(this);
// Hang onto the session info
this.sessionInfo = ((SwingTerminal) terminal).getSessionInfo();
@ -209,4 +213,26 @@ public class SwingBackend extends GenericBackend {
((SwingTerminal) terminal).setMouseStyle(mouseStyle);
}
/**
* Convert a CellAttributes foreground color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToForegroundColor(final CellAttributes attr) {
// Use Swing colors.
return SwingTerminal.attrToForegroundColor(attr);
}
/**
* Convert a CellAttributes background color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToBackgroundColor(final CellAttributes attr) {
// Use Swing colors.
return SwingTerminal.attrToBackgroundColor(attr);
}
}

View file

@ -1173,10 +1173,10 @@ public class SwingTerminal extends LogicalScreen
}
/**
* Convert a CellAttributes foreground color to an Swing Color.
* Convert a CellAttributes foreground color to an AWT Color.
*
* @param attr the text attributes
* @return the Swing Color
* @return the AWT Color
*/
public static Color attrToForegroundColor(final CellAttributes attr) {
int rgb = attr.getForeColorRGB();
@ -1230,10 +1230,10 @@ public class SwingTerminal extends LogicalScreen
}
/**
* Convert a CellAttributes background color to an Swing Color.
* Convert a CellAttributes background color to an AWT Color.
*
* @param attr the text attributes
* @return the Swing Color
* @return the AWT Color
*/
public static Color attrToBackgroundColor(final CellAttributes attr) {
int rgb = attr.getBackColorRGB();

View file

@ -33,6 +33,7 @@ import java.util.List;
import jexer.TApplication;
import jexer.TWindow;
import jexer.bits.CellAttributes;
import jexer.event.TCommandEvent;
import jexer.event.TInputEvent;
import jexer.event.TKeypressEvent;
@ -608,4 +609,24 @@ public class TWindowBackend extends TWindow implements Backend {
this.otherApplication = application;
}
/**
* Convert a CellAttributes foreground color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToForegroundColor(final CellAttributes attr) {
return getApplication().getBackend().attrToForegroundColor(attr);
}
/**
* Convert a CellAttributes background color to an AWT Color.
*
* @param attr the text attributes
* @return the AWT Color
*/
public java.awt.Color attrToBackgroundColor(final CellAttributes attr) {
return getApplication().getBackend().attrToBackgroundColor(attr);
}
}

View file

@ -29,6 +29,7 @@
package jexer.bits;
import java.awt.image.BufferedImage;
import jexer.backend.Backend;
import jexer.backend.GlyphMaker;
/**
@ -233,8 +234,10 @@ public class Cell extends CellAttributes {
* background color, or generating the glyph and rendering over that.
*
* @param overGlyph if true, render over the glyph
* @param backend the backend that can obtain the correct background
* color
*/
public void flattenImage(final boolean overGlyph) {
public void flattenImage(final boolean overGlyph, final Backend backend) {
if (!isImage()) {
return;
}
@ -252,15 +255,14 @@ public class Cell extends CellAttributes {
BufferedImage newImage = new BufferedImage(textWidth,
textHeight, BufferedImage.TYPE_INT_ARGB);
java.awt.Graphics gr = newImage.getGraphics();
gr.setColor(jexer.backend.SwingTerminal.
attrToBackgroundColor(this));
gr.setColor(backend.attrToBackgroundColor(this));
if (overGlyph) {
// Render this cell to a flat image. The bad news is that we
// won't get to use the actual terminal's font.
GlyphMaker glyphMaker = GlyphMaker.getInstance(textHeight);
gr.drawImage(glyphMaker.getImage(this, textWidth, textHeight),
0, 0, null, null);
gr.drawImage(glyphMaker.getImage(this, textWidth, textHeight,
backend), 0, 0, null, null);
} else {
// Put the background color behind the pixels.
gr.fillRect(0, 0, newImage.getWidth(),

View file

@ -267,7 +267,7 @@ public class Tackboard {
// Blit this image over that one.
BufferedImage oldImage = oldCell.getImage(true);
java.awt.Graphics gr = oldImage.getGraphics();
gr.setColor(jexer.backend.SwingTerminal.
gr.setColor(screen.getBackend().
attrToBackgroundColor(oldCell));
gr.drawImage(newImage, 0, 0, null, null);
gr.dispose();
@ -279,7 +279,7 @@ public class Tackboard {
backImage = new BufferedImage(cellWidth,
cellHeight, BufferedImage.TYPE_INT_ARGB);
java.awt.Graphics gr = backImage.getGraphics();
gr.setColor(jexer.backend.SwingTerminal.
gr.setColor(screen.getBackend().
attrToBackgroundColor(oldCell));
gr.fillRect(0, 0, backImage.getWidth(),
backImage.getHeight());

View file

@ -5362,12 +5362,17 @@ public class ECMA48 implements Runnable {
}
if (p[0].equals("4")) {
for (int i = 1; i + 1 < p.length; i += 2) {
// Set a color index value
try {
set88Color(Integer.parseInt(p[i]), p[i + 1]);
} catch (NumberFormatException e) {
// SQUASH
if (p[1].equals("?")) {
// Query a color index value
// TODO AZL
} else {
for (int i = 1; i + 1 < p.length; i += 2) {
// Set a color index value
try {
set88Color(Integer.parseInt(p[i]), p[i + 1]);
} catch (NumberFormatException e) {
// SQUASH
}
}
}
}
@ -5375,8 +5380,9 @@ public class ECMA48 implements Runnable {
if (p[0].equals("10")) {
if (p[1].equals("?")) {
// Respond with foreground color.
java.awt.Color color = SwingTerminal.attrToForegroundColor(currentState.attr);
java.awt.Color color = (backend != null ?
backend.attrToForegroundColor(currentState.attr) :
SwingTerminal.attrToForegroundColor(currentState.attr));
writeRemote(String.format(
"\033]10;rgb:%04x/%04x/%04x\033\\",
color.getRed() << 8,
@ -5388,8 +5394,9 @@ public class ECMA48 implements Runnable {
if (p[0].equals("11")) {
if (p[1].equals("?")) {
// Respond with background color.
java.awt.Color color = SwingTerminal.attrToBackgroundColor(currentState.attr);
java.awt.Color color = (backend != null ?
backend.attrToBackgroundColor(currentState.attr) :
SwingTerminal.attrToBackgroundColor(currentState.attr));
writeRemote(String.format(
"\033]11;rgb:%04x/%04x/%04x\033\\",
color.getRed() << 8,
@ -7732,7 +7739,7 @@ public class ECMA48 implements Runnable {
Cell cell = new Cell(ch, currentState.attr);
BufferedImage image = glyphMaker.getImage(cell, textWidth * 2,
textHeight);
textHeight, backend);
BufferedImage leftImage = image.getSubimage(0, 0, textWidth,
textHeight);
BufferedImage rightImage = image.getSubimage(textWidth, 0, textWidth,
@ -7851,7 +7858,9 @@ public class ECMA48 implements Runnable {
}
SixelDecoder sixel = new SixelDecoder(sixelParseBuffer.toString(),
sixelPalette,
SwingTerminal.attrToBackgroundColor(currentState.attr),
(backend != null ?
backend.attrToBackgroundColor(currentState.attr) :
SwingTerminal.attrToBackgroundColor(currentState.attr)),
maybeTransparent);
BufferedImage image = sixel.getImage();
@ -8244,14 +8253,18 @@ public class ECMA48 implements Runnable {
// Scale the image to fit the requested dimensions.
image = ImageUtils.scaleImage(image, displayWidth, displayHeight,
ImageUtils.Scale.SCALE,
SwingTerminal.attrToBackgroundColor(currentState.attr));
(backend != null ?
backend.attrToBackgroundColor(currentState.attr) :
SwingTerminal.attrToBackgroundColor(currentState.attr)));
} else if ((displayWidth != fileImageWidth)
|| (displayHeight != fileImageHeight)
) {
// Scale the image to fit the requested dimensions.
image = ImageUtils.scaleImage(image, displayWidth, displayHeight,
ImageUtils.Scale.STRETCH,
SwingTerminal.attrToBackgroundColor(currentState.attr));
(backend != null ?
backend.attrToBackgroundColor(currentState.attr) :
SwingTerminal.attrToBackgroundColor(currentState.attr)));
}
imageToCells(image, !doNotMoveCursor, maybeTransparent);
@ -8436,7 +8449,7 @@ public class ECMA48 implements Runnable {
textHeight, BufferedImage.TYPE_INT_ARGB);
BufferedImage textImage = glyphMaker.getImage(oldCell,
textWidth, textHeight);
textWidth, textHeight, backend);
java.awt.Graphics gr = newImage.getGraphics();
gr.setColor(java.awt.Color.BLACK);