Prep for 2019 release
[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 // Dispatch the keypress to an active widget
353 for (TWidget widget: children) {
354 if (widget.active) {
355 widget.onKeypress(keypress);
356 return;
357 }
358 }
359 }
360
361 /**
362 * Method that subclasses can override to handle mouse button presses.
363 *
364 * @param mouse mouse button event
365 */
366 public void onMouseDown(final TMouseEvent mouse) {
367 // Default: do nothing, pass to children instead
368 if (activeChild != null) {
369 if (activeChild.mouseWouldHit(mouse)) {
370 // Dispatch to the active child
371
372 // Set x and y relative to the child's coordinates
373 mouse.setX(mouse.getAbsoluteX() - activeChild.getAbsoluteX());
374 mouse.setY(mouse.getAbsoluteY() - activeChild.getAbsoluteY());
375 activeChild.onMouseDown(mouse);
376 return;
377 }
378 }
379 for (int i = children.size() - 1 ; i >= 0 ; i--) {
380 TWidget widget = children.get(i);
381 if (widget.mouseWouldHit(mouse)) {
382 // Dispatch to this child, also activate it
383 activate(widget);
384
385 // Set x and y relative to the child's coordinates
386 mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX());
387 mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY());
388 widget.onMouseDown(mouse);
389 return;
390 }
391 }
392 }
393
394 /**
395 * Method that subclasses can override to handle mouse button releases.
396 *
397 * @param mouse mouse button event
398 */
399 public void onMouseUp(final TMouseEvent mouse) {
400 // Default: do nothing, pass to children instead
401 if (activeChild != null) {
402 if (activeChild.mouseWouldHit(mouse)) {
403 // Dispatch to the active child
404
405 // Set x and y relative to the child's coordinates
406 mouse.setX(mouse.getAbsoluteX() - activeChild.getAbsoluteX());
407 mouse.setY(mouse.getAbsoluteY() - activeChild.getAbsoluteY());
408 activeChild.onMouseUp(mouse);
409 return;
410 }
411 }
412 for (int i = children.size() - 1 ; i >= 0 ; i--) {
413 TWidget widget = children.get(i);
414 if (widget.mouseWouldHit(mouse)) {
415 // Dispatch to this child, also activate it
416 activate(widget);
417
418 // Set x and y relative to the child's coordinates
419 mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX());
420 mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY());
421 widget.onMouseUp(mouse);
422 return;
423 }
424 }
425 }
426
427 /**
428 * Method that subclasses can override to handle mouse movements.
429 *
430 * @param mouse mouse motion event
431 */
432 public void onMouseMotion(final TMouseEvent mouse) {
433 // Default: do nothing, pass it on to ALL of my children. This way
434 // the children can see the mouse "leaving" their area.
435 for (TWidget widget: children) {
436 // Set x and y relative to the child's coordinates
437 mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX());
438 mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY());
439 widget.onMouseMotion(mouse);
440 }
441 }
442
443 /**
444 * Method that subclasses can override to handle mouse button
445 * double-clicks.
446 *
447 * @param mouse mouse button event
448 */
449 public void onMouseDoubleClick(final TMouseEvent mouse) {
450 // Default: do nothing, pass to children instead
451 if (activeChild != null) {
452 if (activeChild.mouseWouldHit(mouse)) {
453 // Dispatch to the active child
454
455 // Set x and y relative to the child's coordinates
456 mouse.setX(mouse.getAbsoluteX() - activeChild.getAbsoluteX());
457 mouse.setY(mouse.getAbsoluteY() - activeChild.getAbsoluteY());
458 activeChild.onMouseDoubleClick(mouse);
459 return;
460 }
461 }
462 for (int i = children.size() - 1 ; i >= 0 ; i--) {
463 TWidget widget = children.get(i);
464 if (widget.mouseWouldHit(mouse)) {
465 // Dispatch to this child, also activate it
466 activate(widget);
467
468 // Set x and y relative to the child's coordinates
469 mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX());
470 mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY());
471 widget.onMouseDoubleClick(mouse);
472 return;
473 }
474 }
475 }
476
477 /**
478 * Method that subclasses can override to handle window/screen resize
479 * events.
480 *
481 * @param resize resize event
482 */
483 public void onResize(final TResizeEvent resize) {
484 // Default: change my width/height.
485 if (resize.getType() == TResizeEvent.Type.WIDGET) {
486 width = resize.getWidth();
487 height = resize.getHeight();
488 } else {
489 // Let children see the screen resize
490 for (TWidget widget: children) {
491 widget.onResize(resize);
492 }
493 }
494 }
495
496 /**
497 * Method that subclasses can override to handle posted command events.
498 *
499 * @param command command event
500 */
501 public void onCommand(final TCommandEvent command) {
502 // Default: do nothing, pass to children instead
503 for (TWidget widget: children) {
504 widget.onCommand(command);
505 }
506 }
507
508 /**
509 * Method that subclasses can override to handle menu or posted menu
510 * events.
511 *
512 * @param menu menu event
513 */
514 public void onMenu(final TMenuEvent menu) {
515 // Default: do nothing, pass to children instead
516 for (TWidget widget: children) {
517 widget.onMenu(menu);
518 }
519 }
520
521 /**
522 * Method that subclasses can override to do processing when the UI is
523 * idle. Note that repainting is NOT assumed. To get a refresh after
524 * onIdle, call doRepaint().
525 */
526 public void onIdle() {
527 // Default: do nothing, pass to children instead
528 for (TWidget widget: children) {
529 widget.onIdle();
530 }
531 }
532
533 /**
534 * Consume event. Subclasses that want to intercept all events in one go
535 * can override this method.
536 *
537 * @param event keyboard, mouse, resize, command, or menu event
538 */
539 public void handleEvent(final TInputEvent event) {
540 /*
541 System.err.printf("TWidget (%s) event: %s\n", this.getClass().getName(),
542 event);
543 */
544
545 if (!enabled) {
546 // Discard event
547 // System.err.println(" -- discard --");
548 return;
549 }
550
551 if (event instanceof TKeypressEvent) {
552 onKeypress((TKeypressEvent) event);
553 } else if (event instanceof TMouseEvent) {
554
555 TMouseEvent mouse = (TMouseEvent) event;
556
557 switch (mouse.getType()) {
558
559 case MOUSE_DOWN:
560 onMouseDown(mouse);
561 break;
562
563 case MOUSE_UP:
564 onMouseUp(mouse);
565 break;
566
567 case MOUSE_MOTION:
568 onMouseMotion(mouse);
569 break;
570
571 case MOUSE_DOUBLE_CLICK:
572 onMouseDoubleClick(mouse);
573 break;
574
575 default:
576 throw new IllegalArgumentException("Invalid mouse event type: "
577 + mouse.getType());
578 }
579 } else if (event instanceof TResizeEvent) {
580 onResize((TResizeEvent) event);
581 } else if (event instanceof TCommandEvent) {
582 onCommand((TCommandEvent) event);
583 } else if (event instanceof TMenuEvent) {
584 onMenu((TMenuEvent) event);
585 }
586
587 // Do nothing else
588 return;
589 }
590
591 // ------------------------------------------------------------------------
592 // TWidget ----------------------------------------------------------------
593 // ------------------------------------------------------------------------
594
595 /**
596 * Get parent widget.
597 *
598 * @return parent widget
599 */
600 public final TWidget getParent() {
601 return parent;
602 }
603
604 /**
605 * Get the list of child widgets that this widget contains.
606 *
607 * @return the list of child widgets
608 */
609 public List<TWidget> getChildren() {
610 return children;
611 }
612
613 /**
614 * Get active flag.
615 *
616 * @return if true, this widget will receive events
617 */
618 public final boolean isActive() {
619 return active;
620 }
621
622 /**
623 * Set active flag.
624 *
625 * @param active if true, this widget will receive events
626 */
627 public final void setActive(final boolean active) {
628 this.active = active;
629 }
630
631 /**
632 * Get the window this widget is on.
633 *
634 * @return the window
635 */
636 public final TWindow getWindow() {
637 return window;
638 }
639
640 /**
641 * Get X position.
642 *
643 * @return absolute X position of the top-left corner
644 */
645 public final int getX() {
646 return x;
647 }
648
649 /**
650 * Set X position.
651 *
652 * @param x absolute X position of the top-left corner
653 */
654 public final void setX(final int x) {
655 this.x = x;
656 }
657
658 /**
659 * Get Y position.
660 *
661 * @return absolute Y position of the top-left corner
662 */
663 public final int getY() {
664 return y;
665 }
666
667 /**
668 * Set Y position.
669 *
670 * @param y absolute Y position of the top-left corner
671 */
672 public final void setY(final int y) {
673 this.y = y;
674 }
675
676 /**
677 * Get the width.
678 *
679 * @return widget width
680 */
681 public final int getWidth() {
682 return this.width;
683 }
684
685 /**
686 * Change the width.
687 *
688 * @param width new widget width
689 */
690 public final void setWidth(final int width) {
691 this.width = width;
692 }
693
694 /**
695 * Get the height.
696 *
697 * @return widget height
698 */
699 public final int getHeight() {
700 return this.height;
701 }
702
703 /**
704 * Change the height.
705 *
706 * @param height new widget height
707 */
708 public final void setHeight(final int height) {
709 this.height = height;
710 }
711
712 /**
713 * Change the dimensions.
714 *
715 * @param x absolute X position of the top-left corner
716 * @param y absolute Y position of the top-left corner
717 * @param width new widget width
718 * @param height new widget height
719 */
720 public final void setDimensions(final int x, final int y, final int width,
721 final int height) {
722
723 setX(x);
724 setY(y);
725 setWidth(width);
726 setHeight(height);
727 }
728
729 /**
730 * Get enabled flag.
731 *
732 * @return if true, this widget can be tabbed to or receive events
733 */
734 public final boolean isEnabled() {
735 return enabled;
736 }
737
738 /**
739 * Set enabled flag.
740 *
741 * @param enabled if true, this widget can be tabbed to or receive events
742 */
743 public final void setEnabled(final boolean enabled) {
744 this.enabled = enabled;
745 if (!enabled) {
746 active = false;
747 // See if there are any active siblings to switch to
748 boolean foundSibling = false;
749 if (parent != null) {
750 for (TWidget w: parent.children) {
751 if ((w.enabled)
752 && !(this instanceof THScroller)
753 && !(this instanceof TVScroller)
754 ) {
755 parent.activate(w);
756 foundSibling = true;
757 break;
758 }
759 }
760 if (!foundSibling) {
761 parent.activeChild = null;
762 }
763 }
764 }
765 }
766
767 /**
768 * Set visible flag.
769 *
770 * @param visible if true, this widget will be drawn
771 */
772 public final void setVisible(final boolean visible) {
773 this.visible = visible;
774 }
775
776 /**
777 * See if this widget is visible.
778 *
779 * @return if true, this widget will be drawn
780 */
781 public final boolean isVisible() {
782 return visible;
783 }
784
785 /**
786 * Set visible cursor flag.
787 *
788 * @param cursorVisible if true, this widget has a cursor
789 */
790 public final void setCursorVisible(final boolean cursorVisible) {
791 this.cursorVisible = cursorVisible;
792 }
793
794 /**
795 * See if this widget has a visible cursor.
796 *
797 * @return if true, this widget has a visible cursor
798 */
799 public final boolean isCursorVisible() {
800 // If cursor is out of my bounds, it is not visible.
801 if ((cursorX >= width)
802 || (cursorX < 0)
803 || (cursorY >= height)
804 || (cursorY < 0)
805 ) {
806 return false;
807 }
808
809 // If cursor is out of my window's bounds, it is not visible.
810 if ((getCursorAbsoluteX() >= window.getAbsoluteX()
811 + window.getWidth() - 1)
812 || (getCursorAbsoluteX() < 0)
813 || (getCursorAbsoluteY() >= window.getAbsoluteY()
814 + window.getHeight() - 1)
815 || (getCursorAbsoluteY() < 0)
816 ) {
817 return false;
818 }
819 return cursorVisible;
820 }
821
822 /**
823 * Get cursor X value.
824 *
825 * @return cursor column position in relative coordinates
826 */
827 public final int getCursorX() {
828 return cursorX;
829 }
830
831 /**
832 * Set cursor X value.
833 *
834 * @param cursorX column position in relative coordinates
835 */
836 public final void setCursorX(final int cursorX) {
837 this.cursorX = cursorX;
838 }
839
840 /**
841 * Get cursor Y value.
842 *
843 * @return cursor row position in relative coordinates
844 */
845 public final int getCursorY() {
846 return cursorY;
847 }
848
849 /**
850 * Set cursor Y value.
851 *
852 * @param cursorY row position in relative coordinates
853 */
854 public final void setCursorY(final int cursorY) {
855 this.cursorY = cursorY;
856 }
857
858 /**
859 * Get this TWidget's parent TApplication.
860 *
861 * @return the parent TApplication
862 */
863 public TApplication getApplication() {
864 return window.getApplication();
865 }
866
867 /**
868 * Get the Screen.
869 *
870 * @return the Screen
871 */
872 public Screen getScreen() {
873 return window.getScreen();
874 }
875
876 /**
877 * Comparison operator. For various subclasses it sorts on:
878 * <ul>
879 * <li>tabOrder for TWidgets</li>
880 * <li>z for TWindows</li>
881 * <li>text for TTreeItems</li>
882 * </ul>
883 *
884 * @param that another TWidget, TWindow, or TTreeItem instance
885 * @return difference between this.tabOrder and that.tabOrder, or
886 * difference between this.z and that.z, or String.compareTo(text)
887 */
888 public final int compareTo(final TWidget that) {
889 if ((this instanceof TWindow)
890 && (that instanceof TWindow)
891 ) {
892 return (((TWindow) this).getZ() - ((TWindow) that).getZ());
893 }
894 if ((this instanceof TTreeItem)
895 && (that instanceof TTreeItem)
896 ) {
897 return (((TTreeItem) this).getText().compareTo(
898 ((TTreeItem) that).getText()));
899 }
900 return (this.tabOrder - that.tabOrder);
901 }
902
903 /**
904 * See if this widget should render with the active color.
905 *
906 * @return true if this widget is active and all of its parents are
907 * active.
908 */
909 public final boolean isAbsoluteActive() {
910 if (parent == this) {
911 return active;
912 }
913 return (active && parent.isAbsoluteActive());
914 }
915
916 /**
917 * Returns the cursor X position.
918 *
919 * @return absolute screen column number for the cursor's X position
920 */
921 public final int getCursorAbsoluteX() {
922 return getAbsoluteX() + cursorX;
923 }
924
925 /**
926 * Returns the cursor Y position.
927 *
928 * @return absolute screen row number for the cursor's Y position
929 */
930 public final int getCursorAbsoluteY() {
931 return getAbsoluteY() + cursorY;
932 }
933
934 /**
935 * Compute my absolute X position as the sum of my X plus all my parent's
936 * X's.
937 *
938 * @return absolute screen column number for my X position
939 */
940 public final int getAbsoluteX() {
941 assert (parent != null);
942 if (parent == this) {
943 return x;
944 }
945 if ((parent instanceof TWindow)
946 && !(parent instanceof TMenu)
947 && !(parent instanceof TDesktop)
948 ) {
949 // Widgets on a TWindow have (0,0) as their top-left, but this is
950 // actually the TWindow's (1,1).
951 return parent.getAbsoluteX() + x + 1;
952 }
953 return parent.getAbsoluteX() + x;
954 }
955
956 /**
957 * Compute my absolute Y position as the sum of my Y plus all my parent's
958 * Y's.
959 *
960 * @return absolute screen row number for my Y position
961 */
962 public final int getAbsoluteY() {
963 assert (parent != null);
964 if (parent == this) {
965 return y;
966 }
967 if ((parent instanceof TWindow)
968 && !(parent instanceof TMenu)
969 && !(parent instanceof TDesktop)
970 ) {
971 // Widgets on a TWindow have (0,0) as their top-left, but this is
972 // actually the TWindow's (1,1).
973 return parent.getAbsoluteY() + y + 1;
974 }
975 return parent.getAbsoluteY() + y;
976 }
977
978 /**
979 * Get the global color theme.
980 *
981 * @return the ColorTheme
982 */
983 protected final ColorTheme getTheme() {
984 return window.getApplication().getTheme();
985 }
986
987 /**
988 * Draw my specific widget. When called, the screen rectangle I draw
989 * into is already setup (offset and clipping).
990 */
991 public void draw() {
992 // Default widget draws nothing.
993 }
994
995 /**
996 * Called by parent to render to TWindow. Note package private access.
997 */
998 final void drawChildren() {
999 // Set my clipping rectangle
1000 assert (window != null);
1001 assert (getScreen() != null);
1002 Screen screen = getScreen();
1003
1004 // Special case: TStatusBar is drawn by TApplication, not anything
1005 // else.
1006 if (this instanceof TStatusBar) {
1007 return;
1008 }
1009
1010 screen.setClipRight(width);
1011 screen.setClipBottom(height);
1012
1013 int absoluteRightEdge = window.getAbsoluteX() + window.getWidth();
1014 int absoluteBottomEdge = window.getAbsoluteY() + window.getHeight();
1015 if (!(this instanceof TWindow) && !(this instanceof TVScroller)) {
1016 absoluteRightEdge -= 1;
1017 }
1018 if (!(this instanceof TWindow) && !(this instanceof THScroller)) {
1019 absoluteBottomEdge -= 1;
1020 }
1021 int myRightEdge = getAbsoluteX() + width;
1022 int myBottomEdge = getAbsoluteY() + height;
1023 if (getAbsoluteX() > absoluteRightEdge) {
1024 // I am offscreen
1025 screen.setClipRight(0);
1026 } else if (myRightEdge > absoluteRightEdge) {
1027 screen.setClipRight(screen.getClipRight()
1028 - (myRightEdge - absoluteRightEdge));
1029 }
1030 if (getAbsoluteY() > absoluteBottomEdge) {
1031 // I am offscreen
1032 screen.setClipBottom(0);
1033 } else if (myBottomEdge > absoluteBottomEdge) {
1034 screen.setClipBottom(screen.getClipBottom()
1035 - (myBottomEdge - absoluteBottomEdge));
1036 }
1037
1038 // Set my offset
1039 screen.setOffsetX(getAbsoluteX());
1040 screen.setOffsetY(getAbsoluteY());
1041
1042 // Draw me
1043 draw();
1044
1045 // Continue down the chain. Draw the active child last so that it
1046 // is on top.
1047 for (TWidget widget: children) {
1048 if (widget.isVisible() && (widget != activeChild)) {
1049 widget.drawChildren();
1050 }
1051 }
1052 if (activeChild != null) {
1053 activeChild.drawChildren();
1054 }
1055 }
1056
1057 /**
1058 * Repaint the screen on the next update.
1059 */
1060 protected final void doRepaint() {
1061 window.getApplication().doRepaint();
1062 }
1063
1064 /**
1065 * Add a child widget to my list of children. We set its tabOrder to 0
1066 * and increment the tabOrder of all other children.
1067 *
1068 * @param child TWidget to add
1069 */
1070 private void addChild(final TWidget child) {
1071 children.add(child);
1072
1073 if ((child.enabled)
1074 && !(child instanceof THScroller)
1075 && !(child instanceof TVScroller)
1076 ) {
1077 for (TWidget widget: children) {
1078 widget.active = false;
1079 }
1080 child.active = true;
1081 activeChild = child;
1082 }
1083 for (int i = 0; i < children.size(); i++) {
1084 children.get(i).tabOrder = i;
1085 }
1086 }
1087
1088 /**
1089 * Switch the active child.
1090 *
1091 * @param child TWidget to activate
1092 */
1093 public final void activate(final TWidget child) {
1094 assert (child.enabled);
1095 if ((child instanceof THScroller)
1096 || (child instanceof TVScroller)
1097 ) {
1098 return;
1099 }
1100
1101 if (child != activeChild) {
1102 if (activeChild != null) {
1103 activeChild.active = false;
1104 }
1105 child.active = true;
1106 activeChild = child;
1107 }
1108 }
1109
1110 /**
1111 * Switch the active child.
1112 *
1113 * @param tabOrder tabOrder of the child to activate. If that child
1114 * isn't enabled, then the next enabled child will be activated.
1115 */
1116 public final void activate(final int tabOrder) {
1117 if (activeChild == null) {
1118 return;
1119 }
1120 TWidget child = null;
1121 for (TWidget widget: children) {
1122 if ((widget.enabled)
1123 && !(widget instanceof THScroller)
1124 && !(widget instanceof TVScroller)
1125 && (widget.tabOrder >= tabOrder)
1126 ) {
1127 child = widget;
1128 break;
1129 }
1130 }
1131 if ((child != null) && (child != activeChild)) {
1132 activeChild.active = false;
1133 assert (child.enabled);
1134 child.active = true;
1135 activeChild = child;
1136 }
1137 }
1138
1139 /**
1140 * Switch the active widget with the next in the tab order.
1141 *
1142 * @param forward if true, then switch to the next enabled widget in the
1143 * list, otherwise switch to the previous enabled widget in the list
1144 */
1145 public final void switchWidget(final boolean forward) {
1146
1147 // Only switch if there are multiple enabled widgets
1148 if ((children.size() < 2) || (activeChild == null)) {
1149 return;
1150 }
1151
1152 int tabOrder = activeChild.tabOrder;
1153 do {
1154 if (forward) {
1155 tabOrder++;
1156 } else {
1157 tabOrder--;
1158 }
1159 if (tabOrder < 0) {
1160
1161 // If at the end, pass the switch to my parent.
1162 if ((!forward) && (parent != this)) {
1163 parent.switchWidget(forward);
1164 return;
1165 }
1166
1167 tabOrder = children.size() - 1;
1168 } else if (tabOrder == children.size()) {
1169 // If at the end, pass the switch to my parent.
1170 if ((forward) && (parent != this)) {
1171 parent.switchWidget(forward);
1172 return;
1173 }
1174
1175 tabOrder = 0;
1176 }
1177 if (activeChild.tabOrder == tabOrder) {
1178 // We wrapped around
1179 break;
1180 }
1181 } while ((!children.get(tabOrder).enabled)
1182 && !(children.get(tabOrder) instanceof THScroller)
1183 && !(children.get(tabOrder) instanceof TVScroller));
1184
1185 assert (children.get(tabOrder).enabled);
1186
1187 activeChild.active = false;
1188 children.get(tabOrder).active = true;
1189 activeChild = children.get(tabOrder);
1190 }
1191
1192 /**
1193 * Returns my active widget.
1194 *
1195 * @return widget that is active, or this if no children
1196 */
1197 public TWidget getActiveChild() {
1198 if ((this instanceof THScroller)
1199 || (this instanceof TVScroller)
1200 ) {
1201 return parent;
1202 }
1203
1204 for (TWidget widget: children) {
1205 if (widget.active) {
1206 return widget.getActiveChild();
1207 }
1208 }
1209 // No active children, return me
1210 return this;
1211 }
1212
1213 // ------------------------------------------------------------------------
1214 // Passthru for Screen functions ------------------------------------------
1215 // ------------------------------------------------------------------------
1216
1217 /**
1218 * Get the attributes at one location.
1219 *
1220 * @param x column coordinate. 0 is the left-most column.
1221 * @param y row coordinate. 0 is the top-most row.
1222 * @return attributes at (x, y)
1223 */
1224 protected final CellAttributes getAttrXY(final int x, final int y) {
1225 return getScreen().getAttrXY(x, y);
1226 }
1227
1228 /**
1229 * Set the attributes at one location.
1230 *
1231 * @param x column coordinate. 0 is the left-most column.
1232 * @param y row coordinate. 0 is the top-most row.
1233 * @param attr attributes to use (bold, foreColor, backColor)
1234 */
1235 protected final void putAttrXY(final int x, final int y,
1236 final CellAttributes attr) {
1237
1238 getScreen().putAttrXY(x, y, attr);
1239 }
1240
1241 /**
1242 * Set the attributes at one location.
1243 *
1244 * @param x column coordinate. 0 is the left-most column.
1245 * @param y row coordinate. 0 is the top-most row.
1246 * @param attr attributes to use (bold, foreColor, backColor)
1247 * @param clip if true, honor clipping/offset
1248 */
1249 protected final void putAttrXY(final int x, final int y,
1250 final CellAttributes attr, final boolean clip) {
1251
1252 getScreen().putAttrXY(x, y, attr, clip);
1253 }
1254
1255 /**
1256 * Fill the entire screen with one character with attributes.
1257 *
1258 * @param ch character to draw
1259 * @param attr attributes to use (bold, foreColor, backColor)
1260 */
1261 protected final void putAll(final char ch, final CellAttributes attr) {
1262 getScreen().putAll(ch, attr);
1263 }
1264
1265 /**
1266 * Render one character with attributes.
1267 *
1268 * @param x column coordinate. 0 is the left-most column.
1269 * @param y row coordinate. 0 is the top-most row.
1270 * @param ch character + attributes to draw
1271 */
1272 protected final void putCharXY(final int x, final int y, final Cell ch) {
1273 getScreen().putCharXY(x, y, ch);
1274 }
1275
1276 /**
1277 * Render one character with attributes.
1278 *
1279 * @param x column coordinate. 0 is the left-most column.
1280 * @param y row coordinate. 0 is the top-most row.
1281 * @param ch character to draw
1282 * @param attr attributes to use (bold, foreColor, backColor)
1283 */
1284 protected final void putCharXY(final int x, final int y, final char ch,
1285 final CellAttributes attr) {
1286
1287 getScreen().putCharXY(x, y, ch, attr);
1288 }
1289
1290 /**
1291 * Render one character without changing the underlying attributes.
1292 *
1293 * @param x column coordinate. 0 is the left-most column.
1294 * @param y row coordinate. 0 is the top-most row.
1295 * @param ch character to draw
1296 */
1297 protected final void putCharXY(final int x, final int y, final char ch) {
1298 getScreen().putCharXY(x, y, ch);
1299 }
1300
1301 /**
1302 * Render a string. Does not wrap if the string exceeds the line.
1303 *
1304 * @param x column coordinate. 0 is the left-most column.
1305 * @param y row coordinate. 0 is the top-most row.
1306 * @param str string to draw
1307 * @param attr attributes to use (bold, foreColor, backColor)
1308 */
1309 protected final void putStringXY(final int x, final int y, final String str,
1310 final CellAttributes attr) {
1311
1312 getScreen().putStringXY(x, y, str, attr);
1313 }
1314
1315 /**
1316 * Render a string without changing the underlying attribute. Does not
1317 * wrap if the string exceeds the line.
1318 *
1319 * @param x column coordinate. 0 is the left-most column.
1320 * @param y row coordinate. 0 is the top-most row.
1321 * @param str string to draw
1322 */
1323 protected final void putStringXY(final int x, final int y, final String str) {
1324 getScreen().putStringXY(x, y, str);
1325 }
1326
1327 /**
1328 * Draw a vertical line from (x, y) to (x, y + n).
1329 *
1330 * @param x column coordinate. 0 is the left-most column.
1331 * @param y row coordinate. 0 is the top-most row.
1332 * @param n number of characters to draw
1333 * @param ch character to draw
1334 * @param attr attributes to use (bold, foreColor, backColor)
1335 */
1336 protected final void vLineXY(final int x, final int y, final int n,
1337 final char ch, final CellAttributes attr) {
1338
1339 getScreen().vLineXY(x, y, n, ch, attr);
1340 }
1341
1342 /**
1343 * Draw a horizontal line from (x, y) to (x + n, y).
1344 *
1345 * @param x column coordinate. 0 is the left-most column.
1346 * @param y row coordinate. 0 is the top-most row.
1347 * @param n number of characters to draw
1348 * @param ch character to draw
1349 * @param attr attributes to use (bold, foreColor, backColor)
1350 */
1351 protected final void hLineXY(final int x, final int y, final int n,
1352 final char ch, final CellAttributes attr) {
1353
1354 getScreen().hLineXY(x, y, n, ch, attr);
1355 }
1356
1357 /**
1358 * Draw a box with a border and empty background.
1359 *
1360 * @param left left column of box. 0 is the left-most row.
1361 * @param top top row of the box. 0 is the top-most row.
1362 * @param right right column of box
1363 * @param bottom bottom row of the box
1364 * @param border attributes to use for the border
1365 * @param background attributes to use for the background
1366 */
1367 protected final void drawBox(final int left, final int top,
1368 final int right, final int bottom,
1369 final CellAttributes border, final CellAttributes background) {
1370
1371 getScreen().drawBox(left, top, right, bottom, border, background);
1372 }
1373
1374 /**
1375 * Draw a box with a border and empty background.
1376 *
1377 * @param left left column of box. 0 is the left-most row.
1378 * @param top top row of the box. 0 is the top-most row.
1379 * @param right right column of box
1380 * @param bottom bottom row of the box
1381 * @param border attributes to use for the border
1382 * @param background attributes to use for the background
1383 * @param borderType if 1, draw a single-line border; if 2, draw a
1384 * double-line border; if 3, draw double-line top/bottom edges and
1385 * single-line left/right edges (like Qmodem)
1386 * @param shadow if true, draw a "shadow" on the box
1387 */
1388 protected final void drawBox(final int left, final int top,
1389 final int right, final int bottom,
1390 final CellAttributes border, final CellAttributes background,
1391 final int borderType, final boolean shadow) {
1392
1393 getScreen().drawBox(left, top, right, bottom, border, background,
1394 borderType, shadow);
1395 }
1396
1397 /**
1398 * Draw a box shadow.
1399 *
1400 * @param left left column of box. 0 is the left-most row.
1401 * @param top top row of the box. 0 is the top-most row.
1402 * @param right right column of box
1403 * @param bottom bottom row of the box
1404 */
1405 protected final void drawBoxShadow(final int left, final int top,
1406 final int right, final int bottom) {
1407
1408 getScreen().drawBoxShadow(left, top, right, bottom);
1409 }
1410
1411 // ------------------------------------------------------------------------
1412 // Other TWidget constructors ---------------------------------------------
1413 // ------------------------------------------------------------------------
1414
1415 /**
1416 * Convenience function to add a label to this container/window.
1417 *
1418 * @param text label
1419 * @param x column relative to parent
1420 * @param y row relative to parent
1421 * @return the new label
1422 */
1423 public final TLabel addLabel(final String text, final int x, final int y) {
1424 return addLabel(text, x, y, "tlabel");
1425 }
1426
1427 /**
1428 * Convenience function to add a label to this container/window.
1429 *
1430 * @param text label
1431 * @param x column relative to parent
1432 * @param y row relative to parent
1433 * @param colorKey ColorTheme key color to use for foreground text.
1434 * Default is "tlabel"
1435 * @return the new label
1436 */
1437 public final TLabel addLabel(final String text, final int x, final int y,
1438 final String colorKey) {
1439
1440 return new TLabel(this, text, x, y, colorKey);
1441 }
1442
1443 /**
1444 * Convenience function to add a label to this container/window.
1445 *
1446 * @param text label
1447 * @param x column relative to parent
1448 * @param y row relative to parent
1449 * @param colorKey ColorTheme key color to use for foreground text.
1450 * Default is "tlabel"
1451 * @param useWindowBackground if true, use the window's background color
1452 * @return the new label
1453 */
1454 public final TLabel addLabel(final String text, final int x, final int y,
1455 final String colorKey, final boolean useWindowBackground) {
1456
1457 return new TLabel(this, text, x, y, colorKey, useWindowBackground);
1458 }
1459
1460 /**
1461 * Convenience function to add a button to this container/window.
1462 *
1463 * @param text label on the button
1464 * @param x column relative to parent
1465 * @param y row relative to parent
1466 * @param action action to call when button is pressed
1467 * @return the new button
1468 */
1469 public final TButton addButton(final String text, final int x, final int y,
1470 final TAction action) {
1471
1472 return new TButton(this, text, x, y, action);
1473 }
1474
1475 /**
1476 * Convenience function to add a checkbox to this container/window.
1477 *
1478 * @param x column relative to parent
1479 * @param y row relative to parent
1480 * @param label label to display next to (right of) the checkbox
1481 * @param checked initial check state
1482 * @return the new checkbox
1483 */
1484 public final TCheckBox addCheckBox(final int x, final int y,
1485 final String label, final boolean checked) {
1486
1487 return new TCheckBox(this, x, y, label, checked);
1488 }
1489
1490 /**
1491 * Convenience function to add a combobox to this container/window.
1492 *
1493 * @param x column relative to parent
1494 * @param y row relative to parent
1495 * @param width visible combobox width, including the down-arrow
1496 * @param values the possible values for the box, shown in the drop-down
1497 * @param valuesIndex the initial index in values, or -1 for no default
1498 * value
1499 * @param valuesHeight the height of the values drop-down when it is
1500 * visible
1501 * @param updateAction action to call when a new value is selected from
1502 * the list or enter is pressed in the edit field
1503 * @return the new combobox
1504 */
1505 public final TComboBox addComboBox(final int x, final int y,
1506 final int width, final List<String> values, final int valuesIndex,
1507 final int valuesHeight, final TAction updateAction) {
1508
1509 return new TComboBox(this, x, y, width, values, valuesIndex,
1510 valuesHeight, updateAction);
1511 }
1512
1513 /**
1514 * Convenience function to add a spinner to this container/window.
1515 *
1516 * @param x column relative to parent
1517 * @param y row relative to parent
1518 * @param upAction action to call when the up arrow is clicked or pressed
1519 * @param downAction action to call when the down arrow is clicked or
1520 * pressed
1521 * @return the new spinner
1522 */
1523 public final TSpinner addSpinner(final int x, final int y,
1524 final TAction upAction, final TAction downAction) {
1525
1526 return new TSpinner(this, x, y, upAction, downAction);
1527 }
1528
1529 /**
1530 * Convenience function to add a calendar to this container/window.
1531 *
1532 * @param x column relative to parent
1533 * @param y row relative to parent
1534 * @param updateAction action to call when the user changes the value of
1535 * the calendar
1536 * @return the new calendar
1537 */
1538 public final TCalendar addCalendar(final int x, final int y,
1539 final TAction updateAction) {
1540
1541 return new TCalendar(this, x, y, updateAction);
1542 }
1543
1544 /**
1545 * Convenience function to add a progress bar to this container/window.
1546 *
1547 * @param x column relative to parent
1548 * @param y row relative to parent
1549 * @param width width of progress bar
1550 * @param value initial value of percent complete
1551 * @return the new progress bar
1552 */
1553 public final TProgressBar addProgressBar(final int x, final int y,
1554 final int width, final int value) {
1555
1556 return new TProgressBar(this, x, y, width, value);
1557 }
1558
1559 /**
1560 * Convenience function to add a radio button group to this
1561 * container/window.
1562 *
1563 * @param x column relative to parent
1564 * @param y row relative to parent
1565 * @param label label to display on the group box
1566 * @return the new radio button group
1567 */
1568 public final TRadioGroup addRadioGroup(final int x, final int y,
1569 final String label) {
1570
1571 return new TRadioGroup(this, x, y, label);
1572 }
1573
1574 /**
1575 * Convenience function to add a text field to this container/window.
1576 *
1577 * @param x column relative to parent
1578 * @param y row relative to parent
1579 * @param width visible text width
1580 * @param fixed if true, the text cannot exceed the display width
1581 * @return the new text field
1582 */
1583 public final TField addField(final int x, final int y,
1584 final int width, final boolean fixed) {
1585
1586 return new TField(this, x, y, width, fixed);
1587 }
1588
1589 /**
1590 * Convenience function to add a text field to this container/window.
1591 *
1592 * @param x column relative to parent
1593 * @param y row relative to parent
1594 * @param width visible text width
1595 * @param fixed if true, the text cannot exceed the display width
1596 * @param text initial text, default is empty string
1597 * @return the new text field
1598 */
1599 public final TField addField(final int x, final int y,
1600 final int width, final boolean fixed, final String text) {
1601
1602 return new TField(this, x, y, width, fixed, text);
1603 }
1604
1605 /**
1606 * Convenience function to add a text field to this container/window.
1607 *
1608 * @param x column relative to parent
1609 * @param y row relative to parent
1610 * @param width visible text width
1611 * @param fixed if true, the text cannot exceed the display width
1612 * @param text initial text, default is empty string
1613 * @param enterAction function to call when enter key is pressed
1614 * @param updateAction function to call when the text is updated
1615 * @return the new text field
1616 */
1617 public final TField addField(final int x, final int y,
1618 final int width, final boolean fixed, final String text,
1619 final TAction enterAction, final TAction updateAction) {
1620
1621 return new TField(this, x, y, width, fixed, text, enterAction,
1622 updateAction);
1623 }
1624
1625 /**
1626 * Convenience function to add a scrollable text box to this
1627 * container/window.
1628 *
1629 * @param text text on the screen
1630 * @param x column relative to parent
1631 * @param y row relative to parent
1632 * @param width width of text area
1633 * @param height height of text area
1634 * @param colorKey ColorTheme key color to use for foreground text
1635 * @return the new text box
1636 */
1637 public final TText addText(final String text, final int x,
1638 final int y, final int width, final int height, final String colorKey) {
1639
1640 return new TText(this, text, x, y, width, height, colorKey);
1641 }
1642
1643 /**
1644 * Convenience function to add a scrollable text box to this
1645 * container/window.
1646 *
1647 * @param text text on the screen
1648 * @param x column relative to parent
1649 * @param y row relative to parent
1650 * @param width width of text area
1651 * @param height height of text area
1652 * @return the new text box
1653 */
1654 public final TText addText(final String text, final int x, final int y,
1655 final int width, final int height) {
1656
1657 return new TText(this, text, x, y, width, height, "ttext");
1658 }
1659
1660 /**
1661 * Convenience function to add an editable text area box to this
1662 * container/window.
1663 *
1664 * @param text text on the screen
1665 * @param x column relative to parent
1666 * @param y row relative to parent
1667 * @param width width of text area
1668 * @param height height of text area
1669 * @return the new text box
1670 */
1671 public final TEditorWidget addEditor(final String text, final int x,
1672 final int y, final int width, final int height) {
1673
1674 return new TEditorWidget(this, text, x, y, width, height);
1675 }
1676
1677 /**
1678 * Convenience function to spawn a message box.
1679 *
1680 * @param title window title, will be centered along the top border
1681 * @param caption message to display. Use embedded newlines to get a
1682 * multi-line box.
1683 * @return the new message box
1684 */
1685 public final TMessageBox messageBox(final String title,
1686 final String caption) {
1687
1688 return getApplication().messageBox(title, caption, TMessageBox.Type.OK);
1689 }
1690
1691 /**
1692 * Convenience function to spawn a message box.
1693 *
1694 * @param title window title, will be centered along the top border
1695 * @param caption message to display. Use embedded newlines to get a
1696 * multi-line box.
1697 * @param type one of the TMessageBox.Type constants. Default is
1698 * Type.OK.
1699 * @return the new message box
1700 */
1701 public final TMessageBox messageBox(final String title,
1702 final String caption, final TMessageBox.Type type) {
1703
1704 return getApplication().messageBox(title, caption, type);
1705 }
1706
1707 /**
1708 * Convenience function to spawn an input box.
1709 *
1710 * @param title window title, will be centered along the top border
1711 * @param caption message to display. Use embedded newlines to get a
1712 * multi-line box.
1713 * @return the new input box
1714 */
1715 public final TInputBox inputBox(final String title, final String caption) {
1716
1717 return getApplication().inputBox(title, caption);
1718 }
1719
1720 /**
1721 * Convenience function to spawn an input box.
1722 *
1723 * @param title window title, will be centered along the top border
1724 * @param caption message to display. Use embedded newlines to get a
1725 * multi-line box.
1726 * @param text initial text to seed the field with
1727 * @return the new input box
1728 */
1729 public final TInputBox inputBox(final String title, final String caption,
1730 final String text) {
1731
1732 return getApplication().inputBox(title, caption, text);
1733 }
1734
1735 /**
1736 * Convenience function to add a password text field to this
1737 * container/window.
1738 *
1739 * @param x column relative to parent
1740 * @param y row relative to parent
1741 * @param width visible text width
1742 * @param fixed if true, the text cannot exceed the display width
1743 * @return the new text field
1744 */
1745 public final TPasswordField addPasswordField(final int x, final int y,
1746 final int width, final boolean fixed) {
1747
1748 return new TPasswordField(this, x, y, width, fixed);
1749 }
1750
1751 /**
1752 * Convenience function to add a password text field to this
1753 * 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 * @param text initial text, default is empty string
1760 * @return the new text field
1761 */
1762 public final TPasswordField addPasswordField(final int x, final int y,
1763 final int width, final boolean fixed, final String text) {
1764
1765 return new TPasswordField(this, x, y, width, fixed, text);
1766 }
1767
1768 /**
1769 * Convenience function to add a password text field to this
1770 * container/window.
1771 *
1772 * @param x column relative to parent
1773 * @param y row relative to parent
1774 * @param width visible text width
1775 * @param fixed if true, the text cannot exceed the display width
1776 * @param text initial text, default is empty string
1777 * @param enterAction function to call when enter key is pressed
1778 * @param updateAction function to call when the text is updated
1779 * @return the new text field
1780 */
1781 public final TPasswordField addPasswordField(final int x, final int y,
1782 final int width, final boolean fixed, final String text,
1783 final TAction enterAction, final TAction updateAction) {
1784
1785 return new TPasswordField(this, x, y, width, fixed, text, enterAction,
1786 updateAction);
1787 }
1788
1789 /**
1790 * Convenience function to add a scrollable tree view to this
1791 * container/window.
1792 *
1793 * @param x column relative to parent
1794 * @param y row relative to parent
1795 * @param width width of tree view
1796 * @param height height of tree view
1797 * @return the new tree view
1798 */
1799 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
1800 final int width, final int height) {
1801
1802 return new TTreeViewWidget(this, x, y, width, height);
1803 }
1804
1805 /**
1806 * Convenience function to add a scrollable tree view to this
1807 * container/window.
1808 *
1809 * @param x column relative to parent
1810 * @param y row relative to parent
1811 * @param width width of tree view
1812 * @param height height of tree view
1813 * @param action action to perform when an item is selected
1814 * @return the new tree view
1815 */
1816 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
1817 final int width, final int height, final TAction action) {
1818
1819 return new TTreeViewWidget(this, x, y, width, height, action);
1820 }
1821
1822 /**
1823 * Convenience function to spawn a file open box.
1824 *
1825 * @param path path of selected file
1826 * @return the result of the new file open box
1827 * @throws IOException if a java.io operation throws
1828 */
1829 public final String fileOpenBox(final String path) throws IOException {
1830 return getApplication().fileOpenBox(path);
1831 }
1832
1833 /**
1834 * Convenience function to spawn a file save box.
1835 *
1836 * @param path path of selected file
1837 * @return the result of the new file open box
1838 * @throws IOException if a java.io operation throws
1839 */
1840 public final String fileSaveBox(final String path) throws IOException {
1841 return getApplication().fileOpenBox(path, TFileOpenBox.Type.SAVE);
1842 }
1843
1844 /**
1845 * Convenience function to spawn a file open box.
1846 *
1847 * @param path path of selected file
1848 * @param type one of the Type constants
1849 * @return the result of the new file open box
1850 * @throws IOException if a java.io operation throws
1851 */
1852 public final String fileOpenBox(final String path,
1853 final TFileOpenBox.Type type) throws IOException {
1854
1855 return getApplication().fileOpenBox(path, type);
1856 }
1857
1858 /**
1859 * Convenience function to spawn a file open box.
1860 *
1861 * @param path path of selected file
1862 * @param type one of the Type constants
1863 * @param filter a string that files must match to be displayed
1864 * @return the result of the new file open box
1865 * @throws IOException of a java.io operation throws
1866 */
1867 public final String fileOpenBox(final String path,
1868 final TFileOpenBox.Type type, final String filter) throws IOException {
1869
1870 ArrayList<String> filters = new ArrayList<String>();
1871 filters.add(filter);
1872
1873 return getApplication().fileOpenBox(path, type, filters);
1874 }
1875
1876 /**
1877 * Convenience function to spawn a file open box.
1878 *
1879 * @param path path of selected file
1880 * @param type one of the Type constants
1881 * @param filters a list of strings that files must match to be displayed
1882 * @return the result of the new file open box
1883 * @throws IOException of a java.io operation throws
1884 */
1885 public final String fileOpenBox(final String path,
1886 final TFileOpenBox.Type type,
1887 final List<String> filters) throws IOException {
1888
1889 return getApplication().fileOpenBox(path, type, filters);
1890 }
1891
1892 /**
1893 * Convenience function to add a directory list to this container/window.
1894 *
1895 * @param path directory path, must be a directory
1896 * @param x column relative to parent
1897 * @param y row relative to parent
1898 * @param width width of text area
1899 * @param height height of text area
1900 * @return the new directory list
1901 */
1902 public final TDirectoryList addDirectoryList(final String path, final int x,
1903 final int y, final int width, final int height) {
1904
1905 return new TDirectoryList(this, path, x, y, width, height, null);
1906 }
1907
1908 /**
1909 * Convenience function to add a directory list to this container/window.
1910 *
1911 * @param path directory path, must be a directory
1912 * @param x column relative to parent
1913 * @param y row relative to parent
1914 * @param width width of text area
1915 * @param height height of text area
1916 * @param action action to perform when an item is selected (enter or
1917 * double-click)
1918 * @return the new directory list
1919 */
1920 public final TDirectoryList addDirectoryList(final String path, final int x,
1921 final int y, final int width, final int height, final TAction action) {
1922
1923 return new TDirectoryList(this, path, x, y, width, height, action);
1924 }
1925
1926 /**
1927 * Convenience function to add a directory list to this container/window.
1928 *
1929 * @param path directory path, must be a directory
1930 * @param x column relative to parent
1931 * @param y row relative to parent
1932 * @param width width of text area
1933 * @param height height of text area
1934 * @param action action to perform when an item is selected (enter or
1935 * double-click)
1936 * @param singleClickAction action to perform when an item is selected
1937 * (single-click)
1938 * @return the new directory list
1939 */
1940 public final TDirectoryList addDirectoryList(final String path, final int x,
1941 final int y, final int width, final int height, final TAction action,
1942 final TAction singleClickAction) {
1943
1944 return new TDirectoryList(this, path, x, y, width, height, action,
1945 singleClickAction);
1946 }
1947
1948 /**
1949 * Convenience function to add a directory list to this container/window.
1950 *
1951 * @param path directory path, must be a directory
1952 * @param x column relative to parent
1953 * @param y row relative to parent
1954 * @param width width of text area
1955 * @param height height of text area
1956 * @param action action to perform when an item is selected (enter or
1957 * double-click)
1958 * @param singleClickAction action to perform when an item is selected
1959 * (single-click)
1960 * @param filters a list of strings that files must match to be displayed
1961 * @return the new directory list
1962 */
1963 public final TDirectoryList addDirectoryList(final String path, final int x,
1964 final int y, final int width, final int height, final TAction action,
1965 final TAction singleClickAction, final List<String> filters) {
1966
1967 return new TDirectoryList(this, path, x, y, width, height, action,
1968 singleClickAction, filters);
1969 }
1970
1971 /**
1972 * Convenience function to add a list to this container/window.
1973 *
1974 * @param strings list of strings to show
1975 * @param x column relative to parent
1976 * @param y row relative to parent
1977 * @param width width of text area
1978 * @param height height of text area
1979 * @return the new directory list
1980 */
1981 public final TList addList(final List<String> strings, final int x,
1982 final int y, final int width, final int height) {
1983
1984 return new TList(this, strings, x, y, width, height, null);
1985 }
1986
1987 /**
1988 * Convenience function to add a list to this container/window.
1989 *
1990 * @param strings list of strings to show
1991 * @param x column relative to parent
1992 * @param y row relative to parent
1993 * @param width width of text area
1994 * @param height height of text area
1995 * @param enterAction action to perform when an item is selected
1996 * @return the new directory list
1997 */
1998 public final TList addList(final List<String> strings, final int x,
1999 final int y, final int width, final int height,
2000 final TAction enterAction) {
2001
2002 return new TList(this, strings, x, y, width, height, enterAction);
2003 }
2004
2005 /**
2006 * Convenience function to add a list to this container/window.
2007 *
2008 * @param strings list of strings to show
2009 * @param x column relative to parent
2010 * @param y row relative to parent
2011 * @param width width of text area
2012 * @param height height of text area
2013 * @param enterAction action to perform when an item is selected
2014 * @param moveAction action to perform when the user navigates to a new
2015 * item with arrow/page keys
2016 * @return the new directory list
2017 */
2018 public final TList addList(final List<String> strings, final int x,
2019 final int y, final int width, final int height,
2020 final TAction enterAction, final TAction moveAction) {
2021
2022 return new TList(this, strings, x, y, width, height, enterAction,
2023 moveAction);
2024 }
2025
2026 }