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