[gnome-clocks/wip/analogtimer] Experiment with a circular progress for timer



commit 352b5910f5732b0ea087c7df0b8f14be33f7a345
Author: Paolo Borelli <pborelli gnome org>
Date:   Mon Jul 29 13:08:23 2013 +0200

    Experiment with a circular progress for timer
    
    This is an experiment to play with the idea of showing some kind of
    progress to spice up the timer panel.

 src/timer.vala |  149 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 139 insertions(+), 10 deletions(-)
---
diff --git a/src/timer.vala b/src/timer.vala
index 0b1b36e..508664e 100644
--- a/src/timer.vala
+++ b/src/timer.vala
@@ -19,6 +19,126 @@
 namespace Clocks {
 namespace Timer {
 
+public class CountdownFrame : Gtk.Frame {
+    private const int RADIUS_PAD = 36;
+
+    public double span { get; set; default = 0; }
+
+    private double elapsed;
+    private double elapsed_before_pause;
+    private Cairo.Pattern cursor_pattern;
+
+    private double get_progress () {
+        return span != 0 ? (elapsed_before_pause + elapsed) / span : 0;
+    }
+
+    private int calculate_diameter () {
+        var child = get_child ();
+        if (child != null && child.visible) {
+            int w, h;
+            child.get_preferred_width (out w, null);
+            child.get_preferred_height (out h, null);
+            return RADIUS_PAD + (int) Math.sqrt (w * w + h * h);
+        } else {
+            return RADIUS_PAD;
+        }
+    }
+
+    public void update (double e) {
+        elapsed = e;
+        queue_draw ();
+    }
+
+    public void pause () {
+        elapsed_before_pause += elapsed;
+        elapsed = 0;
+    }
+
+    public override void get_preferred_width (out int min_w, out int natural_w) {
+        var d = calculate_diameter ();
+        min_w = d;
+        natural_w = d;
+    }
+
+    public override void get_preferred_height (out int min_h, out int natural_h) {
+        var d = calculate_diameter ();
+        min_h = d;
+        natural_h = d;
+    }
+
+    public override void size_allocate (Gtk.Allocation allocation) {
+        set_allocation (allocation);
+        var child = get_child ();
+        if (child != null && child.visible) {
+            int w, h;
+            child.get_preferred_width (out w, null);
+            child.get_preferred_height (out h, null);
+
+            Gtk.Allocation child_allocation = {};
+            child_allocation.x = allocation.x + (allocation.width - w) / 2;
+            child_allocation.y = allocation.y + (allocation.height - h) / 2;
+            child_allocation.width = w;
+            child_allocation.height =  h;
+            child.size_allocate (child_allocation);
+        }
+    }
+
+    public override bool draw (Cairo.Context cr) {
+        base.draw(cr);
+
+        var context = get_style_context ();
+        Gtk.Allocation allocation;
+        get_allocation (out allocation);
+        var center_x = allocation.width / 2;
+        var center_y = allocation.height / 2;
+
+        var radius = calculate_diameter () / 2;
+        cr.move_to (center_x + radius, center_y);
+
+        cr.set_line_width (1);
+        var color = context.get_border_color (Gtk.StateFlags.SELECTED);
+        Gdk.cairo_set_source_rgba (cr, color);
+        cr.arc (center_x, center_y, radius, 0, 2 * Math.PI);
+        cr.arc (center_x, center_y, radius - 9, 0, 2 * Math.PI);
+        cr.stroke ();
+
+        cr.set_line_width (8);
+
+        color = context.get_color (Gtk.StateFlags.SELECTED);
+        cr.arc (center_x, center_y, radius - 4.5, 0, 2 * Math.PI);
+        Gdk.cairo_set_source_rgba (cr, color);
+        cr.stroke ();
+
+        var progress = get_progress ();
+        if (progress > 0) {
+            color = context.get_background_color (Gtk.StateFlags.SELECTED);
+            cr.arc (center_x, center_y, radius - 4.5, 1.5  * Math.PI, (1.5 + progress * 2 ) * Math.PI);
+            Gdk.cairo_set_source_rgba (cr, color);
+            cr.stroke ();
+
+            if (progress < 1) {
+                if (cursor_pattern == null) {
+                    cursor_pattern = new Cairo.Pattern.radial (0, 0, 6, 0, 0, 18);
+                    cursor_pattern.add_color_stop_rgba (0, color.red, color.green, color.blue, 1);
+                    cursor_pattern.add_color_stop_rgba (0.5, color.red, color.green, color.blue, 0);
+                }
+
+                var x = center_x + (radius - 4.5) * Math.cos((1.5 + progress * 2) * Math.PI);
+                var y = center_y + (radius - 4.5) * Math.sin((1.5 + progress * 2) * Math.PI);
+
+                var cursor_radius = 18;
+                cr.arc (x, y, cursor_radius, 0, 2 * Math.PI);
+                cr.translate (x, y);
+                cr.set_source (cursor_pattern);
+                cr.fill ();
+            }
+        }
+
+        return false;
+    }
+
+}
+
 public class MainPanel : Gtk.Stack, Clocks.Clock {
     enum State {
         STOPPED,
@@ -39,7 +159,7 @@ public class MainPanel : Gtk.Stack, Clocks.Clock {
     private Gtk.SpinButton m_spinbutton;
     private Gtk.SpinButton s_spinbutton;
     private Gtk.Button start_button;
-    private Gtk.Widget countdown_panel;
+    private CountdownFrame countdown_frame;
     private Gtk.Label time_label;
     private Gtk.Button left_button;
     private Gtk.Button right_button;
@@ -77,7 +197,12 @@ public class MainPanel : Gtk.Stack, Clocks.Clock {
             start ();
         });
 
-        countdown_panel = builder.get_object ("countdown_panel") as Gtk.Widget;
+        countdown_frame = new CountdownFrame ();
+        countdown_frame.show();
+
+        var countdown_widgets = builder.get_object ("countdown_panel") as Gtk.Widget;
+        countdown_frame.add (countdown_widgets);
+
         time_label = builder.get_object ("time_label") as Gtk.Label;
         left_button = builder.get_object ("left_button") as Gtk.Button;
         right_button = builder.get_object ("right_button") as Gtk.Button;
@@ -105,7 +230,7 @@ public class MainPanel : Gtk.Stack, Clocks.Clock {
         });
 
         add (setup_panel);
-        add (countdown_panel);
+        add (countdown_frame);
 
         reset ();
 
@@ -160,7 +285,9 @@ public class MainPanel : Gtk.Stack, Clocks.Clock {
             settings.set_uint ("timer", (uint) span);
 
             timer.start ();
-            visible_child = countdown_panel;
+
+            countdown_frame.span = span;
+            visible_child = countdown_frame;
 
             update_countdown_label (h, m, s);
             add_timeout ();
@@ -177,23 +304,24 @@ public class MainPanel : Gtk.Stack, Clocks.Clock {
         state = State.PAUSED;
         timer.stop ();
         span -= timer.elapsed ();
+        countdown_frame.pause ();
         remove_timeout ();
     }
 
     private void add_timeout () {
         if (timeout_id == 0) {
-            timeout_id = Timeout.add (100, count);
+            timeout_id = add_tick_callback ((Gtk.TickCallback)count);
         }
     }
 
     private void remove_timeout () {
         if (timeout_id != 0) {
-            Source.remove (timeout_id);
+            remove_tick_callback (timeout_id);
             timeout_id = 0;
         }
     }
 
-    private bool count () {
+    private bool count (Gdk.FrameClock frame_clock) {
         var e = timer.elapsed ();
         if (e >= span) {
             ring ();
@@ -204,22 +332,23 @@ public class MainPanel : Gtk.Stack, Clocks.Clock {
             return false;
         }
 
-        update_countdown (span - e);
+        update_countdown (e);
         return true;
     }
 
-    private void update_countdown (double t) {
+    private void update_countdown (double elapsed) {
         if (time_label.get_mapped ()) {
             // Math.ceil() because we count backwards:
             // with 0.3 seconds we want to show 1 second remaining,
             // with 59.2 seconds we want to show 1 minute, etc
-            t = Math.ceil (t);
+            double t = Math.ceil (span - elapsed);
             int h;
             int m;
             int s;
             double r;
             Utils.time_to_hms (t, out h, out m, out s, out r);
             update_countdown_label (h, m, s);
+            countdown_frame.update (elapsed);
         }
     }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]