+class CustomEventBox(gtk.EventBox):
+
+ def __init__(self):
+ gtk.EventBox.__init__(self)
+
+ def do_expose_event(self, event):
+ self.context = self.window.cairo_create()
+ self.context.rectangle(event.area.x, event.area.y,
+ event.area.width, event.area.height)
+
+ self.context.clip()
+ rect = self.get_allocation()
+ self.context.rectangle(rect.x, rect.y, rect.width, rect.height)
+
+ if self.state == gtk.STATE_ACTIVE:
+ style = self.rc_get_style()
+ color = style.lookup_color("SelectionColor")
+ self.context.set_source_rgba (color.red / 65535.0, color.green / 65335.0, color.blue / 65535.0, 0.75);
+ else:
+ self.context.set_source_rgba(1, 1, 1, 0)
+ self.context.fill()
+
+ gtk.EventBox.do_expose_event(self, event)
+
+class GraphController(Singleton):
+ ytitles = ["Steps", "Average Speed", "Distance", "Calories"]
+ xtitles = ["Day", "Week"] # "Today"]
+ widget = None
+ def __init__(self):
+ self.repository = PedoRepositoryXML()
+ self.last_update = 0
+
+ def set_graph(self, widget):
+ self.widget = widget
+ self.update_ui()
+
+ def set_current_view(self, view):
+ """
+ current_view % len(ytitles) - gives the ytitle
+ current_view / len(ytitles) - gives the xtitle
+ """
+ self.current_view = view
+
+ if self.current_view == len(self.ytitles) * len(self.xtitles):
+ self.current_view = 0
+ self.x_id = self.current_view / len(self.ytitles)
+ self.y_id = self.current_view % len(self.ytitles)
+
+ def next_view(self):
+ self.set_current_view(self.current_view+1)
+ self.update_ui()
+ return self.current_view
+
+ def last_weeks_labels(self):
+ d = date.today()
+ delta = timedelta(days=7)
+ ret = []
+ for i in range(7):
+ ret.append(d.strftime("Week %W"))
+ d = d - delta
+ return ret
+
+ def compute_values(self):
+ labels = []
+ if self.x_id == 0:
+ values = self.repository.get_last_7_days()
+ d = date.today()
+ delta = timedelta(days=1)
+ for i in range(7):
+ labels.append(d.ctime().split()[0])
+ d = d - delta
+
+ elif self.x_id == 1:
+ values = self.repository.get_last_weeks()
+ d = date.today()
+ for i in range(7):
+ labels.append(d.strftime("Week %W"))
+ d = d - timedelta(days=7)
+ else:
+ values = self.repository.get_today()
+ #TODO get labels
+
+ if self.y_id == 0:
+ yvalues = [line.steps for line in values]
+ elif self.y_id == 1:
+ yvalues = [line.get_avg_speed() for line in values]
+ elif self.y_id == 2:
+ yvalues = [line.dist for line in values]
+ else:
+ yvalues = [line.calories for line in values]
+
+ #determine values for y lines in graph
+ diff = self.get_best_interval_value(max(yvalues))
+ ytext = []
+ for i in range(6):
+ s = str(int(i*diff))
+ while len(s) < 5:
+ s = ' ' + s
+ ytext.append(s)
+
+ if self.widget is not None:
+ yvalues.reverse()
+ labels.reverse()
+ self.widget.values = yvalues
+ self.widget.ytext = ytext
+ self.widget.xtext = labels
+ self.widget.max_value = diff * 5
+ self.widget.text = self.xtitles[self.x_id] + " / " + self.ytitles[self.y_id]
+ self.widget.queue_draw()
+ else:
+ logger.error("Widget not set in GraphController")
+
+ def get_best_interval_value(self, max_value):
+ diff = 1.0 * max_value / 5
+ l = len(str(int(diff)))
+ d = math.pow(10, l/2)
+ val = int(math.ceil(1.0 * diff / d)) * d
+ if val == 0:
+ val = 1
+ return val
+
+ def update_ui(self, optional=False):
+ """update graph values every x seconds"""
+ if optional and self.last_update - time.time() < 600:
+ return
+ if self.widget is None:
+ return
+
+ print "update_ui"
+ self.compute_values()
+ self.last_update = time.time()
+
+class GraphWidget(gtk.DrawingArea):
+
+ def __init__(self):
+ gtk.DrawingArea.__init__(self)
+ self.set_size_request(-1, 150)
+ self.yvalues = 5
+ self.ytext = [" 0", "1000", "2000", "3000", "4000", "5000"]
+ self.xtext = ["Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday", "Sunday"]
+ self.values = [1500, 3400, 4000, 3600, 3200, 0, 4500]
+ self.max_value = 5000
+ self.text = "All time steps"
+
+ def do_expose_event(self, event):
+ context = self.window.cairo_create()
+
+ # set a clip region for the expose event
+ context.rectangle(event.area.x, event.area.y,
+ event.area.width, event.area.height)
+ context.clip()
+
+ context.save()
+
+ context.set_operator(cairo.OPERATOR_SOURCE)
+ style = self.rc_get_style()
+
+ if self.state == gtk.STATE_ACTIVE:
+ color = style.lookup_color("SelectionColor")
+ else:
+ color = style.lookup_color("DefaultBackgroundColor")
+ context.set_source_rgba (color.red / 65535.0, color.green / 65335.0, color.blue / 65535.0, 0.75)
+
+ context.paint()
+ context.restore();
+ self.draw(context)
+
+ def draw(self, cr):
+ print self.max_value
+ space_below = 20
+ space_above = 10
+ border_right = 10
+ border_left = 30
+ rect = self.get_allocation()
+ x = rect.width
+ y = rect.height
+
+ cr.set_source_rgb(1, 1, 1)
+ cr.move_to(border_left, space_above)
+ cr.line_to(border_left, y-space_below)
+ cr.set_line_width(2)
+ cr.stroke()
+
+ cr.move_to(border_left, y-space_below)
+ cr.line_to(x-border_right, y-space_below)
+ cr.set_line_width(2)
+ cr.stroke()
+
+ ydiff = (y-space_above-space_below) / self.yvalues
+ for i in range(self.yvalues):
+ yy = y-space_below-ydiff*(i+1)
+ cr.move_to(border_left, yy)
+ cr.line_to(x-border_right, yy)
+ cr.set_line_width(0.8)
+ cr.stroke()
+
+ cr.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL,
+ cairo.FONT_WEIGHT_NORMAL)
+ cr.set_font_size(13)
+ for i in range(6):
+ yy = y - space_below - ydiff*i + 5
+ cr.move_to(1, yy)
+ cr.show_text(self.ytext[i])
+
+ cr.set_font_size(15)
+ cr.move_to(x/3, y-5)
+ cr.show_text(self.text)
+
+ graph_x_space = x - border_left - border_right
+ graph_y_space = y - space_below - space_above
+ bar_width = graph_x_space*0.75 / len(self.values)
+ bar_distance = graph_x_space*0.25 / (1+len(self.values))
+
+ #set dummy max value to avoid exceptions
+ if self.max_value == 0:
+ self.max_value = 100
+
+ for i in range(len(self.values)):
+ xx = border_left + (i+1)*bar_distance + i * bar_width
+ yy = y-space_below
+ height = graph_y_space * (1.0 * self.values[i] / self.max_value)
+ cr.set_source_rgba(1, 1, 1, 0.75)
+ cr.rectangle(int(xx), int(yy-height), int(bar_width), int(height))
+ cr.fill()
+
+ cr.set_source_rgba(1, 1, 1, 1)
+ cr.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL,
+ cairo.FONT_WEIGHT_NORMAL)
+ cr.set_font_size(13)
+
+ cr.rotate(2*math.pi * (-45) / 180)
+ for i in range(len(self.values)):
+ xx = y - space_below - 10
+ yy = border_left + (i+1)*bar_distance + i * bar_width
+ cr.move_to(-xx, yy + bar_width*1.25 / 2)
+ cr.show_text(self.xtext[i])
+