[hamster-applet] no background for timeline, added space between ticks. title moved out of the graph. Og said he like



commit 7c85e5ded9999c2ce1be27375a94bbf8ff5ce5cb
Author: Toms Bauģis <toms baugis gmail com>
Date:   Mon Jan 11 20:53:49 2010 +0000

    no background for timeline, added space between ticks. title moved out of the graph. Og said he liked it, so i said that i'll commit it, because the documentation announce freeze thing is coming and after that i'll have to send out emails.

 data/stats.ui               |   29 ++++++++-
 hamster/stats.py            |  133 +++++++++++++++++-------------------------
 hamster/stats_stats.py      |   11 +++-
 hamster/widgets/timeline.py |   70 +++++++++++++---------
 4 files changed, 131 insertions(+), 112 deletions(-)
---
diff --git a/data/stats.ui b/data/stats.ui
index a27f458..4e47058 100644
--- a/data/stats.ui
+++ b/data/stats.ui
@@ -273,11 +273,34 @@
             <property name="left_padding">12</property>
             <property name="right_padding">12</property>
             <child>
-              <object class="GtkAlignment" id="by_day_box">
-                <property name="height_request">80</property>
+              <object class="GtkVBox" id="vbox2">
                 <property name="visible">True</property>
+                <property name="orientation">vertical</property>
                 <child>
-                  <placeholder/>
+                  <object class="GtkLabel" id="range_title">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label">Range</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                      <attribute name="size" value="15000"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="by_day_box">
+                    <property name="height_request">70</property>
+                    <property name="visible">True</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
                 </child>
               </object>
             </child>
diff --git a/hamster/stats.py b/hamster/stats.py
index 5a6a9d9..ec65a1b 100644
--- a/hamster/stats.py
+++ b/hamster/stats.py
@@ -38,68 +38,6 @@ from stats_overview import OverviewBox
 from stats_reports import ReportsBox
 
 
-class FramedTimeline(widgets.TimeLine):
-    def __init__(self):
-        widgets.TimeLine.__init__(self)
-    
-
-    def draw(self, facts, start_date, end_date):
-        self.start_date = start_date
-        self.end_date = end_date
-        self.set_title(start_date, end_date)
-        widgets.TimeLine.draw(self, facts, start_date, end_date)
-
-    def on_expose(self):
-        widgets.TimeLine.on_expose(self)
-
-        self.rectangle(0.5, 0.5, self.width - 1, self.height + 1, "#999")
-        self.context.stroke()
-
-        self.layout.set_width(-1)
-        self.set_color("#aaaaaa")
-        self.context.move_to(4, 4)
-        font = pango.FontDescription(gtk.Style().font_desc.to_string())
-        font.set_size(14 * pango.SCALE)
-        font.set_weight(pango.WEIGHT_BOLD)
-        self.layout.set_font_description(font)
-
-        self.layout.set_markup(self.title)
-        self.context.show_layout(self.layout)
-
-
-
-    def set_title(self, start_date, end_date):
-        dates_dict = stuff.dateDict(start_date, "start_")
-        dates_dict.update(stuff.dateDict(end_date, "end_"))
-        
-        if start_date == end_date:
-            # date format for overview label when only single day is visible
-            # Using python datetime formatting syntax. See:
-            # http://docs.python.org/library/time.html#time.strftime
-            start_date_str = start_date.strftime(_("%B %d, %Y"))
-            # Overview label if looking on single day
-            self.title = start_date_str
-        elif start_date.year != end_date.year:
-            # overview label if start and end years don't match
-            # letter after prefixes (start_, end_) is the one of
-            # standard python date formatting ones- you can use all of them
-            # see http://docs.python.org/library/time.html#time.strftime
-            self.title = _(u"%(start_B)s %(start_d)s, %(start_Y)s â?? %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
-        elif start_date.month != end_date.month:
-            # overview label if start and end month do not match
-            # letter after prefixes (start_, end_) is the one of
-            # standard python date formatting ones- you can use all of them
-            # see http://docs.python.org/library/time.html#time.strftime
-            self.title = _(u"%(start_B)s %(start_d)s â?? %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
-        else:
-            # overview label for interval in same month
-            # letter after prefixes (start_, end_) is the one of
-            # standard python date formatting ones- you can use all of them
-            # see http://docs.python.org/library/time.html#time.strftime
-            self.title = _(u"%(start_B)s %(start_d)s â?? %(end_d)s, %(end_Y)s") % dates_dict
-
-
-
 class StatsViewer(object):
     def __init__(self, parent = None):
         self.parent = parent# determine if app should shut down on close
@@ -160,7 +98,7 @@ class StatsViewer(object):
         self.end_date_input.connect("date-entered", self.on_end_date_entered)
         self.get_widget("range_end_box").add(self.end_date_input)
 
-        self.timeline = FramedTimeline()
+        self.timeline = widgets.TimeLine()
         self.get_widget("by_day_box").add(self.timeline)
 
         self._gui.connect_signals(self)
@@ -171,22 +109,6 @@ class StatsViewer(object):
         self.window.show_all()
         self.search()
 
-    def on_fact_selection_changed(self, tree):
-        """ enables and disables action buttons depending on selected item """
-        selection = tree.get_selection()
-        (model, iter) = selection.get_selected()
-
-        id = -1
-        if iter:
-            id = model[iter][0]
-
-        self.get_widget('remove').set_sensitive(id != -1)
-        self.get_widget('edit').set_sensitive(id != -1)
-
-        return True
-
-    def after_activity_update(self, widget, renames):
-        self.search()
 
     def search(self):
         if self.start_date > self.end_date: # make sure the end is always after beginning
@@ -200,6 +122,8 @@ class StatsViewer(object):
 
         self.get_widget("report_button").set_sensitive(len(self.facts) > 0)
 
+        self.set_title()
+
         self.timeline.draw(self.facts, self.start_date, self.end_date)
 
 
@@ -210,6 +134,57 @@ class StatsViewer(object):
             self.reports.search(self.start_date, self.end_date, self.facts)
             self.overview.search(self.start_date, self.end_date, self.facts)
 
+    def set_title(self):
+        start_date, end_date = self.start_date, self.end_date
+        dates_dict = stuff.dateDict(start_date, "start_")
+        dates_dict.update(stuff.dateDict(end_date, "end_"))
+        
+        if start_date == end_date:
+            # date format for overview label when only single day is visible
+            # Using python datetime formatting syntax. See:
+            # http://docs.python.org/library/time.html#time.strftime
+            start_date_str = start_date.strftime(_("%B %d, %Y"))
+            # Overview label if looking on single day
+            self.title = start_date_str
+        elif start_date.year != end_date.year:
+            # overview label if start and end years don't match
+            # letter after prefixes (start_, end_) is the one of
+            # standard python date formatting ones- you can use all of them
+            # see http://docs.python.org/library/time.html#time.strftime
+            self.title = _(u"%(start_B)s %(start_d)s, %(start_Y)s â?? %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
+        elif start_date.month != end_date.month:
+            # overview label if start and end month do not match
+            # letter after prefixes (start_, end_) is the one of
+            # standard python date formatting ones- you can use all of them
+            # see http://docs.python.org/library/time.html#time.strftime
+            self.title = _(u"%(start_B)s %(start_d)s â?? %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
+        else:
+            # overview label for interval in same month
+            # letter after prefixes (start_, end_) is the one of
+            # standard python date formatting ones- you can use all of them
+            # see http://docs.python.org/library/time.html#time.strftime
+            self.title = _(u"%(start_B)s %(start_d)s â?? %(end_d)s, %(end_Y)s") % dates_dict
+
+        self.get_widget("range_title").set_text(self.title)
+
+
+    def on_fact_selection_changed(self, tree):
+        """ enables and disables action buttons depending on selected item """
+        selection = tree.get_selection()
+        (model, iter) = selection.get_selected()
+
+        id = -1
+        if iter:
+            id = model[iter][0]
+
+        self.get_widget('remove').set_sensitive(id != -1)
+        self.get_widget('edit').set_sensitive(id != -1)
+
+        return True
+
+    def after_activity_update(self, widget, renames):
+        self.search()
+
     def on_search_activate(self, widget):
         self.search()
         
diff --git a/hamster/stats_stats.py b/hamster/stats_stats.py
index 761e759..ddf80d3 100644
--- a/hamster/stats_stats.py
+++ b/hamster/stats_stats.py
@@ -35,6 +35,15 @@ from configuration import runtime
 
 from hamster.i18n import C_
 
+class TimelineBackground(widgets.TimeLine):
+    def __init__(self):
+        widgets.TimeLine.__init__(self)
+        self.bar_color = (220, 220, 220)
+    
+    def on_expose(self):
+        self.fill_area(0, 0, self.width, self.height, (0.975, 0.975, 0.975))
+        widgets.TimeLine.on_expose(self)
+
 
 class StatsViewer(object):
     def __init__(self, parent = None):
@@ -51,7 +60,7 @@ class StatsViewer(object):
 
         self.stat_facts = None
 
-        self.timeline = widgets.TimeLine()
+        self.timeline = TimelineBackground()
         self.get_widget("explore_everything").add(self.timeline)
         self.get_widget("explore_everything").show_all()
 
diff --git a/hamster/widgets/timeline.py b/hamster/widgets/timeline.py
index fb100bc..982358c 100644
--- a/hamster/widgets/timeline.py
+++ b/hamster/widgets/timeline.py
@@ -46,6 +46,8 @@ class TimeLine(graphics.Area):
         self.minor_tick = None
         
         self.tick_totals = []
+        
+        self.bar_color = "#ccc"
 
         
     def draw(self, facts, start_date, end_date):
@@ -113,20 +115,32 @@ class TimeLine(graphics.Area):
     def on_expose(self):
         self.context.set_line_width(1)
 
-        self.fill_area(0, 0, self.width, self.height, "#fafafa")
-        self.context.stroke()
-        
         self.height = self.height - 2
         graph_x = 2
         graph_width = self.width - graph_x - 2
 
-        if not self.facts:
-            return
         
         total_minutes = stuff.duration_minutes(self.end_time - self.start_time)
         bar_width = float(graph_width) / len(self.tick_totals)
 
 
+        # major ticks
+        all_times = [tick[0] for tick in self.tick_totals]
+
+        if self.end_time - self.start_time < dt.timedelta(days=3):  # about the same day
+            major_step = dt.timedelta(seconds = 60 * 60)
+        else:
+            major_step = dt.timedelta(days=1)
+        
+        x = graph_x
+        major_tick_step = graph_width / (total_minutes / float(stuff.duration_minutes(major_step)))
+        current_time = self.start_time
+        
+
+        def first_weekday(date):
+            return (date.weekday() + 1 - self.first_weekday) % 7 == 0
+
+        
         # calculate position of each bar
         # essentially we care more about the exact 1px gap between bars than about the bar width
         # so after each iteration, we adjust the bar width
@@ -134,24 +148,21 @@ class TimeLine(graphics.Area):
         exes = {}
         adapted_bar_width = bar_width
         for i, (current_time, total) in enumerate(self.tick_totals):
+            
+            # move the x bit further when ticks kick in
+            if (major_step < DAY and current_time.time() == dt.time(0,0)) \
+               or (self.minor_tick == DAY and first_weekday(current_time)) \
+               or (self.minor_tick <= WEEK and current_time.day == 1) \
+               or (current_time.timetuple().tm_yday == 1):
+                x+=2
+
             exes[current_time] = (x, round(adapted_bar_width)) #saving those as getting pixel precision is not an exact science
             x = round(x + adapted_bar_width)
             adapted_bar_width = (self.width - x) / float(max(len(self.tick_totals) - i - 1, 1))
         
 
 
-        # major ticks
-        all_times = [tick[0] for tick in self.tick_totals]
 
-        if self.end_time - self.start_time < dt.timedelta(days=3):  # about the same day
-            major_step = dt.timedelta(seconds = 60 * 60)
-        else:
-            major_step = dt.timedelta(days=1)
-        
-        x = graph_x
-        major_tick_step = graph_width / (total_minutes / float(stuff.duration_minutes(major_step)))
-        current_time = self.start_time
-        
         def line(x, color):
             self.context.move_to(round(x) + 0.5, 0)
             self.set_color(color)
@@ -166,9 +177,9 @@ class TimeLine(graphics.Area):
             x, width = exes[left_index]
             line(x + round(width * adjustment) - 1, color)
         
-        def first_weekday(date):
-            return (date.weekday() + 1 - self.first_weekday) % 7 == 0
         
+        # mark tick lines
+        current_time = self.start_time
         while current_time < self.end_time:
             current_time += major_step
             x += major_tick_step
@@ -178,26 +189,25 @@ class TimeLine(graphics.Area):
             
             if major_step < DAY:  # about the same day
                 if current_time.time() == dt.time(0,0): # midnight
-                    line(exes[current_time][0] - 1, "#aaaaaa")
+                    line(exes[current_time][0] - 2, "#bbb")
             else:
                 if self.minor_tick == DAY:  # week change
                     if first_weekday(current_time):
-                        line(exes[current_time][0] - 1, "#cccccc")
+                        line(exes[current_time][0] - 2, "#bbb")
     
                 if self.minor_tick <= WEEK:  # month change
                     if current_time.day == 1:
                         if current_time in exes:
-                            line(exes[current_time][0] - 1, "#999999")
+                            line(exes[current_time][0] - 2, "#bbb")
                         else: #if we are somewhere in middle then it gets a bit more complicated
-                            somewhere_in_middle(current_time, "#999999")
+                            somewhere_in_middle(current_time, "#bbb")
         
                 # year change    
                 if current_time.timetuple().tm_yday == 1: # year change
                     if current_time in exes:
-                        line(exes[current_time][0] - 1, "#00ff00")
+                        line(exes[current_time][0] - 2, "#f00")
                     else: #if we are somewhere in middle - then just draw it
-                        somewhere_in_middle(current_time, "#00ff00")
-
+                        somewhere_in_middle(current_time, "#f00")
 
 
         # the bars        
@@ -205,8 +215,10 @@ class TimeLine(graphics.Area):
             bar_size = max(round(self.height * total * 0.9), 1)
             x, bar_width = exes[current_time]
 
-            self.fill_area(x, self.height - bar_size, min(bar_width - 1, self.width - x - 2), bar_size, "#E4E4E4")
-
+            self.set_color(self.bar_color)
+            self.context.rectangle(x, self.height - min(bar_size, 2), min(bar_width - 1, self.width - x - 2), min(bar_size, 2))
+            self.draw_rect(x, self.height - bar_size, min(bar_width - 1, self.width - x - 2), bar_size, 3)
+            self.context.fill()
 
 
         #minor tick format
@@ -224,7 +236,7 @@ class TimeLine(graphics.Area):
             step_format = "%H<small><sup>%M</sup></small>"
 
 
-        # ticks. we loop once again to avoid next bar overlapping previous text
+        # tick labels. we loop once again to avoid next bar overlapping previous text
         for i, (current_time, total) in enumerate(self.tick_totals):
             if (self.end_time - self.start_time) > dt.timedelta(10) \
                and self.minor_tick == DAY and first_weekday(current_time) == False:
@@ -232,7 +244,7 @@ class TimeLine(graphics.Area):
             
             x, bar_width = exes[current_time]
 
-            self.set_color("#aaaaaa")
+            self.set_color("#666")
             self.layout.set_width(int((self.width - x) * pango.SCALE))
             self.layout.set_markup(current_time.strftime(step_format))
             w, h = self.layout.get_pixel_size()



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