misc fixes
[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 (children.size() == 1) {
1102 if (children.get(0).enabled == true) {
1103 child.active = true;
1104 activeChild = child;
1105 }
1106 } else {
1107 if (child != activeChild) {
1108 if (activeChild != null) {
1109 activeChild.active = false;
1110 }
1111 child.active = true;
1112 activeChild = child;
1113 }
1114 }
1115 }
1116
1117 /**
1118 * Switch the active child.
1119 *
1120 * @param tabOrder tabOrder of the child to activate. If that child
1121 * isn't enabled, then the next enabled child will be activated.
1122 */
1123 public final void activate(final int tabOrder) {
1124 if (children.size() == 1) {
1125 if (children.get(0).enabled == true) {
1126 children.get(0).active = true;
1127 activeChild = children.get(0);
1128 }
1129 return;
1130 }
1131
1132 if (activeChild == null) {
1133 return;
1134 }
1135 TWidget child = null;
1136 for (TWidget widget: children) {
1137 if ((widget.enabled)
1138 && !(widget instanceof THScroller)
1139 && !(widget instanceof TVScroller)
1140 && (widget.tabOrder >= tabOrder)
1141 ) {
1142 child = widget;
1143 break;
1144 }
1145 }
1146 if ((child != null) && (child != activeChild)) {
1147 activeChild.active = false;
1148 assert (child.enabled);
1149 child.active = true;
1150 activeChild = child;
1151 }
1152 }
1153
1154 /**
1155 * Switch the active widget with the next in the tab order.
1156 *
1157 * @param forward if true, then switch to the next enabled widget in the
1158 * list, otherwise switch to the previous enabled widget in the list
1159 */
1160 public final void switchWidget(final boolean forward) {
1161
1162 // No children: do nothing.
1163 if (children.size() == 0) {
1164 return;
1165 }
1166
1167 // If there is only one child, make it active if it is enabled.
1168 if (children.size() == 1) {
1169 if (children.get(0).enabled == true) {
1170 activeChild = children.get(0);
1171 activeChild.active = true;
1172 } else {
1173 children.get(0).active = false;
1174 activeChild = null;
1175 }
1176 return;
1177 }
1178
1179 // Two or more children: go forward or backward to the next enabled
1180 // child.
1181 int tabOrder = activeChild.tabOrder;
1182 do {
1183 if (forward) {
1184 tabOrder++;
1185 } else {
1186 tabOrder--;
1187 }
1188 if (tabOrder < 0) {
1189
1190 // If at the end, pass the switch to my parent.
1191 if ((!forward) && (parent != this)) {
1192 parent.switchWidget(forward);
1193 return;
1194 }
1195
1196 tabOrder = children.size() - 1;
1197 } else if (tabOrder == children.size()) {
1198 // If at the end, pass the switch to my parent.
1199 if ((forward) && (parent != this)) {
1200 parent.switchWidget(forward);
1201 return;
1202 }
1203
1204 tabOrder = 0;
1205 }
1206 if (activeChild.tabOrder == tabOrder) {
1207 // We wrapped around
1208 break;
1209 }
1210 } while ((!children.get(tabOrder).enabled)
1211 && !(children.get(tabOrder) instanceof THScroller)
1212 && !(children.get(tabOrder) instanceof TVScroller));
1213
1214 assert (children.get(tabOrder).enabled);
1215
1216 activeChild.active = false;
1217 children.get(tabOrder).active = true;
1218 activeChild = children.get(tabOrder);
1219 }
1220
1221 /**
1222 * Returns my active widget.
1223 *
1224 * @return widget that is active, or this if no children
1225 */
1226 public TWidget getActiveChild() {
1227 if ((this instanceof THScroller)
1228 || (this instanceof TVScroller)
1229 ) {
1230 return parent;
1231 }
1232
1233 for (TWidget widget: children) {
1234 if (widget.active) {
1235 return widget.getActiveChild();
1236 }
1237 }
1238 // No active children, return me
1239 return this;
1240 }
1241
1242 // ------------------------------------------------------------------------
1243 // Passthru for Screen functions ------------------------------------------
1244 // ------------------------------------------------------------------------
1245
1246 /**
1247 * Get the attributes at one location.
1248 *
1249 * @param x column coordinate. 0 is the left-most column.
1250 * @param y row coordinate. 0 is the top-most row.
1251 * @return attributes at (x, y)
1252 */
1253 protected final CellAttributes getAttrXY(final int x, final int y) {
1254 return getScreen().getAttrXY(x, y);
1255 }
1256
1257 /**
1258 * Set the attributes at one location.
1259 *
1260 * @param x column coordinate. 0 is the left-most column.
1261 * @param y row coordinate. 0 is the top-most row.
1262 * @param attr attributes to use (bold, foreColor, backColor)
1263 */
1264 protected final void putAttrXY(final int x, final int y,
1265 final CellAttributes attr) {
1266
1267 getScreen().putAttrXY(x, y, attr);
1268 }
1269
1270 /**
1271 * Set the attributes at one location.
1272 *
1273 * @param x column coordinate. 0 is the left-most column.
1274 * @param y row coordinate. 0 is the top-most row.
1275 * @param attr attributes to use (bold, foreColor, backColor)
1276 * @param clip if true, honor clipping/offset
1277 */
1278 protected final void putAttrXY(final int x, final int y,
1279 final CellAttributes attr, final boolean clip) {
1280
1281 getScreen().putAttrXY(x, y, attr, clip);
1282 }
1283
1284 /**
1285 * Fill the entire screen with one character with attributes.
1286 *
1287 * @param ch character to draw
1288 * @param attr attributes to use (bold, foreColor, backColor)
1289 */
1290 protected final void putAll(final char ch, final CellAttributes attr) {
1291 getScreen().putAll(ch, attr);
1292 }
1293
1294 /**
1295 * Render one character with attributes.
1296 *
1297 * @param x column coordinate. 0 is the left-most column.
1298 * @param y row coordinate. 0 is the top-most row.
1299 * @param ch character + attributes to draw
1300 */
1301 protected final void putCharXY(final int x, final int y, final Cell ch) {
1302 getScreen().putCharXY(x, y, ch);
1303 }
1304
1305 /**
1306 * Render one character with attributes.
1307 *
1308 * @param x column coordinate. 0 is the left-most column.
1309 * @param y row coordinate. 0 is the top-most row.
1310 * @param ch character to draw
1311 * @param attr attributes to use (bold, foreColor, backColor)
1312 */
1313 protected final void putCharXY(final int x, final int y, final char ch,
1314 final CellAttributes attr) {
1315
1316 getScreen().putCharXY(x, y, ch, attr);
1317 }
1318
1319 /**
1320 * Render one character without changing the underlying attributes.
1321 *
1322 * @param x column coordinate. 0 is the left-most column.
1323 * @param y row coordinate. 0 is the top-most row.
1324 * @param ch character to draw
1325 */
1326 protected final void putCharXY(final int x, final int y, final char ch) {
1327 getScreen().putCharXY(x, y, ch);
1328 }
1329
1330 /**
1331 * Render a string. Does not wrap if the string exceeds the line.
1332 *
1333 * @param x column coordinate. 0 is the left-most column.
1334 * @param y row coordinate. 0 is the top-most row.
1335 * @param str string to draw
1336 * @param attr attributes to use (bold, foreColor, backColor)
1337 */
1338 protected final void putStringXY(final int x, final int y, final String str,
1339 final CellAttributes attr) {
1340
1341 getScreen().putStringXY(x, y, str, attr);
1342 }
1343
1344 /**
1345 * Render a string without changing the underlying attribute. Does not
1346 * wrap if the string exceeds the line.
1347 *
1348 * @param x column coordinate. 0 is the left-most column.
1349 * @param y row coordinate. 0 is the top-most row.
1350 * @param str string to draw
1351 */
1352 protected final void putStringXY(final int x, final int y, final String str) {
1353 getScreen().putStringXY(x, y, str);
1354 }
1355
1356 /**
1357 * Draw a vertical line from (x, y) to (x, y + n).
1358 *
1359 * @param x column coordinate. 0 is the left-most column.
1360 * @param y row coordinate. 0 is the top-most row.
1361 * @param n number of characters to draw
1362 * @param ch character to draw
1363 * @param attr attributes to use (bold, foreColor, backColor)
1364 */
1365 protected final void vLineXY(final int x, final int y, final int n,
1366 final char ch, final CellAttributes attr) {
1367
1368 getScreen().vLineXY(x, y, n, ch, attr);
1369 }
1370
1371 /**
1372 * Draw a horizontal line from (x, y) to (x + n, y).
1373 *
1374 * @param x column coordinate. 0 is the left-most column.
1375 * @param y row coordinate. 0 is the top-most row.
1376 * @param n number of characters to draw
1377 * @param ch character to draw
1378 * @param attr attributes to use (bold, foreColor, backColor)
1379 */
1380 protected final void hLineXY(final int x, final int y, final int n,
1381 final char ch, final CellAttributes attr) {
1382
1383 getScreen().hLineXY(x, y, n, ch, attr);
1384 }
1385
1386 /**
1387 * Draw a box with a border and empty background.
1388 *
1389 * @param left left column of box. 0 is the left-most row.
1390 * @param top top row of the box. 0 is the top-most row.
1391 * @param right right column of box
1392 * @param bottom bottom row of the box
1393 * @param border attributes to use for the border
1394 * @param background attributes to use for the background
1395 */
1396 protected final void drawBox(final int left, final int top,
1397 final int right, final int bottom,
1398 final CellAttributes border, final CellAttributes background) {
1399
1400 getScreen().drawBox(left, top, right, bottom, border, background);
1401 }
1402
1403 /**
1404 * Draw a box with a border and empty background.
1405 *
1406 * @param left left column of box. 0 is the left-most row.
1407 * @param top top row of the box. 0 is the top-most row.
1408 * @param right right column of box
1409 * @param bottom bottom row of the box
1410 * @param border attributes to use for the border
1411 * @param background attributes to use for the background
1412 * @param borderType if 1, draw a single-line border; if 2, draw a
1413 * double-line border; if 3, draw double-line top/bottom edges and
1414 * single-line left/right edges (like Qmodem)
1415 * @param shadow if true, draw a "shadow" on the box
1416 */
1417 protected final void drawBox(final int left, final int top,
1418 final int right, final int bottom,
1419 final CellAttributes border, final CellAttributes background,
1420 final int borderType, final boolean shadow) {
1421
1422 getScreen().drawBox(left, top, right, bottom, border, background,
1423 borderType, shadow);
1424 }
1425
1426 /**
1427 * Draw a box shadow.
1428 *
1429 * @param left left column of box. 0 is the left-most row.
1430 * @param top top row of the box. 0 is the top-most row.
1431 * @param right right column of box
1432 * @param bottom bottom row of the box
1433 */
1434 protected final void drawBoxShadow(final int left, final int top,
1435 final int right, final int bottom) {
1436
1437 getScreen().drawBoxShadow(left, top, right, bottom);
1438 }
1439
1440 // ------------------------------------------------------------------------
1441 // Other TWidget constructors ---------------------------------------------
1442 // ------------------------------------------------------------------------
1443
1444 /**
1445 * Convenience function to add a label to this container/window.
1446 *
1447 * @param text label
1448 * @param x column relative to parent
1449 * @param y row relative to parent
1450 * @return the new label
1451 */
1452 public final TLabel addLabel(final String text, final int x, final int y) {
1453 return addLabel(text, x, y, "tlabel");
1454 }
1455
1456 /**
1457 * Convenience function to add a label to this container/window.
1458 *
1459 * @param text label
1460 * @param x column relative to parent
1461 * @param y row relative to parent
1462 * @param colorKey ColorTheme key color to use for foreground text.
1463 * Default is "tlabel"
1464 * @return the new label
1465 */
1466 public final TLabel addLabel(final String text, final int x, final int y,
1467 final String colorKey) {
1468
1469 return new TLabel(this, text, x, y, colorKey);
1470 }
1471
1472 /**
1473 * Convenience function to add a label to this container/window.
1474 *
1475 * @param text label
1476 * @param x column relative to parent
1477 * @param y row relative to parent
1478 * @param colorKey ColorTheme key color to use for foreground text.
1479 * Default is "tlabel"
1480 * @param useWindowBackground if true, use the window's background color
1481 * @return the new label
1482 */
1483 public final TLabel addLabel(final String text, final int x, final int y,
1484 final String colorKey, final boolean useWindowBackground) {
1485
1486 return new TLabel(this, text, x, y, colorKey, useWindowBackground);
1487 }
1488
1489 /**
1490 * Convenience function to add a button to this container/window.
1491 *
1492 * @param text label on the button
1493 * @param x column relative to parent
1494 * @param y row relative to parent
1495 * @param action action to call when button is pressed
1496 * @return the new button
1497 */
1498 public final TButton addButton(final String text, final int x, final int y,
1499 final TAction action) {
1500
1501 return new TButton(this, text, x, y, action);
1502 }
1503
1504 /**
1505 * Convenience function to add a checkbox to this container/window.
1506 *
1507 * @param x column relative to parent
1508 * @param y row relative to parent
1509 * @param label label to display next to (right of) the checkbox
1510 * @param checked initial check state
1511 * @return the new checkbox
1512 */
1513 public final TCheckBox addCheckBox(final int x, final int y,
1514 final String label, final boolean checked) {
1515
1516 return new TCheckBox(this, x, y, label, checked);
1517 }
1518
1519 /**
1520 * Convenience function to add a combobox to this container/window.
1521 *
1522 * @param x column relative to parent
1523 * @param y row relative to parent
1524 * @param width visible combobox width, including the down-arrow
1525 * @param values the possible values for the box, shown in the drop-down
1526 * @param valuesIndex the initial index in values, or -1 for no default
1527 * value
1528 * @param valuesHeight the height of the values drop-down when it is
1529 * visible
1530 * @param updateAction action to call when a new value is selected from
1531 * the list or enter is pressed in the edit field
1532 * @return the new combobox
1533 */
1534 public final TComboBox addComboBox(final int x, final int y,
1535 final int width, final List<String> values, final int valuesIndex,
1536 final int valuesHeight, final TAction updateAction) {
1537
1538 return new TComboBox(this, x, y, width, values, valuesIndex,
1539 valuesHeight, updateAction);
1540 }
1541
1542 /**
1543 * Convenience function to add a spinner to this container/window.
1544 *
1545 * @param x column relative to parent
1546 * @param y row relative to parent
1547 * @param upAction action to call when the up arrow is clicked or pressed
1548 * @param downAction action to call when the down arrow is clicked or
1549 * pressed
1550 * @return the new spinner
1551 */
1552 public final TSpinner addSpinner(final int x, final int y,
1553 final TAction upAction, final TAction downAction) {
1554
1555 return new TSpinner(this, x, y, upAction, downAction);
1556 }
1557
1558 /**
1559 * Convenience function to add a calendar to this container/window.
1560 *
1561 * @param x column relative to parent
1562 * @param y row relative to parent
1563 * @param updateAction action to call when the user changes the value of
1564 * the calendar
1565 * @return the new calendar
1566 */
1567 public final TCalendar addCalendar(final int x, final int y,
1568 final TAction updateAction) {
1569
1570 return new TCalendar(this, x, y, updateAction);
1571 }
1572
1573 /**
1574 * Convenience function to add a progress bar to this container/window.
1575 *
1576 * @param x column relative to parent
1577 * @param y row relative to parent
1578 * @param width width of progress bar
1579 * @param value initial value of percent complete
1580 * @return the new progress bar
1581 */
1582 public final TProgressBar addProgressBar(final int x, final int y,
1583 final int width, final int value) {
1584
1585 return new TProgressBar(this, x, y, width, value);
1586 }
1587
1588 /**
1589 * Convenience function to add a radio button group to this
1590 * container/window.
1591 *
1592 * @param x column relative to parent
1593 * @param y row relative to parent
1594 * @param label label to display on the group box
1595 * @return the new radio button group
1596 */
1597 public final TRadioGroup addRadioGroup(final int x, final int y,
1598 final String label) {
1599
1600 return new TRadioGroup(this, x, y, label);
1601 }
1602
1603 /**
1604 * Convenience function to add a text field to this container/window.
1605 *
1606 * @param x column relative to parent
1607 * @param y row relative to parent
1608 * @param width visible text width
1609 * @param fixed if true, the text cannot exceed the display width
1610 * @return the new text field
1611 */
1612 public final TField addField(final int x, final int y,
1613 final int width, final boolean fixed) {
1614
1615 return new TField(this, x, y, width, fixed);
1616 }
1617
1618 /**
1619 * Convenience function to add a text field to this container/window.
1620 *
1621 * @param x column relative to parent
1622 * @param y row relative to parent
1623 * @param width visible text width
1624 * @param fixed if true, the text cannot exceed the display width
1625 * @param text initial text, default is empty string
1626 * @return the new text field
1627 */
1628 public final TField addField(final int x, final int y,
1629 final int width, final boolean fixed, final String text) {
1630
1631 return new TField(this, x, y, width, fixed, text);
1632 }
1633
1634 /**
1635 * Convenience function to add a text field to this container/window.
1636 *
1637 * @param x column relative to parent
1638 * @param y row relative to parent
1639 * @param width visible text width
1640 * @param fixed if true, the text cannot exceed the display width
1641 * @param text initial text, default is empty string
1642 * @param enterAction function to call when enter key is pressed
1643 * @param updateAction function to call when the text is updated
1644 * @return the new text field
1645 */
1646 public final TField addField(final int x, final int y,
1647 final int width, final boolean fixed, final String text,
1648 final TAction enterAction, final TAction updateAction) {
1649
1650 return new TField(this, x, y, width, fixed, text, enterAction,
1651 updateAction);
1652 }
1653
1654 /**
1655 * Convenience function to add a scrollable text box to this
1656 * container/window.
1657 *
1658 * @param text text on the screen
1659 * @param x column relative to parent
1660 * @param y row relative to parent
1661 * @param width width of text area
1662 * @param height height of text area
1663 * @param colorKey ColorTheme key color to use for foreground text
1664 * @return the new text box
1665 */
1666 public final TText addText(final String text, final int x,
1667 final int y, final int width, final int height, final String colorKey) {
1668
1669 return new TText(this, text, x, y, width, height, colorKey);
1670 }
1671
1672 /**
1673 * Convenience function to add a scrollable text box to this
1674 * container/window.
1675 *
1676 * @param text text on the screen
1677 * @param x column relative to parent
1678 * @param y row relative to parent
1679 * @param width width of text area
1680 * @param height height of text area
1681 * @return the new text box
1682 */
1683 public final TText addText(final String text, final int x, final int y,
1684 final int width, final int height) {
1685
1686 return new TText(this, text, x, y, width, height, "ttext");
1687 }
1688
1689 /**
1690 * Convenience function to add an editable text area box to this
1691 * container/window.
1692 *
1693 * @param text text on the screen
1694 * @param x column relative to parent
1695 * @param y row relative to parent
1696 * @param width width of text area
1697 * @param height height of text area
1698 * @return the new text box
1699 */
1700 public final TEditorWidget addEditor(final String text, final int x,
1701 final int y, final int width, final int height) {
1702
1703 return new TEditorWidget(this, text, x, y, width, height);
1704 }
1705
1706 /**
1707 * Convenience function to spawn a message box.
1708 *
1709 * @param title window title, will be centered along the top border
1710 * @param caption message to display. Use embedded newlines to get a
1711 * multi-line box.
1712 * @return the new message box
1713 */
1714 public final TMessageBox messageBox(final String title,
1715 final String caption) {
1716
1717 return getApplication().messageBox(title, caption, TMessageBox.Type.OK);
1718 }
1719
1720 /**
1721 * Convenience function to spawn a message 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 type one of the TMessageBox.Type constants. Default is
1727 * Type.OK.
1728 * @return the new message box
1729 */
1730 public final TMessageBox messageBox(final String title,
1731 final String caption, final TMessageBox.Type type) {
1732
1733 return getApplication().messageBox(title, caption, type);
1734 }
1735
1736 /**
1737 * Convenience function to spawn an input box.
1738 *
1739 * @param title window title, will be centered along the top border
1740 * @param caption message to display. Use embedded newlines to get a
1741 * multi-line box.
1742 * @return the new input box
1743 */
1744 public final TInputBox inputBox(final String title, final String caption) {
1745
1746 return getApplication().inputBox(title, caption);
1747 }
1748
1749 /**
1750 * Convenience function to spawn an input box.
1751 *
1752 * @param title window title, will be centered along the top border
1753 * @param caption message to display. Use embedded newlines to get a
1754 * multi-line box.
1755 * @param text initial text to seed the field with
1756 * @return the new input box
1757 */
1758 public final TInputBox inputBox(final String title, final String caption,
1759 final String text) {
1760
1761 return getApplication().inputBox(title, caption, text);
1762 }
1763
1764 /**
1765 * Convenience function to add a password text field to this
1766 * container/window.
1767 *
1768 * @param x column relative to parent
1769 * @param y row relative to parent
1770 * @param width visible text width
1771 * @param fixed if true, the text cannot exceed the display width
1772 * @return the new text field
1773 */
1774 public final TPasswordField addPasswordField(final int x, final int y,
1775 final int width, final boolean fixed) {
1776
1777 return new TPasswordField(this, x, y, width, fixed);
1778 }
1779
1780 /**
1781 * Convenience function to add a password text field to this
1782 * container/window.
1783 *
1784 * @param x column relative to parent
1785 * @param y row relative to parent
1786 * @param width visible text width
1787 * @param fixed if true, the text cannot exceed the display width
1788 * @param text initial text, default is empty string
1789 * @return the new text field
1790 */
1791 public final TPasswordField addPasswordField(final int x, final int y,
1792 final int width, final boolean fixed, final String text) {
1793
1794 return new TPasswordField(this, x, y, width, fixed, text);
1795 }
1796
1797 /**
1798 * Convenience function to add a password text field to this
1799 * container/window.
1800 *
1801 * @param x column relative to parent
1802 * @param y row relative to parent
1803 * @param width visible text width
1804 * @param fixed if true, the text cannot exceed the display width
1805 * @param text initial text, default is empty string
1806 * @param enterAction function to call when enter key is pressed
1807 * @param updateAction function to call when the text is updated
1808 * @return the new text field
1809 */
1810 public final TPasswordField addPasswordField(final int x, final int y,
1811 final int width, final boolean fixed, final String text,
1812 final TAction enterAction, final TAction updateAction) {
1813
1814 return new TPasswordField(this, x, y, width, fixed, text, enterAction,
1815 updateAction);
1816 }
1817
1818 /**
1819 * Convenience function to add a scrollable tree view to this
1820 * container/window.
1821 *
1822 * @param x column relative to parent
1823 * @param y row relative to parent
1824 * @param width width of tree view
1825 * @param height height of tree view
1826 * @return the new tree view
1827 */
1828 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
1829 final int width, final int height) {
1830
1831 return new TTreeViewWidget(this, x, y, width, height);
1832 }
1833
1834 /**
1835 * Convenience function to add a scrollable tree view to this
1836 * container/window.
1837 *
1838 * @param x column relative to parent
1839 * @param y row relative to parent
1840 * @param width width of tree view
1841 * @param height height of tree view
1842 * @param action action to perform when an item is selected
1843 * @return the new tree view
1844 */
1845 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
1846 final int width, final int height, final TAction action) {
1847
1848 return new TTreeViewWidget(this, x, y, width, height, action);
1849 }
1850
1851 /**
1852 * Convenience function to spawn a file open box.
1853 *
1854 * @param path path of selected file
1855 * @return the result of the new file open box
1856 * @throws IOException if a java.io operation throws
1857 */
1858 public final String fileOpenBox(final String path) throws IOException {
1859 return getApplication().fileOpenBox(path);
1860 }
1861
1862 /**
1863 * Convenience function to spawn a file save box.
1864 *
1865 * @param path path of selected file
1866 * @return the result of the new file open box
1867 * @throws IOException if a java.io operation throws
1868 */
1869 public final String fileSaveBox(final String path) throws IOException {
1870 return getApplication().fileOpenBox(path, TFileOpenBox.Type.SAVE);
1871 }
1872
1873 /**
1874 * Convenience function to spawn a file open box.
1875 *
1876 * @param path path of selected file
1877 * @param type one of the Type constants
1878 * @return the result of the new file open box
1879 * @throws IOException if a java.io operation throws
1880 */
1881 public final String fileOpenBox(final String path,
1882 final TFileOpenBox.Type type) throws IOException {
1883
1884 return getApplication().fileOpenBox(path, type);
1885 }
1886
1887 /**
1888 * Convenience function to spawn a file open box.
1889 *
1890 * @param path path of selected file
1891 * @param type one of the Type constants
1892 * @param filter a string that files must match to be displayed
1893 * @return the result of the new file open box
1894 * @throws IOException of a java.io operation throws
1895 */
1896 public final String fileOpenBox(final String path,
1897 final TFileOpenBox.Type type, final String filter) throws IOException {
1898
1899 ArrayList<String> filters = new ArrayList<String>();
1900 filters.add(filter);
1901
1902 return getApplication().fileOpenBox(path, type, filters);
1903 }
1904
1905 /**
1906 * Convenience function to spawn a file open box.
1907 *
1908 * @param path path of selected file
1909 * @param type one of the Type constants
1910 * @param filters a list of strings that files must match to be displayed
1911 * @return the result of the new file open box
1912 * @throws IOException of a java.io operation throws
1913 */
1914 public final String fileOpenBox(final String path,
1915 final TFileOpenBox.Type type,
1916 final List<String> filters) throws IOException {
1917
1918 return getApplication().fileOpenBox(path, type, filters);
1919 }
1920
1921 /**
1922 * Convenience function to add a directory list to this container/window.
1923 *
1924 * @param path directory path, must be a directory
1925 * @param x column relative to parent
1926 * @param y row relative to parent
1927 * @param width width of text area
1928 * @param height height of text area
1929 * @return the new directory list
1930 */
1931 public final TDirectoryList addDirectoryList(final String path, final int x,
1932 final int y, final int width, final int height) {
1933
1934 return new TDirectoryList(this, path, x, y, width, height, null);
1935 }
1936
1937 /**
1938 * Convenience function to add a directory list to this container/window.
1939 *
1940 * @param path directory path, must be a directory
1941 * @param x column relative to parent
1942 * @param y row relative to parent
1943 * @param width width of text area
1944 * @param height height of text area
1945 * @param action action to perform when an item is selected (enter or
1946 * double-click)
1947 * @return the new directory list
1948 */
1949 public final TDirectoryList addDirectoryList(final String path, final int x,
1950 final int y, final int width, final int height, final TAction action) {
1951
1952 return new TDirectoryList(this, path, x, y, width, height, action);
1953 }
1954
1955 /**
1956 * Convenience function to add a directory list to this container/window.
1957 *
1958 * @param path directory path, must be a directory
1959 * @param x column relative to parent
1960 * @param y row relative to parent
1961 * @param width width of text area
1962 * @param height height of text area
1963 * @param action action to perform when an item is selected (enter or
1964 * double-click)
1965 * @param singleClickAction action to perform when an item is selected
1966 * (single-click)
1967 * @return the new directory list
1968 */
1969 public final TDirectoryList addDirectoryList(final String path, final int x,
1970 final int y, final int width, final int height, final TAction action,
1971 final TAction singleClickAction) {
1972
1973 return new TDirectoryList(this, path, x, y, width, height, action,
1974 singleClickAction);
1975 }
1976
1977 /**
1978 * Convenience function to add a directory list to this container/window.
1979 *
1980 * @param path directory path, must be a directory
1981 * @param x column relative to parent
1982 * @param y row relative to parent
1983 * @param width width of text area
1984 * @param height height of text area
1985 * @param action action to perform when an item is selected (enter or
1986 * double-click)
1987 * @param singleClickAction action to perform when an item is selected
1988 * (single-click)
1989 * @param filters a list of strings that files must match to be displayed
1990 * @return the new directory list
1991 */
1992 public final TDirectoryList addDirectoryList(final String path, final int x,
1993 final int y, final int width, final int height, final TAction action,
1994 final TAction singleClickAction, final List<String> filters) {
1995
1996 return new TDirectoryList(this, path, x, y, width, height, action,
1997 singleClickAction, filters);
1998 }
1999
2000 /**
2001 * Convenience function to add a list to this container/window.
2002 *
2003 * @param strings list of strings to show
2004 * @param x column relative to parent
2005 * @param y row relative to parent
2006 * @param width width of text area
2007 * @param height height of text area
2008 * @return the new directory list
2009 */
2010 public final TList addList(final List<String> strings, final int x,
2011 final int y, final int width, final int height) {
2012
2013 return new TList(this, strings, x, y, width, height, null);
2014 }
2015
2016 /**
2017 * Convenience function to add a list to this container/window.
2018 *
2019 * @param strings list of strings to show
2020 * @param x column relative to parent
2021 * @param y row relative to parent
2022 * @param width width of text area
2023 * @param height height of text area
2024 * @param enterAction action to perform when an item is selected
2025 * @return the new directory list
2026 */
2027 public final TList addList(final List<String> strings, final int x,
2028 final int y, final int width, final int height,
2029 final TAction enterAction) {
2030
2031 return new TList(this, strings, x, y, width, height, enterAction);
2032 }
2033
2034 /**
2035 * Convenience function to add a list to this container/window.
2036 *
2037 * @param strings list of strings to show
2038 * @param x column relative to parent
2039 * @param y row relative to parent
2040 * @param width width of text area
2041 * @param height height of text area
2042 * @param enterAction action to perform when an item is selected
2043 * @param moveAction action to perform when the user navigates to a new
2044 * item with arrow/page keys
2045 * @return the new directory list
2046 */
2047 public final TList addList(final List<String> strings, final int x,
2048 final int y, final int width, final int height,
2049 final TAction enterAction, final TAction moveAction) {
2050
2051 return new TList(this, strings, x, y, width, height, enterAction,
2052 moveAction);
2053 }
2054
2055 }