box drawing intersections
[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();
11cedc9a 1119 assert (visible == true);
d36057df 1120
a69ed767
KL
1121 // Continue down the chain. Draw the active child last so that it
1122 // is on top.
48e27807 1123 for (TWidget widget: children) {
a69ed767 1124 if (widget.isVisible() && (widget != activeChild)) {
051e2913
KL
1125 widget.drawChildren();
1126 }
48e27807 1127 }
a69ed767
KL
1128 if (activeChild != null) {
1129 activeChild.drawChildren();
1130 }
48e27807
KL
1131 }
1132
1133 /**
d36057df 1134 * Repaint the screen on the next update.
48e27807 1135 */
a69ed767 1136 protected final void doRepaint() {
d36057df 1137 window.getApplication().doRepaint();
48e27807
KL
1138 }
1139
1140 /**
d36057df
KL
1141 * Add a child widget to my list of children. We set its tabOrder to 0
1142 * and increment the tabOrder of all other children.
48e27807 1143 *
d36057df 1144 * @param child TWidget to add
48e27807 1145 */
d36057df
KL
1146 private void addChild(final TWidget child) {
1147 children.add(child);
48e27807 1148
d36057df
KL
1149 if ((child.enabled)
1150 && !(child instanceof THScroller)
1151 && !(child instanceof TVScroller)
1152 ) {
1153 for (TWidget widget: children) {
1154 widget.active = false;
48e27807 1155 }
d36057df
KL
1156 child.active = true;
1157 activeChild = child;
48e27807 1158 }
d36057df
KL
1159 for (int i = 0; i < children.size(); i++) {
1160 children.get(i).tabOrder = i;
48e27807
KL
1161 }
1162 }
1163
00691e80
KL
1164 /**
1165 * Reset the tab order of children to match their position in the list.
1166 * Available so that subclasses can re-order their widgets if needed.
1167 */
1168 protected void resetTabOrder() {
1169 for (int i = 0; i < children.size(); i++) {
1170 children.get(i).tabOrder = i;
1171 }
1172 }
1173
b6faeac0 1174 /**
d36057df 1175 * Switch the active child.
b6faeac0 1176 *
d36057df 1177 * @param child TWidget to activate
b6faeac0 1178 */
d36057df
KL
1179 public final void activate(final TWidget child) {
1180 assert (child.enabled);
1181 if ((child instanceof THScroller)
1182 || (child instanceof TVScroller)
1183 ) {
1184 return;
b6faeac0 1185 }
b6faeac0 1186
e23ea538
KL
1187 if (children.size() == 1) {
1188 if (children.get(0).enabled == true) {
1189 child.active = true;
1190 activeChild = child;
1191 }
1192 } else {
1193 if (child != activeChild) {
1194 if (activeChild != null) {
1195 activeChild.active = false;
1196 }
1197 child.active = true;
1198 activeChild = child;
12b55d76 1199 }
48e27807
KL
1200 }
1201 }
1202
1203 /**
d36057df 1204 * Switch the active child.
48e27807 1205 *
d36057df
KL
1206 * @param tabOrder tabOrder of the child to activate. If that child
1207 * isn't enabled, then the next enabled child will be activated.
48e27807 1208 */
d36057df 1209 public final void activate(final int tabOrder) {
e23ea538
KL
1210 if (children.size() == 1) {
1211 if (children.get(0).enabled == true) {
1212 children.get(0).active = true;
1213 activeChild = children.get(0);
1214 }
1215 return;
1216 }
1217
d36057df 1218 TWidget child = null;
48e27807 1219 for (TWidget widget: children) {
d36057df
KL
1220 if ((widget.enabled)
1221 && !(widget instanceof THScroller)
1222 && !(widget instanceof TVScroller)
1223 && (widget.tabOrder >= tabOrder)
1224 ) {
1225 child = widget;
1226 break;
1227 }
48e27807 1228 }
d36057df 1229 if ((child != null) && (child != activeChild)) {
00691e80
KL
1230 if (activeChild != null) {
1231 activeChild.active = false;
1232 }
d36057df
KL
1233 assert (child.enabled);
1234 child.active = true;
1235 activeChild = child;
48e27807
KL
1236 }
1237 }
1238
1239 /**
d36057df 1240 * Switch the active widget with the next in the tab order.
48e27807 1241 *
d36057df
KL
1242 * @param forward if true, then switch to the next enabled widget in the
1243 * list, otherwise switch to the previous enabled widget in the list
48e27807 1244 */
d36057df 1245 public final void switchWidget(final boolean forward) {
48e27807 1246
e23ea538 1247 // No children: do nothing.
00691e80 1248 if (children.size() == 0) {
e23ea538
KL
1249 return;
1250 }
1251
1252 // If there is only one child, make it active if it is enabled.
1253 if (children.size() == 1) {
1254 if (children.get(0).enabled == true) {
1255 activeChild = children.get(0);
1256 activeChild.active = true;
1257 } else {
1258 children.get(0).active = false;
1259 activeChild = null;
1260 }
48e27807
KL
1261 return;
1262 }
1263
e23ea538
KL
1264 // Two or more children: go forward or backward to the next enabled
1265 // child.
00691e80
KL
1266 int tabOrder = 0;
1267 if (activeChild != null) {
1268 tabOrder = activeChild.tabOrder;
1269 }
d36057df
KL
1270 do {
1271 if (forward) {
1272 tabOrder++;
1273 } else {
1274 tabOrder--;
1275 }
1276 if (tabOrder < 0) {
48e27807 1277
d36057df
KL
1278 // If at the end, pass the switch to my parent.
1279 if ((!forward) && (parent != this)) {
1280 parent.switchWidget(forward);
1281 return;
1282 }
48e27807 1283
d36057df
KL
1284 tabOrder = children.size() - 1;
1285 } else if (tabOrder == children.size()) {
1286 // If at the end, pass the switch to my parent.
1287 if ((forward) && (parent != this)) {
1288 parent.switchWidget(forward);
1289 return;
1290 }
48e27807 1291
d36057df
KL
1292 tabOrder = 0;
1293 }
00691e80
KL
1294 if (activeChild == null) {
1295 if (tabOrder == 0) {
1296 // We wrapped around
1297 break;
1298 }
1299 } else if (activeChild.tabOrder == tabOrder) {
d36057df 1300 // We wrapped around
48e27807 1301 break;
d36057df
KL
1302 }
1303 } while ((!children.get(tabOrder).enabled)
1304 && !(children.get(tabOrder) instanceof THScroller)
1305 && !(children.get(tabOrder) instanceof TVScroller));
48e27807 1306
00691e80
KL
1307 if (activeChild != null) {
1308 assert (children.get(tabOrder).enabled);
48e27807 1309
00691e80
KL
1310 activeChild.active = false;
1311 }
1312 if (children.get(tabOrder).enabled == true) {
1313 children.get(tabOrder).active = true;
1314 activeChild = children.get(tabOrder);
1315 }
d36057df 1316 }
48e27807 1317
d36057df
KL
1318 /**
1319 * Returns my active widget.
1320 *
1321 * @return widget that is active, or this if no children
1322 */
1323 public TWidget getActiveChild() {
1324 if ((this instanceof THScroller)
1325 || (this instanceof TVScroller)
1326 ) {
1327 return parent;
1328 }
b6faeac0 1329
d36057df
KL
1330 for (TWidget widget: children) {
1331 if (widget.active) {
1332 return widget.getActiveChild();
48e27807 1333 }
48e27807 1334 }
d36057df
KL
1335 // No active children, return me
1336 return this;
48e27807
KL
1337 }
1338
a69ed767
KL
1339 // ------------------------------------------------------------------------
1340 // Passthru for Screen functions ------------------------------------------
1341 // ------------------------------------------------------------------------
1342
1343 /**
1344 * Get the attributes at one location.
1345 *
1346 * @param x column coordinate. 0 is the left-most column.
1347 * @param y row coordinate. 0 is the top-most row.
1348 * @return attributes at (x, y)
1349 */
1350 protected final CellAttributes getAttrXY(final int x, final int y) {
1351 return getScreen().getAttrXY(x, y);
1352 }
1353
1354 /**
1355 * Set the attributes at one location.
1356 *
1357 * @param x column coordinate. 0 is the left-most column.
1358 * @param y row coordinate. 0 is the top-most row.
1359 * @param attr attributes to use (bold, foreColor, backColor)
1360 */
1361 protected final void putAttrXY(final int x, final int y,
1362 final CellAttributes attr) {
1363
1364 getScreen().putAttrXY(x, y, attr);
1365 }
1366
1367 /**
1368 * Set the attributes at one location.
1369 *
1370 * @param x column coordinate. 0 is the left-most column.
1371 * @param y row coordinate. 0 is the top-most row.
1372 * @param attr attributes to use (bold, foreColor, backColor)
1373 * @param clip if true, honor clipping/offset
1374 */
1375 protected final void putAttrXY(final int x, final int y,
1376 final CellAttributes attr, final boolean clip) {
1377
1378 getScreen().putAttrXY(x, y, attr, clip);
1379 }
1380
1381 /**
1382 * Fill the entire screen with one character with attributes.
1383 *
1384 * @param ch character to draw
1385 * @param attr attributes to use (bold, foreColor, backColor)
1386 */
1387 protected final void putAll(final char ch, final CellAttributes attr) {
1388 getScreen().putAll(ch, attr);
1389 }
1390
1391 /**
1392 * Render one character with attributes.
1393 *
1394 * @param x column coordinate. 0 is the left-most column.
1395 * @param y row coordinate. 0 is the top-most row.
1396 * @param ch character + attributes to draw
1397 */
1398 protected final void putCharXY(final int x, final int y, final Cell ch) {
1399 getScreen().putCharXY(x, y, ch);
1400 }
1401
1402 /**
1403 * Render one character with attributes.
1404 *
1405 * @param x column coordinate. 0 is the left-most column.
1406 * @param y row coordinate. 0 is the top-most row.
1407 * @param ch character to draw
1408 * @param attr attributes to use (bold, foreColor, backColor)
1409 */
1410 protected final void putCharXY(final int x, final int y, final char ch,
1411 final CellAttributes attr) {
1412
1413 getScreen().putCharXY(x, y, ch, attr);
1414 }
1415
1416 /**
1417 * Render one character without changing the underlying attributes.
1418 *
1419 * @param x column coordinate. 0 is the left-most column.
1420 * @param y row coordinate. 0 is the top-most row.
1421 * @param ch character to draw
1422 */
1423 protected final void putCharXY(final int x, final int y, final char ch) {
1424 getScreen().putCharXY(x, y, ch);
1425 }
1426
1427 /**
1428 * Render a string. Does not wrap if the string exceeds the line.
1429 *
1430 * @param x column coordinate. 0 is the left-most column.
1431 * @param y row coordinate. 0 is the top-most row.
1432 * @param str string to draw
1433 * @param attr attributes to use (bold, foreColor, backColor)
1434 */
1435 protected final void putStringXY(final int x, final int y, final String str,
1436 final CellAttributes attr) {
1437
1438 getScreen().putStringXY(x, y, str, attr);
1439 }
1440
1441 /**
1442 * Render a string without changing the underlying attribute. Does not
1443 * wrap if the string exceeds the line.
1444 *
1445 * @param x column coordinate. 0 is the left-most column.
1446 * @param y row coordinate. 0 is the top-most row.
1447 * @param str string to draw
1448 */
1449 protected final void putStringXY(final int x, final int y, final String str) {
1450 getScreen().putStringXY(x, y, str);
1451 }
1452
1453 /**
1454 * Draw a vertical line from (x, y) to (x, y + n).
1455 *
1456 * @param x column coordinate. 0 is the left-most column.
1457 * @param y row coordinate. 0 is the top-most row.
1458 * @param n number of characters to draw
1459 * @param ch character to draw
1460 * @param attr attributes to use (bold, foreColor, backColor)
1461 */
1462 protected final void vLineXY(final int x, final int y, final int n,
1463 final char ch, final CellAttributes attr) {
1464
1465 getScreen().vLineXY(x, y, n, ch, attr);
1466 }
1467
1468 /**
1469 * Draw a horizontal line from (x, y) to (x + n, y).
1470 *
1471 * @param x column coordinate. 0 is the left-most column.
1472 * @param y row coordinate. 0 is the top-most row.
1473 * @param n number of characters to draw
1474 * @param ch character to draw
1475 * @param attr attributes to use (bold, foreColor, backColor)
1476 */
1477 protected final void hLineXY(final int x, final int y, final int n,
1478 final char ch, final CellAttributes attr) {
1479
1480 getScreen().hLineXY(x, y, n, ch, attr);
1481 }
1482
1483 /**
1484 * Draw a box with a border and empty background.
1485 *
1486 * @param left left column of box. 0 is the left-most row.
1487 * @param top top row of the box. 0 is the top-most row.
1488 * @param right right column of box
1489 * @param bottom bottom row of the box
1490 * @param border attributes to use for the border
1491 * @param background attributes to use for the background
1492 */
1493 protected final void drawBox(final int left, final int top,
1494 final int right, final int bottom,
1495 final CellAttributes border, final CellAttributes background) {
1496
1497 getScreen().drawBox(left, top, right, bottom, border, background);
1498 }
1499
1500 /**
1501 * Draw a box with a border and empty background.
1502 *
1503 * @param left left column of box. 0 is the left-most row.
1504 * @param top top row of the box. 0 is the top-most row.
1505 * @param right right column of box
1506 * @param bottom bottom row of the box
1507 * @param border attributes to use for the border
1508 * @param background attributes to use for the background
1509 * @param borderType if 1, draw a single-line border; if 2, draw a
1510 * double-line border; if 3, draw double-line top/bottom edges and
1511 * single-line left/right edges (like Qmodem)
1512 * @param shadow if true, draw a "shadow" on the box
1513 */
1514 protected final void drawBox(final int left, final int top,
1515 final int right, final int bottom,
1516 final CellAttributes border, final CellAttributes background,
1517 final int borderType, final boolean shadow) {
1518
1519 getScreen().drawBox(left, top, right, bottom, border, background,
1520 borderType, shadow);
1521 }
1522
1523 /**
1524 * Draw a box shadow.
1525 *
1526 * @param left left column of box. 0 is the left-most row.
1527 * @param top top row of the box. 0 is the top-most row.
1528 * @param right right column of box
1529 * @param bottom bottom row of the box
1530 */
1531 protected final void drawBoxShadow(final int left, final int top,
1532 final int right, final int bottom) {
1533
1534 getScreen().drawBoxShadow(left, top, right, bottom);
1535 }
1536
2ce6dab2
KL
1537 // ------------------------------------------------------------------------
1538 // Other TWidget constructors ---------------------------------------------
1539 // ------------------------------------------------------------------------
48e27807 1540
30d336cc
KL
1541 /**
1542 * Convenience function to add a label to this container/window.
1543 *
1544 * @param text label
1545 * @param x column relative to parent
1546 * @param y row relative to parent
1547 * @return the new label
1548 */
1549 public final TLabel addLabel(final String text, final int x, final int y) {
1550 return addLabel(text, x, y, "tlabel");
1551 }
1552
00691e80
KL
1553 /**
1554 * Convenience function to add a label to this container/window.
1555 *
1556 * @param text label
1557 * @param x column relative to parent
1558 * @param y row relative to parent
1559 * @param action to call when shortcut is pressed
1560 * @return the new label
1561 */
1562 public final TLabel addLabel(final String text, final int x, final int y,
1563 final TAction action) {
1564
1565 return addLabel(text, x, y, "tlabel", action);
1566 }
1567
30d336cc
KL
1568 /**
1569 * Convenience function to add a label to this container/window.
1570 *
1571 * @param text label
1572 * @param x column relative to parent
1573 * @param y row relative to parent
1574 * @param colorKey ColorTheme key color to use for foreground text.
1575 * Default is "tlabel"
1576 * @return the new label
1577 */
1578 public final TLabel addLabel(final String text, final int x, final int y,
1579 final String colorKey) {
1580
1581 return new TLabel(this, text, x, y, colorKey);
1582 }
1583
00691e80
KL
1584 /**
1585 * Convenience function to add a label to this container/window.
1586 *
1587 * @param text label
1588 * @param x column relative to parent
1589 * @param y row relative to parent
1590 * @param colorKey ColorTheme key color to use for foreground text.
1591 * Default is "tlabel"
1592 * @param action to call when shortcut is pressed
1593 * @return the new label
1594 */
1595 public final TLabel addLabel(final String text, final int x, final int y,
1596 final String colorKey, final TAction action) {
1597
1598 return new TLabel(this, text, x, y, colorKey, action);
1599 }
1600
051e2913
KL
1601 /**
1602 * Convenience function to add a label to this container/window.
1603 *
1604 * @param text label
1605 * @param x column relative to parent
1606 * @param y row relative to parent
1607 * @param colorKey ColorTheme key color to use for foreground text.
1608 * Default is "tlabel"
1609 * @param useWindowBackground if true, use the window's background color
1610 * @return the new label
1611 */
1612 public final TLabel addLabel(final String text, final int x, final int y,
1613 final String colorKey, final boolean useWindowBackground) {
1614
1615 return new TLabel(this, text, x, y, colorKey, useWindowBackground);
1616 }
1617
00691e80
KL
1618 /**
1619 * Convenience function to add a label to this container/window.
1620 *
1621 * @param text label
1622 * @param x column relative to parent
1623 * @param y row relative to parent
1624 * @param colorKey ColorTheme key color to use for foreground text.
1625 * Default is "tlabel"
1626 * @param useWindowBackground if true, use the window's background color
1627 * @param action to call when shortcut is pressed
1628 * @return the new label
1629 */
1630 public final TLabel addLabel(final String text, final int x, final int y,
1631 final String colorKey, final boolean useWindowBackground,
1632 final TAction action) {
1633
1634 return new TLabel(this, text, x, y, colorKey, useWindowBackground,
1635 action);
1636 }
1637
30d336cc
KL
1638 /**
1639 * Convenience function to add a button to this container/window.
1640 *
1641 * @param text label on the button
1642 * @param x column relative to parent
1643 * @param y row relative to parent
051e2913 1644 * @param action action to call when button is pressed
30d336cc
KL
1645 * @return the new button
1646 */
1647 public final TButton addButton(final String text, final int x, final int y,
1648 final TAction action) {
1649
1650 return new TButton(this, text, x, y, action);
1651 }
1652
7272e49f
KL
1653 /**
1654 * Convenience function to add a checkbox to this container/window.
1655 *
1656 * @param x column relative to parent
1657 * @param y row relative to parent
1658 * @param label label to display next to (right of) the checkbox
1659 * @param checked initial check state
1660 * @return the new checkbox
1661 */
051e2913 1662 public final TCheckBox addCheckBox(final int x, final int y,
7272e49f
KL
1663 final String label, final boolean checked) {
1664
051e2913
KL
1665 return new TCheckBox(this, x, y, label, checked);
1666 }
1667
1668 /**
1669 * Convenience function to add a combobox to this container/window.
1670 *
1671 * @param x column relative to parent
1672 * @param y row relative to parent
1673 * @param width visible combobox width, including the down-arrow
1674 * @param values the possible values for the box, shown in the drop-down
1675 * @param valuesIndex the initial index in values, or -1 for no default
1676 * value
1677 * @param valuesHeight the height of the values drop-down when it is
1678 * visible
1679 * @param updateAction action to call when a new value is selected from
1680 * the list or enter is pressed in the edit field
1681 * @return the new combobox
1682 */
1683 public final TComboBox addComboBox(final int x, final int y,
1684 final int width, final List<String> values, final int valuesIndex,
1685 final int valuesHeight, final TAction updateAction) {
1686
1687 return new TComboBox(this, x, y, width, values, valuesIndex,
1688 valuesHeight, updateAction);
1689 }
1690
1691 /**
1692 * Convenience function to add a spinner to this container/window.
1693 *
1694 * @param x column relative to parent
1695 * @param y row relative to parent
1696 * @param upAction action to call when the up arrow is clicked or pressed
1697 * @param downAction action to call when the down arrow is clicked or
1698 * pressed
1699 * @return the new spinner
1700 */
1701 public final TSpinner addSpinner(final int x, final int y,
1702 final TAction upAction, final TAction downAction) {
1703
1704 return new TSpinner(this, x, y, upAction, downAction);
1705 }
1706
1707 /**
1708 * Convenience function to add a calendar to this container/window.
1709 *
1710 * @param x column relative to parent
1711 * @param y row relative to parent
1712 * @param updateAction action to call when the user changes the value of
1713 * the calendar
1714 * @return the new calendar
1715 */
1716 public final TCalendar addCalendar(final int x, final int y,
1717 final TAction updateAction) {
1718
1719 return new TCalendar(this, x, y, updateAction);
7272e49f 1720 }
30d336cc 1721
d502a0e9
KL
1722 /**
1723 * Convenience function to add a progress bar to this container/window.
1724 *
1725 * @param x column relative to parent
1726 * @param y row relative to parent
1727 * @param width width of progress bar
1728 * @param value initial value of percent complete
00d2622b 1729 * @return the new progress bar
d502a0e9
KL
1730 */
1731 public final TProgressBar addProgressBar(final int x, final int y,
1732 final int width, final int value) {
1733
1734 return new TProgressBar(this, x, y, width, value);
1735 }
1736
00d2622b
KL
1737 /**
1738 * Convenience function to add a radio button group to this
1739 * container/window.
1740 *
1741 * @param x column relative to parent
1742 * @param y row relative to parent
1743 * @param label label to display on the group box
1744 * @return the new radio button group
1745 */
1746 public final TRadioGroup addRadioGroup(final int x, final int y,
1747 final String label) {
1748
1749 return new TRadioGroup(this, x, y, label);
1750 }
1751
128e5be1
KL
1752 /**
1753 * Convenience function to add a text field to this container/window.
1754 *
1755 * @param x column relative to parent
1756 * @param y row relative to parent
1757 * @param width visible text width
1758 * @param fixed if true, the text cannot exceed the display width
1759 * @return the new text field
1760 */
1761 public final TField addField(final int x, final int y,
1762 final int width, final boolean fixed) {
1763
1764 return new TField(this, x, y, width, fixed);
1765 }
1766
1767 /**
1768 * Convenience function to add a text field to this container/window.
1769 *
1770 * @param x column relative to parent
1771 * @param y row relative to parent
1772 * @param width visible text width
1773 * @param fixed if true, the text cannot exceed the display width
1774 * @param text initial text, default is empty string
1775 * @return the new text field
1776 */
1777 public final TField addField(final int x, final int y,
1778 final int width, final boolean fixed, final String text) {
1779
1780 return new TField(this, x, y, width, fixed, text);
1781 }
1782
1783 /**
1784 * Convenience function to add a text field to this container/window.
1785 *
1786 * @param x column relative to parent
1787 * @param y row relative to parent
1788 * @param width visible text width
1789 * @param fixed if true, the text cannot exceed the display width
1790 * @param text initial text, default is empty string
1791 * @param enterAction function to call when enter key is pressed
1792 * @param updateAction function to call when the text is updated
1793 * @return the new text field
1794 */
1795 public final TField addField(final int x, final int y,
1796 final int width, final boolean fixed, final String text,
1797 final TAction enterAction, final TAction updateAction) {
1798
1799 return new TField(this, x, y, width, fixed, text, enterAction,
1800 updateAction);
1801 }
00d2622b 1802
cc99cba8
KL
1803 /**
1804 * Convenience function to add a scrollable text box to this
1805 * container/window.
1806 *
1807 * @param text text on the screen
1808 * @param x column relative to parent
1809 * @param y row relative to parent
1810 * @param width width of text area
1811 * @param height height of text area
1812 * @param colorKey ColorTheme key color to use for foreground text
1813 * @return the new text box
1814 */
c6940ed9 1815 public final TText addText(final String text, final int x,
cc99cba8
KL
1816 final int y, final int width, final int height, final String colorKey) {
1817
1818 return new TText(this, text, x, y, width, height, colorKey);
1819 }
1820
1821 /**
1822 * Convenience function to add a scrollable text box to this
1823 * container/window.
1824 *
1825 * @param text text on the screen
1826 * @param x column relative to parent
1827 * @param y row relative to parent
1828 * @param width width of text area
1829 * @param height height of text area
1830 * @return the new text box
1831 */
c6940ed9 1832 public final TText addText(final String text, final int x, final int y,
cc99cba8
KL
1833 final int width, final int height) {
1834
1835 return new TText(this, text, x, y, width, height, "ttext");
1836 }
1837
12b55d76
KL
1838 /**
1839 * Convenience function to add an editable text area box to this
1840 * container/window.
1841 *
1842 * @param text text on the screen
1843 * @param x column relative to parent
1844 * @param y row relative to parent
1845 * @param width width of text area
1846 * @param height height of text area
1847 * @return the new text box
1848 */
1849 public final TEditorWidget addEditor(final String text, final int x,
1850 final int y, final int width, final int height) {
1851
1852 return new TEditorWidget(this, text, x, y, width, height);
1853 }
1854
c6940ed9
KL
1855 /**
1856 * Convenience function to spawn a message box.
1857 *
1858 * @param title window title, will be centered along the top border
1859 * @param caption message to display. Use embedded newlines to get a
1860 * multi-line box.
1861 * @return the new message box
1862 */
1863 public final TMessageBox messageBox(final String title,
1864 final String caption) {
1865
1866 return getApplication().messageBox(title, caption, TMessageBox.Type.OK);
1867 }
1868
1869 /**
1870 * Convenience function to spawn a message box.
1871 *
1872 * @param title window title, will be centered along the top border
1873 * @param caption message to display. Use embedded newlines to get a
1874 * multi-line box.
1875 * @param type one of the TMessageBox.Type constants. Default is
1876 * Type.OK.
1877 * @return the new message box
1878 */
1879 public final TMessageBox messageBox(final String title,
1880 final String caption, final TMessageBox.Type type) {
1881
1882 return getApplication().messageBox(title, caption, type);
1883 }
1884
1885 /**
1886 * Convenience function to spawn an input box.
1887 *
1888 * @param title window title, will be centered along the top border
1889 * @param caption message to display. Use embedded newlines to get a
1890 * multi-line box.
1891 * @return the new input box
1892 */
1893 public final TInputBox inputBox(final String title, final String caption) {
1894
1895 return getApplication().inputBox(title, caption);
1896 }
1897
1898 /**
1899 * Convenience function to spawn an input box.
1900 *
1901 * @param title window title, will be centered along the top border
1902 * @param caption message to display. Use embedded newlines to get a
1903 * multi-line box.
1904 * @param text initial text to seed the field with
1905 * @return the new input box
1906 */
1907 public final TInputBox inputBox(final String title, final String caption,
1908 final String text) {
1909
1910 return getApplication().inputBox(title, caption, text);
1911 }
cc99cba8 1912
87a17f3c
KL
1913 /**
1914 * Convenience function to add a password text field to this
1915 * container/window.
1916 *
1917 * @param x column relative to parent
1918 * @param y row relative to parent
1919 * @param width visible text width
1920 * @param fixed if true, the text cannot exceed the display width
1921 * @return the new text field
1922 */
1923 public final TPasswordField addPasswordField(final int x, final int y,
1924 final int width, final boolean fixed) {
1925
1926 return new TPasswordField(this, x, y, width, fixed);
1927 }
1928
1929 /**
1930 * Convenience function to add a password text field to this
1931 * container/window.
1932 *
1933 * @param x column relative to parent
1934 * @param y row relative to parent
1935 * @param width visible text width
1936 * @param fixed if true, the text cannot exceed the display width
1937 * @param text initial text, default is empty string
1938 * @return the new text field
1939 */
1940 public final TPasswordField addPasswordField(final int x, final int y,
1941 final int width, final boolean fixed, final String text) {
1942
1943 return new TPasswordField(this, x, y, width, fixed, text);
1944 }
1945
1946 /**
1947 * Convenience function to add a password text field to this
1948 * container/window.
1949 *
1950 * @param x column relative to parent
1951 * @param y row relative to parent
1952 * @param width visible text width
1953 * @param fixed if true, the text cannot exceed the display width
1954 * @param text initial text, default is empty string
1955 * @param enterAction function to call when enter key is pressed
1956 * @param updateAction function to call when the text is updated
1957 * @return the new text field
1958 */
1959 public final TPasswordField addPasswordField(final int x, final int y,
1960 final int width, final boolean fixed, final String text,
1961 final TAction enterAction, final TAction updateAction) {
1962
1963 return new TPasswordField(this, x, y, width, fixed, text, enterAction,
1964 updateAction);
1965 }
1966
7668cb45 1967 /**
d36057df
KL
1968 * Convenience function to add a scrollable tree view to this
1969 * container/window.
7668cb45
KL
1970 *
1971 * @param x column relative to parent
1972 * @param y row relative to parent
1973 * @param width width of tree view
1974 * @param height height of tree view
329fd62e 1975 * @return the new tree view
7668cb45 1976 */
d36057df 1977 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
7668cb45
KL
1978 final int width, final int height) {
1979
d36057df 1980 return new TTreeViewWidget(this, x, y, width, height);
7668cb45
KL
1981 }
1982
1983 /**
d36057df
KL
1984 * Convenience function to add a scrollable tree view to this
1985 * container/window.
7668cb45
KL
1986 *
1987 * @param x column relative to parent
1988 * @param y row relative to parent
1989 * @param width width of tree view
1990 * @param height height of tree view
1991 * @param action action to perform when an item is selected
329fd62e 1992 * @return the new tree view
7668cb45 1993 */
d36057df 1994 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
7668cb45
KL
1995 final int width, final int height, final TAction action) {
1996
d36057df 1997 return new TTreeViewWidget(this, x, y, width, height, action);
7668cb45
KL
1998 }
1999
0d47c546
KL
2000 /**
2001 * Convenience function to spawn a file open box.
2002 *
2003 * @param path path of selected file
2004 * @return the result of the new file open box
329fd62e 2005 * @throws IOException if a java.io operation throws
0d47c546
KL
2006 */
2007 public final String fileOpenBox(final String path) throws IOException {
2008 return getApplication().fileOpenBox(path);
2009 }
2010
a69ed767
KL
2011 /**
2012 * Convenience function to spawn a file save box.
2013 *
2014 * @param path path of selected file
2015 * @return the result of the new file open box
2016 * @throws IOException if a java.io operation throws
2017 */
2018 public final String fileSaveBox(final String path) throws IOException {
2019 return getApplication().fileOpenBox(path, TFileOpenBox.Type.SAVE);
2020 }
2021
0d47c546
KL
2022 /**
2023 * Convenience function to spawn a file open box.
2024 *
2025 * @param path path of selected file
2026 * @param type one of the Type constants
2027 * @return the result of the new file open box
329fd62e 2028 * @throws IOException if a java.io operation throws
0d47c546
KL
2029 */
2030 public final String fileOpenBox(final String path,
2031 final TFileOpenBox.Type type) throws IOException {
2032
2033 return getApplication().fileOpenBox(path, type);
2034 }
a69ed767
KL
2035
2036 /**
2037 * Convenience function to spawn a file open box.
2038 *
2039 * @param path path of selected file
2040 * @param type one of the Type constants
2041 * @param filter a string that files must match to be displayed
2042 * @return the result of the new file open box
2043 * @throws IOException of a java.io operation throws
2044 */
2045 public final String fileOpenBox(final String path,
2046 final TFileOpenBox.Type type, final String filter) throws IOException {
2047
2048 ArrayList<String> filters = new ArrayList<String>();
2049 filters.add(filter);
2050
2051 return getApplication().fileOpenBox(path, type, filters);
2052 }
2053
2054 /**
2055 * Convenience function to spawn a file open box.
2056 *
2057 * @param path path of selected file
2058 * @param type one of the Type constants
2059 * @param filters a list of strings that files must match to be displayed
2060 * @return the result of the new file open box
2061 * @throws IOException of a java.io operation throws
2062 */
2063 public final String fileOpenBox(final String path,
2064 final TFileOpenBox.Type type,
2065 final List<String> filters) throws IOException {
2066
2067 return getApplication().fileOpenBox(path, type, filters);
2068 }
2069
0d47c546
KL
2070 /**
2071 * Convenience function to add a directory list to this container/window.
2072 *
2073 * @param path directory path, must be a directory
2074 * @param x column relative to parent
2075 * @param y row relative to parent
2076 * @param width width of text area
2077 * @param height height of text area
329fd62e 2078 * @return the new directory list
0d47c546
KL
2079 */
2080 public final TDirectoryList addDirectoryList(final String path, final int x,
2081 final int y, final int width, final int height) {
2082
2083 return new TDirectoryList(this, path, x, y, width, height, null);
2084 }
2085
2086 /**
2087 * Convenience function to add a directory list to this container/window.
2088 *
2089 * @param path directory path, must be a directory
2090 * @param x column relative to parent
2091 * @param y row relative to parent
2092 * @param width width of text area
2093 * @param height height of text area
a69ed767
KL
2094 * @param action action to perform when an item is selected (enter or
2095 * double-click)
329fd62e 2096 * @return the new directory list
0d47c546
KL
2097 */
2098 public final TDirectoryList addDirectoryList(final String path, final int x,
2099 final int y, final int width, final int height, final TAction action) {
2100
2101 return new TDirectoryList(this, path, x, y, width, height, action);
2102 }
7668cb45 2103
3649b921
KL
2104 /**
2105 * Convenience function to add a directory list to this container/window.
2106 *
a69ed767
KL
2107 * @param path directory path, must be a directory
2108 * @param x column relative to parent
2109 * @param y row relative to parent
2110 * @param width width of text area
2111 * @param height height of text area
2112 * @param action action to perform when an item is selected (enter or
2113 * double-click)
2114 * @param singleClickAction action to perform when an item is selected
2115 * (single-click)
2116 * @return the new directory list
2117 */
2118 public final TDirectoryList addDirectoryList(final String path, final int x,
2119 final int y, final int width, final int height, final TAction action,
2120 final TAction singleClickAction) {
2121
2122 return new TDirectoryList(this, path, x, y, width, height, action,
2123 singleClickAction);
2124 }
2125
2126 /**
2127 * Convenience function to add a directory list to this container/window.
2128 *
2129 * @param path directory path, must be a directory
2130 * @param x column relative to parent
2131 * @param y row relative to parent
2132 * @param width width of text area
2133 * @param height height of text area
2134 * @param action action to perform when an item is selected (enter or
2135 * double-click)
2136 * @param singleClickAction action to perform when an item is selected
2137 * (single-click)
2138 * @param filters a list of strings that files must match to be displayed
2139 * @return the new directory list
2140 */
2141 public final TDirectoryList addDirectoryList(final String path, final int x,
2142 final int y, final int width, final int height, final TAction action,
2143 final TAction singleClickAction, final List<String> filters) {
2144
2145 return new TDirectoryList(this, path, x, y, width, height, action,
2146 singleClickAction, filters);
2147 }
2148
2149 /**
2150 * Convenience function to add a list to this container/window.
2151 *
3649b921
KL
2152 * @param strings list of strings to show
2153 * @param x column relative to parent
2154 * @param y row relative to parent
2155 * @param width width of text area
2156 * @param height height of text area
2157 * @return the new directory list
2158 */
2159 public final TList addList(final List<String> strings, final int x,
2160 final int y, final int width, final int height) {
2161
2162 return new TList(this, strings, x, y, width, height, null);
2163 }
2164
2165 /**
a69ed767 2166 * Convenience function to add a list to this container/window.
3649b921
KL
2167 *
2168 * @param strings list of strings to show
2169 * @param x column relative to parent
2170 * @param y row relative to parent
2171 * @param width width of text area
2172 * @param height height of text area
2173 * @param enterAction action to perform when an item is selected
2174 * @return the new directory list
2175 */
2176 public final TList addList(final List<String> strings, final int x,
2177 final int y, final int width, final int height,
2178 final TAction enterAction) {
2179
2180 return new TList(this, strings, x, y, width, height, enterAction);
2181 }
2182
2183 /**
a69ed767 2184 * Convenience function to add a list to this container/window.
3649b921
KL
2185 *
2186 * @param strings list of strings to show
2187 * @param x column relative to parent
2188 * @param y row relative to parent
2189 * @param width width of text area
2190 * @param height height of text area
2191 * @param enterAction action to perform when an item is selected
2192 * @param moveAction action to perform when the user navigates to a new
2193 * item with arrow/page keys
2194 * @return the new directory list
2195 */
2196 public final TList addList(final List<String> strings, final int x,
2197 final int y, final int width, final int height,
2198 final TAction enterAction, final TAction moveAction) {
2199
2200 return new TList(this, strings, x, y, width, height, enterAction,
2201 moveAction);
2202 }
2203
48e27807 2204}