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