@Override public TerminalSize surroundAreaSize(TerminalSize TerminalSize) { return new TerminalSize( TerminalSize.getColumns() == Integer.MAX_VALUE ? Integer.MAX_VALUE : TerminalSize.getColumns() + 4, TerminalSize.getRows() == Integer.MAX_VALUE ? Integer.MAX_VALUE : TerminalSize.getRows() + 2); }
// WARNING!!! Should only be called in a block synchronized on mutex! See refresh() private void resizeScreenIfNeeded() { TerminalSize newSize; synchronized (resizeQueue) { if (resizeQueue.isEmpty()) return; newSize = resizeQueue.getLast(); resizeQueue.clear(); } int height = newSize.getRows(); int width = newSize.getColumns(); ScreenCharacter[][] newBackBuffer = new ScreenCharacter[height][width]; ScreenCharacter[][] newVisibleScreen = new ScreenCharacter[height][width]; ScreenCharacter newAreaCharacter = new ScreenCharacter('X', Terminal.Color.GREEN, Terminal.Color.BLACK); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (x < backbuffer[0].length && y < backbuffer.length) newBackBuffer[y][x] = backbuffer[y][x]; else newBackBuffer[y][x] = new ScreenCharacter(newAreaCharacter); if (x < visibleScreen[0].length && y < visibleScreen.length) newVisibleScreen[y][x] = visibleScreen[y][x]; else newVisibleScreen[y][x] = new ScreenCharacter(newAreaCharacter); } } backbuffer = newBackBuffer; visibleScreen = newVisibleScreen; wholeScreenInvalid = true; terminalSize = new TerminalSize(newSize); }
@Override public void drawBorder(TextGraphics graphics, TerminalSize actualSize, String title) { graphics.applyTheme(graphics.getTheme().getDefinition(Theme.Category.Border)); final int width = actualSize.getColumns(); final int height = actualSize.getRows(); // Top graphics.drawString(0, 0, ACS.ULCORNER + ""); for (int x = 1; x < width - 1; x++) graphics.drawString(x, 0, ACS.HLINE + ""); graphics.drawString(width - 1, 0, ACS.URCORNER + ""); // Each row for (int i = 1; i < height - 1; i++) { graphics.drawString(0, i, ACS.VLINE + ""); graphics.drawString(0 + width - 1, i, ACS.VLINE + ""); } // Bottom graphics.drawString(0, height - 1, ACS.LLCORNER + ""); for (int x = 1; x < width - 1; x++) graphics.drawString(x, height - 1, ACS.HLINE + ""); graphics.drawString(width - 1, height - 1, ACS.LRCORNER + ""); // Write the title graphics.applyTheme(graphics.getTheme().getDefinition(Theme.Category.DialogArea)); graphics.setBoldMask(true); graphics.drawString(2, 0, title); }
/** * Moves the current cursor position * * @param column 0-indexed column number of the new position * @param row 0-indexed row number of the new position */ public void setCursorPosition(int column, int row) { synchronized (mutex) { if (column >= 0 && column < terminalSize.getColumns() && row >= 0 && row < terminalSize.getRows()) { this.cursorPosition = new TerminalPosition(column, row); } } }
/** * Erases all the characters on the screen, effectively giving you a blank area. The default * background color will be used, if you want to fill the screen with a different color you will * need to do this manually. */ public void clear() { // ScreenCharacter is immutable, so we can use it for every element ScreenCharacter background = new ScreenCharacter(' '); synchronized (mutex) { for (int y = 0; y < terminalSize.getRows(); y++) { for (int x = 0; x < terminalSize.getColumns(); x++) { backbuffer[y][x] = background; } } } }
@Override public void drawBorder(TextGraphics graphics, TerminalSize actualSize, String title) { final int width = actualSize.getColumns(); final int height = actualSize.getRows(); final Theme.Definition upperLeft; final Theme.Definition lowerRight; if (raised) { upperLeft = graphics.getTheme().getDefinition(Theme.Category.RaisedBorder); lowerRight = graphics.getTheme().getDefinition(Theme.Category.Border); } else { upperLeft = graphics.getTheme().getDefinition(Theme.Category.Border); lowerRight = graphics.getTheme().getDefinition(Theme.Category.RaisedBorder); } // Top graphics.applyTheme(upperLeft); graphics.drawString(0, 0, ACS.ULCORNER + ""); for (int i = 1; i < width - 1; i++) graphics.drawString(i, 0, ACS.HLINE + ""); graphics.applyTheme(lowerRight); graphics.drawString(width - 1, 0, ACS.URCORNER + ""); // Each row for (int i = 1; i < height - 1; i++) { graphics.applyTheme(upperLeft); graphics.drawString(0, i, ACS.VLINE + ""); graphics.applyTheme(lowerRight); graphics.drawString(width - 1, i, ACS.VLINE + ""); } // Bottom graphics.applyTheme(upperLeft); graphics.drawString(0, height - 1, ACS.LLCORNER + ""); graphics.applyTheme(lowerRight); for (int i = 1; i < width - 1; i++) graphics.drawString(i, height - 1, ACS.HLINE + ""); graphics.drawString(width - 1, height - 1, ACS.LRCORNER + ""); // Write the title graphics.applyTheme(graphics.getTheme().getDefinition(Theme.Category.DialogArea)); graphics.setBoldMask(true); graphics.drawString(2, 0, title); }
/** * Call this method to make changes done through {@code putCharacter(...)}, {@code putString(...)} * visible on the terminal. The screen will calculate the changes that are required and send the * necessary characters and control sequences to make it so. */ public void refresh() { if (!hasBeenActivated) return; synchronized (mutex) { // If any resize operations are in the queue, execute them resizeScreenIfNeeded(); Map<TerminalPosition, ScreenCharacter> updateMap = new TreeMap<TerminalPosition, ScreenCharacter>(new ScreenPointComparator()); for (int y = 0; y < terminalSize.getRows(); y++) { for (int x = 0; x < terminalSize.getColumns(); x++) { ScreenCharacter c = backbuffer[y][x]; if (!c.equals(visibleScreen[y][x]) || wholeScreenInvalid) { visibleScreen[y][x] = c; // Remember, ScreenCharacter is immutable, we don't need to worry about it being // modified updateMap.put(new TerminalPosition(x, y), c); } } } Writer terminalWriter = new Writer(); terminalWriter.reset(); TerminalPosition previousPoint = null; for (TerminalPosition nextUpdate : updateMap.keySet()) { if (previousPoint == null || previousPoint.getRow() != nextUpdate.getRow() || previousPoint.getColumn() + 1 != nextUpdate.getColumn()) { terminalWriter.setCursorPosition(nextUpdate.getColumn(), nextUpdate.getRow()); } terminalWriter.writeCharacter(updateMap.get(nextUpdate)); previousPoint = nextUpdate; } terminalWriter.setCursorPosition( getCursorPosition().getColumn(), getCursorPosition().getRow()); wholeScreenInvalid = false; } terminal.flush(); }
/** * Creates a new Screen on top of a supplied terminal and will set the size of the screen to a * supplied value. The screen is initially blank. * * @param terminal * @param terminalSize */ public Screen(Terminal terminal, TerminalSize terminalSize) { this(terminal, terminalSize.getColumns(), terminalSize.getRows()); }