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
.ColorTheme
;
40 import jexer
.event
.TCommandEvent
;
41 import jexer
.event
.TInputEvent
;
42 import jexer
.event
.TKeypressEvent
;
43 import jexer
.event
.TMenuEvent
;
44 import jexer
.event
.TMouseEvent
;
45 import jexer
.event
.TResizeEvent
;
46 import jexer
.layout
.LayoutManager
;
47 import jexer
.menu
.TMenu
;
48 import jexer
.ttree
.TTreeItem
;
49 import jexer
.ttree
.TTreeView
;
50 import jexer
.ttree
.TTreeViewWidget
;
51 import static jexer
.TKeypress
.*;
54 * TWidget is the base class of all objects that can be drawn on screen or
55 * handle user input events.
57 public abstract class TWidget
implements Comparable
<TWidget
> {
59 // ------------------------------------------------------------------------
60 // Variables --------------------------------------------------------------
61 // ------------------------------------------------------------------------
64 * Every widget has a parent widget that it may be "contained" in. For
65 * example, a TWindow might contain several TFields, or a TComboBox may
66 * contain a TList that itself contains a TVScroller.
68 private TWidget parent
= null;
71 * Child widgets that this widget contains.
73 private List
<TWidget
> children
;
76 * The currently active child widget that will receive keypress events.
78 private TWidget activeChild
= null;
81 * If true, this widget will receive events.
83 private boolean active
= false;
86 * The window that this widget draws to.
88 private TWindow window
= null;
91 * Absolute X position of the top-left corner.
96 * Absolute Y position of the top-left corner.
103 private int width
= 0;
108 private int height
= 0;
111 * My tab order inside a window or containing widget.
113 private int tabOrder
= 0;
116 * If true, this widget can be tabbed to or receive events.
118 private boolean enabled
= true;
121 * If true, this widget will be rendered.
123 private boolean visible
= true;
126 * If true, this widget has a cursor.
128 private boolean cursorVisible
= false;
131 * Cursor column position in relative coordinates.
133 private int cursorX
= 0;
136 * Cursor row position in relative coordinates.
138 private int cursorY
= 0;
143 private LayoutManager layout
= null;
145 // ------------------------------------------------------------------------
146 // Constructors -----------------------------------------------------------
147 // ------------------------------------------------------------------------
150 * Default constructor for subclasses.
152 protected TWidget() {
153 children
= new ArrayList
<TWidget
>();
157 * Protected constructor.
159 * @param parent parent widget
161 protected TWidget(final TWidget parent
) {
166 * Protected constructor.
168 * @param parent parent widget
169 * @param x column relative to parent
170 * @param y row relative to parent
171 * @param width width of widget
172 * @param height height of widget
174 protected TWidget(final TWidget parent
, final int x
, final int y
,
175 final int width
, final int height
) {
177 this(parent
, true, x
, y
, width
, height
);
181 * Protected constructor used by subclasses that are disabled by default.
183 * @param parent parent widget
184 * @param enabled if true assume enabled
186 protected TWidget(final TWidget parent
, final boolean enabled
) {
187 this.enabled
= enabled
;
188 this.parent
= parent
;
189 children
= new ArrayList
<TWidget
>();
191 if (parent
!= null) {
192 this.window
= parent
.window
;
193 parent
.addChild(this);
198 * Protected constructor used by subclasses that are disabled by default.
200 * @param parent parent widget
201 * @param enabled if true assume enabled
202 * @param x column relative to parent
203 * @param y row relative to parent
204 * @param width width of widget
205 * @param height height of widget
207 protected TWidget(final TWidget parent
, final boolean enabled
,
208 final int x
, final int y
, final int width
, final int height
) {
211 throw new IllegalArgumentException("width cannot be negative");
214 throw new IllegalArgumentException("height cannot be negative");
217 this.enabled
= enabled
;
218 this.parent
= parent
;
219 children
= new ArrayList
<TWidget
>();
224 this.height
= height
;
226 if (parent
!= null) {
227 this.window
= parent
.window
;
228 parent
.addChild(this);
233 * Backdoor access for TWindow's constructor. ONLY TWindow USES THIS.
235 * @param window the top-level window
236 * @param x column relative to parent
237 * @param y row relative to parent
238 * @param width width of window
239 * @param height height of window
241 protected final void setupForTWindow(final TWindow window
,
242 final int x
, final int y
, final int width
, final int height
) {
245 throw new IllegalArgumentException("width cannot be negative");
248 throw new IllegalArgumentException("height cannot be negative");
251 this.parent
= window
;
252 this.window
= window
;
256 this.height
= height
;
259 // ------------------------------------------------------------------------
260 // Event handlers ---------------------------------------------------------
261 // ------------------------------------------------------------------------
264 * Subclasses should override this method to cleanup resources. This is
265 * called by TWindow.onClose().
267 protected void close() {
268 // Default: call close() on children.
269 for (TWidget w
: getChildren()) {
275 * Check if a mouse press/release event coordinate is contained in this
278 * @param mouse a mouse-based event
279 * @return whether or not a mouse click would be sent to this widget
281 public final boolean mouseWouldHit(final TMouseEvent mouse
) {
287 if ((this instanceof TTreeItem
)
288 && ((y
< 0) || (y
> parent
.getHeight() - 1))
293 if ((mouse
.getAbsoluteX() >= getAbsoluteX())
294 && (mouse
.getAbsoluteX() < getAbsoluteX() + width
)
295 && (mouse
.getAbsoluteY() >= getAbsoluteY())
296 && (mouse
.getAbsoluteY() < getAbsoluteY() + height
)
304 * Method that subclasses can override to handle keystrokes.
306 * @param keypress keystroke event
308 public void onKeypress(final TKeypressEvent keypress
) {
309 assert (parent
!= null);
311 if ((children
.size() == 0)
312 || (this instanceof TTreeView
)
313 || (this instanceof TText
)
314 || (this instanceof TComboBox
)
318 // tab / shift-tab - switch to next/previous widget
319 // left-arrow or up-arrow: same as shift-tab
320 if ((keypress
.equals(kbTab
))
321 || (keypress
.equals(kbDown
) && !(this instanceof TComboBox
))
323 parent
.switchWidget(true);
325 } else if ((keypress
.equals(kbShiftTab
))
326 || (keypress
.equals(kbBackTab
))
327 || (keypress
.equals(kbUp
) && !(this instanceof TComboBox
))
329 parent
.switchWidget(false);
334 if ((children
.size() == 0)
335 && !(this instanceof TTreeView
)
339 // right-arrow or down-arrow: same as tab
340 if (keypress
.equals(kbRight
)) {
341 parent
.switchWidget(true);
343 } else if (keypress
.equals(kbLeft
)) {
344 parent
.switchWidget(false);
349 // If I have any buttons on me AND this is an Alt-key that matches
350 // its mnemonic, send it an Enter keystroke.
351 for (TWidget widget
: children
) {
352 if (widget
instanceof TButton
) {
353 TButton button
= (TButton
) widget
;
354 if (button
.isEnabled()
355 && !keypress
.getKey().isFnKey()
356 && keypress
.getKey().isAlt()
357 && !keypress
.getKey().isCtrl()
358 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
359 == Character
.toLowerCase(keypress
.getKey().getChar()))
362 widget
.onKeypress(new TKeypressEvent(kbEnter
));
368 // If I have any labels on me AND this is an Alt-key that matches
369 // its mnemonic, call its action.
370 for (TWidget widget
: children
) {
371 if (widget
instanceof TLabel
) {
372 TLabel label
= (TLabel
) widget
;
373 if (!keypress
.getKey().isFnKey()
374 && keypress
.getKey().isAlt()
375 && !keypress
.getKey().isCtrl()
376 && (Character
.toLowerCase(label
.getMnemonic().getShortcut())
377 == Character
.toLowerCase(keypress
.getKey().getChar()))
386 // If I have any radiobuttons on me AND this is an Alt-key that
387 // matches its mnemonic, select it and send a Space to it.
388 for (TWidget widget
: children
) {
389 if (widget
instanceof TRadioButton
) {
390 TRadioButton button
= (TRadioButton
) widget
;
391 if (button
.isEnabled()
392 && !keypress
.getKey().isFnKey()
393 && keypress
.getKey().isAlt()
394 && !keypress
.getKey().isCtrl()
395 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
396 == Character
.toLowerCase(keypress
.getKey().getChar()))
399 widget
.onKeypress(new TKeypressEvent(kbSpace
));
403 if (widget
instanceof TRadioGroup
) {
404 for (TWidget child
: widget
.getChildren()) {
405 if (child
instanceof TRadioButton
) {
406 TRadioButton button
= (TRadioButton
) child
;
407 if (button
.isEnabled()
408 && !keypress
.getKey().isFnKey()
409 && keypress
.getKey().isAlt()
410 && !keypress
.getKey().isCtrl()
411 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
412 == Character
.toLowerCase(keypress
.getKey().getChar()))
415 widget
.activate(child
);
416 child
.onKeypress(new TKeypressEvent(kbSpace
));
424 // If I have any checkboxes on me AND this is an Alt-key that matches
425 // its mnemonic, select it and set it to checked.
426 for (TWidget widget
: children
) {
427 if (widget
instanceof TCheckBox
) {
428 TCheckBox checkBox
= (TCheckBox
) widget
;
429 if (checkBox
.isEnabled()
430 && !keypress
.getKey().isFnKey()
431 && keypress
.getKey().isAlt()
432 && !keypress
.getKey().isCtrl()
433 && (Character
.toLowerCase(checkBox
.getMnemonic().getShortcut())
434 == Character
.toLowerCase(keypress
.getKey().getChar()))
437 checkBox
.setChecked(true);
443 // Dispatch the keypress to an active widget
444 for (TWidget widget
: children
) {
446 widget
.onKeypress(keypress
);
453 * Method that subclasses can override to handle mouse button presses.
455 * @param mouse mouse button event
457 public void onMouseDown(final TMouseEvent mouse
) {
458 // Default: do nothing, pass to children instead
459 if (activeChild
!= null) {
460 if (activeChild
.mouseWouldHit(mouse
)) {
461 // Dispatch to the active child
463 // Set x and y relative to the child's coordinates
464 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
465 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
466 activeChild
.onMouseDown(mouse
);
470 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
471 TWidget widget
= children
.get(i
);
472 if (widget
.mouseWouldHit(mouse
)) {
473 // Dispatch to this child, also activate it
476 // Set x and y relative to the child's coordinates
477 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
478 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
479 widget
.onMouseDown(mouse
);
486 * Method that subclasses can override to handle mouse button releases.
488 * @param mouse mouse button event
490 public void onMouseUp(final TMouseEvent mouse
) {
491 // Default: do nothing, pass to children instead
492 if (activeChild
!= null) {
493 if (activeChild
.mouseWouldHit(mouse
)) {
494 // Dispatch to the active child
496 // Set x and y relative to the child's coordinates
497 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
498 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
499 activeChild
.onMouseUp(mouse
);
503 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
504 TWidget widget
= children
.get(i
);
505 if (widget
.mouseWouldHit(mouse
)) {
506 // Dispatch to this child, also activate it
509 // Set x and y relative to the child's coordinates
510 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
511 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
512 widget
.onMouseUp(mouse
);
519 * Method that subclasses can override to handle mouse movements.
521 * @param mouse mouse motion event
523 public void onMouseMotion(final TMouseEvent mouse
) {
524 // Default: do nothing, pass it on to ALL of my children. This way
525 // the children can see the mouse "leaving" their area.
526 for (TWidget widget
: children
) {
527 // Set x and y relative to the child's coordinates
528 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
529 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
530 widget
.onMouseMotion(mouse
);
535 * Method that subclasses can override to handle mouse button
538 * @param mouse mouse button event
540 public void onMouseDoubleClick(final TMouseEvent mouse
) {
541 // Default: do nothing, pass to children instead
542 if (activeChild
!= null) {
543 if (activeChild
.mouseWouldHit(mouse
)) {
544 // Dispatch to the active child
546 // Set x and y relative to the child's coordinates
547 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
548 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
549 activeChild
.onMouseDoubleClick(mouse
);
553 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
554 TWidget widget
= children
.get(i
);
555 if (widget
.mouseWouldHit(mouse
)) {
556 // Dispatch to this child, also activate it
559 // Set x and y relative to the child's coordinates
560 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
561 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
562 widget
.onMouseDoubleClick(mouse
);
569 * Method that subclasses can override to handle window/screen resize
572 * @param resize resize event
574 public void onResize(final TResizeEvent resize
) {
575 // Default: change my width/height.
576 if (resize
.getType() == TResizeEvent
.Type
.WIDGET
) {
577 width
= resize
.getWidth();
578 height
= resize
.getHeight();
579 if (layout
!= null) {
580 if (this instanceof TWindow
) {
581 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
582 width
- 2, height
- 2));
584 layout
.onResize(resize
);
588 // Let children see the screen resize
589 for (TWidget widget
: children
) {
590 widget
.onResize(resize
);
596 * Method that subclasses can override to handle posted command events.
598 * @param command command event
600 public void onCommand(final TCommandEvent command
) {
601 // Default: do nothing, pass to children instead
602 for (TWidget widget
: children
) {
603 widget
.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
,
939 this.height
= height
;
940 if (layout
!= null) {
941 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
947 * Get the layout manager.
949 * @return the layout manager, or null if not set
951 public LayoutManager
getLayoutManager() {
956 * Set the layout manager.
958 * @param layout the new layout manager
960 public void setLayoutManager(LayoutManager layout
) {
961 if (this.layout
!= null) {
962 for (TWidget w
: children
) {
963 this.layout
.remove(w
);
967 this.layout
= layout
;
968 if (this.layout
!= null) {
969 for (TWidget w
: children
) {
978 * @return if true, this widget can be tabbed to or receive events
980 public final boolean isEnabled() {
987 * @param enabled if true, this widget can be tabbed to or receive events
989 public final void setEnabled(final boolean enabled
) {
990 this.enabled
= enabled
;
993 // See if there are any active siblings to switch to
994 boolean foundSibling
= false;
995 if (parent
!= null) {
996 for (TWidget w
: parent
.children
) {
998 && !(this instanceof THScroller
)
999 && !(this instanceof TVScroller
)
1002 foundSibling
= true;
1006 if (!foundSibling
) {
1007 parent
.activeChild
= null;
1016 * @param visible if true, this widget will be drawn
1018 public final void setVisible(final boolean visible
) {
1019 this.visible
= visible
;
1023 * See if this widget is visible.
1025 * @return if true, this widget will be drawn
1027 public final boolean isVisible() {
1032 * Set visible cursor flag.
1034 * @param cursorVisible if true, this widget has a cursor
1036 public final void setCursorVisible(final boolean cursorVisible
) {
1037 this.cursorVisible
= cursorVisible
;
1041 * See if this widget has a visible cursor.
1043 * @return if true, this widget has a visible cursor
1045 public final boolean isCursorVisible() {
1046 // If cursor is out of my bounds, it is not visible.
1047 if ((cursorX
>= width
)
1049 || (cursorY
>= height
)
1055 assert (window
!= null);
1057 if (window
instanceof TDesktop
) {
1058 // Desktop doesn't have a window border.
1059 return cursorVisible
;
1062 // If cursor is out of my window's bounds, it is not visible.
1063 if ((getCursorAbsoluteX() >= window
.getAbsoluteX()
1064 + window
.getWidth() - 1)
1065 || (getCursorAbsoluteX() < 0)
1066 || (getCursorAbsoluteY() >= window
.getAbsoluteY()
1067 + window
.getHeight() - 1)
1068 || (getCursorAbsoluteY() < 0)
1072 return cursorVisible
;
1076 * Get cursor X value.
1078 * @return cursor column position in relative coordinates
1080 public final int getCursorX() {
1085 * Set cursor X value.
1087 * @param cursorX column position in relative coordinates
1089 public final void setCursorX(final int cursorX
) {
1090 this.cursorX
= cursorX
;
1094 * Get cursor Y value.
1096 * @return cursor row position in relative coordinates
1098 public final int getCursorY() {
1103 * Set cursor Y value.
1105 * @param cursorY row position in relative coordinates
1107 public final void setCursorY(final int cursorY
) {
1108 this.cursorY
= cursorY
;
1112 * Get this TWidget's parent TApplication.
1114 * @return the parent TApplication, or null if not assigned
1116 public TApplication
getApplication() {
1117 if (window
!= null) {
1118 return window
.getApplication();
1126 * @return the Screen, or null if not assigned
1128 public Screen
getScreen() {
1129 if (window
!= null) {
1130 return window
.getScreen();
1136 * Comparison operator. For various subclasses it sorts on:
1138 * <li>tabOrder for TWidgets</li>
1139 * <li>z for TWindows</li>
1140 * <li>text for TTreeItems</li>
1143 * @param that another TWidget, TWindow, or TTreeItem instance
1144 * @return difference between this.tabOrder and that.tabOrder, or
1145 * difference between this.z and that.z, or String.compareTo(text)
1147 public final int compareTo(final TWidget that
) {
1148 if ((this instanceof TWindow
)
1149 && (that
instanceof TWindow
)
1151 return (((TWindow
) this).getZ() - ((TWindow
) that
).getZ());
1153 if ((this instanceof TTreeItem
)
1154 && (that
instanceof TTreeItem
)
1156 return (((TTreeItem
) this).getText().compareTo(
1157 ((TTreeItem
) that
).getText()));
1159 return (this.tabOrder
- that
.tabOrder
);
1163 * See if this widget should render with the active color.
1165 * @return true if this widget is active and all of its parents are
1168 public final boolean isAbsoluteActive() {
1169 if (parent
== this) {
1172 return (active
&& (parent
== null ?
true : parent
.isAbsoluteActive()));
1176 * Returns the cursor X position.
1178 * @return absolute screen column number for the cursor's X position
1180 public final int getCursorAbsoluteX() {
1181 return getAbsoluteX() + cursorX
;
1185 * Returns the cursor Y position.
1187 * @return absolute screen row number for the cursor's Y position
1189 public final int getCursorAbsoluteY() {
1190 return getAbsoluteY() + cursorY
;
1194 * Compute my absolute X position as the sum of my X plus all my parent's
1197 * @return absolute screen column number for my X position
1199 public final int getAbsoluteX() {
1200 assert (parent
!= null);
1201 if (parent
== this) {
1204 if ((parent
instanceof TWindow
)
1205 && !(parent
instanceof TMenu
)
1206 && !(parent
instanceof TDesktop
)
1208 // Widgets on a TWindow have (0,0) as their top-left, but this is
1209 // actually the TWindow's (1,1).
1210 return parent
.getAbsoluteX() + x
+ 1;
1212 return parent
.getAbsoluteX() + x
;
1216 * Compute my absolute Y position as the sum of my Y plus all my parent's
1219 * @return absolute screen row number for my Y position
1221 public final int getAbsoluteY() {
1222 assert (parent
!= null);
1223 if (parent
== this) {
1226 if ((parent
instanceof TWindow
)
1227 && !(parent
instanceof TMenu
)
1228 && !(parent
instanceof TDesktop
)
1230 // Widgets on a TWindow have (0,0) as their top-left, but this is
1231 // actually the TWindow's (1,1).
1232 return parent
.getAbsoluteY() + y
+ 1;
1234 return parent
.getAbsoluteY() + y
;
1238 * Get the global color theme.
1240 * @return the ColorTheme
1242 protected final ColorTheme
getTheme() {
1243 return window
.getApplication().getTheme();
1247 * See if this widget can be drawn onto a screen.
1249 * @return true if this widget is part of the hierarchy that can draw to
1252 public final boolean isDrawable() {
1253 if ((window
== null)
1254 || (window
.getScreen() == null)
1259 if (parent
== this) {
1262 return (parent
.isDrawable());
1266 * Draw my specific widget. When called, the screen rectangle I draw
1267 * into is already setup (offset and clipping).
1269 public void draw() {
1270 // Default widget draws nothing.
1274 * Called by parent to render to TWindow. Note package private access.
1276 final void drawChildren() {
1277 if (!isDrawable()) {
1281 // Set my clipping rectangle
1282 assert (window
!= null);
1283 assert (getScreen() != null);
1284 Screen screen
= getScreen();
1286 // Special case: TStatusBar is drawn by TApplication, not anything
1288 if (this instanceof TStatusBar
) {
1292 screen
.setClipRight(width
);
1293 screen
.setClipBottom(height
);
1295 int absoluteRightEdge
= window
.getAbsoluteX() + window
.getWidth();
1296 int absoluteBottomEdge
= window
.getAbsoluteY() + window
.getHeight();
1297 if (!(this instanceof TWindow
)
1298 && !(this instanceof TVScroller
)
1299 && !(window
instanceof TDesktop
)
1301 absoluteRightEdge
-= 1;
1303 if (!(this instanceof TWindow
)
1304 && !(this instanceof THScroller
)
1305 && !(window
instanceof TDesktop
)
1307 absoluteBottomEdge
-= 1;
1309 int myRightEdge
= getAbsoluteX() + width
;
1310 int myBottomEdge
= getAbsoluteY() + height
;
1311 if (getAbsoluteX() > absoluteRightEdge
) {
1313 screen
.setClipRight(0);
1314 } else if (myRightEdge
> absoluteRightEdge
) {
1315 screen
.setClipRight(screen
.getClipRight()
1316 - (myRightEdge
- absoluteRightEdge
));
1318 if (getAbsoluteY() > absoluteBottomEdge
) {
1320 screen
.setClipBottom(0);
1321 } else if (myBottomEdge
> absoluteBottomEdge
) {
1322 screen
.setClipBottom(screen
.getClipBottom()
1323 - (myBottomEdge
- absoluteBottomEdge
));
1327 screen
.setOffsetX(getAbsoluteX());
1328 screen
.setOffsetY(getAbsoluteY());
1332 if (!isDrawable()) {
1333 // An action taken by a draw method unhooked me from the UI.
1338 assert (visible
== true);
1340 // Continue down the chain. Draw the active child last so that it
1342 for (TWidget widget
: children
) {
1343 if (widget
.isVisible() && (widget
!= activeChild
)) {
1344 widget
.drawChildren();
1345 if (!isDrawable()) {
1346 // An action taken by a draw method unhooked me from the UI.
1352 if (activeChild
!= null) {
1353 activeChild
.drawChildren();
1358 * Repaint the screen on the next update.
1360 protected final void doRepaint() {
1361 window
.getApplication().doRepaint();
1365 * Add a child widget to my list of children. We set its tabOrder to 0
1366 * and increment the tabOrder of all other children.
1368 * @param child TWidget to add
1370 private void addChild(final TWidget child
) {
1371 children
.add(child
);
1374 && !(child
instanceof THScroller
)
1375 && !(child
instanceof TVScroller
)
1377 for (TWidget widget
: children
) {
1378 widget
.active
= false;
1380 child
.active
= true;
1381 activeChild
= child
;
1383 for (int i
= 0; i
< children
.size(); i
++) {
1384 children
.get(i
).tabOrder
= i
;
1386 if (layout
!= null) {
1392 * Reset the tab order of children to match their position in the list.
1393 * Available so that subclasses can re-order their widgets if needed.
1395 protected void resetTabOrder() {
1396 for (int i
= 0; i
< children
.size(); i
++) {
1397 children
.get(i
).tabOrder
= i
;
1402 * Switch the active child.
1404 * @param child TWidget to activate
1406 public final void activate(final TWidget child
) {
1407 assert (child
.enabled
);
1408 if ((child
instanceof THScroller
)
1409 || (child
instanceof TVScroller
)
1414 if (children
.size() == 1) {
1415 if (children
.get(0).enabled
== true) {
1416 child
.active
= true;
1417 activeChild
= child
;
1420 if (child
!= activeChild
) {
1421 if (activeChild
!= null) {
1422 activeChild
.active
= false;
1424 child
.active
= true;
1425 activeChild
= child
;
1431 * Switch the active child.
1433 * @param tabOrder tabOrder of the child to activate. If that child
1434 * isn't enabled, then the next enabled child will be activated.
1436 public final void activate(final int tabOrder
) {
1437 if (children
.size() == 1) {
1438 if (children
.get(0).enabled
== true) {
1439 children
.get(0).active
= true;
1440 activeChild
= children
.get(0);
1445 TWidget child
= null;
1446 for (TWidget widget
: children
) {
1447 if ((widget
.enabled
)
1448 && !(widget
instanceof THScroller
)
1449 && !(widget
instanceof TVScroller
)
1450 && (widget
.tabOrder
>= tabOrder
)
1456 if ((child
!= null) && (child
!= activeChild
)) {
1457 if (activeChild
!= null) {
1458 activeChild
.active
= false;
1460 assert (child
.enabled
);
1461 child
.active
= true;
1462 activeChild
= child
;
1467 * Make this widget the active child of its parent. Note that this is
1468 * not final since TWindow overrides activate().
1470 public void activate() {
1472 if (parent
!= null) {
1473 parent
.activate(this);
1479 * Make this widget, all of its parents, the active child.
1481 public final void activateAll() {
1483 if (parent
== this) {
1486 if (parent
!= null) {
1487 parent
.activateAll();
1492 * Switch the active widget with the next in the tab order.
1494 * @param forward if true, then switch to the next enabled widget in the
1495 * list, otherwise switch to the previous enabled widget in the list
1497 public final void switchWidget(final boolean forward
) {
1499 // No children: do nothing.
1500 if (children
.size() == 0) {
1504 assert (parent
!= null);
1506 // If there is only one child, make it active if it is enabled.
1507 if (children
.size() == 1) {
1508 if (children
.get(0).enabled
== true) {
1509 activeChild
= children
.get(0);
1510 activeChild
.active
= true;
1512 children
.get(0).active
= false;
1518 // Two or more children: go forward or backward to the next enabled
1521 if (activeChild
!= null) {
1522 tabOrder
= activeChild
.tabOrder
;
1532 // If at the end, pass the switch to my parent.
1533 if ((!forward
) && (parent
!= this)) {
1534 parent
.switchWidget(forward
);
1538 tabOrder
= children
.size() - 1;
1539 } else if (tabOrder
== children
.size()) {
1540 // If at the end, pass the switch to my parent.
1541 if ((forward
) && (parent
!= this)) {
1542 parent
.switchWidget(forward
);
1548 if (activeChild
== null) {
1549 if (tabOrder
== 0) {
1550 // We wrapped around
1553 } else if (activeChild
.tabOrder
== tabOrder
) {
1554 // We wrapped around
1557 } while ((!children
.get(tabOrder
).enabled
)
1558 && !(children
.get(tabOrder
) instanceof THScroller
)
1559 && !(children
.get(tabOrder
) instanceof TVScroller
));
1561 if (activeChild
!= null) {
1562 assert (children
.get(tabOrder
).enabled
);
1564 activeChild
.active
= false;
1566 if (children
.get(tabOrder
).enabled
== true) {
1567 children
.get(tabOrder
).active
= true;
1568 activeChild
= children
.get(tabOrder
);
1573 * Returns my active widget.
1575 * @return widget that is active, or this if no children
1577 public TWidget
getActiveChild() {
1578 if ((this instanceof THScroller
)
1579 || (this instanceof TVScroller
)
1584 for (TWidget widget
: children
) {
1585 if (widget
.active
) {
1586 return widget
.getActiveChild();
1589 // No active children, return me
1594 * Insert a vertical split between this widget and parent, and optionally
1595 * put another widget in the other side of the split.
1597 * @param newWidgetOnLeft if true, the new widget (if specified) will be
1598 * on the left pane, and this widget will be placed on the right pane
1599 * @param newWidget the new widget to add to the other pane, or null
1600 * @return the new split pane widget
1602 public TSplitPane
splitVertical(final boolean newWidgetOnLeft
,
1603 final TWidget newWidget
) {
1605 TSplitPane splitPane
= new TSplitPane(null, x
, y
, width
, height
, true);
1606 TWidget myParent
= parent
;
1608 if (myParent
instanceof TSplitPane
) {
1609 // TSplitPane has a left/right/top/bottom link to me somewhere,
1610 // replace it with a link to splitPane.
1611 ((TSplitPane
) myParent
).replaceWidget(this, splitPane
);
1613 splitPane
.setParent(myParent
, false);
1614 if (newWidgetOnLeft
) {
1615 splitPane
.setLeft(newWidget
);
1616 splitPane
.setRight(this);
1618 splitPane
.setLeft(this);
1619 splitPane
.setRight(newWidget
);
1621 if (newWidget
!= null) {
1622 newWidget
.activateAll();
1627 assert (parent
!= null);
1628 assert (window
!= null);
1629 assert (splitPane
.getWindow() != null);
1630 assert (splitPane
.getParent() != null);
1631 assert (splitPane
.isActive() == true);
1632 assert (parent
== splitPane
);
1633 if (newWidget
!= null) {
1634 assert (newWidget
.parent
== parent
);
1635 assert (newWidget
.active
== true);
1636 assert (active
== false);
1638 assert (active
== true);
1644 * Insert a horizontal split between this widget and parent, and
1645 * optionally put another widget in the other side of the split.
1647 * @param newWidgetOnTop if true, the new widget (if specified) will be
1648 * on the top pane, and this widget's children will be placed on the
1650 * @param newWidget the new widget to add to the other pane, or null
1651 * @return the new split pane widget
1653 public TSplitPane
splitHorizontal(final boolean newWidgetOnTop
,
1654 final TWidget newWidget
) {
1656 TSplitPane splitPane
= new TSplitPane(null, x
, y
, width
, height
, false);
1657 TWidget myParent
= parent
;
1659 if (myParent
instanceof TSplitPane
) {
1660 // TSplitPane has a left/right/top/bottom link to me somewhere,
1661 // replace it with a link to splitPane.
1662 ((TSplitPane
) myParent
).replaceWidget(this, splitPane
);
1664 splitPane
.setParent(myParent
, false);
1665 if (newWidgetOnTop
) {
1666 splitPane
.setTop(newWidget
);
1667 splitPane
.setBottom(this);
1669 splitPane
.setTop(this);
1670 splitPane
.setBottom(newWidget
);
1672 if (newWidget
!= null) {
1673 newWidget
.activateAll();
1678 assert (parent
!= null);
1679 assert (window
!= null);
1680 assert (splitPane
.getWindow() != null);
1681 assert (splitPane
.getParent() != null);
1682 assert (splitPane
.isActive() == true);
1683 assert (parent
== splitPane
);
1684 if (newWidget
!= null) {
1685 assert (newWidget
.parent
== parent
);
1686 assert (newWidget
.active
== true);
1687 assert (active
== false);
1689 assert (active
== true);
1695 * Generate a human-readable string for this widget.
1697 * @return a human-readable string
1700 public String
toString() {
1701 return String
.format("%s(%8x) position (%d, %d) geometry %dx%d " +
1702 "active %s enabled %s visible %s", getClass().getName(),
1703 hashCode(), x
, y
, width
, height
, active
, enabled
, visible
);
1707 * Generate a string for this widget's hierarchy.
1709 * @param prefix a prefix to use for this widget's place in the hierarchy
1710 * @return a pretty-printable string of this hierarchy
1712 protected String
toPrettyString(final String prefix
) {
1713 StringBuilder sb
= new StringBuilder(prefix
);
1714 sb
.append(toString());
1715 String newPrefix
= "";
1716 for (int i
= 0; i
< prefix
.length(); i
++) {
1719 for (int i
= 0; i
< children
.size(); i
++) {
1720 TWidget child
= children
.get(i
);
1722 if (i
== children
.size() - 1) {
1723 sb
.append(child
.toPrettyString(newPrefix
+ " \u2514\u2500"));
1725 sb
.append(child
.toPrettyString(newPrefix
+ " \u251c\u2500"));
1728 return sb
.toString();
1732 * Generate a string for this widget's hierarchy.
1734 * @return a pretty-printable string of this hierarchy
1736 public String
toPrettyString() {
1737 return toPrettyString("");
1740 // ------------------------------------------------------------------------
1741 // Passthru for Screen functions ------------------------------------------
1742 // ------------------------------------------------------------------------
1745 * Get the attributes at one location.
1747 * @param x column coordinate. 0 is the left-most column.
1748 * @param y row coordinate. 0 is the top-most row.
1749 * @return attributes at (x, y)
1751 protected final CellAttributes
getAttrXY(final int x
, final int y
) {
1752 return getScreen().getAttrXY(x
, y
);
1756 * Set the attributes at one location.
1758 * @param x column coordinate. 0 is the left-most column.
1759 * @param y row coordinate. 0 is the top-most row.
1760 * @param attr attributes to use (bold, foreColor, backColor)
1762 protected final void putAttrXY(final int x
, final int y
,
1763 final CellAttributes attr
) {
1765 getScreen().putAttrXY(x
, y
, attr
);
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)
1774 * @param clip if true, honor clipping/offset
1776 protected final void putAttrXY(final int x
, final int y
,
1777 final CellAttributes attr
, final boolean clip
) {
1779 getScreen().putAttrXY(x
, y
, attr
, clip
);
1783 * Fill the entire screen with one character with attributes.
1785 * @param ch character to draw
1786 * @param attr attributes to use (bold, foreColor, backColor)
1788 protected final void putAll(final int ch
, final CellAttributes attr
) {
1789 getScreen().putAll(ch
, attr
);
1793 * Render one character with attributes.
1795 * @param x column coordinate. 0 is the left-most column.
1796 * @param y row coordinate. 0 is the top-most row.
1797 * @param ch character + attributes to draw
1799 protected final void putCharXY(final int x
, final int y
, final Cell ch
) {
1800 getScreen().putCharXY(x
, y
, ch
);
1804 * Render one character with attributes.
1806 * @param x column coordinate. 0 is the left-most column.
1807 * @param y row coordinate. 0 is the top-most row.
1808 * @param ch character to draw
1809 * @param attr attributes to use (bold, foreColor, backColor)
1811 protected final void putCharXY(final int x
, final int y
, final int ch
,
1812 final CellAttributes attr
) {
1814 getScreen().putCharXY(x
, y
, ch
, attr
);
1818 * Render one character without changing the underlying attributes.
1820 * @param x column coordinate. 0 is the left-most column.
1821 * @param y row coordinate. 0 is the top-most row.
1822 * @param ch character to draw
1824 protected final void putCharXY(final int x
, final int y
, final int ch
) {
1825 getScreen().putCharXY(x
, y
, ch
);
1829 * Render a string. Does not wrap if the string exceeds the line.
1831 * @param x column coordinate. 0 is the left-most column.
1832 * @param y row coordinate. 0 is the top-most row.
1833 * @param str string to draw
1834 * @param attr attributes to use (bold, foreColor, backColor)
1836 protected final void putStringXY(final int x
, final int y
, final String str
,
1837 final CellAttributes attr
) {
1839 getScreen().putStringXY(x
, y
, str
, attr
);
1843 * Render a string without changing the underlying attribute. Does not
1844 * wrap if the string exceeds the line.
1846 * @param x column coordinate. 0 is the left-most column.
1847 * @param y row coordinate. 0 is the top-most row.
1848 * @param str string to draw
1850 protected final void putStringXY(final int x
, final int y
, final String str
) {
1851 getScreen().putStringXY(x
, y
, str
);
1855 * Draw a vertical line from (x, y) to (x, y + n).
1857 * @param x column coordinate. 0 is the left-most column.
1858 * @param y row coordinate. 0 is the top-most row.
1859 * @param n number of characters to draw
1860 * @param ch character to draw
1861 * @param attr attributes to use (bold, foreColor, backColor)
1863 protected final void vLineXY(final int x
, final int y
, final int n
,
1864 final int ch
, final CellAttributes attr
) {
1866 getScreen().vLineXY(x
, y
, n
, ch
, attr
);
1870 * Draw a horizontal line from (x, y) to (x + n, y).
1872 * @param x column coordinate. 0 is the left-most column.
1873 * @param y row coordinate. 0 is the top-most row.
1874 * @param n number of characters to draw
1875 * @param ch character to draw
1876 * @param attr attributes to use (bold, foreColor, backColor)
1878 protected final void hLineXY(final int x
, final int y
, final int n
,
1879 final int ch
, final CellAttributes attr
) {
1881 getScreen().hLineXY(x
, y
, n
, ch
, attr
);
1885 * Draw a box with a border and empty background.
1887 * @param left left column of box. 0 is the left-most row.
1888 * @param top top row of the box. 0 is the top-most row.
1889 * @param right right column of box
1890 * @param bottom bottom row of the box
1891 * @param border attributes to use for the border
1892 * @param background attributes to use for the background
1894 protected final void drawBox(final int left
, final int top
,
1895 final int right
, final int bottom
,
1896 final CellAttributes border
, final CellAttributes background
) {
1898 getScreen().drawBox(left
, top
, right
, bottom
, border
, background
);
1902 * Draw a box with a border and empty background.
1904 * @param left left column of box. 0 is the left-most row.
1905 * @param top top row of the box. 0 is the top-most row.
1906 * @param right right column of box
1907 * @param bottom bottom row of the box
1908 * @param border attributes to use for the border
1909 * @param background attributes to use for the background
1910 * @param borderType if 1, draw a single-line border; if 2, draw a
1911 * double-line border; if 3, draw double-line top/bottom edges and
1912 * single-line left/right edges (like Qmodem)
1913 * @param shadow if true, draw a "shadow" on the box
1915 protected final void drawBox(final int left
, final int top
,
1916 final int right
, final int bottom
,
1917 final CellAttributes border
, final CellAttributes background
,
1918 final int borderType
, final boolean shadow
) {
1920 getScreen().drawBox(left
, top
, right
, bottom
, border
, background
,
1921 borderType
, shadow
);
1925 * Draw a box shadow.
1927 * @param left left column of box. 0 is the left-most row.
1928 * @param top top row of the box. 0 is the top-most row.
1929 * @param right right column of box
1930 * @param bottom bottom row of the box
1932 protected final void drawBoxShadow(final int left
, final int top
,
1933 final int right
, final int bottom
) {
1935 getScreen().drawBoxShadow(left
, top
, right
, bottom
);
1938 // ------------------------------------------------------------------------
1939 // Other TWidget constructors ---------------------------------------------
1940 // ------------------------------------------------------------------------
1943 * Convenience function to add a label to this container/window.
1946 * @param x column relative to parent
1947 * @param y row relative to parent
1948 * @return the new label
1950 public final TLabel
addLabel(final String text
, final int x
, final int y
) {
1951 return addLabel(text
, x
, y
, "tlabel");
1955 * Convenience function to add a label to this container/window.
1958 * @param x column relative to parent
1959 * @param y row relative to parent
1960 * @param action to call when shortcut is pressed
1961 * @return the new label
1963 public final TLabel
addLabel(final String text
, final int x
, final int y
,
1964 final TAction action
) {
1966 return addLabel(text
, x
, y
, "tlabel", action
);
1970 * Convenience function to add a label to this container/window.
1973 * @param x column relative to parent
1974 * @param y row relative to parent
1975 * @param colorKey ColorTheme key color to use for foreground text.
1976 * Default is "tlabel"
1977 * @return the new label
1979 public final TLabel
addLabel(final String text
, final int x
, final int y
,
1980 final String colorKey
) {
1982 return new TLabel(this, text
, x
, y
, colorKey
);
1986 * Convenience function to add a label to this container/window.
1989 * @param x column relative to parent
1990 * @param y row relative to parent
1991 * @param colorKey ColorTheme key color to use for foreground text.
1992 * Default is "tlabel"
1993 * @param action to call when shortcut is pressed
1994 * @return the new label
1996 public final TLabel
addLabel(final String text
, final int x
, final int y
,
1997 final String colorKey
, final TAction action
) {
1999 return new TLabel(this, text
, x
, y
, colorKey
, action
);
2003 * Convenience function to add a label to this container/window.
2006 * @param x column relative to parent
2007 * @param y row relative to parent
2008 * @param colorKey ColorTheme key color to use for foreground text.
2009 * Default is "tlabel"
2010 * @param useWindowBackground if true, use the window's background color
2011 * @return the new label
2013 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2014 final String colorKey
, final boolean useWindowBackground
) {
2016 return new TLabel(this, text
, x
, y
, colorKey
, useWindowBackground
);
2020 * Convenience function to add a label to this container/window.
2023 * @param x column relative to parent
2024 * @param y row relative to parent
2025 * @param colorKey ColorTheme key color to use for foreground text.
2026 * Default is "tlabel"
2027 * @param useWindowBackground if true, use the window's background color
2028 * @param action to call when shortcut is pressed
2029 * @return the new label
2031 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2032 final String colorKey
, final boolean useWindowBackground
,
2033 final TAction action
) {
2035 return new TLabel(this, text
, x
, y
, colorKey
, useWindowBackground
,
2040 * Convenience function to add a button to this container/window.
2042 * @param text label on the button
2043 * @param x column relative to parent
2044 * @param y row relative to parent
2045 * @param action action to call when button is pressed
2046 * @return the new button
2048 public final TButton
addButton(final String text
, final int x
, final int y
,
2049 final TAction action
) {
2051 return new TButton(this, text
, x
, y
, action
);
2055 * Convenience function to add a checkbox to this container/window.
2057 * @param x column relative to parent
2058 * @param y row relative to parent
2059 * @param label label to display next to (right of) the checkbox
2060 * @param checked initial check state
2061 * @return the new checkbox
2063 public final TCheckBox
addCheckBox(final int x
, final int y
,
2064 final String label
, final boolean checked
) {
2066 return new TCheckBox(this, x
, y
, label
, checked
);
2070 * Convenience function to add a combobox to this container/window.
2072 * @param x column relative to parent
2073 * @param y row relative to parent
2074 * @param width visible combobox width, including the down-arrow
2075 * @param values the possible values for the box, shown in the drop-down
2076 * @param valuesIndex the initial index in values, or -1 for no default
2078 * @param maxValuesHeight the maximum height of the values drop-down when
2080 * @param updateAction action to call when a new value is selected from
2081 * the list or enter is pressed in the edit field
2082 * @return the new combobox
2084 public final TComboBox
addComboBox(final int x
, final int y
,
2085 final int width
, final List
<String
> values
, final int valuesIndex
,
2086 final int maxValuesHeight
, final TAction updateAction
) {
2088 return new TComboBox(this, x
, y
, width
, values
, valuesIndex
,
2089 maxValuesHeight
, updateAction
);
2093 * Convenience function to add a spinner to this container/window.
2095 * @param x column relative to parent
2096 * @param y row relative to parent
2097 * @param upAction action to call when the up arrow is clicked or pressed
2098 * @param downAction action to call when the down arrow is clicked or
2100 * @return the new spinner
2102 public final TSpinner
addSpinner(final int x
, final int y
,
2103 final TAction upAction
, final TAction downAction
) {
2105 return new TSpinner(this, x
, y
, upAction
, downAction
);
2109 * Convenience function to add a calendar to this container/window.
2111 * @param x column relative to parent
2112 * @param y row relative to parent
2113 * @param updateAction action to call when the user changes the value of
2115 * @return the new calendar
2117 public final TCalendar
addCalendar(final int x
, final int y
,
2118 final TAction updateAction
) {
2120 return new TCalendar(this, x
, y
, updateAction
);
2124 * Convenience function to add a progress bar to this container/window.
2126 * @param x column relative to parent
2127 * @param y row relative to parent
2128 * @param width width of progress bar
2129 * @param value initial value of percent complete
2130 * @return the new progress bar
2132 public final TProgressBar
addProgressBar(final int x
, final int y
,
2133 final int width
, final int value
) {
2135 return new TProgressBar(this, x
, y
, width
, value
);
2139 * Convenience function to add a radio button group to this
2142 * @param x column relative to parent
2143 * @param y row relative to parent
2144 * @param label label to display on the group box
2145 * @return the new radio button group
2147 public final TRadioGroup
addRadioGroup(final int x
, final int y
,
2148 final String label
) {
2150 return new TRadioGroup(this, x
, y
, label
);
2154 * Convenience function to add a text field to this container/window.
2156 * @param x column relative to parent
2157 * @param y row relative to parent
2158 * @param width visible text width
2159 * @param fixed if true, the text cannot exceed the display width
2160 * @return the new text field
2162 public final TField
addField(final int x
, final int y
,
2163 final int width
, final boolean fixed
) {
2165 return new TField(this, x
, y
, width
, fixed
);
2169 * Convenience function to add a text field to this container/window.
2171 * @param x column relative to parent
2172 * @param y row relative to parent
2173 * @param width visible text width
2174 * @param fixed if true, the text cannot exceed the display width
2175 * @param text initial text, default is empty string
2176 * @return the new text field
2178 public final TField
addField(final int x
, final int y
,
2179 final int width
, final boolean fixed
, final String text
) {
2181 return new TField(this, x
, y
, width
, fixed
, text
);
2185 * Convenience function to add a text field to this container/window.
2187 * @param x column relative to parent
2188 * @param y row relative to parent
2189 * @param width visible text width
2190 * @param fixed if true, the text cannot exceed the display width
2191 * @param text initial text, default is empty string
2192 * @param enterAction function to call when enter key is pressed
2193 * @param updateAction function to call when the text is updated
2194 * @return the new text field
2196 public final TField
addField(final int x
, final int y
,
2197 final int width
, final boolean fixed
, final String text
,
2198 final TAction enterAction
, final TAction updateAction
) {
2200 return new TField(this, x
, y
, width
, fixed
, text
, enterAction
,
2205 * Convenience function to add a scrollable text box to this
2208 * @param text text on the screen
2209 * @param x column relative to parent
2210 * @param y row relative to parent
2211 * @param width width of text area
2212 * @param height height of text area
2213 * @param colorKey ColorTheme key color to use for foreground text
2214 * @return the new text box
2216 public final TText
addText(final String text
, final int x
,
2217 final int y
, final int width
, final int height
, final String colorKey
) {
2219 return new TText(this, text
, x
, y
, width
, height
, colorKey
);
2223 * Convenience function to add a scrollable text box to this
2226 * @param text text on the screen
2227 * @param x column relative to parent
2228 * @param y row relative to parent
2229 * @param width width of text area
2230 * @param height height of text area
2231 * @return the new text box
2233 public final TText
addText(final String text
, final int x
, final int y
,
2234 final int width
, final int height
) {
2236 return new TText(this, text
, x
, y
, width
, height
, "ttext");
2240 * Convenience function to add an editable text area box to this
2243 * @param text text on the screen
2244 * @param x column relative to parent
2245 * @param y row relative to parent
2246 * @param width width of text area
2247 * @param height height of text area
2248 * @return the new text box
2250 public final TEditorWidget
addEditor(final String text
, final int x
,
2251 final int y
, final int width
, final int height
) {
2253 return new TEditorWidget(this, text
, x
, y
, width
, height
);
2257 * Convenience function to spawn a message box.
2259 * @param title window title, will be centered along the top border
2260 * @param caption message to display. Use embedded newlines to get a
2262 * @return the new message box
2264 public final TMessageBox
messageBox(final String title
,
2265 final String caption
) {
2267 return getApplication().messageBox(title
, caption
, TMessageBox
.Type
.OK
);
2271 * Convenience function to spawn a message box.
2273 * @param title window title, will be centered along the top border
2274 * @param caption message to display. Use embedded newlines to get a
2276 * @param type one of the TMessageBox.Type constants. Default is
2278 * @return the new message box
2280 public final TMessageBox
messageBox(final String title
,
2281 final String caption
, final TMessageBox
.Type type
) {
2283 return getApplication().messageBox(title
, caption
, type
);
2287 * Convenience function to spawn an input box.
2289 * @param title window title, will be centered along the top border
2290 * @param caption message to display. Use embedded newlines to get a
2292 * @return the new input box
2294 public final TInputBox
inputBox(final String title
, final String caption
) {
2296 return getApplication().inputBox(title
, caption
);
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 * @param text initial text to seed the field with
2306 * @return the new input box
2308 public final TInputBox
inputBox(final String title
, final String caption
,
2309 final String text
) {
2311 return getApplication().inputBox(title
, caption
, text
);
2315 * Convenience function to spawn an input box.
2317 * @param title window title, will be centered along the top border
2318 * @param caption message to display. Use embedded newlines to get a
2320 * @param text initial text to seed the field with
2321 * @param type one of the Type constants. Default is Type.OK.
2322 * @return the new input box
2324 public final TInputBox
inputBox(final String title
, final String caption
,
2325 final String text
, final TInputBox
.Type type
) {
2327 return getApplication().inputBox(title
, caption
, text
, type
);
2331 * Convenience function to add a password text field to this
2334 * @param x column relative to parent
2335 * @param y row relative to parent
2336 * @param width visible text width
2337 * @param fixed if true, the text cannot exceed the display width
2338 * @return the new text field
2340 public final TPasswordField
addPasswordField(final int x
, final int y
,
2341 final int width
, final boolean fixed
) {
2343 return new TPasswordField(this, x
, y
, width
, fixed
);
2347 * Convenience function to add a password text field to this
2350 * @param x column relative to parent
2351 * @param y row relative to parent
2352 * @param width visible text width
2353 * @param fixed if true, the text cannot exceed the display width
2354 * @param text initial text, default is empty string
2355 * @return the new text field
2357 public final TPasswordField
addPasswordField(final int x
, final int y
,
2358 final int width
, final boolean fixed
, final String text
) {
2360 return new TPasswordField(this, x
, y
, width
, fixed
, text
);
2364 * Convenience function to add a password text field to this
2367 * @param x column relative to parent
2368 * @param y row relative to parent
2369 * @param width visible text width
2370 * @param fixed if true, the text cannot exceed the display width
2371 * @param text initial text, default is empty string
2372 * @param enterAction function to call when enter key is pressed
2373 * @param updateAction function to call when the text is updated
2374 * @return the new text field
2376 public final TPasswordField
addPasswordField(final int x
, final int y
,
2377 final int width
, final boolean fixed
, final String text
,
2378 final TAction enterAction
, final TAction updateAction
) {
2380 return new TPasswordField(this, x
, y
, width
, fixed
, text
, enterAction
,
2385 * Convenience function to add a scrollable tree view to this
2388 * @param x column relative to parent
2389 * @param y row relative to parent
2390 * @param width width of tree view
2391 * @param height height of tree view
2392 * @return the new tree view
2394 public final TTreeViewWidget
addTreeViewWidget(final int x
, final int y
,
2395 final int width
, final int height
) {
2397 return new TTreeViewWidget(this, x
, y
, width
, height
);
2401 * Convenience function to add a scrollable tree view to this
2404 * @param x column relative to parent
2405 * @param y row relative to parent
2406 * @param width width of tree view
2407 * @param height height of tree view
2408 * @param action action to perform when an item is selected
2409 * @return the new tree view
2411 public final TTreeViewWidget
addTreeViewWidget(final int x
, final int y
,
2412 final int width
, final int height
, final TAction action
) {
2414 return new TTreeViewWidget(this, x
, y
, width
, height
, action
);
2418 * Convenience function to spawn a file open box.
2420 * @param path path of selected file
2421 * @return the result of the new file open box
2422 * @throws IOException if a java.io operation throws
2424 public final String
fileOpenBox(final String path
) throws IOException
{
2425 return getApplication().fileOpenBox(path
);
2429 * Convenience function to spawn a file save box.
2431 * @param path path of selected file
2432 * @return the result of the new file open box
2433 * @throws IOException if a java.io operation throws
2435 public final String
fileSaveBox(final String path
) throws IOException
{
2436 return getApplication().fileOpenBox(path
, TFileOpenBox
.Type
.SAVE
);
2440 * Convenience function to spawn a file open box.
2442 * @param path path of selected file
2443 * @param type one of the Type constants
2444 * @return the result of the new file open box
2445 * @throws IOException if a java.io operation throws
2447 public final String
fileOpenBox(final String path
,
2448 final TFileOpenBox
.Type type
) throws IOException
{
2450 return getApplication().fileOpenBox(path
, type
);
2454 * Convenience function to spawn a file open box.
2456 * @param path path of selected file
2457 * @param type one of the Type constants
2458 * @param filter a string that files must match to be displayed
2459 * @return the result of the new file open box
2460 * @throws IOException of a java.io operation throws
2462 public final String
fileOpenBox(final String path
,
2463 final TFileOpenBox
.Type type
, final String filter
) throws IOException
{
2465 ArrayList
<String
> filters
= new ArrayList
<String
>();
2466 filters
.add(filter
);
2468 return getApplication().fileOpenBox(path
, type
, filters
);
2472 * Convenience function to spawn a file open box.
2474 * @param path path of selected file
2475 * @param type one of the Type constants
2476 * @param filters a list of strings that files must match to be displayed
2477 * @return the result of the new file open box
2478 * @throws IOException of a java.io operation throws
2480 public final String
fileOpenBox(final String path
,
2481 final TFileOpenBox
.Type type
,
2482 final List
<String
> filters
) throws IOException
{
2484 return getApplication().fileOpenBox(path
, type
, filters
);
2488 * Convenience function to add a directory list to this container/window.
2490 * @param path directory path, must be a directory
2491 * @param x column relative to parent
2492 * @param y row relative to parent
2493 * @param width width of text area
2494 * @param height height of text area
2495 * @return the new directory list
2497 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2498 final int y
, final int width
, final int height
) {
2500 return new TDirectoryList(this, path
, x
, y
, width
, height
, null);
2504 * Convenience function to add a directory list to this container/window.
2506 * @param path directory path, must be a directory
2507 * @param x column relative to parent
2508 * @param y row relative to parent
2509 * @param width width of text area
2510 * @param height height of text area
2511 * @param action action to perform when an item is selected (enter or
2513 * @return the new directory list
2515 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2516 final int y
, final int width
, final int height
, final TAction action
) {
2518 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
);
2522 * Convenience function to add a directory list to this container/window.
2524 * @param path directory path, must be a directory
2525 * @param x column relative to parent
2526 * @param y row relative to parent
2527 * @param width width of text area
2528 * @param height height of text area
2529 * @param action action to perform when an item is selected (enter or
2531 * @param singleClickAction action to perform when an item is selected
2533 * @return the new directory list
2535 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2536 final int y
, final int width
, final int height
, final TAction action
,
2537 final TAction singleClickAction
) {
2539 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
,
2544 * Convenience function to add a directory list to this container/window.
2546 * @param path directory path, must be a directory
2547 * @param x column relative to parent
2548 * @param y row relative to parent
2549 * @param width width of text area
2550 * @param height height of text area
2551 * @param action action to perform when an item is selected (enter or
2553 * @param singleClickAction action to perform when an item is selected
2555 * @param filters a list of strings that files must match to be displayed
2556 * @return the new directory list
2558 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2559 final int y
, final int width
, final int height
, final TAction action
,
2560 final TAction singleClickAction
, final List
<String
> filters
) {
2562 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
,
2563 singleClickAction
, filters
);
2567 * Convenience function to add a list to this container/window.
2569 * @param strings list of strings to show
2570 * @param x column relative to parent
2571 * @param y row relative to parent
2572 * @param width width of text area
2573 * @param height height of text area
2574 * @return the new directory list
2576 public final TList
addList(final List
<String
> strings
, final int x
,
2577 final int y
, final int width
, final int height
) {
2579 return new TList(this, strings
, x
, y
, width
, height
, null);
2583 * Convenience function to add a list to this container/window.
2585 * @param strings list of strings to show
2586 * @param x column relative to parent
2587 * @param y row relative to parent
2588 * @param width width of text area
2589 * @param height height of text area
2590 * @param enterAction action to perform when an item is selected
2591 * @return the new directory list
2593 public final TList
addList(final List
<String
> strings
, final int x
,
2594 final int y
, final int width
, final int height
,
2595 final TAction enterAction
) {
2597 return new TList(this, strings
, x
, y
, width
, height
, enterAction
);
2601 * Convenience function to add a list to this container/window.
2603 * @param strings list of strings to show
2604 * @param x column relative to parent
2605 * @param y row relative to parent
2606 * @param width width of text area
2607 * @param height height of text area
2608 * @param enterAction action to perform when an item is selected
2609 * @param moveAction action to perform when the user navigates to a new
2610 * item with arrow/page keys
2611 * @return the new directory list
2613 public final TList
addList(final List
<String
> strings
, final int x
,
2614 final int y
, final int width
, final int height
,
2615 final TAction enterAction
, final TAction moveAction
) {
2617 return new TList(this, strings
, x
, y
, width
, height
, enterAction
,
2622 * Convenience function to add a list to this container/window.
2624 * @param strings list of strings to show. This is allowed to be null
2625 * and set later with setList() or by subclasses.
2626 * @param x column relative to parent
2627 * @param y row relative to parent
2628 * @param width width of text area
2629 * @param height height of text area
2630 * @param enterAction action to perform when an item is selected
2631 * @param moveAction action to perform when the user navigates to a new
2632 * item with arrow/page keys
2633 * @param singleClickAction action to perform when the user clicks on an
2636 public TList
addList(final List
<String
> strings
, final int x
,
2637 final int y
, final int width
, final int height
,
2638 final TAction enterAction
, final TAction moveAction
,
2639 final TAction singleClickAction
) {
2641 return new TList(this, strings
, x
, y
, width
, height
, enterAction
,
2642 moveAction
, singleClickAction
);
2647 * Convenience function to add an image to this container/window.
2649 * @param x column relative to parent
2650 * @param y row relative to parent
2651 * @param width number of text cells for width of the image
2652 * @param height number of text cells for height of the image
2653 * @param image the image to display
2654 * @param left left column of the image. 0 is the left-most column.
2655 * @param top top row of the image. 0 is the top-most row.
2657 public final TImage
addImage(final int x
, final int y
,
2658 final int width
, final int height
,
2659 final BufferedImage image
, final int left
, final int top
) {
2661 return new TImage(this, x
, y
, width
, height
, image
, left
, top
);
2665 * Convenience function to add an image to this container/window.
2667 * @param x column relative to parent
2668 * @param y row relative to parent
2669 * @param width number of text cells for width of the image
2670 * @param height number of text cells for height of the image
2671 * @param image the image to display
2672 * @param left left column of the image. 0 is the left-most column.
2673 * @param top top row of the image. 0 is the top-most row.
2674 * @param clickAction function to call when mouse is pressed
2676 public final TImage
addImage(final int x
, final int y
,
2677 final int width
, final int height
,
2678 final BufferedImage image
, final int left
, final int top
,
2679 final TAction clickAction
) {
2681 return new TImage(this, x
, y
, width
, height
, image
, left
, top
,
2686 * Convenience function to add an editable 2D data table to this
2689 * @param x column relative to parent
2690 * @param y row relative to parent
2691 * @param width width of widget
2692 * @param height height of widget
2694 public TTableWidget
addTable(final int x
, final int y
, final int width
,
2697 return new TTableWidget(this, x
, y
, width
, height
);
2701 * Convenience function to add an editable 2D data table to this
2704 * @param x column relative to parent
2705 * @param y row relative to parent
2706 * @param width width of widget
2707 * @param height height of widget
2708 * @param gridColumns number of columns in grid
2709 * @param gridRows number of rows in grid
2711 public TTableWidget
addTable(final int x
, final int y
, final int width
,
2712 final int height
, final int gridColumns
, final int gridRows
) {
2714 return new TTableWidget(this, x
, y
, width
, height
, gridColumns
,
2719 * Convenience function to add a panel to this container/window.
2721 * @param x column relative to parent
2722 * @param y row relative to parent
2723 * @param width width of text area
2724 * @param height height of text area
2725 * @return the new panel
2727 public final TPanel
addPanel(final int x
, final int y
, final int width
,
2730 return new TPanel(this, x
, y
, width
, height
);
2734 * Convenience function to add a split pane to this container/window.
2736 * @param x column relative to parent
2737 * @param y row relative to parent
2738 * @param width width of text area
2739 * @param height height of text area
2740 * @param vertical if true, split vertically
2741 * @return the new split pane
2743 public final TSplitPane
addSplitPane(final int x
, final int y
,
2744 final int width
, final int height
, final boolean vertical
) {
2746 return new TSplitPane(this, x
, y
, width
, height
, vertical
);