+ /**
+ * Draw glyphs for a double-width or double-height VT100 cell to two
+ * screen cells.
+ *
+ * @param line the line this VT100 cell is in
+ * @param x the X position to draw the left half to
+ * @param y the Y position to draw to
+ * @param cell the cell to draw
+ */
+ private void putDoubleWidthCharXY(final DisplayLine line, final int x,
+ final int y, final Cell cell) {
+
+ int textWidth = getScreen().getTextWidth();
+ int textHeight = getScreen().getTextHeight();
+ boolean cursorBlinkVisible = true;
+
+ if (getScreen() instanceof SwingTerminal) {
+ SwingTerminal terminal = (SwingTerminal) getScreen();
+ cursorBlinkVisible = terminal.getCursorBlinkVisible();
+ } else if (getScreen() instanceof ECMA48Terminal) {
+ ECMA48Terminal terminal = (ECMA48Terminal) getScreen();
+
+ if (!terminal.hasSixel()) {
+ // The backend does not have sixel support, draw this as text
+ // and bail out.
+ putCharXY(x, y, cell);
+ putCharXY(x + 1, y, ' ', cell);
+ return;
+ }
+ cursorBlinkVisible = blinkState;
+ } 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)) {
+ // Screen size has changed, reset the font.
+ setupFont(textHeight);
+ lastTextWidth = textWidth;
+ lastTextHeight = textHeight;
+ }
+ assert (doubleFont != null);
+
+ BufferedImage image;
+ if (line.getDoubleHeight() == 1) {
+ // Double-height top half: don't draw the underline.
+ Cell newCell = new Cell();
+ newCell.setTo(cell);
+ newCell.setUnderline(false);
+ image = doubleFont.getImage(newCell, textWidth * 2, textHeight * 2,
+ cursorBlinkVisible);
+ } else {
+ image = doubleFont.getImage(cell, textWidth * 2, textHeight * 2,
+ cursorBlinkVisible);
+ }
+
+ // Now that we have the double-wide glyph drawn, copy the right
+ // pieces of it to the cells.
+ Cell left = new Cell();
+ Cell right = new Cell();
+ left.setTo(cell);
+ right.setTo(cell);
+ right.setChar(' ');
+ BufferedImage leftImage = null;
+ BufferedImage rightImage = null;
+ /*
+ System.err.println("image " + image + " textWidth " + textWidth +
+ " textHeight " + textHeight);
+ */
+
+ switch (line.getDoubleHeight()) {
+ case 1:
+ // Top half double height
+ leftImage = image.getSubimage(0, 0, textWidth, textHeight);
+ rightImage = image.getSubimage(textWidth, 0, textWidth, textHeight);
+ break;
+ case 2:
+ // Bottom half double height
+ leftImage = image.getSubimage(0, textHeight, textWidth, textHeight);
+ rightImage = image.getSubimage(textWidth, textHeight,
+ textWidth, textHeight);
+ break;
+ default:
+ // Either single height double-width, or error fallback
+ BufferedImage wideImage = new BufferedImage(textWidth * 2,
+ textHeight, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D grWide = wideImage.createGraphics();
+ grWide.drawImage(image, 0, 0, wideImage.getWidth(),
+ wideImage.getHeight(), null);
+ grWide.dispose();
+ leftImage = wideImage.getSubimage(0, 0, textWidth, textHeight);
+ rightImage = wideImage.getSubimage(textWidth, 0, textWidth,
+ textHeight);
+ break;
+ }
+ left.setImage(leftImage);
+ right.setImage(rightImage);
+ // Since we have image data, ditch the character here. Otherwise, a
+ // drawBoxShadow() over the terminal window will show the characters
+ // which looks wrong.
+ left.setChar(' ');
+ right.setChar(' ');
+ putCharXY(x, y, left);
+ putCharXY(x + 1, y, right);
+ }
+
+ /**
+ * Set up the double-width font.
+ *
+ * @param fontSize the size of font to request for the single-width font.
+ * The double-width font will be 2x this value.
+ */
+ private void setupFont(final int fontSize) {
+ doubleFont = GlyphMaker.getDefault().size(fontSize * 2);
+
+ // Special case: the ECMA48 backend needs to have a timer to drive
+ // its blink state.
+ if (getScreen() instanceof jexer.backend.ECMA48Terminal) {
+ if (!haveTimer) {
+ // Blink every 500 millis.
+ long millis = 500;
+ getApplication().addTimer(millis, true,
+ new TAction() {
+ public void DO() {
+ blinkState = !blinkState;
+ getApplication().doRepaint();
+ }
+ }
+ );
+ haveTimer = true;
+ }
+ }
+ }
+