X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Fio%2FECMA48Screen.java;h=4c3af185db87b929a26aa2447406d75c0000d921;hb=e16dda65585466c8987bd1efd718431450a96605;hp=2e46e397901d21432e9d5527631779593bec015e;hpb=217c61076c63ba87b64921bb072ccad72ecc5298;p=nikiroo-utils.git diff --git a/src/jexer/io/ECMA48Screen.java b/src/jexer/io/ECMA48Screen.java index 2e46e39..4c3af18 100644 --- a/src/jexer/io/ECMA48Screen.java +++ b/src/jexer/io/ECMA48Screen.java @@ -1,34 +1,30 @@ -/** +/* * Jexer - Java Text User Interface * - * Version: $Id$ - * - * Author: Kevin Lamonte, kevin.lamonte@gmail.com + * The MIT License (MIT) * - * License: LGPLv3 or later + * Copyright (C) 2016 Kevin Lamonte * - * Copyright: This module is licensed under the GNU Lesser General - * Public License Version 3. Please see the file "COPYING" in this - * directory for more information about the GNU Lesser General Public - * License Version 3. + * 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: * - * Copyright (C) 2015 Kevin Lamonte + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. + * 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. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see - * http://www.gnu.org/licenses/, or write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA + * @author Kevin Lamonte [kevin.lamonte@gmail.com] + * @version 1 */ package jexer.io; @@ -36,189 +32,201 @@ import jexer.bits.Cell; import jexer.bits.CellAttributes; /** - * This Screen class draws to an xterm/ANSI X3.64/ECMA-48 type terminal. + * This Screen implementation draws to an xterm/ANSI X3.64/ECMA-48 type + * terminal. */ -public class ECMA48Screen extends Screen { +public final class ECMA48Screen extends Screen { /** - * We call terminal.cursor() so need the instance + * Emit debugging to stderr. + */ + private boolean debugToStderr; + + /** + * We call terminal.cursor() so need the instance. */ private ECMA48Terminal terminal; /** - * Public constructor + * Public constructor. * * @param terminal ECMA48Terminal to use */ - public ECMA48Screen(ECMA48Terminal terminal) { - this.terminal = terminal; + public ECMA48Screen(final ECMA48Terminal terminal) { + debugToStderr = false; + + this.terminal = terminal; - // Query the screen size - setDimensions(terminal.session.getWindowWidth(), - terminal.session.getWindowHeight()); + // Query the screen size + setDimensions(terminal.getSessionInfo().getWindowWidth(), + terminal.getSessionInfo().getWindowHeight()); } /** - * Perform a somewhat-optimal rendering of a line + * Perform a somewhat-optimal rendering of a line. * * @param y row coordinate. 0 is the top-most row. * @param sb StringBuilder to write escape sequences to * @param lastAttr cell attributes from the last call to flushLine */ - private void flushLine(int y, StringBuilder sb, CellAttributes lastAttr) { - - int lastX = -1; - int textEnd = 0; - for (int x = 0; x < width; x++) { - Cell lCell = logical[x][y]; - if (!lCell.isBlank()) { - textEnd = x; - } - } - // Push textEnd to first column beyond the text area - textEnd++; - - // DEBUG - // reallyCleared = true; - - for (int x = 0; x < width; x++) { - Cell lCell = logical[x][y]; - Cell pCell = physical[x][y]; - - if ((lCell != pCell) || (reallyCleared == true)) { - - if (debugToStderr) { - System.err.printf("\n--\n"); - System.err.printf(" Y: %d X: %d\n", y, x); - System.err.printf(" lCell: %s\n", lCell); - System.err.printf(" pCell: %s\n", pCell); - System.err.printf(" ==== \n"); - } - - if (lastAttr == null) { - lastAttr = new CellAttributes(); - sb.append(terminal.normal()); - } - - // Place the cell - if ((lastX != (x - 1)) || (lastX == -1)) { - // Advancing at least one cell, or the first gotoXY - sb.append(terminal.gotoXY(x, y)); - } - - assert(lastAttr != null); - - if ((x == textEnd) && (textEnd < width - 1)) { - assert(lCell.isBlank()); - - for (int i = x; i < width; i++) { - assert(logical[i][y].isBlank()); - // Physical is always updatesd - physical[i][y].reset(); - } - - // Clear remaining line - sb.append(terminal.clearRemainingLine()); - lastAttr.reset(); - return; - } - - // Now emit only the modified attributes - if ((lCell.foreColor != lastAttr.foreColor) && - (lCell.backColor != lastAttr.backColor) && - (lCell.bold == lastAttr.bold) && - (lCell.reverse == lastAttr.reverse) && - (lCell.underline == lastAttr.underline) && - (lCell.blink == lastAttr.blink)) { - - // Both colors changed, attributes the same - sb.append(terminal.color(lCell.foreColor, - lCell.backColor)); - - if (debugToStderr) { - System.err.printf("1 Change only fore/back colors\n"); - } - } else if ((lCell.foreColor != lastAttr.foreColor) && - (lCell.backColor != lastAttr.backColor) && - (lCell.bold != lastAttr.bold) && - (lCell.reverse != lastAttr.reverse) && - (lCell.underline != lastAttr.underline) && - (lCell.blink != lastAttr.blink)) { - - if (debugToStderr) { - System.err.printf("2 Set all attributes\n"); - } - - // Everything is different - sb.append(terminal.color(lCell.foreColor, - lCell.backColor, - lCell.bold, lCell.reverse, lCell.blink, - lCell.underline)); - - } else if ((lCell.foreColor != lastAttr.foreColor) && - (lCell.backColor == lastAttr.backColor) && - (lCell.bold == lastAttr.bold) && - (lCell.reverse == lastAttr.reverse) && - (lCell.underline == lastAttr.underline) && - (lCell.blink == lastAttr.blink)) { - - // Attributes same, foreColor different - sb.append(terminal.color(lCell.foreColor, true)); - - if (debugToStderr) { - System.err.printf("3 Change foreColor\n"); - } - - } else if ((lCell.foreColor == lastAttr.foreColor) && - (lCell.backColor != lastAttr.backColor) && - (lCell.bold == lastAttr.bold) && - (lCell.reverse == lastAttr.reverse) && - (lCell.underline == lastAttr.underline) && - (lCell.blink == lastAttr.blink)) { - - // Attributes same, backColor different - sb.append(terminal.color(lCell.backColor, false)); - - if (debugToStderr) { - System.err.printf("4 Change backColor\n"); - } - - } else if ((lCell.foreColor == lastAttr.foreColor) && - (lCell.backColor == lastAttr.backColor) && - (lCell.bold == lastAttr.bold) && - (lCell.reverse == lastAttr.reverse) && - (lCell.underline == lastAttr.underline) && - (lCell.blink == lastAttr.blink)) { - - // All attributes the same, just print the char - // NOP - - if (debugToStderr) { - System.err.printf("5 Only emit character\n"); - } - } else { - // Just reset everything again - sb.append(terminal.color(lCell.foreColor, lCell.backColor, - lCell.bold, lCell.reverse, lCell.blink, - lCell.underline)); - - if (debugToStderr) { - System.err.printf("6 Change all attributes\n"); - } - } - // Emit the character - sb.append(lCell.ch); - - // Save the last rendered cell - lastX = x; - lastAttr.setTo(lCell); - - // Physical is always updatesd - physical[x][y].setTo(lCell); - - } // if ((lCell != pCell) || (reallyCleared == true)) - - } // for (int x = 0; x < width; x++) + private void flushLine(final int y, final StringBuilder sb, + CellAttributes lastAttr) { + + int lastX = -1; + int textEnd = 0; + for (int x = 0; x < width; x++) { + Cell lCell = logical[x][y]; + if (!lCell.isBlank()) { + textEnd = x; + } + } + // Push textEnd to first column beyond the text area + textEnd++; + + // DEBUG + // reallyCleared = true; + + for (int x = 0; x < width; x++) { + Cell lCell = logical[x][y]; + Cell pCell = physical[x][y]; + + if (!lCell.equals(pCell) || reallyCleared) { + + if (debugToStderr) { + System.err.printf("\n--\n"); + System.err.printf(" Y: %d X: %d\n", y, x); + System.err.printf(" lCell: %s\n", lCell); + System.err.printf(" pCell: %s\n", pCell); + System.err.printf(" ==== \n"); + } + + if (lastAttr == null) { + lastAttr = new CellAttributes(); + sb.append(terminal.normal()); + } + + // Place the cell + if ((lastX != (x - 1)) || (lastX == -1)) { + // Advancing at least one cell, or the first gotoXY + sb.append(terminal.gotoXY(x, y)); + } + + assert (lastAttr != null); + + if ((x == textEnd) && (textEnd < width - 1)) { + assert (lCell.isBlank()); + + for (int i = x; i < width; i++) { + assert (logical[i][y].isBlank()); + // Physical is always updatesd + physical[i][y].reset(); + } + + // Clear remaining line + sb.append(terminal.clearRemainingLine()); + lastAttr.reset(); + return; + } + + // Now emit only the modified attributes + if ((lCell.getForeColor() != lastAttr.getForeColor()) + && (lCell.getBackColor() != lastAttr.getBackColor()) + && (lCell.isBold() == lastAttr.isBold()) + && (lCell.isReverse() == lastAttr.isReverse()) + && (lCell.isUnderline() == lastAttr.isUnderline()) + && (lCell.isBlink() == lastAttr.isBlink()) + ) { + // Both colors changed, attributes the same + sb.append(terminal.color(lCell.getForeColor(), + lCell.getBackColor())); + + if (debugToStderr) { + System.err.printf("1 Change only fore/back colors\n"); + } + } else if ((lCell.getForeColor() != lastAttr.getForeColor()) + && (lCell.getBackColor() != lastAttr.getBackColor()) + && (lCell.isBold() != lastAttr.isBold()) + && (lCell.isReverse() != lastAttr.isReverse()) + && (lCell.isUnderline() != lastAttr.isUnderline()) + && (lCell.isBlink() != lastAttr.isBlink()) + ) { + // Everything is different + sb.append(terminal.color(lCell.getForeColor(), + lCell.getBackColor(), + lCell.isBold(), lCell.isReverse(), + lCell.isBlink(), + lCell.isUnderline())); + + if (debugToStderr) { + System.err.printf("2 Set all attributes\n"); + } + } else if ((lCell.getForeColor() != lastAttr.getForeColor()) + && (lCell.getBackColor() == lastAttr.getBackColor()) + && (lCell.isBold() == lastAttr.isBold()) + && (lCell.isReverse() == lastAttr.isReverse()) + && (lCell.isUnderline() == lastAttr.isUnderline()) + && (lCell.isBlink() == lastAttr.isBlink()) + ) { + + // Attributes same, foreColor different + sb.append(terminal.color(lCell.getForeColor(), true)); + + if (debugToStderr) { + System.err.printf("3 Change foreColor\n"); + } + } else if ((lCell.getForeColor() == lastAttr.getForeColor()) + && (lCell.getBackColor() != lastAttr.getBackColor()) + && (lCell.isBold() == lastAttr.isBold()) + && (lCell.isReverse() == lastAttr.isReverse()) + && (lCell.isUnderline() == lastAttr.isUnderline()) + && (lCell.isBlink() == lastAttr.isBlink()) + ) { + // Attributes same, backColor different + sb.append(terminal.color(lCell.getBackColor(), false)); + + if (debugToStderr) { + System.err.printf("4 Change backColor\n"); + } + } else if ((lCell.getForeColor() == lastAttr.getForeColor()) + && (lCell.getBackColor() == lastAttr.getBackColor()) + && (lCell.isBold() == lastAttr.isBold()) + && (lCell.isReverse() == lastAttr.isReverse()) + && (lCell.isUnderline() == lastAttr.isUnderline()) + && (lCell.isBlink() == lastAttr.isBlink()) + ) { + + // All attributes the same, just print the char + // NOP + + if (debugToStderr) { + System.err.printf("5 Only emit character\n"); + } + } else { + // Just reset everything again + sb.append(terminal.color(lCell.getForeColor(), + lCell.getBackColor(), + lCell.isBold(), + lCell.isReverse(), + lCell.isBlink(), + lCell.isUnderline())); + + if (debugToStderr) { + System.err.printf("6 Change all attributes\n"); + } + } + // Emit the character + sb.append(lCell.getChar()); + + // Save the last rendered cell + lastX = x; + lastAttr.setTo(lCell); + + // Physical is always updated + physical[x][y].setTo(lCell); + + } // if (!lCell.equals(pCell) || (reallyCleared == true)) + + } // for (int x = 0; x < width; x++) } /** @@ -228,32 +236,32 @@ public class ECMA48Screen extends Screen { * @return escape sequences string that provides the updates to the * physical screen */ - public String flushString() { - if (dirty == false) { - assert(reallyCleared == false); - return ""; - } - - CellAttributes attr = null; - - StringBuilder sb = new StringBuilder(); - if (reallyCleared == true) { - attr = new CellAttributes(); - sb.append(terminal.clearAll()); - } - - for (int y = 0; y < height; y++) { - flushLine(y, sb, attr); - } - - dirty = false; - reallyCleared = false; - - String result = sb.toString(); - if (debugToStderr) { - System.err.printf("flushString(): %s\n", result); - } - return result; + private String flushString() { + if (!dirty) { + assert (!reallyCleared); + return ""; + } + + CellAttributes attr = null; + + StringBuilder sb = new StringBuilder(); + if (reallyCleared) { + attr = new CellAttributes(); + sb.append(terminal.clearAll()); + } + + for (int y = 0; y < height; y++) { + flushLine(y, sb, attr); + } + + dirty = false; + reallyCleared = false; + + String result = sb.toString(); + if (debugToStderr) { + System.err.printf("flushString(): %s\n", result); + } + return result; } /** @@ -261,17 +269,17 @@ public class ECMA48Screen extends Screen { */ @Override public void flushPhysical() { - String result = flushString(); - if ((cursorVisible) && - (cursorY <= height - 1) && - (cursorX <= width - 1) - ) { - result += terminal.cursor(true); - result += terminal.gotoXY(cursorX, cursorY); - } else { - result += terminal.cursor(false); - } - terminal.getOutput().write(result); - terminal.flush(); + String result = flushString(); + if ((cursorVisible) + && (cursorY <= height - 1) + && (cursorX <= width - 1) + ) { + result += terminal.cursor(true); + result += terminal.gotoXY(cursorX, cursorY); + } else { + result += terminal.cursor(false); + } + terminal.getOutput().write(result); + terminal.flush(); } }