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