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