update README
[fanfix.git] / src / jexer / TWidget.java
CommitLineData
daa4106c 1/*
48e27807
KL
2 * Jexer - Java Text User Interface
3 *
e16dda65 4 * The MIT License (MIT)
48e27807 5 *
a69ed767 6 * Copyright (C) 2019 Kevin Lamonte
48e27807 7 *
e16dda65
KL
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:
48e27807 14 *
e16dda65
KL
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
48e27807 17 *
e16dda65
KL
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.
48e27807
KL
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
0d47c546 31import java.io.IOException;
48e27807 32import java.util.List;
2ce6dab2 33import java.util.ArrayList;
48e27807 34
42873e30 35import jexer.backend.Screen;
a69ed767
KL
36import jexer.bits.Cell;
37import jexer.bits.CellAttributes;
928811d8 38import jexer.bits.ColorTheme;
48e27807
KL
39import jexer.event.TCommandEvent;
40import jexer.event.TInputEvent;
41import jexer.event.TKeypressEvent;
42import jexer.event.TMenuEvent;
43import jexer.event.TMouseEvent;
44import jexer.event.TResizeEvent;
928811d8 45import jexer.menu.TMenu;
d36057df
KL
46import jexer.ttree.TTreeItem;
47import jexer.ttree.TTreeView;
48import jexer.ttree.TTreeViewWidget;
48e27807
KL
49import 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 */
2b9c27db 55public abstract class TWidget implements Comparable<TWidget> {
48e27807 56
2ce6dab2 57 // ------------------------------------------------------------------------
d36057df 58 // Variables --------------------------------------------------------------
2ce6dab2
KL
59 // ------------------------------------------------------------------------
60
48e27807
KL
61 /**
62 * Every widget has a parent widget that it may be "contained" in. For
051e2913
KL
63 * example, a TWindow might contain several TFields, or a TComboBox may
64 * contain a TList that itself contains a TVScroller.
48e27807 65 */
fca67db0
KL
66 private TWidget parent = null;
67
48e27807
KL
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 */
fca67db0
KL
81 private boolean active = false;
82
48e27807
KL
83 /**
84 * The window that this widget draws to.
85 */
fca67db0 86 private TWindow window = null;
48e27807
KL
87
88 /**
89 * Absolute X position of the top-left corner.
90 */
fca67db0
KL
91 private int x = 0;
92
93 /**
d36057df 94 * Absolute Y position of the top-left corner.
fca67db0 95 */
d36057df 96 private int y = 0;
fca67db0
KL
97
98 /**
d36057df 99 * Width.
fca67db0 100 */
d36057df 101 private int width = 0;
48e27807
KL
102
103 /**
d36057df 104 * Height.
48e27807 105 */
d36057df 106 private int height = 0;
fca67db0
KL
107
108 /**
d36057df 109 * My tab order inside a window or containing widget.
fca67db0 110 */
d36057df 111 private int tabOrder = 0;
fca67db0
KL
112
113 /**
d36057df 114 * If true, this widget can be tabbed to or receive events.
fca67db0 115 */
d36057df 116 private boolean enabled = true;
48e27807 117
051e2913
KL
118 /**
119 * If true, this widget will be rendered.
120 */
121 private boolean visible = true;
122
48e27807 123 /**
d36057df 124 * If true, this widget has a cursor.
48e27807 125 */
d36057df 126 private boolean cursorVisible = false;
fca67db0
KL
127
128 /**
d36057df 129 * Cursor column position in relative coordinates.
fca67db0 130 */
d36057df 131 private int cursorX = 0;
fca67db0
KL
132
133 /**
d36057df 134 * Cursor row position in relative coordinates.
fca67db0 135 */
d36057df 136 private int cursorY = 0;
48e27807 137
d36057df
KL
138 // ------------------------------------------------------------------------
139 // Constructors -----------------------------------------------------------
140 // ------------------------------------------------------------------------
fca67db0
KL
141
142 /**
d36057df 143 * Default constructor for subclasses.
fca67db0 144 */
d36057df
KL
145 protected TWidget() {
146 children = new ArrayList<TWidget>();
fca67db0
KL
147 }
148
149 /**
d36057df 150 * Protected constructor.
fca67db0 151 *
d36057df 152 * @param parent parent widget
fca67db0 153 */
d36057df
KL
154 protected TWidget(final TWidget parent) {
155 this(parent, true);
fca67db0 156 }
48e27807 157
0ee88b6d 158 /**
d36057df 159 * Protected constructor.
0ee88b6d 160 *
d36057df
KL
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
0ee88b6d 166 */
d36057df
KL
167 protected TWidget(final TWidget parent, final int x, final int y,
168 final int width, final int height) {
0ee88b6d 169
d36057df 170 this(parent, true, x, y, width, height);
0ee88b6d
KL
171 }
172
48e27807 173 /**
d36057df 174 * Protected constructor used by subclasses that are disabled by default.
48e27807 175 *
d36057df
KL
176 * @param parent parent widget
177 * @param enabled if true assume enabled
48e27807 178 */
d36057df
KL
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
a69ed767 185 // Do not add TStatusBars, they are drawn by TApplication.
d36057df 186 if (this instanceof TStatusBar) {
a69ed767 187 // NOP
d36057df
KL
188 } else {
189 parent.addChild(this);
190 }
48e27807
KL
191 }
192
193 /**
d36057df 194 * Protected constructor used by subclasses that are disabled by default.
48e27807 195 *
d36057df
KL
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
48e27807 202 */
d36057df
KL
203 protected TWidget(final TWidget parent, final boolean enabled,
204 final int x, final int y, final int width, final int height) {
205
48e27807 206 this.enabled = enabled;
d36057df
KL
207 this.parent = parent;
208 this.window = parent.window;
209 children = new ArrayList<TWidget>();
210
a69ed767 211 // Do not add TStatusBars, they are drawn by TApplication.
d36057df 212 if (this instanceof TStatusBar) {
a69ed767 213 // NOP
d36057df
KL
214 } else {
215 parent.addChild(this);
48e27807 216 }
48e27807 217
d36057df
KL
218 this.x = x;
219 this.y = y;
220 this.width = width;
221 this.height = height;
222 }
48e27807 223
7272e49f 224 /**
d36057df 225 * Backdoor access for TWindow's constructor. ONLY TWindow USES THIS.
7272e49f 226 *
d36057df
KL
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
7272e49f 232 */
d36057df
KL
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;
7272e49f
KL
242 }
243
d36057df
KL
244 // ------------------------------------------------------------------------
245 // Event handlers ---------------------------------------------------------
246 // ------------------------------------------------------------------------
247
a69ed767
KL
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
a06459bd 259 /**
d36057df
KL
260 * Check if a mouse press/release event coordinate is contained in this
261 * widget.
a06459bd 262 *
d36057df
KL
263 * @param mouse a mouse-based event
264 * @return whether or not a mouse click would be sent to this widget
a06459bd 265 */
d36057df
KL
266 public final boolean mouseWouldHit(final TMouseEvent mouse) {
267
268 if (!enabled) {
24489803
KL
269 return false;
270 }
271
d36057df
KL
272 if ((this instanceof TTreeItem)
273 && ((y < 0) || (y > parent.getHeight() - 1))
24489803
KL
274 ) {
275 return false;
276 }
a06459bd 277
d36057df
KL
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 }
48e27807 287
7272e49f 288 /**
d36057df 289 * Method that subclasses can override to handle keystrokes.
7272e49f 290 *
d36057df 291 * @param keypress keystroke event
7272e49f 292 */
d36057df
KL
293 public void onKeypress(final TKeypressEvent keypress) {
294
295 if ((children.size() == 0)
296 || (this instanceof TTreeView)
297 || (this instanceof TText)
a69ed767 298 || (this instanceof TComboBox)
d36057df
KL
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))
a69ed767 305 || (keypress.equals(kbDown) && !(this instanceof TComboBox))
d36057df
KL
306 ) {
307 parent.switchWidget(true);
308 return;
309 } else if ((keypress.equals(kbShiftTab))
310 || (keypress.equals(kbBackTab))
a69ed767 311 || (keypress.equals(kbUp) && !(this instanceof TComboBox))
d36057df
KL
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
00691e80 334 // its mnemonic, send it an Enter keystroke.
d36057df
KL
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
00691e80
KL
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
d36057df
KL
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 }
7272e49f
KL
434 }
435
436 /**
d36057df 437 * Method that subclasses can override to handle mouse button presses.
7272e49f 438 *
d36057df 439 * @param mouse mouse button event
7272e49f 440 */
d36057df
KL
441 public void onMouseDown(final TMouseEvent mouse) {
442 // Default: do nothing, pass to children instead
a69ed767
KL
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 }
d36057df
KL
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);
7272e49f 459
d36057df
KL
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 }
48e27807 468
7272e49f 469 /**
d36057df 470 * Method that subclasses can override to handle mouse button releases.
7272e49f 471 *
d36057df 472 * @param mouse mouse button event
7272e49f 473 */
d36057df
KL
474 public void onMouseUp(final TMouseEvent mouse) {
475 // Default: do nothing, pass to children instead
a69ed767
KL
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 }
d36057df
KL
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 }
7272e49f
KL
500 }
501
502 /**
d36057df 503 * Method that subclasses can override to handle mouse movements.
7272e49f 504 *
d36057df 505 * @param mouse mouse motion event
7272e49f 506 */
d36057df
KL
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 }
7272e49f
KL
516 }
517
2ce6dab2 518 /**
d36057df
KL
519 * Method that subclasses can override to handle mouse button
520 * double-clicks.
2ce6dab2 521 *
d36057df 522 * @param mouse mouse button event
2ce6dab2 523 */
d36057df
KL
524 public void onMouseDoubleClick(final TMouseEvent mouse) {
525 // Default: do nothing, pass to children instead
a69ed767
KL
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 }
d36057df
KL
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 }
2ce6dab2
KL
550 }
551
552 /**
d36057df
KL
553 * Method that subclasses can override to handle window/screen resize
554 * events.
2ce6dab2 555 *
d36057df 556 * @param resize resize event
2ce6dab2 557 */
d36057df
KL
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 }
2ce6dab2
KL
569 }
570
48e27807 571 /**
d36057df 572 * Method that subclasses can override to handle posted command events.
7668cb45 573 *
d36057df 574 * @param command command event
2b9c27db 575 */
d36057df
KL
576 public void onCommand(final TCommandEvent command) {
577 // Default: do nothing, pass to children instead
578 for (TWidget widget: children) {
579 widget.onCommand(command);
7668cb45 580 }
48e27807
KL
581 }
582
583 /**
d36057df
KL
584 * Method that subclasses can override to handle menu or posted menu
585 * events.
48e27807 586 *
d36057df 587 * @param menu menu event
48e27807 588 */
d36057df
KL
589 public void onMenu(final TMenuEvent menu) {
590 // Default: do nothing, pass to children instead
591 for (TWidget widget: children) {
592 widget.onMenu(menu);
48e27807 593 }
48e27807
KL
594 }
595
596 /**
d36057df
KL
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().
48e27807 600 */
d36057df
KL
601 public void onIdle() {
602 // Default: do nothing, pass to children instead
603 for (TWidget widget: children) {
604 widget.onIdle();
605 }
48e27807
KL
606 }
607
608 /**
d36057df
KL
609 * Consume event. Subclasses that want to intercept all events in one go
610 * can override this method.
48e27807 611 *
d36057df 612 * @param event keyboard, mouse, resize, command, or menu event
48e27807 613 */
d36057df
KL
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;
48e27807
KL
664 }
665
d36057df
KL
666 // ------------------------------------------------------------------------
667 // TWidget ----------------------------------------------------------------
668 // ------------------------------------------------------------------------
669
48e27807 670 /**
d36057df 671 * Get parent widget.
48e27807 672 *
d36057df 673 * @return parent widget
48e27807 674 */
d36057df
KL
675 public final TWidget getParent() {
676 return parent;
48e27807
KL
677 }
678
679 /**
d36057df 680 * Get the list of child widgets that this widget contains.
48e27807 681 *
d36057df 682 * @return the list of child widgets
48e27807 683 */
d36057df
KL
684 public List<TWidget> getChildren() {
685 return children;
48e27807
KL
686 }
687
928811d8 688 /**
d36057df 689 * Get active flag.
928811d8 690 *
d36057df 691 * @return if true, this widget will receive events
928811d8 692 */
d36057df
KL
693 public final boolean isActive() {
694 return active;
928811d8
KL
695 }
696
48e27807 697 /**
d36057df
KL
698 * Set active flag.
699 *
700 * @param active if true, this widget will receive events
48e27807 701 */
d36057df
KL
702 public final void setActive(final boolean active) {
703 this.active = active;
48e27807
KL
704 }
705
706 /**
d36057df
KL
707 * Get the window this widget is on.
708 *
709 * @return the window
48e27807 710 */
d36057df
KL
711 public final TWindow getWindow() {
712 return window;
48e27807
KL
713 }
714
be72cb5c 715 /**
d36057df
KL
716 * Get X position.
717 *
718 * @return absolute X position of the top-left corner
be72cb5c 719 */
d36057df
KL
720 public final int getX() {
721 return x;
be72cb5c
KL
722 }
723
48e27807 724 /**
d36057df
KL
725 * Set X position.
726 *
727 * @param x absolute X position of the top-left corner
48e27807 728 */
d36057df
KL
729 public final void setX(final int x) {
730 this.x = x;
48e27807
KL
731 }
732
733 /**
d36057df 734 * Get Y position.
48e27807 735 *
d36057df 736 * @return absolute Y position of the top-left corner
48e27807 737 */
d36057df
KL
738 public final int getY() {
739 return y;
30d336cc
KL
740 }
741
a83fea2b 742 /**
d36057df 743 * Set Y position.
a83fea2b 744 *
d36057df 745 * @param y absolute Y position of the top-left corner
a83fea2b 746 */
d36057df
KL
747 public final void setY(final int y) {
748 this.y = y;
a83fea2b
KL
749 }
750
30d336cc 751 /**
d36057df 752 * Get the width.
30d336cc 753 *
d36057df 754 * @return widget width
30d336cc 755 */
d36057df
KL
756 public final int getWidth() {
757 return this.width;
48e27807
KL
758 }
759
a83fea2b 760 /**
d36057df 761 * Change the width.
a83fea2b 762 *
d36057df 763 * @param width new widget width
a83fea2b 764 */
d36057df 765 public final void setWidth(final int width) {
a83fea2b 766 this.width = width;
a83fea2b
KL
767 }
768
2ce6dab2 769 /**
d36057df 770 * Get the height.
2ce6dab2 771 *
d36057df 772 * @return widget height
2ce6dab2 773 */
d36057df
KL
774 public final int getHeight() {
775 return this.height;
776 }
2ce6dab2 777
d36057df
KL
778 /**
779 * Change the height.
780 *
781 * @param height new widget height
782 */
783 public final void setHeight(final int height) {
2ce6dab2
KL
784 this.height = height;
785 }
786
48e27807 787 /**
d36057df 788 * Change the dimensions.
48e27807 789 *
d36057df
KL
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
48e27807 794 */
d36057df
KL
795 public final void setDimensions(final int x, final int y, final int width,
796 final int height) {
48e27807 797
d36057df
KL
798 setX(x);
799 setY(y);
800 setWidth(width);
801 setHeight(height);
48e27807
KL
802 }
803
804 /**
d36057df 805 * Get enabled flag.
48e27807 806 *
d36057df 807 * @return if true, this widget can be tabbed to or receive events
48e27807 808 */
d36057df
KL
809 public final boolean isEnabled() {
810 return enabled;
811 }
48e27807 812
d36057df
KL
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 }
48e27807 838 }
48e27807
KL
839 }
840 }
841
051e2913
KL
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
48e27807 860 /**
d36057df 861 * Set visible cursor flag.
48e27807 862 *
d36057df 863 * @param cursorVisible if true, this widget has a cursor
48e27807 864 */
d36057df
KL
865 public final void setCursorVisible(final boolean cursorVisible) {
866 this.cursorVisible = cursorVisible;
48e27807
KL
867 }
868
869 /**
d36057df 870 * See if this widget has a visible cursor.
48e27807 871 *
d36057df 872 * @return if true, this widget has a visible cursor
48e27807 873 */
d36057df
KL
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 }
48e27807 883
d36057df
KL
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;
48e27807 893 }
d36057df
KL
894 return cursorVisible;
895 }
48e27807 896
d36057df
KL
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 }
48e27807 905
d36057df
KL
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 }
48e27807 914
d36057df
KL
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 }
48e27807 923
d36057df
KL
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 }
48e27807 932
d36057df
KL
933 /**
934 * Get this TWidget's parent TApplication.
935 *
936 * @return the parent TApplication
937 */
938 public TApplication getApplication() {
939 return window.getApplication();
940 }
48e27807 941
d36057df
KL
942 /**
943 * Get the Screen.
944 *
945 * @return the Screen
946 */
947 public Screen getScreen() {
948 return window.getScreen();
48e27807
KL
949 }
950
951 /**
d36057df
KL
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>
48e27807 958 *
d36057df
KL
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)
48e27807 962 */
d36057df
KL
963 public final int compareTo(final TWidget that) {
964 if ((this instanceof TWindow)
965 && (that instanceof TWindow)
48e27807 966 ) {
d36057df
KL
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()));
48e27807 974 }
d36057df
KL
975 return (this.tabOrder - that.tabOrder);
976 }
48e27807 977
d36057df
KL
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;
48e27807 987 }
d36057df 988 return (active && parent.isAbsoluteActive());
48e27807
KL
989 }
990
d36057df
KL
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 }
2ce6dab2
KL
999
1000 /**
d36057df 1001 * Returns the cursor Y position.
2ce6dab2 1002 *
d36057df 1003 * @return absolute screen row number for the cursor's Y position
2ce6dab2 1004 */
d36057df
KL
1005 public final int getCursorAbsoluteY() {
1006 return getAbsoluteY() + cursorY;
1007 }
2ce6dab2 1008
d36057df
KL
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;
2ce6dab2 1019 }
d36057df
KL
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 }
2ce6dab2 1030
d36057df
KL
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)
2ce6dab2 1045 ) {
d36057df
KL
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;
2ce6dab2 1049 }
d36057df 1050 return parent.getAbsoluteY() + y;
2ce6dab2
KL
1051 }
1052
48e27807 1053 /**
d36057df 1054 * Get the global color theme.
48e27807 1055 *
d36057df 1056 * @return the ColorTheme
48e27807 1057 */
a69ed767 1058 protected final ColorTheme getTheme() {
d36057df
KL
1059 return window.getApplication().getTheme();
1060 }
48e27807 1061
d36057df
KL
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 }
48e27807 1069
d36057df 1070 /**
a69ed767 1071 * Called by parent to render to TWindow. Note package private access.
d36057df 1072 */
a69ed767 1073 final void drawChildren() {
d36057df
KL
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;
48e27807
KL
1083 }
1084
d36057df
KL
1085 screen.setClipRight(width);
1086 screen.setClipBottom(height);
92554d64 1087
d36057df
KL
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;
48e27807 1095 }
d36057df
KL
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());
48e27807 1116
d36057df
KL
1117 // Draw me
1118 draw();
1119
a69ed767
KL
1120 // Continue down the chain. Draw the active child last so that it
1121 // is on top.
48e27807 1122 for (TWidget widget: children) {
a69ed767 1123 if (widget.isVisible() && (widget != activeChild)) {
051e2913
KL
1124 widget.drawChildren();
1125 }
48e27807 1126 }
a69ed767
KL
1127 if (activeChild != null) {
1128 activeChild.drawChildren();
1129 }
48e27807
KL
1130 }
1131
1132 /**
d36057df 1133 * Repaint the screen on the next update.
48e27807 1134 */
a69ed767 1135 protected final void doRepaint() {
d36057df 1136 window.getApplication().doRepaint();
48e27807
KL
1137 }
1138
1139 /**
d36057df
KL
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.
48e27807 1142 *
d36057df 1143 * @param child TWidget to add
48e27807 1144 */
d36057df
KL
1145 private void addChild(final TWidget child) {
1146 children.add(child);
48e27807 1147
d36057df
KL
1148 if ((child.enabled)
1149 && !(child instanceof THScroller)
1150 && !(child instanceof TVScroller)
1151 ) {
1152 for (TWidget widget: children) {
1153 widget.active = false;
48e27807 1154 }
d36057df
KL
1155 child.active = true;
1156 activeChild = child;
48e27807 1157 }
d36057df
KL
1158 for (int i = 0; i < children.size(); i++) {
1159 children.get(i).tabOrder = i;
48e27807
KL
1160 }
1161 }
1162
00691e80
KL
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
b6faeac0 1173 /**
d36057df 1174 * Switch the active child.
b6faeac0 1175 *
d36057df 1176 * @param child TWidget to activate
b6faeac0 1177 */
d36057df
KL
1178 public final void activate(final TWidget child) {
1179 assert (child.enabled);
1180 if ((child instanceof THScroller)
1181 || (child instanceof TVScroller)
1182 ) {
1183 return;
b6faeac0 1184 }
b6faeac0 1185
e23ea538
KL
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;
12b55d76 1198 }
48e27807
KL
1199 }
1200 }
1201
1202 /**
d36057df 1203 * Switch the active child.
48e27807 1204 *
d36057df
KL
1205 * @param tabOrder tabOrder of the child to activate. If that child
1206 * isn't enabled, then the next enabled child will be activated.
48e27807 1207 */
d36057df 1208 public final void activate(final int tabOrder) {
e23ea538
KL
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
d36057df 1217 TWidget child = null;
48e27807 1218 for (TWidget widget: children) {
d36057df
KL
1219 if ((widget.enabled)
1220 && !(widget instanceof THScroller)
1221 && !(widget instanceof TVScroller)
1222 && (widget.tabOrder >= tabOrder)
1223 ) {
1224 child = widget;
1225 break;
1226 }
48e27807 1227 }
d36057df 1228 if ((child != null) && (child != activeChild)) {
00691e80
KL
1229 if (activeChild != null) {
1230 activeChild.active = false;
1231 }
d36057df
KL
1232 assert (child.enabled);
1233 child.active = true;
1234 activeChild = child;
48e27807
KL
1235 }
1236 }
1237
1238 /**
d36057df 1239 * Switch the active widget with the next in the tab order.
48e27807 1240 *
d36057df
KL
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
48e27807 1243 */
d36057df 1244 public final void switchWidget(final boolean forward) {
48e27807 1245
e23ea538 1246 // No children: do nothing.
00691e80 1247 if (children.size() == 0) {
e23ea538
KL
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 }
48e27807
KL
1260 return;
1261 }
1262
e23ea538
KL
1263 // Two or more children: go forward or backward to the next enabled
1264 // child.
00691e80
KL
1265 int tabOrder = 0;
1266 if (activeChild != null) {
1267 tabOrder = activeChild.tabOrder;
1268 }
d36057df
KL
1269 do {
1270 if (forward) {
1271 tabOrder++;
1272 } else {
1273 tabOrder--;
1274 }
1275 if (tabOrder < 0) {
48e27807 1276
d36057df
KL
1277 // If at the end, pass the switch to my parent.
1278 if ((!forward) && (parent != this)) {
1279 parent.switchWidget(forward);
1280 return;
1281 }
48e27807 1282
d36057df
KL
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 }
48e27807 1290
d36057df
KL
1291 tabOrder = 0;
1292 }
00691e80
KL
1293 if (activeChild == null) {
1294 if (tabOrder == 0) {
1295 // We wrapped around
1296 break;
1297 }
1298 } else if (activeChild.tabOrder == tabOrder) {
d36057df 1299 // We wrapped around
48e27807 1300 break;
d36057df
KL
1301 }
1302 } while ((!children.get(tabOrder).enabled)
1303 && !(children.get(tabOrder) instanceof THScroller)
1304 && !(children.get(tabOrder) instanceof TVScroller));
48e27807 1305
00691e80
KL
1306 if (activeChild != null) {
1307 assert (children.get(tabOrder).enabled);
48e27807 1308
00691e80
KL
1309 activeChild.active = false;
1310 }
1311 if (children.get(tabOrder).enabled == true) {
1312 children.get(tabOrder).active = true;
1313 activeChild = children.get(tabOrder);
1314 }
d36057df 1315 }
48e27807 1316
d36057df
KL
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 }
b6faeac0 1328
d36057df
KL
1329 for (TWidget widget: children) {
1330 if (widget.active) {
1331 return widget.getActiveChild();
48e27807 1332 }
48e27807 1333 }
d36057df
KL
1334 // No active children, return me
1335 return this;
48e27807
KL
1336 }
1337
a69ed767
KL
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
2ce6dab2
KL
1536 // ------------------------------------------------------------------------
1537 // Other TWidget constructors ---------------------------------------------
1538 // ------------------------------------------------------------------------
48e27807 1539
30d336cc
KL
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
00691e80
KL
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
30d336cc
KL
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
00691e80
KL
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
051e2913
KL
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
00691e80
KL
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
30d336cc
KL
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
051e2913 1643 * @param action action to call when button is pressed
30d336cc
KL
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
7272e49f
KL
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 */
051e2913 1661 public final TCheckBox addCheckBox(final int x, final int y,
7272e49f
KL
1662 final String label, final boolean checked) {
1663
051e2913
KL
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);
7272e49f 1719 }
30d336cc 1720
d502a0e9
KL
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
00d2622b 1728 * @return the new progress bar
d502a0e9
KL
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
00d2622b
KL
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
128e5be1
KL
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 }
00d2622b 1801
cc99cba8
KL
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 */
c6940ed9 1814 public final TText addText(final String text, final int x,
cc99cba8
KL
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 */
c6940ed9 1831 public final TText addText(final String text, final int x, final int y,
cc99cba8
KL
1832 final int width, final int height) {
1833
1834 return new TText(this, text, x, y, width, height, "ttext");
1835 }
1836
12b55d76
KL
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
c6940ed9
KL
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 }
cc99cba8 1911
87a17f3c
KL
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
7668cb45 1966 /**
d36057df
KL
1967 * Convenience function to add a scrollable tree view to this
1968 * container/window.
7668cb45
KL
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
329fd62e 1974 * @return the new tree view
7668cb45 1975 */
d36057df 1976 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
7668cb45
KL
1977 final int width, final int height) {
1978
d36057df 1979 return new TTreeViewWidget(this, x, y, width, height);
7668cb45
KL
1980 }
1981
1982 /**
d36057df
KL
1983 * Convenience function to add a scrollable tree view to this
1984 * container/window.
7668cb45
KL
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
329fd62e 1991 * @return the new tree view
7668cb45 1992 */
d36057df 1993 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
7668cb45
KL
1994 final int width, final int height, final TAction action) {
1995
d36057df 1996 return new TTreeViewWidget(this, x, y, width, height, action);
7668cb45
KL
1997 }
1998
0d47c546
KL
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
329fd62e 2004 * @throws IOException if a java.io operation throws
0d47c546
KL
2005 */
2006 public final String fileOpenBox(final String path) throws IOException {
2007 return getApplication().fileOpenBox(path);
2008 }
2009
a69ed767
KL
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
0d47c546
KL
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
329fd62e 2027 * @throws IOException if a java.io operation throws
0d47c546
KL
2028 */
2029 public final String fileOpenBox(final String path,
2030 final TFileOpenBox.Type type) throws IOException {
2031
2032 return getApplication().fileOpenBox(path, type);
2033 }
a69ed767
KL
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
0d47c546
KL
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
329fd62e 2077 * @return the new directory list
0d47c546
KL
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
a69ed767
KL
2093 * @param action action to perform when an item is selected (enter or
2094 * double-click)
329fd62e 2095 * @return the new directory list
0d47c546
KL
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 }
7668cb45 2102
3649b921
KL
2103 /**
2104 * Convenience function to add a directory list to this container/window.
2105 *
a69ed767
KL
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 *
3649b921
KL
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 /**
a69ed767 2165 * Convenience function to add a list to this container/window.
3649b921
KL
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 /**
a69ed767 2183 * Convenience function to add a list to this container/window.
3649b921
KL
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
48e27807 2203}