Change build scripts
[jvcard.git] / src / com / googlecode / lanterna / graphics / BasicTextImage.java
1 /*
2 * This file is part of lanterna (http://code.google.com/p/lanterna/).
3 *
4 * lanterna is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Copyright (C) 2010-2015 Martin
18 */
19 package com.googlecode.lanterna.graphics;
20
21 import java.util.Arrays;
22
23 import com.googlecode.lanterna.TerminalPosition;
24 import com.googlecode.lanterna.TerminalSize;
25 import com.googlecode.lanterna.TextCharacter;
26 import com.googlecode.lanterna.TextColor;
27
28 /**
29 * Simple implementation of TextImage that keeps the content as a two-dimensional TextCharacter array. Copy operations
30 * between two BasicTextImage classes are semi-optimized by using System.arraycopy instead of iterating over each
31 * character and copying them over one by one.
32 * @author martin
33 */
34 public class BasicTextImage implements TextImage {
35 private final TerminalSize size;
36 private final TextCharacter[][] buffer;
37
38 /**
39 * Creates a new BasicTextImage with the specified size and fills it initially with space characters using the
40 * default foreground and background color
41 * @param columns Size of the image in number of columns
42 * @param rows Size of the image in number of rows
43 */
44 public BasicTextImage(int columns, int rows) {
45 this(new TerminalSize(columns, rows));
46 }
47
48 /**
49 * Creates a new BasicTextImage with the specified size and fills it initially with space characters using the
50 * default foreground and background color
51 * @param size Size to make the image
52 */
53 public BasicTextImage(TerminalSize size) {
54 this(size, new TextCharacter(' ', TextColor.ANSI.DEFAULT, TextColor.ANSI.DEFAULT));
55 }
56
57 /**
58 * Creates a new BasicTextImage with a given size and a TextCharacter to initially fill it with
59 * @param size Size of the image
60 * @param initialContent What character to set as the initial content
61 */
62 public BasicTextImage(TerminalSize size, TextCharacter initialContent) {
63 this(size, new TextCharacter[0][], initialContent);
64 }
65
66 /**
67 * Creates a new BasicTextImage by copying a region of a two-dimensional array of TextCharacter:s. If the area to be
68 * copied to larger than the source array, a filler character is used.
69 * @param size Size to create the new BasicTextImage as (and size to copy from the array)
70 * @param toCopy Array to copy initial data from
71 * @param initialContent Filler character to use if the source array is smaller than the requested size
72 */
73 private BasicTextImage(TerminalSize size, TextCharacter[][] toCopy, TextCharacter initialContent) {
74 if(size == null || toCopy == null || initialContent == null) {
75 throw new IllegalArgumentException("Cannot create BasicTextImage with null " +
76 (size == null ? "size" : (toCopy == null ? "toCopy" : "filler")));
77 }
78 this.size = size;
79
80 int rows = size.getRows();
81 int columns = size.getColumns();
82 buffer = new TextCharacter[rows][];
83 for(int y = 0; y < rows; y++) {
84 buffer[y] = new TextCharacter[columns];
85 for(int x = 0; x < columns; x++) {
86 if(y < toCopy.length && x < toCopy[y].length) {
87 buffer[y][x] = toCopy[y][x];
88 }
89 else {
90 buffer[y][x] = initialContent;
91 }
92 }
93 }
94 }
95
96 @Override
97 public TerminalSize getSize() {
98 return size;
99 }
100
101 @Override
102 public void setAll(TextCharacter character) {
103 if(character == null) {
104 throw new IllegalArgumentException("Cannot call BasicTextImage.setAll(..) with null character");
105 }
106 for(TextCharacter[] line : buffer) {
107 Arrays.fill(line, character);
108 }
109 }
110
111 @Override
112 public BasicTextImage resize(TerminalSize newSize, TextCharacter filler) {
113 if(newSize == null || filler == null) {
114 throw new IllegalArgumentException("Cannot resize BasicTextImage with null " +
115 (newSize == null ? "newSize" : "filler"));
116 }
117 if(newSize.getRows() == buffer.length &&
118 (buffer.length == 0 || newSize.getColumns() == buffer[0].length)) {
119 return this;
120 }
121 return new BasicTextImage(newSize, buffer, filler);
122 }
123
124 @Override
125 public void setCharacterAt(TerminalPosition position, TextCharacter character) {
126 if(position == null) {
127 throw new IllegalArgumentException("Cannot call BasicTextImage.setCharacterAt(..) with null position");
128 }
129 setCharacterAt(position.getColumn(), position.getRow(), character);
130 }
131
132 @Override
133 public void setCharacterAt(int column, int row, TextCharacter character) {
134 if(character == null) {
135 throw new IllegalArgumentException("Cannot call BasicTextImage.setCharacterAt(..) with null character");
136 }
137 if(column < 0 || row < 0 || row >= buffer.length || column >= buffer[0].length) {
138 return;
139 }
140
141 buffer[row][column] = character;
142 }
143
144 @Override
145 public TextCharacter getCharacterAt(TerminalPosition position) {
146 if(position == null) {
147 throw new IllegalArgumentException("Cannot call BasicTextImage.getCharacterAt(..) with null position");
148 }
149 return getCharacterAt(position.getColumn(), position.getRow());
150 }
151
152 @Override
153 public TextCharacter getCharacterAt(int column, int row) {
154 if(column < 0 || row < 0 || row >= buffer.length || column >= buffer[0].length) {
155 return null;
156 }
157
158 return buffer[row][column];
159 }
160
161 @Override
162 public void copyTo(TextImage destination) {
163 copyTo(destination, 0, buffer.length, 0, buffer[0].length, 0, 0);
164 }
165
166 @Override
167 public void copyTo(
168 TextImage destination,
169 int startRowIndex,
170 int rows,
171 int startColumnIndex,
172 int columns,
173 int destinationRowOffset,
174 int destinationColumnOffset) {
175
176 // If the source image position is negative, offset the whole image
177 if(startColumnIndex < 0) {
178 destinationColumnOffset += -startColumnIndex;
179 columns += startColumnIndex;
180 startColumnIndex = 0;
181 }
182 if(startRowIndex < 0) {
183 startRowIndex += -startRowIndex;
184 rows = startRowIndex;
185 startRowIndex = 0;
186 }
187
188 // If the destination offset is negative, adjust the source start indexes
189 if(destinationColumnOffset < 0) {
190 startColumnIndex -= destinationColumnOffset;
191 columns += destinationColumnOffset;
192 destinationColumnOffset = 0;
193 }
194 if(destinationRowOffset < 0) {
195 startRowIndex -= destinationRowOffset;
196 rows += destinationRowOffset;
197 destinationRowOffset = 0;
198 }
199
200 //Make sure we can't copy more than is available
201 columns = Math.min(buffer[0].length - startColumnIndex, columns);
202 rows = Math.min(buffer.length - startRowIndex, rows);
203
204 //Adjust target lengths as well
205 columns = Math.min(destination.getSize().getColumns() - destinationColumnOffset, columns);
206 rows = Math.min(destination.getSize().getRows() - destinationRowOffset, rows);
207
208 if(columns <= 0 || rows <= 0) {
209 return;
210 }
211
212 TerminalSize destinationSize = destination.getSize();
213 if(destination instanceof BasicTextImage) {
214 int targetRow = destinationRowOffset;
215 for(int y = startRowIndex; y < startRowIndex + rows && targetRow < destinationSize.getRows(); y++) {
216 System.arraycopy(buffer[y], startColumnIndex, ((BasicTextImage)destination).buffer[targetRow++], destinationColumnOffset, columns);
217 }
218 }
219 else {
220 //Manually copy character by character
221 for(int y = startRowIndex; y < startRowIndex + rows; y++) {
222 for(int x = startColumnIndex; x < startColumnIndex + columns; x++) {
223 destination.setCharacterAt(
224 x - startColumnIndex + destinationColumnOffset,
225 y - startRowIndex + destinationRowOffset,
226 buffer[y][x]);
227 }
228 }
229 }
230 }
231
232 @Override
233 public TextGraphics newTextGraphics() {
234 return new AbstractTextGraphics() {
235 @Override
236 public TextGraphics setCharacter(int columnIndex, int rowIndex, TextCharacter textCharacter) {
237 BasicTextImage.this.setCharacterAt(columnIndex, rowIndex, textCharacter);
238 return this;
239 }
240
241 @Override
242 public TextCharacter getCharacter(int column, int row) {
243 return BasicTextImage.this.getCharacterAt(column, row);
244 }
245
246 @Override
247 public TerminalSize getSize() {
248 return size;
249 }
250 };
251 }
252
253 private TextCharacter[] newBlankLine() {
254 TextCharacter[] line = new TextCharacter[size.getColumns()];
255 Arrays.fill(line, TextCharacter.DEFAULT_CHARACTER);
256 return line;
257 }
258
259 @Override
260 public void scrollLines(int firstLine, int lastLine, int distance) {
261 if (firstLine < 0) { firstLine = 0; }
262 if (lastLine >= size.getRows()) { lastLine = size.getRows() - 1; }
263 if (firstLine < lastLine) {
264 if (distance > 0) {
265 // scrolling up: start with first line as target:
266 int curLine = firstLine;
267 // copy lines from further "below":
268 for (; curLine <= lastLine - distance; curLine++) {
269 buffer[curLine] = buffer[curLine+distance];
270 }
271 // blank out the remaining lines:
272 for (; curLine <= lastLine; curLine++) {
273 buffer[curLine] = newBlankLine();
274 }
275 }
276 else if (distance < 0) {
277 // scrolling down: start with last line as target:
278 int curLine = lastLine; distance = -distance;
279 // copy lines from further "above":
280 for (; curLine >= firstLine + distance; curLine--) {
281 buffer[curLine] = buffer[curLine-distance];
282 }
283 // blank out the remaining lines:
284 for (; curLine >= firstLine; curLine--) {
285 buffer[curLine] = newBlankLine();
286 }
287 } /* else: distance == 0 => no-op */
288 }
289 }
290
291 @Override
292 public String toString() {
293 StringBuilder sb = new StringBuilder(size.getRows()*(size.getColumns()+1)+50);
294 sb.append('{').append(size.getColumns()).append('x').append(size.getRows()).append('}').append('\n');
295 for (TextCharacter[] line : buffer) {
296 for (TextCharacter tc : line) {
297 sb.append(tc.getCharacter());
298 }
299 sb.append('\n');
300 }
301 return sb.toString();
302 }
303 }