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