timer and progress bar working
authorKevin Lamonte <kevin.lamonte@gmail.com>
Sun, 15 Mar 2015 00:42:08 +0000 (20:42 -0400)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Sun, 15 Mar 2015 00:42:08 +0000 (20:42 -0400)
README.md
demos/Demo1.java
src/jexer/TApplication.java
src/jexer/TLabel.java
src/jexer/TProgressBar.java [new file with mode: 0644]
src/jexer/TTimer.java [new file with mode: 0644]
src/jexer/TWidget.java

index 11e09c34f4abc63564e2b4fb21e413f495769b10..0ee57260caddadb5e1c28be3de05c9281ecbe8a1 100644 (file)
--- a/README.md
+++ b/README.md
@@ -61,8 +61,6 @@ Many tasks remain before calling this version 1.0:
 - TDirectoryList
 - TField
 - TMessageBox
-- TProgressBar
-- TTimer
 - TRadioGroup / TRadioButton
 - THScroller / TVScroller
 - TText
index 44333a42b4be7f3a30f93f38c995bf31f5a395c1..db327081100e416db1f6395682ee887cc0d34f48 100644 (file)
@@ -198,10 +198,13 @@ EOS",
 
 
 class DemoMainWindow extends TWindow {
-    /*
     // Timer that increments a number
     private TTimer timer;
 
+    // Timer label is updated with timerrr ticks
+    TLabel timerLabel;
+
+    /*
     // The modal window is a more low-level example of controlling a window
     // "from the outside".  Most windows will probably subclass TWindow and
     // do this kind of logic on their own.
@@ -217,14 +220,17 @@ class DemoMainWindow extends TWindow {
     private void modalWindowClose() {
         application.closeWindow(modalWindow);
     }
+     */
 
-    /// We need to override onClose so that the timer will no longer be
-    /// called after we close the window.  TTimers currently are completely
-    /// unaware of the rest of the UI classes.
-    override public void onClose() {
-        application.removeTimer(timer);
-    }
+    /**
+     * We need to override onClose so that the timer will no longer be called
+     * after we close the window.  TTimers currently are completely unaware
+     * of the rest of the UI classes.
      */
+    @Override
+    public void onClose() {
+        getApplication().removeTimer(timer);
+    }
 
     /**
      * Construct demo window.  It will be centered on screen.
@@ -233,6 +239,9 @@ class DemoMainWindow extends TWindow {
         this(parent, CENTERED | RESIZABLE);
     }
 
+    int timerI = 0;
+    TProgressBar progressBar;
+
     /**
      * Constructor.
      */
@@ -281,7 +290,7 @@ class DemoMainWindow extends TWindow {
             addButton("&Checkboxes", 35, row,
                 new TAction() {
                     public void DO() {
-                        new DemoCheckboxWindow(getApplication(), MODAL);
+                        new DemoCheckboxWindow(getApplication());
                     }
                 }
             );
@@ -328,24 +337,25 @@ class DemoMainWindow extends TWindow {
             );
         }
         row += 2;
+         */
 
-        TProgressBar bar = addProgressBar(1, row, 22);
+        progressBar = addProgressBar(1, row, 22, 0);
         row++;
-        TLabel timerLabel = addLabel("Timer", 1, row);
-        timer = parent.addTimer(100,
-            {
-                static int i = 0;
-                auto writer = appender!dstring();
-                formattedWrite(writer, "Timer: %d", i);
-                timerLabel.text = writer.data;
-                timerLabel.width = cast(uint)timerLabel.text.length;
-                if (i < 100) {
-                    i++;
+        timerLabel = addLabel("Timer", 1, row);
+        timer = getApplication().addTimer(100, true,
+            new TAction() {
+
+                public void DO() {
+                    timerLabel.setText(String.format("Timer: %d", timerI));
+                    timerLabel.setWidth(timerLabel.getText().length());
+                    if (timerI < 100) {
+                        timerI++;
+                    }
+                    progressBar.setValue(timerI);
+                    DemoMainWindow.this.setRepaint();
                 }
-                bar.value = i;
-                parent.repaint = true;
-            }, true);
-         */
+            }
+        );
     }
 }
 
index d2b8f446c4d15a5b519f3c55bdc590d787c884a2..8786e693271aa6511c747a6d8eb016b640ef1ed7 100644 (file)
@@ -34,6 +34,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -135,6 +136,11 @@ public class TApplication {
      */
     private List<TWindow> windows;
 
+    /**
+     * Timers that are being ticked.
+     */
+    private List<TTimer> timers;
+
     /**
      * When true, exit the application.
      */
@@ -211,6 +217,7 @@ public class TApplication {
         windows         = new LinkedList<TWindow>();
         menus           = new LinkedList<TMenu>();
         subMenus        = new LinkedList<TMenu>();
+        timers          = new LinkedList<TTimer>();
         accelerators    = new HashMap<TKeypress, TMenuItem>();
     }
 
@@ -595,28 +602,25 @@ public class TApplication {
      * Do stuff when there is no user input.
      */
     private void doIdle() {
-        /*
-         TODO
         // Now run any timers that have timed out
-        auto now = Clock.currTime;
-        TTimer [] keepTimers;
-        foreach (t; timers) {
-            if (t.nextTick < now) {
-                t.tick();
-                if (t.recurring == true) {
-                    keepTimers ~= t;
+        Date now = new Date();
+        List<TTimer> keepTimers = new LinkedList<TTimer>();
+        for (TTimer timer: timers) {
+            if (timer.getNextTick().getTime() < now.getTime()) {
+                timer.tick();
+                if (timer.recurring == true) {
+                    keepTimers.add(timer);
                 }
             } else {
-                keepTimers ~= t;
+                keepTimers.add(timer);
             }
         }
         timers = keepTimers;
 
         // Call onIdle's
-        foreach (w; windows) {
-            w.onIdle();
+        for (TWindow window: windows) {
+            window.onIdle();
         }
-         */
     }
 
     /**
@@ -626,24 +630,20 @@ public class TApplication {
      * @return number of milliseconds between now and the next timer event
      */
     protected int getSleepTime(final int timeout) {
-        /*
-        auto now = Clock.currTime;
-        auto sleepTime = dur!("msecs")(timeout);
-        foreach (t; timers) {
-            if (t.nextTick < now) {
+        Date now = new Date();
+        long sleepTime = timeout;
+        for (TTimer timer: timers) {
+            if (timer.getNextTick().getTime() < now.getTime()) {
                 return 0;
             }
-            if ((t.nextTick > now) &&
-                ((t.nextTick - now) < sleepTime)
+            if ((timer.getNextTick().getTime() > now.getTime())
+                && ((timer.getNextTick().getTime() - now.getTime()) < sleepTime)
             ) {
-                sleepTime = t.nextTick - now;
+                sleepTime = timer.getNextTick().getTime() - now.getTime();
             }
         }
-        assert(sleepTime.total!("msecs")() >= 0);
-        return cast(uint)sleepTime.total!("msecs")();
-         */
-        // TODO: fix timers.  Until then, come back after 250 millis.
-        return 250;
+        assert (sleepTime >= 0);
+        return (int)sleepTime;
     }
 
     /**
@@ -1310,9 +1310,9 @@ public class TApplication {
         List<TWindow> sorted = new LinkedList<TWindow>(windows);
         Collections.sort(sorted);
         Collections.reverse(sorted);
-        for (TWindow w: sorted) {
-            w.setX(x);
-            w.setY(y);
+        for (TWindow window: sorted) {
+            window.setX(x);
+            window.setY(y);
             x++;
             y++;
             if (x > getScreen().getWidth()) {
@@ -1324,4 +1324,32 @@ public class TApplication {
         }
     }
 
+    /**
+     * Convenience function to add a timer.
+     *
+     * @param duration number of milliseconds to wait between ticks
+     * @param recurring if true, re-schedule this timer after every tick
+     * @param action function to call when button is pressed
+     */
+    public final TTimer addTimer(final long duration, final boolean recurring,
+        final TAction action) {
+
+        TTimer timer = new TTimer(duration, recurring, action);
+        synchronized (timers) {
+            timers.add(timer);
+        }
+        return timer;
+    }
+
+    /**
+     * Convenience function to remove a timer.
+     *
+     * @param timer timer to remove
+     */
+    public final void removeTimer(final TTimer timer) {
+        synchronized (timers) {
+            timers.remove(timer);
+        }
+    }
+
 }
index 15d6376d5313adff2010b8e5fd559f8a2b15fdd0..d56be67f7d3815a42dc25c6f43c7e9a416db9cb8 100644 (file)
@@ -42,6 +42,24 @@ public final class TLabel extends TWidget {
      */
     private String text = "";
 
+    /**
+     * Get label text.
+     *
+     * @return label text
+     */
+    public String getText() {
+        return text;
+    }
+
+    /**
+     * Set label text.
+     *
+     * @param text new label text
+     */
+    public void setText(final String text) {
+        this.text = text;
+    }
+
     /**
      * Label color.
      */
diff --git a/src/jexer/TProgressBar.java b/src/jexer/TProgressBar.java
new file mode 100644 (file)
index 0000000..1cd950c
--- /dev/null
@@ -0,0 +1,167 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * License: LGPLv3 or later
+ *
+ * This module is licensed under the GNU Lesser General Public License
+ * Version 3.  Please see the file "COPYING" in this directory for more
+ * information about the GNU Lesser General Public License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * @author Kevin Lamonte [kevin.lamonte@gmail.com]
+ * @version 1
+ */
+package jexer;
+
+import jexer.bits.CellAttributes;
+import jexer.bits.GraphicsChars;
+
+/**
+ * TProgressBar implements a simple progress bar.
+ */
+public final class TProgressBar extends TWidget {
+
+    /**
+     * Value that corresponds to 0% progress.
+     */
+    private int minValue = 0;
+
+    /**
+     * Get the value that corresponds to 0% progress.
+     *
+     * @return the value that corresponds to 0% progress
+     */
+    public int getMinValue() {
+        return minValue;
+    }
+
+    /**
+     * Set the value that corresponds to 0% progress.
+     *
+     * @param minValue the value that corresponds to 0% progress
+     */
+    public void setMinValue(final int minValue) {
+        this.minValue = minValue;
+    }
+
+    /**
+     * Value that corresponds to 100% progress.
+     */
+    private int maxValue = 100;
+
+    /**
+     * Get the value that corresponds to 100% progress.
+     *
+     * @return the value that corresponds to 100% progress
+     */
+    public int getMaxValue() {
+        return maxValue;
+    }
+
+    /**
+     * Set the value that corresponds to 100% progress.
+     *
+     * @param maxValue the value that corresponds to 100% progress
+     */
+    public void setMaxValue(final int maxValue) {
+        this.maxValue = maxValue;
+    }
+
+    /**
+     * Current value of the progress.
+     */
+    private int value = 0;
+
+    /**
+     * Get the current value of the progress.
+     *
+     * @return the current value of the progress
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Set the current value of the progress.
+     *
+     * @param value the current value of the progress
+     */
+    public void setValue(final int value) {
+        this.value = value;
+    }
+
+    /**
+     * Public constructor.
+     *
+     * @param parent parent widget
+     * @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
+     */
+    public TProgressBar(final TWidget parent, final int x, final int y,
+        final int width, final int value) {
+
+        // Set parent and window
+        super(parent, false);
+
+        setX(x);
+        setY(y);
+        setHeight(1);
+        setWidth(width);
+        this.value = value;
+    }
+
+    /**
+     * Draw a static progress bar.
+     */
+    @Override
+    public void draw() {
+        CellAttributes completeColor = getTheme().getColor("tprogressbar.complete");
+        CellAttributes incompleteColor = getTheme().getColor("tprogressbar.incomplete");
+
+        float progress = ((float)value - minValue) / ((float)maxValue - minValue);
+        int progressInt = (int)(progress * 100);
+        int progressUnit = 100 / (getWidth() - 2);
+
+        getScreen().putCharXY(0, 0, GraphicsChars.CP437[0xC3], incompleteColor);
+        for (int i = 0; i < getWidth() - 2; i++) {
+            float iProgress = (float)i / (getWidth() - 2);
+            int iProgressInt = (int)(iProgress * 100);
+            if (iProgressInt <= progressInt - progressUnit) {
+                getScreen().putCharXY(i + 1, 0, GraphicsChars.BOX,
+                    completeColor);
+            } else {
+                getScreen().putCharXY(i + 1, 0, GraphicsChars.SINGLE_BAR,
+                    incompleteColor);
+            }
+        }
+        if (value >= maxValue) {
+            getScreen().putCharXY(getWidth() - 2, 0, GraphicsChars.BOX,
+                completeColor);
+        } else {
+            getScreen().putCharXY(getWidth() - 2, 0, GraphicsChars.SINGLE_BAR,
+                incompleteColor);
+        }
+        getScreen().putCharXY(getWidth() - 1, 0, GraphicsChars.CP437[0xB4],
+            incompleteColor);
+    }
+
+}
diff --git a/src/jexer/TTimer.java b/src/jexer/TTimer.java
new file mode 100644 (file)
index 0000000..0e711b9
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * Jexer - Java Text User Interface
+ *
+ * License: LGPLv3 or later
+ *
+ * This module is licensed under the GNU Lesser General Public License
+ * Version 3.  Please see the file "COPYING" in this directory for more
+ * information about the GNU Lesser General Public License Version 3.
+ *
+ *     Copyright (C) 2015  Kevin Lamonte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * http://www.gnu.org/licenses/, or write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * @author Kevin Lamonte [kevin.lamonte@gmail.com]
+ * @version 1
+ */
+package jexer;
+
+import java.util.Date;
+
+/**
+ * TTimer implements a simple timer.
+ */
+public final class TTimer {
+
+    /**
+     * If true, re-schedule after every tick.  Note package private access.
+     */
+    boolean recurring = false;
+
+    /**
+     * Duration (in millis) between ticks if this is a recurring timer.
+     */
+    private long duration = 0;
+
+    /**
+     * The next time this timer needs to be ticked.
+     */
+    private Date nextTick;
+
+    /**
+     * Get the next time this timer needs to be ticked.  Note package private
+     * access.
+     *
+     * @return time at which action should be called
+     */
+    Date getNextTick() {
+        return nextTick;
+    }
+
+    /**
+     * The action to perfom on a tick.
+     */
+    private TAction action;
+
+    /**
+     * Tick this timer.  Note package private access.
+     */
+    void tick() {
+        if (action != null) {
+            action.DO();
+        }
+        // Set next tick
+        Date ticked = new Date();
+        if (recurring) {
+            nextTick = new Date(ticked.getTime() + duration);
+        }
+    }
+
+    /**
+     * Get the number of milliseconds between now and the next tick time.
+     *
+     * @return number of millis
+     */
+    public long getMillis() {
+        return nextTick.getTime() - (new Date()).getTime();
+    }
+
+    /**
+     * Package private constructor.
+     *
+     * @param duration number of milliseconds to wait between ticks
+     * @param recurring if true, re-schedule this timer after every tick
+     * @param action to perform on next tick
+     */
+    TTimer(final long duration, final boolean recurring, final TAction action) {
+
+        this.recurring = recurring;
+        this.duration  = duration;
+        this.action    = action;
+
+        nextTick = new Date((new Date()).getTime() + duration);
+    }
+
+}
index 6c03a9cccef8d85c4fb934022e88d545a2922d32..1ab54e29b484e4220a79a06624290aa300968701 100644 (file)
@@ -1016,4 +1016,18 @@ public abstract class TWidget implements Comparable<TWidget> {
         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
+     */
+    public final TProgressBar addProgressBar(final int x, final int y,
+        final int width, final int value) {
+
+        return new TProgressBar(this, x, y, width, value);
+    }
+
 }