ttable navigation correct
[fanfix.git] / src / jexer / TWidget.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2019 Kevin Lamonte
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29 package jexer;
30
31 import java.io.IOException;
32 import java.util.List;
33 import java.util.ArrayList;
34
35 import jexer.backend.Screen;
36 import jexer.bits.Cell;
37 import jexer.bits.CellAttributes;
38 import jexer.bits.ColorTheme;
39 import jexer.event.TCommandEvent;
40 import jexer.event.TInputEvent;
41 import jexer.event.TKeypressEvent;
42 import jexer.event.TMenuEvent;
43 import jexer.event.TMouseEvent;
44 import jexer.event.TResizeEvent;
45 import jexer.menu.TMenu;
46 import jexer.ttree.TTreeItem;
47 import jexer.ttree.TTreeView;
48 import jexer.ttree.TTreeViewWidget;
49 import static jexer.TKeypress.*;
50
51 /**
52 * TWidget is the base class of all objects that can be drawn on screen or
53 * handle user input events.
54 */
55 public abstract class TWidget implements Comparable<TWidget> {
56
57 // ------------------------------------------------------------------------
58 // Variables --------------------------------------------------------------
59 // ------------------------------------------------------------------------
60
61 /**
62 * Every widget has a parent widget that it may be "contained" in. For
63 * example, a TWindow might contain several TFields, or a TComboBox may
64 * contain a TList that itself contains a TVScroller.
65 */
66 private TWidget parent = null;
67
68 /**
69 * Child widgets that this widget contains.
70 */
71 private List<TWidget> children;
72
73 /**
74 * The currently active child widget that will receive keypress events.
75 */
76 private TWidget activeChild = null;
77
78 /**
79 * If true, this widget will receive events.
80 */
81 private boolean active = false;
82
83 /**
84 * The window that this widget draws to.
85 */
86 private TWindow window = null;
87
88 /**
89 * Absolute X position of the top-left corner.
90 */
91 private int x = 0;
92
93 /**
94 * Absolute Y position of the top-left corner.
95 */
96 private int y = 0;
97
98 /**
99 * Width.
100 */
101 private int width = 0;
102
103 /**
104 * Height.
105 */
106 private int height = 0;
107
108 /**
109 * My tab order inside a window or containing widget.
110 */
111 private int tabOrder = 0;
112
113 /**
114 * If true, this widget can be tabbed to or receive events.
115 */
116 private boolean enabled = true;
117
118 /**
119 * If true, this widget will be rendered.
120 */
121 private boolean visible = true;
122
123 /**
124 * If true, this widget has a cursor.
125 */
126 private boolean cursorVisible = false;
127
128 /**
129 * Cursor column position in relative coordinates.
130 */
131 private int cursorX = 0;
132
133 /**
134 * Cursor row position in relative coordinates.
135 */
136 private int cursorY = 0;
137
138 // ------------------------------------------------------------------------
139 // Constructors -----------------------------------------------------------
140 // ------------------------------------------------------------------------
141
142 /**
143 * Default constructor for subclasses.
144 */
145 protected TWidget() {
146 children = new ArrayList<TWidget>();
147 }
148
149 /**
150 * Protected constructor.
151 *
152 * @param parent parent widget
153 */
154 protected TWidget(final TWidget parent) {
155 this(parent, true);
156 }
157
158 /**
159 * Protected constructor.
160 *
161 * @param parent parent widget
162 * @param x column relative to parent
163 * @param y row relative to parent
164 * @param width width of widget
165 * @param height height of widget
166 */
167 protected TWidget(final TWidget parent, final int x, final int y,
168 final int width, final int height) {
169
170 this(parent, true, x, y, width, height);
171 }
172
173 /**
174 * Protected constructor used by subclasses that are disabled by default.
175 *
176 * @param parent parent widget
177 * @param enabled if true assume enabled
178 */
179 protected TWidget(final TWidget parent, final boolean enabled) {
180 this.enabled = enabled;
181 this.parent = parent;
182 this.window = parent.window;
183 children = new ArrayList<TWidget>();
184
185 // Do not add TStatusBars, they are drawn by TApplication.
186 if (this instanceof TStatusBar) {
187 // NOP
188 } else {
189 parent.addChild(this);
190 }
191 }
192
193 /**
194 * Protected constructor used by subclasses that are disabled by default.
195 *
196 * @param parent parent widget
197 * @param enabled if true assume enabled
198 * @param x column relative to parent
199 * @param y row relative to parent
200 * @param width width of widget
201 * @param height height of widget
202 */
203 protected TWidget(final TWidget parent, final boolean enabled,
204 final int x, final int y, final int width, final int height) {
205
206 this.enabled = enabled;
207 this.parent = parent;
208 this.window = parent.window;
209 children = new ArrayList<TWidget>();
210
211 // Do not add TStatusBars, they are drawn by TApplication.
212 if (this instanceof TStatusBar) {
213 // NOP
214 } else {
215 parent.addChild(this);
216 }
217
218 this.x = x;
219 this.y = y;
220 this.width = width;
221 this.height = height;
222 }
223
224 /**
225 * Backdoor access for TWindow's constructor. ONLY TWindow USES THIS.
226 *
227 * @param window the top-level window
228 * @param x column relative to parent
229 * @param y row relative to parent
230 * @param width width of window
231 * @param height height of window
232 */
233 protected final void setupForTWindow(final TWindow window,
234 final int x, final int y, final int width, final int height) {
235
236 this.parent = window;
237 this.window = window;
238 this.x = x;
239 this.y = y;
240 this.width = width;
241 this.height = height;
242 }
243
244 // ------------------------------------------------------------------------
245 // Event handlers ---------------------------------------------------------
246 // ------------------------------------------------------------------------
247
248 /**
249 * Subclasses should override this method to cleanup resources. This is
250 * called by TWindow.onClose().
251 */
252 protected void close() {
253 // Default: call close() on children.
254 for (TWidget w: getChildren()) {
255 w.close();
256 }
257 }
258
259 /**
260 * Check if a mouse press/release event coordinate is contained in this
261 * widget.
262 *
263 * @param mouse a mouse-based event
264 * @return whether or not a mouse click would be sent to this widget
265 */
266 public final boolean mouseWouldHit(final TMouseEvent mouse) {
267
268 if (!enabled) {
269 return false;
270 }
271
272 if ((this instanceof TTreeItem)
273 && ((y < 0) || (y > parent.getHeight() - 1))
274 ) {
275 return false;
276 }
277
278 if ((mouse.getAbsoluteX() >= getAbsoluteX())
279 && (mouse.getAbsoluteX() < getAbsoluteX() + width)
280 && (mouse.getAbsoluteY() >= getAbsoluteY())
281 && (mouse.getAbsoluteY() < getAbsoluteY() + height)
282 ) {
283 return true;
284 }
285 return false;
286 }
287
288 /**
289 * Method that subclasses can override to handle keystrokes.
290 *
291 * @param keypress keystroke event
292 */
293 public void onKeypress(final TKeypressEvent keypress) {
294
295 if ((children.size() == 0)
296 || (this instanceof TTreeView)
297 || (this instanceof TText)
298 || (this instanceof TComboBox)
299 ) {
300
301 // Defaults:
302 // tab / shift-tab - switch to next/previous widget
303 // left-arrow or up-arrow: same as shift-tab
304 if ((keypress.equals(kbTab))
305 || (keypress.equals(kbDown) && !(this instanceof TComboBox))
306 ) {
307 parent.switchWidget(true);
308 return;
309 } else if ((keypress.equals(kbShiftTab))
310 || (keypress.equals(kbBackTab))
311 || (keypress.equals(kbUp) && !(this instanceof TComboBox))
312 ) {
313 parent.switchWidget(false);
314 return;
315 }
316 }
317
318 if ((children.size() == 0)
319 && !(this instanceof TTreeView)
320 ) {
321
322 // Defaults:
323 // right-arrow or down-arrow: same as tab
324 if (keypress.equals(kbRight)) {
325 parent.switchWidget(true);
326 return;
327 } else if (keypress.equals(kbLeft)) {
328 parent.switchWidget(false);
329 return;
330 }
331 }
332
333 // If I have any buttons on me AND this is an Alt-key that matches
334 // its mnemonic, send it an Enter keystroke.
335 for (TWidget widget: children) {
336 if (widget instanceof TButton) {
337 TButton button = (TButton) widget;
338 if (button.isEnabled()
339 && !keypress.getKey().isFnKey()
340 && keypress.getKey().isAlt()
341 && !keypress.getKey().isCtrl()
342 && (Character.toLowerCase(button.getMnemonic().getShortcut())
343 == Character.toLowerCase(keypress.getKey().getChar()))
344 ) {
345
346 widget.onKeypress(new TKeypressEvent(kbEnter));
347 return;
348 }
349 }
350 }
351
352 // If I have any labels on me AND this is an Alt-key that matches
353 // its mnemonic, call its action.
354 for (TWidget widget: children) {
355 if (widget instanceof TLabel) {
356 TLabel label = (TLabel) widget;
357 if (!keypress.getKey().isFnKey()
358 && keypress.getKey().isAlt()
359 && !keypress.getKey().isCtrl()
360 && (Character.toLowerCase(label.getMnemonic().getShortcut())
361 == Character.toLowerCase(keypress.getKey().getChar()))
362 ) {
363
364 label.dispatch();
365 return;
366 }
367 }
368 }
369
370 // If I have any radiobuttons on me AND this is an Alt-key that
371 // matches its mnemonic, select it and send a Space to it.
372 for (TWidget widget: children) {
373 if (widget instanceof TRadioButton) {
374 TRadioButton button = (TRadioButton) widget;
375 if (button.isEnabled()
376 && !keypress.getKey().isFnKey()
377 && keypress.getKey().isAlt()
378 && !keypress.getKey().isCtrl()
379 && (Character.toLowerCase(button.getMnemonic().getShortcut())
380 == Character.toLowerCase(keypress.getKey().getChar()))
381 ) {
382 activate(widget);
383 widget.onKeypress(new TKeypressEvent(kbSpace));
384 return;
385 }
386 }
387 if (widget instanceof TRadioGroup) {
388 for (TWidget child: widget.getChildren()) {
389 if (child instanceof TRadioButton) {
390 TRadioButton button = (TRadioButton) child;
391 if (button.isEnabled()
392 && !keypress.getKey().isFnKey()
393 && keypress.getKey().isAlt()
394 && !keypress.getKey().isCtrl()
395 && (Character.toLowerCase(button.getMnemonic().getShortcut())
396 == Character.toLowerCase(keypress.getKey().getChar()))
397 ) {
398 activate(widget);
399 widget.activate(child);
400 child.onKeypress(new TKeypressEvent(kbSpace));
401 return;
402 }
403 }
404 }
405 }
406 }
407
408 // If I have any checkboxes on me AND this is an Alt-key that matches
409 // its mnemonic, select it and set it to checked.
410 for (TWidget widget: children) {
411 if (widget instanceof TCheckBox) {
412 TCheckBox checkBox = (TCheckBox) widget;
413 if (checkBox.isEnabled()
414 && !keypress.getKey().isFnKey()
415 && keypress.getKey().isAlt()
416 && !keypress.getKey().isCtrl()
417 && (Character.toLowerCase(checkBox.getMnemonic().getShortcut())
418 == Character.toLowerCase(keypress.getKey().getChar()))
419 ) {
420 activate(checkBox);
421 checkBox.setChecked(true);
422 return;
423 }
424 }
425 }
426
427 // Dispatch the keypress to an active widget
428 for (TWidget widget: children) {
429 if (widget.active) {
430 widget.onKeypress(keypress);
431 return;
432 }
433 }
434 }
435
436 /**
437 * Method that subclasses can override to handle mouse button presses.
438 *
439 * @param mouse mouse button event
440 */
441 public void onMouseDown(final TMouseEvent mouse) {
442 // Default: do nothing, pass to children instead
443 if (activeChild != null) {
444 if (activeChild.mouseWouldHit(mouse)) {
445 // Dispatch to the active child
446
447 // Set x and y relative to the child's coordinates
448 mouse.setX(mouse.getAbsoluteX() - activeChild.getAbsoluteX());
449 mouse.setY(mouse.getAbsoluteY() - activeChild.getAbsoluteY());
450 activeChild.onMouseDown(mouse);
451 return;
452 }
453 }
454 for (int i = children.size() - 1 ; i >= 0 ; i--) {
455 TWidget widget = children.get(i);
456 if (widget.mouseWouldHit(mouse)) {
457 // Dispatch to this child, also activate it
458 activate(widget);
459
460 // Set x and y relative to the child's coordinates
461 mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX());
462 mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY());
463 widget.onMouseDown(mouse);
464 return;
465 }
466 }
467 }
468
469 /**
470 * Method that subclasses can override to handle mouse button releases.
471 *
472 * @param mouse mouse button event
473 */
474 public void onMouseUp(final TMouseEvent mouse) {
475 // Default: do nothing, pass to children instead
476 if (activeChild != null) {
477 if (activeChild.mouseWouldHit(mouse)) {
478 // Dispatch to the active child
479
480 // Set x and y relative to the child's coordinates
481 mouse.setX(mouse.getAbsoluteX() - activeChild.getAbsoluteX());
482 mouse.setY(mouse.getAbsoluteY() - activeChild.getAbsoluteY());
483 activeChild.onMouseUp(mouse);
484 return;
485 }
486 }
487 for (int i = children.size() - 1 ; i >= 0 ; i--) {
488 TWidget widget = children.get(i);
489 if (widget.mouseWouldHit(mouse)) {
490 // Dispatch to this child, also activate it
491 activate(widget);
492
493 // Set x and y relative to the child's coordinates
494 mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX());
495 mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY());
496 widget.onMouseUp(mouse);
497 return;
498 }
499 }
500 }
501
502 /**
503 * Method that subclasses can override to handle mouse movements.
504 *
505 * @param mouse mouse motion event
506 */
507 public void onMouseMotion(final TMouseEvent mouse) {
508 // Default: do nothing, pass it on to ALL of my children. This way
509 // the children can see the mouse "leaving" their area.
510 for (TWidget widget: children) {
511 // Set x and y relative to the child's coordinates
512 mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX());
513 mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY());
514 widget.onMouseMotion(mouse);
515 }
516 }
517
518 /**
519 * Method that subclasses can override to handle mouse button
520 * double-clicks.
521 *
522 * @param mouse mouse button event
523 */
524 public void onMouseDoubleClick(final TMouseEvent mouse) {
525 // Default: do nothing, pass to children instead
526 if (activeChild != null) {
527 if (activeChild.mouseWouldHit(mouse)) {
528 // Dispatch to the active child
529
530 // Set x and y relative to the child's coordinates
531 mouse.setX(mouse.getAbsoluteX() - activeChild.getAbsoluteX());
532 mouse.setY(mouse.getAbsoluteY() - activeChild.getAbsoluteY());
533 activeChild.onMouseDoubleClick(mouse);
534 return;
535 }
536 }
537 for (int i = children.size() - 1 ; i >= 0 ; i--) {
538 TWidget widget = children.get(i);
539 if (widget.mouseWouldHit(mouse)) {
540 // Dispatch to this child, also activate it
541 activate(widget);
542
543 // Set x and y relative to the child's coordinates
544 mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX());
545 mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY());
546 widget.onMouseDoubleClick(mouse);
547 return;
548 }
549 }
550 }
551
552 /**
553 * Method that subclasses can override to handle window/screen resize
554 * events.
555 *
556 * @param resize resize event
557 */
558 public void onResize(final TResizeEvent resize) {
559 // Default: change my width/height.
560 if (resize.getType() == TResizeEvent.Type.WIDGET) {
561 width = resize.getWidth();
562 height = resize.getHeight();
563 } else {
564 // Let children see the screen resize
565 for (TWidget widget: children) {
566 widget.onResize(resize);
567 }
568 }
569 }
570
571 /**
572 * Method that subclasses can override to handle posted command events.
573 *
574 * @param command command event
575 */
576 public void onCommand(final TCommandEvent command) {
577 // Default: do nothing, pass to children instead
578 for (TWidget widget: children) {
579 widget.onCommand(command);
580 }
581 }
582
583 /**
584 * Method that subclasses can override to handle menu or posted menu
585 * events.
586 *
587 * @param menu menu event
588 */
589 public void onMenu(final TMenuEvent menu) {
590 // Default: do nothing, pass to children instead
591 for (TWidget widget: children) {
592 widget.onMenu(menu);
593 }
594 }
595
596 /**
597 * Method that subclasses can override to do processing when the UI is
598 * idle. Note that repainting is NOT assumed. To get a refresh after
599 * onIdle, call doRepaint().
600 */
601 public void onIdle() {
602 // Default: do nothing, pass to children instead
603 for (TWidget widget: children) {
604 widget.onIdle();
605 }
606 }
607
608 /**
609 * Consume event. Subclasses that want to intercept all events in one go
610 * can override this method.
611 *
612 * @param event keyboard, mouse, resize, command, or menu event
613 */
614 public void handleEvent(final TInputEvent event) {
615 /*
616 System.err.printf("TWidget (%s) event: %s\n", this.getClass().getName(),
617 event);
618 */
619
620 if (!enabled) {
621 // Discard event
622 // System.err.println(" -- discard --");
623 return;
624 }
625
626 if (event instanceof TKeypressEvent) {
627 onKeypress((TKeypressEvent) event);
628 } else if (event instanceof TMouseEvent) {
629
630 TMouseEvent mouse = (TMouseEvent) event;
631
632 switch (mouse.getType()) {
633
634 case MOUSE_DOWN:
635 onMouseDown(mouse);
636 break;
637
638 case MOUSE_UP:
639 onMouseUp(mouse);
640 break;
641
642 case MOUSE_MOTION:
643 onMouseMotion(mouse);
644 break;
645
646 case MOUSE_DOUBLE_CLICK:
647 onMouseDoubleClick(mouse);
648 break;
649
650 default:
651 throw new IllegalArgumentException("Invalid mouse event type: "
652 + mouse.getType());
653 }
654 } else if (event instanceof TResizeEvent) {
655 onResize((TResizeEvent) event);
656 } else if (event instanceof TCommandEvent) {
657 onCommand((TCommandEvent) event);
658 } else if (event instanceof TMenuEvent) {
659 onMenu((TMenuEvent) event);
660 }
661
662 // Do nothing else
663 return;
664 }
665
666 // ------------------------------------------------------------------------
667 // TWidget ----------------------------------------------------------------
668 // ------------------------------------------------------------------------
669
670 /**
671 * Get parent widget.
672 *
673 * @return parent widget
674 */
675 public final TWidget getParent() {
676 return parent;
677 }
678
679 /**
680 * Get the list of child widgets that this widget contains.
681 *
682 * @return the list of child widgets
683 */
684 public List<TWidget> getChildren() {
685 return children;
686 }
687
688 /**
689 * Get active flag.
690 *
691 * @return if true, this widget will receive events
692 */
693 public final boolean isActive() {
694 return active;
695 }
696
697 /**
698 * Set active flag.
699 *
700 * @param active if true, this widget will receive events
701 */
702 public final void setActive(final boolean active) {
703 this.active = active;
704 }
705
706 /**
707 * Get the window this widget is on.
708 *
709 * @return the window
710 */
711 public final TWindow getWindow() {
712 return window;
713 }
714
715 /**
716 * Get X position.
717 *
718 * @return absolute X position of the top-left corner
719 */
720 public final int getX() {
721 return x;
722 }
723
724 /**
725 * Set X position.
726 *
727 * @param x absolute X position of the top-left corner
728 */
729 public final void setX(final int x) {
730 this.x = x;
731 }
732
733 /**
734 * Get Y position.
735 *
736 * @return absolute Y position of the top-left corner
737 */
738 public final int getY() {
739 return y;
740 }
741
742 /**
743 * Set Y position.
744 *
745 * @param y absolute Y position of the top-left corner
746 */
747 public final void setY(final int y) {
748 this.y = y;
749 }
750
751 /**
752 * Get the width.
753 *
754 * @return widget width
755 */
756 public final int getWidth() {
757 return this.width;
758 }
759
760 /**
761 * Change the width.
762 *
763 * @param width new widget width
764 */
765 public final void setWidth(final int width) {
766 this.width = width;
767 }
768
769 /**
770 * Get the height.
771 *
772 * @return widget height
773 */
774 public final int getHeight() {
775 return this.height;
776 }
777
778 /**
779 * Change the height.
780 *
781 * @param height new widget height
782 */
783 public final void setHeight(final int height) {
784 this.height = height;
785 }
786
787 /**
788 * Change the dimensions.
789 *
790 * @param x absolute X position of the top-left corner
791 * @param y absolute Y position of the top-left corner
792 * @param width new widget width
793 * @param height new widget height
794 */
795 public final void setDimensions(final int x, final int y, final int width,
796 final int height) {
797
798 setX(x);
799 setY(y);
800 setWidth(width);
801 setHeight(height);
802 }
803
804 /**
805 * Get enabled flag.
806 *
807 * @return if true, this widget can be tabbed to or receive events
808 */
809 public final boolean isEnabled() {
810 return enabled;
811 }
812
813 /**
814 * Set enabled flag.
815 *
816 * @param enabled if true, this widget can be tabbed to or receive events
817 */
818 public final void setEnabled(final boolean enabled) {
819 this.enabled = enabled;
820 if (!enabled) {
821 active = false;
822 // See if there are any active siblings to switch to
823 boolean foundSibling = false;
824 if (parent != null) {
825 for (TWidget w: parent.children) {
826 if ((w.enabled)
827 && !(this instanceof THScroller)
828 && !(this instanceof TVScroller)
829 ) {
830 parent.activate(w);
831 foundSibling = true;
832 break;
833 }
834 }
835 if (!foundSibling) {
836 parent.activeChild = null;
837 }
838 }
839 }
840 }
841
842 /**
843 * Set visible flag.
844 *
845 * @param visible if true, this widget will be drawn
846 */
847 public final void setVisible(final boolean visible) {
848 this.visible = visible;
849 }
850
851 /**
852 * See if this widget is visible.
853 *
854 * @return if true, this widget will be drawn
855 */
856 public final boolean isVisible() {
857 return visible;
858 }
859
860 /**
861 * Set visible cursor flag.
862 *
863 * @param cursorVisible if true, this widget has a cursor
864 */
865 public final void setCursorVisible(final boolean cursorVisible) {
866 this.cursorVisible = cursorVisible;
867 }
868
869 /**
870 * See if this widget has a visible cursor.
871 *
872 * @return if true, this widget has a visible cursor
873 */
874 public final boolean isCursorVisible() {
875 // If cursor is out of my bounds, it is not visible.
876 if ((cursorX >= width)
877 || (cursorX < 0)
878 || (cursorY >= height)
879 || (cursorY < 0)
880 ) {
881 return false;
882 }
883
884 // If cursor is out of my window's bounds, it is not visible.
885 if ((getCursorAbsoluteX() >= window.getAbsoluteX()
886 + window.getWidth() - 1)
887 || (getCursorAbsoluteX() < 0)
888 || (getCursorAbsoluteY() >= window.getAbsoluteY()
889 + window.getHeight() - 1)
890 || (getCursorAbsoluteY() < 0)
891 ) {
892 return false;
893 }
894 return cursorVisible;
895 }
896
897 /**
898 * Get cursor X value.
899 *
900 * @return cursor column position in relative coordinates
901 */
902 public final int getCursorX() {
903 return cursorX;
904 }
905
906 /**
907 * Set cursor X value.
908 *
909 * @param cursorX column position in relative coordinates
910 */
911 public final void setCursorX(final int cursorX) {
912 this.cursorX = cursorX;
913 }
914
915 /**
916 * Get cursor Y value.
917 *
918 * @return cursor row position in relative coordinates
919 */
920 public final int getCursorY() {
921 return cursorY;
922 }
923
924 /**
925 * Set cursor Y value.
926 *
927 * @param cursorY row position in relative coordinates
928 */
929 public final void setCursorY(final int cursorY) {
930 this.cursorY = cursorY;
931 }
932
933 /**
934 * Get this TWidget's parent TApplication.
935 *
936 * @return the parent TApplication
937 */
938 public TApplication getApplication() {
939 return window.getApplication();
940 }
941
942 /**
943 * Get the Screen.
944 *
945 * @return the Screen
946 */
947 public Screen getScreen() {
948 return window.getScreen();
949 }
950
951 /**
952 * Comparison operator. For various subclasses it sorts on:
953 * <ul>
954 * <li>tabOrder for TWidgets</li>
955 * <li>z for TWindows</li>
956 * <li>text for TTreeItems</li>
957 * </ul>
958 *
959 * @param that another TWidget, TWindow, or TTreeItem instance
960 * @return difference between this.tabOrder and that.tabOrder, or
961 * difference between this.z and that.z, or String.compareTo(text)
962 */
963 public final int compareTo(final TWidget that) {
964 if ((this instanceof TWindow)
965 && (that instanceof TWindow)
966 ) {
967 return (((TWindow) this).getZ() - ((TWindow) that).getZ());
968 }
969 if ((this instanceof TTreeItem)
970 && (that instanceof TTreeItem)
971 ) {
972 return (((TTreeItem) this).getText().compareTo(
973 ((TTreeItem) that).getText()));
974 }
975 return (this.tabOrder - that.tabOrder);
976 }
977
978 /**
979 * See if this widget should render with the active color.
980 *
981 * @return true if this widget is active and all of its parents are
982 * active.
983 */
984 public final boolean isAbsoluteActive() {
985 if (parent == this) {
986 return active;
987 }
988 return (active && parent.isAbsoluteActive());
989 }
990
991 /**
992 * Returns the cursor X position.
993 *
994 * @return absolute screen column number for the cursor's X position
995 */
996 public final int getCursorAbsoluteX() {
997 return getAbsoluteX() + cursorX;
998 }
999
1000 /**
1001 * Returns the cursor Y position.
1002 *
1003 * @return absolute screen row number for the cursor's Y position
1004 */
1005 public final int getCursorAbsoluteY() {
1006 return getAbsoluteY() + cursorY;
1007 }
1008
1009 /**
1010 * Compute my absolute X position as the sum of my X plus all my parent's
1011 * X's.
1012 *
1013 * @return absolute screen column number for my X position
1014 */
1015 public final int getAbsoluteX() {
1016 assert (parent != null);
1017 if (parent == this) {
1018 return x;
1019 }
1020 if ((parent instanceof TWindow)
1021 && !(parent instanceof TMenu)
1022 && !(parent instanceof TDesktop)
1023 ) {
1024 // Widgets on a TWindow have (0,0) as their top-left, but this is
1025 // actually the TWindow's (1,1).
1026 return parent.getAbsoluteX() + x + 1;
1027 }
1028 return parent.getAbsoluteX() + x;
1029 }
1030
1031 /**
1032 * Compute my absolute Y position as the sum of my Y plus all my parent's
1033 * Y's.
1034 *
1035 * @return absolute screen row number for my Y position
1036 */
1037 public final int getAbsoluteY() {
1038 assert (parent != null);
1039 if (parent == this) {
1040 return y;
1041 }
1042 if ((parent instanceof TWindow)
1043 && !(parent instanceof TMenu)
1044 && !(parent instanceof TDesktop)
1045 ) {
1046 // Widgets on a TWindow have (0,0) as their top-left, but this is
1047 // actually the TWindow's (1,1).
1048 return parent.getAbsoluteY() + y + 1;
1049 }
1050 return parent.getAbsoluteY() + y;
1051 }
1052
1053 /**
1054 * Get the global color theme.
1055 *
1056 * @return the ColorTheme
1057 */
1058 protected final ColorTheme getTheme() {
1059 return window.getApplication().getTheme();
1060 }
1061
1062 /**
1063 * Draw my specific widget. When called, the screen rectangle I draw
1064 * into is already setup (offset and clipping).
1065 */
1066 public void draw() {
1067 // Default widget draws nothing.
1068 }
1069
1070 /**
1071 * Called by parent to render to TWindow. Note package private access.
1072 */
1073 final void drawChildren() {
1074 // Set my clipping rectangle
1075 assert (window != null);
1076 assert (getScreen() != null);
1077 Screen screen = getScreen();
1078
1079 // Special case: TStatusBar is drawn by TApplication, not anything
1080 // else.
1081 if (this instanceof TStatusBar) {
1082 return;
1083 }
1084
1085 screen.setClipRight(width);
1086 screen.setClipBottom(height);
1087
1088 int absoluteRightEdge = window.getAbsoluteX() + window.getWidth();
1089 int absoluteBottomEdge = window.getAbsoluteY() + window.getHeight();
1090 if (!(this instanceof TWindow) && !(this instanceof TVScroller)) {
1091 absoluteRightEdge -= 1;
1092 }
1093 if (!(this instanceof TWindow) && !(this instanceof THScroller)) {
1094 absoluteBottomEdge -= 1;
1095 }
1096 int myRightEdge = getAbsoluteX() + width;
1097 int myBottomEdge = getAbsoluteY() + height;
1098 if (getAbsoluteX() > absoluteRightEdge) {
1099 // I am offscreen
1100 screen.setClipRight(0);
1101 } else if (myRightEdge > absoluteRightEdge) {
1102 screen.setClipRight(screen.getClipRight()
1103 - (myRightEdge - absoluteRightEdge));
1104 }
1105 if (getAbsoluteY() > absoluteBottomEdge) {
1106 // I am offscreen
1107 screen.setClipBottom(0);
1108 } else if (myBottomEdge > absoluteBottomEdge) {
1109 screen.setClipBottom(screen.getClipBottom()
1110 - (myBottomEdge - absoluteBottomEdge));
1111 }
1112
1113 // Set my offset
1114 screen.setOffsetX(getAbsoluteX());
1115 screen.setOffsetY(getAbsoluteY());
1116
1117 // Draw me
1118 draw();
1119 assert (visible == true);
1120
1121 // Continue down the chain. Draw the active child last so that it
1122 // is on top.
1123 for (TWidget widget: children) {
1124 if (widget.isVisible() && (widget != activeChild)) {
1125 widget.drawChildren();
1126 }
1127 }
1128 if (activeChild != null) {
1129 activeChild.drawChildren();
1130 }
1131 }
1132
1133 /**
1134 * Repaint the screen on the next update.
1135 */
1136 protected final void doRepaint() {
1137 window.getApplication().doRepaint();
1138 }
1139
1140 /**
1141 * Add a child widget to my list of children. We set its tabOrder to 0
1142 * and increment the tabOrder of all other children.
1143 *
1144 * @param child TWidget to add
1145 */
1146 private void addChild(final TWidget child) {
1147 children.add(child);
1148
1149 if ((child.enabled)
1150 && !(child instanceof THScroller)
1151 && !(child instanceof TVScroller)
1152 ) {
1153 for (TWidget widget: children) {
1154 widget.active = false;
1155 }
1156 child.active = true;
1157 activeChild = child;
1158 }
1159 for (int i = 0; i < children.size(); i++) {
1160 children.get(i).tabOrder = i;
1161 }
1162 }
1163
1164 /**
1165 * Reset the tab order of children to match their position in the list.
1166 * Available so that subclasses can re-order their widgets if needed.
1167 */
1168 protected void resetTabOrder() {
1169 for (int i = 0; i < children.size(); i++) {
1170 children.get(i).tabOrder = i;
1171 }
1172 }
1173
1174 /**
1175 * Switch the active child.
1176 *
1177 * @param child TWidget to activate
1178 */
1179 public final void activate(final TWidget child) {
1180 assert (child.enabled);
1181 if ((child instanceof THScroller)
1182 || (child instanceof TVScroller)
1183 ) {
1184 return;
1185 }
1186
1187 if (children.size() == 1) {
1188 if (children.get(0).enabled == true) {
1189 child.active = true;
1190 activeChild = child;
1191 }
1192 } else {
1193 if (child != activeChild) {
1194 if (activeChild != null) {
1195 activeChild.active = false;
1196 }
1197 child.active = true;
1198 activeChild = child;
1199 }
1200 }
1201 }
1202
1203 /**
1204 * Switch the active child.
1205 *
1206 * @param tabOrder tabOrder of the child to activate. If that child
1207 * isn't enabled, then the next enabled child will be activated.
1208 */
1209 public final void activate(final int tabOrder) {
1210 if (children.size() == 1) {
1211 if (children.get(0).enabled == true) {
1212 children.get(0).active = true;
1213 activeChild = children.get(0);
1214 }
1215 return;
1216 }
1217
1218 TWidget child = null;
1219 for (TWidget widget: children) {
1220 if ((widget.enabled)
1221 && !(widget instanceof THScroller)
1222 && !(widget instanceof TVScroller)
1223 && (widget.tabOrder >= tabOrder)
1224 ) {
1225 child = widget;
1226 break;
1227 }
1228 }
1229 if ((child != null) && (child != activeChild)) {
1230 if (activeChild != null) {
1231 activeChild.active = false;
1232 }
1233 assert (child.enabled);
1234 child.active = true;
1235 activeChild = child;
1236 }
1237 }
1238
1239 /**
1240 * Switch the active widget with the next in the tab order.
1241 *
1242 * @param forward if true, then switch to the next enabled widget in the
1243 * list, otherwise switch to the previous enabled widget in the list
1244 */
1245 public final void switchWidget(final boolean forward) {
1246
1247 // No children: do nothing.
1248 if (children.size() == 0) {
1249 return;
1250 }
1251
1252 // If there is only one child, make it active if it is enabled.
1253 if (children.size() == 1) {
1254 if (children.get(0).enabled == true) {
1255 activeChild = children.get(0);
1256 activeChild.active = true;
1257 } else {
1258 children.get(0).active = false;
1259 activeChild = null;
1260 }
1261 return;
1262 }
1263
1264 // Two or more children: go forward or backward to the next enabled
1265 // child.
1266 int tabOrder = 0;
1267 if (activeChild != null) {
1268 tabOrder = activeChild.tabOrder;
1269 }
1270 do {
1271 if (forward) {
1272 tabOrder++;
1273 } else {
1274 tabOrder--;
1275 }
1276 if (tabOrder < 0) {
1277
1278 // If at the end, pass the switch to my parent.
1279 if ((!forward) && (parent != this)) {
1280 parent.switchWidget(forward);
1281 return;
1282 }
1283
1284 tabOrder = children.size() - 1;
1285 } else if (tabOrder == children.size()) {
1286 // If at the end, pass the switch to my parent.
1287 if ((forward) && (parent != this)) {
1288 parent.switchWidget(forward);
1289 return;
1290 }
1291
1292 tabOrder = 0;
1293 }
1294 if (activeChild == null) {
1295 if (tabOrder == 0) {
1296 // We wrapped around
1297 break;
1298 }
1299 } else if (activeChild.tabOrder == tabOrder) {
1300 // We wrapped around
1301 break;
1302 }
1303 } while ((!children.get(tabOrder).enabled)
1304 && !(children.get(tabOrder) instanceof THScroller)
1305 && !(children.get(tabOrder) instanceof TVScroller));
1306
1307 if (activeChild != null) {
1308 assert (children.get(tabOrder).enabled);
1309
1310 activeChild.active = false;
1311 }
1312 if (children.get(tabOrder).enabled == true) {
1313 children.get(tabOrder).active = true;
1314 activeChild = children.get(tabOrder);
1315 }
1316 }
1317
1318 /**
1319 * Returns my active widget.
1320 *
1321 * @return widget that is active, or this if no children
1322 */
1323 public TWidget getActiveChild() {
1324 if ((this instanceof THScroller)
1325 || (this instanceof TVScroller)
1326 ) {
1327 return parent;
1328 }
1329
1330 for (TWidget widget: children) {
1331 if (widget.active) {
1332 return widget.getActiveChild();
1333 }
1334 }
1335 // No active children, return me
1336 return this;
1337 }
1338
1339 // ------------------------------------------------------------------------
1340 // Passthru for Screen functions ------------------------------------------
1341 // ------------------------------------------------------------------------
1342
1343 /**
1344 * Get the attributes at one location.
1345 *
1346 * @param x column coordinate. 0 is the left-most column.
1347 * @param y row coordinate. 0 is the top-most row.
1348 * @return attributes at (x, y)
1349 */
1350 protected final CellAttributes getAttrXY(final int x, final int y) {
1351 return getScreen().getAttrXY(x, y);
1352 }
1353
1354 /**
1355 * Set the attributes at one location.
1356 *
1357 * @param x column coordinate. 0 is the left-most column.
1358 * @param y row coordinate. 0 is the top-most row.
1359 * @param attr attributes to use (bold, foreColor, backColor)
1360 */
1361 protected final void putAttrXY(final int x, final int y,
1362 final CellAttributes attr) {
1363
1364 getScreen().putAttrXY(x, y, attr);
1365 }
1366
1367 /**
1368 * Set the attributes at one location.
1369 *
1370 * @param x column coordinate. 0 is the left-most column.
1371 * @param y row coordinate. 0 is the top-most row.
1372 * @param attr attributes to use (bold, foreColor, backColor)
1373 * @param clip if true, honor clipping/offset
1374 */
1375 protected final void putAttrXY(final int x, final int y,
1376 final CellAttributes attr, final boolean clip) {
1377
1378 getScreen().putAttrXY(x, y, attr, clip);
1379 }
1380
1381 /**
1382 * Fill the entire screen with one character with attributes.
1383 *
1384 * @param ch character to draw
1385 * @param attr attributes to use (bold, foreColor, backColor)
1386 */
1387 protected final void putAll(final char ch, final CellAttributes attr) {
1388 getScreen().putAll(ch, attr);
1389 }
1390
1391 /**
1392 * Render one character with attributes.
1393 *
1394 * @param x column coordinate. 0 is the left-most column.
1395 * @param y row coordinate. 0 is the top-most row.
1396 * @param ch character + attributes to draw
1397 */
1398 protected final void putCharXY(final int x, final int y, final Cell ch) {
1399 getScreen().putCharXY(x, y, ch);
1400 }
1401
1402 /**
1403 * Render one character with attributes.
1404 *
1405 * @param x column coordinate. 0 is the left-most column.
1406 * @param y row coordinate. 0 is the top-most row.
1407 * @param ch character to draw
1408 * @param attr attributes to use (bold, foreColor, backColor)
1409 */
1410 protected final void putCharXY(final int x, final int y, final char ch,
1411 final CellAttributes attr) {
1412
1413 getScreen().putCharXY(x, y, ch, attr);
1414 }
1415
1416 /**
1417 * Render one character without changing the underlying attributes.
1418 *
1419 * @param x column coordinate. 0 is the left-most column.
1420 * @param y row coordinate. 0 is the top-most row.
1421 * @param ch character to draw
1422 */
1423 protected final void putCharXY(final int x, final int y, final char ch) {
1424 getScreen().putCharXY(x, y, ch);
1425 }
1426
1427 /**
1428 * Render a string. Does not wrap if the string exceeds the line.
1429 *
1430 * @param x column coordinate. 0 is the left-most column.
1431 * @param y row coordinate. 0 is the top-most row.
1432 * @param str string to draw
1433 * @param attr attributes to use (bold, foreColor, backColor)
1434 */
1435 protected final void putStringXY(final int x, final int y, final String str,
1436 final CellAttributes attr) {
1437
1438 getScreen().putStringXY(x, y, str, attr);
1439 }
1440
1441 /**
1442 * Render a string without changing the underlying attribute. Does not
1443 * wrap if the string exceeds the line.
1444 *
1445 * @param x column coordinate. 0 is the left-most column.
1446 * @param y row coordinate. 0 is the top-most row.
1447 * @param str string to draw
1448 */
1449 protected final void putStringXY(final int x, final int y, final String str) {
1450 getScreen().putStringXY(x, y, str);
1451 }
1452
1453 /**
1454 * Draw a vertical line from (x, y) to (x, y + n).
1455 *
1456 * @param x column coordinate. 0 is the left-most column.
1457 * @param y row coordinate. 0 is the top-most row.
1458 * @param n number of characters to draw
1459 * @param ch character to draw
1460 * @param attr attributes to use (bold, foreColor, backColor)
1461 */
1462 protected final void vLineXY(final int x, final int y, final int n,
1463 final char ch, final CellAttributes attr) {
1464
1465 getScreen().vLineXY(x, y, n, ch, attr);
1466 }
1467
1468 /**
1469 * Draw a horizontal line from (x, y) to (x + n, y).
1470 *
1471 * @param x column coordinate. 0 is the left-most column.
1472 * @param y row coordinate. 0 is the top-most row.
1473 * @param n number of characters to draw
1474 * @param ch character to draw
1475 * @param attr attributes to use (bold, foreColor, backColor)
1476 */
1477 protected final void hLineXY(final int x, final int y, final int n,
1478 final char ch, final CellAttributes attr) {
1479
1480 getScreen().hLineXY(x, y, n, ch, attr);
1481 }
1482
1483 /**
1484 * Draw a box with a border and empty background.
1485 *
1486 * @param left left column of box. 0 is the left-most row.
1487 * @param top top row of the box. 0 is the top-most row.
1488 * @param right right column of box
1489 * @param bottom bottom row of the box
1490 * @param border attributes to use for the border
1491 * @param background attributes to use for the background
1492 */
1493 protected final void drawBox(final int left, final int top,
1494 final int right, final int bottom,
1495 final CellAttributes border, final CellAttributes background) {
1496
1497 getScreen().drawBox(left, top, right, bottom, border, background);
1498 }
1499
1500 /**
1501 * Draw a box with a border and empty background.
1502 *
1503 * @param left left column of box. 0 is the left-most row.
1504 * @param top top row of the box. 0 is the top-most row.
1505 * @param right right column of box
1506 * @param bottom bottom row of the box
1507 * @param border attributes to use for the border
1508 * @param background attributes to use for the background
1509 * @param borderType if 1, draw a single-line border; if 2, draw a
1510 * double-line border; if 3, draw double-line top/bottom edges and
1511 * single-line left/right edges (like Qmodem)
1512 * @param shadow if true, draw a "shadow" on the box
1513 */
1514 protected final void drawBox(final int left, final int top,
1515 final int right, final int bottom,
1516 final CellAttributes border, final CellAttributes background,
1517 final int borderType, final boolean shadow) {
1518
1519 getScreen().drawBox(left, top, right, bottom, border, background,
1520 borderType, shadow);
1521 }
1522
1523 /**
1524 * Draw a box shadow.
1525 *
1526 * @param left left column of box. 0 is the left-most row.
1527 * @param top top row of the box. 0 is the top-most row.
1528 * @param right right column of box
1529 * @param bottom bottom row of the box
1530 */
1531 protected final void drawBoxShadow(final int left, final int top,
1532 final int right, final int bottom) {
1533
1534 getScreen().drawBoxShadow(left, top, right, bottom);
1535 }
1536
1537 // ------------------------------------------------------------------------
1538 // Other TWidget constructors ---------------------------------------------
1539 // ------------------------------------------------------------------------
1540
1541 /**
1542 * Convenience function to add a label to this container/window.
1543 *
1544 * @param text label
1545 * @param x column relative to parent
1546 * @param y row relative to parent
1547 * @return the new label
1548 */
1549 public final TLabel addLabel(final String text, final int x, final int y) {
1550 return addLabel(text, x, y, "tlabel");
1551 }
1552
1553 /**
1554 * Convenience function to add a label to this container/window.
1555 *
1556 * @param text label
1557 * @param x column relative to parent
1558 * @param y row relative to parent
1559 * @param action to call when shortcut is pressed
1560 * @return the new label
1561 */
1562 public final TLabel addLabel(final String text, final int x, final int y,
1563 final TAction action) {
1564
1565 return addLabel(text, x, y, "tlabel", action);
1566 }
1567
1568 /**
1569 * Convenience function to add a label to this container/window.
1570 *
1571 * @param text label
1572 * @param x column relative to parent
1573 * @param y row relative to parent
1574 * @param colorKey ColorTheme key color to use for foreground text.
1575 * Default is "tlabel"
1576 * @return the new label
1577 */
1578 public final TLabel addLabel(final String text, final int x, final int y,
1579 final String colorKey) {
1580
1581 return new TLabel(this, text, x, y, colorKey);
1582 }
1583
1584 /**
1585 * Convenience function to add a label to this container/window.
1586 *
1587 * @param text label
1588 * @param x column relative to parent
1589 * @param y row relative to parent
1590 * @param colorKey ColorTheme key color to use for foreground text.
1591 * Default is "tlabel"
1592 * @param action to call when shortcut is pressed
1593 * @return the new label
1594 */
1595 public final TLabel addLabel(final String text, final int x, final int y,
1596 final String colorKey, final TAction action) {
1597
1598 return new TLabel(this, text, x, y, colorKey, action);
1599 }
1600
1601 /**
1602 * Convenience function to add a label to this container/window.
1603 *
1604 * @param text label
1605 * @param x column relative to parent
1606 * @param y row relative to parent
1607 * @param colorKey ColorTheme key color to use for foreground text.
1608 * Default is "tlabel"
1609 * @param useWindowBackground if true, use the window's background color
1610 * @return the new label
1611 */
1612 public final TLabel addLabel(final String text, final int x, final int y,
1613 final String colorKey, final boolean useWindowBackground) {
1614
1615 return new TLabel(this, text, x, y, colorKey, useWindowBackground);
1616 }
1617
1618 /**
1619 * Convenience function to add a label to this container/window.
1620 *
1621 * @param text label
1622 * @param x column relative to parent
1623 * @param y row relative to parent
1624 * @param colorKey ColorTheme key color to use for foreground text.
1625 * Default is "tlabel"
1626 * @param useWindowBackground if true, use the window's background color
1627 * @param action to call when shortcut is pressed
1628 * @return the new label
1629 */
1630 public final TLabel addLabel(final String text, final int x, final int y,
1631 final String colorKey, final boolean useWindowBackground,
1632 final TAction action) {
1633
1634 return new TLabel(this, text, x, y, colorKey, useWindowBackground,
1635 action);
1636 }
1637
1638 /**
1639 * Convenience function to add a button to this container/window.
1640 *
1641 * @param text label on the button
1642 * @param x column relative to parent
1643 * @param y row relative to parent
1644 * @param action action to call when button is pressed
1645 * @return the new button
1646 */
1647 public final TButton addButton(final String text, final int x, final int y,
1648 final TAction action) {
1649
1650 return new TButton(this, text, x, y, action);
1651 }
1652
1653 /**
1654 * Convenience function to add a checkbox to this container/window.
1655 *
1656 * @param x column relative to parent
1657 * @param y row relative to parent
1658 * @param label label to display next to (right of) the checkbox
1659 * @param checked initial check state
1660 * @return the new checkbox
1661 */
1662 public final TCheckBox addCheckBox(final int x, final int y,
1663 final String label, final boolean checked) {
1664
1665 return new TCheckBox(this, x, y, label, checked);
1666 }
1667
1668 /**
1669 * Convenience function to add a combobox to this container/window.
1670 *
1671 * @param x column relative to parent
1672 * @param y row relative to parent
1673 * @param width visible combobox width, including the down-arrow
1674 * @param values the possible values for the box, shown in the drop-down
1675 * @param valuesIndex the initial index in values, or -1 for no default
1676 * value
1677 * @param valuesHeight the height of the values drop-down when it is
1678 * visible
1679 * @param updateAction action to call when a new value is selected from
1680 * the list or enter is pressed in the edit field
1681 * @return the new combobox
1682 */
1683 public final TComboBox addComboBox(final int x, final int y,
1684 final int width, final List<String> values, final int valuesIndex,
1685 final int valuesHeight, final TAction updateAction) {
1686
1687 return new TComboBox(this, x, y, width, values, valuesIndex,
1688 valuesHeight, updateAction);
1689 }
1690
1691 /**
1692 * Convenience function to add a spinner to this container/window.
1693 *
1694 * @param x column relative to parent
1695 * @param y row relative to parent
1696 * @param upAction action to call when the up arrow is clicked or pressed
1697 * @param downAction action to call when the down arrow is clicked or
1698 * pressed
1699 * @return the new spinner
1700 */
1701 public final TSpinner addSpinner(final int x, final int y,
1702 final TAction upAction, final TAction downAction) {
1703
1704 return new TSpinner(this, x, y, upAction, downAction);
1705 }
1706
1707 /**
1708 * Convenience function to add a calendar to this container/window.
1709 *
1710 * @param x column relative to parent
1711 * @param y row relative to parent
1712 * @param updateAction action to call when the user changes the value of
1713 * the calendar
1714 * @return the new calendar
1715 */
1716 public final TCalendar addCalendar(final int x, final int y,
1717 final TAction updateAction) {
1718
1719 return new TCalendar(this, x, y, updateAction);
1720 }
1721
1722 /**
1723 * Convenience function to add a progress bar to this container/window.
1724 *
1725 * @param x column relative to parent
1726 * @param y row relative to parent
1727 * @param width width of progress bar
1728 * @param value initial value of percent complete
1729 * @return the new progress bar
1730 */
1731 public final TProgressBar addProgressBar(final int x, final int y,
1732 final int width, final int value) {
1733
1734 return new TProgressBar(this, x, y, width, value);
1735 }
1736
1737 /**
1738 * Convenience function to add a radio button group to this
1739 * container/window.
1740 *
1741 * @param x column relative to parent
1742 * @param y row relative to parent
1743 * @param label label to display on the group box
1744 * @return the new radio button group
1745 */
1746 public final TRadioGroup addRadioGroup(final int x, final int y,
1747 final String label) {
1748
1749 return new TRadioGroup(this, x, y, label);
1750 }
1751
1752 /**
1753 * Convenience function to add a text field to this container/window.
1754 *
1755 * @param x column relative to parent
1756 * @param y row relative to parent
1757 * @param width visible text width
1758 * @param fixed if true, the text cannot exceed the display width
1759 * @return the new text field
1760 */
1761 public final TField addField(final int x, final int y,
1762 final int width, final boolean fixed) {
1763
1764 return new TField(this, x, y, width, fixed);
1765 }
1766
1767 /**
1768 * Convenience function to add a text field to this container/window.
1769 *
1770 * @param x column relative to parent
1771 * @param y row relative to parent
1772 * @param width visible text width
1773 * @param fixed if true, the text cannot exceed the display width
1774 * @param text initial text, default is empty string
1775 * @return the new text field
1776 */
1777 public final TField addField(final int x, final int y,
1778 final int width, final boolean fixed, final String text) {
1779
1780 return new TField(this, x, y, width, fixed, text);
1781 }
1782
1783 /**
1784 * Convenience function to add a text field to this container/window.
1785 *
1786 * @param x column relative to parent
1787 * @param y row relative to parent
1788 * @param width visible text width
1789 * @param fixed if true, the text cannot exceed the display width
1790 * @param text initial text, default is empty string
1791 * @param enterAction function to call when enter key is pressed
1792 * @param updateAction function to call when the text is updated
1793 * @return the new text field
1794 */
1795 public final TField addField(final int x, final int y,
1796 final int width, final boolean fixed, final String text,
1797 final TAction enterAction, final TAction updateAction) {
1798
1799 return new TField(this, x, y, width, fixed, text, enterAction,
1800 updateAction);
1801 }
1802
1803 /**
1804 * Convenience function to add a scrollable text box to this
1805 * container/window.
1806 *
1807 * @param text text on the screen
1808 * @param x column relative to parent
1809 * @param y row relative to parent
1810 * @param width width of text area
1811 * @param height height of text area
1812 * @param colorKey ColorTheme key color to use for foreground text
1813 * @return the new text box
1814 */
1815 public final TText addText(final String text, final int x,
1816 final int y, final int width, final int height, final String colorKey) {
1817
1818 return new TText(this, text, x, y, width, height, colorKey);
1819 }
1820
1821 /**
1822 * Convenience function to add a scrollable text box to this
1823 * container/window.
1824 *
1825 * @param text text on the screen
1826 * @param x column relative to parent
1827 * @param y row relative to parent
1828 * @param width width of text area
1829 * @param height height of text area
1830 * @return the new text box
1831 */
1832 public final TText addText(final String text, final int x, final int y,
1833 final int width, final int height) {
1834
1835 return new TText(this, text, x, y, width, height, "ttext");
1836 }
1837
1838 /**
1839 * Convenience function to add an editable text area box to this
1840 * container/window.
1841 *
1842 * @param text text on the screen
1843 * @param x column relative to parent
1844 * @param y row relative to parent
1845 * @param width width of text area
1846 * @param height height of text area
1847 * @return the new text box
1848 */
1849 public final TEditorWidget addEditor(final String text, final int x,
1850 final int y, final int width, final int height) {
1851
1852 return new TEditorWidget(this, text, x, y, width, height);
1853 }
1854
1855 /**
1856 * Convenience function to spawn a message box.
1857 *
1858 * @param title window title, will be centered along the top border
1859 * @param caption message to display. Use embedded newlines to get a
1860 * multi-line box.
1861 * @return the new message box
1862 */
1863 public final TMessageBox messageBox(final String title,
1864 final String caption) {
1865
1866 return getApplication().messageBox(title, caption, TMessageBox.Type.OK);
1867 }
1868
1869 /**
1870 * Convenience function to spawn a message box.
1871 *
1872 * @param title window title, will be centered along the top border
1873 * @param caption message to display. Use embedded newlines to get a
1874 * multi-line box.
1875 * @param type one of the TMessageBox.Type constants. Default is
1876 * Type.OK.
1877 * @return the new message box
1878 */
1879 public final TMessageBox messageBox(final String title,
1880 final String caption, final TMessageBox.Type type) {
1881
1882 return getApplication().messageBox(title, caption, type);
1883 }
1884
1885 /**
1886 * Convenience function to spawn an input box.
1887 *
1888 * @param title window title, will be centered along the top border
1889 * @param caption message to display. Use embedded newlines to get a
1890 * multi-line box.
1891 * @return the new input box
1892 */
1893 public final TInputBox inputBox(final String title, final String caption) {
1894
1895 return getApplication().inputBox(title, caption);
1896 }
1897
1898 /**
1899 * Convenience function to spawn an input box.
1900 *
1901 * @param title window title, will be centered along the top border
1902 * @param caption message to display. Use embedded newlines to get a
1903 * multi-line box.
1904 * @param text initial text to seed the field with
1905 * @return the new input box
1906 */
1907 public final TInputBox inputBox(final String title, final String caption,
1908 final String text) {
1909
1910 return getApplication().inputBox(title, caption, text);
1911 }
1912
1913 /**
1914 * Convenience function to add a password text field to this
1915 * container/window.
1916 *
1917 * @param x column relative to parent
1918 * @param y row relative to parent
1919 * @param width visible text width
1920 * @param fixed if true, the text cannot exceed the display width
1921 * @return the new text field
1922 */
1923 public final TPasswordField addPasswordField(final int x, final int y,
1924 final int width, final boolean fixed) {
1925
1926 return new TPasswordField(this, x, y, width, fixed);
1927 }
1928
1929 /**
1930 * Convenience function to add a password text field to this
1931 * container/window.
1932 *
1933 * @param x column relative to parent
1934 * @param y row relative to parent
1935 * @param width visible text width
1936 * @param fixed if true, the text cannot exceed the display width
1937 * @param text initial text, default is empty string
1938 * @return the new text field
1939 */
1940 public final TPasswordField addPasswordField(final int x, final int y,
1941 final int width, final boolean fixed, final String text) {
1942
1943 return new TPasswordField(this, x, y, width, fixed, text);
1944 }
1945
1946 /**
1947 * Convenience function to add a password text field to this
1948 * container/window.
1949 *
1950 * @param x column relative to parent
1951 * @param y row relative to parent
1952 * @param width visible text width
1953 * @param fixed if true, the text cannot exceed the display width
1954 * @param text initial text, default is empty string
1955 * @param enterAction function to call when enter key is pressed
1956 * @param updateAction function to call when the text is updated
1957 * @return the new text field
1958 */
1959 public final TPasswordField addPasswordField(final int x, final int y,
1960 final int width, final boolean fixed, final String text,
1961 final TAction enterAction, final TAction updateAction) {
1962
1963 return new TPasswordField(this, x, y, width, fixed, text, enterAction,
1964 updateAction);
1965 }
1966
1967 /**
1968 * Convenience function to add a scrollable tree view to this
1969 * container/window.
1970 *
1971 * @param x column relative to parent
1972 * @param y row relative to parent
1973 * @param width width of tree view
1974 * @param height height of tree view
1975 * @return the new tree view
1976 */
1977 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
1978 final int width, final int height) {
1979
1980 return new TTreeViewWidget(this, x, y, width, height);
1981 }
1982
1983 /**
1984 * Convenience function to add a scrollable tree view to this
1985 * container/window.
1986 *
1987 * @param x column relative to parent
1988 * @param y row relative to parent
1989 * @param width width of tree view
1990 * @param height height of tree view
1991 * @param action action to perform when an item is selected
1992 * @return the new tree view
1993 */
1994 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
1995 final int width, final int height, final TAction action) {
1996
1997 return new TTreeViewWidget(this, x, y, width, height, action);
1998 }
1999
2000 /**
2001 * Convenience function to spawn a file open box.
2002 *
2003 * @param path path of selected file
2004 * @return the result of the new file open box
2005 * @throws IOException if a java.io operation throws
2006 */
2007 public final String fileOpenBox(final String path) throws IOException {
2008 return getApplication().fileOpenBox(path);
2009 }
2010
2011 /**
2012 * Convenience function to spawn a file save box.
2013 *
2014 * @param path path of selected file
2015 * @return the result of the new file open box
2016 * @throws IOException if a java.io operation throws
2017 */
2018 public final String fileSaveBox(final String path) throws IOException {
2019 return getApplication().fileOpenBox(path, TFileOpenBox.Type.SAVE);
2020 }
2021
2022 /**
2023 * Convenience function to spawn a file open box.
2024 *
2025 * @param path path of selected file
2026 * @param type one of the Type constants
2027 * @return the result of the new file open box
2028 * @throws IOException if a java.io operation throws
2029 */
2030 public final String fileOpenBox(final String path,
2031 final TFileOpenBox.Type type) throws IOException {
2032
2033 return getApplication().fileOpenBox(path, type);
2034 }
2035
2036 /**
2037 * Convenience function to spawn a file open box.
2038 *
2039 * @param path path of selected file
2040 * @param type one of the Type constants
2041 * @param filter a string that files must match to be displayed
2042 * @return the result of the new file open box
2043 * @throws IOException of a java.io operation throws
2044 */
2045 public final String fileOpenBox(final String path,
2046 final TFileOpenBox.Type type, final String filter) throws IOException {
2047
2048 ArrayList<String> filters = new ArrayList<String>();
2049 filters.add(filter);
2050
2051 return getApplication().fileOpenBox(path, type, filters);
2052 }
2053
2054 /**
2055 * Convenience function to spawn a file open box.
2056 *
2057 * @param path path of selected file
2058 * @param type one of the Type constants
2059 * @param filters a list of strings that files must match to be displayed
2060 * @return the result of the new file open box
2061 * @throws IOException of a java.io operation throws
2062 */
2063 public final String fileOpenBox(final String path,
2064 final TFileOpenBox.Type type,
2065 final List<String> filters) throws IOException {
2066
2067 return getApplication().fileOpenBox(path, type, filters);
2068 }
2069
2070 /**
2071 * Convenience function to add a directory list to this container/window.
2072 *
2073 * @param path directory path, must be a directory
2074 * @param x column relative to parent
2075 * @param y row relative to parent
2076 * @param width width of text area
2077 * @param height height of text area
2078 * @return the new directory list
2079 */
2080 public final TDirectoryList addDirectoryList(final String path, final int x,
2081 final int y, final int width, final int height) {
2082
2083 return new TDirectoryList(this, path, x, y, width, height, null);
2084 }
2085
2086 /**
2087 * Convenience function to add a directory list to this container/window.
2088 *
2089 * @param path directory path, must be a directory
2090 * @param x column relative to parent
2091 * @param y row relative to parent
2092 * @param width width of text area
2093 * @param height height of text area
2094 * @param action action to perform when an item is selected (enter or
2095 * double-click)
2096 * @return the new directory list
2097 */
2098 public final TDirectoryList addDirectoryList(final String path, final int x,
2099 final int y, final int width, final int height, final TAction action) {
2100
2101 return new TDirectoryList(this, path, x, y, width, height, action);
2102 }
2103
2104 /**
2105 * Convenience function to add a directory list to this container/window.
2106 *
2107 * @param path directory path, must be a directory
2108 * @param x column relative to parent
2109 * @param y row relative to parent
2110 * @param width width of text area
2111 * @param height height of text area
2112 * @param action action to perform when an item is selected (enter or
2113 * double-click)
2114 * @param singleClickAction action to perform when an item is selected
2115 * (single-click)
2116 * @return the new directory list
2117 */
2118 public final TDirectoryList addDirectoryList(final String path, final int x,
2119 final int y, final int width, final int height, final TAction action,
2120 final TAction singleClickAction) {
2121
2122 return new TDirectoryList(this, path, x, y, width, height, action,
2123 singleClickAction);
2124 }
2125
2126 /**
2127 * Convenience function to add a directory list to this container/window.
2128 *
2129 * @param path directory path, must be a directory
2130 * @param x column relative to parent
2131 * @param y row relative to parent
2132 * @param width width of text area
2133 * @param height height of text area
2134 * @param action action to perform when an item is selected (enter or
2135 * double-click)
2136 * @param singleClickAction action to perform when an item is selected
2137 * (single-click)
2138 * @param filters a list of strings that files must match to be displayed
2139 * @return the new directory list
2140 */
2141 public final TDirectoryList addDirectoryList(final String path, final int x,
2142 final int y, final int width, final int height, final TAction action,
2143 final TAction singleClickAction, final List<String> filters) {
2144
2145 return new TDirectoryList(this, path, x, y, width, height, action,
2146 singleClickAction, filters);
2147 }
2148
2149 /**
2150 * Convenience function to add a list to this container/window.
2151 *
2152 * @param strings list of strings to show
2153 * @param x column relative to parent
2154 * @param y row relative to parent
2155 * @param width width of text area
2156 * @param height height of text area
2157 * @return the new directory list
2158 */
2159 public final TList addList(final List<String> strings, final int x,
2160 final int y, final int width, final int height) {
2161
2162 return new TList(this, strings, x, y, width, height, null);
2163 }
2164
2165 /**
2166 * Convenience function to add a list to this container/window.
2167 *
2168 * @param strings list of strings to show
2169 * @param x column relative to parent
2170 * @param y row relative to parent
2171 * @param width width of text area
2172 * @param height height of text area
2173 * @param enterAction action to perform when an item is selected
2174 * @return the new directory list
2175 */
2176 public final TList addList(final List<String> strings, final int x,
2177 final int y, final int width, final int height,
2178 final TAction enterAction) {
2179
2180 return new TList(this, strings, x, y, width, height, enterAction);
2181 }
2182
2183 /**
2184 * Convenience function to add a list to this container/window.
2185 *
2186 * @param strings list of strings to show
2187 * @param x column relative to parent
2188 * @param y row relative to parent
2189 * @param width width of text area
2190 * @param height height of text area
2191 * @param enterAction action to perform when an item is selected
2192 * @param moveAction action to perform when the user navigates to a new
2193 * item with arrow/page keys
2194 * @return the new directory list
2195 */
2196 public final TList addList(final List<String> strings, final int x,
2197 final int y, final int width, final int height,
2198 final TAction enterAction, final TAction moveAction) {
2199
2200 return new TList(this, strings, x, y, width, height, enterAction,
2201 moveAction);
2202 }
2203
2204 }