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(parent
, enabled
, 0, 0, 0, 0);
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
) {
204 throw new IllegalArgumentException("width cannot be negative");
207 throw new IllegalArgumentException("height cannot be negative");
210 this.enabled
= enabled
;
211 children
= new ArrayList
<TWidget
>();
213 // Allow parentless widgets
214 if (parent
!= null) {
215 // Do not add TStatusBars, they are drawn by TApplication.
216 if (this instanceof TStatusBar
) {
217 // We don't add the child to the children list here
218 this.parent
= parent
;
219 this.window
= parent
.window
;
221 parent
.addChild(this);
228 this.height
= height
;
230 if (parent
!= null) {
231 this.window
= parent
.window
;
232 parent
.addChild(this);
237 * Backdoor access for TWindow's constructor. ONLY TWindow USES THIS.
239 * @param window the top-level window
240 * @param x column relative to parent
241 * @param y row relative to parent
242 * @param width width of window
243 * @param height height of window
245 protected final void setupForTWindow(final TWindow window
,
246 final int x
, final int y
, final int width
, final int height
) {
249 throw new IllegalArgumentException("width cannot be negative");
252 throw new IllegalArgumentException("height cannot be negative");
255 this.parent
= window
;
256 this.window
= window
;
260 this.height
= height
;
263 // ------------------------------------------------------------------------
264 // Event handlers ---------------------------------------------------------
265 // ------------------------------------------------------------------------
268 * Subclasses should override this method to cleanup resources. This is
269 * called by TWindow.onClose().
271 protected void close() {
272 // Default: call close() on children.
273 for (TWidget w
: getChildren()) {
279 * Check if a mouse press/release event coordinate is contained in this
282 * @param mouse a mouse-based event
283 * @return whether or not a mouse click would be sent to this widget
285 public final boolean mouseWouldHit(final TMouseEvent mouse
) {
291 if ((this instanceof TTreeItem
)
292 && ((y
< 0) || (y
> parent
.getHeight() - 1))
297 if ((mouse
.getAbsoluteX() >= getAbsoluteX())
298 && (mouse
.getAbsoluteX() < getAbsoluteX() + width
)
299 && (mouse
.getAbsoluteY() >= getAbsoluteY())
300 && (mouse
.getAbsoluteY() < getAbsoluteY() + height
)
308 * Method that subclasses can override to handle keystrokes.
310 * @param keypress keystroke event
312 public void onKeypress(final TKeypressEvent keypress
) {
313 assert (parent
!= null);
315 if ((children
.size() == 0)
316 || (this instanceof TTreeView
)
317 || (this instanceof TText
)
318 || (this instanceof TComboBox
)
322 // tab / shift-tab - switch to next/previous widget
323 // left-arrow or up-arrow: same as shift-tab
324 if ((keypress
.equals(kbTab
))
325 || (keypress
.equals(kbDown
) && !(this instanceof TComboBox
))
327 parent
.switchWidget(true);
329 } else if ((keypress
.equals(kbShiftTab
))
330 || (keypress
.equals(kbBackTab
))
331 || (keypress
.equals(kbUp
) && !(this instanceof TComboBox
))
333 parent
.switchWidget(false);
338 if ((children
.size() == 0)
339 && !(this instanceof TTreeView
)
343 // right-arrow or down-arrow: same as tab
344 if (keypress
.equals(kbRight
)) {
345 parent
.switchWidget(true);
347 } else if (keypress
.equals(kbLeft
)) {
348 parent
.switchWidget(false);
353 // If I have any buttons on me AND this is an Alt-key that matches
354 // its mnemonic, send it an Enter keystroke.
355 for (TWidget widget
: children
) {
356 if (widget
instanceof TButton
) {
357 TButton button
= (TButton
) widget
;
358 if (button
.isEnabled()
359 && !keypress
.getKey().isFnKey()
360 && keypress
.getKey().isAlt()
361 && !keypress
.getKey().isCtrl()
362 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
363 == Character
.toLowerCase(keypress
.getKey().getChar()))
366 widget
.onKeypress(new TKeypressEvent(kbEnter
));
372 // If I have any labels on me AND this is an Alt-key that matches
373 // its mnemonic, call its action.
374 for (TWidget widget
: children
) {
375 if (widget
instanceof TLabel
) {
376 TLabel label
= (TLabel
) widget
;
377 if (!keypress
.getKey().isFnKey()
378 && keypress
.getKey().isAlt()
379 && !keypress
.getKey().isCtrl()
380 && (Character
.toLowerCase(label
.getMnemonic().getShortcut())
381 == Character
.toLowerCase(keypress
.getKey().getChar()))
390 // If I have any radiobuttons on me AND this is an Alt-key that
391 // matches its mnemonic, select it and send a Space to it.
392 for (TWidget widget
: children
) {
393 if (widget
instanceof TRadioButton
) {
394 TRadioButton button
= (TRadioButton
) widget
;
395 if (button
.isEnabled()
396 && !keypress
.getKey().isFnKey()
397 && keypress
.getKey().isAlt()
398 && !keypress
.getKey().isCtrl()
399 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
400 == Character
.toLowerCase(keypress
.getKey().getChar()))
403 widget
.onKeypress(new TKeypressEvent(kbSpace
));
407 if (widget
instanceof TRadioGroup
) {
408 for (TWidget child
: widget
.getChildren()) {
409 if (child
instanceof TRadioButton
) {
410 TRadioButton button
= (TRadioButton
) child
;
411 if (button
.isEnabled()
412 && !keypress
.getKey().isFnKey()
413 && keypress
.getKey().isAlt()
414 && !keypress
.getKey().isCtrl()
415 && (Character
.toLowerCase(button
.getMnemonic().getShortcut())
416 == Character
.toLowerCase(keypress
.getKey().getChar()))
419 widget
.activate(child
);
420 child
.onKeypress(new TKeypressEvent(kbSpace
));
428 // If I have any checkboxes on me AND this is an Alt-key that matches
429 // its mnemonic, select it and set it to checked.
430 for (TWidget widget
: children
) {
431 if (widget
instanceof TCheckBox
) {
432 TCheckBox checkBox
= (TCheckBox
) widget
;
433 if (checkBox
.isEnabled()
434 && !keypress
.getKey().isFnKey()
435 && keypress
.getKey().isAlt()
436 && !keypress
.getKey().isCtrl()
437 && (Character
.toLowerCase(checkBox
.getMnemonic().getShortcut())
438 == Character
.toLowerCase(keypress
.getKey().getChar()))
441 checkBox
.setChecked(true);
447 // Dispatch the keypress to an active widget
448 for (TWidget widget
: children
) {
450 widget
.onKeypress(keypress
);
457 * Method that subclasses can override to handle mouse button presses.
459 * @param mouse mouse button event
461 public void onMouseDown(final TMouseEvent mouse
) {
462 // Default: do nothing, pass to children instead
463 if (activeChild
!= null) {
464 if (activeChild
.mouseWouldHit(mouse
)) {
465 // Dispatch to the active child
467 // Set x and y relative to the child's coordinates
468 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
469 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
470 activeChild
.onMouseDown(mouse
);
474 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
475 TWidget widget
= children
.get(i
);
476 if (widget
.mouseWouldHit(mouse
)) {
477 // Dispatch to this child, also activate it
480 // Set x and y relative to the child's coordinates
481 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
482 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
483 widget
.onMouseDown(mouse
);
490 * Method that subclasses can override to handle mouse button releases.
492 * @param mouse mouse button event
494 public void onMouseUp(final TMouseEvent mouse
) {
495 // Default: do nothing, pass to children instead
496 if (activeChild
!= null) {
497 if (activeChild
.mouseWouldHit(mouse
)) {
498 // Dispatch to the active child
500 // Set x and y relative to the child's coordinates
501 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
502 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
503 activeChild
.onMouseUp(mouse
);
507 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
508 TWidget widget
= children
.get(i
);
509 if (widget
.mouseWouldHit(mouse
)) {
510 // Dispatch to this child, also activate it
513 // Set x and y relative to the child's coordinates
514 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
515 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
516 widget
.onMouseUp(mouse
);
523 * Method that subclasses can override to handle mouse movements.
525 * @param mouse mouse motion event
527 public void onMouseMotion(final TMouseEvent mouse
) {
528 // Default: do nothing, pass it on to ALL of my children. This way
529 // the children can see the mouse "leaving" their area.
530 for (TWidget widget
: children
) {
531 // Set x and y relative to the child's coordinates
532 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
533 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
534 widget
.onMouseMotion(mouse
);
539 * Method that subclasses can override to handle mouse button
542 * @param mouse mouse button event
544 public void onMouseDoubleClick(final TMouseEvent mouse
) {
545 // Default: do nothing, pass to children instead
546 if (activeChild
!= null) {
547 if (activeChild
.mouseWouldHit(mouse
)) {
548 // Dispatch to the active child
550 // Set x and y relative to the child's coordinates
551 mouse
.setX(mouse
.getAbsoluteX() - activeChild
.getAbsoluteX());
552 mouse
.setY(mouse
.getAbsoluteY() - activeChild
.getAbsoluteY());
553 activeChild
.onMouseDoubleClick(mouse
);
557 for (int i
= children
.size() - 1 ; i
>= 0 ; i
--) {
558 TWidget widget
= children
.get(i
);
559 if (widget
.mouseWouldHit(mouse
)) {
560 // Dispatch to this child, also activate it
563 // Set x and y relative to the child's coordinates
564 mouse
.setX(mouse
.getAbsoluteX() - widget
.getAbsoluteX());
565 mouse
.setY(mouse
.getAbsoluteY() - widget
.getAbsoluteY());
566 widget
.onMouseDoubleClick(mouse
);
573 * Method that subclasses can override to handle window/screen resize
576 * @param resize resize event
578 public void onResize(final TResizeEvent resize
) {
579 // Default: change my width/height.
580 if (resize
.getType() == TResizeEvent
.Type
.WIDGET
) {
581 width
= resize
.getWidth();
582 height
= resize
.getHeight();
583 if (layout
!= null) {
584 if (this instanceof TWindow
) {
585 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
586 width
- 2, height
- 2));
588 layout
.onResize(resize
);
592 // Let children see the screen resize
593 for (TWidget widget
: children
) {
594 widget
.onResize(resize
);
600 * Method that subclasses can override to handle posted command events.
602 * @param command command event
604 public void onCommand(final TCommandEvent command
) {
605 // Default: do nothing, pass to children instead
606 for (TWidget widget
: children
) {
607 widget
.onCommand(command
);
612 * Method that subclasses can override to handle menu or posted menu
615 * @param menu menu event
617 public void onMenu(final TMenuEvent menu
) {
618 // Default: do nothing, pass to children instead
619 for (TWidget widget
: children
) {
625 * Method that subclasses can override to do processing when the UI is
626 * idle. Note that repainting is NOT assumed. To get a refresh after
627 * onIdle, call doRepaint().
629 public void onIdle() {
630 // Default: do nothing, pass to children instead
631 for (TWidget widget
: children
) {
637 * Consume event. Subclasses that want to intercept all events in one go
638 * can override this method.
640 * @param event keyboard, mouse, resize, command, or menu event
642 public void handleEvent(final TInputEvent event
) {
644 System.err.printf("TWidget (%s) event: %s\n", this.getClass().getName(),
650 // System.err.println(" -- discard --");
654 if (event
instanceof TKeypressEvent
) {
655 onKeypress((TKeypressEvent
) event
);
656 } else if (event
instanceof TMouseEvent
) {
658 TMouseEvent mouse
= (TMouseEvent
) event
;
660 switch (mouse
.getType()) {
671 onMouseMotion(mouse
);
674 case MOUSE_DOUBLE_CLICK
:
675 onMouseDoubleClick(mouse
);
679 throw new IllegalArgumentException("Invalid mouse event type: "
682 } else if (event
instanceof TResizeEvent
) {
683 onResize((TResizeEvent
) event
);
684 } else if (event
instanceof TCommandEvent
) {
685 onCommand((TCommandEvent
) event
);
686 } else if (event
instanceof TMenuEvent
) {
687 onMenu((TMenuEvent
) event
);
694 // ------------------------------------------------------------------------
695 // TWidget ----------------------------------------------------------------
696 // ------------------------------------------------------------------------
701 * @return parent widget
703 public final TWidget
getParent() {
708 * Get the list of child widgets that this widget contains.
710 * @return the list of child widgets
712 public List
<TWidget
> getChildren() {
717 * Remove this widget from its parent container. close() will be called
718 * before it is removed.
720 public final void remove() {
725 * Remove this widget from its parent container.
727 * @param doClose if true, call the close() method before removing the
730 public final void remove(final boolean doClose
) {
731 if (parent
!= null) {
732 parent
.remove(this, doClose
);
737 * Remove a child widget from this container.
739 * @param child the child widget to remove
741 public final void remove(final TWidget child
) {
746 * Remove a child widget from this container.
748 * @param child the child widget to remove
749 * @param doClose if true, call the close() method before removing the
752 public final void remove(final TWidget child
, final boolean doClose
) {
753 if (!children
.contains(child
)) {
754 throw new IndexOutOfBoundsException("child widget is not in " +
755 "list of children of this parent");
760 children
.remove(child
);
763 if (layout
!= null) {
769 * Set this widget's parent to a different widget.
771 * @param newParent new parent widget
772 * @param doClose if true, call the close() method before removing the
773 * child from its existing parent widget
775 public final void setParent(final TWidget newParent
,
776 final boolean doClose
) {
778 if (parent
!= null) {
779 parent
.remove(this, doClose
);
782 assert (parent
== null);
783 assert (window
== null);
785 setWindow(parent
.window
);
786 parent
.addChild(this);
790 * Set this widget's window to a specific window.
792 * Having a null parent with a specified window is only used within Jexer
793 * by TStatusBar because TApplication routes events directly to it and
794 * calls its draw() method. Any other non-parented widgets will require
795 * similar special case functionality to receive events or be drawn to
798 * @param window the window to use
800 public final void setWindow(final TWindow window
) {
801 this.window
= window
;
802 for (TWidget child
: getChildren()) {
803 child
.setWindow(window
);
808 * Remove a child widget from this container, and all of its children
809 * recursively from their parent containers.
811 * @param child the child widget to remove
812 * @param doClose if true, call the close() method before removing each
815 public final void removeAll(final TWidget child
, final boolean doClose
) {
816 remove(child
, doClose
);
817 for (TWidget w
: child
.children
) {
818 child
.removeAll(w
, doClose
);
825 * @return if true, this widget will receive events
827 public final boolean isActive() {
834 * @param active if true, this widget will receive events
836 public final void setActive(final boolean active
) {
837 this.active
= active
;
841 * Get the window this widget is on.
845 public final TWindow
getWindow() {
852 * @return absolute X position of the top-left corner
854 public final int getX() {
861 * @param x absolute X position of the top-left corner
863 public final void setX(final int x
) {
870 * @return absolute Y position of the top-left corner
872 public final int getY() {
879 * @param y absolute Y position of the top-left corner
881 public final void setY(final int y
) {
888 * @return widget width
890 public int getWidth() {
897 * @param width new widget width
899 public void setWidth(final int width
) {
901 if (layout
!= null) {
902 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
910 * @return widget height
912 public int getHeight() {
919 * @param height new widget height
921 public void setHeight(final int height
) {
922 this.height
= height
;
923 if (layout
!= null) {
924 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
930 * Change the dimensions.
932 * @param x absolute X position of the top-left corner
933 * @param y absolute Y position of the top-left corner
934 * @param width new widget width
935 * @param height new widget height
937 public final void setDimensions(final int x
, final int y
, final int width
,
942 // Call the functions so that subclasses can choose how to handle it.
945 if (layout
!= null) {
946 layout
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
952 * Get the layout manager.
954 * @return the layout manager, or null if not set
956 public LayoutManager
getLayoutManager() {
961 * Set the layout manager.
963 * @param layout the new layout manager
965 public void setLayoutManager(LayoutManager layout
) {
966 if (this.layout
!= null) {
967 for (TWidget w
: children
) {
968 this.layout
.remove(w
);
972 this.layout
= layout
;
973 if (this.layout
!= null) {
974 for (TWidget w
: children
) {
983 * @return if true, this widget can be tabbed to or receive events
985 public final boolean isEnabled() {
992 * @param enabled if true, this widget can be tabbed to or receive events
994 public final void setEnabled(final boolean enabled
) {
995 this.enabled
= enabled
;
998 // See if there are any active siblings to switch to
999 boolean foundSibling
= false;
1000 if (parent
!= null) {
1001 for (TWidget w
: parent
.children
) {
1003 && !(this instanceof THScroller
)
1004 && !(this instanceof TVScroller
)
1007 foundSibling
= true;
1011 if (!foundSibling
) {
1012 parent
.activeChild
= null;
1021 * @param visible if true, this widget will be drawn
1023 public final void setVisible(final boolean visible
) {
1024 this.visible
= visible
;
1028 * See if this widget is visible.
1030 * @return if true, this widget will be drawn
1032 public final boolean isVisible() {
1037 * Set visible cursor flag.
1039 * @param cursorVisible if true, this widget has a cursor
1041 public final void setCursorVisible(final boolean cursorVisible
) {
1042 this.cursorVisible
= cursorVisible
;
1046 * See if this widget has a visible cursor.
1048 * @return if true, this widget has a visible cursor
1050 public final boolean isCursorVisible() {
1051 // If cursor is out of my bounds, it is not visible.
1052 if ((cursorX
>= width
)
1054 || (cursorY
>= height
)
1060 assert (window
!= null);
1062 if (window
instanceof TDesktop
) {
1063 // Desktop doesn't have a window border.
1064 return cursorVisible
;
1067 // If cursor is out of my window's bounds, it is not visible.
1068 if ((getCursorAbsoluteX() >= window
.getAbsoluteX()
1069 + window
.getWidth() - 1)
1070 || (getCursorAbsoluteX() < 0)
1071 || (getCursorAbsoluteY() >= window
.getAbsoluteY()
1072 + window
.getHeight() - 1)
1073 || (getCursorAbsoluteY() < 0)
1077 return cursorVisible
;
1081 * Get cursor X value.
1083 * @return cursor column position in relative coordinates
1085 public final int getCursorX() {
1090 * Set cursor X value.
1092 * @param cursorX column position in relative coordinates
1094 public final void setCursorX(final int cursorX
) {
1095 this.cursorX
= cursorX
;
1099 * Get cursor Y value.
1101 * @return cursor row position in relative coordinates
1103 public final int getCursorY() {
1108 * Set cursor Y value.
1110 * @param cursorY row position in relative coordinates
1112 public final void setCursorY(final int cursorY
) {
1113 this.cursorY
= cursorY
;
1117 * Get this TWidget's parent TApplication.
1119 * @return the parent TApplication, or null if not assigned
1121 public TApplication
getApplication() {
1122 if (window
!= null) {
1123 return window
.getApplication();
1131 * @return the Screen, or null if not assigned
1133 public Screen
getScreen() {
1134 if (window
!= null) {
1135 return window
.getScreen();
1141 * Comparison operator. For various subclasses it sorts on:
1143 * <li>tabOrder for TWidgets</li>
1144 * <li>z for TWindows</li>
1145 * <li>text for TTreeItems</li>
1148 * @param that another TWidget, TWindow, or TTreeItem instance
1149 * @return difference between this.tabOrder and that.tabOrder, or
1150 * difference between this.z and that.z, or String.compareTo(text)
1153 public final int compareTo(final TWidget that
) {
1154 if ((this instanceof TWindow
)
1155 && (that
instanceof TWindow
)
1157 return (((TWindow
) this).getZ() - ((TWindow
) that
).getZ());
1159 if ((this instanceof TTreeItem
)
1160 && (that
instanceof TTreeItem
)
1162 return (((TTreeItem
) this).getText().compareTo(
1163 ((TTreeItem
) that
).getText()));
1165 return (this.tabOrder
- that
.tabOrder
);
1169 * See if this widget should render with the active color.
1171 * @return true if this widget is active and all of its parents are
1174 public final boolean isAbsoluteActive() {
1175 if (parent
== this) {
1178 return (active
&& (parent
== null ?
true : parent
.isAbsoluteActive()));
1182 * Returns the cursor X position.
1184 * @return absolute screen column number for the cursor's X position
1186 public final int getCursorAbsoluteX() {
1187 return getAbsoluteX() + cursorX
;
1191 * Returns the cursor Y position.
1193 * @return absolute screen row number for the cursor's Y position
1195 public final int getCursorAbsoluteY() {
1196 return getAbsoluteY() + cursorY
;
1200 * Compute my absolute X position as the sum of my X plus all my parent's
1203 * @return absolute screen column number for my X position
1205 public final int getAbsoluteX() {
1206 assert (parent
!= null);
1207 if (parent
== this) {
1210 if ((parent
instanceof TWindow
)
1211 && !(parent
instanceof TMenu
)
1212 && !(parent
instanceof TDesktop
)
1214 // Widgets on a TWindow have (0,0) as their top-left, but this is
1215 // actually the TWindow's (1,1).
1216 return parent
.getAbsoluteX() + x
+ 1;
1218 return parent
.getAbsoluteX() + x
;
1222 * Compute my absolute Y position as the sum of my Y plus all my parent's
1225 * @return absolute screen row number for my Y position
1227 public final int getAbsoluteY() {
1228 assert (parent
!= null);
1229 if (parent
== this) {
1232 if ((parent
instanceof TWindow
)
1233 && !(parent
instanceof TMenu
)
1234 && !(parent
instanceof TDesktop
)
1236 // Widgets on a TWindow have (0,0) as their top-left, but this is
1237 // actually the TWindow's (1,1).
1238 return parent
.getAbsoluteY() + y
+ 1;
1240 return parent
.getAbsoluteY() + y
;
1244 * Get the global color theme.
1246 * @return the ColorTheme
1248 protected final ColorTheme
getTheme() {
1249 return window
.getApplication().getTheme();
1253 * See if this widget can be drawn onto a screen.
1255 * @return true if this widget is part of the hierarchy that can draw to
1258 public final boolean isDrawable() {
1259 if ((window
== null)
1260 || (window
.getScreen() == null)
1265 if (parent
== this) {
1268 return (parent
.isDrawable());
1272 * Draw my specific widget. When called, the screen rectangle I draw
1273 * into is already setup (offset and clipping).
1275 public void draw() {
1276 // Default widget draws nothing.
1280 * Called by parent to render to TWindow. Note package private access.
1282 final void drawChildren() {
1283 if (!isDrawable()) {
1287 // Set my clipping rectangle
1288 assert (window
!= null);
1289 assert (getScreen() != null);
1290 Screen screen
= getScreen();
1292 // Special case: TStatusBar is drawn by TApplication, not anything
1294 if (this instanceof TStatusBar
) {
1298 screen
.setClipRight(width
);
1299 screen
.setClipBottom(height
);
1301 int absoluteRightEdge
= window
.getAbsoluteX() + window
.getWidth();
1302 int absoluteBottomEdge
= window
.getAbsoluteY() + window
.getHeight();
1303 if (!(this instanceof TWindow
)
1304 && !(this instanceof TVScroller
)
1305 && !(window
instanceof TDesktop
)
1307 absoluteRightEdge
-= 1;
1309 if (!(this instanceof TWindow
)
1310 && !(this instanceof THScroller
)
1311 && !(window
instanceof TDesktop
)
1313 absoluteBottomEdge
-= 1;
1315 int myRightEdge
= getAbsoluteX() + width
;
1316 int myBottomEdge
= getAbsoluteY() + height
;
1317 if (getAbsoluteX() > absoluteRightEdge
) {
1319 screen
.setClipRight(0);
1320 } else if (myRightEdge
> absoluteRightEdge
) {
1321 screen
.setClipRight(screen
.getClipRight()
1322 - (myRightEdge
- absoluteRightEdge
));
1324 if (getAbsoluteY() > absoluteBottomEdge
) {
1326 screen
.setClipBottom(0);
1327 } else if (myBottomEdge
> absoluteBottomEdge
) {
1328 screen
.setClipBottom(screen
.getClipBottom()
1329 - (myBottomEdge
- absoluteBottomEdge
));
1333 screen
.setOffsetX(getAbsoluteX());
1334 screen
.setOffsetY(getAbsoluteY());
1338 if (!isDrawable()) {
1339 // An action taken by a draw method unhooked me from the UI.
1344 assert (visible
== true);
1346 // Continue down the chain. Draw the active child last so that it
1348 for (TWidget widget
: children
) {
1349 if (widget
.isVisible() && (widget
!= activeChild
)) {
1350 widget
.drawChildren();
1351 if (!isDrawable()) {
1352 // An action taken by a draw method unhooked me from the UI.
1358 if (activeChild
!= null) {
1359 activeChild
.drawChildren();
1364 * Repaint the screen on the next update.
1366 protected final void doRepaint() {
1367 window
.getApplication().doRepaint();
1371 * Add a child widget to my list of children. We set its tabOrder to 0
1372 * and increment the tabOrder of all other children.
1374 * @param child TWidget to add
1376 private void addChild(final TWidget child
) {
1377 children
.add(child
);
1378 child
.parent
= this;
1379 child
.window
= this.window
;
1382 && !(child
instanceof THScroller
)
1383 && !(child
instanceof TVScroller
)
1385 for (TWidget widget
: children
) {
1386 widget
.active
= false;
1388 child
.active
= true;
1389 activeChild
= child
;
1391 for (int i
= 0; i
< children
.size(); i
++) {
1392 children
.get(i
).tabOrder
= i
;
1394 if (layout
!= null) {
1400 * Reset the tab order of children to match their position in the list.
1401 * Available so that subclasses can re-order their widgets if needed.
1403 protected void resetTabOrder() {
1404 for (int i
= 0; i
< children
.size(); i
++) {
1405 children
.get(i
).tabOrder
= i
;
1410 * Remove and {@link TWidget#close()} the given child from this {@link TWidget}.
1412 * Will also reorder the tab values of the remaining children.
1414 * @param child the child to remove
1416 * @return TRUE if the child was removed, FALSE if it was not found
1418 public boolean removeChild(final TWidget child
) {
1419 if (children
.remove(child
)) {
1421 child
.parent
= null;
1422 child
.window
= null;
1433 * Switch the active child.
1435 * @param child TWidget to activate
1437 public final void activate(final TWidget child
) {
1438 assert (child
.enabled
);
1439 if ((child
instanceof THScroller
)
1440 || (child
instanceof TVScroller
)
1445 if (children
.size() == 1) {
1446 if (children
.get(0).enabled
== true) {
1447 child
.active
= true;
1448 activeChild
= child
;
1451 if (child
!= activeChild
) {
1452 if (activeChild
!= null) {
1453 activeChild
.active
= false;
1455 child
.active
= true;
1456 activeChild
= child
;
1462 * Switch the active child.
1464 * @param tabOrder tabOrder of the child to activate. If that child
1465 * isn't enabled, then the next enabled child will be activated.
1467 public final void activate(final int tabOrder
) {
1468 if (children
.size() == 1) {
1469 if (children
.get(0).enabled
== true) {
1470 children
.get(0).active
= true;
1471 activeChild
= children
.get(0);
1476 TWidget child
= null;
1477 for (TWidget widget
: children
) {
1478 if ((widget
.enabled
)
1479 && !(widget
instanceof THScroller
)
1480 && !(widget
instanceof TVScroller
)
1481 && (widget
.tabOrder
>= tabOrder
)
1487 if ((child
!= null) && (child
!= activeChild
)) {
1488 if (activeChild
!= null) {
1489 activeChild
.active
= false;
1491 assert (child
.enabled
);
1492 child
.active
= true;
1493 activeChild
= child
;
1498 * Make this widget the active child of its parent. Note that this is
1499 * not final since TWindow overrides activate().
1501 public void activate() {
1503 if (parent
!= null) {
1504 parent
.activate(this);
1510 * Make this widget, all of its parents, the active child.
1512 public final void activateAll() {
1514 if (parent
== this) {
1517 if (parent
!= null) {
1518 parent
.activateAll();
1523 * Switch the active widget with the next in the tab order.
1525 * @param forward if true, then switch to the next enabled widget in the
1526 * list, otherwise switch to the previous enabled widget in the list
1528 public final void switchWidget(final boolean forward
) {
1530 // No children: do nothing.
1531 if (children
.size() == 0) {
1535 assert (parent
!= null);
1537 // If there is only one child, make it active if it is enabled.
1538 if (children
.size() == 1) {
1539 if (children
.get(0).enabled
== true) {
1540 activeChild
= children
.get(0);
1541 activeChild
.active
= true;
1543 children
.get(0).active
= false;
1549 // Two or more children: go forward or backward to the next enabled
1552 if (activeChild
!= null) {
1553 tabOrder
= activeChild
.tabOrder
;
1563 // If at the end, pass the switch to my parent.
1564 if ((!forward
) && (parent
!= this)) {
1565 parent
.switchWidget(forward
);
1569 tabOrder
= children
.size() - 1;
1570 } else if (tabOrder
== children
.size()) {
1571 // If at the end, pass the switch to my parent.
1572 if ((forward
) && (parent
!= this)) {
1573 parent
.switchWidget(forward
);
1579 if (activeChild
== null) {
1580 if (tabOrder
== 0) {
1581 // We wrapped around
1584 } else if (activeChild
.tabOrder
== tabOrder
) {
1585 // We wrapped around
1588 } while ((!children
.get(tabOrder
).enabled
)
1589 && !(children
.get(tabOrder
) instanceof THScroller
)
1590 && !(children
.get(tabOrder
) instanceof TVScroller
));
1592 if (activeChild
!= null) {
1593 assert (children
.get(tabOrder
).enabled
);
1595 activeChild
.active
= false;
1597 if (children
.get(tabOrder
).enabled
== true) {
1598 children
.get(tabOrder
).active
= true;
1599 activeChild
= children
.get(tabOrder
);
1604 * Returns my active widget.
1606 * @return widget that is active, or this if no children
1608 public TWidget
getActiveChild() {
1609 if ((this instanceof THScroller
)
1610 || (this instanceof TVScroller
)
1615 for (TWidget widget
: children
) {
1616 if (widget
.active
) {
1617 return widget
.getActiveChild();
1620 // No active children, return me
1625 * Insert a vertical split between this widget and parent, and optionally
1626 * put another widget in the other side of the split.
1628 * @param newWidgetOnLeft if true, the new widget (if specified) will be
1629 * on the left pane, and this widget will be placed on the right pane
1630 * @param newWidget the new widget to add to the other pane, or null
1631 * @return the new split pane widget
1633 public TSplitPane
splitVertical(final boolean newWidgetOnLeft
,
1634 final TWidget newWidget
) {
1636 TSplitPane splitPane
= new TSplitPane(null, x
, y
, width
, height
, true);
1637 TWidget myParent
= parent
;
1639 if (myParent
instanceof TSplitPane
) {
1640 // TSplitPane has a left/right/top/bottom link to me somewhere,
1641 // replace it with a link to splitPane.
1642 ((TSplitPane
) myParent
).replaceWidget(this, splitPane
);
1644 splitPane
.setParent(myParent
, false);
1645 if (newWidgetOnLeft
) {
1646 splitPane
.setLeft(newWidget
);
1647 splitPane
.setRight(this);
1649 splitPane
.setLeft(this);
1650 splitPane
.setRight(newWidget
);
1652 if (newWidget
!= null) {
1653 newWidget
.activateAll();
1658 assert (parent
!= null);
1659 assert (window
!= null);
1660 assert (splitPane
.getWindow() != null);
1661 assert (splitPane
.getParent() != null);
1662 assert (splitPane
.isActive() == true);
1663 assert (parent
== splitPane
);
1664 if (newWidget
!= null) {
1665 assert (newWidget
.parent
== parent
);
1666 assert (newWidget
.active
== true);
1667 assert (active
== false);
1669 assert (active
== true);
1675 * Insert a horizontal split between this widget and parent, and
1676 * optionally put another widget in the other side of the split.
1678 * @param newWidgetOnTop if true, the new widget (if specified) will be
1679 * on the top pane, and this widget's children will be placed on the
1681 * @param newWidget the new widget to add to the other pane, or null
1682 * @return the new split pane widget
1684 public TSplitPane
splitHorizontal(final boolean newWidgetOnTop
,
1685 final TWidget newWidget
) {
1687 TSplitPane splitPane
= new TSplitPane(null, x
, y
, width
, height
, false);
1688 TWidget myParent
= parent
;
1690 if (myParent
instanceof TSplitPane
) {
1691 // TSplitPane has a left/right/top/bottom link to me somewhere,
1692 // replace it with a link to splitPane.
1693 ((TSplitPane
) myParent
).replaceWidget(this, splitPane
);
1695 splitPane
.setParent(myParent
, false);
1696 if (newWidgetOnTop
) {
1697 splitPane
.setTop(newWidget
);
1698 splitPane
.setBottom(this);
1700 splitPane
.setTop(this);
1701 splitPane
.setBottom(newWidget
);
1703 if (newWidget
!= null) {
1704 newWidget
.activateAll();
1709 assert (parent
!= null);
1710 assert (window
!= null);
1711 assert (splitPane
.getWindow() != null);
1712 assert (splitPane
.getParent() != null);
1713 assert (splitPane
.isActive() == true);
1714 assert (parent
== splitPane
);
1715 if (newWidget
!= null) {
1716 assert (newWidget
.parent
== parent
);
1717 assert (newWidget
.active
== true);
1718 assert (active
== false);
1720 assert (active
== true);
1726 * Generate a human-readable string for this widget.
1728 * @return a human-readable string
1731 public String
toString() {
1732 return String
.format("%s(%8x) position (%d, %d) geometry %dx%d " +
1733 "active %s enabled %s visible %s", getClass().getName(),
1734 hashCode(), x
, y
, width
, height
, active
, enabled
, visible
);
1738 * Generate a string for this widget's hierarchy.
1740 * @param prefix a prefix to use for this widget's place in the hierarchy
1741 * @return a pretty-printable string of this hierarchy
1743 protected String
toPrettyString(final String prefix
) {
1744 StringBuilder sb
= new StringBuilder(prefix
);
1745 sb
.append(toString());
1746 String newPrefix
= "";
1747 for (int i
= 0; i
< prefix
.length(); i
++) {
1750 for (int i
= 0; i
< children
.size(); i
++) {
1751 TWidget child
= children
.get(i
);
1753 if (i
== children
.size() - 1) {
1754 sb
.append(child
.toPrettyString(newPrefix
+ " \u2514\u2500"));
1756 sb
.append(child
.toPrettyString(newPrefix
+ " \u251c\u2500"));
1759 return sb
.toString();
1763 * Generate a string for this widget's hierarchy.
1765 * @return a pretty-printable string of this hierarchy
1767 public String
toPrettyString() {
1768 return toPrettyString("");
1771 // ------------------------------------------------------------------------
1772 // Passthru for Screen functions ------------------------------------------
1773 // ------------------------------------------------------------------------
1776 * Get the attributes at one location.
1778 * @param x column coordinate. 0 is the left-most column.
1779 * @param y row coordinate. 0 is the top-most row.
1780 * @return attributes at (x, y)
1782 protected final CellAttributes
getAttrXY(final int x
, final int y
) {
1783 return getScreen().getAttrXY(x
, y
);
1787 * Set the attributes at one location.
1789 * @param x column coordinate. 0 is the left-most column.
1790 * @param y row coordinate. 0 is the top-most row.
1791 * @param attr attributes to use (bold, foreColor, backColor)
1793 protected final void putAttrXY(final int x
, final int y
,
1794 final CellAttributes attr
) {
1796 getScreen().putAttrXY(x
, y
, attr
);
1800 * Set the attributes at one location.
1802 * @param x column coordinate. 0 is the left-most column.
1803 * @param y row coordinate. 0 is the top-most row.
1804 * @param attr attributes to use (bold, foreColor, backColor)
1805 * @param clip if true, honor clipping/offset
1807 protected final void putAttrXY(final int x
, final int y
,
1808 final CellAttributes attr
, final boolean clip
) {
1810 getScreen().putAttrXY(x
, y
, attr
, clip
);
1814 * Fill the entire screen with one character with attributes.
1816 * @param ch character to draw
1817 * @param attr attributes to use (bold, foreColor, backColor)
1819 protected final void putAll(final int ch
, final CellAttributes attr
) {
1820 getScreen().putAll(ch
, attr
);
1824 * Render one character with attributes.
1826 * @param x column coordinate. 0 is the left-most column.
1827 * @param y row coordinate. 0 is the top-most row.
1828 * @param ch character + attributes to draw
1830 protected final void putCharXY(final int x
, final int y
, final Cell ch
) {
1831 getScreen().putCharXY(x
, y
, ch
);
1835 * Render one character with attributes.
1837 * @param x column coordinate. 0 is the left-most column.
1838 * @param y row coordinate. 0 is the top-most row.
1839 * @param ch character to draw
1840 * @param attr attributes to use (bold, foreColor, backColor)
1842 protected final void putCharXY(final int x
, final int y
, final int ch
,
1843 final CellAttributes attr
) {
1845 getScreen().putCharXY(x
, y
, ch
, attr
);
1849 * Render one character without changing the underlying attributes.
1851 * @param x column coordinate. 0 is the left-most column.
1852 * @param y row coordinate. 0 is the top-most row.
1853 * @param ch character to draw
1855 protected final void putCharXY(final int x
, final int y
, final int ch
) {
1856 getScreen().putCharXY(x
, y
, ch
);
1860 * Render a string. Does not wrap if the string exceeds the line.
1862 * @param x column coordinate. 0 is the left-most column.
1863 * @param y row coordinate. 0 is the top-most row.
1864 * @param str string to draw
1865 * @param attr attributes to use (bold, foreColor, backColor)
1867 protected final void putStringXY(final int x
, final int y
, final String str
,
1868 final CellAttributes attr
) {
1870 getScreen().putStringXY(x
, y
, str
, attr
);
1874 * Render a string without changing the underlying attribute. Does not
1875 * wrap if the string exceeds the line.
1877 * @param x column coordinate. 0 is the left-most column.
1878 * @param y row coordinate. 0 is the top-most row.
1879 * @param str string to draw
1881 protected final void putStringXY(final int x
, final int y
, final String str
) {
1882 getScreen().putStringXY(x
, y
, str
);
1886 * Draw a vertical line from (x, y) to (x, y + n).
1888 * @param x column coordinate. 0 is the left-most column.
1889 * @param y row coordinate. 0 is the top-most row.
1890 * @param n number of characters to draw
1891 * @param ch character to draw
1892 * @param attr attributes to use (bold, foreColor, backColor)
1894 protected final void vLineXY(final int x
, final int y
, final int n
,
1895 final int ch
, final CellAttributes attr
) {
1897 getScreen().vLineXY(x
, y
, n
, ch
, attr
);
1901 * Draw a horizontal line from (x, y) to (x + n, y).
1903 * @param x column coordinate. 0 is the left-most column.
1904 * @param y row coordinate. 0 is the top-most row.
1905 * @param n number of characters to draw
1906 * @param ch character to draw
1907 * @param attr attributes to use (bold, foreColor, backColor)
1909 protected final void hLineXY(final int x
, final int y
, final int n
,
1910 final int ch
, final CellAttributes attr
) {
1912 getScreen().hLineXY(x
, y
, n
, ch
, attr
);
1916 * Draw a box with a border and empty background.
1918 * @param left left column of box. 0 is the left-most row.
1919 * @param top top row of the box. 0 is the top-most row.
1920 * @param right right column of box
1921 * @param bottom bottom row of the box
1922 * @param border attributes to use for the border
1923 * @param background attributes to use for the background
1925 protected final void drawBox(final int left
, final int top
,
1926 final int right
, final int bottom
,
1927 final CellAttributes border
, final CellAttributes background
) {
1929 getScreen().drawBox(left
, top
, right
, bottom
, border
, background
);
1933 * Draw a box with a border and empty background.
1935 * @param left left column of box. 0 is the left-most row.
1936 * @param top top row of the box. 0 is the top-most row.
1937 * @param right right column of box
1938 * @param bottom bottom row of the box
1939 * @param border attributes to use for the border
1940 * @param background attributes to use for the background
1941 * @param borderType if 1, draw a single-line border; if 2, draw a
1942 * double-line border; if 3, draw double-line top/bottom edges and
1943 * single-line left/right edges (like Qmodem)
1944 * @param shadow if true, draw a "shadow" on the box
1946 protected final void drawBox(final int left
, final int top
,
1947 final int right
, final int bottom
,
1948 final CellAttributes border
, final CellAttributes background
,
1949 final int borderType
, final boolean shadow
) {
1951 getScreen().drawBox(left
, top
, right
, bottom
, border
, background
,
1952 borderType
, shadow
);
1956 * Draw a box shadow.
1958 * @param left left column of box. 0 is the left-most row.
1959 * @param top top row of the box. 0 is the top-most row.
1960 * @param right right column of box
1961 * @param bottom bottom row of the box
1963 protected final void drawBoxShadow(final int left
, final int top
,
1964 final int right
, final int bottom
) {
1966 getScreen().drawBoxShadow(left
, top
, right
, bottom
);
1969 // ------------------------------------------------------------------------
1970 // Other TWidget constructors ---------------------------------------------
1971 // ------------------------------------------------------------------------
1974 * Convenience function to add a label to this container/window.
1977 * @param x column relative to parent
1978 * @param y row relative to parent
1979 * @return the new label
1981 public final TLabel
addLabel(final String text
, final int x
, final int y
) {
1982 return addLabel(text
, x
, y
, "tlabel");
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 action to call when shortcut is pressed
1992 * @return the new label
1994 public final TLabel
addLabel(final String text
, final int x
, final int y
,
1995 final TAction action
) {
1997 return addLabel(text
, x
, y
, "tlabel", action
);
2001 * Convenience function to add a label to this container/window.
2004 * @param x column relative to parent
2005 * @param y row relative to parent
2006 * @param colorKey ColorTheme key color to use for foreground text.
2007 * Default is "tlabel"
2008 * @return the new label
2010 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2011 final String colorKey
) {
2013 return new TLabel(this, text
, x
, y
, colorKey
);
2017 * Convenience function to add a label to this container/window.
2020 * @param x column relative to parent
2021 * @param y row relative to parent
2022 * @param colorKey ColorTheme key color to use for foreground text.
2023 * Default is "tlabel"
2024 * @param action to call when shortcut is pressed
2025 * @return the new label
2027 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2028 final String colorKey
, final TAction action
) {
2030 return new TLabel(this, text
, x
, y
, colorKey
, action
);
2034 * Convenience function to add a label to this container/window.
2037 * @param x column relative to parent
2038 * @param y row relative to parent
2039 * @param colorKey ColorTheme key color to use for foreground text.
2040 * Default is "tlabel"
2041 * @param useWindowBackground if true, use the window's background color
2042 * @return the new label
2044 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2045 final String colorKey
, final boolean useWindowBackground
) {
2047 return new TLabel(this, text
, x
, y
, colorKey
, useWindowBackground
);
2051 * Convenience function to add a label to this container/window.
2054 * @param x column relative to parent
2055 * @param y row relative to parent
2056 * @param colorKey ColorTheme key color to use for foreground text.
2057 * Default is "tlabel"
2058 * @param useWindowBackground if true, use the window's background color
2059 * @param action to call when shortcut is pressed
2060 * @return the new label
2062 public final TLabel
addLabel(final String text
, final int x
, final int y
,
2063 final String colorKey
, final boolean useWindowBackground
,
2064 final TAction action
) {
2066 return new TLabel(this, text
, x
, y
, colorKey
, useWindowBackground
,
2071 * Convenience function to add a button to this container/window.
2073 * @param text label on the button
2074 * @param x column relative to parent
2075 * @param y row relative to parent
2076 * @param action action to call when button is pressed
2077 * @return the new button
2079 public final TButton
addButton(final String text
, final int x
, final int y
,
2080 final TAction action
) {
2082 return new TButton(this, text
, x
, y
, action
);
2086 * Convenience function to add a checkbox to this container/window.
2088 * @param x column relative to parent
2089 * @param y row relative to parent
2090 * @param label label to display next to (right of) the checkbox
2091 * @param checked initial check state
2092 * @return the new checkbox
2094 public final TCheckBox
addCheckBox(final int x
, final int y
,
2095 final String label
, final boolean checked
) {
2097 return new TCheckBox(this, x
, y
, label
, checked
);
2101 * Convenience function to add a combobox to this container/window.
2103 * @param x column relative to parent
2104 * @param y row relative to parent
2105 * @param width visible combobox width, including the down-arrow
2106 * @param values the possible values for the box, shown in the drop-down
2107 * @param valuesIndex the initial index in values, or -1 for no default
2109 * @param maxValuesHeight the maximum height of the values drop-down when
2111 * @param updateAction action to call when a new value is selected from
2112 * the list or enter is pressed in the edit field
2113 * @return the new combobox
2115 public final TComboBox
addComboBox(final int x
, final int y
,
2116 final int width
, final List
<String
> values
, final int valuesIndex
,
2117 final int maxValuesHeight
, final TAction updateAction
) {
2119 return new TComboBox(this, x
, y
, width
, values
, valuesIndex
,
2120 maxValuesHeight
, updateAction
);
2124 * Convenience function to add a spinner to this container/window.
2126 * @param x column relative to parent
2127 * @param y row relative to parent
2128 * @param upAction action to call when the up arrow is clicked or pressed
2129 * @param downAction action to call when the down arrow is clicked or
2131 * @return the new spinner
2133 public final TSpinner
addSpinner(final int x
, final int y
,
2134 final TAction upAction
, final TAction downAction
) {
2136 return new TSpinner(this, x
, y
, upAction
, downAction
);
2140 * Convenience function to add a calendar to this container/window.
2142 * @param x column relative to parent
2143 * @param y row relative to parent
2144 * @param updateAction action to call when the user changes the value of
2146 * @return the new calendar
2148 public final TCalendar
addCalendar(final int x
, final int y
,
2149 final TAction updateAction
) {
2151 return new TCalendar(this, x
, y
, updateAction
);
2155 * Convenience function to add a progress bar to this container/window.
2157 * @param x column relative to parent
2158 * @param y row relative to parent
2159 * @param width width of progress bar
2160 * @param value initial value of percent complete
2161 * @return the new progress bar
2163 public final TProgressBar
addProgressBar(final int x
, final int y
,
2164 final int width
, final int value
) {
2166 return new TProgressBar(this, x
, y
, width
, value
);
2170 * Convenience function to add a radio button group to this
2173 * @param x column relative to parent
2174 * @param y row relative to parent
2175 * @param label label to display on the group box
2176 * @return the new radio button group
2178 public final TRadioGroup
addRadioGroup(final int x
, final int y
,
2179 final String label
) {
2181 return new TRadioGroup(this, x
, y
, label
);
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 * @return the new text field
2193 public final TField
addField(final int x
, final int y
,
2194 final int width
, final boolean fixed
) {
2196 return new TField(this, x
, y
, width
, fixed
);
2200 * Convenience function to add a text field to this container/window.
2202 * @param x column relative to parent
2203 * @param y row relative to parent
2204 * @param width visible text width
2205 * @param fixed if true, the text cannot exceed the display width
2206 * @param text initial text, default is empty string
2207 * @return the new text field
2209 public final TField
addField(final int x
, final int y
,
2210 final int width
, final boolean fixed
, final String text
) {
2212 return new TField(this, x
, y
, width
, fixed
, text
);
2216 * Convenience function to add a text field to this container/window.
2218 * @param x column relative to parent
2219 * @param y row relative to parent
2220 * @param width visible text width
2221 * @param fixed if true, the text cannot exceed the display width
2222 * @param text initial text, default is empty string
2223 * @param enterAction function to call when enter key is pressed
2224 * @param updateAction function to call when the text is updated
2225 * @return the new text field
2227 public final TField
addField(final int x
, final int y
,
2228 final int width
, final boolean fixed
, final String text
,
2229 final TAction enterAction
, final TAction updateAction
) {
2231 return new TField(this, x
, y
, width
, fixed
, text
, enterAction
,
2236 * Convenience function to add a scrollable text box to this
2239 * @param text text on the screen
2240 * @param x column relative to parent
2241 * @param y row relative to parent
2242 * @param width width of text area
2243 * @param height height of text area
2244 * @param colorKey ColorTheme key color to use for foreground text
2245 * @return the new text box
2247 public final TText
addText(final String text
, final int x
,
2248 final int y
, final int width
, final int height
, final String colorKey
) {
2250 return new TText(this, text
, x
, y
, width
, height
, colorKey
);
2254 * Convenience function to add a scrollable text box to this
2257 * @param text text on the screen
2258 * @param x column relative to parent
2259 * @param y row relative to parent
2260 * @param width width of text area
2261 * @param height height of text area
2262 * @return the new text box
2264 public final TText
addText(final String text
, final int x
, final int y
,
2265 final int width
, final int height
) {
2267 return new TText(this, text
, x
, y
, width
, height
, "ttext");
2271 * Convenience function to add an editable text area box to this
2274 * @param text text on the screen
2275 * @param x column relative to parent
2276 * @param y row relative to parent
2277 * @param width width of text area
2278 * @param height height of text area
2279 * @return the new text box
2281 public final TEditorWidget
addEditor(final String text
, final int x
,
2282 final int y
, final int width
, final int height
) {
2284 return new TEditorWidget(this, text
, x
, y
, width
, height
);
2288 * Convenience function to spawn a message box.
2290 * @param title window title, will be centered along the top border
2291 * @param caption message to display. Use embedded newlines to get a
2293 * @return the new message box
2295 public final TMessageBox
messageBox(final String title
,
2296 final String caption
) {
2298 return getApplication().messageBox(title
, caption
, TMessageBox
.Type
.OK
);
2302 * Convenience function to spawn a message box.
2304 * @param title window title, will be centered along the top border
2305 * @param caption message to display. Use embedded newlines to get a
2307 * @param type one of the TMessageBox.Type constants. Default is
2309 * @return the new message box
2311 public final TMessageBox
messageBox(final String title
,
2312 final String caption
, final TMessageBox
.Type type
) {
2314 return getApplication().messageBox(title
, caption
, type
);
2318 * Convenience function to spawn an input box.
2320 * @param title window title, will be centered along the top border
2321 * @param caption message to display. Use embedded newlines to get a
2323 * @return the new input box
2325 public final TInputBox
inputBox(final String title
, final String caption
) {
2327 return getApplication().inputBox(title
, caption
);
2331 * Convenience function to spawn an input box.
2333 * @param title window title, will be centered along the top border
2334 * @param caption message to display. Use embedded newlines to get a
2336 * @param text initial text to seed the field with
2337 * @return the new input box
2339 public final TInputBox
inputBox(final String title
, final String caption
,
2340 final String text
) {
2342 return getApplication().inputBox(title
, caption
, text
);
2346 * Convenience function to spawn an input box.
2348 * @param title window title, will be centered along the top border
2349 * @param caption message to display. Use embedded newlines to get a
2351 * @param text initial text to seed the field with
2352 * @param type one of the Type constants. Default is Type.OK.
2353 * @return the new input box
2355 public final TInputBox
inputBox(final String title
, final String caption
,
2356 final String text
, final TInputBox
.Type type
) {
2358 return getApplication().inputBox(title
, caption
, text
, type
);
2362 * Convenience function to add a password text field to this
2365 * @param x column relative to parent
2366 * @param y row relative to parent
2367 * @param width visible text width
2368 * @param fixed if true, the text cannot exceed the display width
2369 * @return the new text field
2371 public final TPasswordField
addPasswordField(final int x
, final int y
,
2372 final int width
, final boolean fixed
) {
2374 return new TPasswordField(this, x
, y
, width
, fixed
);
2378 * Convenience function to add a password text field to this
2381 * @param x column relative to parent
2382 * @param y row relative to parent
2383 * @param width visible text width
2384 * @param fixed if true, the text cannot exceed the display width
2385 * @param text initial text, default is empty string
2386 * @return the new text field
2388 public final TPasswordField
addPasswordField(final int x
, final int y
,
2389 final int width
, final boolean fixed
, final String text
) {
2391 return new TPasswordField(this, x
, y
, width
, fixed
, text
);
2395 * Convenience function to add a password text field to this
2398 * @param x column relative to parent
2399 * @param y row relative to parent
2400 * @param width visible text width
2401 * @param fixed if true, the text cannot exceed the display width
2402 * @param text initial text, default is empty string
2403 * @param enterAction function to call when enter key is pressed
2404 * @param updateAction function to call when the text is updated
2405 * @return the new text field
2407 public final TPasswordField
addPasswordField(final int x
, final int y
,
2408 final int width
, final boolean fixed
, final String text
,
2409 final TAction enterAction
, final TAction updateAction
) {
2411 return new TPasswordField(this, x
, y
, width
, fixed
, text
, enterAction
,
2416 * Convenience function to add a scrollable tree view to this
2419 * @param x column relative to parent
2420 * @param y row relative to parent
2421 * @param width width of tree view
2422 * @param height height of tree view
2423 * @return the new tree view
2425 public final TTreeViewWidget
addTreeViewWidget(final int x
, final int y
,
2426 final int width
, final int height
) {
2428 return new TTreeViewWidget(this, x
, y
, width
, height
);
2432 * Convenience function to add a scrollable tree view to this
2435 * @param x column relative to parent
2436 * @param y row relative to parent
2437 * @param width width of tree view
2438 * @param height height of tree view
2439 * @param action action to perform when an item is selected
2440 * @return the new tree view
2442 public final TTreeViewWidget
addTreeViewWidget(final int x
, final int y
,
2443 final int width
, final int height
, final TAction action
) {
2445 return new TTreeViewWidget(this, x
, y
, width
, height
, action
);
2449 * Convenience function to spawn a file open box.
2451 * @param path path of selected file
2452 * @return the result of the new file open box
2453 * @throws IOException if a java.io operation throws
2455 public final String
fileOpenBox(final String path
) throws IOException
{
2456 return getApplication().fileOpenBox(path
);
2460 * Convenience function to spawn a file save box.
2462 * @param path path of selected file
2463 * @return the result of the new file open box
2464 * @throws IOException if a java.io operation throws
2466 public final String
fileSaveBox(final String path
) throws IOException
{
2467 return getApplication().fileOpenBox(path
, TFileOpenBox
.Type
.SAVE
);
2471 * Convenience function to spawn a file open box.
2473 * @param path path of selected file
2474 * @param type one of the Type constants
2475 * @return the result of the new file open box
2476 * @throws IOException if a java.io operation throws
2478 public final String
fileOpenBox(final String path
,
2479 final TFileOpenBox
.Type type
) throws IOException
{
2481 return getApplication().fileOpenBox(path
, type
);
2485 * Convenience function to spawn a file open box.
2487 * @param path path of selected file
2488 * @param type one of the Type constants
2489 * @param filter a string that files must match to be displayed
2490 * @return the result of the new file open box
2491 * @throws IOException of a java.io operation throws
2493 public final String
fileOpenBox(final String path
,
2494 final TFileOpenBox
.Type type
, final String filter
) throws IOException
{
2496 ArrayList
<String
> filters
= new ArrayList
<String
>();
2497 filters
.add(filter
);
2499 return getApplication().fileOpenBox(path
, type
, filters
);
2503 * Convenience function to spawn a file open box.
2505 * @param path path of selected file
2506 * @param type one of the Type constants
2507 * @param filters a list of strings that files must match to be displayed
2508 * @return the result of the new file open box
2509 * @throws IOException of a java.io operation throws
2511 public final String
fileOpenBox(final String path
,
2512 final TFileOpenBox
.Type type
,
2513 final List
<String
> filters
) throws IOException
{
2515 return getApplication().fileOpenBox(path
, type
, filters
);
2519 * Convenience function to add a directory list to this container/window.
2521 * @param path directory path, must be a directory
2522 * @param x column relative to parent
2523 * @param y row relative to parent
2524 * @param width width of text area
2525 * @param height height of text area
2526 * @return the new directory list
2528 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2529 final int y
, final int width
, final int height
) {
2531 return new TDirectoryList(this, path
, x
, y
, width
, height
, null);
2535 * Convenience function to add a directory list to this container/window.
2537 * @param path directory path, must be a directory
2538 * @param x column relative to parent
2539 * @param y row relative to parent
2540 * @param width width of text area
2541 * @param height height of text area
2542 * @param action action to perform when an item is selected (enter or
2544 * @return the new directory list
2546 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2547 final int y
, final int width
, final int height
, final TAction action
) {
2549 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
);
2553 * Convenience function to add a directory list to this container/window.
2555 * @param path directory path, must be a directory
2556 * @param x column relative to parent
2557 * @param y row relative to parent
2558 * @param width width of text area
2559 * @param height height of text area
2560 * @param action action to perform when an item is selected (enter or
2562 * @param singleClickAction action to perform when an item is selected
2564 * @return the new directory list
2566 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2567 final int y
, final int width
, final int height
, final TAction action
,
2568 final TAction singleClickAction
) {
2570 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
,
2575 * Convenience function to add a directory list to this container/window.
2577 * @param path directory path, must be a directory
2578 * @param x column relative to parent
2579 * @param y row relative to parent
2580 * @param width width of text area
2581 * @param height height of text area
2582 * @param action action to perform when an item is selected (enter or
2584 * @param singleClickAction action to perform when an item is selected
2586 * @param filters a list of strings that files must match to be displayed
2587 * @return the new directory list
2589 public final TDirectoryList
addDirectoryList(final String path
, final int x
,
2590 final int y
, final int width
, final int height
, final TAction action
,
2591 final TAction singleClickAction
, final List
<String
> filters
) {
2593 return new TDirectoryList(this, path
, x
, y
, width
, height
, action
,
2594 singleClickAction
, filters
);
2598 * Convenience function to add a list to this container/window.
2600 * @param strings list of strings to show
2601 * @param x column relative to parent
2602 * @param y row relative to parent
2603 * @param width width of text area
2604 * @param height height of text area
2605 * @return the new directory list
2607 public final TList
addList(final List
<String
> strings
, final int x
,
2608 final int y
, final int width
, final int height
) {
2610 return new TList(this, strings
, x
, y
, width
, height
, null);
2614 * Convenience function to add a list to this container/window.
2616 * @param strings list of strings to show
2617 * @param x column relative to parent
2618 * @param y row relative to parent
2619 * @param width width of text area
2620 * @param height height of text area
2621 * @param enterAction action to perform when an item is selected
2622 * @return the new directory list
2624 public final TList
addList(final List
<String
> strings
, final int x
,
2625 final int y
, final int width
, final int height
,
2626 final TAction enterAction
) {
2628 return new TList(this, strings
, x
, y
, width
, height
, enterAction
);
2632 * Convenience function to add a list to this container/window.
2634 * @param strings list of strings to show
2635 * @param x column relative to parent
2636 * @param y row relative to parent
2637 * @param width width of text area
2638 * @param height height of text area
2639 * @param enterAction action to perform when an item is selected
2640 * @param moveAction action to perform when the user navigates to a new
2641 * item with arrow/page keys
2642 * @return the new directory list
2644 public final TList
addList(final List
<String
> strings
, final int x
,
2645 final int y
, final int width
, final int height
,
2646 final TAction enterAction
, final TAction moveAction
) {
2648 return new TList(this, strings
, x
, y
, width
, height
, enterAction
,
2653 * Convenience function to add a list to this container/window.
2655 * @param strings list of strings to show. This is allowed to be null
2656 * and set later with setList() or by subclasses.
2657 * @param x column relative to parent
2658 * @param y row relative to parent
2659 * @param width width of text area
2660 * @param height height of text area
2661 * @param enterAction action to perform when an item is selected
2662 * @param moveAction action to perform when the user navigates to a new
2663 * item with arrow/page keys
2664 * @param singleClickAction action to perform when the user clicks on an
2667 public TList
addList(final List
<String
> strings
, final int x
,
2668 final int y
, final int width
, final int height
,
2669 final TAction enterAction
, final TAction moveAction
,
2670 final TAction singleClickAction
) {
2672 return new TList(this, strings
, x
, y
, width
, height
, enterAction
,
2673 moveAction
, singleClickAction
);
2678 * Convenience function to add an image to this container/window.
2680 * @param x column relative to parent
2681 * @param y row relative to parent
2682 * @param width number of text cells for width of the image
2683 * @param height number of text cells for height of the image
2684 * @param image the image to display
2685 * @param left left column of the image. 0 is the left-most column.
2686 * @param top top row of the image. 0 is the top-most row.
2688 public final TImage
addImage(final int x
, final int y
,
2689 final int width
, final int height
,
2690 final BufferedImage image
, final int left
, final int top
) {
2692 return new TImage(this, x
, y
, width
, height
, image
, left
, top
);
2696 * Convenience function to add an image to this container/window.
2698 * @param x column relative to parent
2699 * @param y row relative to parent
2700 * @param width number of text cells for width of the image
2701 * @param height number of text cells for height of the image
2702 * @param image the image to display
2703 * @param left left column of the image. 0 is the left-most column.
2704 * @param top top row of the image. 0 is the top-most row.
2705 * @param clickAction function to call when mouse is pressed
2707 public final TImage
addImage(final int x
, final int y
,
2708 final int width
, final int height
,
2709 final BufferedImage image
, final int left
, final int top
,
2710 final TAction clickAction
) {
2712 return new TImage(this, x
, y
, width
, height
, image
, left
, top
,
2717 * Convenience function to add an editable 2D data table to this
2720 * @param x column relative to parent
2721 * @param y row relative to parent
2722 * @param width width of widget
2723 * @param height height of widget
2725 public TTableWidget
addTable(final int x
, final int y
, final int width
,
2728 return new TTableWidget(this, x
, y
, width
, height
);
2732 * Convenience function to add an editable 2D data table to this
2735 * @param x column relative to parent
2736 * @param y row relative to parent
2737 * @param width width of widget
2738 * @param height height of widget
2739 * @param gridColumns number of columns in grid
2740 * @param gridRows number of rows in grid
2742 public TTableWidget
addTable(final int x
, final int y
, final int width
,
2743 final int height
, final int gridColumns
, final int gridRows
) {
2745 return new TTableWidget(this, x
, y
, width
, height
, gridColumns
,
2750 * Convenience function to add a panel to this container/window.
2752 * @param x column relative to parent
2753 * @param y row relative to parent
2754 * @param width width of text area
2755 * @param height height of text area
2756 * @return the new panel
2758 public final TPanel
addPanel(final int x
, final int y
, final int width
,
2761 return new TPanel(this, x
, y
, width
, height
);
2765 * Convenience function to add a split pane to this container/window.
2767 * @param x column relative to parent
2768 * @param y row relative to parent
2769 * @param width width of text area
2770 * @param height height of text area
2771 * @param vertical if true, split vertically
2772 * @return the new split pane
2774 public final TSplitPane
addSplitPane(final int x
, final int y
,
2775 final int width
, final int height
, final boolean vertical
) {
2777 return new TSplitPane(this, x
, y
, width
, height
, vertical
);