2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
31 import java
.awt
.image
.BufferedImage
;
32 import java
.io
.IOException
;
33 import java
.util
.List
;
34 import java
.util
.ArrayList
;
36 import jexer
.backend
.Screen
;
37 import jexer
.bits
.Cell
;
38 import jexer
.bits
.CellAttributes
;
39 import jexer
.bits
.Clipboard
;
40 import jexer
.bits
.ColorTheme
;
41 import jexer
.event
.TCommandEvent
;
42 import jexer
.event
.TInputEvent
;
43 import jexer
.event
.TKeypressEvent
;
44 import jexer
.event
.TMenuEvent
;
45 import jexer
.event
.TMouseEvent
;
46 import jexer
.event
.TResizeEvent
;
47 import jexer
.layout
.LayoutManager
;
48 import jexer
.menu
.TMenu
;
49 import jexer
.ttree
.TTreeItem
;
50 import jexer
.ttree
.TTreeView
;
51 import jexer
.ttree
.TTreeViewWidget
;
52 import static jexer
.TKeypress
.*;
55 * TWidget is the base class of all objects that can be drawn on screen or
56 * handle user input events.
58 public abstract class TWidget
implements Comparable
<TWidget
> {
60 // ------------------------------------------------------------------------
61 // Variables --------------------------------------------------------------
62 // ------------------------------------------------------------------------
65 * Every widget has a parent widget that it may be "contained" in. For
66 * example, a TWindow might contain several TFields, or a TComboBox may
67 * contain a TList that itself contains a TVScroller.
69 private TWidget parent
= null;
72 * Child widgets that this widget contains.
74 private List
<TWidget
> children
;
77 * The currently active child widget that will receive keypress events.
79 private TWidget activeChild
= null;
82 * If true, this widget will receive events.
84 private boolean active
= false;
87 * The window that this widget draws to.
89 private TWindow window
= null;
92 * Absolute X position of the top-left corner.
97 * Absolute Y position of the top-left corner.
104 private int width
= 0;
109 private int height
= 0;
112 * My tab order inside a window or containing widget.
114 private int tabOrder
= 0;
117 * If true, this widget can be tabbed to or receive events.
119 private boolean enabled
= true;
122 * If true, this widget will be rendered.
124 private boolean visible
= true;
127 * If true, this widget has a cursor.
129 private boolean cursorVisible
= false;
132 * Cursor column position in relative coordinates.
134 private int cursorX
= 0;
137 * Cursor row position in relative coordinates.
139 private int cursorY
= 0;
144 private LayoutManager layout
= null;
146 // ------------------------------------------------------------------------
147 // Constructors -----------------------------------------------------------
148 // ------------------------------------------------------------------------
151 * Default constructor for subclasses.
153 protected TWidget() {
154 children
= new ArrayList
<TWidget
>();
158 * Protected constructor.
160 * @param parent parent widget
162 protected TWidget(final TWidget parent
) {
167 * Protected constructor.
169 * @param parent parent widget
170 * @param x column relative to parent
171 * @param y row relative to parent
172 * @param width width of widget
173 * @param height height of widget
175 protected TWidget(final TWidget parent
, final int x
, final int y
,
176 final int width
, final int height
) {
178 this(parent
, true, x
, y
, width
, height
);
182 * Protected constructor used by subclasses that are disabled by default.
184 * @param parent parent widget
185 * @param enabled if true assume enabled
187 protected TWidget(final TWidget parent
, final boolean enabled
) {
188 this.enabled
= enabled
;
189 this.parent
= parent
;
190 children
= new ArrayList
<TWidget
>();
192 if (parent
!= null) {
193 this.window
= parent
.window
;
194 parent
.addChild(this);
199 * Protected constructor used by subclasses that are disabled by default.
201 * @param parent parent widget
202 * @param enabled if true assume enabled
203 * @param x column relative to parent
204 * @param y row relative to parent
205 * @param width width of widget
206 * @param height height of widget
208 protected TWidget(final TWidget parent
, final boolean enabled
,
209 final int x
, final int y
, final int width
, final int height
) {
212 throw new IllegalArgumentException("width cannot be negative");
215 throw new IllegalArgumentException("height cannot be negative");
218 this.enabled
= enabled
;
219 this.parent
= parent
;
220 children
= new ArrayList
<TWidget
>();
225 this.height
= height
;
227 if (parent
!= null) {
228 this.window
= parent
.window
;
229 parent
.addChild(this);
234 * Backdoor access for TWindow's constructor. ONLY TWindow USES THIS.
236 * @param window the top-level window
237 * @param x column relative to parent
238 * @param y row relative to parent
239 * @param width width of window
240 * @param height height of window
242 protected final void setupForTWindow(final TWindow window
,
243 final int x
, final int y
, final int width
, final int height
) {
246 throw new IllegalArgumentException("width cannot be negative");
249 throw new IllegalArgumentException("height cannot be negative");
252 this.parent
= window
;
253 this.window
= window
;
257 this.height
= height
;
260 // ------------------------------------------------------------------------
261 // Event handlers ---------------------------------------------------------
262 // ------------------------------------------------------------------------
265 * Subclasses should override this method to cleanup resources. This is
266 * called by TWindow.onClose().
268 protected void close() {
269 // Default: call close() on children.
270 for (TWidget w
: getChildren()) {
276 * Check if a mouse press/release event coordinate is contained in this
279 * @param mouse a mouse-based event
280 * @return whether or not a mouse click would be sent to this widget
282 public final boolean mouseWouldHit(final TMouseEvent mouse
) {
288 if ((this instanceof TTreeItem
)
289 && ((y
< 0) || (y
> parent
.getHeight() - 1))
294 if ((mouse
.getAbsoluteX() >= getAbsoluteX())
295 && (mouse
.getAbsoluteX() < getAbsoluteX() + width
)
296 && (mouse
.getAbsoluteY() >= getAbsoluteY())
297 && (mouse
.getAbsoluteY() < getAbsoluteY() + height
)
305 * Method that subclasses can override to handle keystrokes.
307 * @param keypress keystroke event
309 public void onKeypress(final TKeypressEvent keypress
) {
310 assert (parent
!= null);
312 if ((children
.size() == 0)
313 || (this instanceof TTreeView
)
314 || (this instanceof TText
)
315 || (this instanceof TComboBox
)
319 // tab / shift-tab - switch to next/previous widget
320 // left-arrow or up-arrow: same as shift-tab
321 if ((keypress
.equals(kbTab
))
322 || (keypress
.equals(kbDown
) && !(this instanceof TComboBox
))
324 parent
.switchWidget(true);
326 } else if ((keypress
.equals(kbShiftTab
))
327 || (keypress
.equals(kbBackTab
))
328 || (keypress
.equals(kbUp
) && !(this instanceof TComboBox
))
330 parent
.switchWidget(false);
335 if ((children
.size() == 0)
336 && !(this instanceof TTreeView
)
340 // right-arrow or down-arrow: same as tab
341 if (keypress
.equals(kbRight
)) {
342 parent
.switchWidget(true);
344 } else if (keypress
.equals(kbLeft
)) {
345 parent
.switchWidget(false);
350 // If I have any buttons on me AND this is an Alt-key that matches
351 // its mnemonic, send it an Enter keystroke.
352 for (TWidget widget
: children
) {
353 if (widget
instanceof TButton
) {
354 TButton button
= (TButton
) widget
;
355 if (button
.isEnabled()
356 && !keypress
.getKey().isFnKey()
357 && keypress
.getKey().isAlt()
358 && !keypress
.getKey().isCtrl()
359 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
360 == Character
.toLowerCase(keypress
.getKey().getChar()))
363 widget
.onKeypress(new TKeypressEvent(kbEnter
));
369 // If I have any labels on me AND this is an Alt-key that matches
370 // its mnemonic, call its action.
371 for (TWidget widget
: children
) {
372 if (widget
instanceof TLabel
) {
373 TLabel label
= (TLabel
) widget
;
374 if (!keypress
.getKey().isFnKey()
375 && keypress
.getKey().isAlt()
376 && !keypress
.getKey().isCtrl()
377 && (Character
.toLowerCase(label
.getMnemonic().getShortcut())
378 == Character
.toLowerCase(keypress
.getKey().getChar()))
387 // If I have any radiobuttons on me AND this is an Alt-key that
388 // matches its mnemonic, select it and send a Space to it.
389 for (TWidget widget
: children
) {
390 if (widget
instanceof TRadioButton
) {
391 TRadioButton button
= (TRadioButton
) widget
;
392 if (button
.isEnabled()
393 && !keypress
.getKey().isFnKey()
394 && keypress
.getKey().isAlt()
395 && !keypress
.getKey().isCtrl()
396 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
397 == Character
.toLowerCase(keypress
.getKey().getChar()))
400 widget
.onKeypress(new TKeypressEvent(kbSpace
));
404 if (widget
instanceof TRadioGroup
) {
405 for (TWidget child
: widget
.getChildren()) {
406 if (child
instanceof TRadioButton
) {
407 TRadioButton button
= (TRadioButton
) child
;
408 if (button
.isEnabled()
409 && !keypress
.getKey().isFnKey()
410 && keypress
.getKey().isAlt()
411 && !keypress
.getKey().isCtrl()
412 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
413 == Character
.toLowerCase(keypress
.getKey().getChar()))
416 widget
.activate(child
);
417 child
.onKeypress(new TKeypressEvent(kbSpace
));
425 // If I have any checkboxes on me AND this is an Alt-key that matches
426 // its mnemonic, select it and set it to checked.
427 for (TWidget widget
: children
) {
428 if (widget
instanceof TCheckBox
) {
429 TCheckBox checkBox
= (TCheckBox
) widget
;
430 if (checkBox
.isEnabled()
431 && !keypress
.getKey().isFnKey()
432 && keypress
.getKey().isAlt()
433 && !keypress
.getKey().isCtrl()
434 && (Character
.toLowerCase(checkBox
.getMnemonic().getShortcut())
435 == Character
.toLowerCase(keypress
.getKey().getChar()))
438 checkBox
.setChecked(true);
444 // Dispatch the keypress to an active widget
445 for (TWidget widget
: children
) {
447 widget
.onKeypress(keypress
);
454 * Method that subclasses can override to handle mouse button presses.
456 * @param mouse mouse button event
458 public void onMouseDown(final TMouseEvent mouse
) {
459 // Default: do nothing, pass to children instead
460 if (activeChild
!= null) {
461 if (activeChild
.mouseWouldHit(mouse
)) {
462 // Dispatch to the active child
464 // Set x and y relative to the child's coordinates
465 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
466 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
467 activeChild
.onMouseDown(mouse
);
471 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
472 TWidget widget
= children
.get(i
);
473 if (widget
.mouseWouldHit(mouse
)) {
474 // Dispatch to this child, also activate it
477 // Set x and y relative to the child's coordinates
478 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
479 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
480 widget
.onMouseDown(mouse
);
487 * Method that subclasses can override to handle mouse button releases.
489 * @param mouse mouse button event
491 public void onMouseUp(final TMouseEvent mouse
) {
492 // Default: do nothing, pass to children instead
493 if (activeChild
!= null) {
494 if (activeChild
.mouseWouldHit(mouse
)) {
495 // Dispatch to the active child
497 // Set x and y relative to the child's coordinates
498 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
499 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
500 activeChild
.onMouseUp(mouse
);
504 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
505 TWidget widget
= children
.get(i
);
506 if (widget
.mouseWouldHit(mouse
)) {
507 // Dispatch to this child, also activate it
510 // Set x and y relative to the child's coordinates
511 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
512 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
513 widget
.onMouseUp(mouse
);
520 * Method that subclasses can override to handle mouse movements.
522 * @param mouse mouse motion event
524 public void onMouseMotion(final TMouseEvent mouse
) {
525 // Default: do nothing, pass it on to ALL of my children. This way
526 // the children can see the mouse "leaving" their area.
527 for (TWidget widget
: children
) {
528 // Set x and y relative to the child's coordinates
529 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
530 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
531 widget
.onMouseMotion(mouse
);
536 * Method that subclasses can override to handle mouse button
539 * @param mouse mouse button event
541 public void onMouseDoubleClick(final TMouseEvent mouse
) {
542 // Default: do nothing, pass to children instead
543 if (activeChild
!= null) {
544 if (activeChild
.mouseWouldHit(mouse
)) {
545 // Dispatch to the active child
547 // Set x and y relative to the child's coordinates
548 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
549 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
550 activeChild
.onMouseDoubleClick(mouse
);
554 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
555 TWidget widget
= children
.get(i
);
556 if (widget
.mouseWouldHit(mouse
)) {
557 // Dispatch to this child, also activate it
560 // Set x and y relative to the child's coordinates
561 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
562 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
563 widget
.onMouseDoubleClick(mouse
);
570 * Method that subclasses can override to handle window/screen resize
573 * @param resize resize event
575 public void onResize(final TResizeEvent resize
) {
576 // Default: change my width/height.
577 if (resize
.getType() == TResizeEvent
.Type
.WIDGET
) {
578 width
= resize
.getWidth();
579 height
= resize
.getHeight();
580 if (layout
!= null) {
581 if (this instanceof TWindow
) {
582 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
583 width
- 2, height
- 2));
585 layout
.onResize(resize
);
589 // Let children see the screen resize
590 for (TWidget widget
: children
) {
591 widget
.onResize(resize
);
597 * Method that subclasses can override to handle posted command events.
599 * @param command command event
601 public void onCommand(final TCommandEvent command
) {
602 if (activeChild
!= null) {
603 activeChild
.onCommand(command
);
608 * Method that subclasses can override to handle menu or posted menu
611 * @param menu menu event
613 public void onMenu(final TMenuEvent menu
) {
614 // Default: do nothing, pass to children instead
615 for (TWidget widget
: children
) {
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().
625 public void onIdle() {
626 // Default: do nothing, pass to children instead
627 for (TWidget widget
: children
) {
633 * Consume event. Subclasses that want to intercept all events in one go
634 * can override this method.
636 * @param event keyboard, mouse, resize, command, or menu event
638 public void handleEvent(final TInputEvent event
) {
640 System.err.printf("TWidget (%s) event: %s\n", this.getClass().getName(),
646 // System.err.println(" -- discard --");
650 if (event
instanceof TKeypressEvent
) {
651 onKeypress((TKeypressEvent
) event
);
652 } else if (event
instanceof TMouseEvent
) {
654 TMouseEvent mouse
= (TMouseEvent
) event
;
656 switch (mouse
.getType()) {
667 onMouseMotion(mouse
);
670 case MOUSE_DOUBLE_CLICK
:
671 onMouseDoubleClick(mouse
);
675 throw new IllegalArgumentException("Invalid mouse event type: "
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
);
690 // ------------------------------------------------------------------------
691 // TWidget ----------------------------------------------------------------
692 // ------------------------------------------------------------------------
697 * @return parent widget
699 public final TWidget
getParent() {
704 * Get the list of child widgets that this widget contains.
706 * @return the list of child widgets
708 public List
<TWidget
> getChildren() {
713 * Remove this widget from its parent container. close() will be called
714 * before it is removed.
716 public final void remove() {
721 * Remove this widget from its parent container.
723 * @param doClose if true, call the close() method before removing the
726 public final void remove(final boolean doClose
) {
727 if (parent
!= null) {
728 parent
.remove(this, doClose
);
733 * Remove a child widget from this container.
735 * @param child the child widget to remove
737 public final void remove(final TWidget child
) {
742 * Remove a child widget from this container.
744 * @param child the child widget to remove
745 * @param doClose if true, call the close() method before removing the
748 public final void remove(final TWidget child
, final boolean doClose
) {
749 if (!children
.contains(child
)) {
750 throw new IndexOutOfBoundsException("child widget is not in " +
751 "list of children of this parent");
756 children
.remove(child
);
759 if (layout
!= null) {
765 * Set this widget's parent to a different widget.
767 * @param newParent new parent widget
768 * @param doClose if true, call the close() method before removing the
769 * child from its existing parent widget
771 public final void setParent(final TWidget newParent
,
772 final boolean doClose
) {
774 if (parent
!= null) {
775 parent
.remove(this, doClose
);
778 assert (parent
== null);
779 assert (window
== null);
781 setWindow(parent
.window
);
782 parent
.addChild(this);
786 * Set this widget's window to a specific window.
788 * Having a null parent with a specified window is only used within Jexer
789 * by TStatusBar because TApplication routes events directly to it and
790 * calls its draw() method. Any other non-parented widgets will require
791 * similar special case functionality to receive events or be drawn to
794 * @param window the window to use
796 public final void setWindow(final TWindow window
) {
797 this.window
= window
;
798 for (TWidget child
: getChildren()) {
799 child
.setWindow(window
);
804 * Remove a child widget from this container, and all of its children
805 * recursively from their parent containers.
807 * @param child the child widget to remove
808 * @param doClose if true, call the close() method before removing each
811 public final void removeAll(final TWidget child
, final boolean doClose
) {
812 remove(child
, doClose
);
813 for (TWidget w
: child
.children
) {
814 child
.removeAll(w
, doClose
);
821 * @return if true, this widget will receive events
823 public final boolean isActive() {
830 * @param active if true, this widget will receive events
832 public final void setActive(final boolean active
) {
833 this.active
= active
;
837 * Get the window this widget is on.
841 public final TWindow
getWindow() {
848 * @return absolute X position of the top-left corner
850 public final int getX() {
857 * @param x absolute X position of the top-left corner
859 public final void setX(final int x
) {
866 * @return absolute Y position of the top-left corner
868 public final int getY() {
875 * @param y absolute Y position of the top-left corner
877 public final void setY(final int y
) {
884 * @return widget width
886 public int getWidth() {
893 * @param width new widget width
895 public void setWidth(final int width
) {
897 if (layout
!= null) {
898 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
906 * @return widget height
908 public int getHeight() {
915 * @param height new widget height
917 public void setHeight(final int height
) {
918 this.height
= height
;
919 if (layout
!= null) {
920 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
926 * Change the dimensions.
928 * @param x absolute X position of the top-left corner
929 * @param y absolute Y position of the top-left corner
930 * @param width new widget width
931 * @param height new widget height
933 public final void setDimensions(final int x
, final int y
, final int width
,
938 // Call the functions so that subclasses can choose how to handle it.
941 if (layout
!= null) {
942 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
948 * Get the layout manager.
950 * @return the layout manager, or null if not set
952 public LayoutManager
getLayoutManager() {
957 * Set the layout manager.
959 * @param layout the new layout manager
961 public void setLayoutManager(LayoutManager layout
) {
962 if (this.layout
!= null) {
963 for (TWidget w
: children
) {
964 this.layout
.remove(w
);
968 this.layout
= layout
;
969 if (this.layout
!= null) {
970 for (TWidget w
: children
) {
979 * @return if true, this widget can be tabbed to or receive events
981 public final boolean isEnabled() {
988 * @param enabled if true, this widget can be tabbed to or receive events
990 public final void setEnabled(final boolean enabled
) {
991 this.enabled
= enabled
;
994 // See if there are any active siblings to switch to
995 boolean foundSibling
= false;
996 if (parent
!= null) {
997 for (TWidget w
: parent
.children
) {
999 && !(this instanceof THScroller
)
1000 && !(this instanceof TVScroller
)
1003 foundSibling
= true;
1007 if (!foundSibling
) {
1008 parent
.activeChild
= null;
1017 * @param visible if true, this widget will be drawn
1019 public final void setVisible(final boolean visible
) {
1020 this.visible
= visible
;
1024 * See if this widget is visible.
1026 * @return if true, this widget will be drawn
1028 public final boolean isVisible() {
1033 * Set visible cursor flag.
1035 * @param cursorVisible if true, this widget has a cursor
1037 public final void setCursorVisible(final boolean cursorVisible
) {
1038 this.cursorVisible
= cursorVisible
;
1042 * See if this widget has a visible cursor.
1044 * @return if true, this widget has a visible cursor
1046 public final boolean isCursorVisible() {
1047 // If cursor is out of my bounds, it is not visible.
1048 if ((cursorX
>= width
)
1050 || (cursorY
>= height
)
1056 assert (window
!= null);
1058 if (window
instanceof TDesktop
) {
1059 // Desktop doesn't have a window border.
1060 return cursorVisible
;
1063 // If cursor is out of my window's bounds, it is not visible.
1064 if ((getCursorAbsoluteX() >= window
.getAbsoluteX()
1065 + window
.getWidth() - 1)
1066 || (getCursorAbsoluteX() < 0)
1067 || (getCursorAbsoluteY() >= window
.getAbsoluteY()
1068 + window
.getHeight() - 1)
1069 || (getCursorAbsoluteY() < 0)
1073 return cursorVisible
;
1077 * Get cursor X value.
1079 * @return cursor column position in relative coordinates
1081 public final int getCursorX() {
1086 * Set cursor X value.
1088 * @param cursorX column position in relative coordinates
1090 public final void setCursorX(final int cursorX
) {
1091 this.cursorX
= cursorX
;
1095 * Get cursor Y value.
1097 * @return cursor row position in relative coordinates
1099 public final int getCursorY() {
1104 * Set cursor Y value.
1106 * @param cursorY row position in relative coordinates
1108 public final void setCursorY(final int cursorY
) {
1109 this.cursorY
= cursorY
;
1113 * Get this TWidget's parent TApplication.
1115 * @return the parent TApplication, or null if not assigned
1117 public TApplication
getApplication() {
1118 if (window
!= null) {
1119 return window
.getApplication();
1127 * @return the Screen, or null if not assigned
1129 public Screen
getScreen() {
1130 if (window
!= null) {
1131 return window
.getScreen();
1137 * Get the Clipboard.
1139 * @return the Clipboard, or null if not assigned
1141 public Clipboard
getClipboard() {
1142 if (window
!= null) {
1143 return window
.getApplication().getClipboard();
1149 * Comparison operator. For various subclasses it sorts on:
1151 * <li>tabOrder for TWidgets</li>
1152 * <li>z for TWindows</li>
1153 * <li>text for TTreeItems</li>
1156 * @param that another TWidget, TWindow, or TTreeItem instance
1157 * @return difference between this.tabOrder and that.tabOrder, or
1158 * difference between this.z and that.z, or String.compareTo(text)
1160 public final int compareTo(final TWidget that
) {
1161 if ((this instanceof TWindow
)
1162 && (that
instanceof TWindow
)
1164 return (((TWindow
) this).getZ() - ((TWindow
) that
).getZ());
1166 if ((this instanceof TTreeItem
)
1167 && (that
instanceof TTreeItem
)
1169 return (((TTreeItem
) this).getText().compareTo(
1170 ((TTreeItem
) that
).getText()));
1172 return (this.tabOrder
- that
.tabOrder
);
1176 * See if this widget should render with the active color.
1178 * @return true if this widget is active and all of its parents are
1181 public final boolean isAbsoluteActive() {
1182 if (parent
== this) {
1185 return (active
&& (parent
== null ?
true : parent
.isAbsoluteActive()));
1189 * Returns the cursor X position.
1191 * @return absolute screen column number for the cursor's X position
1193 public final int getCursorAbsoluteX() {
1194 return getAbsoluteX() + cursorX
;
1198 * Returns the cursor Y position.
1200 * @return absolute screen row number for the cursor's Y position
1202 public final int getCursorAbsoluteY() {
1203 return getAbsoluteY() + cursorY
;
1207 * Compute my absolute X position as the sum of my X plus all my parent's
1210 * @return absolute screen column number for my X position
1212 public final int getAbsoluteX() {
1213 assert (parent
!= null);
1214 if (parent
== this) {
1217 if ((parent
instanceof TWindow
)
1218 && !(parent
instanceof TMenu
)
1219 && !(parent
instanceof TDesktop
)
1221 // Widgets on a TWindow have (0,0) as their top-left, but this is
1222 // actually the TWindow's (1,1).
1223 return parent
.getAbsoluteX() + x
+ 1;
1225 return parent
.getAbsoluteX() + x
;
1229 * Compute my absolute Y position as the sum of my Y plus all my parent's
1232 * @return absolute screen row number for my Y position
1234 public final int getAbsoluteY() {
1235 assert (parent
!= null);
1236 if (parent
== this) {
1239 if ((parent
instanceof TWindow
)
1240 && !(parent
instanceof TMenu
)
1241 && !(parent
instanceof TDesktop
)
1243 // Widgets on a TWindow have (0,0) as their top-left, but this is
1244 // actually the TWindow's (1,1).
1245 return parent
.getAbsoluteY() + y
+ 1;
1247 return parent
.getAbsoluteY() + y
;
1251 * Get the global color theme.
1253 * @return the ColorTheme
1255 protected final ColorTheme
getTheme() {
1256 return window
.getApplication().getTheme();
1260 * See if this widget can be drawn onto a screen.
1262 * @return true if this widget is part of the hierarchy that can draw to
1265 public final boolean isDrawable() {
1266 if ((window
== null)
1267 || (window
.getScreen() == null)
1272 if (parent
== this) {
1275 return (parent
.isDrawable());
1279 * Draw my specific widget. When called, the screen rectangle I draw
1280 * into is already setup (offset and clipping).
1282 public void draw() {
1283 // Default widget draws nothing.
1287 * Called by parent to render to TWindow. Note package private access.
1289 final void drawChildren() {
1290 if (!isDrawable()) {
1294 // Set my clipping rectangle
1295 assert (window
!= null);
1296 assert (getScreen() != null);
1297 Screen screen
= getScreen();
1299 // Special case: TStatusBar is drawn by TApplication, not anything
1301 if (this instanceof TStatusBar
) {
1305 screen
.setClipRight(width
);
1306 screen
.setClipBottom(height
);
1308 int absoluteRightEdge
= window
.getAbsoluteX() + window
.getWidth();
1309 int absoluteBottomEdge
= window
.getAbsoluteY() + window
.getHeight();
1310 if (!(this instanceof TWindow
)
1311 && !(this instanceof TVScroller
)
1312 && !(window
instanceof TDesktop
)
1314 absoluteRightEdge
-= 1;
1316 if (!(this instanceof TWindow
)
1317 && !(this instanceof THScroller
)
1318 && !(window
instanceof TDesktop
)
1320 absoluteBottomEdge
-= 1;
1322 int myRightEdge
= getAbsoluteX() + width
;
1323 int myBottomEdge
= getAbsoluteY() + height
;
1324 if (getAbsoluteX() > absoluteRightEdge
) {
1326 screen
.setClipRight(0);
1327 } else if (myRightEdge
> absoluteRightEdge
) {
1328 screen
.setClipRight(screen
.getClipRight()
1329 - (myRightEdge
- absoluteRightEdge
));
1331 if (getAbsoluteY() > absoluteBottomEdge
) {
1333 screen
.setClipBottom(0);
1334 } else if (myBottomEdge
> absoluteBottomEdge
) {
1335 screen
.setClipBottom(screen
.getClipBottom()
1336 - (myBottomEdge
- absoluteBottomEdge
));
1340 screen
.setOffsetX(getAbsoluteX());
1341 screen
.setOffsetY(getAbsoluteY());
1345 if (!isDrawable()) {
1346 // An action taken by a draw method unhooked me from the UI.
1351 assert (visible
== true);
1353 // Continue down the chain. Draw the active child last so that it
1355 for (TWidget widget
: children
) {
1356 if (widget
.isVisible() && (widget
!= activeChild
)) {
1357 widget
.drawChildren();
1358 if (!isDrawable()) {
1359 // An action taken by a draw method unhooked me from the UI.
1365 if (activeChild
!= null) {
1366 activeChild
.drawChildren();
1371 * Repaint the screen on the next update.
1373 protected final void doRepaint() {
1374 window
.getApplication().doRepaint();
1378 * Add a child widget to my list of children. We set its tabOrder to 0
1379 * and increment the tabOrder of all other children.
1381 * @param child TWidget to add
1383 private void addChild(final TWidget child
) {
1384 children
.add(child
);
1387 && !(child
instanceof THScroller
)
1388 && !(child
instanceof TVScroller
)
1390 for (TWidget widget
: children
) {
1391 widget
.active
= false;
1393 child
.active
= true;
1394 activeChild
= child
;
1396 for (int i
= 0; i
< children
.size(); i
++) {
1397 children
.get(i
).tabOrder
= i
;
1399 if (layout
!= null) {
1405 * Reset the tab order of children to match their position in the list.
1406 * Available so that subclasses can re-order their widgets if needed.
1408 protected void resetTabOrder() {
1409 for (int i
= 0; i
< children
.size(); i
++) {
1410 children
.get(i
).tabOrder
= i
;
1415 * Switch the active child.
1417 * @param child TWidget to activate
1419 public final void activate(final TWidget child
) {
1420 assert (child
.enabled
);
1421 if ((child
instanceof THScroller
)
1422 || (child
instanceof TVScroller
)
1427 if (children
.size() == 1) {
1428 if (children
.get(0).enabled
== true) {
1429 child
.active
= true;
1430 activeChild
= child
;
1433 if (child
!= activeChild
) {
1434 if (activeChild
!= null) {
1435 activeChild
.active
= false;
1437 child
.active
= true;
1438 activeChild
= child
;
1444 * Switch the active child.
1446 * @param tabOrder tabOrder of the child to activate. If that child
1447 * isn't enabled, then the next enabled child will be activated.
1449 public final void activate(final int tabOrder
) {
1450 if (children
.size() == 1) {
1451 if (children
.get(0).enabled
== true) {
1452 children
.get(0).active
= true;
1453 activeChild
= children
.get(0);
1458 TWidget child
= null;
1459 for (TWidget widget
: children
) {
1460 if ((widget
.enabled
)
1461 && !(widget
instanceof THScroller
)
1462 && !(widget
instanceof TVScroller
)
1463 && (widget
.tabOrder
>= tabOrder
)
1469 if ((child
!= null) && (child
!= activeChild
)) {
1470 if (activeChild
!= null) {
1471 activeChild
.active
= false;
1473 assert (child
.enabled
);
1474 child
.active
= true;
1475 activeChild
= child
;
1480 * Make this widget the active child of its parent. Note that this is
1481 * not final since TWindow overrides activate().
1483 public void activate() {
1485 if (parent
!= null) {
1486 parent
.activate(this);
1492 * Make this widget, all of its parents, the active child.
1494 public final void activateAll() {
1496 if (parent
== this) {
1499 if (parent
!= null) {
1500 parent
.activateAll();
1505 * Switch the active widget with the next in the tab order.
1507 * @param forward if true, then switch to the next enabled widget in the
1508 * list, otherwise switch to the previous enabled widget in the list
1510 public final void switchWidget(final boolean forward
) {
1512 // No children: do nothing.
1513 if (children
.size() == 0) {
1517 assert (parent
!= null);
1519 // If there is only one child, make it active if it is enabled.
1520 if (children
.size() == 1) {
1521 if (children
.get(0).enabled
== true) {
1522 activeChild
= children
.get(0);
1523 activeChild
.active
= true;
1525 children
.get(0).active
= false;
1531 // Two or more children: go forward or backward to the next enabled
1534 if (activeChild
!= null) {
1535 tabOrder
= activeChild
.tabOrder
;
1545 // If at the end, pass the switch to my parent.
1546 if ((!forward
) && (parent
!= this)) {
1547 parent
.switchWidget(forward
);
1551 tabOrder
= children
.size() - 1;
1552 } else if (tabOrder
== children
.size()) {
1553 // If at the end, pass the switch to my parent.
1554 if ((forward
) && (parent
!= this)) {
1555 parent
.switchWidget(forward
);
1561 if (activeChild
== null) {
1562 if (tabOrder
== 0) {
1563 // We wrapped around
1566 } else if (activeChild
.tabOrder
== tabOrder
) {
1567 // We wrapped around
1570 } while ((!children
.get(tabOrder
).enabled
)
1571 && !(children
.get(tabOrder
) instanceof THScroller
)
1572 && !(children
.get(tabOrder
) instanceof TVScroller
));
1574 if (activeChild
!= null) {
1575 assert (children
.get(tabOrder
).enabled
);
1577 activeChild
.active
= false;
1579 if (children
.get(tabOrder
).enabled
== true) {
1580 children
.get(tabOrder
).active
= true;
1581 activeChild
= children
.get(tabOrder
);
1586 * Returns my active widget.
1588 * @return widget that is active, or this if no children
1590 public TWidget
getActiveChild() {
1591 if ((this instanceof THScroller
)
1592 || (this instanceof TVScroller
)
1597 for (TWidget widget
: children
) {
1598 if (widget
.active
) {
1599 return widget
.getActiveChild();
1602 // No active children, return me
1607 * Insert a vertical split between this widget and parent, and optionally
1608 * put another widget in the other side of the split.
1610 * @param newWidgetOnLeft if true, the new widget (if specified) will be
1611 * on the left pane, and this widget will be placed on the right pane
1612 * @param newWidget the new widget to add to the other pane, or null
1613 * @return the new split pane widget
1615 public TSplitPane
splitVertical(final boolean newWidgetOnLeft
,
1616 final TWidget newWidget
) {
1618 TSplitPane splitPane
= new TSplitPane(null, x
, y
, width
, height
, true);
1619 TWidget myParent
= parent
;
1621 if (myParent
instanceof TSplitPane
) {
1622 // TSplitPane has a left/right/top/bottom link to me somewhere,
1623 // replace it with a link to splitPane.
1624 ((TSplitPane
) myParent
).replaceWidget(this, splitPane
);
1626 splitPane
.setParent(myParent
, false);
1627 if (newWidgetOnLeft
) {
1628 splitPane
.setLeft(newWidget
);
1629 splitPane
.setRight(this);
1631 splitPane
.setLeft(this);
1632 splitPane
.setRight(newWidget
);
1634 if (newWidget
!= null) {
1635 newWidget
.activateAll();
1640 assert (parent
!= null);
1641 assert (window
!= null);
1642 assert (splitPane
.getWindow() != null);
1643 assert (splitPane
.getParent() != null);
1644 assert (splitPane
.isActive() == true);
1645 assert (parent
== splitPane
);
1646 if (newWidget
!= null) {
1647 assert (newWidget
.parent
== parent
);
1648 assert (newWidget
.active
== true);
1649 assert (active
== false);
1651 assert (active
== true);
1657 * Insert a horizontal split between this widget and parent, and
1658 * optionally put another widget in the other side of the split.
1660 * @param newWidgetOnTop if true, the new widget (if specified) will be
1661 * on the top pane, and this widget's children will be placed on the
1663 * @param newWidget the new widget to add to the other pane, or null
1664 * @return the new split pane widget
1666 public TSplitPane
splitHorizontal(final boolean newWidgetOnTop
,
1667 final TWidget newWidget
) {
1669 TSplitPane splitPane
= new TSplitPane(null, x
, y
, width
, height
, false);
1670 TWidget myParent
= parent
;
1672 if (myParent
instanceof TSplitPane
) {
1673 // TSplitPane has a left/right/top/bottom link to me somewhere,
1674 // replace it with a link to splitPane.
1675 ((TSplitPane
) myParent
).replaceWidget(this, splitPane
);
1677 splitPane
.setParent(myParent
, false);
1678 if (newWidgetOnTop
) {
1679 splitPane
.setTop(newWidget
);
1680 splitPane
.setBottom(this);
1682 splitPane
.setTop(this);
1683 splitPane
.setBottom(newWidget
);
1685 if (newWidget
!= null) {
1686 newWidget
.activateAll();
1691 assert (parent
!= null);
1692 assert (window
!= null);
1693 assert (splitPane
.getWindow() != null);
1694 assert (splitPane
.getParent() != null);
1695 assert (splitPane
.isActive() == true);
1696 assert (parent
== splitPane
);
1697 if (newWidget
!= null) {
1698 assert (newWidget
.parent
== parent
);
1699 assert (newWidget
.active
== true);
1700 assert (active
== false);
1702 assert (active
== true);
1708 * Generate a human-readable string for this widget.
1710 * @return a human-readable string
1713 public String
toString() {
1714 return String
.format("%s(%8x) position (%d, %d) geometry %dx%d " +
1715 "active %s enabled %s visible %s", getClass().getName(),
1716 hashCode(), x
, y
, width
, height
, active
, enabled
, visible
);
1720 * Generate a string for this widget's hierarchy.
1722 * @param prefix a prefix to use for this widget's place in the hierarchy
1723 * @return a pretty-printable string of this hierarchy
1725 protected String
toPrettyString(final String prefix
) {
1726 StringBuilder sb
= new StringBuilder(prefix
);
1727 sb
.append(toString());
1728 String newPrefix
= "";
1729 for (int i
= 0; i
< prefix
.length(); i
++) {
1732 for (int i
= 0; i
< children
.size(); i
++) {
1733 TWidget child
= children
.get(i
);
1735 if (i
== children
.size() - 1) {
1736 sb
.append(child
.toPrettyString(newPrefix
+ " \u2514\u2500"));
1738 sb
.append(child
.toPrettyString(newPrefix
+ " \u251c\u2500"));
1741 return sb
.toString();
1745 * Generate a string for this widget's hierarchy.
1747 * @return a pretty-printable string of this hierarchy
1749 public String
toPrettyString() {
1750 return toPrettyString("");
1753 // ------------------------------------------------------------------------
1754 // Passthru for Screen functions ------------------------------------------
1755 // ------------------------------------------------------------------------
1758 * Get the attributes at one location.
1760 * @param x column coordinate. 0 is the left-most column.
1761 * @param y row coordinate. 0 is the top-most row.
1762 * @return attributes at (x, y)
1764 protected final CellAttributes
getAttrXY(final int x
, final int y
) {
1765 return getScreen().getAttrXY(x
, y
);
1769 * Set the attributes at one location.
1771 * @param x column coordinate. 0 is the left-most column.
1772 * @param y row coordinate. 0 is the top-most row.
1773 * @param attr attributes to use (bold, foreColor, backColor)
1775 protected final void putAttrXY(final int x
, final int y
,
1776 final CellAttributes attr
) {
1778 getScreen().putAttrXY(x
, y
, attr
);
1782 * Set the attributes at one location.
1784 * @param x column coordinate. 0 is the left-most column.
1785 * @param y row coordinate. 0 is the top-most row.
1786 * @param attr attributes to use (bold, foreColor, backColor)
1787 * @param clip if true, honor clipping/offset
1789 protected final void putAttrXY(final int x
, final int y
,
1790 final CellAttributes attr
, final boolean clip
) {
1792 getScreen().putAttrXY(x
, y
, attr
, clip
);
1796 * Fill the entire screen with one character with attributes.
1798 * @param ch character to draw
1799 * @param attr attributes to use (bold, foreColor, backColor)
1801 protected final void putAll(final int ch
, final CellAttributes attr
) {
1802 getScreen().putAll(ch
, attr
);
1806 * Render one character with attributes.
1808 * @param x column coordinate. 0 is the left-most column.
1809 * @param y row coordinate. 0 is the top-most row.
1810 * @param ch character + attributes to draw
1812 protected final void putCharXY(final int x
, final int y
, final Cell ch
) {
1813 getScreen().putCharXY(x
, y
, ch
);
1817 * Render one character with attributes.
1819 * @param x column coordinate. 0 is the left-most column.
1820 * @param y row coordinate. 0 is the top-most row.
1821 * @param ch character to draw
1822 * @param attr attributes to use (bold, foreColor, backColor)
1824 protected final void putCharXY(final int x
, final int y
, final int ch
,
1825 final CellAttributes attr
) {
1827 getScreen().putCharXY(x
, y
, ch
, attr
);
1831 * Render one character without changing the underlying attributes.
1833 * @param x column coordinate. 0 is the left-most column.
1834 * @param y row coordinate. 0 is the top-most row.
1835 * @param ch character to draw
1837 protected final void putCharXY(final int x
, final int y
, final int ch
) {
1838 getScreen().putCharXY(x
, y
, ch
);
1842 * Render a string. Does not wrap if the string exceeds the line.
1844 * @param x column coordinate. 0 is the left-most column.
1845 * @param y row coordinate. 0 is the top-most row.
1846 * @param str string to draw
1847 * @param attr attributes to use (bold, foreColor, backColor)
1849 protected final void putStringXY(final int x
, final int y
, final String str
,
1850 final CellAttributes attr
) {
1852 getScreen().putStringXY(x
, y
, str
, attr
);
1856 * Render a string without changing the underlying attribute. Does not
1857 * wrap if the string exceeds the line.
1859 * @param x column coordinate. 0 is the left-most column.
1860 * @param y row coordinate. 0 is the top-most row.
1861 * @param str string to draw
1863 protected final void putStringXY(final int x
, final int y
, final String str
) {
1864 getScreen().putStringXY(x
, y
, str
);
1868 * Draw a vertical line from (x, y) to (x, y + n).
1870 * @param x column coordinate. 0 is the left-most column.
1871 * @param y row coordinate. 0 is the top-most row.
1872 * @param n number of characters to draw
1873 * @param ch character to draw
1874 * @param attr attributes to use (bold, foreColor, backColor)
1876 protected final void vLineXY(final int x
, final int y
, final int n
,
1877 final int ch
, final CellAttributes attr
) {
1879 getScreen().vLineXY(x
, y
, n
, ch
, attr
);
1883 * Draw a horizontal line from (x, y) to (x + n, y).
1885 * @param x column coordinate. 0 is the left-most column.
1886 * @param y row coordinate. 0 is the top-most row.
1887 * @param n number of characters to draw
1888 * @param ch character to draw
1889 * @param attr attributes to use (bold, foreColor, backColor)
1891 protected final void hLineXY(final int x
, final int y
, final int n
,
1892 final int ch
, final CellAttributes attr
) {
1894 getScreen().hLineXY(x
, y
, n
, ch
, attr
);
1898 * Draw a box with a border and empty background.
1900 * @param left left column of box. 0 is the left-most row.
1901 * @param top top row of the box. 0 is the top-most row.
1902 * @param right right column of box
1903 * @param bottom bottom row of the box
1904 * @param border attributes to use for the border
1905 * @param background attributes to use for the background
1907 protected final void drawBox(final int left
, final int top
,
1908 final int right
, final int bottom
,
1909 final CellAttributes border
, final CellAttributes background
) {
1911 getScreen().drawBox(left
, top
, right
, bottom
, border
, background
);
1915 * Draw a box with a border and empty background.
1917 * @param left left column of box. 0 is the left-most row.
1918 * @param top top row of the box. 0 is the top-most row.
1919 * @param right right column of box
1920 * @param bottom bottom row of the box
1921 * @param border attributes to use for the border
1922 * @param background attributes to use for the background
1923 * @param borderType if 1, draw a single-line border; if 2, draw a
1924 * double-line border; if 3, draw double-line top/bottom edges and
1925 * single-line left/right edges (like Qmodem)
1926 * @param shadow if true, draw a "shadow" on the box
1928 protected final void drawBox(final int left
, final int top
,
1929 final int right
, final int bottom
,
1930 final CellAttributes border
, final CellAttributes background
,
1931 final int borderType
, final boolean shadow
) {
1933 getScreen().drawBox(left
, top
, right
, bottom
, border
, background
,
1934 borderType
, shadow
);
1938 * Draw a box shadow.
1940 * @param left left column of box. 0 is the left-most row.
1941 * @param top top row of the box. 0 is the top-most row.
1942 * @param right right column of box
1943 * @param bottom bottom row of the box
1945 protected final void drawBoxShadow(final int left
, final int top
,
1946 final int right
, final int bottom
) {
1948 getScreen().drawBoxShadow(left
, top
, right
, bottom
);
1951 // ------------------------------------------------------------------------
1952 // Other TWidget constructors ---------------------------------------------
1953 // ------------------------------------------------------------------------
1956 * Convenience function to add a label to this container/window.
1959 * @param x column relative to parent
1960 * @param y row relative to parent
1961 * @return the new label
1963 public final TLabel
addLabel(final String text
, final int x
, final int y
) {
1964 return addLabel(text
, x
, y
, "tlabel");
1968 * Convenience function to add a label to this container/window.
1971 * @param x column relative to parent
1972 * @param y row relative to parent
1973 * @param action to call when shortcut is pressed
1974 * @return the new label
1976 public final TLabel
addLabel(final String text
, final int x
, final int y
,
1977 final TAction action
) {
1979 return addLabel(text
, x
, y
, "tlabel", action
);
1983 * Convenience function to add a label to this container/window.
1986 * @param x column relative to parent
1987 * @param y row relative to parent
1988 * @param colorKey ColorTheme key color to use for foreground text.
1989 * Default is "tlabel"
1990 * @return the new label
1992 public final TLabel
addLabel(final String text
, final int x
, final int y
,
1993 final String colorKey
) {
1995 return new TLabel(this, text
, x
, y
, colorKey
);
1999 * Convenience function to add a label to this container/window.
2002 * @param x column relative to parent
2003 * @param y row relative to parent
2004 * @param colorKey ColorTheme key color to use for foreground text.
2005 * Default is "tlabel"
2006 * @param action to call when shortcut is pressed
2007 * @return the new label
2009 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2010 final String colorKey
, final TAction action
) {
2012 return new TLabel(this, text
, x
, y
, colorKey
, action
);
2016 * Convenience function to add a label to this container/window.
2019 * @param x column relative to parent
2020 * @param y row relative to parent
2021 * @param colorKey ColorTheme key color to use for foreground text.
2022 * Default is "tlabel"
2023 * @param useWindowBackground if true, use the window's background color
2024 * @return the new label
2026 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2027 final String colorKey
, final boolean useWindowBackground
) {
2029 return new TLabel(this, text
, x
, y
, colorKey
, useWindowBackground
);
2033 * Convenience function to add a label to this container/window.
2036 * @param x column relative to parent
2037 * @param y row relative to parent
2038 * @param colorKey ColorTheme key color to use for foreground text.
2039 * Default is "tlabel"
2040 * @param useWindowBackground if true, use the window's background color
2041 * @param action to call when shortcut is pressed
2042 * @return the new label
2044 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2045 final String colorKey
, final boolean useWindowBackground
,
2046 final TAction action
) {
2048 return new TLabel(this, text
, x
, y
, colorKey
, useWindowBackground
,
2053 * Convenience function to add a button to this container/window.
2055 * @param text label on the button
2056 * @param x column relative to parent
2057 * @param y row relative to parent
2058 * @param action action to call when button is pressed
2059 * @return the new button
2061 public final TButton
addButton(final String text
, final int x
, final int y
,
2062 final TAction action
) {
2064 return new TButton(this, text
, x
, y
, action
);
2068 * Convenience function to add a checkbox to this container/window.
2070 * @param x column relative to parent
2071 * @param y row relative to parent
2072 * @param label label to display next to (right of) the checkbox
2073 * @param checked initial check state
2074 * @return the new checkbox
2076 public final TCheckBox
addCheckBox(final int x
, final int y
,
2077 final String label
, final boolean checked
) {
2079 return new TCheckBox(this, x
, y
, label
, checked
);
2083 * Convenience function to add a combobox to this container/window.
2085 * @param x column relative to parent
2086 * @param y row relative to parent
2087 * @param width visible combobox width, including the down-arrow
2088 * @param values the possible values for the box, shown in the drop-down
2089 * @param valuesIndex the initial index in values, or -1 for no default
2091 * @param maxValuesHeight the maximum height of the values drop-down when
2093 * @param updateAction action to call when a new value is selected from
2094 * the list or enter is pressed in the edit field
2095 * @return the new combobox
2097 public final TComboBox
addComboBox(final int x
, final int y
,
2098 final int width
, final List
<String
> values
, final int valuesIndex
,
2099 final int maxValuesHeight
, final TAction updateAction
) {
2101 return new TComboBox(this, x
, y
, width
, values
, valuesIndex
,
2102 maxValuesHeight
, updateAction
);
2106 * Convenience function to add a spinner to this container/window.
2108 * @param x column relative to parent
2109 * @param y row relative to parent
2110 * @param upAction action to call when the up arrow is clicked or pressed
2111 * @param downAction action to call when the down arrow is clicked or
2113 * @return the new spinner
2115 public final TSpinner
addSpinner(final int x
, final int y
,
2116 final TAction upAction
, final TAction downAction
) {
2118 return new TSpinner(this, x
, y
, upAction
, downAction
);
2122 * Convenience function to add a calendar to this container/window.
2124 * @param x column relative to parent
2125 * @param y row relative to parent
2126 * @param updateAction action to call when the user changes the value of
2128 * @return the new calendar
2130 public final TCalendar
addCalendar(final int x
, final int y
,
2131 final TAction updateAction
) {
2133 return new TCalendar(this, x
, y
, updateAction
);
2137 * Convenience function to add a progress bar to this container/window.
2139 * @param x column relative to parent
2140 * @param y row relative to parent
2141 * @param width width of progress bar
2142 * @param value initial value of percent complete
2143 * @return the new progress bar
2145 public final TProgressBar
addProgressBar(final int x
, final int y
,
2146 final int width
, final int value
) {
2148 return new TProgressBar(this, x
, y
, width
, value
);
2152 * Convenience function to add a radio button group to this
2155 * @param x column relative to parent
2156 * @param y row relative to parent
2157 * @param label label to display on the group box
2158 * @return the new radio button group
2160 public final TRadioGroup
addRadioGroup(final int x
, final int y
,
2161 final String label
) {
2163 return new TRadioGroup(this, x
, y
, label
);
2167 * Convenience function to add a text field to this container/window.
2169 * @param x column relative to parent
2170 * @param y row relative to parent
2171 * @param width visible text width
2172 * @param fixed if true, the text cannot exceed the display width
2173 * @return the new text field
2175 public final TField
addField(final int x
, final int y
,
2176 final int width
, final boolean fixed
) {
2178 return new TField(this, x
, y
, width
, fixed
);
2182 * Convenience function to add a text field to this container/window.
2184 * @param x column relative to parent
2185 * @param y row relative to parent
2186 * @param width visible text width
2187 * @param fixed if true, the text cannot exceed the display width
2188 * @param text initial text, default is empty string
2189 * @return the new text field
2191 public final TField
addField(final int x
, final int y
,
2192 final int width
, final boolean fixed
, final String text
) {
2194 return new TField(this, x
, y
, width
, fixed
, text
);
2198 * Convenience function to add a text field to this container/window.
2200 * @param x column relative to parent
2201 * @param y row relative to parent
2202 * @param width visible text width
2203 * @param fixed if true, the text cannot exceed the display width
2204 * @param text initial text, default is empty string
2205 * @param enterAction function to call when enter key is pressed
2206 * @param updateAction function to call when the text is updated
2207 * @return the new text field
2209 public final TField
addField(final int x
, final int y
,
2210 final int width
, final boolean fixed
, final String text
,
2211 final TAction enterAction
, final TAction updateAction
) {
2213 return new TField(this, x
, y
, width
, fixed
, text
, enterAction
,
2218 * Convenience function to add a scrollable text box to this
2221 * @param text text on the screen
2222 * @param x column relative to parent
2223 * @param y row relative to parent
2224 * @param width width of text area
2225 * @param height height of text area
2226 * @param colorKey ColorTheme key color to use for foreground text
2227 * @return the new text box
2229 public final TText
addText(final String text
, final int x
,
2230 final int y
, final int width
, final int height
, final String colorKey
) {
2232 return new TText(this, text
, x
, y
, width
, height
, colorKey
);
2236 * Convenience function to add a scrollable text box to this
2239 * @param text text on the screen
2240 * @param x column relative to parent
2241 * @param y row relative to parent
2242 * @param width width of text area
2243 * @param height height of text area
2244 * @return the new text box
2246 public final TText
addText(final String text
, final int x
, final int y
,
2247 final int width
, final int height
) {
2249 return new TText(this, text
, x
, y
, width
, height
, "ttext");
2253 * Convenience function to add an editable text area box to this
2256 * @param text text on the screen
2257 * @param x column relative to parent
2258 * @param y row relative to parent
2259 * @param width width of text area
2260 * @param height height of text area
2261 * @return the new text box
2263 public final TEditorWidget
addEditor(final String text
, final int x
,
2264 final int y
, final int width
, final int height
) {
2266 return new TEditorWidget(this, text
, x
, y
, width
, height
);
2270 * Convenience function to spawn a message box.
2272 * @param title window title, will be centered along the top border
2273 * @param caption message to display. Use embedded newlines to get a
2275 * @return the new message box
2277 public final TMessageBox
messageBox(final String title
,
2278 final String caption
) {
2280 return getApplication().messageBox(title
, caption
, TMessageBox
.Type
.OK
);
2284 * Convenience function to spawn a message box.
2286 * @param title window title, will be centered along the top border
2287 * @param caption message to display. Use embedded newlines to get a
2289 * @param type one of the TMessageBox.Type constants. Default is
2291 * @return the new message box
2293 public final TMessageBox
messageBox(final String title
,
2294 final String caption
, final TMessageBox
.Type type
) {
2296 return getApplication().messageBox(title
, caption
, type
);
2300 * Convenience function to spawn an input box.
2302 * @param title window title, will be centered along the top border
2303 * @param caption message to display. Use embedded newlines to get a
2305 * @return the new input box
2307 public final TInputBox
inputBox(final String title
, final String caption
) {
2309 return getApplication().inputBox(title
, caption
);
2313 * Convenience function to spawn an input box.
2315 * @param title window title, will be centered along the top border
2316 * @param caption message to display. Use embedded newlines to get a
2318 * @param text initial text to seed the field with
2319 * @return the new input box
2321 public final TInputBox
inputBox(final String title
, final String caption
,
2322 final String text
) {
2324 return getApplication().inputBox(title
, caption
, text
);
2328 * Convenience function to spawn an input box.
2330 * @param title window title, will be centered along the top border
2331 * @param caption message to display. Use embedded newlines to get a
2333 * @param text initial text to seed the field with
2334 * @param type one of the Type constants. Default is Type.OK.
2335 * @return the new input box
2337 public final TInputBox
inputBox(final String title
, final String caption
,
2338 final String text
, final TInputBox
.Type type
) {
2340 return getApplication().inputBox(title
, caption
, text
, type
);
2344 * Convenience function to add a password text field to this
2347 * @param x column relative to parent
2348 * @param y row relative to parent
2349 * @param width visible text width
2350 * @param fixed if true, the text cannot exceed the display width
2351 * @return the new text field
2353 public final TPasswordField
addPasswordField(final int x
, final int y
,
2354 final int width
, final boolean fixed
) {
2356 return new TPasswordField(this, x
, y
, width
, fixed
);
2360 * Convenience function to add a password text field to this
2363 * @param x column relative to parent
2364 * @param y row relative to parent
2365 * @param width visible text width
2366 * @param fixed if true, the text cannot exceed the display width
2367 * @param text initial text, default is empty string
2368 * @return the new text field
2370 public final TPasswordField
addPasswordField(final int x
, final int y
,
2371 final int width
, final boolean fixed
, final String text
) {
2373 return new TPasswordField(this, x
, y
, width
, fixed
, text
);
2377 * Convenience function to add a password text field to this
2380 * @param x column relative to parent
2381 * @param y row relative to parent
2382 * @param width visible text width
2383 * @param fixed if true, the text cannot exceed the display width
2384 * @param text initial text, default is empty string
2385 * @param enterAction function to call when enter key is pressed
2386 * @param updateAction function to call when the text is updated
2387 * @return the new text field
2389 public final TPasswordField
addPasswordField(final int x
, final int y
,
2390 final int width
, final boolean fixed
, final String text
,
2391 final TAction enterAction
, final TAction updateAction
) {
2393 return new TPasswordField(this, x
, y
, width
, fixed
, text
, enterAction
,
2398 * Convenience function to add a scrollable tree view to this
2401 * @param x column relative to parent
2402 * @param y row relative to parent
2403 * @param width width of tree view
2404 * @param height height of tree view
2405 * @return the new tree view
2407 public final TTreeViewWidget
addTreeViewWidget(final int x
, final int y
,
2408 final int width
, final int height
) {
2410 return new TTreeViewWidget(this, x
, y
, width
, height
);
2414 * Convenience function to add a scrollable tree view to this
2417 * @param x column relative to parent
2418 * @param y row relative to parent
2419 * @param width width of tree view
2420 * @param height height of tree view
2421 * @param action action to perform when an item is selected
2422 * @return the new tree view
2424 public final TTreeViewWidget
addTreeViewWidget(final int x
, final int y
,
2425 final int width
, final int height
, final TAction action
) {
2427 return new TTreeViewWidget(this, x
, y
, width
, height
, action
);
2431 * Convenience function to spawn a file open box.
2433 * @param path path of selected file
2434 * @return the result of the new file open box
2435 * @throws IOException if a java.io operation throws
2437 public final String
fileOpenBox(final String path
) throws IOException
{
2438 return getApplication().fileOpenBox(path
);
2442 * Convenience function to spawn a file save box.
2444 * @param path path of selected file
2445 * @return the result of the new file open box
2446 * @throws IOException if a java.io operation throws
2448 public final String
fileSaveBox(final String path
) throws IOException
{
2449 return getApplication().fileOpenBox(path
, TFileOpenBox
.Type
.SAVE
);
2453 * Convenience function to spawn a file open box.
2455 * @param path path of selected file
2456 * @param type one of the Type constants
2457 * @return the result of the new file open box
2458 * @throws IOException if a java.io operation throws
2460 public final String
fileOpenBox(final String path
,
2461 final TFileOpenBox
.Type type
) throws IOException
{
2463 return getApplication().fileOpenBox(path
, type
);
2467 * Convenience function to spawn a file open box.
2469 * @param path path of selected file
2470 * @param type one of the Type constants
2471 * @param filter a string that files must match to be displayed
2472 * @return the result of the new file open box
2473 * @throws IOException of a java.io operation throws
2475 public final String
fileOpenBox(final String path
,
2476 final TFileOpenBox
.Type type
, final String filter
) throws IOException
{
2478 ArrayList
<String
> filters
= new ArrayList
<String
>();
2479 filters
.add(filter
);
2481 return getApplication().fileOpenBox(path
, type
, filters
);
2485 * Convenience function to spawn a file open box.
2487 * @param path path of selected file
2488 * @param type one of the Type constants
2489 * @param filters a list of strings that files must match to be displayed
2490 * @return the result of the new file open box
2491 * @throws IOException of a java.io operation throws
2493 public final String
fileOpenBox(final String path
,
2494 final TFileOpenBox
.Type type
,
2495 final List
<String
> filters
) throws IOException
{
2497 return getApplication().fileOpenBox(path
, type
, filters
);
2501 * Convenience function to add a directory list to this container/window.
2503 * @param path directory path, must be a directory
2504 * @param x column relative to parent
2505 * @param y row relative to parent
2506 * @param width width of text area
2507 * @param height height of text area
2508 * @return the new directory list
2510 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2511 final int y
, final int width
, final int height
) {
2513 return new TDirectoryList(this, path
, x
, y
, width
, height
, null);
2517 * Convenience function to add a directory list to this container/window.
2519 * @param path directory path, must be a directory
2520 * @param x column relative to parent
2521 * @param y row relative to parent
2522 * @param width width of text area
2523 * @param height height of text area
2524 * @param action action to perform when an item is selected (enter or
2526 * @return the new directory list
2528 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2529 final int y
, final int width
, final int height
, final TAction action
) {
2531 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
);
2535 * Convenience function to add a directory list to this container/window.
2537 * @param path directory path, must be a directory
2538 * @param x column relative to parent
2539 * @param y row relative to parent
2540 * @param width width of text area
2541 * @param height height of text area
2542 * @param action action to perform when an item is selected (enter or
2544 * @param singleClickAction action to perform when an item is selected
2546 * @return the new directory list
2548 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2549 final int y
, final int width
, final int height
, final TAction action
,
2550 final TAction singleClickAction
) {
2552 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
,
2557 * Convenience function to add a directory list to this container/window.
2559 * @param path directory path, must be a directory
2560 * @param x column relative to parent
2561 * @param y row relative to parent
2562 * @param width width of text area
2563 * @param height height of text area
2564 * @param action action to perform when an item is selected (enter or
2566 * @param singleClickAction action to perform when an item is selected
2568 * @param filters a list of strings that files must match to be displayed
2569 * @return the new directory list
2571 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2572 final int y
, final int width
, final int height
, final TAction action
,
2573 final TAction singleClickAction
, final List
<String
> filters
) {
2575 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
,
2576 singleClickAction
, filters
);
2580 * Convenience function to add a list to this container/window.
2582 * @param strings list of strings to show
2583 * @param x column relative to parent
2584 * @param y row relative to parent
2585 * @param width width of text area
2586 * @param height height of text area
2587 * @return the new directory list
2589 public final TList
addList(final List
<String
> strings
, final int x
,
2590 final int y
, final int width
, final int height
) {
2592 return new TList(this, strings
, x
, y
, width
, height
, null);
2596 * Convenience function to add a list to this container/window.
2598 * @param strings list of strings to show
2599 * @param x column relative to parent
2600 * @param y row relative to parent
2601 * @param width width of text area
2602 * @param height height of text area
2603 * @param enterAction action to perform when an item is selected
2604 * @return the new directory list
2606 public final TList
addList(final List
<String
> strings
, final int x
,
2607 final int y
, final int width
, final int height
,
2608 final TAction enterAction
) {
2610 return new TList(this, strings
, x
, y
, width
, height
, enterAction
);
2614 * Convenience function to add a list to this container/window.
2616 * @param strings list of strings to show
2617 * @param x column relative to parent
2618 * @param y row relative to parent
2619 * @param width width of text area
2620 * @param height height of text area
2621 * @param enterAction action to perform when an item is selected
2622 * @param moveAction action to perform when the user navigates to a new
2623 * item with arrow/page keys
2624 * @return the new directory list
2626 public final TList
addList(final List
<String
> strings
, final int x
,
2627 final int y
, final int width
, final int height
,
2628 final TAction enterAction
, final TAction moveAction
) {
2630 return new TList(this, strings
, x
, y
, width
, height
, enterAction
,
2635 * Convenience function to add a list to this container/window.
2637 * @param strings list of strings to show. This is allowed to be null
2638 * and set later with setList() or by subclasses.
2639 * @param x column relative to parent
2640 * @param y row relative to parent
2641 * @param width width of text area
2642 * @param height height of text area
2643 * @param enterAction action to perform when an item is selected
2644 * @param moveAction action to perform when the user navigates to a new
2645 * item with arrow/page keys
2646 * @param singleClickAction action to perform when the user clicks on an
2649 public TList
addList(final List
<String
> strings
, final int x
,
2650 final int y
, final int width
, final int height
,
2651 final TAction enterAction
, final TAction moveAction
,
2652 final TAction singleClickAction
) {
2654 return new TList(this, strings
, x
, y
, width
, height
, enterAction
,
2655 moveAction
, singleClickAction
);
2660 * Convenience function to add an image to this container/window.
2662 * @param x column relative to parent
2663 * @param y row relative to parent
2664 * @param width number of text cells for width of the image
2665 * @param height number of text cells for height of the image
2666 * @param image the image to display
2667 * @param left left column of the image. 0 is the left-most column.
2668 * @param top top row of the image. 0 is the top-most row.
2670 public final TImage
addImage(final int x
, final int y
,
2671 final int width
, final int height
,
2672 final BufferedImage image
, final int left
, final int top
) {
2674 return new TImage(this, x
, y
, width
, height
, image
, left
, top
);
2678 * Convenience function to add an image to this container/window.
2680 * @param x column relative to parent
2681 * @param y row relative to parent
2682 * @param width number of text cells for width of the image
2683 * @param height number of text cells for height of the image
2684 * @param image the image to display
2685 * @param left left column of the image. 0 is the left-most column.
2686 * @param top top row of the image. 0 is the top-most row.
2687 * @param clickAction function to call when mouse is pressed
2689 public final TImage
addImage(final int x
, final int y
,
2690 final int width
, final int height
,
2691 final BufferedImage image
, final int left
, final int top
,
2692 final TAction clickAction
) {
2694 return new TImage(this, x
, y
, width
, height
, image
, left
, top
,
2699 * Convenience function to add an editable 2D data table to this
2702 * @param x column relative to parent
2703 * @param y row relative to parent
2704 * @param width width of widget
2705 * @param height height of widget
2707 public TTableWidget
addTable(final int x
, final int y
, final int width
,
2710 return new TTableWidget(this, x
, y
, width
, height
);
2714 * Convenience function to add an editable 2D data table to this
2717 * @param x column relative to parent
2718 * @param y row relative to parent
2719 * @param width width of widget
2720 * @param height height of widget
2721 * @param gridColumns number of columns in grid
2722 * @param gridRows number of rows in grid
2724 public TTableWidget
addTable(final int x
, final int y
, final int width
,
2725 final int height
, final int gridColumns
, final int gridRows
) {
2727 return new TTableWidget(this, x
, y
, width
, height
, gridColumns
,
2732 * Convenience function to add a panel to this container/window.
2734 * @param x column relative to parent
2735 * @param y row relative to parent
2736 * @param width width of text area
2737 * @param height height of text area
2738 * @return the new panel
2740 public final TPanel
addPanel(final int x
, final int y
, final int width
,
2743 return new TPanel(this, x
, y
, width
, height
);
2747 * Convenience function to add a split pane to this container/window.
2749 * @param x column relative to parent
2750 * @param y row relative to parent
2751 * @param width width of text area
2752 * @param height height of text area
2753 * @param vertical if true, split vertically
2754 * @return the new split pane
2756 public final TSplitPane
addSplitPane(final int x
, final int y
,
2757 final int width
, final int height
, final boolean vertical
) {
2759 return new TSplitPane(this, x
, y
, width
, height
, vertical
);