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