Fix excess redraws
[fanfix.git] / src / jexer / TWindow.java
CommitLineData
48e27807
KL
1/**
2 * Jexer - Java Text User Interface
3 *
4 * License: LGPLv3 or later
5 *
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.
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
27 *
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
29 * @version 1
30 */
31package jexer;
32
33import jexer.bits.Cell;
34import jexer.bits.CellAttributes;
35import jexer.bits.GraphicsChars;
36import jexer.event.TCommandEvent;
37import jexer.event.TKeypressEvent;
38import jexer.event.TMenuEvent;
39import jexer.event.TMouseEvent;
40import jexer.event.TResizeEvent;
41import jexer.io.Screen;
42import static jexer.TCommand.*;
43import static jexer.TKeypress.*;
44
45/**
46 * TWindow is the top-level container and drawing surface for other widgets.
47 */
a06459bd 48public class TWindow extends TWidget implements Comparable<TWindow> {
48e27807
KL
49
50 /**
51 * Window's parent TApplication.
52 */
fca67db0 53 private TApplication application;
48e27807
KL
54
55 /**
56 * Get this TWindow's parent TApplication.
57 *
58 * @return this TWindow's parent TApplication
59 */
60 public final TApplication getApplication() {
61 return application;
62 }
63
64 /**
65 * Get the Screen.
66 *
67 * @return the Screen
68 */
69 public final Screen getScreen() {
70 return application.getScreen();
71 }
72
73 /**
74 * Window title.
75 */
fca67db0
KL
76 private String title = "";
77
78 /**
79 * Get window title.
80 *
81 * @return window title
82 */
83 public final String getTitle() {
84 return title;
85 }
86
87 /**
88 * Set window title.
89 *
90 * @param title new window title
91 */
92 public final void setTitle(final String title) {
93 this.title = title;
94 }
48e27807
KL
95
96 /**
97 * Window is resizable (default yes).
98 */
99 public static final int RESIZABLE = 0x01;
100
101 /**
102 * Window is modal (default no).
103 */
104 public static final int MODAL = 0x02;
105
106 /**
107 * Window is centered (default no).
108 */
109 public static final int CENTERED = 0x04;
110
111 /**
112 * Window flags.
113 */
114 private int flags = RESIZABLE;
115
116 /**
117 * Z order. Lower number means more in-front.
118 */
119 private int z = 0;
120
a06459bd
KL
121 /**
122 * Get Z order. Lower number means more in-front.
123 *
124 * @return Z value. Lower number means more in-front.
125 */
126 public final int getZ() {
127 return z;
128 }
129
130 /**
131 * Set Z order. Lower number means more in-front.
132 *
133 * @param z the new Z value. Lower number means more in-front.
134 */
135 public final void setZ(final int z) {
136 this.z = z;
137 }
138
48e27807
KL
139 /**
140 * If true, then the user clicked on the title bar and is moving the
141 * window.
142 */
143 private boolean inWindowMove = false;
144
145 /**
146 * If true, then the user clicked on the bottom right corner and is
147 * resizing the window.
148 */
149 private boolean inWindowResize = false;
150
151 /**
152 * If true, then the user selected "Size/Move" (or hit Ctrl-F5) and is
153 * resizing/moving the window via the keyboard.
154 */
155 private boolean inKeyboardResize = false;
156
157 /**
158 * If true, this window is maximized.
159 */
160 private boolean maximized = false;
161
162 /**
163 * Remember mouse state.
164 */
fca67db0 165 private TMouseEvent mouse;
48e27807
KL
166
167 // For moving the window. resizing also uses moveWindowMouseX/Y
168 private int moveWindowMouseX;
169 private int moveWindowMouseY;
170 private int oldWindowX;
171 private int oldWindowY;
172
173 // Resizing
174 private int resizeWindowWidth;
175 private int resizeWindowHeight;
176 private int minimumWindowWidth = 10;
177 private int minimumWindowHeight = 2;
178 private int maximumWindowWidth = -1;
179 private int maximumWindowHeight = -1;
180
181 // For maximize/restore
182 private int restoreWindowWidth;
183 private int restoreWindowHeight;
184 private int restoreWindowX;
185 private int restoreWindowY;
186
187 /**
188 * Public constructor. Window will be located at (0, 0).
189 *
190 * @param application TApplication that manages this window
191 * @param title window title, will be centered along the top border
192 * @param width width of window
193 * @param height height of window
194 */
195 public TWindow(final TApplication application, final String title,
196 final int width, final int height) {
197
198 this(application, title, 0, 0, width, height, RESIZABLE);
199 }
200
201 /**
202 * Public constructor. Window will be located at (0, 0).
203 *
204 * @param application TApplication that manages this window
205 * @param title window title, will be centered along the top border
206 * @param width width of window
207 * @param height height of window
208 * @param flags bitmask of RESIZABLE, CENTERED, or MODAL
209 */
210 public TWindow(final TApplication application, final String title,
211 final int width, final int height, final int flags) {
212
213 this(application, title, 0, 0, width, height, flags);
214 }
215
216 /**
217 * Public constructor.
218 *
219 * @param application TApplication that manages this window
220 * @param title window title, will be centered along the top border
221 * @param x column relative to parent
222 * @param y row relative to parent
223 * @param width width of window
224 * @param height height of window
225 */
226 public TWindow(final TApplication application, final String title,
227 final int x, final int y, final int width, final int height) {
228
229 this(application, title, x, y, width, height, RESIZABLE);
230 }
231
232 /**
233 * Public constructor.
234 *
235 * @param application TApplication that manages this window
236 * @param title window title, will be centered along the top border
237 * @param x column relative to parent
238 * @param y row relative to parent
239 * @param width width of window
240 * @param height height of window
241 * @param flags mask of RESIZABLE, CENTERED, or MODAL
242 */
243 public TWindow(final TApplication application, final String title,
244 final int x, final int y, final int width, final int height,
245 final int flags) {
246
fca67db0
KL
247 super();
248
48e27807 249 // I am my own window and parent
fca67db0
KL
250 setupForTWindow(this, x, y + application.getDesktopTop(),
251 width, height);
48e27807
KL
252
253 // Save fields
254 this.title = title;
255 this.application = application;
48e27807
KL
256 this.flags = flags;
257
258 // Minimum width/height are 10 and 2
259 assert (width >= 10);
fca67db0 260 assert (getHeight() >= 2);
48e27807
KL
261
262 // MODAL implies CENTERED
263 if (isModal()) {
264 this.flags |= CENTERED;
265 }
266
267 // Center window if specified
268 center();
269
270 // Add me to the application
271 application.addWindow(this);
272 }
273
274 /**
275 * Recenter the window on-screen.
276 */
277 public final void center() {
278 if ((flags & CENTERED) != 0) {
fca67db0
KL
279 if (getWidth() < getScreen().getWidth()) {
280 setX((getScreen().getWidth() - getWidth()) / 2);
48e27807 281 } else {
fca67db0 282 setX(0);
48e27807 283 }
fca67db0
KL
284 setY(((application.getDesktopBottom()
285 - application.getDesktopTop()) - getHeight()) / 2);
286 if (getY() < 0) {
287 setY(0);
48e27807 288 }
fca67db0 289 setY(getY() + application.getDesktopTop());
48e27807
KL
290 }
291 }
292
293 /**
294 * Returns true if this window is modal.
295 *
296 * @return true if this window is modal
297 */
298 public final boolean isModal() {
299 if ((flags & MODAL) == 0) {
300 return false;
301 }
302 return true;
303 }
304
305 /**
306 * Comparison operator sorts on z.
307 *
308 * @param that another TWindow instance
309 * @return difference between this.z and that.z
310 */
a06459bd
KL
311 @Override
312 public final int compareTo(final TWindow that) {
313 return (this.z - that.z);
48e27807
KL
314 }
315
316 /**
317 * Returns true if the mouse is currently on the close button.
318 *
319 * @return true if mouse is currently on the close button
320 */
321 private boolean mouseOnClose() {
322 if ((mouse != null)
fca67db0
KL
323 && (mouse.getAbsoluteY() == getY())
324 && (mouse.getAbsoluteX() == getX() + 3)
48e27807
KL
325 ) {
326 return true;
327 }
328 return false;
329 }
330
331 /**
332 * Returns true if the mouse is currently on the maximize/restore button.
333 *
334 * @return true if the mouse is currently on the maximize/restore button
335 */
336 private boolean mouseOnMaximize() {
337 if ((mouse != null)
338 && !isModal()
fca67db0
KL
339 && (mouse.getAbsoluteY() == getY())
340 && (mouse.getAbsoluteX() == getX() + getWidth() - 4)
48e27807
KL
341 ) {
342 return true;
343 }
344 return false;
345 }
346
347 /**
348 * Returns true if the mouse is currently on the resizable lower right
349 * corner.
350 *
351 * @return true if the mouse is currently on the resizable lower right
352 * corner
353 */
354 private boolean mouseOnResize() {
355 if (((flags & RESIZABLE) != 0)
356 && !isModal()
357 && (mouse != null)
fca67db0
KL
358 && (mouse.getAbsoluteY() == getY() + getHeight() - 1)
359 && ((mouse.getAbsoluteX() == getX() + getWidth() - 1)
360 || (mouse.getAbsoluteX() == getX() + getWidth() - 2))
48e27807
KL
361 ) {
362 return true;
363 }
364 return false;
365 }
366
367 /**
368 * Retrieve the background color.
369 *
370 * @return the background color
371 */
fca67db0 372 private final CellAttributes getBackground() {
48e27807
KL
373 if (!isModal()
374 && (inWindowMove || inWindowResize || inKeyboardResize)
375 ) {
fca67db0 376 assert (getActive());
48e27807
KL
377 return application.getTheme().getColor("twindow.background.windowmove");
378 } else if (isModal() && inWindowMove) {
fca67db0 379 assert (getActive());
48e27807
KL
380 return application.getTheme().getColor("twindow.background.modal");
381 } else if (isModal()) {
fca67db0 382 if (getActive()) {
48e27807
KL
383 return application.getTheme().getColor("twindow.background.modal");
384 }
385 return application.getTheme().getColor("twindow.background.modal.inactive");
fca67db0 386 } else if (getActive()) {
48e27807
KL
387 assert (!isModal());
388 return application.getTheme().getColor("twindow.background");
389 } else {
390 assert (!isModal());
391 return application.getTheme().getColor("twindow.background.inactive");
392 }
393 }
394
395 /**
396 * Retrieve the border color.
397 *
398 * @return the border color
399 */
fca67db0 400 private final CellAttributes getBorder() {
48e27807
KL
401 if (!isModal()
402 && (inWindowMove || inWindowResize || inKeyboardResize)
403 ) {
fca67db0 404 assert (getActive());
48e27807
KL
405 return application.getTheme().getColor("twindow.border.windowmove");
406 } else if (isModal() && inWindowMove) {
fca67db0 407 assert (getActive());
48e27807
KL
408 return application.getTheme().getColor("twindow.border.modal.windowmove");
409 } else if (isModal()) {
fca67db0 410 if (getActive()) {
48e27807
KL
411 return application.getTheme().getColor("twindow.border.modal");
412 } else {
413 return application.getTheme().getColor("twindow.border.modal.inactive");
414 }
fca67db0 415 } else if (getActive()) {
48e27807
KL
416 assert (!isModal());
417 return application.getTheme().getColor("twindow.border");
418 } else {
419 assert (!isModal());
420 return application.getTheme().getColor("twindow.border.inactive");
421 }
422 }
423
424 /**
425 * Retrieve the border line type.
426 *
427 * @return the border line type
428 */
fca67db0 429 private final int getBorderType() {
48e27807
KL
430 if (!isModal()
431 && (inWindowMove || inWindowResize || inKeyboardResize)
432 ) {
fca67db0 433 assert (getActive());
48e27807
KL
434 return 1;
435 } else if (isModal() && inWindowMove) {
fca67db0 436 assert (getActive());
48e27807
KL
437 return 1;
438 } else if (isModal()) {
fca67db0 439 if (getActive()) {
48e27807
KL
440 return 2;
441 } else {
442 return 1;
443 }
fca67db0 444 } else if (getActive()) {
48e27807
KL
445 return 2;
446 } else {
447 return 1;
448 }
449 }
450
451 /**
452 * Subclasses should override this method to cleanup resources. This is
453 * called by application.closeWindow().
454 */
455 public void onClose() {
456 // Default: do nothing
457 }
458
459 /**
460 * Called by TApplication.drawChildren() to render on screen.
461 */
462 @Override
463 public void draw() {
464 // Draw the box and background first.
465 CellAttributes border = getBorder();
466 CellAttributes background = getBackground();
467 int borderType = getBorderType();
468
fca67db0 469 getScreen().drawBox(0, 0, getWidth(), getHeight(), border,
48e27807
KL
470 background, borderType, true);
471
472 // Draw the title
fca67db0 473 int titleLeft = (getWidth() - title.length() - 2) / 2;
48e27807
KL
474 putCharXY(titleLeft, 0, ' ', border);
475 putStrXY(titleLeft + 1, 0, title);
476 putCharXY(titleLeft + title.length() + 1, 0, ' ', border);
477
fca67db0 478 if (getActive()) {
48e27807
KL
479
480 // Draw the close button
481 putCharXY(2, 0, '[', border);
482 putCharXY(4, 0, ']', border);
483 if (mouseOnClose() && mouse.getMouse1()) {
484 putCharXY(3, 0, GraphicsChars.CP437[0x0F],
485 !isModal()
486 ? application.getTheme().getColor("twindow.border.windowmove")
487 : application.getTheme().getColor("twindow.border.modal.windowmove"));
488 } else {
489 putCharXY(3, 0, GraphicsChars.CP437[0xFE],
490 !isModal()
491 ? application.getTheme().getColor("twindow.border.windowmove")
492 : application.getTheme().getColor("twindow.border.modal.windowmove"));
493 }
494
495 // Draw the maximize button
496 if (!isModal()) {
497
fca67db0
KL
498 putCharXY(getWidth() - 5, 0, '[', border);
499 putCharXY(getWidth() - 3, 0, ']', border);
48e27807 500 if (mouseOnMaximize() && mouse.getMouse1()) {
fca67db0 501 putCharXY(getWidth() - 4, 0, GraphicsChars.CP437[0x0F],
48e27807
KL
502 application.getTheme().getColor("twindow.border.windowmove"));
503 } else {
504 if (maximized) {
fca67db0 505 putCharXY(getWidth() - 4, 0, GraphicsChars.CP437[0x12],
48e27807
KL
506 application.getTheme().getColor("twindow.border.windowmove"));
507 } else {
fca67db0 508 putCharXY(getWidth() - 4, 0, GraphicsChars.UPARROW,
48e27807
KL
509 application.getTheme().getColor("twindow.border.windowmove"));
510 }
511 }
512
513 // Draw the resize corner
514 if ((flags & RESIZABLE) != 0) {
fca67db0 515 putCharXY(getWidth() - 2, getHeight() - 1, GraphicsChars.SINGLE_BAR,
48e27807 516 application.getTheme().getColor("twindow.border.windowmove"));
fca67db0 517 putCharXY(getWidth() - 1, getHeight() - 1, GraphicsChars.LRCORNER,
48e27807
KL
518 application.getTheme().getColor("twindow.border.windowmove"));
519 }
520 }
521 }
522 }
523
524 /**
525 * Handle mouse button presses.
526 *
527 * @param mouse mouse button event
528 */
529 @Override
530 public void onMouseDown(final TMouseEvent mouse) {
531 this.mouse = mouse;
532 application.setRepaint();
533
534 inKeyboardResize = false;
535
fca67db0 536 if ((mouse.getAbsoluteY() == getY())
48e27807 537 && mouse.getMouse1()
fca67db0
KL
538 && (getX() <= mouse.getAbsoluteX())
539 && (mouse.getAbsoluteX() < getX() + getWidth())
48e27807
KL
540 && !mouseOnClose()
541 && !mouseOnMaximize()
542 ) {
543 // Begin moving window
544 inWindowMove = true;
545 moveWindowMouseX = mouse.getAbsoluteX();
546 moveWindowMouseY = mouse.getAbsoluteY();
fca67db0
KL
547 oldWindowX = getX();
548 oldWindowY = getY();
48e27807
KL
549 if (maximized) {
550 maximized = false;
551 }
552 return;
553 }
554 if (mouseOnResize()) {
555 // Begin window resize
556 inWindowResize = true;
557 moveWindowMouseX = mouse.getAbsoluteX();
558 moveWindowMouseY = mouse.getAbsoluteY();
fca67db0
KL
559 resizeWindowWidth = getWidth();
560 resizeWindowHeight = getHeight();
48e27807
KL
561 if (maximized) {
562 maximized = false;
563 }
564 return;
565 }
566
567 // I didn't take it, pass it on to my children
568 super.onMouseDown(mouse);
569 }
570
571 /**
572 * Maximize window.
573 */
574 private void maximize() {
fca67db0
KL
575 restoreWindowWidth = getWidth();
576 restoreWindowHeight = getHeight();
577 restoreWindowX = getX();
578 restoreWindowY = getY();
579 setWidth(getScreen().getWidth());
580 setHeight(application.getDesktopBottom() - 1);
581 setX(0);
582 setY(1);
48e27807
KL
583 maximized = true;
584 }
585
586 /**
587 * Restote (unmaximize) window.
588 */
589 private void restore() {
fca67db0
KL
590 setWidth(restoreWindowWidth);
591 setHeight(restoreWindowHeight);
592 setX(restoreWindowX);
593 setY(restoreWindowY);
48e27807
KL
594 maximized = false;
595 }
596
597 /**
598 * Handle mouse button releases.
599 *
600 * @param mouse mouse button release event
601 */
602 @Override
603 public void onMouseUp(final TMouseEvent mouse) {
604 this.mouse = mouse;
605 application.setRepaint();
606
607 if ((inWindowMove) && (mouse.getMouse1())) {
608 // Stop moving window
609 inWindowMove = false;
610 return;
611 }
612
613 if ((inWindowResize) && (mouse.getMouse1())) {
614 // Stop resizing window
615 inWindowResize = false;
616 return;
617 }
618
619 if (mouse.getMouse1() && mouseOnClose()) {
620 // Close window
621 application.closeWindow(this);
622 return;
623 }
624
fca67db0
KL
625 if ((mouse.getAbsoluteY() == getY())
626 && mouse.getMouse1()
48e27807
KL
627 && mouseOnMaximize()) {
628 if (maximized) {
629 // Restore
630 restore();
631 } else {
632 // Maximize
633 maximize();
634 }
635 // Pass a resize event to my children
fca67db0
KL
636 onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
637 getWidth(), getHeight()));
48e27807
KL
638 return;
639 }
640
641 // I didn't take it, pass it on to my children
642 super.onMouseUp(mouse);
643 }
644
645 /**
646 * Handle mouse movements.
647 *
648 * @param mouse mouse motion event
649 */
650 @Override
651 public void onMouseMotion(final TMouseEvent mouse) {
652 this.mouse = mouse;
653 application.setRepaint();
654
655 if (inWindowMove) {
656 // Move window over
fca67db0
KL
657 setX(oldWindowX + (mouse.getAbsoluteX() - moveWindowMouseX));
658 setY(oldWindowY + (mouse.getAbsoluteY() - moveWindowMouseY));
48e27807 659 // Don't cover up the menu bar
fca67db0
KL
660 if (getY() < application.getDesktopTop()) {
661 setY(application.getDesktopTop());
48e27807
KL
662 }
663 return;
664 }
665
666 if (inWindowResize) {
667 // Move window over
fca67db0
KL
668 setWidth(resizeWindowWidth + (mouse.getAbsoluteX()
669 - moveWindowMouseX));
670 setHeight(resizeWindowHeight + (mouse.getAbsoluteY()
671 - moveWindowMouseY));
672 if (getX() + getWidth() > getScreen().getWidth()) {
673 setWidth(getScreen().getWidth() - getX());
48e27807 674 }
fca67db0
KL
675 if (getY() + getHeight() > application.getDesktopBottom()) {
676 setY(application.getDesktopBottom() - getHeight() + 1);
48e27807
KL
677 }
678 // Don't cover up the menu bar
fca67db0
KL
679 if (getY() < application.getDesktopTop()) {
680 setY(application.getDesktopTop());
48e27807
KL
681 }
682
683 // Keep within min/max bounds
fca67db0
KL
684 if (getWidth() < minimumWindowWidth) {
685 setWidth(minimumWindowWidth);
48e27807
KL
686 inWindowResize = false;
687 }
fca67db0
KL
688 if (getHeight() < minimumWindowHeight) {
689 setHeight(minimumWindowHeight);
48e27807
KL
690 inWindowResize = false;
691 }
fca67db0
KL
692 if ((maximumWindowWidth > 0)
693 && (getWidth() > maximumWindowWidth)
694 ) {
695 setWidth(maximumWindowWidth);
48e27807
KL
696 inWindowResize = false;
697 }
fca67db0
KL
698 if ((maximumWindowHeight > 0)
699 && (getHeight() > maximumWindowHeight)
700 ) {
701 setHeight(maximumWindowHeight);
48e27807
KL
702 inWindowResize = false;
703 }
704
705 // Pass a resize event to my children
fca67db0
KL
706 onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
707 getWidth(), getHeight()));
48e27807
KL
708 return;
709 }
710
711 // I didn't take it, pass it on to my children
712 super.onMouseMotion(mouse);
713 }
714
715 /**
716 * Handle keystrokes.
717 *
718 * @param keypress keystroke event
719 */
720 @Override
721 public void onKeypress(final TKeypressEvent keypress) {
722
723 if (inKeyboardResize) {
724
725 // ESC - Exit size/move
726 if (keypress.equals(kbEsc)) {
727 inKeyboardResize = false;
728 }
729
730 if (keypress.equals(kbLeft)) {
fca67db0
KL
731 if (getX() > 0) {
732 setX(getX() - 1);
48e27807
KL
733 }
734 }
735 if (keypress.equals(kbRight)) {
fca67db0
KL
736 if (getX() < getScreen().getWidth() - 1) {
737 setX(getX() + 1);
48e27807
KL
738 }
739 }
740 if (keypress.equals(kbDown)) {
fca67db0
KL
741 if (getY() < application.getDesktopBottom() - 1) {
742 setY(getY() + 1);
48e27807
KL
743 }
744 }
745 if (keypress.equals(kbUp)) {
fca67db0
KL
746 if (getY() > 1) {
747 setY(getY() - 1);
48e27807
KL
748 }
749 }
750 if (keypress.equals(kbShiftLeft)) {
fca67db0
KL
751 if (getWidth() > minimumWindowWidth) {
752 setWidth(getWidth() - 1);
48e27807
KL
753 }
754 }
755 if (keypress.equals(kbShiftRight)) {
fca67db0
KL
756 if (getWidth() < maximumWindowWidth) {
757 setWidth(getWidth() + 1);
48e27807
KL
758 }
759 }
760 if (keypress.equals(kbShiftUp)) {
fca67db0
KL
761 if (getHeight() > minimumWindowHeight) {
762 setHeight(getHeight() - 1);
48e27807
KL
763 }
764 }
765 if (keypress.equals(kbShiftDown)) {
fca67db0
KL
766 if (getHeight() < maximumWindowHeight) {
767 setHeight(getHeight() + 1);
48e27807
KL
768 }
769 }
770
771 return;
772 }
773
774 // These keystrokes will typically not be seen unless a subclass
775 // overrides onMenu() due to how TApplication dispatches
776 // accelerators.
777
778 // Ctrl-W - close window
779 if (keypress.equals(kbCtrlW)) {
780 application.closeWindow(this);
781 return;
782 }
783
784 // F6 - behave like Alt-TAB
785 if (keypress.equals(kbF6)) {
786 application.switchWindow(true);
787 return;
788 }
789
790 // Shift-F6 - behave like Shift-Alt-TAB
791 if (keypress.equals(kbShiftF6)) {
792 application.switchWindow(false);
793 return;
794 }
795
796 // F5 - zoom
797 if (keypress.equals(kbF5)) {
798 if (maximized) {
799 restore();
800 } else {
801 maximize();
802 }
803 }
804
805 // Ctrl-F5 - size/move
806 if (keypress.equals(kbCtrlF5)) {
807 inKeyboardResize = !inKeyboardResize;
808 }
809
810 // I didn't take it, pass it on to my children
811 super.onKeypress(keypress);
812 }
813
814 /**
815 * Handle posted command events.
816 *
817 * @param command command event
818 */
819 @Override
820 public void onCommand(final TCommandEvent command) {
821
822 // These commands will typically not be seen unless a subclass
823 // overrides onMenu() due to how TApplication dispatches
824 // accelerators.
825
826 if (command.equals(cmWindowClose)) {
827 application.closeWindow(this);
828 return;
829 }
830
831 if (command.equals(cmWindowNext)) {
832 application.switchWindow(true);
833 return;
834 }
835
836 if (command.equals(cmWindowPrevious)) {
837 application.switchWindow(false);
838 return;
839 }
840
841 if (command.equals(cmWindowMove)) {
842 inKeyboardResize = true;
843 return;
844 }
845
846 if (command.equals(cmWindowZoom)) {
847 if (maximized) {
848 restore();
849 } else {
850 maximize();
851 }
852 }
853
854 // I didn't take it, pass it on to my children
855 super.onCommand(command);
856 }
857
858 /**
859 * Handle posted menu events.
860 *
861 * @param menu menu event
862 */
863 @Override
864 public void onMenu(final TMenuEvent menu) {
865 if (menu.getId() == TMenu.MID_WINDOW_CLOSE) {
866 application.closeWindow(this);
867 return;
868 }
869
870 if (menu.getId() == TMenu.MID_WINDOW_NEXT) {
871 application.switchWindow(true);
872 return;
873 }
874
875 if (menu.getId() == TMenu.MID_WINDOW_PREVIOUS) {
876 application.switchWindow(false);
877 return;
878 }
879
880 if (menu.getId() == TMenu.MID_WINDOW_MOVE) {
881 inKeyboardResize = true;
882 return;
883 }
884
885 if (menu.getId() == TMenu.MID_WINDOW_ZOOM) {
886 if (maximized) {
887 restore();
888 } else {
889 maximize();
890 }
891 return;
892 }
893
894 // I didn't take it, pass it on to my children
895 super.onMenu(menu);
896 }
897
898 // ------------------------------------------------------------------------
899 // Passthru for Screen functions ------------------------------------------
900 // ------------------------------------------------------------------------
901
902 /**
903 * Get the attributes at one location.
904 *
905 * @param x column coordinate. 0 is the left-most column.
906 * @param y row coordinate. 0 is the top-most row.
907 * @return attributes at (x, y)
908 */
909 public final CellAttributes getAttrXY(final int x, final int y) {
910 return getScreen().getAttrXY(x, y);
911 }
912
913 /**
914 * Set the attributes at one location.
915 *
916 * @param x column coordinate. 0 is the left-most column.
917 * @param y row coordinate. 0 is the top-most row.
918 * @param attr attributes to use (bold, foreColor, backColor)
919 */
920 public final void putAttrXY(final int x, final int y,
921 final CellAttributes attr) {
922
923 getScreen().putAttrXY(x, y, attr);
924 }
925
926 /**
927 * Set the attributes at one location.
928 *
929 * @param x column coordinate. 0 is the left-most column.
930 * @param y row coordinate. 0 is the top-most row.
931 * @param attr attributes to use (bold, foreColor, backColor)
932 * @param clip if true, honor clipping/offset
933 */
934 public final void putAttrXY(final int x, final int y,
935 final CellAttributes attr, final boolean clip) {
936
937 getScreen().putAttrXY(x, y, attr, clip);
938 }
939
940 /**
941 * Fill the entire screen with one character with attributes.
942 *
943 * @param ch character to draw
944 * @param attr attributes to use (bold, foreColor, backColor)
945 */
946 public final void putAll(final char ch, final CellAttributes attr) {
947 getScreen().putAll(ch, attr);
948 }
949
950 /**
951 * Render one character with attributes.
952 *
953 * @param x column coordinate. 0 is the left-most column.
954 * @param y row coordinate. 0 is the top-most row.
955 * @param ch character + attributes to draw
956 */
957 public final void putCharXY(final int x, final int y, final Cell ch) {
958 getScreen().putCharXY(x, y, ch);
959 }
960
961 /**
962 * Render one character with attributes.
963 *
964 * @param x column coordinate. 0 is the left-most column.
965 * @param y row coordinate. 0 is the top-most row.
966 * @param ch character to draw
967 * @param attr attributes to use (bold, foreColor, backColor)
968 */
969 public final void putCharXY(final int x, final int y, final char ch,
970 final CellAttributes attr) {
971
972 getScreen().putCharXY(x, y, ch, attr);
973 }
974
975 /**
976 * Render one character without changing the underlying attributes.
977 *
978 * @param x column coordinate. 0 is the left-most column.
979 * @param y row coordinate. 0 is the top-most row.
980 * @param ch character to draw
981 */
982 public final void putCharXY(final int x, final int y, final char ch) {
983 getScreen().putCharXY(x, y, ch);
984 }
985
986 /**
987 * Render a string. Does not wrap if the string exceeds the line.
988 *
989 * @param x column coordinate. 0 is the left-most column.
990 * @param y row coordinate. 0 is the top-most row.
991 * @param str string to draw
992 * @param attr attributes to use (bold, foreColor, backColor)
993 */
994 public final void putStrXY(final int x, final int y, final String str,
995 final CellAttributes attr) {
996
997 getScreen().putStrXY(x, y, str, attr);
998 }
999
1000 /**
1001 * Render a string without changing the underlying attribute. Does not
1002 * wrap if the string exceeds the line.
1003 *
1004 * @param x column coordinate. 0 is the left-most column.
1005 * @param y row coordinate. 0 is the top-most row.
1006 * @param str string to draw
1007 */
1008 public final void putStrXY(final int x, final int y, final String str) {
1009 getScreen().putStrXY(x, y, str);
1010 }
1011
1012 /**
1013 * Draw a vertical line from (x, y) to (x, y + n).
1014 *
1015 * @param x column coordinate. 0 is the left-most column.
1016 * @param y row coordinate. 0 is the top-most row.
1017 * @param n number of characters to draw
1018 * @param ch character to draw
1019 * @param attr attributes to use (bold, foreColor, backColor)
1020 */
1021 public final void vLineXY(final int x, final int y, final int n,
1022 final char ch, final CellAttributes attr) {
1023
1024 getScreen().vLineXY(x, y, n, ch, attr);
1025 }
1026
1027 /**
1028 * Draw a horizontal line from (x, y) to (x + n, y).
1029 *
1030 * @param x column coordinate. 0 is the left-most column.
1031 * @param y row coordinate. 0 is the top-most row.
1032 * @param n number of characters to draw
1033 * @param ch character to draw
1034 * @param attr attributes to use (bold, foreColor, backColor)
1035 */
1036 public final void hLineXY(final int x, final int y, final int n,
1037 final char ch, final CellAttributes attr) {
1038
1039 getScreen().hLineXY(x, y, n, ch, attr);
1040 }
1041
1042
1043}