From: Kevin Lamonte Date: Tue, 6 Aug 2019 12:00:45 +0000 (-0500) Subject: #35 CJK WIP X-Git-Url: https://git.nikiroo.be/?a=commitdiff_plain;h=3af53a35f41caa36050a69d39a8ec40be92e7aca;p=nikiroo-utils.git #35 CJK WIP --- diff --git a/src/jexer/TApplication.java b/src/jexer/TApplication.java index b44664e..4428d29 100644 --- a/src/jexer/TApplication.java +++ b/src/jexer/TApplication.java @@ -1534,6 +1534,19 @@ public class TApplication implements Runnable { * @param y row position */ private void invertCell(final int x, final int y) { + invertCell(x, y, false); + } + + /** + * Invert the cell color at a position. This is used to track the mouse. + * + * @param x column position + * @param y row position + * @param onlyThisCell if true, only invert this cell + */ + private void invertCell(final int x, final int y, + final boolean onlyThisCell) { + if (debugThreads) { System.err.printf("%d %s invertCell() %d %d\n", System.currentTimeMillis(), Thread.currentThread(), x, y); @@ -1573,6 +1586,29 @@ public class TApplication implements Runnable { } } getScreen().putCharXY(x, y, cell); + if ((onlyThisCell == true) || (cell.getWidth() == Cell.Width.SINGLE)) { + return; + } + + // This cell is one half of a fullwidth glyph. Invert the other + // half. + if (cell.getWidth() == Cell.Width.LEFT) { + if (x < getScreen().getWidth() - 1) { + Cell rightHalf = getScreen().getCharXY(x + 1, y); + if (rightHalf.getWidth() == Cell.Width.RIGHT) { + invertCell(x + 1, y, true); + return; + } + } + } + assert (cell.getWidth() == Cell.Width.RIGHT); + + if (x > 0) { + Cell leftHalf = getScreen().getCharXY(x - 1, y); + if (leftHalf.getWidth() == Cell.Width.LEFT) { + invertCell(x - 1, y, true); + } + } } /** diff --git a/src/jexer/TButton.java b/src/jexer/TButton.java index 33fe733..534c12a 100644 --- a/src/jexer/TButton.java +++ b/src/jexer/TButton.java @@ -32,6 +32,7 @@ import jexer.bits.CellAttributes; import jexer.bits.Color; import jexer.bits.GraphicsChars; import jexer.bits.MnemonicString; +import jexer.bits.StringUtils; import jexer.event.TKeypressEvent; import jexer.event.TMouseEvent; import static jexer.TKeypress.kbEnter; @@ -98,7 +99,7 @@ public class TButton extends TWidget { setX(x); setY(y); setHeight(2); - setWidth(mnemonic.getRawLabel().length() + 3); + setWidth(StringUtils.width(mnemonic.getRawLabel()) + 3); shadowColor = new CellAttributes(); shadowColor.setTo(getWindow().getBackground()); diff --git a/src/jexer/backend/ECMA48Terminal.java b/src/jexer/backend/ECMA48Terminal.java index 39ca236..e22e4fe 100644 --- a/src/jexer/backend/ECMA48Terminal.java +++ b/src/jexer/backend/ECMA48Terminal.java @@ -2851,7 +2851,9 @@ public class ECMA48Terminal extends LogicalScreen int [] rgbArray; for (int i = 0; i < cells.size() - 1; i++) { - if (cells.get(i).isInvertedImage()) { + if (false && cells.get(i).isInvertedImage()) { + // I used to put an all-white cell over the cursor, don't do + // that anymore. rgbArray = new int[imageWidth * imageHeight]; for (int j = 0; j < rgbArray.length; j++) { rgbArray[j] = 0xFFFFFF; @@ -2883,7 +2885,9 @@ public class ECMA48Terminal extends LogicalScreen } } totalWidth -= ((cells.size() - 1) * imageWidth); - if (cells.get(cells.size() - 1).isInvertedImage()) { + if (false && cells.get(cells.size() - 1).isInvertedImage()) { + // I used to put an all-white cell over the cursor, don't do that + // anymore. rgbArray = new int[totalWidth * imageHeight]; for (int j = 0; j < rgbArray.length; j++) { rgbArray[j] = 0xFFFFFF; diff --git a/src/jexer/backend/LogicalScreen.java b/src/jexer/backend/LogicalScreen.java index 513c599..3149e68 100644 --- a/src/jexer/backend/LogicalScreen.java +++ b/src/jexer/backend/LogicalScreen.java @@ -28,9 +28,13 @@ */ package jexer.backend; +import java.awt.image.BufferedImage; + +import jexer.backend.GlyphMaker; import jexer.bits.Cell; import jexer.bits.CellAttributes; import jexer.bits.GraphicsChars; +import jexer.bits.StringUtils; /** * A logical screen composed of a 2D array of Cells. @@ -113,6 +117,17 @@ public class LogicalScreen implements Screen { */ protected int cursorY; + /** + * The last used height of a character cell in pixels, only used for + * full-width chars. + */ + private int lastTextHeight = -1; + + /** + * The glyph drawer for full-width chars. + */ + private GlyphMaker glyphMaker = null; + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ @@ -379,6 +394,11 @@ public class LogicalScreen implements Screen { return; } + if ((StringUtils.width(ch.getChar()) == 2) && (!ch.isImage())) { + putFullwidthCharXY(x, y, ch); + return; + } + int X = x + offsetX; int Y = y + offsetY; @@ -421,6 +441,11 @@ public class LogicalScreen implements Screen { return; } + if (StringUtils.width(ch) == 2) { + putFullwidthCharXY(x, y, ch, attr); + return; + } + int X = x + offsetX; int Y = y + offsetY; @@ -461,6 +486,11 @@ public class LogicalScreen implements Screen { return; } + if (StringUtils.width(ch) == 2) { + putFullwidthCharXY(x, y, ch); + return; + } + int X = x + offsetX; int Y = y + offsetY; @@ -927,4 +957,73 @@ public class LogicalScreen implements Screen { } } + /** + * Render one fullwidth cell. + * + * @param x column coordinate. 0 is the left-most column. + * @param y row coordinate. 0 is the top-most row. + * @param cell the cell to draw + */ + public final void putFullwidthCharXY(final int x, final int y, + final Cell cell) { + + if (lastTextHeight != getTextHeight()) { + glyphMaker = GlyphMaker.getInstance(getTextHeight()); + lastTextHeight = getTextHeight(); + } + BufferedImage image = glyphMaker.getImage(cell, getTextWidth() * 2, + getTextHeight()); + BufferedImage leftImage = image.getSubimage(0, 0, getTextWidth(), + getTextHeight()); + BufferedImage rightImage = image.getSubimage(getTextWidth(), 0, + getTextWidth(), getTextHeight()); + + Cell left = new Cell(); + left.setTo(cell); + left.setImage(leftImage); + left.setWidth(Cell.Width.LEFT); + // Blank out the char itself, so that shadows do not leave artifacts. + left.setChar(' '); + putCharXY(x, y, left); + + Cell right = new Cell(); + right.setTo(cell); + right.setImage(rightImage); + right.setWidth(Cell.Width.RIGHT); + // Blank out the char itself, so that shadows do not leave artifacts. + right.setChar(' '); + putCharXY(x + 1, y, right); + } + + /** + * Render one fullwidth character with attributes. + * + * @param x column coordinate. 0 is the left-most column. + * @param y row coordinate. 0 is the top-most row. + * @param ch character to draw + * @param attr attributes to use (bold, foreColor, backColor) + */ + public final void putFullwidthCharXY(final int x, final int y, + final char ch, final CellAttributes attr) { + + Cell cell = new Cell(ch); + cell.setAttr(attr); + putFullwidthCharXY(x, y, cell); + } + + /** + * Render one fullwidth character with attributes. + * + * @param x column coordinate. 0 is the left-most column. + * @param y row coordinate. 0 is the top-most row. + * @param ch character to draw + */ + public final void putFullwidthCharXY(final int x, final int y, + final char ch) { + + Cell cell = new Cell(ch); + cell.setAttr(getAttrXY(x, y)); + putFullwidthCharXY(x, y, cell); + } + } diff --git a/src/jexer/tterminal/ECMA48.java b/src/jexer/tterminal/ECMA48.java index f00164b..f9c9866 100644 --- a/src/jexer/tterminal/ECMA48.java +++ b/src/jexer/tterminal/ECMA48.java @@ -488,7 +488,7 @@ public class ECMA48 implements Runnable { /** * The glyph drawer for full-width chars. */ - GlyphMaker glyphMaker = null; + private GlyphMaker glyphMaker = null; /** * DECSC/DECRC save/restore a subset of the total state. This class