X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTWidget.java;h=85910abea53e83d203bcda7b450ff1ea489dd2b1;hb=daa4106c096cd4d2b92c3cbae6491edccd25fcc4;hp=e07594997d1b208a4824191030f429a849457dc8;hpb=fca67db090dc7e6476b98b800ce225c2bf60425c;p=fanfix.git diff --git a/src/jexer/TWidget.java b/src/jexer/TWidget.java index e075949..85910ab 100644 --- a/src/jexer/TWidget.java +++ b/src/jexer/TWidget.java @@ -1,4 +1,4 @@ -/** +/* * Jexer - Java Text User Interface * * License: LGPLv3 or later @@ -30,9 +30,11 @@ */ package jexer; +import java.io.IOException; import java.util.List; import java.util.LinkedList; +import jexer.bits.ColorTheme; import jexer.event.TCommandEvent; import jexer.event.TInputEvent; import jexer.event.TKeypressEvent; @@ -40,13 +42,14 @@ import jexer.event.TMenuEvent; import jexer.event.TMouseEvent; import jexer.event.TResizeEvent; import jexer.io.Screen; +import jexer.menu.TMenu; import static jexer.TKeypress.*; /** * TWidget is the base class of all objects that can be drawn on screen or * handle user input events. */ -public abstract class TWidget { +public abstract class TWidget implements Comparable { /** * Every widget has a parent widget that it may be "contained" in. For @@ -55,6 +58,15 @@ public abstract class TWidget { */ private TWidget parent = null; + /** + * Get parent widget. + * + * @return parent widget + */ + public final TWidget getParent() { + return parent; + } + /** * Backdoor access for TWindow's constructor. ONLY TWindow USES THIS. * @@ -75,11 +87,38 @@ public abstract class TWidget { this.height = height; } + /** + * Get this TWidget's parent TApplication. + * + * @return the parent TApplication + */ + public TApplication getApplication() { + return window.getApplication(); + } + + /** + * Get the Screen. + * + * @return the Screen + */ + public Screen getScreen() { + return window.getScreen(); + } + /** * Child widgets that this widget contains. */ private List children; + /** + * Get the list of child widgets that this widget contains. + * + * @return the list of child widgets + */ + public List getChildren() { + return children; + } + /** * The currently active child widget that will receive keypress events. */ @@ -95,7 +134,7 @@ public abstract class TWidget { * * @return if true, this widget will receive events */ - public final boolean getActive() { + public final boolean isActive() { return active; } @@ -104,7 +143,7 @@ public abstract class TWidget { * * @param active if true, this widget will receive events */ - public final void setActive(boolean active) { + public final void setActive(final boolean active) { this.active = active; } @@ -113,6 +152,15 @@ public abstract class TWidget { */ private TWindow window = null; + /** + * Get the window this widget is on. + * + * @return the window + */ + public final TWindow getWindow() { + return window; + } + /** * Absolute X position of the top-left corner. */ @@ -220,7 +268,7 @@ public abstract class TWidget { * * @return if true, this widget can be tabbed to or receive events */ - public final boolean getEnabled() { + public final boolean isEnabled() { return enabled; } @@ -256,15 +304,24 @@ public abstract class TWidget { /** * If true, this widget has a cursor. */ - private boolean hasCursor = false; + private boolean cursorVisible = false; + + /** + * Set visible cursor flag. + * + * @param cursorVisible if true, this widget has a cursor + */ + public final void setCursorVisible(final boolean cursorVisible) { + this.cursorVisible = cursorVisible; + } /** * See if this widget has a visible cursor. * * @return if true, this widget has a visible cursor */ - public final boolean visibleCursor() { - return hasCursor; + public final boolean isCursorVisible() { + return cursorVisible; } /** @@ -272,18 +329,71 @@ public abstract class TWidget { */ private int cursorX = 0; + /** + * Get cursor X value. + * + * @return cursor column position in relative coordinates + */ + public final int getCursorX() { + return cursorX; + } + + /** + * Set cursor X value. + * + * @param cursorX column position in relative coordinates + */ + public final void setCursorX(final int cursorX) { + this.cursorX = cursorX; + } + /** * Cursor row position in relative coordinates. */ private int cursorY = 0; /** - * Comparison operator sorts on tabOrder. + * Get cursor Y value. + * + * @return cursor row position in relative coordinates + */ + public final int getCursorY() { + return cursorY; + } + + /** + * Set cursor Y value. * - * @param that another TWidget instance - * @return difference between this.tabOrder and that.tabOrder + * @param cursorY row position in relative coordinates */ - public final int compare(final TWidget that) { + public final void setCursorY(final int cursorY) { + this.cursorY = cursorY; + } + + /** + * Comparison operator sorts on: + *
    + *
  • tabOrder for TWidgets
  • + *
  • z for TWindows
  • + *
  • text for TTreeItems
  • + *
+ * + * @param that another TWidget, TWindow, or TTreeItem instance + * @return difference between this.tabOrder and that.tabOrder, or + * difference between this.z and that.z, or String.compareTo(text) + */ + public final int compareTo(final TWidget that) { + if ((this instanceof TWindow) + && (that instanceof TWindow) + ) { + return (((TWindow) this).getZ() - ((TWindow) that).getZ()); + } + if ((this instanceof TTreeItem) + && (that instanceof TTreeItem) + ) { + return (((TTreeItem) this).getText().compareTo( + ((TTreeItem) that).getText())); + } return (this.tabOrder - that.tabOrder); } @@ -293,11 +403,11 @@ public abstract class TWidget { * @return true if this widget is active and all of its parents are * active. */ - public final boolean getAbsoluteActive() { + public final boolean isAbsoluteActive() { if (parent == this) { return active; } - return (active && parent.getAbsoluteActive()); + return (active && parent.isAbsoluteActive()); } /** @@ -306,7 +416,7 @@ public abstract class TWidget { * @return absolute screen column number for the cursor's X position */ public final int getCursorAbsoluteX() { - assert (hasCursor); + assert (cursorVisible); return getAbsoluteX() + cursorX; } @@ -316,7 +426,7 @@ public abstract class TWidget { * @return absolute screen row number for the cursor's Y position */ public final int getCursorAbsoluteY() { - assert (hasCursor); + assert (cursorVisible); return getAbsoluteY() + cursorY; } @@ -358,6 +468,15 @@ public abstract class TWidget { return parent.getAbsoluteY() + y; } + /** + * Get the global color theme. + * + * @return the ColorTheme + */ + public final ColorTheme getTheme() { + return window.getApplication().getTheme(); + } + /** * Draw my specific widget. When called, the screen rectangle I draw * into is already setup (offset and clipping). @@ -372,14 +491,14 @@ public abstract class TWidget { public final void drawChildren() { // Set my clipping rectangle assert (window != null); - assert (window.getScreen() != null); - Screen screen = window.getScreen(); + assert (getScreen() != null); + Screen screen = getScreen(); screen.setClipRight(width); screen.setClipBottom(height); - int absoluteRightEdge = window.getAbsoluteX() + screen.getWidth(); - int absoluteBottomEdge = window.getAbsoluteY() + screen.getHeight(); + int absoluteRightEdge = window.getAbsoluteX() + window.getWidth(); + int absoluteBottomEdge = window.getAbsoluteY() + window.getHeight(); if (!(this instanceof TWindow) && !(this instanceof TVScroller)) { absoluteRightEdge -= 1; } @@ -393,14 +512,14 @@ public abstract class TWidget { screen.setClipRight(0); } else if (myRightEdge > absoluteRightEdge) { screen.setClipRight(screen.getClipRight() - - myRightEdge - absoluteRightEdge); + - (myRightEdge - absoluteRightEdge)); } if (getAbsoluteY() > absoluteBottomEdge) { // I am offscreen screen.setClipBottom(0); } else if (myBottomEdge > absoluteBottomEdge) { screen.setClipBottom(screen.getClipBottom() - - myBottomEdge - absoluteBottomEdge); + - (myBottomEdge - absoluteBottomEdge)); } // Set my offset @@ -429,12 +548,63 @@ public abstract class TWidget { * @param parent parent widget */ protected TWidget(final TWidget parent) { + this(parent, true); + } + + /** + * Protected constructor. + * + * @param parent parent widget + * @param x column relative to parent + * @param y row relative to parent + * @param width width of widget + * @param height height of widget + */ + protected TWidget(final TWidget parent, final int x, final int y, + final int width, final int height) { + + this(parent, true, x, y, width, height); + } + + /** + * Protected constructor used by subclasses that are disabled by default. + * + * @param parent parent widget + * @param enabled if true assume enabled + */ + protected TWidget(final TWidget parent, final boolean enabled) { + this.enabled = enabled; this.parent = parent; this.window = parent.window; children = new LinkedList(); parent.addChild(this); } + /** + * Protected constructor used by subclasses that are disabled by default. + * + * @param parent parent widget + * @param enabled if true assume enabled + * @param x column relative to parent + * @param y row relative to parent + * @param width width of widget + * @param height height of widget + */ + protected TWidget(final TWidget parent, final boolean enabled, + final int x, final int y, final int width, final int height) { + + this.enabled = enabled; + this.parent = parent; + this.window = parent.window; + children = new LinkedList(); + parent.addChild(this); + + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + /** * Add a child widget to my list of children. We set its tabOrder to 0 * and increment the tabOrder of all other children. @@ -561,9 +731,6 @@ public abstract class TWidget { activeChild.active = false; children.get(tabOrder).active = true; activeChild = children.get(tabOrder); - - // Refresh - window.getApplication().setRepaint(); } /** @@ -571,7 +738,7 @@ public abstract class TWidget { * * @return widget that is active, or this if no children */ - public final TWidget getActiveChild() { + public TWidget getActiveChild() { if ((this instanceof THScroller) || (this instanceof TVScroller) ) { @@ -595,9 +762,8 @@ public abstract class TWidget { public void onKeypress(final TKeypressEvent keypress) { if ((children.size() == 0) - // TODO - // || (cast(TTreeView)this) - // || (cast(TText)this) + || (this instanceof TTreeView) + || (this instanceof TText) ) { // Defaults: @@ -623,27 +789,25 @@ public abstract class TWidget { // If I have any buttons on me AND this is an Alt-key that matches // its mnemonic, send it an Enter keystroke for (TWidget widget: children) { - /* - TODO - - if (TButton button = cast(TButton)w) { - if (button.enabled && - !keypress.key.isKey && - keypress.key.alt && - !keypress.key.ctrl && - (toLowercase(button.mnemonic.shortcut) == toLowercase(keypress.key.ch))) { - - w.handleEvent(new TKeypressEvent(kbEnter)); + if (widget instanceof TButton) { + TButton button = (TButton) widget; + if (button.isEnabled() + && !keypress.getKey().isFnKey() + && keypress.getKey().isAlt() + && !keypress.getKey().isCtrl() + && (Character.toLowerCase(button.getMnemonic().getShortcut()) + == Character.toLowerCase(keypress.getKey().getChar())) + ) { + + widget.handleEvent(new TKeypressEvent(kbEnter)); return; } } - */ } // Dispatch the keypress to an active widget for (TWidget widget: children) { if (widget.active) { - window.getApplication().setRepaint(); widget.handleEvent(keypress); return; } @@ -832,4 +996,372 @@ public abstract class TWidget { return false; } + /** + * Convenience function to add a label to this container/window. + * + * @param text label + * @param x column relative to parent + * @param y row relative to parent + * @return the new label + */ + public final TLabel addLabel(final String text, final int x, final int y) { + return addLabel(text, x, y, "tlabel"); + } + + /** + * Convenience function to add a label to this container/window. + * + * @param text label + * @param x column relative to parent + * @param y row relative to parent + * @param colorKey ColorTheme key color to use for foreground text. + * Default is "tlabel" + * @return the new label + */ + public final TLabel addLabel(final String text, final int x, final int y, + final String colorKey) { + + return new TLabel(this, text, x, y, colorKey); + } + + /** + * Convenience function to add a button to this container/window. + * + * @param text label on the button + * @param x column relative to parent + * @param y row relative to parent + * @param action to call when button is pressed + * @return the new button + */ + public final TButton addButton(final String text, final int x, final int y, + final TAction action) { + + return new TButton(this, text, x, y, action); + } + + /** + * Convenience function to add a checkbox to this container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param label label to display next to (right of) the checkbox + * @param checked initial check state + * @return the new checkbox + */ + public final TCheckbox addCheckbox(final int x, final int y, + final String label, final boolean checked) { + + return new TCheckbox(this, x, y, label, checked); + } + + /** + * Convenience function to add a progress bar to this container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width width of progress bar + * @param value initial value of percent complete + * @return the new progress bar + */ + public final TProgressBar addProgressBar(final int x, final int y, + final int width, final int value) { + + return new TProgressBar(this, x, y, width, value); + } + + /** + * Convenience function to add a radio button group to this + * container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param label label to display on the group box + * @return the new radio button group + */ + public final TRadioGroup addRadioGroup(final int x, final int y, + final String label) { + + return new TRadioGroup(this, x, y, label); + } + + /** + * Convenience function to add a text field to this container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width visible text width + * @param fixed if true, the text cannot exceed the display width + * @return the new text field + */ + public final TField addField(final int x, final int y, + final int width, final boolean fixed) { + + return new TField(this, x, y, width, fixed); + } + + /** + * Convenience function to add a text field to this container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width visible text width + * @param fixed if true, the text cannot exceed the display width + * @param text initial text, default is empty string + * @return the new text field + */ + public final TField addField(final int x, final int y, + final int width, final boolean fixed, final String text) { + + return new TField(this, x, y, width, fixed, text); + } + + /** + * Convenience function to add a text field to this container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width visible text width + * @param fixed if true, the text cannot exceed the display width + * @param text initial text, default is empty string + * @param enterAction function to call when enter key is pressed + * @param updateAction function to call when the text is updated + * @return the new text field + */ + public final TField addField(final int x, final int y, + final int width, final boolean fixed, final String text, + final TAction enterAction, final TAction updateAction) { + + return new TField(this, x, y, width, fixed, text, enterAction, + updateAction); + } + + /** + * Convenience function to add a scrollable text box to this + * container/window. + * + * @param text text on the screen + * @param x column relative to parent + * @param y row relative to parent + * @param width width of text area + * @param height height of text area + * @param colorKey ColorTheme key color to use for foreground text + * @return the new text box + */ + public final TText addText(final String text, final int x, + final int y, final int width, final int height, final String colorKey) { + + return new TText(this, text, x, y, width, height, colorKey); + } + + /** + * Convenience function to add a scrollable text box to this + * container/window. + * + * @param text text on the screen + * @param x column relative to parent + * @param y row relative to parent + * @param width width of text area + * @param height height of text area + * @return the new text box + */ + public final TText addText(final String text, final int x, final int y, + final int width, final int height) { + + return new TText(this, text, x, y, width, height, "ttext"); + } + + /** + * Convenience function to spawn a message box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @return the new message box + */ + public final TMessageBox messageBox(final String title, + final String caption) { + + return getApplication().messageBox(title, caption, TMessageBox.Type.OK); + } + + /** + * Convenience function to spawn a message box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param type one of the TMessageBox.Type constants. Default is + * Type.OK. + * @return the new message box + */ + public final TMessageBox messageBox(final String title, + final String caption, final TMessageBox.Type type) { + + return getApplication().messageBox(title, caption, type); + } + + /** + * Convenience function to spawn an input box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @return the new input box + */ + public final TInputBox inputBox(final String title, final String caption) { + + return getApplication().inputBox(title, caption); + } + + /** + * Convenience function to spawn an input box. + * + * @param title window title, will be centered along the top border + * @param caption message to display. Use embedded newlines to get a + * multi-line box. + * @param text initial text to seed the field with + * @return the new input box + */ + public final TInputBox inputBox(final String title, final String caption, + final String text) { + + return getApplication().inputBox(title, caption, text); + } + + /** + * Convenience function to add a password text field to this + * container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width visible text width + * @param fixed if true, the text cannot exceed the display width + * @return the new text field + */ + public final TPasswordField addPasswordField(final int x, final int y, + final int width, final boolean fixed) { + + return new TPasswordField(this, x, y, width, fixed); + } + + /** + * Convenience function to add a password text field to this + * container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width visible text width + * @param fixed if true, the text cannot exceed the display width + * @param text initial text, default is empty string + * @return the new text field + */ + public final TPasswordField addPasswordField(final int x, final int y, + final int width, final boolean fixed, final String text) { + + return new TPasswordField(this, x, y, width, fixed, text); + } + + /** + * Convenience function to add a password text field to this + * container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width visible text width + * @param fixed if true, the text cannot exceed the display width + * @param text initial text, default is empty string + * @param enterAction function to call when enter key is pressed + * @param updateAction function to call when the text is updated + * @return the new text field + */ + public final TPasswordField addPasswordField(final int x, final int y, + final int width, final boolean fixed, final String text, + final TAction enterAction, final TAction updateAction) { + + return new TPasswordField(this, x, y, width, fixed, text, enterAction, + updateAction); + } + + /** + * Convenience function to add a tree view to this container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width width of tree view + * @param height height of tree view + */ + public final TTreeView addTreeView(final int x, final int y, + final int width, final int height) { + + return new TTreeView(this, x, y, width, height); + } + + /** + * Convenience function to add a tree view to this container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width width of tree view + * @param height height of tree view + * @param action action to perform when an item is selected + */ + public final TTreeView addTreeView(final int x, final int y, + final int width, final int height, final TAction action) { + + return new TTreeView(this, x, y, width, height, action); + } + + /** + * Convenience function to spawn a file open box. + * + * @param path path of selected file + * @return the result of the new file open box + */ + public final String fileOpenBox(final String path) throws IOException { + return getApplication().fileOpenBox(path); + } + + /** + * Convenience function to spawn a file open box. + * + * @param path path of selected file + * @param type one of the Type constants + * @return the result of the new file open box + */ + public final String fileOpenBox(final String path, + final TFileOpenBox.Type type) throws IOException { + + return getApplication().fileOpenBox(path, type); + } + /** + * Convenience function to add a directory list to this container/window. + * + * @param path directory path, must be a directory + * @param x column relative to parent + * @param y row relative to parent + * @param width width of text area + * @param height height of text area + */ + public final TDirectoryList addDirectoryList(final String path, final int x, + final int y, final int width, final int height) { + + return new TDirectoryList(this, path, x, y, width, height, null); + } + + /** + * Convenience function to add a directory list to this container/window. + * + * @param path directory path, must be a directory + * @param x column relative to parent + * @param y row relative to parent + * @param width width of text area + * @param height height of text area + * @param action action to perform when an item is selected + */ + public final TDirectoryList addDirectoryList(final String path, final int x, + final int y, final int width, final int height, final TAction action) { + + return new TDirectoryList(this, path, x, y, width, height, action); + } + }