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