PMD code sweep, #6 don't add MyWindow twice to MyApplication
[nikiroo-utils.git] / src / jexer / backend / LogicalScreen.java
CommitLineData
daa4106c 1/*
df8de03f
KL
2 * Jexer - Java Text User Interface
3 *
e16dda65 4 * The MIT License (MIT)
df8de03f 5 *
a2018e99 6 * Copyright (C) 2017 Kevin Lamonte
df8de03f 7 *
e16dda65
KL
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:
df8de03f 14 *
e16dda65
KL
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
df8de03f 17 *
e16dda65
KL
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.
7b5261bc
KL
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
df8de03f 28 */
42873e30 29package jexer.backend;
df8de03f
KL
30
31import jexer.bits.Cell;
32import jexer.bits.CellAttributes;
33import jexer.bits.GraphicsChars;
34
35/**
42873e30 36 * A logical screen composed of a 2D array of Cells.
df8de03f 37 */
42873e30 38public class LogicalScreen implements Screen {
df8de03f 39
d36057df
KL
40 // ------------------------------------------------------------------------
41 // Variables --------------------------------------------------------------
42 // ------------------------------------------------------------------------
43
df8de03f 44 /**
7b5261bc 45 * Width of the visible window.
df8de03f
KL
46 */
47 protected int width;
48
49 /**
7b5261bc 50 * Height of the visible window.
df8de03f
KL
51 */
52 protected int height;
53
54 /**
7b5261bc 55 * Drawing offset for x.
df8de03f 56 */
fca67db0 57 private int offsetX;
48e27807 58
d36057df
KL
59 /**
60 * Drawing offset for y.
61 */
62 private int offsetY;
63
64 /**
65 * Ignore anything drawn right of clipRight.
66 */
67 private int clipRight;
68
69 /**
70 * Ignore anything drawn below clipBottom.
71 */
72 private int clipBottom;
73
74 /**
75 * Ignore anything drawn left of clipLeft.
76 */
77 private int clipLeft;
78
79 /**
80 * Ignore anything drawn above clipTop.
81 */
82 private int clipTop;
83
84 /**
85 * The physical screen last sent out on flush().
86 */
87 protected Cell [][] physical;
88
89 /**
90 * The logical screen being rendered to.
91 */
92 protected Cell [][] logical;
93
94 /**
95 * Set if the user explicitly wants to redraw everything starting with a
96 * ECMATerminal.clearAll().
97 */
98 protected boolean reallyCleared;
99
100 /**
101 * If true, the cursor is visible and should be placed onscreen at
102 * (cursorX, cursorY) during a call to flushPhysical().
103 */
104 protected boolean cursorVisible;
105
106 /**
107 * Cursor X position if visible.
108 */
109 protected int cursorX;
110
111 /**
112 * Cursor Y position if visible.
113 */
114 protected int cursorY;
115
116 // ------------------------------------------------------------------------
117 // Constructors -----------------------------------------------------------
118 // ------------------------------------------------------------------------
119
120 /**
121 * Public constructor. Sets everything to not-bold, white-on-black.
122 */
123 protected LogicalScreen() {
124 offsetX = 0;
125 offsetY = 0;
126 width = 80;
127 height = 24;
128 logical = null;
129 physical = null;
130 reallocate(width, height);
131 }
132
133 // ------------------------------------------------------------------------
134 // Screen -----------------------------------------------------------------
135 // ------------------------------------------------------------------------
136
48e27807
KL
137 /**
138 * Set drawing offset for x.
139 *
140 * @param offsetX new drawing offset
141 */
142 public final void setOffsetX(final int offsetX) {
143 this.offsetX = offsetX;
144 }
df8de03f 145
48e27807
KL
146 /**
147 * Set drawing offset for y.
148 *
149 * @param offsetY new drawing offset
150 */
151 public final void setOffsetY(final int offsetY) {
152 this.offsetY = offsetY;
153 }
fca67db0 154
48e27807
KL
155 /**
156 * Get right drawing clipping boundary.
157 *
158 * @return drawing boundary
159 */
160 public final int getClipRight() {
161 return clipRight;
162 }
163
164 /**
165 * Set right drawing clipping boundary.
166 *
167 * @param clipRight new boundary
168 */
169 public final void setClipRight(final int clipRight) {
170 this.clipRight = clipRight;
171 }
df8de03f 172
48e27807
KL
173 /**
174 * Get bottom drawing clipping boundary.
175 *
176 * @return drawing boundary
177 */
178 public final int getClipBottom() {
179 return clipBottom;
180 }
181
182 /**
183 * Set bottom drawing clipping boundary.
184 *
185 * @param clipBottom new boundary
186 */
187 public final void setClipBottom(final int clipBottom) {
188 this.clipBottom = clipBottom;
189 }
df8de03f 190
48e27807
KL
191 /**
192 * Get left drawing clipping boundary.
193 *
194 * @return drawing boundary
195 */
196 public final int getClipLeft() {
197 return clipLeft;
198 }
199
200 /**
201 * Set left drawing clipping boundary.
202 *
203 * @param clipLeft new boundary
204 */
205 public final void setClipLeft(final int clipLeft) {
206 this.clipLeft = clipLeft;
207 }
df8de03f 208
48e27807
KL
209 /**
210 * Get top drawing clipping boundary.
211 *
212 * @return drawing boundary
213 */
214 public final int getClipTop() {
215 return clipTop;
216 }
217
218 /**
219 * Set top drawing clipping boundary.
220 *
221 * @param clipTop new boundary
222 */
223 public final void setClipTop(final int clipTop) {
224 this.clipTop = clipTop;
225 }
df8de03f 226
92554d64
KL
227 /**
228 * Get dirty flag.
229 *
230 * @return if true, the logical screen is not in sync with the physical
231 * screen
232 */
233 public final boolean isDirty() {
be72cb5c
KL
234 for (int x = 0; x < width; x++) {
235 for (int y = 0; y < height; y++) {
236 if (!logical[x][y].equals(physical[x][y])) {
237 return true;
238 }
239 if (logical[x][y].isBlink()) {
240 // Blinking screens are always dirty. There is
241 // opportunity for a Netscape blink tag joke here...
242 return true;
243 }
244 }
245 }
246
247 return false;
92554d64
KL
248 }
249
df8de03f
KL
250 /**
251 * Get the attributes at one location.
252 *
253 * @param x column coordinate. 0 is the left-most column.
254 * @param y row coordinate. 0 is the top-most row.
255 * @return attributes at (x, y)
256 */
fca67db0 257 public final CellAttributes getAttrXY(final int x, final int y) {
7b5261bc 258 CellAttributes attr = new CellAttributes();
30bd4abd
KL
259 if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
260 attr.setTo(logical[x][y]);
261 }
7b5261bc 262 return attr;
df8de03f
KL
263 }
264
3e074355
KL
265 /**
266 * Get the cell at one location.
267 *
268 * @param x column coordinate. 0 is the left-most column.
269 * @param y row coordinate. 0 is the top-most row.
270 * @return the character + attributes
271 */
272 public Cell getCharXY(final int x, final int y) {
273 Cell cell = new Cell();
274 if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
275 cell.setTo(logical[x][y]);
276 }
277 return cell;
278 }
279
df8de03f
KL
280 /**
281 * Set the attributes at one location.
282 *
283 * @param x column coordinate. 0 is the left-most column.
284 * @param y row coordinate. 0 is the top-most row.
285 * @param attr attributes to use (bold, foreColor, backColor)
df8de03f 286 */
fca67db0
KL
287 public final void putAttrXY(final int x, final int y,
288 final CellAttributes attr) {
289
7b5261bc 290 putAttrXY(x, y, attr, true);
df8de03f 291 }
7b5261bc 292
df8de03f
KL
293 /**
294 * Set the attributes at one location.
295 *
296 * @param x column coordinate. 0 is the left-most column.
297 * @param y row coordinate. 0 is the top-most row.
298 * @param attr attributes to use (bold, foreColor, backColor)
299 * @param clip if true, honor clipping/offset
300 */
a1879051
KL
301 public final void putAttrXY(final int x, final int y,
302 final CellAttributes attr, final boolean clip) {
7b5261bc
KL
303
304 int X = x;
305 int Y = y;
306
307 if (clip) {
308 if ((x < clipLeft)
309 || (x >= clipRight)
310 || (y < clipTop)
311 || (y >= clipBottom)
312 ) {
313 return;
314 }
315 X += offsetX;
316 Y += offsetY;
317 }
318
319 if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
be72cb5c 320 logical[X][Y].setTo(attr);
24489803
KL
321
322 // If this happens to be the cursor position, make the position
323 // dirty.
324 if ((cursorX == X) && (cursorY == Y)) {
325 if (physical[cursorX][cursorY].getChar() == 'Q') {
326 physical[cursorX][cursorY].setChar('X');
327 } else {
328 physical[cursorX][cursorY].setChar('Q');
329 }
330 }
7b5261bc 331 }
df8de03f
KL
332 }
333
334 /**
335 * Fill the entire screen with one character with attributes.
336 *
337 * @param ch character to draw
338 * @param attr attributes to use (bold, foreColor, backColor)
339 */
fca67db0 340 public final void putAll(final char ch, final CellAttributes attr) {
87a17f3c 341
7b5261bc
KL
342 for (int x = 0; x < width; x++) {
343 for (int y = 0; y < height; y++) {
344 putCharXY(x, y, ch, attr);
345 }
346 }
df8de03f
KL
347 }
348
349 /**
350 * Render one character with attributes.
351 *
352 * @param x column coordinate. 0 is the left-most column.
353 * @param y row coordinate. 0 is the top-most row.
354 * @param ch character + attributes to draw
355 */
fca67db0 356 public final void putCharXY(final int x, final int y, final Cell ch) {
7b5261bc 357 putCharXY(x, y, ch.getChar(), ch);
df8de03f
KL
358 }
359
360 /**
361 * Render one character with attributes.
362 *
363 * @param x column coordinate. 0 is the left-most column.
364 * @param y row coordinate. 0 is the top-most row.
365 * @param ch character to draw
366 * @param attr attributes to use (bold, foreColor, backColor)
367 */
fca67db0 368 public final void putCharXY(final int x, final int y, final char ch,
7b5261bc
KL
369 final CellAttributes attr) {
370
371 if ((x < clipLeft)
372 || (x >= clipRight)
373 || (y < clipTop)
374 || (y >= clipBottom)
375 ) {
376 return;
377 }
378
379 int X = x + offsetX;
380 int Y = y + offsetY;
381
382 // System.err.printf("putCharXY: %d, %d, %c\n", X, Y, ch);
383
384 if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
7b5261bc
KL
385
386 // Do not put control characters on the display
387 assert (ch >= 0x20);
388 assert (ch != 0x7F);
389
be72cb5c 390 logical[X][Y].setTo(attr);
7b5261bc 391 logical[X][Y].setChar(ch);
24489803
KL
392
393 // If this happens to be the cursor position, make the position
394 // dirty.
395 if ((cursorX == X) && (cursorY == Y)) {
396 if (physical[cursorX][cursorY].getChar() == 'Q') {
397 physical[cursorX][cursorY].setChar('X');
398 } else {
399 physical[cursorX][cursorY].setChar('Q');
400 }
401 }
7b5261bc 402 }
df8de03f
KL
403 }
404
405 /**
406 * Render one character without changing the underlying attributes.
407 *
408 * @param x column coordinate. 0 is the left-most column.
409 * @param y row coordinate. 0 is the top-most row.
410 * @param ch character to draw
411 */
fca67db0 412 public final void putCharXY(final int x, final int y, final char ch) {
87a17f3c 413
7b5261bc
KL
414 if ((x < clipLeft)
415 || (x >= clipRight)
416 || (y < clipTop)
417 || (y >= clipBottom)
418 ) {
419 return;
420 }
df8de03f 421
7b5261bc
KL
422 int X = x + offsetX;
423 int Y = y + offsetY;
df8de03f 424
7b5261bc 425 // System.err.printf("putCharXY: %d, %d, %c\n", X, Y, ch);
df8de03f 426
7b5261bc 427 if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
7b5261bc 428 logical[X][Y].setChar(ch);
24489803
KL
429
430 // If this happens to be the cursor position, make the position
431 // dirty.
432 if ((cursorX == X) && (cursorY == Y)) {
433 if (physical[cursorX][cursorY].getChar() == 'Q') {
434 physical[cursorX][cursorY].setChar('X');
435 } else {
436 physical[cursorX][cursorY].setChar('Q');
437 }
438 }
7b5261bc 439 }
df8de03f
KL
440 }
441
442 /**
443 * Render a string. Does not wrap if the string exceeds the line.
444 *
445 * @param x column coordinate. 0 is the left-most column.
446 * @param y row coordinate. 0 is the top-most row.
447 * @param str string to draw
448 * @param attr attributes to use (bold, foreColor, backColor)
449 */
0d47c546 450 public final void putStringXY(final int x, final int y, final String str,
7b5261bc
KL
451 final CellAttributes attr) {
452
453 int i = x;
454 for (int j = 0; j < str.length(); j++) {
455 char ch = str.charAt(j);
456 putCharXY(i, y, ch, attr);
457 i++;
458 if (i == width) {
459 break;
460 }
461 }
df8de03f
KL
462 }
463
464 /**
465 * Render a string without changing the underlying attribute. Does not
466 * wrap if the string exceeds the line.
467 *
468 * @param x column coordinate. 0 is the left-most column.
469 * @param y row coordinate. 0 is the top-most row.
470 * @param str string to draw
471 */
0d47c546 472 public final void putStringXY(final int x, final int y, final String str) {
87a17f3c 473
7b5261bc
KL
474 int i = x;
475 for (int j = 0; j < str.length(); j++) {
476 char ch = str.charAt(j);
477 putCharXY(i, y, ch);
478 i++;
479 if (i == width) {
480 break;
481 }
482 }
df8de03f
KL
483 }
484
485 /**
7b5261bc 486 * Draw a vertical line from (x, y) to (x, y + n).
df8de03f
KL
487 *
488 * @param x column coordinate. 0 is the left-most column.
489 * @param y row coordinate. 0 is the top-most row.
490 * @param n number of characters to draw
491 * @param ch character to draw
492 * @param attr attributes to use (bold, foreColor, backColor)
493 */
fca67db0
KL
494 public final void vLineXY(final int x, final int y, final int n,
495 final char ch, final CellAttributes attr) {
7b5261bc
KL
496
497 for (int i = y; i < y + n; i++) {
498 putCharXY(x, i, ch, attr);
499 }
df8de03f
KL
500 }
501
502 /**
7b5261bc 503 * Draw a horizontal line from (x, y) to (x + n, y).
df8de03f
KL
504 *
505 * @param x column coordinate. 0 is the left-most column.
506 * @param y row coordinate. 0 is the top-most row.
507 * @param n number of characters to draw
508 * @param ch character to draw
509 * @param attr attributes to use (bold, foreColor, backColor)
510 */
fca67db0
KL
511 public final void hLineXY(final int x, final int y, final int n,
512 final char ch, final CellAttributes attr) {
7b5261bc
KL
513
514 for (int i = x; i < x + n; i++) {
515 putCharXY(i, y, ch, attr);
516 }
df8de03f
KL
517 }
518
df8de03f
KL
519 /**
520 * Change the width. Everything on-screen will be destroyed and must be
521 * redrawn.
7b5261bc 522 *
df8de03f
KL
523 * @param width new screen width
524 */
87a17f3c 525 public final synchronized void setWidth(final int width) {
7b5261bc 526 reallocate(width, this.height);
df8de03f
KL
527 }
528
529 /**
530 * Change the height. Everything on-screen will be destroyed and must be
531 * redrawn.
532 *
533 * @param height new screen height
534 */
87a17f3c 535 public final synchronized void setHeight(final int height) {
7b5261bc 536 reallocate(this.width, height);
df8de03f
KL
537 }
538
539 /**
540 * Change the width and height. Everything on-screen will be destroyed
541 * and must be redrawn.
542 *
543 * @param width new screen width
544 * @param height new screen height
545 */
fca67db0 546 public final void setDimensions(final int width, final int height) {
7b5261bc 547 reallocate(width, height);
df8de03f
KL
548 }
549
550 /**
551 * Get the height.
552 *
553 * @return current screen height
554 */
87a17f3c 555 public final synchronized int getHeight() {
7b5261bc 556 return this.height;
df8de03f
KL
557 }
558
559 /**
560 * Get the width.
561 *
562 * @return current screen width
563 */
87a17f3c 564 public final synchronized int getWidth() {
7b5261bc 565 return this.width;
df8de03f
KL
566 }
567
df8de03f
KL
568 /**
569 * Reset screen to not-bold, white-on-black. Also flushes the offset and
570 * clip variables.
571 */
87a17f3c 572 public final synchronized void reset() {
7b5261bc
KL
573 for (int row = 0; row < height; row++) {
574 for (int col = 0; col < width; col++) {
575 logical[col][row].reset();
576 }
577 }
578 resetClipping();
df8de03f
KL
579 }
580
581 /**
582 * Flush the offset and clip variables.
583 */
fca67db0 584 public final void resetClipping() {
7b5261bc
KL
585 offsetX = 0;
586 offsetY = 0;
587 clipLeft = 0;
588 clipTop = 0;
589 clipRight = width;
590 clipBottom = height;
df8de03f
KL
591 }
592
593 /**
bd8d51fa 594 * Clear the logical screen.
df8de03f 595 */
fca67db0 596 public final void clear() {
7b5261bc 597 reset();
df8de03f
KL
598 }
599
600 /**
601 * Draw a box with a border and empty background.
602 *
603 * @param left left column of box. 0 is the left-most row.
604 * @param top top row of the box. 0 is the top-most row.
605 * @param right right column of box
606 * @param bottom bottom row of the box
7b5261bc 607 * @param border attributes to use for the border
df8de03f
KL
608 * @param background attributes to use for the background
609 */
fca67db0 610 public final void drawBox(final int left, final int top,
7b5261bc
KL
611 final int right, final int bottom,
612 final CellAttributes border, final CellAttributes background) {
613
614 drawBox(left, top, right, bottom, border, background, 1, false);
df8de03f
KL
615 }
616
617 /**
618 * Draw a box with a border and empty background.
619 *
620 * @param left left column of box. 0 is the left-most row.
621 * @param top top row of the box. 0 is the top-most row.
622 * @param right right column of box
623 * @param bottom bottom row of the box
7b5261bc 624 * @param border attributes to use for the border
df8de03f 625 * @param background attributes to use for the background
7b5261bc
KL
626 * @param borderType if 1, draw a single-line border; if 2, draw a
627 * double-line border; if 3, draw double-line top/bottom edges and
628 * single-line left/right edges (like Qmodem)
df8de03f
KL
629 * @param shadow if true, draw a "shadow" on the box
630 */
fca67db0 631 public final void drawBox(final int left, final int top,
7b5261bc
KL
632 final int right, final int bottom,
633 final CellAttributes border, final CellAttributes background,
634 final int borderType, final boolean shadow) {
635
7b5261bc
KL
636 int boxWidth = right - left;
637 int boxHeight = bottom - top;
638
639 char cTopLeft;
640 char cTopRight;
641 char cBottomLeft;
642 char cBottomRight;
643 char cHSide;
644 char cVSide;
645
646 switch (borderType) {
647 case 1:
648 cTopLeft = GraphicsChars.ULCORNER;
649 cTopRight = GraphicsChars.URCORNER;
650 cBottomLeft = GraphicsChars.LLCORNER;
651 cBottomRight = GraphicsChars.LRCORNER;
652 cHSide = GraphicsChars.SINGLE_BAR;
653 cVSide = GraphicsChars.WINDOW_SIDE;
654 break;
655
656 case 2:
657 cTopLeft = GraphicsChars.WINDOW_LEFT_TOP_DOUBLE;
658 cTopRight = GraphicsChars.WINDOW_RIGHT_TOP_DOUBLE;
659 cBottomLeft = GraphicsChars.WINDOW_LEFT_BOTTOM_DOUBLE;
660 cBottomRight = GraphicsChars.WINDOW_RIGHT_BOTTOM_DOUBLE;
661 cHSide = GraphicsChars.DOUBLE_BAR;
662 cVSide = GraphicsChars.WINDOW_SIDE_DOUBLE;
663 break;
664
665 case 3:
666 cTopLeft = GraphicsChars.WINDOW_LEFT_TOP;
667 cTopRight = GraphicsChars.WINDOW_RIGHT_TOP;
668 cBottomLeft = GraphicsChars.WINDOW_LEFT_BOTTOM;
669 cBottomRight = GraphicsChars.WINDOW_RIGHT_BOTTOM;
670 cHSide = GraphicsChars.WINDOW_TOP;
671 cVSide = GraphicsChars.WINDOW_SIDE;
672 break;
673 default:
674 throw new IllegalArgumentException("Invalid border type: "
675 + borderType);
676 }
677
678 // Place the corner characters
679 putCharXY(left, top, cTopLeft, border);
680 putCharXY(left + boxWidth - 1, top, cTopRight, border);
681 putCharXY(left, top + boxHeight - 1, cBottomLeft, border);
682 putCharXY(left + boxWidth - 1, top + boxHeight - 1, cBottomRight,
683 border);
684
685 // Draw the box lines
686 hLineXY(left + 1, top, boxWidth - 2, cHSide, border);
687 vLineXY(left, top + 1, boxHeight - 2, cVSide, border);
688 hLineXY(left + 1, top + boxHeight - 1, boxWidth - 2, cHSide, border);
689 vLineXY(left + boxWidth - 1, top + 1, boxHeight - 2, cVSide, border);
690
691 // Fill in the interior background
692 for (int i = 1; i < boxHeight - 1; i++) {
693 hLineXY(1 + left, i + top, boxWidth - 2, ' ', background);
694 }
695
696 if (shadow) {
697 // Draw a shadow
698 drawBoxShadow(left, top, right, bottom);
699 }
df8de03f
KL
700 }
701
702 /**
fca67db0 703 * Draw a box shadow.
df8de03f
KL
704 *
705 * @param left left column of box. 0 is the left-most row.
706 * @param top top row of the box. 0 is the top-most row.
707 * @param right right column of box
708 * @param bottom bottom row of the box
709 */
fca67db0 710 public final void drawBoxShadow(final int left, final int top,
7b5261bc
KL
711 final int right, final int bottom) {
712
713 int boxTop = top;
714 int boxLeft = left;
715 int boxWidth = right - left;
716 int boxHeight = bottom - top;
717 CellAttributes shadowAttr = new CellAttributes();
718
719 // Shadows do not honor clipping but they DO honor offset.
720 int oldClipRight = clipRight;
721 int oldClipBottom = clipBottom;
722 /*
723 clipRight = boxWidth + 2;
724 clipBottom = boxHeight + 1;
725 */
726 clipRight = width;
727 clipBottom = height;
728
729 for (int i = 0; i < boxHeight; i++) {
730 putAttrXY(boxLeft + boxWidth, boxTop + 1 + i, shadowAttr);
731 putAttrXY(boxLeft + boxWidth + 1, boxTop + 1 + i, shadowAttr);
732 }
733 for (int i = 0; i < boxWidth; i++) {
734 putAttrXY(boxLeft + 2 + i, boxTop + boxHeight, shadowAttr);
735 }
736 clipRight = oldClipRight;
737 clipBottom = oldClipBottom;
df8de03f
KL
738 }
739
740 /**
42873e30 741 * Default implementation does nothing.
df8de03f 742 */
42873e30 743 public void flushPhysical() {}
df8de03f
KL
744
745 /**
746 * Put the cursor at (x,y).
747 *
748 * @param visible if true, the cursor should be visible
749 * @param x column coordinate to put the cursor on
750 * @param y row coordinate to put the cursor on
751 */
30bd4abd 752 public void putCursor(final boolean visible, final int x, final int y) {
be72cb5c
KL
753 if ((cursorY >= 0)
754 && (cursorX >= 0)
755 && (cursorY <= height - 1)
756 && (cursorX <= width - 1)
757 ) {
758 // Make the current cursor position dirty
759 if (physical[cursorX][cursorY].getChar() == 'Q') {
760 physical[cursorX][cursorY].setChar('X');
761 } else {
762 physical[cursorX][cursorY].setChar('Q');
763 }
764 }
fca67db0 765
7b5261bc
KL
766 cursorVisible = visible;
767 cursorX = x;
768 cursorY = y;
df8de03f
KL
769 }
770
771 /**
fca67db0 772 * Hide the cursor.
df8de03f 773 */
fca67db0 774 public final void hideCursor() {
7b5261bc 775 cursorVisible = false;
df8de03f 776 }
42873e30 777
3e074355
KL
778 /**
779 * Get the cursor visibility.
780 *
781 * @return true if the cursor is visible
782 */
783 public boolean isCursorVisible() {
784 return cursorVisible;
785 }
786
787 /**
788 * Get the cursor X position.
789 *
790 * @return the cursor x column position
791 */
792 public int getCursorX() {
793 return cursorX;
794 }
795
796 /**
797 * Get the cursor Y position.
798 *
799 * @return the cursor y row position
800 */
801 public int getCursorY() {
802 return cursorY;
803 }
804
42873e30
KL
805 /**
806 * Set the window title. Default implementation does nothing.
807 *
808 * @param title the new title
809 */
810 public void setTitle(final String title) {}
811
d36057df
KL
812 // ------------------------------------------------------------------------
813 // LogicalScreen ----------------------------------------------------------
814 // ------------------------------------------------------------------------
815
816 /**
817 * Reallocate screen buffers.
818 *
819 * @param width new width
820 * @param height new height
821 */
822 private synchronized void reallocate(final int width, final int height) {
823 if (logical != null) {
824 for (int row = 0; row < this.height; row++) {
825 for (int col = 0; col < this.width; col++) {
826 logical[col][row] = null;
827 }
828 }
829 logical = null;
830 }
831 logical = new Cell[width][height];
832 if (physical != null) {
833 for (int row = 0; row < this.height; row++) {
834 for (int col = 0; col < this.width; col++) {
835 physical[col][row] = null;
836 }
837 }
838 physical = null;
839 }
840 physical = new Cell[width][height];
841
842 for (int row = 0; row < height; row++) {
843 for (int col = 0; col < width; col++) {
844 physical[col][row] = new Cell();
845 logical[col][row] = new Cell();
846 }
847 }
848
849 this.width = width;
850 this.height = height;
851
852 clipLeft = 0;
853 clipTop = 0;
854 clipRight = width;
855 clipBottom = height;
856
857 reallyCleared = true;
858 }
859
860 /**
861 * Clear the physical screen.
862 */
863 public final void clearPhysical() {
864 for (int row = 0; row < height; row++) {
865 for (int col = 0; col < width; col++) {
866 physical[col][row].reset();
867 }
868 }
869 }
870
df8de03f 871}