package com.googlecode.lanterna.graphics;
import java.util.Arrays;
import com.googlecode.lanterna.TerminalPosition;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.TextCharacter;
import com.googlecode.lanterna.TextColor;
public class BasicTextImage implements TextImage {
private final TerminalSize size;
private final TextCharacter[][] buffer;
public BasicTextImage(int columns, int rows) {
this(new TerminalSize(columns, rows));
}
public BasicTextImage(TerminalSize size) {
this(size, new TextCharacter(' ', TextColor.ANSI.DEFAULT, TextColor.ANSI.DEFAULT));
}
public BasicTextImage(TerminalSize size, TextCharacter initialContent) {
this(size, new TextCharacter[0][], initialContent);
}
private BasicTextImage(TerminalSize size, TextCharacter[][] toCopy, TextCharacter initialContent) {
if(size == null || toCopy == null || initialContent == null) {
throw new IllegalArgumentException("Cannot create BasicTextImage with null " +
(size == null ? "size" : (toCopy == null ? "toCopy" : "filler")));
}
this.size = size;
int rows = size.getRows();
int columns = size.getColumns();
buffer = new TextCharacter[rows][];
for(int y = 0; y < rows; y++) {
buffer[y] = new TextCharacter[columns];
for(int x = 0; x < columns; x++) {
if(y < toCopy.length && x < toCopy[y].length) {
buffer[y][x] = toCopy[y][x];
}
else {
buffer[y][x] = initialContent;
}
}
}
}
@Override
public TerminalSize getSize() {
return size;
}
@Override
public void setAll(TextCharacter character) {
if(character == null) {
throw new IllegalArgumentException("Cannot call BasicTextImage.setAll(..) with null character");
}
for(TextCharacter[] line : buffer) {
Arrays.fill(line, character);
}
}
@Override
public BasicTextImage resize(TerminalSize newSize, TextCharacter filler) {
if(newSize == null || filler == null) {
throw new IllegalArgumentException("Cannot resize BasicTextImage with null " +
(newSize == null ? "newSize" : "filler"));
}
if(newSize.getRows() == buffer.length &&
(buffer.length == 0 || newSize.getColumns() == buffer[0].length)) {
return this;
}
return new BasicTextImage(newSize, buffer, filler);
}
@Override
public void setCharacterAt(TerminalPosition position, TextCharacter character) {
if(position == null) {
throw new IllegalArgumentException("Cannot call BasicTextImage.setCharacterAt(..) with null position");
}
setCharacterAt(position.getColumn(), position.getRow(), character);
}
@Override
public void setCharacterAt(int column, int row, TextCharacter character) {
if(character == null) {
throw new IllegalArgumentException("Cannot call BasicTextImage.setCharacterAt(..) with null character");
}
if(column < 0 || row < 0 || row >= buffer.length || column >= buffer[0].length) {
return;
}
if(column > 0 && buffer[row][column - 1].isDoubleWidth()) {
buffer[row][column - 1] = buffer[row][column - 1].withCharacter(' ');
}
buffer[row][column] = character;
if(character.isDoubleWidth() && column + 1 < buffer[0].length) {
buffer[row][column+1] = character.withCharacter(' ');
}
}
@Override
public TextCharacter getCharacterAt(TerminalPosition position) {
if(position == null) {
throw new IllegalArgumentException("Cannot call BasicTextImage.getCharacterAt(..) with null position");
}
return getCharacterAt(position.getColumn(), position.getRow());
}
@Override
public TextCharacter getCharacterAt(int column, int row) {
if(column < 0 || row < 0 || row >= buffer.length || column >= buffer[0].length) {
return null;
}
return buffer[row][column];
}
@Override
public void copyTo(TextImage destination) {
if (buffer.length > 0) {
copyTo(destination, 0, buffer.length, 0, buffer[0].length, 0, 0);
}
}
@Override
public void copyTo(
TextImage destination,
int startRowIndex,
int rows,
int startColumnIndex,
int columns,
int destinationRowOffset,
int destinationColumnOffset) {
if(startColumnIndex < 0) {
destinationColumnOffset += -startColumnIndex;
columns += startColumnIndex;
startColumnIndex = 0;
}
if(startRowIndex < 0) {
destinationRowOffset += -startRowIndex;
rows += startRowIndex;
startRowIndex = 0;
}
if(destinationColumnOffset < 0) {
startColumnIndex -= destinationColumnOffset;
columns += destinationColumnOffset;
destinationColumnOffset = 0;
}
if(destinationRowOffset < 0) {
startRowIndex -= destinationRowOffset;
rows += destinationRowOffset;
destinationRowOffset = 0;
}
rows = Math.min(buffer.length - startRowIndex, rows);
columns = rows>0 ? Math.min(buffer[0].length - startColumnIndex, columns) : 0;
columns = Math.min(destination.getSize().getColumns() - destinationColumnOffset, columns);
rows = Math.min(destination.getSize().getRows() - destinationRowOffset, rows);
if(columns <= 0 || rows <= 0) {
return;
}
TerminalSize destinationSize = destination.getSize();
if(destination instanceof BasicTextImage) {
int targetRow = destinationRowOffset;
for(int y = startRowIndex; y < startRowIndex + rows && targetRow < destinationSize.getRows(); y++) {
System.arraycopy(buffer[y], startColumnIndex, ((BasicTextImage)destination).buffer[targetRow++], destinationColumnOffset, columns);
}
}
else {
for(int y = startRowIndex; y < startRowIndex + rows; y++) {
for(int x = startColumnIndex; x < startColumnIndex + columns; x++) {
TextCharacter character = buffer[y][x];
if (character.isDoubleWidth()) {
if (x + 1 < startColumnIndex + columns) {
destination.setCharacterAt(
x - startColumnIndex + destinationColumnOffset,
y - startRowIndex + destinationRowOffset,
character.withCharacter(' '));
}
else if (x + 1 == startColumnIndex + columns) {
character = character.withCharacter(' ');
}
}
destination.setCharacterAt(
x - startColumnIndex + destinationColumnOffset,
y - startRowIndex + destinationRowOffset,
character);
if (character.isDoubleWidth()) {
x++;
}
}
}
}
if (destinationColumnOffset > 0) {
int destinationX = destinationColumnOffset - 1;
for(int y = startRowIndex; y < startRowIndex + rows; y++) {
int destinationY = y - startRowIndex + destinationRowOffset;
TextCharacter neighbour = destination.getCharacterAt(destinationX, destinationY);
if (neighbour.isDoubleWidth()) {
destination.setCharacterAt(destinationX, destinationY, neighbour.withCharacter(' '));
}
}
}
}
@Override
public TextGraphics newTextGraphics() {
return new AbstractTextGraphics() {
@Override
public TextGraphics setCharacter(int columnIndex, int rowIndex, TextCharacter textCharacter) {
BasicTextImage.this.setCharacterAt(columnIndex, rowIndex, textCharacter);
return this;
}
@Override
public TextCharacter getCharacter(int column, int row) {
return BasicTextImage.this.getCharacterAt(column, row);
}
@Override
public TerminalSize getSize() {
return size;
}
};
}
private TextCharacter[] newBlankLine() {
TextCharacter[] line = new TextCharacter[size.getColumns()];
Arrays.fill(line, TextCharacter.DEFAULT_CHARACTER);
return line;
}
@Override
public void scrollLines(int firstLine, int lastLine, int distance) {
if (firstLine < 0) { firstLine = 0; }
if (lastLine >= size.getRows()) { lastLine = size.getRows() - 1; }
if (firstLine < lastLine) {
if (distance > 0) {
int curLine = firstLine;
for (; curLine <= lastLine - distance; curLine++) {
buffer[curLine] = buffer[curLine+distance];
}
for (; curLine <= lastLine; curLine++) {
buffer[curLine] = newBlankLine();
}
}
else if (distance < 0) {
int curLine = lastLine; distance = -distance;
for (; curLine >= firstLine + distance; curLine--) {
buffer[curLine] = buffer[curLine-distance];
}
for (; curLine >= firstLine; curLine--) {
buffer[curLine] = newBlankLine();
}
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(size.getRows()*(size.getColumns()+1)+50);
sb.append('{').append(size.getColumns()).append('x').append(size.getRows()).append('}').append('\n');
for (TextCharacter[] line : buffer) {
for (TextCharacter tc : line) {
sb.append(tc.getCharacter());
}
sb.append('\n');
}
return sb.toString();
}
}