X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Fbackend%2FLogicalScreen.java;h=22b7e95f6564aad97431ca2e60a2fec09e9d2365;hb=c4cefaa04ec122fc02efb6542451a31fdf722c32;hp=9af633dbac645be3198a27935590d6145143b9cc;hpb=97bc3f29f12d64d27d49b0d61947d15dfa64d156;p=fanfix.git diff --git a/src/jexer/backend/LogicalScreen.java b/src/jexer/backend/LogicalScreen.java index 9af633d..22b7e95 100644 --- a/src/jexer/backend/LogicalScreen.java +++ b/src/jexer/backend/LogicalScreen.java @@ -33,6 +33,7 @@ import java.awt.image.BufferedImage; import jexer.backend.GlyphMaker; import jexer.bits.Cell; import jexer.bits.CellAttributes; +import jexer.bits.Clipboard; import jexer.bits.GraphicsChars; import jexer.bits.StringUtils; @@ -369,7 +370,7 @@ public class LogicalScreen implements Screen { * @param ch character to draw * @param attr attributes to use (bold, foreColor, backColor) */ - public final void putAll(final char ch, final CellAttributes attr) { + public final void putAll(final int ch, final CellAttributes attr) { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { @@ -430,7 +431,7 @@ public class LogicalScreen implements Screen { * @param ch character to draw * @param attr attributes to use (bold, foreColor, backColor) */ - public final void putCharXY(final int x, final int y, final char ch, + public final void putCharXY(final int x, final int y, final int ch, final CellAttributes attr) { if ((x < clipLeft) @@ -476,8 +477,7 @@ public class LogicalScreen implements Screen { * @param y row coordinate. 0 is the top-most row. * @param ch character to draw */ - public final void putCharXY(final int x, final int y, final char ch) { - + public final void putCharXY(final int x, final int y, final int ch) { if ((x < clipLeft) || (x >= clipRight) || (y < clipTop) @@ -520,8 +520,9 @@ public class LogicalScreen implements Screen { final CellAttributes attr) { int i = x; - for (int j = 0; j < str.length(); j++) { - char ch = str.charAt(j); + for (int j = 0; j < str.length();) { + int ch = str.codePointAt(j); + j += Character.charCount(ch); putCharXY(i, y, ch, attr); i += StringUtils.width(ch); if (i == width) { @@ -541,8 +542,9 @@ public class LogicalScreen implements Screen { public final void putStringXY(final int x, final int y, final String str) { int i = x; - for (int j = 0; j < str.length(); j++) { - char ch = str.charAt(j); + for (int j = 0; j < str.length();) { + int ch = str.codePointAt(j); + j += Character.charCount(ch); putCharXY(i, y, ch); i += StringUtils.width(ch); if (i == width) { @@ -561,7 +563,7 @@ public class LogicalScreen implements Screen { * @param attr attributes to use (bold, foreColor, backColor) */ public final void vLineXY(final int x, final int y, final int n, - final char ch, final CellAttributes attr) { + final int ch, final CellAttributes attr) { for (int i = y; i < y + n; i++) { putCharXY(x, i, ch, attr); @@ -578,7 +580,7 @@ public class LogicalScreen implements Screen { * @param attr attributes to use (bold, foreColor, backColor) */ public final void hLineXY(final int x, final int y, final int n, - final char ch, final CellAttributes attr) { + final int ch, final CellAttributes attr) { for (int i = x; i < x + n; i++) { putCharXY(i, y, ch, attr); @@ -802,11 +804,30 @@ public class LogicalScreen implements Screen { clipBottom = height - offsetY; for (int i = 0; i < boxHeight; i++) { - putAttrXY(boxLeft + boxWidth, boxTop + 1 + i, shadowAttr); - putAttrXY(boxLeft + boxWidth + 1, boxTop + 1 + i, shadowAttr); + Cell cell = getCharXY(offsetX + boxLeft + boxWidth, + offsetY + boxTop + 1 + i); + if (cell.getWidth() == Cell.Width.SINGLE) { + putAttrXY(boxLeft + boxWidth, boxTop + 1 + i, shadowAttr); + } else { + putCharXY(boxLeft + boxWidth, boxTop + 1 + i, ' ', shadowAttr); + } + cell = getCharXY(offsetX + boxLeft + boxWidth + 1, + offsetY + boxTop + 1 + i); + if (cell.getWidth() == Cell.Width.SINGLE) { + putAttrXY(boxLeft + boxWidth + 1, boxTop + 1 + i, shadowAttr); + } else { + putCharXY(boxLeft + boxWidth + 1, boxTop + 1 + i, ' ', + shadowAttr); + } } for (int i = 0; i < boxWidth; i++) { - putAttrXY(boxLeft + 2 + i, boxTop + boxHeight, shadowAttr); + Cell cell = getCharXY(offsetX + boxLeft + 2 + i, + offsetY + boxTop + boxHeight); + if (cell.getWidth() == Cell.Width.SINGLE) { + putAttrXY(boxLeft + 2 + i, boxTop + boxHeight, shadowAttr); + } else { + putCharXY(boxLeft + 2 + i, boxTop + boxHeight, ' ', shadowAttr); + } } clipRight = oldClipRight; clipBottom = oldClipBottom; @@ -967,31 +988,28 @@ public class LogicalScreen implements Screen { public final void putFullwidthCharXY(final int x, final int y, final Cell cell) { - if (lastTextHeight != getTextHeight()) { - glyphMaker = GlyphMaker.getInstance(getTextHeight()); - lastTextHeight = getTextHeight(); + int cellWidth = getTextWidth(); + int cellHeight = getTextHeight(); + + if (lastTextHeight != cellHeight) { + glyphMaker = GlyphMaker.getInstance(cellHeight); + lastTextHeight = cellHeight; } - 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); + BufferedImage image = glyphMaker.getImage(cell, cellWidth * 2, + cellHeight); + BufferedImage leftImage = image.getSubimage(0, 0, cellWidth, + cellHeight); + BufferedImage rightImage = image.getSubimage(cellWidth, 0, cellWidth, + cellHeight); + + Cell left = new Cell(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); + Cell right = new Cell(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); } @@ -1004,10 +1022,9 @@ public class LogicalScreen implements Screen { * @param attr attributes to use (bold, foreColor, backColor) */ public final void putFullwidthCharXY(final int x, final int y, - final char ch, final CellAttributes attr) { + final int ch, final CellAttributes attr) { - Cell cell = new Cell(ch); - cell.setAttr(attr); + Cell cell = new Cell(ch, attr); putFullwidthCharXY(x, y, cell); } @@ -1019,11 +1036,191 @@ public class LogicalScreen implements Screen { * @param ch character to draw */ public final void putFullwidthCharXY(final int x, final int y, - final char ch) { + final int ch) { Cell cell = new Cell(ch); cell.setAttr(getAttrXY(x, y)); putFullwidthCharXY(x, y, cell); } + /** + * Invert the cell color at a position, including both halves of a + * double-width cell. + * + * @param x column position + * @param y row position + */ + public void invertCell(final int x, final int y) { + invertCell(x, y, false); + } + + /** + * Invert the cell color at a position. + * + * @param x column position + * @param y row position + * @param onlyThisCell if true, only invert this cell, otherwise invert + * both halves of a double-width cell if necessary + */ + public void invertCell(final int x, final int y, + final boolean onlyThisCell) { + + Cell cell = getCharXY(x, y); + if (cell.isImage()) { + cell.invertImage(); + } + if (cell.getForeColorRGB() < 0) { + cell.setForeColor(cell.getForeColor().invert()); + } else { + cell.setForeColorRGB(cell.getForeColorRGB() ^ 0x00ffffff); + } + if (cell.getBackColorRGB() < 0) { + cell.setBackColor(cell.getBackColor().invert()); + } else { + cell.setBackColorRGB(cell.getBackColorRGB() ^ 0x00ffffff); + } + 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 < width - 1) { + Cell rightHalf = getCharXY(x + 1, y); + if (rightHalf.getWidth() == Cell.Width.RIGHT) { + invertCell(x + 1, y, true); + return; + } + } + } + if (cell.getWidth() == Cell.Width.RIGHT) { + if (x > 0) { + Cell leftHalf = getCharXY(x - 1, y); + if (leftHalf.getWidth() == Cell.Width.LEFT) { + invertCell(x - 1, y, true); + } + } + } + } + + /** + * Set a selection area on the screen. + * + * @param x0 the starting X position of the selection + * @param y0 the starting Y position of the selection + * @param x1 the ending X position of the selection + * @param y1 the ending Y position of the selection + * @param rectangle if true, this is a rectangle select + */ + public void setSelection(final int x0, final int y0, + final int x1, final int y1, final boolean rectangle) { + + int startX = x0; + int startY = y0; + int endX = x1; + int endY = y1; + + if (((x1 < x0) && (y1 == y0)) + || (y1 < y0) + ) { + // The user dragged from bottom-to-top and/or right-to-left. + // Reverse the coordinates for the inverted section. + startX = x1; + startY = y1; + endX = x0; + endY = y0; + } + if (rectangle) { + for (int y = startY; y <= endY; y++) { + for (int x = startX; x <= endX; x++) { + invertCell(x, y); + } + } + } else { + if (endY > startY) { + for (int x = startX; x < width; x++) { + invertCell(x, startY); + } + for (int y = startY + 1; y < endY; y++) { + for (int x = 0; x < width; x++) { + invertCell(x, y); + } + } + for (int x = 0; x <= endX; x++) { + invertCell(x, endY); + } + } else { + assert (startY == endY); + for (int x = startX; x <= endX; x++) { + invertCell(x, startY); + } + } + } + } + + /** + * Copy the screen selection area to the clipboard. + * + * @param clipboard the clipboard to use + * @param x0 the starting X position of the selection + * @param y0 the starting Y position of the selection + * @param x1 the ending X position of the selection + * @param y1 the ending Y position of the selection + * @param rectangle if true, this is a rectangle select + */ + public void copySelection(final Clipboard clipboard, + final int x0, final int y0, final int x1, final int y1, + final boolean rectangle) { + + StringBuilder sb = new StringBuilder(); + + int startX = x0; + int startY = y0; + int endX = x1; + int endY = y1; + + if (((x1 < x0) && (y1 == y0)) + || (y1 < y0) + ) { + // The user dragged from bottom-to-top and/or right-to-left. + // Reverse the coordinates for the inverted section. + startX = x1; + startY = y1; + endX = x0; + endY = y0; + } + if (rectangle) { + for (int y = startY; y <= endY; y++) { + for (int x = startX; x <= endX; x++) { + sb.append(Character.toChars(getCharXY(x, y).getChar())); + } + sb.append("\n"); + } + } else { + if (endY > startY) { + for (int x = startX; x < width; x++) { + sb.append(Character.toChars(getCharXY(x, startY).getChar())); + } + sb.append("\n"); + for (int y = startY + 1; y < endY; y++) { + for (int x = 0; x < width; x++) { + sb.append(Character.toChars(getCharXY(x, y).getChar())); + } + sb.append("\n"); + } + for (int x = 0; x <= endX; x++) { + sb.append(Character.toChars(getCharXY(x, endY).getChar())); + } + } else { + assert (startY == endY); + for (int x = startX; x <= endX; x++) { + sb.append(Character.toChars(getCharXY(x, startY).getChar())); + } + } + } + clipboard.copyText(sb.toString()); + } + }