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