misc cleanup
[nikiroo-utils.git] / src / jexer / TWidget.java
index 4d9e22ced4e628770657303343284d77c0566cac..d6864db746316659ef5d3ed4fed3cc76b0934d6a 100644 (file)
@@ -33,6 +33,7 @@ package jexer;
 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,26 +41,90 @@ 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<TWidget> {
 
     /**
      * Every widget has a parent widget that it may be "contained" in.  For
      * example, a TWindow might contain several TTextFields, or a TComboBox
      * may contain a TScrollBar.
      */
-    protected TWidget parent = null;
+    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.
+     *
+     * @param window the top-level window
+     * @param x column relative to parent
+     * @param y row relative to parent
+     * @param width width of window
+     * @param height height of window
+     */
+    protected final void setupForTWindow(final TWindow window,
+        final int x, final int y, final int width, final int height) {
+
+        this.parent = window;
+        this.window = window;
+        this.x      = x;
+        this.y      = y;
+        this.width  = width;
+        this.height = height;
+    }
+
+    /**
+     * Request full repaint on next screen refresh.
+     */
+    protected final void setRepaint() {
+        window.getApplication().setRepaint();
+    }
+
+    /**
+     * 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<TWidget> children;
 
+    /**
+     * Get the list of child widgets that this widget contains.
+     *
+     * @return the list of child widgets
+     */
+    public List<TWidget> getChildren() {
+        return children;
+    }
+
     /**
      * The currently active child widget that will receive keypress events.
      */
@@ -68,32 +133,131 @@ public abstract class TWidget {
     /**
      * If true, this widget will receive events.
      */
-    protected boolean active = false;
+    private boolean active = false;
+
+    /**
+     * Get active flag.
+     *
+     * @return if true, this widget will receive events
+     */
+    public final boolean getActive() {
+        return active;
+    }
+
+    /**
+     * Set active flag.
+     *
+     * @param active if true, this widget will receive events
+     */
+    public final void setActive(final boolean active) {
+        this.active = active;
+    }
 
     /**
      * The window that this widget draws to.
      */
-    protected TWindow window = null;
+    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.
      */
-    protected int x = 0;
+    private int x = 0;
+
+    /**
+     * Get X position.
+     *
+     * @return absolute X position of the top-left corner
+     */
+    public final int getX() {
+        return x;
+    }
+
+    /**
+     * Set X position.
+     *
+     * @param x absolute X position of the top-left corner
+     */
+    public final void setX(final int x) {
+        this.x = x;
+    }
 
     /**
      * Absolute Y position of the top-left corner.
      */
-    protected int y = 0;
+    private int y = 0;
+
+    /**
+     * Get Y position.
+     *
+     * @return absolute Y position of the top-left corner
+     */
+    public final int getY() {
+        return y;
+    }
+
+    /**
+     * Set Y position.
+     *
+     * @param y absolute Y position of the top-left corner
+     */
+    public final void setY(final int y) {
+        this.y = y;
+    }
 
     /**
      * Width.
      */
-    protected int width = 0;
+    private int width = 0;
+
+    /**
+     * Get the width.
+     *
+     * @return widget width
+     */
+    public final int getWidth() {
+        return this.width;
+    }
+
+    /**
+     * Change the width.
+     *
+     * @param width new widget width
+     */
+    public final void setWidth(final int width) {
+        this.width = width;
+    }
 
     /**
      * Height.
      */
-    protected int height = 0;
+    private int height = 0;
+
+    /**
+     * Get the height.
+     *
+     * @return widget height
+     */
+    public final int getHeight() {
+        return this.height;
+    }
+
+    /**
+     * Change the height.
+     *
+     * @param height new widget height
+     */
+    public final void setHeight(final int height) {
+        this.height = height;
+    }
 
     /**
      * My tab order inside a window or containing widget.
@@ -121,19 +285,15 @@ public abstract class TWidget {
      */
     public final void setEnabled(final boolean enabled) {
         this.enabled = enabled;
-        /*
-
-        // TODO: get this working after scrollers are going again
-
-        if (enabled == false) {
+        if (!enabled) {
             active = false;
             // See if there are any active siblings to switch to
             boolean foundSibling = false;
-            if (parent !is null) {
-                foreach (w; parent.children) {
-                    if ((w.enabled) &&
-                        (!cast(THScroller)this) &&
-                        (!cast(TVScroller)this)
+            if (parent != null) {
+                for (TWidget w: parent.children) {
+                    if ((w.enabled)
+                        && !(this instanceof THScroller)
+                        && !(this instanceof TVScroller)
                     ) {
                         parent.activate(w);
                         foundSibling = true;
@@ -145,7 +305,6 @@ public abstract class TWidget {
                 }
             }
         }
-         */
     }
 
     /**
@@ -153,6 +312,15 @@ public abstract class TWidget {
      */
     private boolean hasCursor = false;
 
+    /**
+     * Set visible cursor flag.
+     *
+     * @param hasCursor if true, this widget has a cursor
+     */
+    public final void setHasCursor(final boolean hasCursor) {
+        this.hasCursor = hasCursor;
+    }
+
     /**
      * See if this widget has a visible cursor.
      *
@@ -167,18 +335,61 @@ 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 cursorY row position in relative coordinates
+     */
+    public final void setCursorY(final int cursorY) {
+        this.cursorY = cursorY;
+    }
+
+    /**
+     * Comparison operator sorts on tabOrder for TWidgets and z for TWindows.
      *
-     * @param that another TWidget instance
-     * @return difference between this.tabOrder and that.tabOrder
+     * @param that another TWidget or TWindow instance
+     * @return difference between this.tabOrder and that.tabOrder, or
+     * difference between this.z and that.z
      */
-    public final int compare(final TWidget that) {
+    @Override
+    public final int compareTo(final TWidget that) {
+        if ((this instanceof TWindow)
+            && (that instanceof TWindow)
+        ) {
+            return (((TWindow) this).getZ() - ((TWindow) that).getZ());
+        }
         return (this.tabOrder - that.tabOrder);
     }
 
@@ -253,6 +464,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).
@@ -312,7 +532,7 @@ public abstract class TWidget {
     }
 
     /**
-     * Subclasses need this constructor to setup children.
+     * Default constructor for subclasses.
      */
     protected TWidget() {
         children = new LinkedList<TWidget>();
@@ -324,10 +544,61 @@ 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<TWidget>();
+        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<TWidget>();
         parent.addChild(this);
+
+        this.x = x;
+        this.y = y;
+        this.width = width;
+        this.height = height;
     }
 
     /**
@@ -466,7 +737,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)
         ) {
@@ -490,8 +761,9 @@ public abstract class TWidget {
     public void onKeypress(final TKeypressEvent keypress) {
 
         if ((children.size() == 0)
+            // TODO
             // || (cast(TTreeView)this)
-            // || (cast(TText)this)
+            || (this instanceof TText)
         ) {
 
             // Defaults:
@@ -726,4 +998,290 @@ 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);
+    }
+
 }