mirror of
https://gitlab.com/AutumnMeowMeow/jexer
synced 2024-09-19 11:50:19 -06:00
#83 eliminate empty image cells
This commit is contained in:
parent
4e3a73bb67
commit
6c7628b01d
8 changed files with 310 additions and 77 deletions
|
@ -2262,33 +2262,57 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
BufferedImage textImage;
|
||||
|
||||
if (logical[x + i][y].isTransparentImage()) {
|
||||
// We should only see transparent cells at this layer if
|
||||
// backend transparency was enabled.
|
||||
assert (imagesOverText == true);
|
||||
// We would normally only see transparent cells at
|
||||
// this layer if backend transparency was enabled.
|
||||
// But in the case of multihead, we may have been
|
||||
// passed a cell with transparency even though this
|
||||
// backend can't display it. So we will check, and
|
||||
// if imagesOverText is disabled then we will quietly
|
||||
// continue on. Otherwise render a text character
|
||||
// under the image.
|
||||
if (imagesOverText == true) {
|
||||
// Render this cell to a flat image. The bad
|
||||
// news is that we don't get to use the actual
|
||||
// terminal's font, because putting image data
|
||||
// over text is really iffy depending on
|
||||
// terminal. So we render it here instead.
|
||||
BufferedImage image = logical[x + i][y].getImage();
|
||||
int textWidth = image.getWidth();
|
||||
int textHeight = image.getHeight();
|
||||
if (glyphMaker == null) {
|
||||
glyphMaker = GlyphMaker.getInstance(textHeight);
|
||||
}
|
||||
newImage = new BufferedImage(textWidth,
|
||||
textHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
textImage = glyphMaker.getImage(logical[x + i][y],
|
||||
textWidth, textHeight);
|
||||
|
||||
// Render this cell to a flat image. The bad news is
|
||||
// that we don't get to use the actual terminal's
|
||||
// font, because putting image data over text is
|
||||
// really iffy depending on terminal. So we render
|
||||
// it here instead.
|
||||
BufferedImage image = logical[x + i][y].getImage();
|
||||
int textWidth = image.getWidth();
|
||||
int textHeight = image.getHeight();
|
||||
if (glyphMaker == null) {
|
||||
glyphMaker = GlyphMaker.getInstance(textHeight);
|
||||
java.awt.Graphics gr = newImage.getGraphics();
|
||||
gr.setColor(jexer.backend.SwingTerminal.
|
||||
attrToBackgroundColor(logical[x + i][y]));
|
||||
gr.drawImage(textImage, 0, 0, null, null);
|
||||
gr.drawImage(logical[x + i][y].getImage(), 0, 0,
|
||||
null, null);
|
||||
gr.dispose();
|
||||
logical[x + i][y].setImage(newImage);
|
||||
} else {
|
||||
// Put the cell's background color behind the
|
||||
// pixels.
|
||||
BufferedImage image = logical[x + i][y].getImage();
|
||||
int textWidth = image.getWidth();
|
||||
int textHeight = image.getHeight();
|
||||
newImage = new BufferedImage(textWidth,
|
||||
textHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
java.awt.Graphics gr = newImage.getGraphics();
|
||||
gr.setColor(jexer.backend.SwingTerminal.
|
||||
attrToBackgroundColor(logical[x + i][y]));
|
||||
gr.fillRect(0, 0, newImage.getWidth(),
|
||||
newImage.getHeight());
|
||||
gr.drawImage(logical[x + i][y].getImage(), 0, 0,
|
||||
null, null);
|
||||
gr.dispose();
|
||||
logical[x + i][y].setImage(newImage);
|
||||
}
|
||||
newImage = new BufferedImage(textWidth,
|
||||
textHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
textImage = glyphMaker.getImage(logical[x + i][y],
|
||||
textWidth, textHeight);
|
||||
|
||||
java.awt.Graphics gr = newImage.getGraphics();
|
||||
gr.setColor(java.awt.Color.BLACK);
|
||||
gr.drawImage(textImage, 0, 0, null, null);
|
||||
gr.drawImage(logical[x + i][y].getImage(), 0, 0,
|
||||
null, null);
|
||||
gr.dispose();
|
||||
logical[x + i][y].setImage(newImage);
|
||||
}
|
||||
assert (!logical[x + i][y].isTransparentImage());
|
||||
cellsToDraw.add(logical[x + i][y]);
|
||||
|
|
|
@ -1432,13 +1432,15 @@ public class SwingTerminal extends LogicalScreen
|
|||
if ((SwingComponent.tripleBuffer) && (swing.getFrame() != null)) {
|
||||
gr2.dispose();
|
||||
|
||||
// We need a new key that will not be mutated by
|
||||
// invertCell().
|
||||
Cell key = new Cell(cell);
|
||||
if (cell.isBlink() && !cursorBlinkVisible) {
|
||||
glyphCacheBlink.put(key, image);
|
||||
} else {
|
||||
glyphCache.put(key, image);
|
||||
if (!cell.isImage()) {
|
||||
// We need a new key that will not be mutated by
|
||||
// invertCell().
|
||||
Cell key = new Cell(cell);
|
||||
if (cell.isBlink() && !cursorBlinkVisible) {
|
||||
glyphCacheBlink.put(key, image);
|
||||
} else {
|
||||
glyphCache.put(key, image);
|
||||
}
|
||||
}
|
||||
|
||||
if (swing.getFrame() != null) {
|
||||
|
|
|
@ -111,7 +111,8 @@ public class Cell extends CellAttributes {
|
|||
* If this cell has image data, whether or not it also has transparent
|
||||
* pixels. -1 = no image data; 0 = unknown if transparent pixels are
|
||||
* present; 1 = transparent pixels are present; 2 = transparent pixels
|
||||
* are not present.
|
||||
* are not present; 3 = the entire image is transparent; 4 = transparent
|
||||
* pixels are present, but not all of the image.
|
||||
*/
|
||||
private int hasTransparentPixels = -1;
|
||||
|
||||
|
@ -203,7 +204,7 @@ public class Cell extends CellAttributes {
|
|||
* @param cell the other cell
|
||||
*/
|
||||
public void blitImage(final Cell cell) {
|
||||
if (!cell.isImage()) {
|
||||
if (!cell.isImage() || cell.isFullyTransparentImage()) {
|
||||
// The other cell has no image data.
|
||||
return;
|
||||
}
|
||||
|
@ -280,10 +281,67 @@ public class Cell extends CellAttributes {
|
|||
// No transparent pixels.
|
||||
hasTransparentPixels = 2;
|
||||
}
|
||||
if (hasTransparentPixels == 1) {
|
||||
if ((hasTransparentPixels == 1)
|
||||
|| (hasTransparentPixels == 3)
|
||||
|| (hasTransparentPixels == 4)
|
||||
) {
|
||||
// Transparent pixels were found at some time.
|
||||
return true;
|
||||
}
|
||||
assert (hasTransparentPixels == 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, this cell has image data and all of its pixels are fully
|
||||
* transparent (alpha of 0).
|
||||
*
|
||||
* @return true if this cell has image data with only transparent pixels
|
||||
*/
|
||||
public boolean isFullyTransparentImage() {
|
||||
if (image == null) {
|
||||
return false;
|
||||
}
|
||||
if ((hasTransparentPixels == 0) || (hasTransparentPixels == 1)) {
|
||||
// Scan for transparent pixels. Only if ALL pixels are
|
||||
// transparent do we return true.
|
||||
int [] rgbArray = image.getRGB(0, 0,
|
||||
image.getWidth(), image.getHeight(), null, 0, image.getWidth());
|
||||
|
||||
if (rgbArray.length == 0) {
|
||||
// No image data, fully transparent.
|
||||
hasTransparentPixels = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean allOpaque = true;
|
||||
boolean allTransparent = true;
|
||||
for (int i = 0; i < rgbArray.length; i++) {
|
||||
int alpha = (rgbArray[i] >>> 24) & 0xFF;
|
||||
if ((alpha != 0xFF) && (alpha != 0x00)) {
|
||||
// Some transparent pixels, but not fully transparent.
|
||||
hasTransparentPixels = 4;
|
||||
return false;
|
||||
}
|
||||
// This pixel is either fully opaque or fully transparent.
|
||||
if (alpha == 0xFF) {
|
||||
allTransparent = false;
|
||||
} else {
|
||||
allOpaque = false;
|
||||
}
|
||||
}
|
||||
if (allOpaque == true) {
|
||||
// No transparent pixels.
|
||||
hasTransparentPixels = 2;
|
||||
} else {
|
||||
assert (allTransparent == true);
|
||||
hasTransparentPixels = 3;
|
||||
}
|
||||
}
|
||||
if (hasTransparentPixels == 3) {
|
||||
// Fully transparent.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
68
src/jexer/bits/ImageUtils.java
Normal file
68
src/jexer/bits/ImageUtils.java
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Jexer - Java Text User Interface
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (C) 2021 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 [AutumnWalksTheLake@gmail.com] ⚧ Trans Liberation Now
|
||||
* @version 1
|
||||
*/
|
||||
package jexer.bits;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* ImageUtils contains methods to:
|
||||
*
|
||||
* - Check if an image is fully transparent.
|
||||
*
|
||||
*/
|
||||
public class ImageUtils {
|
||||
|
||||
/**
|
||||
* Check if any pixels in an image have not-100% alpha value.
|
||||
*
|
||||
* @return true if every pixel is fully transparent
|
||||
*/
|
||||
public static boolean isFullyTransparent(final BufferedImage image) {
|
||||
assert (image != null);
|
||||
|
||||
int [] rgbArray = image.getRGB(0, 0,
|
||||
image.getWidth(), image.getHeight(), null, 0, image.getWidth());
|
||||
|
||||
if (rgbArray.length == 0) {
|
||||
// No image data, fully transparent.
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rgbArray.length; i++) {
|
||||
int alpha = (rgbArray[i] >>> 24) & 0xFF;
|
||||
if (alpha != 0x00) {
|
||||
// A not-fully transparent pixel is found.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Every pixel was transparent.
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -402,7 +402,8 @@ public class DemoMainWindow extends TWindow {
|
|||
|
||||
// For this one, render to the entire screen, not to the window.
|
||||
getScreen().resetClipping();
|
||||
tackboard.draw(getScreen());
|
||||
tackboard.draw(getScreen(),
|
||||
getApplication().getBackend().isImagesOverText());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,6 +36,7 @@ import java.util.List;
|
|||
import jexer.backend.GlyphMaker;
|
||||
import jexer.backend.Screen;
|
||||
import jexer.bits.Cell;
|
||||
import jexer.bits.ImageUtils;
|
||||
|
||||
/**
|
||||
* Tackboard maintains a collection of TackboardItems to draw on a Screen.
|
||||
|
@ -72,6 +73,16 @@ public class Tackboard {
|
|||
*/
|
||||
private ArrayList<TackboardItem> items = new ArrayList<TackboardItem>();
|
||||
|
||||
/**
|
||||
* Last text width value.
|
||||
*/
|
||||
private int lastTextWidth = -1;
|
||||
|
||||
/**
|
||||
* Last text height value.
|
||||
*/
|
||||
private int lastTextHeight = -1;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -109,13 +120,30 @@ public class Tackboard {
|
|||
* Draw everything to the screen.
|
||||
*
|
||||
* @param screen the screen to render to
|
||||
* @param transparent if true, allow partially transparent images to be
|
||||
* drawn to the screen
|
||||
*/
|
||||
public void draw(final Screen screen) {
|
||||
public void draw(final Screen screen, final boolean transparent) {
|
||||
Collections.sort(items);
|
||||
int cellWidth = screen.getTextWidth();
|
||||
int cellHeight = screen.getTextHeight();
|
||||
boolean redraw = false;
|
||||
|
||||
if ((lastTextWidth == -1)
|
||||
|| (lastTextWidth != cellWidth)
|
||||
|| (lastTextHeight != cellHeight)
|
||||
) {
|
||||
// We need to force a redraw because the cell grid dimensions
|
||||
// have changed.
|
||||
redraw = true;
|
||||
lastTextWidth = cellWidth;
|
||||
lastTextHeight = cellHeight;
|
||||
}
|
||||
|
||||
for (TackboardItem item: items) {
|
||||
if (redraw) {
|
||||
item.setDirty();
|
||||
}
|
||||
BufferedImage image = item.getImage(cellWidth, cellHeight);
|
||||
if (image == null) {
|
||||
continue;
|
||||
|
@ -128,8 +156,20 @@ public class Tackboard {
|
|||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
|
||||
assert (width % cellWidth == 0);
|
||||
assert (height % cellHeight == 0);
|
||||
if ((width % cellWidth != 0) || (height % cellHeight != 0)) {
|
||||
// These should have lined up, that was the whole point of
|
||||
// the redraw. Why didn't they?
|
||||
/*
|
||||
System.err.println("HUH? width " + width +
|
||||
" cellWidth " + cellWidth +
|
||||
" height " + height +
|
||||
" cellHeight " + cellHeight);
|
||||
*/
|
||||
} else {
|
||||
// This should be impossible, right?
|
||||
assert (width % cellWidth == 0);
|
||||
assert (height % cellHeight == 0);
|
||||
}
|
||||
|
||||
int columns = width / cellWidth;
|
||||
int rows = height / cellHeight;
|
||||
|
@ -148,9 +188,8 @@ public class Tackboard {
|
|||
int dx = x % cellWidth;
|
||||
int dy = y % cellHeight;
|
||||
|
||||
// TODO: handle images that have negative X or Y coordinates.
|
||||
int left = 0;
|
||||
int top = 0;
|
||||
int left = (x < 0 ? -1 : 0);
|
||||
int top = (y < 0 ? -1 : 0);
|
||||
|
||||
for (int sy = 0; sy < rows; sy++) {
|
||||
if ((sy + textY + top < 0)
|
||||
|
@ -177,6 +216,11 @@ public class Tackboard {
|
|||
newImage = image.getSubimage(sx * cellWidth,
|
||||
sy * cellHeight, cellWidth, cellHeight);
|
||||
|
||||
if (ImageUtils.isFullyTransparent(newImage)) {
|
||||
// Skip this cell.
|
||||
continue;
|
||||
}
|
||||
|
||||
// newImage has the image that needs to be overlaid on
|
||||
// (sx + textX + left, sy + textY + top)
|
||||
|
||||
|
@ -186,13 +230,28 @@ public class Tackboard {
|
|||
// Blit this image over that one.
|
||||
BufferedImage oldImage = oldCell.getImage();
|
||||
java.awt.Graphics gr = oldImage.getGraphics();
|
||||
gr.setColor(java.awt.Color.BLACK);
|
||||
gr.setColor(jexer.backend.SwingTerminal.
|
||||
attrToBackgroundColor(oldCell));
|
||||
gr.drawImage(newImage, 0, 0, null, null);
|
||||
gr.dispose();
|
||||
oldCell.setImage(oldImage);
|
||||
} else {
|
||||
// Old cell is text only, just add the image.
|
||||
oldCell.setImage(newImage);
|
||||
if (!transparent) {
|
||||
BufferedImage backImage;
|
||||
backImage = new BufferedImage(cellWidth,
|
||||
cellHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
java.awt.Graphics gr = backImage.getGraphics();
|
||||
gr.setColor(jexer.backend.SwingTerminal.
|
||||
attrToBackgroundColor(oldCell));
|
||||
gr.fillRect(0, 0, backImage.getWidth(),
|
||||
backImage.getHeight());
|
||||
gr.drawImage(newImage, 0, 0, null, null);
|
||||
gr.dispose();
|
||||
oldCell.setImage(backImage);
|
||||
} else {
|
||||
oldCell.setImage(newImage);
|
||||
}
|
||||
}
|
||||
screen.putCharXY(sx + textX + left, sy + textY + top,
|
||||
oldCell);
|
||||
|
|
|
@ -160,6 +160,13 @@ public class TackboardItem implements Comparable<TackboardItem> {
|
|||
return dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set dirty flag.
|
||||
*/
|
||||
public final void setDirty() {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison check. All fields must match to return true.
|
||||
*
|
||||
|
|
|
@ -56,6 +56,7 @@ import jexer.backend.GlyphMaker;
|
|||
import jexer.bits.Color;
|
||||
import jexer.bits.Cell;
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.ImageUtils;
|
||||
import jexer.bits.StringUtils;
|
||||
import jexer.event.TInputEvent;
|
||||
import jexer.event.TKeypressEvent;
|
||||
|
@ -7505,7 +7506,13 @@ public class ECMA48 implements Runnable {
|
|||
*/
|
||||
|
||||
boolean maybeTransparent = false;
|
||||
if ((backend != null) && backend.isImagesOverText()) {
|
||||
// The check below is forced to always enable maybeTransparent. Even
|
||||
// when imagesOverText is disabled, we can still process sixel images
|
||||
// with missing pixels by way of checking for entirely empty text
|
||||
// cell regions and removing them. The effect is to have a blocky
|
||||
// black outline around the image rather than an entire black
|
||||
// rectangle.
|
||||
if (true || ((backend != null) && backend.isImagesOverText())) {
|
||||
maybeTransparent = true;
|
||||
}
|
||||
Sixel sixel = new Sixel(sixelParseBuffer.toString(), sixelPalette,
|
||||
|
@ -7721,6 +7728,7 @@ public class ECMA48 implements Runnable {
|
|||
// If the backend supports transparent images, then we will not
|
||||
// draw the black underneath the cells.
|
||||
boolean transparent = false;
|
||||
|
||||
if ((backend != null) && backend.isImagesOverText()) {
|
||||
transparent = true;
|
||||
}
|
||||
|
@ -7734,7 +7742,9 @@ public class ECMA48 implements Runnable {
|
|||
cellRows++;
|
||||
}
|
||||
|
||||
if (!transparent && maybeTransparent) {
|
||||
// See the comment in parseSixel(). The partially-transparent cell
|
||||
// will be rendered over a black background below inside the loop.
|
||||
if (false && !transparent && maybeTransparent) {
|
||||
// Re-render the image against a black background, so that alpha
|
||||
// in the image does not lead to bleed-through artifacts.
|
||||
BufferedImage newImage;
|
||||
|
@ -7753,8 +7763,6 @@ public class ECMA48 implements Runnable {
|
|||
Cell [][] cells = new Cell[cellColumns][cellRows];
|
||||
for (int x = 0; x < cellColumns; x++) {
|
||||
for (int y = 0; y < cellRows; y++) {
|
||||
Cell cell = new Cell();
|
||||
|
||||
int width = textWidth;
|
||||
if ((x + 1) * textWidth > image.getWidth()) {
|
||||
width = image.getWidth() - (x * textWidth);
|
||||
|
@ -7765,13 +7773,20 @@ public class ECMA48 implements Runnable {
|
|||
}
|
||||
|
||||
// I'm genuinely not sure if making many small cells with
|
||||
// array copy is better than slicing. Memory pressure is
|
||||
// killing it at high animation rates. Leaving the true in
|
||||
// the check below will use the smaller cells rather than
|
||||
// subImages.
|
||||
if (true || (width != textWidth) || (height != textHeight)) {
|
||||
// Copy the smaller-than-text-cell-size image to a
|
||||
// full-text-cell-size.
|
||||
// array copy is better than lots of sumImages. Memory
|
||||
// pressure is killing it at high animation rates. For now,
|
||||
// we will ALWAYS make a copy.
|
||||
Cell cell = new Cell();
|
||||
|
||||
BufferedImage imageSlice = image.getSubimage(x * textWidth,
|
||||
y * textHeight, width, height);
|
||||
|
||||
if (ImageUtils.isFullyTransparent(imageSlice)) {
|
||||
// There is nothing more to do, this entire image is
|
||||
// empty.
|
||||
|
||||
// NOP
|
||||
} else {
|
||||
BufferedImage newImage;
|
||||
newImage = new BufferedImage(textWidth, textHeight,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
|
@ -7781,29 +7796,26 @@ public class ECMA48 implements Runnable {
|
|||
gr.fillRect(0, 0, newImage.getWidth(),
|
||||
newImage.getHeight());
|
||||
}
|
||||
gr.drawImage(image.getSubimage(x * textWidth,
|
||||
y * textHeight, width, height),
|
||||
0, 0, null, null);
|
||||
gr.drawImage(imageSlice, 0, 0, null, null);
|
||||
gr.dispose();
|
||||
cell.setImage(newImage);
|
||||
} else {
|
||||
cell.setImage(image.getSubimage(x * textWidth,
|
||||
y * textHeight, width, height));
|
||||
}
|
||||
if (transparent && maybeTransparent) {
|
||||
// Check now if this cell has transparent pixels. This
|
||||
// will slow down the reader thread but unload the render
|
||||
// thread.
|
||||
//
|
||||
// Truth is performance is going to be bad for a while...
|
||||
cell.isTransparentImage();
|
||||
} else if (transparent && !maybeTransparent) {
|
||||
// We support transparency, but this image doesn't have
|
||||
// any transparent pixels. Force the cell to never check
|
||||
// transparency.
|
||||
cell.setOpaqueImage();
|
||||
}
|
||||
|
||||
cell.setImage(newImage);
|
||||
|
||||
if (maybeTransparent) {
|
||||
// Check now if this cell has transparent pixels.
|
||||
// This will slow down the reader thread but unload
|
||||
// the render thread.
|
||||
//
|
||||
// Truth is performance is going to be bad for a
|
||||
// while...
|
||||
cell.isTransparentImage();
|
||||
} else {
|
||||
// We support transparency, but this image doesn't
|
||||
// have any transparent pixels. Force the cell to
|
||||
// never check transparency.
|
||||
cell.setOpaqueImage();
|
||||
}
|
||||
}
|
||||
cells[x][y] = cell;
|
||||
}
|
||||
}
|
||||
|
@ -7865,7 +7877,9 @@ public class ECMA48 implements Runnable {
|
|||
cells[x][y].isTransparentImage();
|
||||
}
|
||||
}
|
||||
line.replace(currentState.cursorX, cells[x][y]);
|
||||
if (cells[x][y].isImage()) {
|
||||
line.replace(currentState.cursorX, cells[x][y]);
|
||||
}
|
||||
|
||||
// If at the end of the visible screen, stop.
|
||||
if (currentState.cursorX == rightMargin) {
|
||||
|
|
Loading…
Reference in a new issue