[gnome-clocks/redesign/stopwatch] Stopwatch: implement the new mockup



commit 83d57309012c06a855c16d2e2e0d950daed53966
Author: Bilal Elmoussaoui <bil elmoussaoui gmail com>
Date:   Wed Dec 4 22:07:18 2019 +0100

    Stopwatch: implement the new mockup

 data/css/gnome-clocks.css   |  50 ++++++-
 data/ui/stopwatch.ui        | 352 +++++++++++++++++++++++++++++++++-----------
 data/ui/stopwatchlapsrow.ui |  58 ++++----
 src/stopwatch.vala          | 302 ++++++++++++++++++++-----------------
 4 files changed, 511 insertions(+), 251 deletions(-)
---
diff --git a/data/css/gnome-clocks.css b/data/css/gnome-clocks.css
index 883bbed..e5dc2eb 100644
--- a/data/css/gnome-clocks.css
+++ b/data/css/gnome-clocks.css
@@ -143,7 +143,6 @@ window > stack:backdrop {
     font-size: 48pt;
 }
 
-.clocks-stopwatch-label,
 .clocks-timer-label {
     font-size: 48pt;
 }
@@ -228,3 +227,52 @@ spinbutton.clocks-timer-label button {
     animation-timing-function: cubic-bezier(1.0,0,0,1.0);
     animation-duration: 1s; 
 }
+
+/* Stopwatch */
+.large-button {
+  padding: 6px 32px;
+}
+
+.lap-row label {
+  font-size: 16px;
+  font-weight: 400;
+}
+.negative-lap {
+  color: #ED333B;
+}
+.positive-lap {
+  color:green;
+}
+.stopped-stopwatch label,
+.running-stopwatch label,
+.paused-stopwatch label {
+  font-size: 80px;
+  color: grey;
+  font-weight: 200;
+}
+
+.stopped-stopwatch .seconds-label {
+  font-weight: 300;
+}
+
+.running-stopwatch .seconds-label,
+.running-stopwatch .miliseconds-label {
+       color: #428be5;
+}
+.stopped-stopwatch .miliseconds-label,
+.running-stopwatch .miliseconds-label,
+.paused-stopwatch .miliseconds-label {
+  font-size: 50px;
+}
+.running-stopwatch .seconds-label,
+.paused-stopwatch .seconds-label {
+  font-weight: 500;
+}
+
+.stopped-stopwatch .seconds-label,
+.stopped-stopwatch .miliseconds-label,
+.paused-stopwatch .seconds-label,
+.paused-stopwatch .miliseconds-label {
+color:black;
+}
+
diff --git a/data/ui/stopwatch.ui b/data/ui/stopwatch.ui
index 005ef27..b3272f8 100644
--- a/data/ui/stopwatch.ui
+++ b/data/ui/stopwatch.ui
@@ -1,83 +1,298 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
 <interface>
-  <!-- interface-requires gtk+ 3.6 -->
+  <requires lib="gtk+" version="3.16"/>
+  <requires lib="libhandy" version="0.0"/>
   <template class="ClocksStopwatchFace" parent="GtkBox">
     <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
     <child>
-      <object class="GtkGrid" id="stopwatch_panel">
+      <object class="HdyColumn">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="hexpand">True</property>
-        <property name="valign">fill</property>
-        <property name="column_spacing">0</property>
+        <property name="maximum_width">700</property>
+        <property name="linear_growth_width">700</property>
         <child>
-          <object class="ClocksStopwatchFrame" id="analog_frame">
+          <object class="GtkBox">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="hexpand">True</property>
-            <property name="halign">center</property>
-            <property name="margin_start">48</property>
-            <property name="margin_end">48</property>
+            <property name="margin_top">48</property>
+            <property name="margin_bottom">48</property>
+            <property name="orientation">vertical</property>
             <child>
-              <object class="GtkGrid" id="top_grid">
+              <object class="GtkBox" id="time_container">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="halign">center</property>
-                <property name="valign">center</property>
-                <property name="row_spacing">24</property>
-                <property name="column_homogeneous">True</property>
                 <child>
-                  <object class="GtkLabel" id="time_label">
+                  <object class="GtkLabel" id="hours_label">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
+                    <property name="label">00</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <attributes>
+                      <attribute name="font-features" value="tnum=1"/>
+                    </attributes>
                     <style>
-                      <class name="clocks-stopwatch-label"/>
+                      <class name="hours-label"/>
                     </style>
                   </object>
                   <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">0</property>
-                    <property name="width">1</property>
-                    <property name="height">1</property>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkBox" id="button_box">
+                  <object class="GtkLabel">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="hexpand">True</property>
-                    <property name="homogeneous">True</property>
-                    <property name="spacing">16</property>
-                    <property name="height_request">40</property>
+                    <property name="label">:</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="minutes_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label">00</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <attributes>
+                      <attribute name="font-features" value="tnum=1"/>
+                    </attributes>
+                    <style>
+                      <class name="minutes-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label">:</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="seconds_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label">00</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <attributes>
+                      <attribute name="font-features" value="tnum=1"/>
+                    </attributes>
+                    <style>
+                      <class name="seconds-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label">.</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="miliseconds_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="valign">end</property>
+                    <property name="ypad">6</property>
+                    <property name="label">0</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <attributes>
+                      <attribute name="font-features" value="tnum=1"/>
+
+                    </attributes>
+                    <style>
+                      <class name="miliseconds-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+                <style>
+                  <class name="stopped-stopwatch"/>
+                </style>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">6</property>
+                <child>
+                  <object class="GtkButton" id="start_btn">
+                    <property name="label" translatable="yes">Start</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <signal name="clicked" handler="on_start_btn_clicked" swapped="no"/>
+                    <style>
+                      <class name="suggested-action"/>
+                      <class name="large-button"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="clear_btn">
+                    <property name="label" translatable="yes">Clear</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <signal name="clicked" handler="on_clear_btn_clicked" swapped="no"/>
+                    <style>
+                      <class name="large-button"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="pack_type">end</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="padding">48</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRevealer" id="laps_revealer">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="transition_type">crossfade</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
                     <child>
-                      <object class="GtkButton" id="left_button">
-                        <property name="label" translatable="yes">Start</property>
-                        <property name="width_request">132</property>
+                      <object class="GtkBox">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <signal name="clicked" handler="on_left_button_clicked" swapped="no"/>
-                        <style>
-                          <class name="clocks-button"/>
-                        </style>
+                        <property name="can_focus">False</property>
+                        <property name="margin_bottom">6</property>
+                        <child>
+                          <object class="GtkLabel">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="halign">center</property>
+                            <property name="valign">center</property>
+                            <property name="label" translatable="yes">Lap</property>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="halign">center</property>
+                            <property name="valign">center</property>
+                            <property name="label" translatable="yes">Lap Duration</property>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="halign">center</property>
+                            <property name="valign">center</property>
+                            <property name="label" translatable="yes">Difference</property>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
                       </object>
                       <packing>
-                        <property name="expand">True</property>
+                        <property name="expand">False</property>
                         <property name="fill">True</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkButton" id="right_button">
-                        <property name="label" translatable="yes">Reset</property>
-                        <property name="width_request">132</property>
+                      <object class="GtkScrolledWindow">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <signal name="clicked" handler="on_right_button_clicked" swapped="no"/>
-                        <style>
-                          <class name="clocks-button"/>
-                        </style>
+                        <child>
+                          <object class="GtkViewport">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="shadow_type">none</property>
+                            <child>
+                              <object class="GtkListBox" id="laps_list">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="valign">start</property>
+                                <property name="selection_mode">none</property>
+                                <style>
+                                  <class name="frame"/>
+                                </style>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
                       </object>
                       <packing>
                         <property name="expand">True</property>
@@ -86,53 +301,22 @@
                       </packing>
                     </child>
                   </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">1</property>
-                    <property name="width">1</property>
-                    <property name="height">1</property>
-                  </packing>
                 </child>
               </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
             </child>
           </object>
-          <packing>
-            <property name="left_attach">0</property>
-            <property name="top_attach">0</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkScrolledWindow" id="laps_scrollwin">
-            <property name="width_request">320</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="hexpand">False</property>
-            <property name="vexpand">True</property>
-            <property name="shadow_type">in</property>
-            <property name="hscrollbar_policy">never</property>
-            <style>
-              <class name="clocks-laps-panel"/>
-            </style>
-            <child>
-              <object class="GtkListBox" id="laps_list">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="vexpand">False</property>
-                <property name="valign">center</property>
-                <property name="selection_mode">none</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="left_attach">1</property>
-            <property name="top_attach">0</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
-          </packing>
         </child>
       </object>
+      <packing>
+        <property name="expand">True</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
     </child>
   </template>
 </interface>
diff --git a/data/ui/stopwatchlapsrow.ui b/data/ui/stopwatchlapsrow.ui
index d4db2f9..32d1c2c 100644
--- a/data/ui/stopwatchlapsrow.ui
+++ b/data/ui/stopwatchlapsrow.ui
@@ -1,75 +1,73 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
 <interface>
-  <!-- interface-requires gtk+ 3.0 -->
+  <requires lib="gtk+" version="3.14"/>
   <template class="ClocksStopwatchLapsRow" parent="GtkListBoxRow">
     <property name="visible">True</property>
+    <property name="can_focus">False</property>
     <property name="activatable">False</property>
     <child>
       <object class="GtkRevealer" id="slider">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="reveal_child">False</property>
         <child>
-          <object class="GtkGrid" id="grid">
+          <object class="GtkBox">
             <property name="visible">True</property>
-            <property name="orientation">horizontal</property>
-            <property name="column_spacing">12</property>
-            <property name="halign">start</property>
-            <property name="margin">6</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">18</property>
             <child>
-              <object class="GtkLabel" id="num_label">
+              <object class="GtkLabel" id="index_label">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="hexpand">False</property>
-                <property name="xalign">0</property>
+                <property name="halign">center</property>
+                <property name="valign">center</property>
                 <property name="width_chars">3</property>
-                <style>
-                  <class name="dim-label"/>
-                </style>
+                <property name="xalign">0</property>
               </object>
               <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">0</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="split_label">
+              <object class="GtkLabel" id="duration_label">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="halign">center</property>
-                <property name="hexpand">True</property>
+                <property name="valign">center</property>
                 <style>
                   <class name="lap-time"/>
                 </style>
               </object>
               <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">0</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="padding">6</property>
+                <property name="position">1</property>
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="tot_label">
+              <object class="GtkLabel" id="difference_label">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="halign">center</property>
-                <property name="hexpand">True</property>
+                <property name="valign">center</property>
                 <property name="xalign">0.5</property>
               </object>
               <packing>
-                <property name="left_attach">2</property>
-                <property name="top_attach">0</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="padding">6</property>
+                <property name="position">2</property>
               </packing>
             </child>
           </object>
         </child>
       </object>
     </child>
+    <style>
+      <class name="lap-row"/>
+    </style>
   </template>
 </interface>
diff --git a/src/stopwatch.vala b/src/stopwatch.vala
index fca93bb..14b9322 100644
--- a/src/stopwatch.vala
+++ b/src/stopwatch.vala
@@ -19,82 +19,95 @@
 namespace Clocks {
 namespace Stopwatch {
 
-public class Frame : AnalogFrame {
-    private int seconds;
-    private double millisecs;
-
-    public void update (int s, double ms) {
-        seconds = s;
-        millisecs = ms;
-        queue_draw ();
+[GtkTemplate (ui = "/org/gnome/clocks/ui/stopwatchlapsrow.ui")]
+private class LapsRow : Gtk.ListBoxRow {
+    [GtkChild]
+    private Gtk.Revealer slider;
+    [GtkChild]
+    private Gtk.Label index_label;
+    [GtkChild]
+    private Gtk.Label difference_label;
+    [GtkChild]
+    private Gtk.Label duration_label;
+
+    private Lap current;
+    private Lap? before;
+
+    public LapsRow (Lap current, Lap? before) {
+        this.current = current;
+        this.before = before;
+        index_label.label = this.current.get_index();
+        duration_label.label = this.get_duration();
+
+        if (this.before != null) {
+            difference_label.label = this.get_difference_duration();
+        } else {
+            difference_label.hide();
+        }
+        var difference = this.get_difference();
+        if (difference > 0) {
+            get_style_context().add_class("negative-lap");
+        } else if (difference < 0) {
+            get_style_context().add_class("positive-lap");
+        }
     }
 
-    public void reset () {
-        update (0, 0);
+    public string get_duration() {
+        int h;
+        int m;
+        int s;
+        double r;
+        Utils.time_to_hms (Math.floor(this.current.duration * 100) / 100, out h, out m, out s, out r);
+        int cs = (int) (r * 100);
+        return "%02i\u200E∶%02i\u200E∶%02i.%i".printf (h, m, s, cs);
     }
 
-    public override void draw_progress (Cairo.Context cr, int center_x, int center_y, int radius) {
-        var context = get_style_context ();
-
-        context.save ();
-        context.add_class ("progress");
-
-        cr.set_line_width (LINE_WIDTH);
-        cr.set_line_cap  (Cairo.LineCap.ROUND);
-
-        var color = context.get_color (context.get_state ());
-        var progress = ((double) seconds + millisecs) / 60;
-        if (progress > 0) {
-            cr.arc (center_x,
-                    center_y,
-                    radius - LINE_WIDTH / 2,
-                    1.5  * Math.PI,
-                    (1.5 + progress * 2 ) * Math.PI);
-            Gdk.cairo_set_source_rgba (cr, color);
-            cr.stroke ();
+    public double get_difference() {
+        if (this.before != null) {
+            return this.current.duration - this.before.duration;
         }
+        return 0;
+    }
 
-        context.restore ();
-
-        context.save ();
-        context.add_class ("progress-fast");
-
-        cr.set_line_width (LINE_WIDTH - 2);
-        color = context.get_color (context.get_state ());
-        progress = millisecs;
-        if (progress > 0) {
-            cr.arc (center_x,
-                    center_y,
-                    radius - LINE_WIDTH / 2,
-                    (1.5 + progress * 2 ) * Math.PI - 0.1,
-                    (1.5 + progress * 2 ) * Math.PI + 0.1);
-            Gdk.cairo_set_source_rgba (cr, color);
-            cr.stroke ();
+    public string? get_difference_duration() {
+        if (this.before != null) {
+            var difference = Math.floor((this.current.duration - this.before.duration) * 100) / 100;
+            int h;
+            int m;
+            int s;
+            double r;
+            Utils.time_to_hms (difference, out h, out m, out s, out r);
+            int cs = (int) (r * 100);
+            if (difference > 0) {
+                return "- %02i\u200E∶%02i\u200E∶%02i.%i".printf (h.abs(), m.abs(), s.abs(), cs.abs());
+            } else {
+                return "+ %02i\u200E∶%02i\u200E∶%02i.%i".printf (h.abs(), m.abs(), s.abs(), cs.abs());
+            }
         }
+        return null;
+    }
 
-        context.restore ();
+    public void slide_out() {
+        slider.reveal_child = false;
+    }
+
+    public void slide_in () {
+        slider.reveal_child = true;
     }
 }
 
-[GtkTemplate (ui = "/org/gnome/clocks/ui/stopwatchlapsrow.ui")]
-private class LapsRow : Gtk.ListBoxRow {
-    [GtkChild]
-    private Gtk.Revealer slider;
-    [GtkChild]
-    private Gtk.Label num_label;
-    [GtkChild]
-    private Gtk.Label split_label;
-    [GtkChild]
-    private Gtk.Label tot_label;
 
-    public LapsRow (string n, string split, string tot) {
-        num_label.label = n;
-        split_label.label = split;
-        tot_label.label = tot;
+public class Lap : GLib.Object {
+    private int index; // Starts at #1
+    public double duration;
+
+    public Lap(int index, double duration) {
+        this.index = index;
+        this.duration = duration;
     }
 
-    public void slide_in () {
-        slider.reveal_child = true;
+    public string get_index() {
+        return index.to_string();
     }
 }
 
@@ -112,6 +125,8 @@ public class Face : Gtk.Box, Clocks.Clock {
         TOTAL
     }
 
+    private ListStore laps;
+
     public string label { get; construct set; }
     public string icon_name { get; construct set; }
     public HeaderBar header_bar { get; construct set; }
@@ -124,15 +139,23 @@ public class Face : Gtk.Box, Clocks.Clock {
     private int current_lap;
     private double last_lap_time;
     [GtkChild]
-    private Frame analog_frame;
+    private Gtk.Label hours_label;
     [GtkChild]
-    private Gtk.Label time_label;
+    private Gtk.Label minutes_label;
     [GtkChild]
-    private Gtk.Button left_button;
+    private Gtk.Label seconds_label;
     [GtkChild]
-    private Gtk.Button right_button;
+    private Gtk.Label miliseconds_label;
     [GtkChild]
-    private Gtk.ScrolledWindow laps_scrollwin;
+    private Gtk.Box time_container;
+
+    [GtkChild]
+    private Gtk.Revealer laps_revealer;
+
+    [GtkChild]
+    private Gtk.Button start_btn;
+    [GtkChild]
+    private Gtk.Button clear_btn;
     [GtkChild]
     private Gtk.ListBox laps_list;
 
@@ -142,9 +165,30 @@ public class Face : Gtk.Box, Clocks.Clock {
                 header_bar: header_bar,
                 panel_id: PanelId.STOPWATCH);
 
+        laps = new GLib.ListStore(typeof(Lap));
+
         timer = new GLib.Timer ();
         tick_id = 0;
 
+        laps_list.set_header_func((before, after) => {
+            if (after != null) {
+                var separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL);
+                separator.show();
+                before.set_header(separator);
+            }
+        });
+
+        laps_list.bind_model(laps, (lap) => {
+            var total_items = laps.get_n_items();
+            Lap? before = null;
+            if (total_items > 1) {
+                before = (Lap)laps.get_item(total_items - 1); // Get the latest item
+            }
+            var lap_row = new LapsRow((Lap)lap, before);
+            lap_row.slide_in();
+            return lap_row;
+        });
+
         map.connect ((w) => {
             if (state == State.RUNNING) {
                 update_time_label ();
@@ -162,7 +206,7 @@ public class Face : Gtk.Box, Clocks.Clock {
     }
 
     [GtkCallback]
-    private void on_left_button_clicked (Gtk.Button button) {
+    private void on_start_btn_clicked (Gtk.Button button) {
         switch (state) {
         case State.RESET:
         case State.STOPPED:
@@ -177,7 +221,7 @@ public class Face : Gtk.Box, Clocks.Clock {
     }
 
     [GtkCallback]
-    private void on_right_button_clicked (Gtk.Button button) {
+    private void on_clear_btn_clicked (Gtk.Button button) {
         switch (state) {
         case State.STOPPED:
             reset ();
@@ -198,86 +242,75 @@ public class Face : Gtk.Box, Clocks.Clock {
         }
         state = State.RUNNING;
         add_tick ();
-        left_button.set_label (_("Stop"));
-        left_button.get_style_context ().add_class ("destructive-action");
-        right_button.set_sensitive (true);
-        right_button.set_label (_("Lap"));
+        start_btn.set_label (_("Pause"));
+        start_btn.get_style_context ().remove_class ("destructive-action");
+        start_btn.get_style_context ().remove_class ("suggested-action");
+        clear_btn.set_sensitive (true);
+        clear_btn.set_label (_("Lap"));
+        clear_btn.get_style_context().remove_class("destructive-action");
+
+        time_container.get_style_context().add_class ("running-stopwatch");
+        time_container.get_style_context().remove_class ("paused-stopwatch");
+        time_container.get_style_context().remove_class("stopped-stopwatch");
     }
 
     private void stop () {
         timer.stop ();
         state = State.STOPPED;
         remove_tick ();
-        left_button.set_label (_("Continue"));
-        left_button.get_style_context ().remove_class ("destructive-action");
-        left_button.get_style_context ().add_class ("suggested-action");
-        right_button.set_sensitive (true);
-        right_button.set_label (_("Reset"));
+        start_btn.set_label (_("Resume"));
+        start_btn.get_style_context ().remove_class ("destructive-action");
+        start_btn.get_style_context ().add_class ("suggested-action");
+        clear_btn.set_sensitive (true);
+        clear_btn.set_label (_("Clear"));
+        clear_btn.get_style_context().add_class("destructive-action");
+
+        time_container.get_style_context().add_class("paused-stopwatch");
+        time_container.get_style_context().remove_class ("running-stopwatch");
+        time_container.get_style_context().remove_class ("stopped-stopwatch");
     }
 
     private void reset () {
+        laps_revealer.set_reveal_child(false);
+
         timer.reset ();
         state = State.RESET;
         remove_tick ();
         update_time_label ();
-        left_button.set_label (_("Start"));
-        left_button.get_style_context ().add_class ("suggested-action");
-        right_button.set_sensitive (false);
+        start_btn.set_label (_("Start"));
+        start_btn.get_style_context ().add_class ("suggested-action");
+        clear_btn.set_sensitive (false);
+        clear_btn.set_label(_("Lap"));
+        clear_btn.get_style_context().remove_class("destructive-action");
         current_lap = 0;
         last_lap_time = 0;
-        foreach (var l in laps_list.get_children ()) {
-            laps_list.remove (l);
+
+
+        time_container.get_style_context().add_class ("stopped-stopwatch");
+        time_container.get_style_context().remove_class ("paused-stopwatch");
+        time_container.get_style_context().remove_class("running-stopwatch");
+        laps.remove_all();
+    }
+
+    private double total_laps_duration() {
+        double total = 0;
+        for(var i=0; i < laps.get_n_items(); i++) {
+            var lap = (Lap) laps.get_item(i);
+            total += lap.duration;
         }
+        return total;
     }
 
     private void lap () {
         current_lap += 1;
+        laps_revealer.set_reveal_child(current_lap >= 1);
         var e = timer.elapsed ();
-        var split = e - last_lap_time;
-
-        // Discard milliseconds in the saved lap time to ensure
-        // total and split times are consistent: for instance if we saved
-        // 0.108000 and the next lap is 1.202000, we would see on screen 0.10
-        // and 1.20, so we would expect a split time of 1.10, but we would
-        // instead get 1.094000 and thus display 1.09
-        last_lap_time = Math.floor(e * 100) / 100;
-
-        int h;
-        int m;
-        int s;
-        double r;
-        Utils.time_to_hms (e, out h, out m, out s, out r);
-        int cs = (int) (r * 100);
-
-        int split_h;
-        int split_m;
-        int split_s;
-        Utils.time_to_hms (split, out split_h, out split_m, out split_s, out r);
-        int split_cs = (int) (r * 100);
-
-        var n_label = "#%d".printf (current_lap);
-
-        // Note that the format uses unicode RATIO character
-        // We also prepend the LTR mark to make sure text is always in this direction
-
-        string split_label;
-        if (split_h > 0) {
-            split_label = "%i\u200E∶%02i\u200E∶%02i.%02i".printf (split_h, split_m, split_s, split_cs);
-        } else {
-            split_label = "%02i\u200E∶%02i.%02i".printf (split_m, split_s, split_cs);
-        }
-
-        string tot_label;
-        if (h > 0) {
-            tot_label = "%i\u200E∶%02i\u200E∶%02i.%02i".printf (h, m, s, cs);
-        } else {
-            tot_label = "%02i\u200E∶%02i.%02i".printf (m, s, cs);
-        }
-
-        var row = new LapsRow (n_label, split_label, tot_label);
-        laps_list.prepend (row);
-        row.slide_in ();
-        laps_scrollwin.vadjustment.value = laps_scrollwin.vadjustment.lower;
+        print(e.to_string() + "\n");
+        double lap_duration = e - this.total_laps_duration();
+        print(lap_duration.to_string() + "\n");
+        print("#####\n");
+        var lap = new Lap(current_lap, lap_duration);
+        laps.insert(0, lap);
     }
 
     private void add_tick () {
@@ -308,19 +341,16 @@ public class Face : Gtk.Box, Clocks.Clock {
 
         // Note that the format uses unicode RATIO character
         // We also prepend the LTR mark to make sure text is always in this direction
-        if (h > 0) {
-            time_label.set_text ("%i\u200E∶%02i\u200E∶%02i.%i".printf (h, m, s, ds));
-        } else {
-            time_label.set_text ("%02i\u200E∶%02i.%i".printf (m, s, ds));
-        }
-
-        analog_frame.update (s, r);
+        hours_label.set_text("%02i\u200E".printf(h));
+        minutes_label.set_text("%02i\u200E".printf(m));
+        seconds_label.set_text("%02i".printf(s));
+        miliseconds_label.set_text("%i".printf(ds));
 
         return true;
     }
 
     public override void grab_focus () {
-        left_button.grab_focus ();
+        start_btn.grab_focus ();
     }
 
     public bool escape_pressed () {



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