2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2017 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
.io
.IOException
;
32 import java
.util
.List
;
33 import java
.util
.ArrayList
;
35 import jexer
.backend
.Screen
;
36 import jexer
.bits
.ColorTheme
;
37 import jexer
.event
.TCommandEvent
;
38 import jexer
.event
.TInputEvent
;
39 import jexer
.event
.TKeypressEvent
;
40 import jexer
.event
.TMenuEvent
;
41 import jexer
.event
.TMouseEvent
;
42 import jexer
.event
.TResizeEvent
;
43 import jexer
.menu
.TMenu
;
44 import jexer
.ttree
.TTreeItem
;
45 import jexer
.ttree
.TTreeView
;
46 import jexer
.ttree
.TTreeViewWidget
;
47 import static jexer
.TKeypress
.*;
50 * TWidget is the base class of all objects that can be drawn on screen or
51 * handle user input events.
53 public abstract class TWidget
implements Comparable
<TWidget
> {
55 // ------------------------------------------------------------------------
56 // Variables --------------------------------------------------------------
57 // ------------------------------------------------------------------------
60 * Every widget has a parent widget that it may be "contained" in. For
61 * example, a TWindow might contain several TFields, or a TComboBox may
62 * contain a TList that itself contains a TVScroller.
64 private TWidget parent
= null;
67 * Child widgets that this widget contains.
69 private List
<TWidget
> children
;
72 * The currently active child widget that will receive keypress events.
74 private TWidget activeChild
= null;
77 * If true, this widget will receive events.
79 private boolean active
= false;
82 * The window that this widget draws to.
84 private TWindow window
= null;
87 * Absolute X position of the top-left corner.
92 * Absolute Y position of the top-left corner.
99 private int width
= 0;
104 private int height
= 0;
107 * My tab order inside a window or containing widget.
109 private int tabOrder
= 0;
112 * If true, this widget can be tabbed to or receive events.
114 private boolean enabled
= true;
117 * If true, this widget will be rendered.
119 private boolean visible
= true;
122 * If true, this widget has a cursor.
124 private boolean cursorVisible
= false;
127 * Cursor column position in relative coordinates.
129 private int cursorX
= 0;
132 * Cursor row position in relative coordinates.
134 private int cursorY
= 0;
136 // ------------------------------------------------------------------------
137 // Constructors -----------------------------------------------------------
138 // ------------------------------------------------------------------------
141 * Default constructor for subclasses.
143 protected TWidget() {
144 children
= new ArrayList
<TWidget
>();
148 * Protected constructor.
150 * @param parent parent widget
152 protected TWidget(final TWidget parent
) {
157 * Protected constructor.
159 * @param parent parent widget
160 * @param x column relative to parent
161 * @param y row relative to parent
162 * @param width width of widget
163 * @param height height of widget
165 protected TWidget(final TWidget parent
, final int x
, final int y
,
166 final int width
, final int height
) {
168 this(parent
, true, x
, y
, width
, height
);
172 * Protected constructor used by subclasses that are disabled by default.
174 * @param parent parent widget
175 * @param enabled if true assume enabled
177 protected TWidget(final TWidget parent
, final boolean enabled
) {
178 this.enabled
= enabled
;
179 this.parent
= parent
;
180 this.window
= parent
.window
;
181 children
= new ArrayList
<TWidget
>();
183 // Do not add TStatusBars, they are drawn by TApplication
184 if (this instanceof TStatusBar
) {
186 parent
.addChild(this);
191 * Protected constructor used by subclasses that are disabled by default.
193 * @param parent parent widget
194 * @param enabled if true assume enabled
195 * @param x column relative to parent
196 * @param y row relative to parent
197 * @param width width of widget
198 * @param height height of widget
200 protected TWidget(final TWidget parent
, final boolean enabled
,
201 final int x
, final int y
, final int width
, final int height
) {
203 this.enabled
= enabled
;
204 this.parent
= parent
;
205 this.window
= parent
.window
;
206 children
= new ArrayList
<TWidget
>();
208 // Do not add TStatusBars, they are drawn by TApplication
209 if (this instanceof TStatusBar
) {
211 parent
.addChild(this);
217 this.height
= height
;
221 * Backdoor access for TWindow's constructor. ONLY TWindow USES THIS.
223 * @param window the top-level window
224 * @param x column relative to parent
225 * @param y row relative to parent
226 * @param width width of window
227 * @param height height of window
229 protected final void setupForTWindow(final TWindow window
,
230 final int x
, final int y
, final int width
, final int height
) {
232 this.parent
= window
;
233 this.window
= window
;
237 this.height
= height
;
240 // ------------------------------------------------------------------------
241 // Event handlers ---------------------------------------------------------
242 // ------------------------------------------------------------------------
245 * Check if a mouse press/release event coordinate is contained in this
248 * @param mouse a mouse-based event
249 * @return whether or not a mouse click would be sent to this widget
251 public final boolean mouseWouldHit(final TMouseEvent mouse
) {
257 if ((this instanceof TTreeItem
)
258 && ((y
< 0) || (y
> parent
.getHeight() - 1))
263 if ((mouse
.getAbsoluteX() >= getAbsoluteX())
264 && (mouse
.getAbsoluteX() < getAbsoluteX() + width
)
265 && (mouse
.getAbsoluteY() >= getAbsoluteY())
266 && (mouse
.getAbsoluteY() < getAbsoluteY() + height
)
274 * Method that subclasses can override to handle keystrokes.
276 * @param keypress keystroke event
278 public void onKeypress(final TKeypressEvent keypress
) {
280 if ((children
.size() == 0)
281 || (this instanceof TTreeView
)
282 || (this instanceof TText
)
286 // tab / shift-tab - switch to next/previous widget
287 // left-arrow or up-arrow: same as shift-tab
288 if ((keypress
.equals(kbTab
))
289 || (keypress
.equals(kbDown
))
291 parent
.switchWidget(true);
293 } else if ((keypress
.equals(kbShiftTab
))
294 || (keypress
.equals(kbBackTab
))
295 || (keypress
.equals(kbUp
))
297 parent
.switchWidget(false);
302 if ((children
.size() == 0)
303 && !(this instanceof TTreeView
)
307 // right-arrow or down-arrow: same as tab
308 if (keypress
.equals(kbRight
)) {
309 parent
.switchWidget(true);
311 } else if (keypress
.equals(kbLeft
)) {
312 parent
.switchWidget(false);
317 // If I have any buttons on me AND this is an Alt-key that matches
318 // its mnemonic, send it an Enter keystroke
319 for (TWidget widget
: children
) {
320 if (widget
instanceof TButton
) {
321 TButton button
= (TButton
) widget
;
322 if (button
.isEnabled()
323 && !keypress
.getKey().isFnKey()
324 && keypress
.getKey().isAlt()
325 && !keypress
.getKey().isCtrl()
326 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
327 == Character
.toLowerCase(keypress
.getKey().getChar()))
330 widget
.onKeypress(new TKeypressEvent(kbEnter
));
336 // Dispatch the keypress to an active widget
337 for (TWidget widget
: children
) {
339 widget
.onKeypress(keypress
);
346 * Method that subclasses can override to handle mouse button presses.
348 * @param mouse mouse button event
350 public void onMouseDown(final TMouseEvent mouse
) {
351 // Default: do nothing, pass to children instead
352 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
353 TWidget widget
= children
.get(i
);
354 if (widget
.mouseWouldHit(mouse
)) {
355 // Dispatch to this child, also activate it
358 // Set x and y relative to the child's coordinates
359 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
360 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
361 widget
.onMouseDown(mouse
);
368 * Method that subclasses can override to handle mouse button releases.
370 * @param mouse mouse button event
372 public void onMouseUp(final TMouseEvent mouse
) {
373 // Default: do nothing, pass to children instead
374 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
375 TWidget widget
= children
.get(i
);
376 if (widget
.mouseWouldHit(mouse
)) {
377 // Dispatch to this child, also activate it
380 // Set x and y relative to the child's coordinates
381 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
382 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
383 widget
.onMouseUp(mouse
);
390 * Method that subclasses can override to handle mouse movements.
392 * @param mouse mouse motion event
394 public void onMouseMotion(final TMouseEvent mouse
) {
395 // Default: do nothing, pass it on to ALL of my children. This way
396 // the children can see the mouse "leaving" their area.
397 for (TWidget widget
: children
) {
398 // Set x and y relative to the child's coordinates
399 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
400 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
401 widget
.onMouseMotion(mouse
);
406 * Method that subclasses can override to handle mouse button
409 * @param mouse mouse button event
411 public void onMouseDoubleClick(final TMouseEvent mouse
) {
412 // Default: do nothing, pass to children instead
413 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
414 TWidget widget
= children
.get(i
);
415 if (widget
.mouseWouldHit(mouse
)) {
416 // Dispatch to this child, also activate it
419 // Set x and y relative to the child's coordinates
420 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
421 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
422 widget
.onMouseDoubleClick(mouse
);
429 * Method that subclasses can override to handle window/screen resize
432 * @param resize resize event
434 public void onResize(final TResizeEvent resize
) {
435 // Default: change my width/height.
436 if (resize
.getType() == TResizeEvent
.Type
.WIDGET
) {
437 width
= resize
.getWidth();
438 height
= resize
.getHeight();
440 // Let children see the screen resize
441 for (TWidget widget
: children
) {
442 widget
.onResize(resize
);
448 * Method that subclasses can override to handle posted command events.
450 * @param command command event
452 public void onCommand(final TCommandEvent command
) {
453 // Default: do nothing, pass to children instead
454 for (TWidget widget
: children
) {
455 widget
.onCommand(command
);
460 * Method that subclasses can override to handle menu or posted menu
463 * @param menu menu event
465 public void onMenu(final TMenuEvent menu
) {
466 // Default: do nothing, pass to children instead
467 for (TWidget widget
: children
) {
473 * Method that subclasses can override to do processing when the UI is
474 * idle. Note that repainting is NOT assumed. To get a refresh after
475 * onIdle, call doRepaint().
477 public void onIdle() {
478 // Default: do nothing, pass to children instead
479 for (TWidget widget
: children
) {
485 * Consume event. Subclasses that want to intercept all events in one go
486 * can override this method.
488 * @param event keyboard, mouse, resize, command, or menu event
490 public void handleEvent(final TInputEvent event
) {
492 System.err.printf("TWidget (%s) event: %s\n", this.getClass().getName(),
498 // System.err.println(" -- discard --");
502 if (event
instanceof TKeypressEvent
) {
503 onKeypress((TKeypressEvent
) event
);
504 } else if (event
instanceof TMouseEvent
) {
506 TMouseEvent mouse
= (TMouseEvent
) event
;
508 switch (mouse
.getType()) {
519 onMouseMotion(mouse
);
522 case MOUSE_DOUBLE_CLICK
:
523 onMouseDoubleClick(mouse
);
527 throw new IllegalArgumentException("Invalid mouse event type: "
530 } else if (event
instanceof TResizeEvent
) {
531 onResize((TResizeEvent
) event
);
532 } else if (event
instanceof TCommandEvent
) {
533 onCommand((TCommandEvent
) event
);
534 } else if (event
instanceof TMenuEvent
) {
535 onMenu((TMenuEvent
) event
);
542 // ------------------------------------------------------------------------
543 // TWidget ----------------------------------------------------------------
544 // ------------------------------------------------------------------------
549 * @return parent widget
551 public final TWidget
getParent() {
556 * Get the list of child widgets that this widget contains.
558 * @return the list of child widgets
560 public List
<TWidget
> getChildren() {
567 * @return if true, this widget will receive events
569 public final boolean isActive() {
576 * @param active if true, this widget will receive events
578 public final void setActive(final boolean active
) {
579 this.active
= active
;
583 * Get the window this widget is on.
587 public final TWindow
getWindow() {
594 * @return absolute X position of the top-left corner
596 public final int getX() {
603 * @param x absolute X position of the top-left corner
605 public final void setX(final int x
) {
612 * @return absolute Y position of the top-left corner
614 public final int getY() {
621 * @param y absolute Y position of the top-left corner
623 public final void setY(final int y
) {
630 * @return widget width
632 public final int getWidth() {
639 * @param width new widget width
641 public final void setWidth(final int width
) {
648 * @return widget height
650 public final int getHeight() {
657 * @param height new widget height
659 public final void setHeight(final int height
) {
660 this.height
= height
;
664 * Change the dimensions.
666 * @param x absolute X position of the top-left corner
667 * @param y absolute Y position of the top-left corner
668 * @param width new widget width
669 * @param height new widget height
671 public final void setDimensions(final int x
, final int y
, final int width
,
683 * @return if true, this widget can be tabbed to or receive events
685 public final boolean isEnabled() {
692 * @param enabled if true, this widget can be tabbed to or receive events
694 public final void setEnabled(final boolean enabled
) {
695 this.enabled
= enabled
;
698 // See if there are any active siblings to switch to
699 boolean foundSibling
= false;
700 if (parent
!= null) {
701 for (TWidget w
: parent
.children
) {
703 && !(this instanceof THScroller
)
704 && !(this instanceof TVScroller
)
712 parent
.activeChild
= null;
721 * @param visible if true, this widget will be drawn
723 public final void setVisible(final boolean visible
) {
724 this.visible
= visible
;
728 * See if this widget is visible.
730 * @return if true, this widget will be drawn
732 public final boolean isVisible() {
737 * Set visible cursor flag.
739 * @param cursorVisible if true, this widget has a cursor
741 public final void setCursorVisible(final boolean cursorVisible
) {
742 this.cursorVisible
= cursorVisible
;
746 * See if this widget has a visible cursor.
748 * @return if true, this widget has a visible cursor
750 public final boolean isCursorVisible() {
751 // If cursor is out of my bounds, it is not visible.
752 if ((cursorX
>= width
)
754 || (cursorY
>= height
)
760 // If cursor is out of my window's bounds, it is not visible.
761 if ((getCursorAbsoluteX() >= window
.getAbsoluteX()
762 + window
.getWidth() - 1)
763 || (getCursorAbsoluteX() < 0)
764 || (getCursorAbsoluteY() >= window
.getAbsoluteY()
765 + window
.getHeight() - 1)
766 || (getCursorAbsoluteY() < 0)
770 return cursorVisible
;
774 * Get cursor X value.
776 * @return cursor column position in relative coordinates
778 public final int getCursorX() {
783 * Set cursor X value.
785 * @param cursorX column position in relative coordinates
787 public final void setCursorX(final int cursorX
) {
788 this.cursorX
= cursorX
;
792 * Get cursor Y value.
794 * @return cursor row position in relative coordinates
796 public final int getCursorY() {
801 * Set cursor Y value.
803 * @param cursorY row position in relative coordinates
805 public final void setCursorY(final int cursorY
) {
806 this.cursorY
= cursorY
;
810 * Get this TWidget's parent TApplication.
812 * @return the parent TApplication
814 public TApplication
getApplication() {
815 return window
.getApplication();
823 public Screen
getScreen() {
824 return window
.getScreen();
828 * Comparison operator. For various subclasses it sorts on:
830 * <li>tabOrder for TWidgets</li>
831 * <li>z for TWindows</li>
832 * <li>text for TTreeItems</li>
835 * @param that another TWidget, TWindow, or TTreeItem instance
836 * @return difference between this.tabOrder and that.tabOrder, or
837 * difference between this.z and that.z, or String.compareTo(text)
839 public final int compareTo(final TWidget that
) {
840 if ((this instanceof TWindow
)
841 && (that
instanceof TWindow
)
843 return (((TWindow
) this).getZ() - ((TWindow
) that
).getZ());
845 if ((this instanceof TTreeItem
)
846 && (that
instanceof TTreeItem
)
848 return (((TTreeItem
) this).getText().compareTo(
849 ((TTreeItem
) that
).getText()));
851 return (this.tabOrder
- that
.tabOrder
);
855 * See if this widget should render with the active color.
857 * @return true if this widget is active and all of its parents are
860 public final boolean isAbsoluteActive() {
861 if (parent
== this) {
864 return (active
&& parent
.isAbsoluteActive());
868 * Returns the cursor X position.
870 * @return absolute screen column number for the cursor's X position
872 public final int getCursorAbsoluteX() {
873 return getAbsoluteX() + cursorX
;
877 * Returns the cursor Y position.
879 * @return absolute screen row number for the cursor's Y position
881 public final int getCursorAbsoluteY() {
882 return getAbsoluteY() + cursorY
;
886 * Compute my absolute X position as the sum of my X plus all my parent's
889 * @return absolute screen column number for my X position
891 public final int getAbsoluteX() {
892 assert (parent
!= null);
893 if (parent
== this) {
896 if ((parent
instanceof TWindow
)
897 && !(parent
instanceof TMenu
)
898 && !(parent
instanceof TDesktop
)
900 // Widgets on a TWindow have (0,0) as their top-left, but this is
901 // actually the TWindow's (1,1).
902 return parent
.getAbsoluteX() + x
+ 1;
904 return parent
.getAbsoluteX() + x
;
908 * Compute my absolute Y position as the sum of my Y plus all my parent's
911 * @return absolute screen row number for my Y position
913 public final int getAbsoluteY() {
914 assert (parent
!= null);
915 if (parent
== this) {
918 if ((parent
instanceof TWindow
)
919 && !(parent
instanceof TMenu
)
920 && !(parent
instanceof TDesktop
)
922 // Widgets on a TWindow have (0,0) as their top-left, but this is
923 // actually the TWindow's (1,1).
924 return parent
.getAbsoluteY() + y
+ 1;
926 return parent
.getAbsoluteY() + y
;
930 * Get the global color theme.
932 * @return the ColorTheme
934 public final ColorTheme
getTheme() {
935 return window
.getApplication().getTheme();
939 * Draw my specific widget. When called, the screen rectangle I draw
940 * into is already setup (offset and clipping).
943 // Default widget draws nothing.
947 * Called by parent to render to TWindow.
949 public final void drawChildren() {
950 // Set my clipping rectangle
951 assert (window
!= null);
952 assert (getScreen() != null);
953 Screen screen
= getScreen();
955 // Special case: TStatusBar is drawn by TApplication, not anything
957 if (this instanceof TStatusBar
) {
961 screen
.setClipRight(width
);
962 screen
.setClipBottom(height
);
964 int absoluteRightEdge
= window
.getAbsoluteX() + window
.getWidth();
965 int absoluteBottomEdge
= window
.getAbsoluteY() + window
.getHeight();
966 if (!(this instanceof TWindow
) && !(this instanceof TVScroller
)) {
967 absoluteRightEdge
-= 1;
969 if (!(this instanceof TWindow
) && !(this instanceof THScroller
)) {
970 absoluteBottomEdge
-= 1;
972 int myRightEdge
= getAbsoluteX() + width
;
973 int myBottomEdge
= getAbsoluteY() + height
;
974 if (getAbsoluteX() > absoluteRightEdge
) {
976 screen
.setClipRight(0);
977 } else if (myRightEdge
> absoluteRightEdge
) {
978 screen
.setClipRight(screen
.getClipRight()
979 - (myRightEdge
- absoluteRightEdge
));
981 if (getAbsoluteY() > absoluteBottomEdge
) {
983 screen
.setClipBottom(0);
984 } else if (myBottomEdge
> absoluteBottomEdge
) {
985 screen
.setClipBottom(screen
.getClipBottom()
986 - (myBottomEdge
- absoluteBottomEdge
));
990 screen
.setOffsetX(getAbsoluteX());
991 screen
.setOffsetY(getAbsoluteY());
996 // Continue down the chain
997 for (TWidget widget
: children
) {
998 if (widget
.isVisible()) {
999 widget
.drawChildren();
1005 * Repaint the screen on the next update.
1007 public final void doRepaint() {
1008 window
.getApplication().doRepaint();
1012 * Add a child widget to my list of children. We set its tabOrder to 0
1013 * and increment the tabOrder of all other children.
1015 * @param child TWidget to add
1017 private void addChild(final TWidget child
) {
1018 children
.add(child
);
1021 && !(child
instanceof THScroller
)
1022 && !(child
instanceof TVScroller
)
1024 for (TWidget widget
: children
) {
1025 widget
.active
= false;
1027 child
.active
= true;
1028 activeChild
= child
;
1030 for (int i
= 0; i
< children
.size(); i
++) {
1031 children
.get(i
).tabOrder
= i
;
1036 * Switch the active child.
1038 * @param child TWidget to activate
1040 public final void activate(final TWidget child
) {
1041 assert (child
.enabled
);
1042 if ((child
instanceof THScroller
)
1043 || (child
instanceof TVScroller
)
1048 if (child
!= activeChild
) {
1049 if (activeChild
!= null) {
1050 activeChild
.active
= false;
1052 child
.active
= true;
1053 activeChild
= child
;
1058 * Switch the active child.
1060 * @param tabOrder tabOrder of the child to activate. If that child
1061 * isn't enabled, then the next enabled child will be activated.
1063 public final void activate(final int tabOrder
) {
1064 if (activeChild
== null) {
1067 TWidget child
= null;
1068 for (TWidget widget
: children
) {
1069 if ((widget
.enabled
)
1070 && !(widget
instanceof THScroller
)
1071 && !(widget
instanceof TVScroller
)
1072 && (widget
.tabOrder
>= tabOrder
)
1078 if ((child
!= null) && (child
!= activeChild
)) {
1079 activeChild
.active
= false;
1080 assert (child
.enabled
);
1081 child
.active
= true;
1082 activeChild
= child
;
1087 * Switch the active widget with the next in the tab order.
1089 * @param forward if true, then switch to the next enabled widget in the
1090 * list, otherwise switch to the previous enabled widget in the list
1092 public final void switchWidget(final boolean forward
) {
1094 // Only switch if there are multiple enabled widgets
1095 if ((children
.size() < 2) || (activeChild
== null)) {
1099 int tabOrder
= activeChild
.tabOrder
;
1108 // If at the end, pass the switch to my parent.
1109 if ((!forward
) && (parent
!= this)) {
1110 parent
.switchWidget(forward
);
1114 tabOrder
= children
.size() - 1;
1115 } else if (tabOrder
== children
.size()) {
1116 // If at the end, pass the switch to my parent.
1117 if ((forward
) && (parent
!= this)) {
1118 parent
.switchWidget(forward
);
1124 if (activeChild
.tabOrder
== tabOrder
) {
1125 // We wrapped around
1128 } while ((!children
.get(tabOrder
).enabled
)
1129 && !(children
.get(tabOrder
) instanceof THScroller
)
1130 && !(children
.get(tabOrder
) instanceof TVScroller
));
1132 assert (children
.get(tabOrder
).enabled
);
1134 activeChild
.active
= false;
1135 children
.get(tabOrder
).active
= true;
1136 activeChild
= children
.get(tabOrder
);
1140 * Returns my active widget.
1142 * @return widget that is active, or this if no children
1144 public TWidget
getActiveChild() {
1145 if ((this instanceof THScroller
)
1146 || (this instanceof TVScroller
)
1151 for (TWidget widget
: children
) {
1152 if (widget
.active
) {
1153 return widget
.getActiveChild();
1156 // No active children, return me
1160 // ------------------------------------------------------------------------
1161 // Other TWidget constructors ---------------------------------------------
1162 // ------------------------------------------------------------------------
1165 * Convenience function to add a label to this container/window.
1168 * @param x column relative to parent
1169 * @param y row relative to parent
1170 * @return the new label
1172 public final TLabel
addLabel(final String text
, final int x
, final int y
) {
1173 return addLabel(text
, x
, y
, "tlabel");
1177 * Convenience function to add a label to this container/window.
1180 * @param x column relative to parent
1181 * @param y row relative to parent
1182 * @param colorKey ColorTheme key color to use for foreground text.
1183 * Default is "tlabel"
1184 * @return the new label
1186 public final TLabel
addLabel(final String text
, final int x
, final int y
,
1187 final String colorKey
) {
1189 return new TLabel(this, text
, x
, y
, colorKey
);
1193 * Convenience function to add a label to this container/window.
1196 * @param x column relative to parent
1197 * @param y row relative to parent
1198 * @param colorKey ColorTheme key color to use for foreground text.
1199 * Default is "tlabel"
1200 * @param useWindowBackground if true, use the window's background color
1201 * @return the new label
1203 public final TLabel
addLabel(final String text
, final int x
, final int y
,
1204 final String colorKey
, final boolean useWindowBackground
) {
1206 return new TLabel(this, text
, x
, y
, colorKey
, useWindowBackground
);
1210 * Convenience function to add a button to this container/window.
1212 * @param text label on the button
1213 * @param x column relative to parent
1214 * @param y row relative to parent
1215 * @param action action to call when button is pressed
1216 * @return the new button
1218 public final TButton
addButton(final String text
, final int x
, final int y
,
1219 final TAction action
) {
1221 return new TButton(this, text
, x
, y
, action
);
1225 * Convenience function to add a checkbox to this container/window.
1227 * @param x column relative to parent
1228 * @param y row relative to parent
1229 * @param label label to display next to (right of) the checkbox
1230 * @param checked initial check state
1231 * @return the new checkbox
1233 public final TCheckBox
addCheckBox(final int x
, final int y
,
1234 final String label
, final boolean checked
) {
1236 return new TCheckBox(this, x
, y
, label
, checked
);
1240 * Convenience function to add a combobox to this container/window.
1242 * @param x column relative to parent
1243 * @param y row relative to parent
1244 * @param width visible combobox width, including the down-arrow
1245 * @param values the possible values for the box, shown in the drop-down
1246 * @param valuesIndex the initial index in values, or -1 for no default
1248 * @param valuesHeight the height of the values drop-down when it is
1250 * @param updateAction action to call when a new value is selected from
1251 * the list or enter is pressed in the edit field
1252 * @return the new combobox
1254 public final TComboBox
addComboBox(final int x
, final int y
,
1255 final int width
, final List
<String
> values
, final int valuesIndex
,
1256 final int valuesHeight
, final TAction updateAction
) {
1258 return new TComboBox(this, x
, y
, width
, values
, valuesIndex
,
1259 valuesHeight
, updateAction
);
1263 * Convenience function to add a spinner to this container/window.
1265 * @param x column relative to parent
1266 * @param y row relative to parent
1267 * @param upAction action to call when the up arrow is clicked or pressed
1268 * @param downAction action to call when the down arrow is clicked or
1270 * @return the new spinner
1272 public final TSpinner
addSpinner(final int x
, final int y
,
1273 final TAction upAction
, final TAction downAction
) {
1275 return new TSpinner(this, x
, y
, upAction
, downAction
);
1279 * Convenience function to add a calendar to this container/window.
1281 * @param x column relative to parent
1282 * @param y row relative to parent
1283 * @param updateAction action to call when the user changes the value of
1285 * @return the new calendar
1287 public final TCalendar
addCalendar(final int x
, final int y
,
1288 final TAction updateAction
) {
1290 return new TCalendar(this, x
, y
, updateAction
);
1294 * Convenience function to add a progress bar to this container/window.
1296 * @param x column relative to parent
1297 * @param y row relative to parent
1298 * @param width width of progress bar
1299 * @param value initial value of percent complete
1300 * @return the new progress bar
1302 public final TProgressBar
addProgressBar(final int x
, final int y
,
1303 final int width
, final int value
) {
1305 return new TProgressBar(this, x
, y
, width
, value
);
1309 * Convenience function to add a radio button group to this
1312 * @param x column relative to parent
1313 * @param y row relative to parent
1314 * @param label label to display on the group box
1315 * @return the new radio button group
1317 public final TRadioGroup
addRadioGroup(final int x
, final int y
,
1318 final String label
) {
1320 return new TRadioGroup(this, x
, y
, label
);
1324 * Convenience function to add a text field to this container/window.
1326 * @param x column relative to parent
1327 * @param y row relative to parent
1328 * @param width visible text width
1329 * @param fixed if true, the text cannot exceed the display width
1330 * @return the new text field
1332 public final TField
addField(final int x
, final int y
,
1333 final int width
, final boolean fixed
) {
1335 return new TField(this, x
, y
, width
, fixed
);
1339 * Convenience function to add a text field to this container/window.
1341 * @param x column relative to parent
1342 * @param y row relative to parent
1343 * @param width visible text width
1344 * @param fixed if true, the text cannot exceed the display width
1345 * @param text initial text, default is empty string
1346 * @return the new text field
1348 public final TField
addField(final int x
, final int y
,
1349 final int width
, final boolean fixed
, final String text
) {
1351 return new TField(this, x
, y
, width
, fixed
, text
);
1355 * Convenience function to add a text field to this container/window.
1357 * @param x column relative to parent
1358 * @param y row relative to parent
1359 * @param width visible text width
1360 * @param fixed if true, the text cannot exceed the display width
1361 * @param text initial text, default is empty string
1362 * @param enterAction function to call when enter key is pressed
1363 * @param updateAction function to call when the text is updated
1364 * @return the new text field
1366 public final TField
addField(final int x
, final int y
,
1367 final int width
, final boolean fixed
, final String text
,
1368 final TAction enterAction
, final TAction updateAction
) {
1370 return new TField(this, x
, y
, width
, fixed
, text
, enterAction
,
1375 * Convenience function to add a scrollable text box to this
1378 * @param text text on the screen
1379 * @param x column relative to parent
1380 * @param y row relative to parent
1381 * @param width width of text area
1382 * @param height height of text area
1383 * @param colorKey ColorTheme key color to use for foreground text
1384 * @return the new text box
1386 public final TText
addText(final String text
, final int x
,
1387 final int y
, final int width
, final int height
, final String colorKey
) {
1389 return new TText(this, text
, x
, y
, width
, height
, colorKey
);
1393 * Convenience function to add a scrollable text box to this
1396 * @param text text on the screen
1397 * @param x column relative to parent
1398 * @param y row relative to parent
1399 * @param width width of text area
1400 * @param height height of text area
1401 * @return the new text box
1403 public final TText
addText(final String text
, final int x
, final int y
,
1404 final int width
, final int height
) {
1406 return new TText(this, text
, x
, y
, width
, height
, "ttext");
1410 * Convenience function to add an editable text area box to this
1413 * @param text text on the screen
1414 * @param x column relative to parent
1415 * @param y row relative to parent
1416 * @param width width of text area
1417 * @param height height of text area
1418 * @return the new text box
1420 public final TEditorWidget
addEditor(final String text
, final int x
,
1421 final int y
, final int width
, final int height
) {
1423 return new TEditorWidget(this, text
, x
, y
, width
, height
);
1427 * Convenience function to spawn a message box.
1429 * @param title window title, will be centered along the top border
1430 * @param caption message to display. Use embedded newlines to get a
1432 * @return the new message box
1434 public final TMessageBox
messageBox(final String title
,
1435 final String caption
) {
1437 return getApplication().messageBox(title
, caption
, TMessageBox
.Type
.OK
);
1441 * Convenience function to spawn a message box.
1443 * @param title window title, will be centered along the top border
1444 * @param caption message to display. Use embedded newlines to get a
1446 * @param type one of the TMessageBox.Type constants. Default is
1448 * @return the new message box
1450 public final TMessageBox
messageBox(final String title
,
1451 final String caption
, final TMessageBox
.Type type
) {
1453 return getApplication().messageBox(title
, caption
, type
);
1457 * Convenience function to spawn an input box.
1459 * @param title window title, will be centered along the top border
1460 * @param caption message to display. Use embedded newlines to get a
1462 * @return the new input box
1464 public final TInputBox
inputBox(final String title
, final String caption
) {
1466 return getApplication().inputBox(title
, caption
);
1470 * Convenience function to spawn an input box.
1472 * @param title window title, will be centered along the top border
1473 * @param caption message to display. Use embedded newlines to get a
1475 * @param text initial text to seed the field with
1476 * @return the new input box
1478 public final TInputBox
inputBox(final String title
, final String caption
,
1479 final String text
) {
1481 return getApplication().inputBox(title
, caption
, text
);
1485 * Convenience function to add a password text field to this
1488 * @param x column relative to parent
1489 * @param y row relative to parent
1490 * @param width visible text width
1491 * @param fixed if true, the text cannot exceed the display width
1492 * @return the new text field
1494 public final TPasswordField
addPasswordField(final int x
, final int y
,
1495 final int width
, final boolean fixed
) {
1497 return new TPasswordField(this, x
, y
, width
, fixed
);
1501 * Convenience function to add a password text field to this
1504 * @param x column relative to parent
1505 * @param y row relative to parent
1506 * @param width visible text width
1507 * @param fixed if true, the text cannot exceed the display width
1508 * @param text initial text, default is empty string
1509 * @return the new text field
1511 public final TPasswordField
addPasswordField(final int x
, final int y
,
1512 final int width
, final boolean fixed
, final String text
) {
1514 return new TPasswordField(this, x
, y
, width
, fixed
, text
);
1518 * Convenience function to add a password text field to this
1521 * @param x column relative to parent
1522 * @param y row relative to parent
1523 * @param width visible text width
1524 * @param fixed if true, the text cannot exceed the display width
1525 * @param text initial text, default is empty string
1526 * @param enterAction function to call when enter key is pressed
1527 * @param updateAction function to call when the text is updated
1528 * @return the new text field
1530 public final TPasswordField
addPasswordField(final int x
, final int y
,
1531 final int width
, final boolean fixed
, final String text
,
1532 final TAction enterAction
, final TAction updateAction
) {
1534 return new TPasswordField(this, x
, y
, width
, fixed
, text
, enterAction
,
1539 * Convenience function to add a scrollable tree view to this
1542 * @param x column relative to parent
1543 * @param y row relative to parent
1544 * @param width width of tree view
1545 * @param height height of tree view
1546 * @return the new tree view
1548 public final TTreeViewWidget
addTreeViewWidget(final int x
, final int y
,
1549 final int width
, final int height
) {
1551 return new TTreeViewWidget(this, x
, y
, width
, height
);
1555 * Convenience function to add a scrollable tree view to this
1558 * @param x column relative to parent
1559 * @param y row relative to parent
1560 * @param width width of tree view
1561 * @param height height of tree view
1562 * @param action action to perform when an item is selected
1563 * @return the new tree view
1565 public final TTreeViewWidget
addTreeViewWidget(final int x
, final int y
,
1566 final int width
, final int height
, final TAction action
) {
1568 return new TTreeViewWidget(this, x
, y
, width
, height
, action
);
1572 * Convenience function to spawn a file open box.
1574 * @param path path of selected file
1575 * @return the result of the new file open box
1576 * @throws IOException if a java.io operation throws
1578 public final String
fileOpenBox(final String path
) throws IOException
{
1579 return getApplication().fileOpenBox(path
);
1583 * Convenience function to spawn a file open box.
1585 * @param path path of selected file
1586 * @param type one of the Type constants
1587 * @return the result of the new file open box
1588 * @throws IOException if a java.io operation throws
1590 public final String
fileOpenBox(final String path
,
1591 final TFileOpenBox
.Type type
) throws IOException
{
1593 return getApplication().fileOpenBox(path
, type
);
1596 * Convenience function to add a directory list to this container/window.
1598 * @param path directory path, must be a directory
1599 * @param x column relative to parent
1600 * @param y row relative to parent
1601 * @param width width of text area
1602 * @param height height of text area
1603 * @return the new directory list
1605 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
1606 final int y
, final int width
, final int height
) {
1608 return new TDirectoryList(this, path
, x
, y
, width
, height
, null);
1612 * Convenience function to add a directory list to this container/window.
1614 * @param path directory path, must be a directory
1615 * @param x column relative to parent
1616 * @param y row relative to parent
1617 * @param width width of text area
1618 * @param height height of text area
1619 * @param action action to perform when an item is selected
1620 * @return the new directory list
1622 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
1623 final int y
, final int width
, final int height
, final TAction action
) {
1625 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
);
1629 * Convenience function to add a directory list to this container/window.
1631 * @param strings list of strings to show
1632 * @param x column relative to parent
1633 * @param y row relative to parent
1634 * @param width width of text area
1635 * @param height height of text area
1636 * @return the new directory list
1638 public final TList
addList(final List
<String
> strings
, final int x
,
1639 final int y
, final int width
, final int height
) {
1641 return new TList(this, strings
, x
, y
, width
, height
, null);
1645 * Convenience function to add a directory list to this container/window.
1647 * @param strings list of strings to show
1648 * @param x column relative to parent
1649 * @param y row relative to parent
1650 * @param width width of text area
1651 * @param height height of text area
1652 * @param enterAction action to perform when an item is selected
1653 * @return the new directory list
1655 public final TList
addList(final List
<String
> strings
, final int x
,
1656 final int y
, final int width
, final int height
,
1657 final TAction enterAction
) {
1659 return new TList(this, strings
, x
, y
, width
, height
, enterAction
);
1663 * Convenience function to add a directory list to this container/window.
1665 * @param strings list of strings to show
1666 * @param x column relative to parent
1667 * @param y row relative to parent
1668 * @param width width of text area
1669 * @param height height of text area
1670 * @param enterAction action to perform when an item is selected
1671 * @param moveAction action to perform when the user navigates to a new
1672 * item with arrow/page keys
1673 * @return the new directory list
1675 public final TList
addList(final List
<String
> strings
, final int x
,
1676 final int y
, final int width
, final int height
,
1677 final TAction enterAction
, final TAction moveAction
) {
1679 return new TList(this, strings
, x
, y
, width
, height
, enterAction
,