[hamster-applet] no background for timeline, added space between ticks. title moved out of the graph. Og said he like
- From: Toms Baugis <tbaugis src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [hamster-applet] no background for timeline, added space between ticks. title moved out of the graph. Og said he like
- Date: Mon, 11 Jan 2010 21:40:54 +0000 (UTC)
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]