#51 wip
[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:
c7a75ad3
KL
622 if (children.size() == 0) {
623 break;
624 }
5ffeabcc
KL
625 panel = new TPanel(null, x, y, width, height);
626 pane = new TSplitPane(null, x, y, width, height, true);
627 widgets = new ArrayList<TWidget>(children);
628 for (TWidget w: widgets) {
629 w.setParent(panel, false);
630 }
631 children.clear();
632 pane.setParent(this, false);
633 pane.setLeft(panel);
634 activate(pane);
635 for (TWidget w: widgets) {
636 assert (w.window != null);
637 assert (w.parent != null);
638 }
639 assert (pane.getWindow() != null);
640 assert (pane.getParent() != null);
641 assert (panel.getWindow() != null);
642 assert (panel.getParent() != null);
643 assert (pane.isActive() == true);
644 assert (panel.isActive() == true);
645 return;
646 case TMenu.MID_SPLIT_HORIZONTAL:
c7a75ad3
KL
647 if (children.size() == 0) {
648 break;
649 }
5ffeabcc
KL
650 panel = new TPanel(null, x, y, width, height);
651 pane = new TSplitPane(null, x, y, width, height, false);
652 widgets = new ArrayList<TWidget>(children);
653 for (TWidget w: widgets) {
654 w.setParent(panel, false);
655 }
656 children.clear();
657 pane.setParent(this, false);
658 pane.setTop(panel);
659 activate(pane);
660 for (TWidget w: widgets) {
661 assert (w.window != null);
662 assert (w.parent != null);
663 }
664 assert (pane.getWindow() != null);
665 assert (pane.getParent() != null);
666 assert (panel.getWindow() != null);
667 assert (panel.getParent() != null);
668 assert (pane.isActive() == true);
669 assert (panel.isActive() == true);
670 return;
671 default:
672 break;
673 }
674
d36057df
KL
675 // Default: do nothing, pass to children instead
676 for (TWidget widget: children) {
677 widget.onMenu(menu);
48e27807 678 }
48e27807
KL
679 }
680
681 /**
d36057df
KL
682 * Method that subclasses can override to do processing when the UI is
683 * idle. Note that repainting is NOT assumed. To get a refresh after
684 * onIdle, call doRepaint().
48e27807 685 */
d36057df
KL
686 public void onIdle() {
687 // Default: do nothing, pass to children instead
688 for (TWidget widget: children) {
689 widget.onIdle();
690 }
48e27807
KL
691 }
692
693 /**
d36057df
KL
694 * Consume event. Subclasses that want to intercept all events in one go
695 * can override this method.
48e27807 696 *
d36057df 697 * @param event keyboard, mouse, resize, command, or menu event
48e27807 698 */
d36057df
KL
699 public void handleEvent(final TInputEvent event) {
700 /*
701 System.err.printf("TWidget (%s) event: %s\n", this.getClass().getName(),
702 event);
703 */
704
705 if (!enabled) {
706 // Discard event
707 // System.err.println(" -- discard --");
708 return;
709 }
710
711 if (event instanceof TKeypressEvent) {
712 onKeypress((TKeypressEvent) event);
713 } else if (event instanceof TMouseEvent) {
714
715 TMouseEvent mouse = (TMouseEvent) event;
716
717 switch (mouse.getType()) {
718
719 case MOUSE_DOWN:
720 onMouseDown(mouse);
721 break;
722
723 case MOUSE_UP:
724 onMouseUp(mouse);
725 break;
726
727 case MOUSE_MOTION:
728 onMouseMotion(mouse);
729 break;
730
731 case MOUSE_DOUBLE_CLICK:
732 onMouseDoubleClick(mouse);
733 break;
734
735 default:
736 throw new IllegalArgumentException("Invalid mouse event type: "
737 + mouse.getType());
738 }
739 } else if (event instanceof TResizeEvent) {
740 onResize((TResizeEvent) event);
741 } else if (event instanceof TCommandEvent) {
742 onCommand((TCommandEvent) event);
743 } else if (event instanceof TMenuEvent) {
744 onMenu((TMenuEvent) event);
745 }
746
747 // Do nothing else
748 return;
48e27807
KL
749 }
750
d36057df
KL
751 // ------------------------------------------------------------------------
752 // TWidget ----------------------------------------------------------------
753 // ------------------------------------------------------------------------
754
48e27807 755 /**
d36057df 756 * Get parent widget.
48e27807 757 *
d36057df 758 * @return parent widget
48e27807 759 */
d36057df
KL
760 public final TWidget getParent() {
761 return parent;
48e27807
KL
762 }
763
764 /**
d36057df 765 * Get the list of child widgets that this widget contains.
48e27807 766 *
d36057df 767 * @return the list of child widgets
48e27807 768 */
d36057df
KL
769 public List<TWidget> getChildren() {
770 return children;
48e27807
KL
771 }
772
5218e73c
KL
773 /**
774 * Remove this widget from its parent container. close() will be called
775 * before it is removed.
776 */
777 public final void remove() {
778 remove(true);
779 }
780
781 /**
782 * Remove this widget from its parent container.
783 *
784 * @param doClose if true, call the close() method before removing the
785 * child
786 */
787 public final void remove(final boolean doClose) {
788 if (parent != null) {
789 parent.remove(this, doClose);
790 }
791 }
792
5ffeabcc
KL
793 /**
794 * Remove a child widget from this container.
795 *
796 * @param child the child widget to remove
797 */
798 public final void remove(final TWidget child) {
799 remove(child, true);
800 }
801
5218e73c
KL
802 /**
803 * Remove a child widget from this container.
804 *
805 * @param child the child widget to remove
806 * @param doClose if true, call the close() method before removing the
807 * child
808 */
809 public final void remove(final TWidget child, final boolean doClose) {
810 if (!children.contains(child)) {
811 throw new IndexOutOfBoundsException("child widget is not in " +
812 "list of children of this parent");
813 }
814 if (doClose) {
815 child.close();
816 }
817 children.remove(child);
818 child.parent = null;
5ffeabcc 819 child.window = null;
d8dc8aea
KL
820 if (layout != null) {
821 layout.remove(this);
822 }
5218e73c
KL
823 }
824
825 /**
826 * Set this widget's parent to a different widget.
827 *
828 * @param newParent new parent widget
829 * @param doClose if true, call the close() method before removing the
830 * child from its existing parent widget
831 */
832 public final void setParent(final TWidget newParent,
833 final boolean doClose) {
834
835 if (parent != null) {
836 parent.remove(this, doClose);
5ffeabcc 837 window = null;
5218e73c
KL
838 }
839 assert (parent == null);
5ffeabcc
KL
840 assert (window == null);
841 parent = newParent;
842 setWindow(parent.window);
843 parent.addChild(this);
5218e73c
KL
844 }
845
846 /**
5ffeabcc
KL
847 * Set this widget's window to a specific window.
848 *
849 * Having a null parent with a specified window is only used within Jexer
850 * by TStatusBar because TApplication routes events directly to it and
851 * calls its draw() method. Any other non-parented widgets will require
852 * similar special case functionality to receive events or be drawn to
853 * screen.
5218e73c
KL
854 *
855 * @param window the window to use
856 */
857 public final void setWindow(final TWindow window) {
5218e73c 858 this.window = window;
5ffeabcc
KL
859 for (TWidget child: getChildren()) {
860 child.setWindow(window);
861 }
5218e73c
KL
862 }
863
864 /**
865 * Remove a child widget from this container, and all of its children
866 * recursively from their parent containers.
867 *
868 * @param child the child widget to remove
869 * @param doClose if true, call the close() method before removing each
870 * child
871 */
872 public final void removeAll(final TWidget child, final boolean doClose) {
873 remove(child, doClose);
874 for (TWidget w: child.children) {
875 child.removeAll(w, doClose);
876 }
877 }
878
928811d8 879 /**
d36057df 880 * Get active flag.
928811d8 881 *
d36057df 882 * @return if true, this widget will receive events
928811d8 883 */
d36057df
KL
884 public final boolean isActive() {
885 return active;
928811d8
KL
886 }
887
48e27807 888 /**
d36057df
KL
889 * Set active flag.
890 *
891 * @param active if true, this widget will receive events
48e27807 892 */
d36057df
KL
893 public final void setActive(final boolean active) {
894 this.active = active;
48e27807
KL
895 }
896
897 /**
d36057df
KL
898 * Get the window this widget is on.
899 *
900 * @return the window
48e27807 901 */
d36057df
KL
902 public final TWindow getWindow() {
903 return window;
48e27807
KL
904 }
905
be72cb5c 906 /**
d36057df
KL
907 * Get X position.
908 *
909 * @return absolute X position of the top-left corner
be72cb5c 910 */
d36057df
KL
911 public final int getX() {
912 return x;
be72cb5c
KL
913 }
914
48e27807 915 /**
d36057df
KL
916 * Set X position.
917 *
918 * @param x absolute X position of the top-left corner
48e27807 919 */
d36057df
KL
920 public final void setX(final int x) {
921 this.x = x;
48e27807
KL
922 }
923
924 /**
d36057df 925 * Get Y position.
48e27807 926 *
d36057df 927 * @return absolute Y position of the top-left corner
48e27807 928 */
d36057df
KL
929 public final int getY() {
930 return y;
30d336cc
KL
931 }
932
a83fea2b 933 /**
d36057df 934 * Set Y position.
a83fea2b 935 *
d36057df 936 * @param y absolute Y position of the top-left corner
a83fea2b 937 */
d36057df
KL
938 public final void setY(final int y) {
939 this.y = y;
a83fea2b
KL
940 }
941
30d336cc 942 /**
d36057df 943 * Get the width.
30d336cc 944 *
d36057df 945 * @return widget width
30d336cc 946 */
d8dc8aea 947 public int getWidth() {
d36057df 948 return this.width;
48e27807
KL
949 }
950
a83fea2b 951 /**
d36057df 952 * Change the width.
a83fea2b 953 *
d36057df 954 * @param width new widget width
a83fea2b 955 */
d8dc8aea 956 public void setWidth(final int width) {
a83fea2b 957 this.width = width;
d8dc8aea
KL
958 if (layout != null) {
959 layout.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
960 width, height));
961 }
a83fea2b
KL
962 }
963
2ce6dab2 964 /**
d36057df 965 * Get the height.
2ce6dab2 966 *
d36057df 967 * @return widget height
2ce6dab2 968 */
d8dc8aea 969 public int getHeight() {
d36057df
KL
970 return this.height;
971 }
2ce6dab2 972
d36057df
KL
973 /**
974 * Change the height.
975 *
976 * @param height new widget height
977 */
d8dc8aea 978 public void setHeight(final int height) {
2ce6dab2 979 this.height = height;
d8dc8aea
KL
980 if (layout != null) {
981 layout.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
982 width, height));
983 }
2ce6dab2
KL
984 }
985
48e27807 986 /**
d36057df 987 * Change the dimensions.
48e27807 988 *
d36057df
KL
989 * @param x absolute X position of the top-left corner
990 * @param y absolute Y position of the top-left corner
991 * @param width new widget width
992 * @param height new widget height
48e27807 993 */
d36057df
KL
994 public final void setDimensions(final int x, final int y, final int width,
995 final int height) {
48e27807 996
d36057df
KL
997 setX(x);
998 setY(y);
999 setWidth(width);
1000 setHeight(height);
d8dc8aea
KL
1001 if (layout != null) {
1002 layout.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
1003 width, height));
1004 }
1005 }
1006
1007 /**
1008 * Get the layout manager.
1009 *
1010 * @return the layout manager, or null if not set
1011 */
1012 public LayoutManager getLayoutManager() {
1013 return layout;
1014 }
1015
1016 /**
1017 * Set the layout manager.
1018 *
1019 * @param layout the new layout manager
1020 */
1021 public void setLayoutManager(LayoutManager layout) {
1022 if (this.layout != null) {
1023 for (TWidget w: children) {
1024 this.layout.remove(w);
1025 }
1026 this.layout = null;
1027 }
1028 this.layout = layout;
1029 if (this.layout != null) {
1030 for (TWidget w: children) {
1031 this.layout.add(w);
1032 }
1033 }
48e27807
KL
1034 }
1035
1036 /**
d36057df 1037 * Get enabled flag.
48e27807 1038 *
d36057df 1039 * @return if true, this widget can be tabbed to or receive events
48e27807 1040 */
d36057df
KL
1041 public final boolean isEnabled() {
1042 return enabled;
1043 }
48e27807 1044
d36057df
KL
1045 /**
1046 * Set enabled flag.
1047 *
1048 * @param enabled if true, this widget can be tabbed to or receive events
1049 */
1050 public final void setEnabled(final boolean enabled) {
1051 this.enabled = enabled;
1052 if (!enabled) {
1053 active = false;
1054 // See if there are any active siblings to switch to
1055 boolean foundSibling = false;
1056 if (parent != null) {
1057 for (TWidget w: parent.children) {
1058 if ((w.enabled)
1059 && !(this instanceof THScroller)
1060 && !(this instanceof TVScroller)
1061 ) {
1062 parent.activate(w);
1063 foundSibling = true;
1064 break;
1065 }
1066 }
1067 if (!foundSibling) {
1068 parent.activeChild = null;
1069 }
48e27807 1070 }
48e27807
KL
1071 }
1072 }
1073
051e2913
KL
1074 /**
1075 * Set visible flag.
1076 *
1077 * @param visible if true, this widget will be drawn
1078 */
1079 public final void setVisible(final boolean visible) {
1080 this.visible = visible;
1081 }
1082
1083 /**
1084 * See if this widget is visible.
1085 *
1086 * @return if true, this widget will be drawn
1087 */
1088 public final boolean isVisible() {
1089 return visible;
1090 }
1091
48e27807 1092 /**
d36057df 1093 * Set visible cursor flag.
48e27807 1094 *
d36057df 1095 * @param cursorVisible if true, this widget has a cursor
48e27807 1096 */
d36057df
KL
1097 public final void setCursorVisible(final boolean cursorVisible) {
1098 this.cursorVisible = cursorVisible;
48e27807
KL
1099 }
1100
1101 /**
d36057df 1102 * See if this widget has a visible cursor.
48e27807 1103 *
d36057df 1104 * @return if true, this widget has a visible cursor
48e27807 1105 */
d36057df
KL
1106 public final boolean isCursorVisible() {
1107 // If cursor is out of my bounds, it is not visible.
1108 if ((cursorX >= width)
1109 || (cursorX < 0)
1110 || (cursorY >= height)
1111 || (cursorY < 0)
1112 ) {
1113 return false;
1114 }
48e27807 1115
5218e73c
KL
1116 assert (window != null);
1117
2bc32111
KL
1118 if (window instanceof TDesktop) {
1119 // Desktop doesn't have a window border.
1120 return cursorVisible;
1121 }
1122
d36057df
KL
1123 // If cursor is out of my window's bounds, it is not visible.
1124 if ((getCursorAbsoluteX() >= window.getAbsoluteX()
1125 + window.getWidth() - 1)
1126 || (getCursorAbsoluteX() < 0)
1127 || (getCursorAbsoluteY() >= window.getAbsoluteY()
1128 + window.getHeight() - 1)
1129 || (getCursorAbsoluteY() < 0)
1130 ) {
1131 return false;
48e27807 1132 }
d36057df
KL
1133 return cursorVisible;
1134 }
48e27807 1135
d36057df
KL
1136 /**
1137 * Get cursor X value.
1138 *
1139 * @return cursor column position in relative coordinates
1140 */
1141 public final int getCursorX() {
1142 return cursorX;
1143 }
48e27807 1144
d36057df
KL
1145 /**
1146 * Set cursor X value.
1147 *
1148 * @param cursorX column position in relative coordinates
1149 */
1150 public final void setCursorX(final int cursorX) {
1151 this.cursorX = cursorX;
1152 }
48e27807 1153
d36057df
KL
1154 /**
1155 * Get cursor Y value.
1156 *
1157 * @return cursor row position in relative coordinates
1158 */
1159 public final int getCursorY() {
1160 return cursorY;
1161 }
48e27807 1162
d36057df
KL
1163 /**
1164 * Set cursor Y value.
1165 *
1166 * @param cursorY row position in relative coordinates
1167 */
1168 public final void setCursorY(final int cursorY) {
1169 this.cursorY = cursorY;
1170 }
48e27807 1171
d36057df
KL
1172 /**
1173 * Get this TWidget's parent TApplication.
1174 *
c7a75ad3 1175 * @return the parent TApplication, or null if not assigned
d36057df
KL
1176 */
1177 public TApplication getApplication() {
c7a75ad3
KL
1178 if (window != null) {
1179 return window.getApplication();
1180 }
1181 return null;
d36057df 1182 }
48e27807 1183
d36057df
KL
1184 /**
1185 * Get the Screen.
1186 *
c7a75ad3 1187 * @return the Screen, or null if not assigned
d36057df
KL
1188 */
1189 public Screen getScreen() {
c7a75ad3
KL
1190 if (window != null) {
1191 return window.getScreen();
1192 }
1193 return null;
48e27807
KL
1194 }
1195
1196 /**
d36057df
KL
1197 * Comparison operator. For various subclasses it sorts on:
1198 * <ul>
1199 * <li>tabOrder for TWidgets</li>
1200 * <li>z for TWindows</li>
1201 * <li>text for TTreeItems</li>
1202 * </ul>
48e27807 1203 *
d36057df
KL
1204 * @param that another TWidget, TWindow, or TTreeItem instance
1205 * @return difference between this.tabOrder and that.tabOrder, or
1206 * difference between this.z and that.z, or String.compareTo(text)
48e27807 1207 */
d36057df
KL
1208 public final int compareTo(final TWidget that) {
1209 if ((this instanceof TWindow)
1210 && (that instanceof TWindow)
48e27807 1211 ) {
d36057df
KL
1212 return (((TWindow) this).getZ() - ((TWindow) that).getZ());
1213 }
1214 if ((this instanceof TTreeItem)
1215 && (that instanceof TTreeItem)
1216 ) {
1217 return (((TTreeItem) this).getText().compareTo(
1218 ((TTreeItem) that).getText()));
48e27807 1219 }
d36057df
KL
1220 return (this.tabOrder - that.tabOrder);
1221 }
48e27807 1222
d36057df
KL
1223 /**
1224 * See if this widget should render with the active color.
1225 *
1226 * @return true if this widget is active and all of its parents are
1227 * active.
1228 */
1229 public final boolean isAbsoluteActive() {
1230 if (parent == this) {
1231 return active;
48e27807 1232 }
5218e73c 1233 return (active && (parent == null ? true : parent.isAbsoluteActive()));
48e27807
KL
1234 }
1235
d36057df
KL
1236 /**
1237 * Returns the cursor X position.
1238 *
1239 * @return absolute screen column number for the cursor's X position
1240 */
1241 public final int getCursorAbsoluteX() {
1242 return getAbsoluteX() + cursorX;
1243 }
2ce6dab2
KL
1244
1245 /**
d36057df 1246 * Returns the cursor Y position.
2ce6dab2 1247 *
d36057df 1248 * @return absolute screen row number for the cursor's Y position
2ce6dab2 1249 */
d36057df
KL
1250 public final int getCursorAbsoluteY() {
1251 return getAbsoluteY() + cursorY;
1252 }
2ce6dab2 1253
d36057df
KL
1254 /**
1255 * Compute my absolute X position as the sum of my X plus all my parent's
1256 * X's.
1257 *
1258 * @return absolute screen column number for my X position
1259 */
1260 public final int getAbsoluteX() {
1261 assert (parent != null);
1262 if (parent == this) {
1263 return x;
2ce6dab2 1264 }
d36057df
KL
1265 if ((parent instanceof TWindow)
1266 && !(parent instanceof TMenu)
1267 && !(parent instanceof TDesktop)
1268 ) {
1269 // Widgets on a TWindow have (0,0) as their top-left, but this is
1270 // actually the TWindow's (1,1).
1271 return parent.getAbsoluteX() + x + 1;
1272 }
1273 return parent.getAbsoluteX() + x;
1274 }
2ce6dab2 1275
d36057df
KL
1276 /**
1277 * Compute my absolute Y position as the sum of my Y plus all my parent's
1278 * Y's.
1279 *
1280 * @return absolute screen row number for my Y position
1281 */
1282 public final int getAbsoluteY() {
1283 assert (parent != null);
1284 if (parent == this) {
1285 return y;
1286 }
1287 if ((parent instanceof TWindow)
1288 && !(parent instanceof TMenu)
1289 && !(parent instanceof TDesktop)
2ce6dab2 1290 ) {
d36057df
KL
1291 // Widgets on a TWindow have (0,0) as their top-left, but this is
1292 // actually the TWindow's (1,1).
1293 return parent.getAbsoluteY() + y + 1;
2ce6dab2 1294 }
d36057df 1295 return parent.getAbsoluteY() + y;
2ce6dab2
KL
1296 }
1297
48e27807 1298 /**
d36057df 1299 * Get the global color theme.
48e27807 1300 *
d36057df 1301 * @return the ColorTheme
48e27807 1302 */
a69ed767 1303 protected final ColorTheme getTheme() {
d36057df
KL
1304 return window.getApplication().getTheme();
1305 }
48e27807 1306
d36057df
KL
1307 /**
1308 * Draw my specific widget. When called, the screen rectangle I draw
1309 * into is already setup (offset and clipping).
1310 */
1311 public void draw() {
1312 // Default widget draws nothing.
1313 }
48e27807 1314
d36057df 1315 /**
a69ed767 1316 * Called by parent to render to TWindow. Note package private access.
d36057df 1317 */
a69ed767 1318 final void drawChildren() {
2bc32111
KL
1319 if (window == null) {
1320 return;
1321 }
1322
d36057df
KL
1323 // Set my clipping rectangle
1324 assert (window != null);
1325 assert (getScreen() != null);
1326 Screen screen = getScreen();
1327
1328 // Special case: TStatusBar is drawn by TApplication, not anything
1329 // else.
1330 if (this instanceof TStatusBar) {
1331 return;
48e27807
KL
1332 }
1333
d36057df
KL
1334 screen.setClipRight(width);
1335 screen.setClipBottom(height);
92554d64 1336
d36057df
KL
1337 int absoluteRightEdge = window.getAbsoluteX() + window.getWidth();
1338 int absoluteBottomEdge = window.getAbsoluteY() + window.getHeight();
2bc32111
KL
1339 if (!(this instanceof TWindow)
1340 && !(this instanceof TVScroller)
1341 && !(parent instanceof TDesktop)
1342 ) {
d36057df
KL
1343 absoluteRightEdge -= 1;
1344 }
2bc32111
KL
1345 if (!(this instanceof TWindow)
1346 && !(this instanceof THScroller)
1347 && !(parent instanceof TDesktop)
1348 ) {
d36057df 1349 absoluteBottomEdge -= 1;
48e27807 1350 }
d36057df
KL
1351 int myRightEdge = getAbsoluteX() + width;
1352 int myBottomEdge = getAbsoluteY() + height;
1353 if (getAbsoluteX() > absoluteRightEdge) {
1354 // I am offscreen
1355 screen.setClipRight(0);
1356 } else if (myRightEdge > absoluteRightEdge) {
1357 screen.setClipRight(screen.getClipRight()
1358 - (myRightEdge - absoluteRightEdge));
1359 }
1360 if (getAbsoluteY() > absoluteBottomEdge) {
1361 // I am offscreen
1362 screen.setClipBottom(0);
1363 } else if (myBottomEdge > absoluteBottomEdge) {
1364 screen.setClipBottom(screen.getClipBottom()
1365 - (myBottomEdge - absoluteBottomEdge));
1366 }
1367
1368 // Set my offset
1369 screen.setOffsetX(getAbsoluteX());
1370 screen.setOffsetY(getAbsoluteY());
48e27807 1371
d36057df
KL
1372 // Draw me
1373 draw();
11cedc9a 1374 assert (visible == true);
d36057df 1375
a69ed767
KL
1376 // Continue down the chain. Draw the active child last so that it
1377 // is on top.
48e27807 1378 for (TWidget widget: children) {
a69ed767 1379 if (widget.isVisible() && (widget != activeChild)) {
051e2913
KL
1380 widget.drawChildren();
1381 }
48e27807 1382 }
a69ed767
KL
1383 if (activeChild != null) {
1384 activeChild.drawChildren();
1385 }
48e27807
KL
1386 }
1387
1388 /**
d36057df 1389 * Repaint the screen on the next update.
48e27807 1390 */
a69ed767 1391 protected final void doRepaint() {
d36057df 1392 window.getApplication().doRepaint();
48e27807
KL
1393 }
1394
1395 /**
d36057df
KL
1396 * Add a child widget to my list of children. We set its tabOrder to 0
1397 * and increment the tabOrder of all other children.
48e27807 1398 *
d36057df 1399 * @param child TWidget to add
48e27807 1400 */
d36057df
KL
1401 private void addChild(final TWidget child) {
1402 children.add(child);
48e27807 1403
d36057df
KL
1404 if ((child.enabled)
1405 && !(child instanceof THScroller)
1406 && !(child instanceof TVScroller)
1407 ) {
1408 for (TWidget widget: children) {
1409 widget.active = false;
48e27807 1410 }
d36057df
KL
1411 child.active = true;
1412 activeChild = child;
48e27807 1413 }
d36057df
KL
1414 for (int i = 0; i < children.size(); i++) {
1415 children.get(i).tabOrder = i;
48e27807 1416 }
d8dc8aea
KL
1417 if (layout != null) {
1418 layout.add(child);
1419 }
48e27807
KL
1420 }
1421
00691e80
KL
1422 /**
1423 * Reset the tab order of children to match their position in the list.
1424 * Available so that subclasses can re-order their widgets if needed.
1425 */
1426 protected void resetTabOrder() {
1427 for (int i = 0; i < children.size(); i++) {
1428 children.get(i).tabOrder = i;
1429 }
1430 }
1431
b6faeac0 1432 /**
d36057df 1433 * Switch the active child.
b6faeac0 1434 *
d36057df 1435 * @param child TWidget to activate
b6faeac0 1436 */
d36057df
KL
1437 public final void activate(final TWidget child) {
1438 assert (child.enabled);
1439 if ((child instanceof THScroller)
1440 || (child instanceof TVScroller)
1441 ) {
1442 return;
b6faeac0 1443 }
b6faeac0 1444
e23ea538
KL
1445 if (children.size() == 1) {
1446 if (children.get(0).enabled == true) {
1447 child.active = true;
1448 activeChild = child;
1449 }
1450 } else {
1451 if (child != activeChild) {
1452 if (activeChild != null) {
1453 activeChild.active = false;
1454 }
1455 child.active = true;
1456 activeChild = child;
12b55d76 1457 }
48e27807
KL
1458 }
1459 }
1460
1461 /**
d36057df 1462 * Switch the active child.
48e27807 1463 *
d36057df
KL
1464 * @param tabOrder tabOrder of the child to activate. If that child
1465 * isn't enabled, then the next enabled child will be activated.
48e27807 1466 */
d36057df 1467 public final void activate(final int tabOrder) {
e23ea538
KL
1468 if (children.size() == 1) {
1469 if (children.get(0).enabled == true) {
1470 children.get(0).active = true;
1471 activeChild = children.get(0);
1472 }
1473 return;
1474 }
1475
d36057df 1476 TWidget child = null;
48e27807 1477 for (TWidget widget: children) {
d36057df
KL
1478 if ((widget.enabled)
1479 && !(widget instanceof THScroller)
1480 && !(widget instanceof TVScroller)
1481 && (widget.tabOrder >= tabOrder)
1482 ) {
1483 child = widget;
1484 break;
1485 }
48e27807 1486 }
d36057df 1487 if ((child != null) && (child != activeChild)) {
00691e80
KL
1488 if (activeChild != null) {
1489 activeChild.active = false;
1490 }
d36057df
KL
1491 assert (child.enabled);
1492 child.active = true;
1493 activeChild = child;
48e27807
KL
1494 }
1495 }
1496
5218e73c
KL
1497 /**
1498 * Make this widget the active child of its parent. Note that this is
1499 * not final since TWindow overrides activate().
1500 */
1501 public void activate() {
1502 if (enabled) {
1503 if (parent != null) {
1504 parent.activate(this);
1505 }
1506 }
1507 }
1508
48e27807 1509 /**
d36057df 1510 * Switch the active widget with the next in the tab order.
48e27807 1511 *
d36057df
KL
1512 * @param forward if true, then switch to the next enabled widget in the
1513 * list, otherwise switch to the previous enabled widget in the list
48e27807 1514 */
d36057df 1515 public final void switchWidget(final boolean forward) {
48e27807 1516
e23ea538 1517 // No children: do nothing.
00691e80 1518 if (children.size() == 0) {
e23ea538
KL
1519 return;
1520 }
1521
5218e73c
KL
1522 assert (parent != null);
1523
e23ea538
KL
1524 // If there is only one child, make it active if it is enabled.
1525 if (children.size() == 1) {
1526 if (children.get(0).enabled == true) {
1527 activeChild = children.get(0);
1528 activeChild.active = true;
1529 } else {
1530 children.get(0).active = false;
1531 activeChild = null;
1532 }
48e27807
KL
1533 return;
1534 }
1535
e23ea538
KL
1536 // Two or more children: go forward or backward to the next enabled
1537 // child.
00691e80
KL
1538 int tabOrder = 0;
1539 if (activeChild != null) {
1540 tabOrder = activeChild.tabOrder;
1541 }
d36057df
KL
1542 do {
1543 if (forward) {
1544 tabOrder++;
1545 } else {
1546 tabOrder--;
1547 }
1548 if (tabOrder < 0) {
48e27807 1549
d36057df
KL
1550 // If at the end, pass the switch to my parent.
1551 if ((!forward) && (parent != this)) {
1552 parent.switchWidget(forward);
1553 return;
1554 }
48e27807 1555
d36057df
KL
1556 tabOrder = children.size() - 1;
1557 } else if (tabOrder == children.size()) {
1558 // If at the end, pass the switch to my parent.
1559 if ((forward) && (parent != this)) {
1560 parent.switchWidget(forward);
1561 return;
1562 }
48e27807 1563
d36057df
KL
1564 tabOrder = 0;
1565 }
00691e80
KL
1566 if (activeChild == null) {
1567 if (tabOrder == 0) {
1568 // We wrapped around
1569 break;
1570 }
1571 } else if (activeChild.tabOrder == tabOrder) {
d36057df 1572 // We wrapped around
48e27807 1573 break;
d36057df
KL
1574 }
1575 } while ((!children.get(tabOrder).enabled)
1576 && !(children.get(tabOrder) instanceof THScroller)
1577 && !(children.get(tabOrder) instanceof TVScroller));
48e27807 1578
00691e80
KL
1579 if (activeChild != null) {
1580 assert (children.get(tabOrder).enabled);
48e27807 1581
00691e80
KL
1582 activeChild.active = false;
1583 }
1584 if (children.get(tabOrder).enabled == true) {
1585 children.get(tabOrder).active = true;
1586 activeChild = children.get(tabOrder);
1587 }
d36057df 1588 }
48e27807 1589
d36057df
KL
1590 /**
1591 * Returns my active widget.
1592 *
1593 * @return widget that is active, or this if no children
1594 */
1595 public TWidget getActiveChild() {
1596 if ((this instanceof THScroller)
1597 || (this instanceof TVScroller)
1598 ) {
1599 return parent;
1600 }
b6faeac0 1601
d36057df
KL
1602 for (TWidget widget: children) {
1603 if (widget.active) {
1604 return widget.getActiveChild();
48e27807 1605 }
48e27807 1606 }
d36057df
KL
1607 // No active children, return me
1608 return this;
48e27807
KL
1609 }
1610
a69ed767
KL
1611 // ------------------------------------------------------------------------
1612 // Passthru for Screen functions ------------------------------------------
1613 // ------------------------------------------------------------------------
1614
1615 /**
1616 * Get the attributes at one location.
1617 *
1618 * @param x column coordinate. 0 is the left-most column.
1619 * @param y row coordinate. 0 is the top-most row.
1620 * @return attributes at (x, y)
1621 */
1622 protected final CellAttributes getAttrXY(final int x, final int y) {
1623 return getScreen().getAttrXY(x, y);
1624 }
1625
1626 /**
1627 * Set the attributes at one location.
1628 *
1629 * @param x column coordinate. 0 is the left-most column.
1630 * @param y row coordinate. 0 is the top-most row.
1631 * @param attr attributes to use (bold, foreColor, backColor)
1632 */
1633 protected final void putAttrXY(final int x, final int y,
1634 final CellAttributes attr) {
1635
1636 getScreen().putAttrXY(x, y, attr);
1637 }
1638
1639 /**
1640 * Set the attributes at one location.
1641 *
1642 * @param x column coordinate. 0 is the left-most column.
1643 * @param y row coordinate. 0 is the top-most row.
1644 * @param attr attributes to use (bold, foreColor, backColor)
1645 * @param clip if true, honor clipping/offset
1646 */
1647 protected final void putAttrXY(final int x, final int y,
1648 final CellAttributes attr, final boolean clip) {
1649
1650 getScreen().putAttrXY(x, y, attr, clip);
1651 }
1652
1653 /**
1654 * Fill the entire screen with one character with attributes.
1655 *
1656 * @param ch character to draw
1657 * @param attr attributes to use (bold, foreColor, backColor)
1658 */
218d18db 1659 protected final void putAll(final int ch, final CellAttributes attr) {
a69ed767
KL
1660 getScreen().putAll(ch, attr);
1661 }
1662
1663 /**
1664 * Render one character with attributes.
1665 *
1666 * @param x column coordinate. 0 is the left-most column.
1667 * @param y row coordinate. 0 is the top-most row.
1668 * @param ch character + attributes to draw
1669 */
1670 protected final void putCharXY(final int x, final int y, final Cell ch) {
1671 getScreen().putCharXY(x, y, ch);
1672 }
1673
1674 /**
1675 * Render one character with attributes.
1676 *
1677 * @param x column coordinate. 0 is the left-most column.
1678 * @param y row coordinate. 0 is the top-most row.
1679 * @param ch character to draw
1680 * @param attr attributes to use (bold, foreColor, backColor)
1681 */
218d18db 1682 protected final void putCharXY(final int x, final int y, final int ch,
a69ed767
KL
1683 final CellAttributes attr) {
1684
1685 getScreen().putCharXY(x, y, ch, attr);
1686 }
1687
1688 /**
1689 * Render one character without changing the underlying attributes.
1690 *
1691 * @param x column coordinate. 0 is the left-most column.
1692 * @param y row coordinate. 0 is the top-most row.
1693 * @param ch character to draw
1694 */
218d18db 1695 protected final void putCharXY(final int x, final int y, final int ch) {
a69ed767
KL
1696 getScreen().putCharXY(x, y, ch);
1697 }
1698
1699 /**
1700 * Render a string. Does not wrap if the string exceeds the line.
1701 *
1702 * @param x column coordinate. 0 is the left-most column.
1703 * @param y row coordinate. 0 is the top-most row.
1704 * @param str string to draw
1705 * @param attr attributes to use (bold, foreColor, backColor)
1706 */
1707 protected final void putStringXY(final int x, final int y, final String str,
1708 final CellAttributes attr) {
1709
1710 getScreen().putStringXY(x, y, str, attr);
1711 }
1712
1713 /**
1714 * Render a string without changing the underlying attribute. Does not
1715 * wrap if the string exceeds the line.
1716 *
1717 * @param x column coordinate. 0 is the left-most column.
1718 * @param y row coordinate. 0 is the top-most row.
1719 * @param str string to draw
1720 */
1721 protected final void putStringXY(final int x, final int y, final String str) {
1722 getScreen().putStringXY(x, y, str);
1723 }
1724
1725 /**
1726 * Draw a vertical line from (x, y) to (x, y + n).
1727 *
1728 * @param x column coordinate. 0 is the left-most column.
1729 * @param y row coordinate. 0 is the top-most row.
1730 * @param n number of characters to draw
1731 * @param ch character to draw
1732 * @param attr attributes to use (bold, foreColor, backColor)
1733 */
1734 protected final void vLineXY(final int x, final int y, final int n,
218d18db 1735 final int ch, final CellAttributes attr) {
a69ed767
KL
1736
1737 getScreen().vLineXY(x, y, n, ch, attr);
1738 }
1739
1740 /**
1741 * Draw a horizontal line from (x, y) to (x + n, y).
1742 *
1743 * @param x column coordinate. 0 is the left-most column.
1744 * @param y row coordinate. 0 is the top-most row.
1745 * @param n number of characters to draw
1746 * @param ch character to draw
1747 * @param attr attributes to use (bold, foreColor, backColor)
1748 */
1749 protected final void hLineXY(final int x, final int y, final int n,
218d18db 1750 final int ch, final CellAttributes attr) {
a69ed767
KL
1751
1752 getScreen().hLineXY(x, y, n, ch, attr);
1753 }
1754
1755 /**
1756 * Draw a box with a border and empty background.
1757 *
1758 * @param left left column of box. 0 is the left-most row.
1759 * @param top top row of the box. 0 is the top-most row.
1760 * @param right right column of box
1761 * @param bottom bottom row of the box
1762 * @param border attributes to use for the border
1763 * @param background attributes to use for the background
1764 */
1765 protected final void drawBox(final int left, final int top,
1766 final int right, final int bottom,
1767 final CellAttributes border, final CellAttributes background) {
1768
1769 getScreen().drawBox(left, top, right, bottom, border, background);
1770 }
1771
1772 /**
1773 * Draw a box with a border and empty background.
1774 *
1775 * @param left left column of box. 0 is the left-most row.
1776 * @param top top row of the box. 0 is the top-most row.
1777 * @param right right column of box
1778 * @param bottom bottom row of the box
1779 * @param border attributes to use for the border
1780 * @param background attributes to use for the background
1781 * @param borderType if 1, draw a single-line border; if 2, draw a
1782 * double-line border; if 3, draw double-line top/bottom edges and
1783 * single-line left/right edges (like Qmodem)
1784 * @param shadow if true, draw a "shadow" on the box
1785 */
1786 protected final void drawBox(final int left, final int top,
1787 final int right, final int bottom,
1788 final CellAttributes border, final CellAttributes background,
1789 final int borderType, final boolean shadow) {
1790
1791 getScreen().drawBox(left, top, right, bottom, border, background,
1792 borderType, shadow);
1793 }
1794
1795 /**
1796 * Draw a box shadow.
1797 *
1798 * @param left left column of box. 0 is the left-most row.
1799 * @param top top row of the box. 0 is the top-most row.
1800 * @param right right column of box
1801 * @param bottom bottom row of the box
1802 */
1803 protected final void drawBoxShadow(final int left, final int top,
1804 final int right, final int bottom) {
1805
1806 getScreen().drawBoxShadow(left, top, right, bottom);
1807 }
1808
2ce6dab2
KL
1809 // ------------------------------------------------------------------------
1810 // Other TWidget constructors ---------------------------------------------
1811 // ------------------------------------------------------------------------
48e27807 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 * @return the new label
1820 */
1821 public final TLabel addLabel(final String text, final int x, final int y) {
1822 return addLabel(text, x, y, "tlabel");
1823 }
1824
00691e80
KL
1825 /**
1826 * Convenience function to add a label to this container/window.
1827 *
1828 * @param text label
1829 * @param x column relative to parent
1830 * @param y row relative to parent
1831 * @param action to call when shortcut is pressed
1832 * @return the new label
1833 */
1834 public final TLabel addLabel(final String text, final int x, final int y,
1835 final TAction action) {
1836
1837 return addLabel(text, x, y, "tlabel", action);
1838 }
1839
30d336cc
KL
1840 /**
1841 * Convenience function to add a label to this container/window.
1842 *
1843 * @param text label
1844 * @param x column relative to parent
1845 * @param y row relative to parent
1846 * @param colorKey ColorTheme key color to use for foreground text.
1847 * Default is "tlabel"
1848 * @return the new label
1849 */
1850 public final TLabel addLabel(final String text, final int x, final int y,
1851 final String colorKey) {
1852
1853 return new TLabel(this, text, x, y, colorKey);
1854 }
1855
00691e80
KL
1856 /**
1857 * Convenience function to add a label to this container/window.
1858 *
1859 * @param text label
1860 * @param x column relative to parent
1861 * @param y row relative to parent
1862 * @param colorKey ColorTheme key color to use for foreground text.
1863 * Default is "tlabel"
1864 * @param action to call when shortcut is pressed
1865 * @return the new label
1866 */
1867 public final TLabel addLabel(final String text, final int x, final int y,
1868 final String colorKey, final TAction action) {
1869
1870 return new TLabel(this, text, x, y, colorKey, action);
1871 }
1872
051e2913
KL
1873 /**
1874 * Convenience function to add a label to this container/window.
1875 *
1876 * @param text label
1877 * @param x column relative to parent
1878 * @param y row relative to parent
1879 * @param colorKey ColorTheme key color to use for foreground text.
1880 * Default is "tlabel"
1881 * @param useWindowBackground if true, use the window's background color
1882 * @return the new label
1883 */
1884 public final TLabel addLabel(final String text, final int x, final int y,
1885 final String colorKey, final boolean useWindowBackground) {
1886
1887 return new TLabel(this, text, x, y, colorKey, useWindowBackground);
1888 }
1889
00691e80
KL
1890 /**
1891 * Convenience function to add a label to this container/window.
1892 *
1893 * @param text label
1894 * @param x column relative to parent
1895 * @param y row relative to parent
1896 * @param colorKey ColorTheme key color to use for foreground text.
1897 * Default is "tlabel"
1898 * @param useWindowBackground if true, use the window's background color
1899 * @param action to call when shortcut is pressed
1900 * @return the new label
1901 */
1902 public final TLabel addLabel(final String text, final int x, final int y,
1903 final String colorKey, final boolean useWindowBackground,
1904 final TAction action) {
1905
1906 return new TLabel(this, text, x, y, colorKey, useWindowBackground,
1907 action);
1908 }
1909
30d336cc
KL
1910 /**
1911 * Convenience function to add a button to this container/window.
1912 *
1913 * @param text label on the button
1914 * @param x column relative to parent
1915 * @param y row relative to parent
051e2913 1916 * @param action action to call when button is pressed
30d336cc
KL
1917 * @return the new button
1918 */
1919 public final TButton addButton(final String text, final int x, final int y,
1920 final TAction action) {
1921
1922 return new TButton(this, text, x, y, action);
1923 }
1924
7272e49f
KL
1925 /**
1926 * Convenience function to add a checkbox to this container/window.
1927 *
1928 * @param x column relative to parent
1929 * @param y row relative to parent
1930 * @param label label to display next to (right of) the checkbox
1931 * @param checked initial check state
1932 * @return the new checkbox
1933 */
051e2913 1934 public final TCheckBox addCheckBox(final int x, final int y,
7272e49f
KL
1935 final String label, final boolean checked) {
1936
051e2913
KL
1937 return new TCheckBox(this, x, y, label, checked);
1938 }
1939
1940 /**
1941 * Convenience function to add a combobox to this container/window.
1942 *
1943 * @param x column relative to parent
1944 * @param y row relative to parent
1945 * @param width visible combobox width, including the down-arrow
1946 * @param values the possible values for the box, shown in the drop-down
1947 * @param valuesIndex the initial index in values, or -1 for no default
1948 * value
8ab60a33
KL
1949 * @param maxValuesHeight the maximum height of the values drop-down when
1950 * it is visible
051e2913
KL
1951 * @param updateAction action to call when a new value is selected from
1952 * the list or enter is pressed in the edit field
1953 * @return the new combobox
1954 */
1955 public final TComboBox addComboBox(final int x, final int y,
1956 final int width, final List<String> values, final int valuesIndex,
8ab60a33 1957 final int maxValuesHeight, final TAction updateAction) {
051e2913
KL
1958
1959 return new TComboBox(this, x, y, width, values, valuesIndex,
8ab60a33 1960 maxValuesHeight, updateAction);
051e2913
KL
1961 }
1962
1963 /**
1964 * Convenience function to add a spinner to this container/window.
1965 *
1966 * @param x column relative to parent
1967 * @param y row relative to parent
1968 * @param upAction action to call when the up arrow is clicked or pressed
1969 * @param downAction action to call when the down arrow is clicked or
1970 * pressed
1971 * @return the new spinner
1972 */
1973 public final TSpinner addSpinner(final int x, final int y,
1974 final TAction upAction, final TAction downAction) {
1975
1976 return new TSpinner(this, x, y, upAction, downAction);
1977 }
1978
1979 /**
1980 * Convenience function to add a calendar to this container/window.
1981 *
1982 * @param x column relative to parent
1983 * @param y row relative to parent
1984 * @param updateAction action to call when the user changes the value of
1985 * the calendar
1986 * @return the new calendar
1987 */
1988 public final TCalendar addCalendar(final int x, final int y,
1989 final TAction updateAction) {
1990
1991 return new TCalendar(this, x, y, updateAction);
7272e49f 1992 }
30d336cc 1993
d502a0e9
KL
1994 /**
1995 * Convenience function to add a progress bar to this container/window.
1996 *
1997 * @param x column relative to parent
1998 * @param y row relative to parent
1999 * @param width width of progress bar
2000 * @param value initial value of percent complete
00d2622b 2001 * @return the new progress bar
d502a0e9
KL
2002 */
2003 public final TProgressBar addProgressBar(final int x, final int y,
2004 final int width, final int value) {
2005
2006 return new TProgressBar(this, x, y, width, value);
2007 }
2008
00d2622b
KL
2009 /**
2010 * Convenience function to add a radio button group to this
2011 * container/window.
2012 *
2013 * @param x column relative to parent
2014 * @param y row relative to parent
2015 * @param label label to display on the group box
2016 * @return the new radio button group
2017 */
2018 public final TRadioGroup addRadioGroup(final int x, final int y,
2019 final String label) {
2020
2021 return new TRadioGroup(this, x, y, label);
2022 }
2023
128e5be1
KL
2024 /**
2025 * Convenience function to add a text field to this container/window.
2026 *
2027 * @param x column relative to parent
2028 * @param y row relative to parent
2029 * @param width visible text width
2030 * @param fixed if true, the text cannot exceed the display width
2031 * @return the new text field
2032 */
2033 public final TField addField(final int x, final int y,
2034 final int width, final boolean fixed) {
2035
2036 return new TField(this, x, y, width, fixed);
2037 }
2038
2039 /**
2040 * Convenience function to add a text field to this container/window.
2041 *
2042 * @param x column relative to parent
2043 * @param y row relative to parent
2044 * @param width visible text width
2045 * @param fixed if true, the text cannot exceed the display width
2046 * @param text initial text, default is empty string
2047 * @return the new text field
2048 */
2049 public final TField addField(final int x, final int y,
2050 final int width, final boolean fixed, final String text) {
2051
2052 return new TField(this, x, y, width, fixed, text);
2053 }
2054
2055 /**
2056 * Convenience function to add a text field to this container/window.
2057 *
2058 * @param x column relative to parent
2059 * @param y row relative to parent
2060 * @param width visible text width
2061 * @param fixed if true, the text cannot exceed the display width
2062 * @param text initial text, default is empty string
2063 * @param enterAction function to call when enter key is pressed
2064 * @param updateAction function to call when the text is updated
2065 * @return the new text field
2066 */
2067 public final TField addField(final int x, final int y,
2068 final int width, final boolean fixed, final String text,
2069 final TAction enterAction, final TAction updateAction) {
2070
2071 return new TField(this, x, y, width, fixed, text, enterAction,
2072 updateAction);
2073 }
00d2622b 2074
cc99cba8
KL
2075 /**
2076 * Convenience function to add a scrollable text box to this
2077 * container/window.
2078 *
2079 * @param text text on the screen
2080 * @param x column relative to parent
2081 * @param y row relative to parent
2082 * @param width width of text area
2083 * @param height height of text area
2084 * @param colorKey ColorTheme key color to use for foreground text
2085 * @return the new text box
2086 */
c6940ed9 2087 public final TText addText(final String text, final int x,
cc99cba8
KL
2088 final int y, final int width, final int height, final String colorKey) {
2089
2090 return new TText(this, text, x, y, width, height, colorKey);
2091 }
2092
2093 /**
2094 * Convenience function to add a scrollable text box to this
2095 * container/window.
2096 *
2097 * @param text text on the screen
2098 * @param x column relative to parent
2099 * @param y row relative to parent
2100 * @param width width of text area
2101 * @param height height of text area
2102 * @return the new text box
2103 */
c6940ed9 2104 public final TText addText(final String text, final int x, final int y,
cc99cba8
KL
2105 final int width, final int height) {
2106
2107 return new TText(this, text, x, y, width, height, "ttext");
2108 }
2109
12b55d76
KL
2110 /**
2111 * Convenience function to add an editable text area box to this
2112 * container/window.
2113 *
2114 * @param text text on the screen
2115 * @param x column relative to parent
2116 * @param y row relative to parent
2117 * @param width width of text area
2118 * @param height height of text area
2119 * @return the new text box
2120 */
2121 public final TEditorWidget addEditor(final String text, final int x,
2122 final int y, final int width, final int height) {
2123
2124 return new TEditorWidget(this, text, x, y, width, height);
2125 }
2126
c6940ed9
KL
2127 /**
2128 * Convenience function to spawn a message box.
2129 *
2130 * @param title window title, will be centered along the top border
2131 * @param caption message to display. Use embedded newlines to get a
2132 * multi-line box.
2133 * @return the new message box
2134 */
2135 public final TMessageBox messageBox(final String title,
2136 final String caption) {
2137
2138 return getApplication().messageBox(title, caption, TMessageBox.Type.OK);
2139 }
2140
2141 /**
2142 * Convenience function to spawn a message box.
2143 *
2144 * @param title window title, will be centered along the top border
2145 * @param caption message to display. Use embedded newlines to get a
2146 * multi-line box.
2147 * @param type one of the TMessageBox.Type constants. Default is
2148 * Type.OK.
2149 * @return the new message box
2150 */
2151 public final TMessageBox messageBox(final String title,
2152 final String caption, final TMessageBox.Type type) {
2153
2154 return getApplication().messageBox(title, caption, type);
2155 }
2156
2157 /**
2158 * Convenience function to spawn an input box.
2159 *
2160 * @param title window title, will be centered along the top border
2161 * @param caption message to display. Use embedded newlines to get a
2162 * multi-line box.
2163 * @return the new input box
2164 */
2165 public final TInputBox inputBox(final String title, final String caption) {
2166
2167 return getApplication().inputBox(title, caption);
2168 }
2169
2170 /**
2171 * Convenience function to spawn an input box.
2172 *
2173 * @param title window title, will be centered along the top border
2174 * @param caption message to display. Use embedded newlines to get a
2175 * multi-line box.
2176 * @param text initial text to seed the field with
2177 * @return the new input box
2178 */
2179 public final TInputBox inputBox(final String title, final String caption,
2180 final String text) {
2181
2182 return getApplication().inputBox(title, caption, text);
2183 }
cc99cba8 2184
2b427404
KL
2185 /**
2186 * Convenience function to spawn an input box.
2187 *
2188 * @param title window title, will be centered along the top border
2189 * @param caption message to display. Use embedded newlines to get a
2190 * multi-line box.
2191 * @param text initial text to seed the field with
2192 * @param type one of the Type constants. Default is Type.OK.
2193 * @return the new input box
2194 */
2195 public final TInputBox inputBox(final String title, final String caption,
2196 final String text, final TInputBox.Type type) {
2197
2198 return getApplication().inputBox(title, caption, text, type);
2199 }
2200
87a17f3c
KL
2201 /**
2202 * Convenience function to add a password text field to this
2203 * container/window.
2204 *
2205 * @param x column relative to parent
2206 * @param y row relative to parent
2207 * @param width visible text width
2208 * @param fixed if true, the text cannot exceed the display width
2209 * @return the new text field
2210 */
2211 public final TPasswordField addPasswordField(final int x, final int y,
2212 final int width, final boolean fixed) {
2213
2214 return new TPasswordField(this, x, y, width, fixed);
2215 }
2216
2217 /**
2218 * Convenience function to add a password text field to this
2219 * container/window.
2220 *
2221 * @param x column relative to parent
2222 * @param y row relative to parent
2223 * @param width visible text width
2224 * @param fixed if true, the text cannot exceed the display width
2225 * @param text initial text, default is empty string
2226 * @return the new text field
2227 */
2228 public final TPasswordField addPasswordField(final int x, final int y,
2229 final int width, final boolean fixed, final String text) {
2230
2231 return new TPasswordField(this, x, y, width, fixed, text);
2232 }
2233
2234 /**
2235 * Convenience function to add a password text field to this
2236 * container/window.
2237 *
2238 * @param x column relative to parent
2239 * @param y row relative to parent
2240 * @param width visible text width
2241 * @param fixed if true, the text cannot exceed the display width
2242 * @param text initial text, default is empty string
2243 * @param enterAction function to call when enter key is pressed
2244 * @param updateAction function to call when the text is updated
2245 * @return the new text field
2246 */
2247 public final TPasswordField addPasswordField(final int x, final int y,
2248 final int width, final boolean fixed, final String text,
2249 final TAction enterAction, final TAction updateAction) {
2250
2251 return new TPasswordField(this, x, y, width, fixed, text, enterAction,
2252 updateAction);
2253 }
2254
7668cb45 2255 /**
d36057df
KL
2256 * Convenience function to add a scrollable tree view to this
2257 * container/window.
7668cb45
KL
2258 *
2259 * @param x column relative to parent
2260 * @param y row relative to parent
2261 * @param width width of tree view
2262 * @param height height of tree view
329fd62e 2263 * @return the new tree view
7668cb45 2264 */
d36057df 2265 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
7668cb45
KL
2266 final int width, final int height) {
2267
d36057df 2268 return new TTreeViewWidget(this, x, y, width, height);
7668cb45
KL
2269 }
2270
2271 /**
d36057df
KL
2272 * Convenience function to add a scrollable tree view to this
2273 * container/window.
7668cb45
KL
2274 *
2275 * @param x column relative to parent
2276 * @param y row relative to parent
2277 * @param width width of tree view
2278 * @param height height of tree view
2279 * @param action action to perform when an item is selected
329fd62e 2280 * @return the new tree view
7668cb45 2281 */
d36057df 2282 public final TTreeViewWidget addTreeViewWidget(final int x, final int y,
7668cb45
KL
2283 final int width, final int height, final TAction action) {
2284
d36057df 2285 return new TTreeViewWidget(this, x, y, width, height, action);
7668cb45
KL
2286 }
2287
0d47c546
KL
2288 /**
2289 * Convenience function to spawn a file open box.
2290 *
2291 * @param path path of selected file
2292 * @return the result of the new file open box
329fd62e 2293 * @throws IOException if a java.io operation throws
0d47c546
KL
2294 */
2295 public final String fileOpenBox(final String path) throws IOException {
2296 return getApplication().fileOpenBox(path);
2297 }
2298
a69ed767
KL
2299 /**
2300 * Convenience function to spawn a file save box.
2301 *
2302 * @param path path of selected file
2303 * @return the result of the new file open box
2304 * @throws IOException if a java.io operation throws
2305 */
2306 public final String fileSaveBox(final String path) throws IOException {
2307 return getApplication().fileOpenBox(path, TFileOpenBox.Type.SAVE);
2308 }
2309
0d47c546
KL
2310 /**
2311 * Convenience function to spawn a file open box.
2312 *
2313 * @param path path of selected file
2314 * @param type one of the Type constants
2315 * @return the result of the new file open box
329fd62e 2316 * @throws IOException if a java.io operation throws
0d47c546
KL
2317 */
2318 public final String fileOpenBox(final String path,
2319 final TFileOpenBox.Type type) throws IOException {
2320
2321 return getApplication().fileOpenBox(path, type);
2322 }
a69ed767
KL
2323
2324 /**
2325 * Convenience function to spawn a file open box.
2326 *
2327 * @param path path of selected file
2328 * @param type one of the Type constants
2329 * @param filter a string that files must match to be displayed
2330 * @return the result of the new file open box
2331 * @throws IOException of a java.io operation throws
2332 */
2333 public final String fileOpenBox(final String path,
2334 final TFileOpenBox.Type type, final String filter) throws IOException {
2335
2336 ArrayList<String> filters = new ArrayList<String>();
2337 filters.add(filter);
2338
2339 return getApplication().fileOpenBox(path, type, filters);
2340 }
2341
2342 /**
2343 * Convenience function to spawn a file open box.
2344 *
2345 * @param path path of selected file
2346 * @param type one of the Type constants
2347 * @param filters a list of strings that files must match to be displayed
2348 * @return the result of the new file open box
2349 * @throws IOException of a java.io operation throws
2350 */
2351 public final String fileOpenBox(final String path,
2352 final TFileOpenBox.Type type,
2353 final List<String> filters) throws IOException {
2354
2355 return getApplication().fileOpenBox(path, type, filters);
2356 }
2357
0d47c546
KL
2358 /**
2359 * Convenience function to add a directory list to this container/window.
2360 *
2361 * @param path directory path, must be a directory
2362 * @param x column relative to parent
2363 * @param y row relative to parent
2364 * @param width width of text area
2365 * @param height height of text area
329fd62e 2366 * @return the new directory list
0d47c546
KL
2367 */
2368 public final TDirectoryList addDirectoryList(final String path, final int x,
2369 final int y, final int width, final int height) {
2370
2371 return new TDirectoryList(this, path, x, y, width, height, null);
2372 }
2373
2374 /**
2375 * Convenience function to add a directory list to this container/window.
2376 *
2377 * @param path directory path, must be a directory
2378 * @param x column relative to parent
2379 * @param y row relative to parent
2380 * @param width width of text area
2381 * @param height height of text area
a69ed767
KL
2382 * @param action action to perform when an item is selected (enter or
2383 * double-click)
329fd62e 2384 * @return the new directory list
0d47c546
KL
2385 */
2386 public final TDirectoryList addDirectoryList(final String path, final int x,
2387 final int y, final int width, final int height, final TAction action) {
2388
2389 return new TDirectoryList(this, path, x, y, width, height, action);
2390 }
7668cb45 2391
3649b921
KL
2392 /**
2393 * Convenience function to add a directory list to this container/window.
2394 *
a69ed767
KL
2395 * @param path directory path, must be a directory
2396 * @param x column relative to parent
2397 * @param y row relative to parent
2398 * @param width width of text area
2399 * @param height height of text area
2400 * @param action action to perform when an item is selected (enter or
2401 * double-click)
2402 * @param singleClickAction action to perform when an item is selected
2403 * (single-click)
2404 * @return the new directory list
2405 */
2406 public final TDirectoryList addDirectoryList(final String path, final int x,
2407 final int y, final int width, final int height, final TAction action,
2408 final TAction singleClickAction) {
2409
2410 return new TDirectoryList(this, path, x, y, width, height, action,
2411 singleClickAction);
2412 }
2413
2414 /**
2415 * Convenience function to add a directory list to this container/window.
2416 *
2417 * @param path directory path, must be a directory
2418 * @param x column relative to parent
2419 * @param y row relative to parent
2420 * @param width width of text area
2421 * @param height height of text area
2422 * @param action action to perform when an item is selected (enter or
2423 * double-click)
2424 * @param singleClickAction action to perform when an item is selected
2425 * (single-click)
2426 * @param filters a list of strings that files must match to be displayed
2427 * @return the new directory list
2428 */
2429 public final TDirectoryList addDirectoryList(final String path, final int x,
2430 final int y, final int width, final int height, final TAction action,
2431 final TAction singleClickAction, final List<String> filters) {
2432
2433 return new TDirectoryList(this, path, x, y, width, height, action,
2434 singleClickAction, filters);
2435 }
2436
2437 /**
2438 * Convenience function to add a list to this container/window.
2439 *
3649b921
KL
2440 * @param strings list of strings to show
2441 * @param x column relative to parent
2442 * @param y row relative to parent
2443 * @param width width of text area
2444 * @param height height of text area
2445 * @return the new directory list
2446 */
2447 public final TList addList(final List<String> strings, final int x,
2448 final int y, final int width, final int height) {
2449
2450 return new TList(this, strings, x, y, width, height, null);
2451 }
2452
2453 /**
a69ed767 2454 * Convenience function to add a list to this container/window.
3649b921
KL
2455 *
2456 * @param strings list of strings to show
2457 * @param x column relative to parent
2458 * @param y row relative to parent
2459 * @param width width of text area
2460 * @param height height of text area
2461 * @param enterAction action to perform when an item is selected
2462 * @return the new directory list
2463 */
2464 public final TList addList(final List<String> strings, final int x,
2465 final int y, final int width, final int height,
2466 final TAction enterAction) {
2467
2468 return new TList(this, strings, x, y, width, height, enterAction);
2469 }
2470
2471 /**
a69ed767 2472 * Convenience function to add a list to this container/window.
3649b921
KL
2473 *
2474 * @param strings list of strings to show
2475 * @param x column relative to parent
2476 * @param y row relative to parent
2477 * @param width width of text area
2478 * @param height height of text area
2479 * @param enterAction action to perform when an item is selected
2480 * @param moveAction action to perform when the user navigates to a new
2481 * item with arrow/page keys
2482 * @return the new directory list
2483 */
2484 public final TList addList(final List<String> strings, final int x,
2485 final int y, final int width, final int height,
2486 final TAction enterAction, final TAction moveAction) {
2487
2488 return new TList(this, strings, x, y, width, height, enterAction,
2489 moveAction);
2490 }
2491
9577a9d0
KL
2492 /**
2493 * Convenience function to add a list to this container/window.
2494 *
2495 * @param strings list of strings to show. This is allowed to be null
2496 * and set later with setList() or by subclasses.
2497 * @param x column relative to parent
2498 * @param y row relative to parent
2499 * @param width width of text area
2500 * @param height height of text area
2501 * @param enterAction action to perform when an item is selected
2502 * @param moveAction action to perform when the user navigates to a new
2503 * item with arrow/page keys
2504 * @param singleClickAction action to perform when the user clicks on an
2505 * item
2506 */
2507 public TList addList(final List<String> strings, final int x,
2508 final int y, final int width, final int height,
2509 final TAction enterAction, final TAction moveAction,
2510 final TAction singleClickAction) {
2511
2512 return new TList(this, strings, x, y, width, height, enterAction,
2513 moveAction, singleClickAction);
2514 }
2515
2516
382bc294
KL
2517 /**
2518 * Convenience function to add an image to this container/window.
2519 *
2520 * @param x column relative to parent
2521 * @param y row relative to parent
2522 * @param width number of text cells for width of the image
2523 * @param height number of text cells for height of the image
2524 * @param image the image to display
2525 * @param left left column of the image. 0 is the left-most column.
2526 * @param top top row of the image. 0 is the top-most row.
2527 */
2528 public final TImage addImage(final int x, final int y,
2529 final int width, final int height,
2530 final BufferedImage image, final int left, final int top) {
2531
2532 return new TImage(this, x, y, width, height, image, left, top);
2533 }
2534
2535 /**
2536 * Convenience function to add an image to this container/window.
2537 *
2538 * @param x column relative to parent
2539 * @param y row relative to parent
2540 * @param width number of text cells for width of the image
2541 * @param height number of text cells for height of the image
2542 * @param image the image to display
2543 * @param left left column of the image. 0 is the left-most column.
2544 * @param top top row of the image. 0 is the top-most row.
2545 * @param clickAction function to call when mouse is pressed
2546 */
2547 public final TImage addImage(final int x, final int y,
2548 final int width, final int height,
2549 final BufferedImage image, final int left, final int top,
2550 final TAction clickAction) {
2551
2552 return new TImage(this, x, y, width, height, image, left, top,
2553 clickAction);
2554 }
2555
2556 /**
2557 * Convenience function to add an editable 2D data table to this
2558 * container/window.
2559 *
2560 * @param x column relative to parent
2561 * @param y row relative to parent
2562 * @param width width of widget
2563 * @param height height of widget
2564 */
2565 public TTableWidget addTable(final int x, final int y, final int width,
2566 final int height) {
2567
2568 return new TTableWidget(this, x, y, width, height);
2569 }
2570
656c0ddd
KL
2571 /**
2572 * Convenience function to add an editable 2D data table to this
2573 * container/window.
2574 *
2575 * @param x column relative to parent
2576 * @param y row relative to parent
2577 * @param width width of widget
2578 * @param height height of widget
2579 * @param gridColumns number of columns in grid
2580 * @param gridRows number of rows in grid
2581 */
2582 public TTableWidget addTable(final int x, final int y, final int width,
2583 final int height, final int gridColumns, final int gridRows) {
2584
2585 return new TTableWidget(this, x, y, width, height, gridColumns,
2586 gridRows);
2587 }
2588
fc2af494
KL
2589 /**
2590 * Convenience function to add a panel to this container/window.
2591 *
2592 * @param x column relative to parent
2593 * @param y row relative to parent
2594 * @param width width of text area
2595 * @param height height of text area
2596 * @return the new panel
2597 */
2598 public final TPanel addPanel(final int x, final int y, final int width,
2599 final int height) {
2600
2601 return new TPanel(this, x, y, width, height);
2602 }
2603
5ffeabcc
KL
2604 /**
2605 * Convenience function to add a split pane to this container/window.
2606 *
2607 * @param x column relative to parent
2608 * @param y row relative to parent
2609 * @param width width of text area
2610 * @param height height of text area
2611 * @param vertical if true, split vertically
2612 * @return the new split pane
2613 */
2614 public final TSplitPane addSplitPane(final int x, final int y,
2615 final int width, final int height, final boolean vertical) {
2616
2617 return new TSplitPane(this, x, y, width, height, vertical);
2618 }
2619
48e27807 2620}