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