only keep the (re)sources here
[fanfix.git] / src / jexer / backend / LogicalScreen.java
diff --git a/src/jexer/backend/LogicalScreen.java b/src/jexer/backend/LogicalScreen.java
deleted file mode 100644 (file)
index 4e4aecc..0000000
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- * Jexer - Java Text User Interface
- *
- * The MIT License (MIT)
- *
- * Copyright (C) 2019 Kevin 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 Kevin Lamonte [kevin.lamonte@gmail.com]
- * @version 1
- */
-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.
- */
-public class LogicalScreen implements Screen {
-
-    // ------------------------------------------------------------------------
-    // Variables --------------------------------------------------------------
-    // ------------------------------------------------------------------------
-
-    /**
-     * Width of the visible window.
-     */
-    protected int width;
-
-    /**
-     * Height of the visible window.
-     */
-    protected int height;
-
-    /**
-     * Drawing offset for x.
-     */
-    private int offsetX;
-
-    /**
-     * Drawing offset for y.
-     */
-    private int offsetY;
-
-    /**
-     * Ignore anything drawn right of clipRight.
-     */
-    private int clipRight;
-
-    /**
-     * Ignore anything drawn below clipBottom.
-     */
-    private int clipBottom;
-
-    /**
-     * Ignore anything drawn left of clipLeft.
-     */
-    private int clipLeft;
-
-    /**
-     * Ignore anything drawn above clipTop.
-     */
-    private int clipTop;
-
-    /**
-     * The physical screen last sent out on flush().
-     */
-    protected Cell [][] physical;
-
-    /**
-     * The logical screen being rendered to.
-     */
-    protected Cell [][] logical;
-
-    /**
-     * Set if the user explicitly wants to redraw everything starting with a
-     * ECMATerminal.clearAll().
-     */
-    protected boolean reallyCleared;
-
-    /**
-     * If true, the cursor is visible and should be placed onscreen at
-     * (cursorX, cursorY) during a call to flushPhysical().
-     */
-    protected boolean cursorVisible;
-
-    /**
-     * Cursor X position if visible.
-     */
-    protected int cursorX;
-
-    /**
-     * Cursor Y position if visible.
-     */
-    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 -----------------------------------------------------------
-    // ------------------------------------------------------------------------
-
-    /**
-     * Public constructor.  Sets everything to not-bold, white-on-black.
-     */
-    protected LogicalScreen() {
-        offsetX  = 0;
-        offsetY  = 0;
-        width    = 80;
-        height   = 24;
-        logical  = null;
-        physical = null;
-        reallocate(width, height);
-    }
-
-    // ------------------------------------------------------------------------
-    // Screen -----------------------------------------------------------------
-    // ------------------------------------------------------------------------
-
-    /**
-     * Get the width of a character cell in pixels.
-     *
-     * @return the width in pixels of a character cell
-     */
-    public int getTextWidth() {
-        // Default width is 16 pixels.
-        return 16;
-    }
-
-    /**
-     * Get the height of a character cell in pixels.
-     *
-     * @return the height in pixels of a character cell
-     */
-    public int getTextHeight() {
-        // Default height is 20 pixels.
-        return 20;
-    }
-
-    /**
-     * Set drawing offset for x.
-     *
-     * @param offsetX new drawing offset
-     */
-    public final void setOffsetX(final int offsetX) {
-        this.offsetX = offsetX;
-    }
-
-    /**
-     * Set drawing offset for y.
-     *
-     * @param offsetY new drawing offset
-     */
-    public final void setOffsetY(final int offsetY) {
-        this.offsetY = offsetY;
-    }
-
-    /**
-     * Get right drawing clipping boundary.
-     *
-     * @return drawing boundary
-     */
-    public final int getClipRight() {
-        return clipRight;
-    }
-
-    /**
-     * Set right drawing clipping boundary.
-     *
-     * @param clipRight new boundary
-     */
-    public final void setClipRight(final int clipRight) {
-        this.clipRight = clipRight;
-    }
-
-    /**
-     * Get bottom drawing clipping boundary.
-     *
-     * @return drawing boundary
-     */
-    public final int getClipBottom() {
-        return clipBottom;
-    }
-
-    /**
-     * Set bottom drawing clipping boundary.
-     *
-     * @param clipBottom new boundary
-     */
-    public final void setClipBottom(final int clipBottom) {
-        this.clipBottom = clipBottom;
-    }
-
-    /**
-     * Get left drawing clipping boundary.
-     *
-     * @return drawing boundary
-     */
-    public final int getClipLeft() {
-        return clipLeft;
-    }
-
-    /**
-     * Set left drawing clipping boundary.
-     *
-     * @param clipLeft new boundary
-     */
-    public final void setClipLeft(final int clipLeft) {
-        this.clipLeft = clipLeft;
-    }
-
-    /**
-     * Get top drawing clipping boundary.
-     *
-     * @return drawing boundary
-     */
-    public final int getClipTop() {
-        return clipTop;
-    }
-
-    /**
-     * Set top drawing clipping boundary.
-     *
-     * @param clipTop new boundary
-     */
-    public final void setClipTop(final int clipTop) {
-        this.clipTop = clipTop;
-    }
-
-    /**
-     * Get dirty flag.
-     *
-     * @return if true, the logical screen is not in sync with the physical
-     * screen
-     */
-    public final boolean isDirty() {
-        for (int x = 0; x < width; x++) {
-            for (int y = 0; y < height; y++) {
-                if (!logical[x][y].equals(physical[x][y])) {
-                    return true;
-                }
-                if (logical[x][y].isBlink()) {
-                    // Blinking screens are always dirty.  There is
-                    // opportunity for a Netscape blink tag joke here...
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Get the attributes at one location.
-     *
-     * @param x column coordinate.  0 is the left-most column.
-     * @param y row coordinate.  0 is the top-most row.
-     * @return attributes at (x, y)
-     */
-    public final CellAttributes getAttrXY(final int x, final int y) {
-        CellAttributes attr = new CellAttributes();
-        if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
-            attr.setTo(logical[x][y]);
-        }
-        return attr;
-    }
-
-    /**
-     * Get the cell at one location.
-     *
-     * @param x column coordinate.  0 is the left-most column.
-     * @param y row coordinate.  0 is the top-most row.
-     * @return the character + attributes
-     */
-    public Cell getCharXY(final int x, final int y) {
-        Cell cell = new Cell();
-        if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
-            cell.setTo(logical[x][y]);
-        }
-        return cell;
-    }
-
-    /**
-     * Set the attributes at one location.
-     *
-     * @param x column coordinate.  0 is the left-most column.
-     * @param y row coordinate.  0 is the top-most row.
-     * @param attr attributes to use (bold, foreColor, backColor)
-     */
-    public final void putAttrXY(final int x, final int y,
-        final CellAttributes attr) {
-
-        putAttrXY(x, y, attr, true);
-    }
-
-    /**
-     * Set the attributes at one location.
-     *
-     * @param x column coordinate.  0 is the left-most column.
-     * @param y row coordinate.  0 is the top-most row.
-     * @param attr attributes to use (bold, foreColor, backColor)
-     * @param clip if true, honor clipping/offset
-     */
-    public final void putAttrXY(final int x, final int y,
-        final CellAttributes attr, final boolean clip) {
-
-        int X = x;
-        int Y = y;
-
-        if (clip) {
-            if ((x < clipLeft)
-                || (x >= clipRight)
-                || (y < clipTop)
-                || (y >= clipBottom)
-            ) {
-                return;
-            }
-            X += offsetX;
-            Y += offsetY;
-        }
-
-        if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
-            logical[X][Y].setTo(attr);
-
-            // If this happens to be the cursor position, make the position
-            // dirty.
-            if ((cursorX == X) && (cursorY == Y)) {
-                physical[cursorX][cursorY].unset();
-                unsetImageRow(cursorY);
-            }
-        }
-    }
-
-    /**
-     * Fill the entire screen with one character with attributes.
-     *
-     * @param ch character to draw
-     * @param attr attributes to use (bold, foreColor, backColor)
-     */
-    public final void putAll(final int ch, final CellAttributes attr) {
-
-        for (int x = 0; x < width; x++) {
-            for (int y = 0; y < height; y++) {
-                putCharXY(x, y, ch, attr);
-            }
-        }
-    }
-
-    /**
-     * Render one 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 + attributes to draw
-     */
-    public final void putCharXY(final int x, final int y, final Cell ch) {
-        if ((x < clipLeft)
-            || (x >= clipRight)
-            || (y < clipTop)
-            || (y >= clipBottom)
-        ) {
-            return;
-        }
-
-        if ((StringUtils.width(ch.getChar()) == 2) && (!ch.isImage())) {
-            putFullwidthCharXY(x, y, ch);
-            return;
-        }
-
-        int X = x + offsetX;
-        int Y = y + offsetY;
-
-        // System.err.printf("putCharXY: %d, %d, %c\n", X, Y, ch);
-
-        if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
-
-            // Do not put control characters on the display
-            if (!ch.isImage()) {
-                assert (ch.getChar() >= 0x20);
-                assert (ch.getChar() != 0x7F);
-            }
-            logical[X][Y].setTo(ch);
-
-            // If this happens to be the cursor position, make the position
-            // dirty.
-            if ((cursorX == X) && (cursorY == Y)) {
-                physical[cursorX][cursorY].unset();
-                unsetImageRow(cursorY);
-            }
-        }
-    }
-
-    /**
-     * Render one 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 putCharXY(final int x, final int y, final int ch,
-        final CellAttributes attr) {
-
-        if ((x < clipLeft)
-            || (x >= clipRight)
-            || (y < clipTop)
-            || (y >= clipBottom)
-        ) {
-            return;
-        }
-
-        if (StringUtils.width(ch) == 2) {
-            putFullwidthCharXY(x, y, ch, attr);
-            return;
-        }
-
-        int X = x + offsetX;
-        int Y = y + offsetY;
-
-        // System.err.printf("putCharXY: %d, %d, %c\n", X, Y, ch);
-
-        if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
-
-            // Do not put control characters on the display
-            assert (ch >= 0x20);
-            assert (ch != 0x7F);
-
-            logical[X][Y].setTo(attr);
-            logical[X][Y].setChar(ch);
-
-            // If this happens to be the cursor position, make the position
-            // dirty.
-            if ((cursorX == X) && (cursorY == Y)) {
-                physical[cursorX][cursorY].unset();
-                unsetImageRow(cursorY);
-            }
-        }
-    }
-
-    /**
-     * Render one character without changing the underlying 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 putCharXY(final int x, final int y, final int ch) {
-        if ((x < clipLeft)
-            || (x >= clipRight)
-            || (y < clipTop)
-            || (y >= clipBottom)
-        ) {
-            return;
-        }
-
-        if (StringUtils.width(ch) == 2) {
-            putFullwidthCharXY(x, y, ch);
-            return;
-        }
-
-        int X = x + offsetX;
-        int Y = y + offsetY;
-
-        // System.err.printf("putCharXY: %d, %d, %c\n", X, Y, ch);
-
-        if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
-            logical[X][Y].setChar(ch);
-
-            // If this happens to be the cursor position, make the position
-            // dirty.
-            if ((cursorX == X) && (cursorY == Y)) {
-                physical[cursorX][cursorY].unset();
-                unsetImageRow(cursorY);
-            }
-        }
-    }
-
-    /**
-     * Render a string.  Does not wrap if the string exceeds the line.
-     *
-     * @param x column coordinate.  0 is the left-most column.
-     * @param y row coordinate.  0 is the top-most row.
-     * @param str string to draw
-     * @param attr attributes to use (bold, foreColor, backColor)
-     */
-    public final void putStringXY(final int x, final int y, final String str,
-        final CellAttributes attr) {
-
-        int i = x;
-        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) {
-                break;
-            }
-        }
-    }
-
-    /**
-     * Render a string without changing the underlying attribute.  Does not
-     * wrap if the string exceeds the line.
-     *
-     * @param x column coordinate.  0 is the left-most column.
-     * @param y row coordinate.  0 is the top-most row.
-     * @param str string to draw
-     */
-    public final void putStringXY(final int x, final int y, final String str) {
-
-        int i = x;
-        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) {
-                break;
-            }
-        }
-    }
-
-    /**
-     * Draw a vertical line from (x, y) to (x, y + n).
-     *
-     * @param x column coordinate.  0 is the left-most column.
-     * @param y row coordinate.  0 is the top-most row.
-     * @param n number of characters to draw
-     * @param ch character to draw
-     * @param attr attributes to use (bold, foreColor, backColor)
-     */
-    public final void vLineXY(final int x, final int y, final int n,
-        final int ch, final CellAttributes attr) {
-
-        for (int i = y; i < y + n; i++) {
-            putCharXY(x, i, ch, attr);
-        }
-    }
-
-    /**
-     * Draw a horizontal line from (x, y) to (x + n, y).
-     *
-     * @param x column coordinate.  0 is the left-most column.
-     * @param y row coordinate.  0 is the top-most row.
-     * @param n number of characters to draw
-     * @param ch character to draw
-     * @param attr attributes to use (bold, foreColor, backColor)
-     */
-    public final void hLineXY(final int x, final int y, final int n,
-        final int ch, final CellAttributes attr) {
-
-        for (int i = x; i < x + n; i++) {
-            putCharXY(i, y, ch, attr);
-        }
-    }
-
-    /**
-     * Change the width.  Everything on-screen will be destroyed and must be
-     * redrawn.
-     *
-     * @param width new screen width
-     */
-    public final synchronized void setWidth(final int width) {
-        reallocate(width, this.height);
-    }
-
-    /**
-     * Change the height.  Everything on-screen will be destroyed and must be
-     * redrawn.
-     *
-     * @param height new screen height
-     */
-    public final synchronized void setHeight(final int height) {
-        reallocate(this.width, height);
-    }
-
-    /**
-     * Change the width and height.  Everything on-screen will be destroyed
-     * and must be redrawn.
-     *
-     * @param width new screen width
-     * @param height new screen height
-     */
-    public final void setDimensions(final int width, final int height) {
-        reallocate(width, height);
-        resizeToScreen();
-    }
-
-    /**
-     * Resize the physical screen to match the logical screen dimensions.
-     */
-    public void resizeToScreen() {
-        // Subclasses are expected to override this.
-    }
-
-    /**
-     * Get the height.
-     *
-     * @return current screen height
-     */
-    public final synchronized int getHeight() {
-        return this.height;
-    }
-
-    /**
-     * Get the width.
-     *
-     * @return current screen width
-     */
-    public final synchronized int getWidth() {
-        return this.width;
-    }
-
-    /**
-     * Reset screen to not-bold, white-on-black.  Also flushes the offset and
-     * clip variables.
-     */
-    public final synchronized void reset() {
-        for (int row = 0; row < height; row++) {
-            for (int col = 0; col < width; col++) {
-                logical[col][row].reset();
-            }
-        }
-        resetClipping();
-    }
-
-    /**
-     * Flush the offset and clip variables.
-     */
-    public final void resetClipping() {
-        offsetX    = 0;
-        offsetY    = 0;
-        clipLeft   = 0;
-        clipTop    = 0;
-        clipRight  = width;
-        clipBottom = height;
-    }
-
-    /**
-     * Clear the logical screen.
-     */
-    public final void clear() {
-        reset();
-    }
-
-    /**
-     * Draw a box with a border and empty background.
-     *
-     * @param left left column of box.  0 is the left-most column.
-     * @param top top row of the box.  0 is the top-most row.
-     * @param right right column of box
-     * @param bottom bottom row of the box
-     * @param border attributes to use for the border
-     * @param background attributes to use for the background
-     */
-    public final void drawBox(final int left, final int top,
-        final int right, final int bottom,
-        final CellAttributes border, final CellAttributes background) {
-
-        drawBox(left, top, right, bottom, border, background, 1, false);
-    }
-
-    /**
-     * Draw a box with a border and empty background.
-     *
-     * @param left left column of box.  0 is the left-most column.
-     * @param top top row of the box.  0 is the top-most row.
-     * @param right right column of box
-     * @param bottom bottom row of the box
-     * @param border attributes to use for the border
-     * @param background attributes to use for the background
-     * @param borderType if 1, draw a single-line border; if 2, draw a
-     * double-line border; if 3, draw double-line top/bottom edges and
-     * single-line left/right edges (like Qmodem)
-     * @param shadow if true, draw a "shadow" on the box
-     */
-    public final void drawBox(final int left, final int top,
-        final int right, final int bottom,
-        final CellAttributes border, final CellAttributes background,
-        final int borderType, final boolean shadow) {
-
-        int boxWidth = right - left;
-        int boxHeight = bottom - top;
-
-        char cTopLeft;
-        char cTopRight;
-        char cBottomLeft;
-        char cBottomRight;
-        char cHSide;
-        char cVSide;
-
-        switch (borderType) {
-        case 1:
-            cTopLeft = GraphicsChars.ULCORNER;
-            cTopRight = GraphicsChars.URCORNER;
-            cBottomLeft = GraphicsChars.LLCORNER;
-            cBottomRight = GraphicsChars.LRCORNER;
-            cHSide = GraphicsChars.SINGLE_BAR;
-            cVSide = GraphicsChars.WINDOW_SIDE;
-            break;
-
-        case 2:
-            cTopLeft = GraphicsChars.WINDOW_LEFT_TOP_DOUBLE;
-            cTopRight = GraphicsChars.WINDOW_RIGHT_TOP_DOUBLE;
-            cBottomLeft = GraphicsChars.WINDOW_LEFT_BOTTOM_DOUBLE;
-            cBottomRight = GraphicsChars.WINDOW_RIGHT_BOTTOM_DOUBLE;
-            cHSide = GraphicsChars.DOUBLE_BAR;
-            cVSide = GraphicsChars.WINDOW_SIDE_DOUBLE;
-            break;
-
-        case 3:
-            cTopLeft = GraphicsChars.WINDOW_LEFT_TOP;
-            cTopRight = GraphicsChars.WINDOW_RIGHT_TOP;
-            cBottomLeft = GraphicsChars.WINDOW_LEFT_BOTTOM;
-            cBottomRight = GraphicsChars.WINDOW_RIGHT_BOTTOM;
-            cHSide = GraphicsChars.WINDOW_TOP;
-            cVSide = GraphicsChars.WINDOW_SIDE;
-            break;
-        default:
-            throw new IllegalArgumentException("Invalid border type: "
-                + borderType);
-        }
-
-        // Place the corner characters
-        putCharXY(left, top, cTopLeft, border);
-        putCharXY(left + boxWidth - 1, top, cTopRight, border);
-        putCharXY(left, top + boxHeight - 1, cBottomLeft, border);
-        putCharXY(left + boxWidth - 1, top + boxHeight - 1, cBottomRight,
-            border);
-
-        // Draw the box lines
-        hLineXY(left + 1, top, boxWidth - 2, cHSide, border);
-        vLineXY(left, top + 1, boxHeight - 2, cVSide, border);
-        hLineXY(left + 1, top + boxHeight - 1, boxWidth - 2, cHSide, border);
-        vLineXY(left + boxWidth - 1, top + 1, boxHeight - 2, cVSide, border);
-
-        // Fill in the interior background
-        for (int i = 1; i < boxHeight - 1; i++) {
-            hLineXY(1 + left, i + top, boxWidth - 2, ' ', background);
-        }
-
-        if (shadow) {
-            // Draw a shadow
-            drawBoxShadow(left, top, right, bottom);
-        }
-    }
-
-    /**
-     * Draw a box shadow.
-     *
-     * @param left left column of box.  0 is the left-most column.
-     * @param top top row of the box.  0 is the top-most row.
-     * @param right right column of box
-     * @param bottom bottom row of the box
-     */
-    public final void drawBoxShadow(final int left, final int top,
-        final int right, final int bottom) {
-
-        int boxTop = top;
-        int boxLeft = left;
-        int boxWidth = right - left;
-        int boxHeight = bottom - top;
-        CellAttributes shadowAttr = new CellAttributes();
-
-        // Shadows do not honor clipping but they DO honor offset.
-        int oldClipRight = clipRight;
-        int oldClipBottom = clipBottom;
-        // When offsetX or offsetY go negative, we need to increase the clip
-        // bounds.
-        clipRight = width - offsetX;
-        clipBottom = height - offsetY;
-
-        for (int i = 0; i < boxHeight; i++) {
-            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++) {
-            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;
-    }
-
-    /**
-     * Default implementation does nothing.
-     */
-    public void flushPhysical() {}
-
-    /**
-     * Put the cursor at (x,y).
-     *
-     * @param visible if true, the cursor should be visible
-     * @param x column coordinate to put the cursor on
-     * @param y row coordinate to put the cursor on
-     */
-    public void putCursor(final boolean visible, final int x, final int y) {
-        if ((cursorY >= 0)
-            && (cursorX >= 0)
-            && (cursorY <= height - 1)
-            && (cursorX <= width - 1)
-        ) {
-            // Make the current cursor position dirty
-            physical[cursorX][cursorY].unset();
-            unsetImageRow(cursorY);
-        }
-
-        cursorVisible = visible;
-        cursorX = x;
-        cursorY = y;
-    }
-
-    /**
-     * Hide the cursor.
-     */
-    public final void hideCursor() {
-        cursorVisible = false;
-    }
-
-    /**
-     * Get the cursor visibility.
-     *
-     * @return true if the cursor is visible
-     */
-    public boolean isCursorVisible() {
-        return cursorVisible;
-    }
-
-    /**
-     * Get the cursor X position.
-     *
-     * @return the cursor x column position
-     */
-    public int getCursorX() {
-        return cursorX;
-    }
-
-    /**
-     * Get the cursor Y position.
-     *
-     * @return the cursor y row position
-     */
-    public int getCursorY() {
-        return cursorY;
-    }
-
-    /**
-     * Set the window title.  Default implementation does nothing.
-     *
-     * @param title the new title
-     */
-    public void setTitle(final String title) {}
-
-    // ------------------------------------------------------------------------
-    // LogicalScreen ----------------------------------------------------------
-    // ------------------------------------------------------------------------
-
-    /**
-     * Reallocate screen buffers.
-     *
-     * @param width new width
-     * @param height new height
-     */
-    private synchronized void reallocate(final int width, final int height) {
-        if (logical != null) {
-            for (int row = 0; row < this.height; row++) {
-                for (int col = 0; col < this.width; col++) {
-                    logical[col][row] = null;
-                }
-            }
-            logical = null;
-        }
-        logical = new Cell[width][height];
-        if (physical != null) {
-            for (int row = 0; row < this.height; row++) {
-                for (int col = 0; col < this.width; col++) {
-                    physical[col][row] = null;
-                }
-            }
-            physical = null;
-        }
-        physical = new Cell[width][height];
-
-        for (int row = 0; row < height; row++) {
-            for (int col = 0; col < width; col++) {
-                physical[col][row] = new Cell();
-                logical[col][row] = new Cell();
-            }
-        }
-
-        this.width = width;
-        this.height = height;
-
-        clipLeft = 0;
-        clipTop = 0;
-        clipRight = width;
-        clipBottom = height;
-
-        reallyCleared = true;
-    }
-
-    /**
-     * Clear the physical screen.
-     */
-    public final void clearPhysical() {
-        for (int row = 0; row < height; row++) {
-            for (int col = 0; col < width; col++) {
-                physical[col][row].unset();
-            }
-        }
-    }
-
-    /**
-     * Unset every image cell on one row of the physical screen, forcing
-     * images on that row to be redrawn.
-     *
-     * @param y row coordinate.  0 is the top-most row.
-     */
-    public final void unsetImageRow(final int y) {
-        if ((y < 0) || (y >= height)) {
-            return;
-        }
-        for (int x = 0; x < width; x++) {
-            if (logical[x][y].isImage()) {
-                physical[x][y].unset();
-            }
-        }
-    }
-
-    /**
-     * 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) {
-
-        int cellWidth = getTextWidth();
-        int cellHeight = getTextHeight();
-
-        if (lastTextHeight != cellHeight) {
-            glyphMaker = GlyphMaker.getInstance(cellHeight);
-            lastTextHeight = cellHeight;
-        }
-        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);
-        putCharXY(x, y, left);
-
-        Cell right = new Cell(cell);
-        right.setImage(rightImage);
-        right.setWidth(Cell.Width.RIGHT);
-        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 int ch, final CellAttributes attr) {
-
-        Cell cell = new Cell(ch, 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 int ch) {
-
-        Cell cell = new Cell(ch);
-        cell.setAttr(getAttrXY(x, y));
-        putFullwidthCharXY(x, y, cell);
-    }
-
-}