#18 move to event-driven main loop
[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 for (Screen screen: screens) {
186 if (screen.isDirty()) {
187 return true;
188 }
189 }
190 return false;
191 }
192
193 /**
194 * Get the attributes at one location.
195 *
196 * @param x column coordinate. 0 is the left-most column.
197 * @param y row coordinate. 0 is the top-most row.
198 * @return attributes at (x, y)
199 */
200 public CellAttributes getAttrXY(final int x, final int y) {
201 return screens.get(0).getAttrXY(x, y);
202 }
203
204 /**
205 * Get the cell at one location.
206 *
207 * @param x column coordinate. 0 is the left-most column.
208 * @param y row coordinate. 0 is the top-most row.
209 * @return the character + attributes
210 */
211 public Cell getCharXY(final int x, final int y) {
212 return screens.get(0).getCharXY(x, y);
213 }
214
215 /**
216 * Set the attributes at one location.
217 *
218 * @param x column coordinate. 0 is the left-most column.
219 * @param y row coordinate. 0 is the top-most row.
220 * @param attr attributes to use (bold, foreColor, backColor)
221 */
222 public void putAttrXY(final int x, final int y,
223 final CellAttributes attr) {
224
225 for (Screen screen: screens) {
226 screen.putAttrXY(x, y, attr);
227 }
228 }
229
230 /**
231 * Set the attributes at one location.
232 *
233 * @param x column coordinate. 0 is the left-most column.
234 * @param y row coordinate. 0 is the top-most row.
235 * @param attr attributes to use (bold, foreColor, backColor)
236 * @param clip if true, honor clipping/offset
237 */
238 public void putAttrXY(final int x, final int y,
239 final CellAttributes attr, final boolean clip) {
240
241 for (Screen screen: screens) {
242 screen.putAttrXY(x, y, attr, clip);
243 }
244 }
245
246 /**
247 * Fill the entire screen with one character with attributes.
248 *
249 * @param ch character to draw
250 * @param attr attributes to use (bold, foreColor, backColor)
251 */
252 public void putAll(final char ch, final CellAttributes attr) {
253 for (Screen screen: screens) {
254 screen.putAll(ch, attr);
255 }
256 }
257
258 /**
259 * Render one character with attributes.
260 *
261 * @param x column coordinate. 0 is the left-most column.
262 * @param y row coordinate. 0 is the top-most row.
263 * @param ch character + attributes to draw
264 */
265 public void putCharXY(final int x, final int y, final Cell ch) {
266 for (Screen screen: screens) {
267 screen.putCharXY(x, y, ch);
268 }
269 }
270
271 /**
272 * Render one character with attributes.
273 *
274 * @param x column coordinate. 0 is the left-most column.
275 * @param y row coordinate. 0 is the top-most row.
276 * @param ch character to draw
277 * @param attr attributes to use (bold, foreColor, backColor)
278 */
279 public void putCharXY(final int x, final int y, final char ch,
280 final CellAttributes attr) {
281
282 for (Screen screen: screens) {
283 screen.putCharXY(x, y, ch, attr);
284 }
285 }
286
287 /**
288 * Render one character without changing the underlying attributes.
289 *
290 * @param x column coordinate. 0 is the left-most column.
291 * @param y row coordinate. 0 is the top-most row.
292 * @param ch character to draw
293 */
294 public void putCharXY(final int x, final int y, final char ch) {
295 for (Screen screen: screens) {
296 screen.putCharXY(x, y, ch);
297 }
298 }
299
300 /**
301 * Render a string. Does not wrap if the string exceeds the line.
302 *
303 * @param x column coordinate. 0 is the left-most column.
304 * @param y row coordinate. 0 is the top-most row.
305 * @param str string to draw
306 * @param attr attributes to use (bold, foreColor, backColor)
307 */
308 public void putStringXY(final int x, final int y, final String str,
309 final CellAttributes attr) {
310
311 for (Screen screen: screens) {
312 screen.putStringXY(x, y, str, attr);
313 }
314 }
315
316 /**
317 * Render a string without changing the underlying attribute. Does not
318 * wrap if the string exceeds the line.
319 *
320 * @param x column coordinate. 0 is the left-most column.
321 * @param y row coordinate. 0 is the top-most row.
322 * @param str string to draw
323 */
324 public void putStringXY(final int x, final int y, final String str) {
325 for (Screen screen: screens) {
326 screen.putStringXY(x, y, str);
327 }
328 }
329
330 /**
331 * Draw a vertical line from (x, y) to (x, y + n).
332 *
333 * @param x column coordinate. 0 is the left-most column.
334 * @param y row coordinate. 0 is the top-most row.
335 * @param n number of characters to draw
336 * @param ch character to draw
337 * @param attr attributes to use (bold, foreColor, backColor)
338 */
339 public void vLineXY(final int x, final int y, final int n,
340 final char ch, final CellAttributes attr) {
341
342 for (Screen screen: screens) {
343 screen.vLineXY(x, y, n, ch, attr);
344 }
345 }
346
347 /**
348 * Draw a horizontal line from (x, y) to (x + n, y).
349 *
350 * @param x column coordinate. 0 is the left-most column.
351 * @param y row coordinate. 0 is the top-most row.
352 * @param n number of characters to draw
353 * @param ch character to draw
354 * @param attr attributes to use (bold, foreColor, backColor)
355 */
356 public void hLineXY(final int x, final int y, final int n,
357 final char ch, final CellAttributes attr) {
358
359 for (Screen screen: screens) {
360 screen.hLineXY(x, y, n, ch, attr);
361 }
362 }
363
364 /**
365 * Change the width. Everything on-screen will be destroyed and must be
366 * redrawn.
367 *
368 * @param width new screen width
369 */
370 public void setWidth(final int width) {
371 for (Screen screen: screens) {
372 screen.setWidth(width);
373 }
374 }
375
376 /**
377 * Change the height. Everything on-screen will be destroyed and must be
378 * redrawn.
379 *
380 * @param height new screen height
381 */
382 public void setHeight(final int height) {
383 for (Screen screen: screens) {
384 screen.setHeight(height);
385 }
386 }
387
388 /**
389 * Change the width and height. Everything on-screen will be destroyed
390 * and must be redrawn.
391 *
392 * @param width new screen width
393 * @param height new screen height
394 */
395 public void setDimensions(final int width, final int height) {
396 for (Screen screen: screens) {
397 screen.setDimensions(width, height);
398 }
399 }
400
401 /**
402 * Get the height.
403 *
404 * @return current screen height
405 */
406 public int getHeight() {
407 return screens.get(0).getHeight();
408 }
409
410 /**
411 * Get the width.
412 *
413 * @return current screen width
414 */
415 public int getWidth() {
416 return screens.get(0).getWidth();
417 }
418
419 /**
420 * Reset screen to not-bold, white-on-black. Also flushes the offset and
421 * clip variables.
422 */
423 public void reset() {
424 for (Screen screen: screens) {
425 screen.reset();
426 }
427 }
428
429 /**
430 * Flush the offset and clip variables.
431 */
432 public void resetClipping() {
433 for (Screen screen: screens) {
434 screen.resetClipping();
435 }
436 }
437
438 /**
439 * Clear the logical screen.
440 */
441 public void clear() {
442 for (Screen screen: screens) {
443 screen.clear();
444 }
445 }
446
447 /**
448 * Draw a box with a border and empty background.
449 *
450 * @param left left column of box. 0 is the left-most row.
451 * @param top top row of the box. 0 is the top-most row.
452 * @param right right column of box
453 * @param bottom bottom row of the box
454 * @param border attributes to use for the border
455 * @param background attributes to use for the background
456 */
457 public void drawBox(final int left, final int top,
458 final int right, final int bottom,
459 final CellAttributes border, final CellAttributes background) {
460
461 for (Screen screen: screens) {
462 screen.drawBox(left, top, right, bottom, border, background);
463 }
464 }
465
466 /**
467 * Draw a box with a border and empty background.
468 *
469 * @param left left column of box. 0 is the left-most row.
470 * @param top top row of the box. 0 is the top-most row.
471 * @param right right column of box
472 * @param bottom bottom row of the box
473 * @param border attributes to use for the border
474 * @param background attributes to use for the background
475 * @param borderType if 1, draw a single-line border; if 2, draw a
476 * double-line border; if 3, draw double-line top/bottom edges and
477 * single-line left/right edges (like Qmodem)
478 * @param shadow if true, draw a "shadow" on the box
479 */
480 public void drawBox(final int left, final int top,
481 final int right, final int bottom,
482 final CellAttributes border, final CellAttributes background,
483 final int borderType, final boolean shadow) {
484
485 for (Screen screen: screens) {
486 screen.drawBox(left, top, right, bottom, border, background,
487 borderType, shadow);
488 }
489 }
490
491 /**
492 * Draw a box shadow.
493 *
494 * @param left left column of box. 0 is the left-most row.
495 * @param top top row of the box. 0 is the top-most row.
496 * @param right right column of box
497 * @param bottom bottom row of the box
498 */
499 public void drawBoxShadow(final int left, final int top,
500 final int right, final int bottom) {
501
502 for (Screen screen: screens) {
503 screen.drawBoxShadow(left, top, right, bottom);
504 }
505 }
506
507 /**
508 * Classes must provide an implementation to push the logical screen to
509 * the physical device.
510 */
511 public void flushPhysical() {
512 for (Screen screen: screens) {
513 screen.flushPhysical();
514 }
515 }
516
517 /**
518 * Put the cursor at (x,y).
519 *
520 * @param visible if true, the cursor should be visible
521 * @param x column coordinate to put the cursor on
522 * @param y row coordinate to put the cursor on
523 */
524 public void putCursor(final boolean visible, final int x, final int y) {
525 for (Screen screen: screens) {
526 screen.putCursor(visible, x, y);
527 }
528 }
529
530 /**
531 * Hide the cursor.
532 */
533 public void hideCursor() {
534 for (Screen screen: screens) {
535 screen.hideCursor();
536 }
537 }
538
539 /**
540 * Get the cursor visibility.
541 *
542 * @return true if the cursor is visible
543 */
544 public boolean isCursorVisible() {
545 return screens.get(0).isCursorVisible();
546 }
547
548 /**
549 * Get the cursor X position.
550 *
551 * @return the cursor x column position
552 */
553 public int getCursorX() {
554 return screens.get(0).getCursorX();
555 }
556
557 /**
558 * Get the cursor Y position.
559 *
560 * @return the cursor y row position
561 */
562 public int getCursorY() {
563 return screens.get(0).getCursorY();
564 }
565
566 /**
567 * Set the window title.
568 *
569 * @param title the new title
570 */
571 public void setTitle(final String title) {
572 for (Screen screen: screens) {
573 screen.setTitle(title);
574 }
575 }
576
577}