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