Bug fixes
[fanfix.git] / src / jexer / backend / MultiScreen.java
... / ...
CommitLineData
1/*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2017 Kevin Lamonte
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer.backend;
30
31import java.util.LinkedList;
32import java.util.List;
33
34import jexer.bits.Cell;
35import jexer.bits.CellAttributes;
36
37/**
38 * MultiScreen mirrors its I/O to several screens.
39 */
40public class MultiScreen implements Screen {
41
42 /**
43 * The list of screens to use.
44 */
45 private List<Screen> screens = new LinkedList<Screen>();
46
47 /**
48 * Public constructor requires one screen.
49 *
50 * @param screen the screen to add
51 */
52 public MultiScreen(final Screen screen) {
53 screens.add(screen);
54 }
55
56 /**
57 * Add a screen to the list.
58 *
59 * @param screen the screen to add
60 */
61 public void addScreen(final Screen screen) {
62 screens.add(screen);
63 }
64
65 /**
66 * Remove a screen from the list.
67 *
68 * @param screen the screen to remove
69 */
70 public void removeScreen(final Screen screen) {
71 if (screens.size() > 1) {
72 screens.remove(screen);
73 }
74 }
75
76 /**
77 * Set drawing offset for x.
78 *
79 * @param offsetX new drawing offset
80 */
81 public void setOffsetX(final int offsetX) {
82 for (Screen screen: screens) {
83 screen.setOffsetX(offsetX);
84 }
85 }
86
87 /**
88 * Set drawing offset for y.
89 *
90 * @param offsetY new drawing offset
91 */
92 public void setOffsetY(final int offsetY) {
93 for (Screen screen: screens) {
94 screen.setOffsetY(offsetY);
95 }
96 }
97
98 /**
99 * Get right drawing clipping boundary.
100 *
101 * @return drawing boundary
102 */
103 public int getClipRight() {
104 return screens.get(0).getClipRight();
105 }
106
107 /**
108 * Set right drawing clipping boundary.
109 *
110 * @param clipRight new boundary
111 */
112 public void setClipRight(final int clipRight) {
113 for (Screen screen: screens) {
114 screen.setClipRight(clipRight);
115 }
116 }
117
118 /**
119 * Get bottom drawing clipping boundary.
120 *
121 * @return drawing boundary
122 */
123 public int getClipBottom() {
124 return screens.get(0).getClipBottom();
125 }
126
127 /**
128 * Set bottom drawing clipping boundary.
129 *
130 * @param clipBottom new boundary
131 */
132 public void setClipBottom(final int clipBottom) {
133 for (Screen screen: screens) {
134 screen.setClipBottom(clipBottom);
135 }
136 }
137
138 /**
139 * Get left drawing clipping boundary.
140 *
141 * @return drawing boundary
142 */
143 public int getClipLeft() {
144 return screens.get(0).getClipLeft();
145 }
146
147 /**
148 * Set left drawing clipping boundary.
149 *
150 * @param clipLeft new boundary
151 */
152 public void setClipLeft(final int clipLeft) {
153 for (Screen screen: screens) {
154 screen.setClipLeft(clipLeft);
155 }
156 }
157
158 /**
159 * Get top drawing clipping boundary.
160 *
161 * @return drawing boundary
162 */
163 public int getClipTop() {
164 return screens.get(0).getClipTop();
165 }
166
167 /**
168 * Set top drawing clipping boundary.
169 *
170 * @param clipTop new boundary
171 */
172 public void setClipTop(final int clipTop) {
173 for (Screen screen: screens) {
174 screen.setClipTop(clipTop);
175 }
176 }
177
178 /**
179 * Get dirty flag.
180 *
181 * @return if true, the logical screen is not in sync with the physical
182 * screen
183 */
184 public boolean isDirty() {
185 return screens.get(0).isDirty();
186 }
187
188 /**
189 * Get the attributes at one location.
190 *
191 * @param x column coordinate. 0 is the left-most column.
192 * @param y row coordinate. 0 is the top-most row.
193 * @return attributes at (x, y)
194 */
195 public CellAttributes getAttrXY(final int x, final int y) {
196 return screens.get(0).getAttrXY(x, y);
197 }
198
199 /**
200 * Get the cell at one location.
201 *
202 * @param x column coordinate. 0 is the left-most column.
203 * @param y row coordinate. 0 is the top-most row.
204 * @return the character + attributes
205 */
206 public Cell getCharXY(final int x, final int y) {
207 return screens.get(0).getCharXY(x, y);
208 }
209
210 /**
211 * Set the attributes at one location.
212 *
213 * @param x column coordinate. 0 is the left-most column.
214 * @param y row coordinate. 0 is the top-most row.
215 * @param attr attributes to use (bold, foreColor, backColor)
216 */
217 public void putAttrXY(final int x, final int y,
218 final CellAttributes attr) {
219
220 for (Screen screen: screens) {
221 screen.putAttrXY(x, y, attr);
222 }
223 }
224
225 /**
226 * Set the attributes at one location.
227 *
228 * @param x column coordinate. 0 is the left-most column.
229 * @param y row coordinate. 0 is the top-most row.
230 * @param attr attributes to use (bold, foreColor, backColor)
231 * @param clip if true, honor clipping/offset
232 */
233 public void putAttrXY(final int x, final int y,
234 final CellAttributes attr, final boolean clip) {
235
236 for (Screen screen: screens) {
237 screen.putAttrXY(x, y, attr, clip);
238 }
239 }
240
241 /**
242 * Fill the entire screen with one character with attributes.
243 *
244 * @param ch character to draw
245 * @param attr attributes to use (bold, foreColor, backColor)
246 */
247 public void putAll(final char ch, final CellAttributes attr) {
248 for (Screen screen: screens) {
249 screen.putAll(ch, attr);
250 }
251 }
252
253 /**
254 * Render one character with attributes.
255 *
256 * @param x column coordinate. 0 is the left-most column.
257 * @param y row coordinate. 0 is the top-most row.
258 * @param ch character + attributes to draw
259 */
260 public void putCharXY(final int x, final int y, final Cell ch) {
261 for (Screen screen: screens) {
262 screen.putCharXY(x, y, ch);
263 }
264 }
265
266 /**
267 * Render one character with attributes.
268 *
269 * @param x column coordinate. 0 is the left-most column.
270 * @param y row coordinate. 0 is the top-most row.
271 * @param ch character to draw
272 * @param attr attributes to use (bold, foreColor, backColor)
273 */
274 public void putCharXY(final int x, final int y, final char ch,
275 final CellAttributes attr) {
276
277 for (Screen screen: screens) {
278 screen.putCharXY(x, y, ch, attr);
279 }
280 }
281
282 /**
283 * Render one character without changing the underlying attributes.
284 *
285 * @param x column coordinate. 0 is the left-most column.
286 * @param y row coordinate. 0 is the top-most row.
287 * @param ch character to draw
288 */
289 public void putCharXY(final int x, final int y, final char ch) {
290 for (Screen screen: screens) {
291 screen.putCharXY(x, y, ch);
292 }
293 }
294
295 /**
296 * Render a string. Does not wrap if the string exceeds the line.
297 *
298 * @param x column coordinate. 0 is the left-most column.
299 * @param y row coordinate. 0 is the top-most row.
300 * @param str string to draw
301 * @param attr attributes to use (bold, foreColor, backColor)
302 */
303 public void putStringXY(final int x, final int y, final String str,
304 final CellAttributes attr) {
305
306 for (Screen screen: screens) {
307 screen.putStringXY(x, y, str, attr);
308 }
309 }
310
311 /**
312 * Render a string without changing the underlying attribute. Does not
313 * wrap if the string exceeds the line.
314 *
315 * @param x column coordinate. 0 is the left-most column.
316 * @param y row coordinate. 0 is the top-most row.
317 * @param str string to draw
318 */
319 public void putStringXY(final int x, final int y, final String str) {
320 for (Screen screen: screens) {
321 screen.putStringXY(x, y, str);
322 }
323 }
324
325 /**
326 * Draw a vertical line from (x, y) to (x, y + n).
327 *
328 * @param x column coordinate. 0 is the left-most column.
329 * @param y row coordinate. 0 is the top-most row.
330 * @param n number of characters to draw
331 * @param ch character to draw
332 * @param attr attributes to use (bold, foreColor, backColor)
333 */
334 public void vLineXY(final int x, final int y, final int n,
335 final char ch, final CellAttributes attr) {
336
337 for (Screen screen: screens) {
338 screen.vLineXY(x, y, n, ch, attr);
339 }
340 }
341
342 /**
343 * Draw a horizontal line from (x, y) to (x + n, y).
344 *
345 * @param x column coordinate. 0 is the left-most column.
346 * @param y row coordinate. 0 is the top-most row.
347 * @param n number of characters to draw
348 * @param ch character to draw
349 * @param attr attributes to use (bold, foreColor, backColor)
350 */
351 public void hLineXY(final int x, final int y, final int n,
352 final char ch, final CellAttributes attr) {
353
354 for (Screen screen: screens) {
355 screen.hLineXY(x, y, n, ch, attr);
356 }
357 }
358
359 /**
360 * Change the width. Everything on-screen will be destroyed and must be
361 * redrawn.
362 *
363 * @param width new screen width
364 */
365 public void setWidth(final int width) {
366 for (Screen screen: screens) {
367 screen.setWidth(width);
368 }
369 }
370
371 /**
372 * Change the height. Everything on-screen will be destroyed and must be
373 * redrawn.
374 *
375 * @param height new screen height
376 */
377 public void setHeight(final int height) {
378 for (Screen screen: screens) {
379 screen.setHeight(height);
380 }
381 }
382
383 /**
384 * Change the width and height. Everything on-screen will be destroyed
385 * and must be redrawn.
386 *
387 * @param width new screen width
388 * @param height new screen height
389 */
390 public void setDimensions(final int width, final int height) {
391 for (Screen screen: screens) {
392 screen.setDimensions(width, height);
393 }
394 }
395
396 /**
397 * Get the height.
398 *
399 * @return current screen height
400 */
401 public int getHeight() {
402 return screens.get(0).getHeight();
403 }
404
405 /**
406 * Get the width.
407 *
408 * @return current screen width
409 */
410 public int getWidth() {
411 return screens.get(0).getWidth();
412 }
413
414 /**
415 * Reset screen to not-bold, white-on-black. Also flushes the offset and
416 * clip variables.
417 */
418 public void reset() {
419 for (Screen screen: screens) {
420 screen.reset();
421 }
422 }
423
424 /**
425 * Flush the offset and clip variables.
426 */
427 public void resetClipping() {
428 for (Screen screen: screens) {
429 screen.resetClipping();
430 }
431 }
432
433 /**
434 * Clear the logical screen.
435 */
436 public void clear() {
437 for (Screen screen: screens) {
438 screen.clear();
439 }
440 }
441
442 /**
443 * Draw a box with a border and empty background.
444 *
445 * @param left left column of box. 0 is the left-most row.
446 * @param top top row of the box. 0 is the top-most row.
447 * @param right right column of box
448 * @param bottom bottom row of the box
449 * @param border attributes to use for the border
450 * @param background attributes to use for the background
451 */
452 public void drawBox(final int left, final int top,
453 final int right, final int bottom,
454 final CellAttributes border, final CellAttributes background) {
455
456 for (Screen screen: screens) {
457 screen.drawBox(left, top, right, bottom, border, background);
458 }
459 }
460
461 /**
462 * Draw a box with a border and empty background.
463 *
464 * @param left left column of box. 0 is the left-most row.
465 * @param top top row of the box. 0 is the top-most row.
466 * @param right right column of box
467 * @param bottom bottom row of the box
468 * @param border attributes to use for the border
469 * @param background attributes to use for the background
470 * @param borderType if 1, draw a single-line border; if 2, draw a
471 * double-line border; if 3, draw double-line top/bottom edges and
472 * single-line left/right edges (like Qmodem)
473 * @param shadow if true, draw a "shadow" on the box
474 */
475 public void drawBox(final int left, final int top,
476 final int right, final int bottom,
477 final CellAttributes border, final CellAttributes background,
478 final int borderType, final boolean shadow) {
479
480 for (Screen screen: screens) {
481 screen.drawBox(left, top, right, bottom, border, background,
482 borderType, shadow);
483 }
484 }
485
486 /**
487 * Draw a box shadow.
488 *
489 * @param left left column of box. 0 is the left-most row.
490 * @param top top row of the box. 0 is the top-most row.
491 * @param right right column of box
492 * @param bottom bottom row of the box
493 */
494 public void drawBoxShadow(final int left, final int top,
495 final int right, final int bottom) {
496
497 for (Screen screen: screens) {
498 screen.drawBoxShadow(left, top, right, bottom);
499 }
500 }
501
502 /**
503 * Classes must provide an implementation to push the logical screen to
504 * the physical device.
505 */
506 public void flushPhysical() {
507 for (Screen screen: screens) {
508 screen.flushPhysical();
509 }
510 }
511
512 /**
513 * Put the cursor at (x,y).
514 *
515 * @param visible if true, the cursor should be visible
516 * @param x column coordinate to put the cursor on
517 * @param y row coordinate to put the cursor on
518 */
519 public void putCursor(final boolean visible, final int x, final int y) {
520 for (Screen screen: screens) {
521 screen.putCursor(visible, x, y);
522 }
523 }
524
525 /**
526 * Hide the cursor.
527 */
528 public void hideCursor() {
529 for (Screen screen: screens) {
530 screen.hideCursor();
531 }
532 }
533
534 /**
535 * Get the cursor visibility.
536 *
537 * @return true if the cursor is visible
538 */
539 public boolean isCursorVisible() {
540 return screens.get(0).isCursorVisible();
541 }
542
543 /**
544 * Get the cursor X position.
545 *
546 * @return the cursor x column position
547 */
548 public int getCursorX() {
549 return screens.get(0).getCursorX();
550 }
551
552 /**
553 * Get the cursor Y position.
554 *
555 * @return the cursor y row position
556 */
557 public int getCursorY() {
558 return screens.get(0).getCursorY();
559 }
560
561 /**
562 * Set the window title.
563 *
564 * @param title the new title
565 */
566 public void setTitle(final String title) {
567 for (Screen screen: screens) {
568 screen.setTitle(title);
569 }
570 }
571
572}