[hamster-applet] added bit of interaction the code is a bit disorganised
- From: Toms Baugis <tbaugis src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [hamster-applet] added bit of interaction the code is a bit disorganised
- Date: Thu, 31 Dec 2009 13:58:24 +0000 (UTC)
commit cc6cac7c0eb924b106b165fb1cbe94babbcb6a7d
Author: Toms Bauģis <toms baugis gmail com>
Date: Thu Dec 31 13:57:09 2009 +0000
added bit of interaction the code is a bit disorganised
hamster/charting.py | 63 +++++++++++++++++----
hamster/stats_reports.py | 136 ++++++++++++++++++++++++++++++++++++----------
2 files changed, 159 insertions(+), 40 deletions(-)
---
diff --git a/hamster/charting.py b/hamster/charting.py
index cc3ac36..0d1f314 100644
--- a/hamster/charting.py
+++ b/hamster/charting.py
@@ -33,7 +33,7 @@ http://projecthamster.wordpress.com/
"""
-import gtk
+import gtk, gobject
import cairo, pango
import copy
import math
@@ -115,6 +115,9 @@ class Chart(graphics.Area):
self.labels_at_end = If stack bars are displayed, this allows to
show them at right end of graph.
"""
+ __gsignals__ = {
+ "bar-clicked": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )),
+ }
def __init__(self, **args):
graphics.Area.__init__(self)
@@ -136,6 +139,8 @@ class Chart(graphics.Area):
self.labels_at_end = args.get("labels_at_end", False)
self.framerate = args.get("framerate", 60)
+ self.interactive = args.get("interactive", False) # if the bars are clickable
+
# other stuff
self.bars = []
self.keys = []
@@ -150,7 +155,28 @@ class Chart(graphics.Area):
self.graph_x, self.graph_y = 0, 0
self.graph_width, self.graph_height = None, None
+ self.mouse_bar = None
+ if self.interactive:
+ self.connect("mouse-over", self.on_mouse_over)
+ self.connect("button-release", self.on_clicked)
+
+ self.bars_selected = []
+
+
+ def on_mouse_over(self, area, region):
+ if region:
+ self.mouse_bar = int(region[0])
+ else:
+ self.mouse_bar = None
+
+ self.redraw_canvas()
+ def on_clicked(self, area, bar):
+ self.emit("bar-clicked", self.mouse_bar)
+
+ def select_bar(self, index):
+ pass
+
def get_bar_color(self, index):
# returns color darkened by it's index
# the approach reduces contrast by each step
@@ -509,25 +535,32 @@ class HorizontalBarChart(Chart):
- context.set_line_width(0)
+ context.set_line_width(1)
# bars and labels
self.layout.set_width(legend_width * pango.SCALE)
for i, label in enumerate(keys):
+ if self.interactive:
+ self.register_mouse_region(0,
+ positions[label][0],
+ self.width,
+ positions[label][0] + positions[label][1],
+ str(i))
+
self.layout.set_width(legend_width * pango.SCALE)
- self.set_color(graphics.Colors.aluminium[5])
-
self.layout.set_text(label)
label_w, label_h = self.layout.get_pixel_size()
-
+
+ self.set_color(graphics.Colors.aluminium[5])
context.move_to(0, positions[label][0] + (positions[label][1] - label_h) / 2)
context.show_layout(self.layout)
base_color = self.bar_base_color or (220, 220, 220)
last_color = (255,255,255)
+
if self.stack_keys:
bar_start = 0
@@ -550,7 +583,12 @@ class HorizontalBarChart(Chart):
bar_size = round(max_bar_size * self.bars[i].size)
bar_start = bar_size
- last_color = self.key_colors.get(self.keys[i]) or base_color
+ if i in self.bars_selected:
+ last_color = self.get_style().bg[gtk.STATE_SELECTED].to_string()
+ elif i == self.mouse_bar:
+ last_color = self.get_style().bg[gtk.STATE_PRELIGHT].to_string()
+ else:
+ last_color = self.key_colors.get(self.keys[i]) or base_color
self.draw_bar(self.graph_x,
positions[label][0],
@@ -573,11 +611,14 @@ class HorizontalBarChart(Chart):
label_x = self.graph_x + bar_start + vertical_padding
self.set_color(graphics.Colors.aluminium[5])
else:
- # we are in the bar so make sure that the font color is distinguishable
- if colorsys.rgb_to_hls(*graphics.Colors.rgb(last_color))[1] < 150:
- self.set_color(graphics.Colors.almost_white)
+ if i in self.bars_selected:
+ self.set_color(self.get_style().fg[gtk.STATE_SELECTED].to_string())
else:
- self.set_color(graphics.Colors.aluminium[5])
+ # we are in the bar so make sure that the font color is distinguishable
+ if colorsys.rgb_to_hls(*graphics.Colors.rgb(last_color))[1] < 150:
+ self.set_color(graphics.Colors.almost_white)
+ else:
+ self.set_color(graphics.Colors.aluminium[5])
label_x = self.graph_x + bar_start - label_w - vertical_padding
@@ -638,8 +679,6 @@ class HorizontalDayChart(Chart):
return
- self.context.translate(0.5, 0.5)
-
positions = {}
y = 0
bar_width = min(self.graph_height / float(len(self.keys)), self.max_bar_width)
diff --git a/hamster/stats_reports.py b/hamster/stats_reports.py
index c1b7598..e255e59 100644
--- a/hamster/stats_reports.py
+++ b/hamster/stats_reports.py
@@ -58,21 +58,33 @@ class ReportsBox(gtk.VBox):
max_bar_width = 20,
legend_width = x_offset,
value_format = "%.1f",
- animate = False)
+ interactive = True)
+ self.category_chart.connect("bar-clicked", self.on_category_clicked)
+ self.selected_categories = []
+ self.category_sums = None
+
self.get_widget("totals_by_category").add(self.category_chart);
self.activity_chart = charting.HorizontalBarChart(background = self.background,
max_bar_width = 20,
legend_width = x_offset,
value_format = "%.1f",
- animate = False)
+ interactive = True)
+ self.activity_chart.connect("bar-clicked", self.on_activity_clicked)
+ self.selected_activities = []
+ self.activity_sums = None
+
self.get_widget("totals_by_activity").add(self.activity_chart);
self.tag_chart = charting.HorizontalBarChart(background = self.background,
max_bar_width = 20,
legend_width = x_offset,
value_format = "%.1f",
- animate = False)
+ interactive = True)
+ self.tag_chart.connect("bar-clicked", self.on_tag_clicked)
+ self.selected_tags = []
+ self.tag_sums = None
+
self.get_widget("totals_by_tag").add(self.tag_chart);
@@ -83,13 +95,47 @@ class ReportsBox(gtk.VBox):
self.report_chooser = None
+
+ def on_category_clicked(self, widget, idx):
+ if idx in self.category_chart.bars_selected:
+ self.category_chart.bars_selected.remove(idx)
+ self.selected_categories.remove(self.category_sums[0][idx])
+ else:
+ self.category_chart.bars_selected.append(idx)
+ self.selected_categories.append(self.category_sums[0][idx])
+ self.do_charts()
+
+ def on_activity_clicked(self, widget, idx):
+ if idx in self.activity_chart.bars_selected:
+ self.activity_chart.bars_selected.remove(idx)
+ self.selected_activities.remove(self.activity_sums[0][idx])
+ else:
+ self.activity_chart.bars_selected.append(idx)
+ self.selected_activities.append(self.activity_sums[0][idx])
+ self.do_charts()
+
+ def on_tag_clicked(self, widget, idx):
+ if idx in self.tag_chart.bars_selected:
+ self.tag_chart.bars_selected.remove(idx)
+ self.selected_tags.remove(self.tag_sums[0][idx])
+ else:
+ self.tag_chart.bars_selected.append(idx)
+ self.selected_tags.append(self.tag_sums[0][idx])
+ self.do_charts()
+
+
def on_reports_box_expose_event(self, box, someth):
self.do_charts()
def search(self, start_date, end_date, facts):
self.facts = facts
+ self.category_sums, self.activity_sums, self.tag_sums = [], [], []
+ self.selected_categories, self.selected_activities, self.selected_tags = [], [], []
+ self.category_chart.bars_selected, self.activity_chart.bars_selected, self.tag_chart.bars_selected = [], [], []
+
self.start_date = start_date
self.end_date = end_date
+
self.do_graph()
def do_graph(self):
@@ -105,46 +151,80 @@ class ReportsBox(gtk.VBox):
def do_charts(self):
if not self.facts:
return
+
+ import copy
+ facts = copy.deepcopy(self.facts)
- #totals by category
- category_sums = stuff.totals(self.facts,
+ for fact in facts:
+ if self.selected_categories and fact["category"] not in self.selected_categories:
+ fact["delta"] = dt.timedelta()
+ if self.selected_activities and fact["name"] not in self.selected_activities:
+ fact["delta"] = dt.timedelta()
+ if self.selected_tags and len(set(self.selected_tags) - set(fact["tags"])) > 0:
+ fact["delta"] = dt.timedelta()
+
+
+
+ # category totals
+ category_sums = stuff.totals(facts,
lambda fact: (fact["category"]),
lambda fact: stuff.duration_minutes(fact["delta"]) / 60.0)
if category_sums:
- category_sums = sorted(category_sums.items(), key=lambda x:x[1], reverse = True)
- keys, values = zip(*category_sums)
- self.get_widget("totals_by_category").set_size_request(280, len(keys) * 20)
- self.category_chart.plot(keys, values)
- else:
- self.category_chart.plot([], [])
-
-
- #totals by activity
- activity_sums = stuff.totals(self.facts,
+ if self.category_sums:
+ category_sums = [(key, category_sums[key]) for key in self.category_sums[0]]
+ else:
+ category_sums = sorted(category_sums.items(), key=lambda x:x[1], reverse = True)
+ self.category_sums = zip(*category_sums)
+
+ # activity totals
+ activity_sums = stuff.totals(facts,
lambda fact: (fact["name"]),
lambda fact: stuff.duration_minutes(fact["delta"]) / 60.0)
- activity_sums = sorted(activity_sums.items(), key=lambda x:x[1], reverse = True)
- keys, values = zip(*activity_sums)
- self.get_widget("totals_by_activity").set_size_request(10,10)
- self.get_widget("totals_by_activity").set_size_request(280, len(keys) * 20)
- self.activity_chart.plot(keys, values)
+ if self.activity_sums:
+ activity_sums = [(key, activity_sums[key]) for key in self.activity_sums[0]]
+ else:
+ activity_sums = sorted(activity_sums.items(), key=lambda x:x[1], reverse = True)
+ self.activity_sums = zip(*activity_sums)
+
+ # tag totals
tag_sums = {}
- for fact in self.facts:
+ for fact in facts:
for tag in fact["tags"]:
tag_sums.setdefault(tag, 0)
tag_sums[tag] += stuff.duration_minutes(fact["delta"]) / 60.0
if tag_sums:
- tag_sums = sorted(tag_sums.items(), key=lambda x:x[1], reverse = True)
- keys, values = zip(*tag_sums)
- self.get_widget("totals_by_tag").set_size_request(10,10)
- self.get_widget("totals_by_tag").set_size_request(280, len(keys) * 20)
- self.tag_chart.plot(keys, values)
+ if self.tag_sums:
+ tag_sums = [(key, tag_sums[key]) for key in self.tag_sums[0]]
+ else:
+ tag_sums = sorted(tag_sums.items(), key=lambda x:x[1], reverse = True)
+ self.tag_sums = zip(*tag_sums)
+
+
+
+
+ self.get_widget("totals_by_category").set_size_request(10,10)
+ if self.category_sums:
+ self.get_widget("totals_by_category").set_size_request(280, len(self.category_sums[0]) * 20)
+ self.category_chart.plot(*self.category_sums)
else:
- self.tag_chart.plot([], [])
-
+ self.get_widget("totals_by_category").set_size_request(280, 10)
+ self.category_chart.plot(([],[]))
+
+ self.get_widget("totals_by_activity").set_size_request(10,10)
+ self.get_widget("totals_by_activity").set_size_request(280, len(self.activity_sums[0]) * 20)
+ self.activity_chart.plot(*self.activity_sums)
+
+ self.get_widget("totals_by_tag").set_size_request(10,10)
+ if self.tag_sums:
+ self.get_widget("totals_by_tag").set_size_request(280, len(self.tag_sums[0]) * 20)
+ self.tag_chart.plot(*self.tag_sums)
+ else:
+ self.get_widget("totals_by_tag").set_size_request(280, 10)
+ self.tag_chart.plot(([],[]))
+
def get_widget(self, name):
""" skip one variable (huh) """
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]