hamster-applet r824 - trunk/hamster
- From: tbaugis svn gnome org
- To: svn-commits-list gnome org
- Subject: hamster-applet r824 - trunk/hamster
- Date: Sun, 1 Mar 2009 17:31:08 +0000 (UTC)
Author: tbaugis
Date: Sun Mar 1 17:31:07 2009
New Revision: 824
URL: http://svn.gnome.org/viewvc/hamster-applet?rev=824&view=rev
Log:
shuffling stuff - added our own internal matrix transformations that
allow to keep text intact (like size, ratio and whatnot).
using the transformation where saw it suitable
Modified:
trunk/hamster/charting.py
trunk/hamster/edit_activity.py
trunk/hamster/graphics.py
Modified: trunk/hamster/charting.py
==============================================================================
--- trunk/hamster/charting.py (original)
+++ trunk/hamster/charting.py Sun Mar 1 17:31:07 2009
@@ -174,8 +174,6 @@
def draw_bar(self, x, y, w, h, color = None):
""" draws a simple bar"""
- context = self.context
-
base_color = color or self.bar_base_color or (220, 220, 220)
if self.bars_beveled:
@@ -264,7 +262,7 @@
self.context.fill()
#forward to specific implementations
- self._draw()
+ self._draw(self.context)
self.context.stroke()
return False
@@ -296,9 +294,8 @@
class BarChart(Chart):
- def _draw(self):
- # graph box dimensions
-
+ def _draw(self, context):
+ # determine graph dimensions
if self.show_stack_labels:
legend_width = self.legend_width or self.longest_label(self.keys)
elif self.show_scale:
@@ -306,7 +303,7 @@
grid_stride = int(self.max_value * self.grid_stride)
else:
grid_stride = int(self.grid_stride)
-
+
scale_labels = [self.value_format % i
for i in range(grid_stride, int(self.max_value), grid_stride)]
legend_width = self.legend_width or self.longest_label(scale_labels)
@@ -314,74 +311,55 @@
legend_width = self.legend_width
if self.stack_keys and self.labels_at_end:
- graph_x = 0
- graph_width = self.width - legend_width
+ self.graph_x = 0
+ self.graph_width = self.width - legend_width
else:
- graph_x = legend_width + 8 # give some space to scale labels
- graph_width = self.width - graph_x - 10
+ self.graph_x = legend_width + 8 # give some space to scale labels
+ self.graph_width = self.width - self.graph_x - 10
-
-
-
- graph_y = 0
- graph_height = self.height - 15
+ self.graph_y = 0
+ self.graph_height = self.height - 15
+ if self.chart_background:
+ self.fill_area(self.graph_x, self.graph_y,
+ self.graph_width, self.graph_height,
+ self.chart_background)
- self.context.set_line_width(1)
-
- if self.chart_background:
- self.fill_area(graph_x - 1, graph_y, graph_width, graph_height,
- self.chart_background)
+ # flip hamster.graphics matrix so we don't think upside down
+ self.set_value_range(y_max = 0, y_min = self.graph_height)
+ # bars and keys
+ max_bar_size = self.graph_height
+ #make sure bars don't hit the ceiling
+ if self.animate:
+ max_bar_size = self.graph_height - 10
- self.bar_width = min(graph_width / float(len(self.keys)), self.max_bar_width)
+ bar_width = min(self.graph_width / float(len(self.keys)),
+ self.max_bar_width)
+ gap = bar_width * 0.05
- # keys
- prev_end = None
- set_color(self.context, dark[8]);
+ prev_label_end = None
self.layout.set_width(-1)
for i in range(len(self.keys)):
+ set_color(context, dark[8]);
self.layout.set_text(self.keys[i])
label_w, label_h = self.layout.get_pixel_size()
- intended_x = graph_x + (self.bar_width * i) + (self.bar_width - label_w) / 2.0
+ intended_x = (bar_width * i) + (bar_width - label_w) / 2.0
- if not prev_end or intended_x > prev_end:
- self.context.move_to(intended_x, graph_y + graph_height + 4)
- self.context.show_layout(self.layout)
+ if not prev_label_end or intended_x > prev_label_end:
+ self.move_to(intended_x, -4)
+ context.show_layout(self.layout)
- prev_end = intended_x + label_w + 10
+ prev_label_end = intended_x + label_w + 10
-
-
- context = self.context
- keys, rowcount = self.keys, len(self.keys)
-
-
- max_bar_size = graph_height
- #make sure bars don't hit the ceiling
- if self.animate:
- max_bar_size = graph_height - 10
-
-
- """draw moving parts"""
- #flip the matrix vertically, so we do not have to think upside-down
- context.set_line_width(0)
-
- # bars
- for i in range(rowcount):
- color = 3
-
bar_start = 0
-
base_color = self.bar_base_color or (220, 220, 220)
-
- gap = self.bar_width * 0.05
- bar_x = graph_x + (self.bar_width * i) + gap
+ bar_x = self.graph_x + bar_width * i + gap
for j in range(len(self.integrators[i])):
factor = self.integrators[i][j].value
@@ -391,19 +369,14 @@
bar_start += bar_size
self.draw_bar(bar_x,
- graph_height - bar_start,
- self.bar_width - (gap * 2),
+ self.graph_height - bar_start,
+ bar_width - (gap * 2),
bar_size,
[col - (j * 22) for col in base_color])
- #flip the matrix back, so text doesn't come upside down
- context.transform(cairo.Matrix(yy = 1, y0 = graph_height))
-
-
- self.layout.set_width(-1)
-
#white grid and scale values
+ self.layout.set_width(-1)
if self.grid_stride and self.max_value:
# if grid stride is less than 1 then we consider it to be percentage
if self.grid_stride < 1:
@@ -413,28 +386,31 @@
context.set_line_width(1)
for i in range(grid_stride, int(self.max_value), grid_stride):
- y = - max_bar_size * (i / self.max_value)
+ y = max_bar_size * (i / self.max_value)
if self.show_scale:
self.layout.set_text(self.value_format % i)
label_w, label_h = self.layout.get_pixel_size()
- context.move_to(graph_x - label_w - 8, y - label_h / 2)
+ context.move_to(self.graph_x - label_w - 8,
+ self.get_pixel(y_value=y) - label_h / 2)
set_color(context, medium[8])
context.show_layout(self.layout)
set_color(context, (255,255,255))
- context.move_to(graph_x, y)
- context.line_to(graph_x + graph_width, y)
+ self.move_to(0, y)
+ self.line_to(self.graph_width, y)
+
- context.set_line_width(1)
#stack keys
+ context.save()
if self.show_stack_labels:
- self.context.set_antialias(cairo.ANTIALIAS_DEFAULT)
+ context.set_line_width(1)
+ context.set_antialias(cairo.ANTIALIAS_DEFAULT)
#put series keys
set_color(context, dark[8]);
- y = 0
+ y = self.graph_height
label_y = None
# if labels are at end, then we need show them for the last bar!
@@ -444,7 +420,7 @@
factors = self.integrators[-1]
self.layout.set_ellipsize(pango.ELLIPSIZE_END)
- self.layout.set_width(graph_x * pango.SCALE)
+ self.layout.set_width(self.graph_x * pango.SCALE)
if self.labels_at_end:
self.layout.set_alignment(pango.ALIGN_LEFT)
else:
@@ -470,13 +446,13 @@
label_y = intended_position
if self.labels_at_end:
- label_x = graph_x + graph_width
- line_x1 = graph_x + graph_width - 1
- line_x2 = graph_x + graph_width - 6
+ label_x = self.graph_x + self.graph_width
+ line_x1 = self.graph_x + self.graph_width - 1
+ line_x2 = self.graph_x + self.graph_width - 6
else:
label_x = -8
- line_x1 = graph_x - 6
- line_x2 = graph_x
+ line_x1 = self.graph_x - 6
+ line_x2 = self.graph_x
context.move_to(label_x, label_y)
@@ -486,103 +462,95 @@
context.move_to(line_x1, label_y + label_h / 2)
context.line_to(line_x2, round(y + bar_size / 2))
-
-
-
+ context.stroke()
+ context.restore()
class HorizontalBarChart(Chart):
- def _draw(self):
+ def _draw(self, context):
rowcount, keys = len(self.keys), self.keys
- #push graph to the right, so it doesn't overlap, and add little padding aswell
+ # push graph to the right, so it doesn't overlap
legend_width = self.legend_width or self.longest_label(keys)
- graph_x = legend_width
- graph_x += 8 #add another 8 pixes of padding
+ self.graph_x = legend_width
+ self.graph_x += 8 #add another 8 pixes of padding
- graph_width = self.width - graph_x
- graph_y, graph_height = 0, self.height
+ self.graph_width = self.width - self.graph_x
+ self.graph_y, self.graph_height = 0, self.height
if self.chart_background:
- self.fill_area(graph_x, graph_y, graph_width, graph_height, self.chart_background)
+ self.fill_area(self.graph_x, self.graph_y, self.graph_width, self.graph_height, self.chart_background)
- """
- # stripes for the case i decided that they are not annoying
- for i in range(0, round(self.current_max.value), 10):
- x = graph_x + (graph_width * (i / float(self.current_max.value)))
- w = (graph_width * (5 / float(self.current_max.value)))
- self.context.set_source_rgb(0.93, 0.93, 0.93)
- self.context.rectangle(x + w, graph_y, w, graph_height)
- self.context.fill()
- self.context.stroke()
+ # stripes for the case i decided that they are not annoying
+ """
+ for i in range(0, int(self.current_max.value), 10):
+ x = self.graph_x + (self.graph_width * (i / float(self.current_max.value)))
+ w = (self.graph_width * (5 / float(self.current_max.value)))
+
+ context.set_source_rgb(0.93, 0.93, 0.93)
+ context.rectangle(x + w, self.graph_y, w, self.graph_height)
+ context.fill()
+ context.stroke()
- self.context.set_source_rgb(0.70, 0.70, 0.70)
- self.context.move_to(x, graph_y + graph_height - 2)
+ context.set_source_rgb(0.70, 0.70, 0.70)
+ context.move_to(x, self.graph_y + self.graph_height - 2)
- self.context.show_text(str(i))
+ context.show_text(str(i))
"""
+
if not self.data: #if we have nothing, let's go home
return
- bar_width = int(graph_height / float(rowcount))
+ bar_width = int(self.graph_height / float(rowcount))
if self.max_bar_width:
bar_width = min(bar_width, self.max_bar_width)
- max_bar_size = graph_width - 15
+ max_bar_size = self.graph_width - 15
gap = bar_width * 0.05
self.layout.set_alignment(pango.ALIGN_RIGHT)
self.layout.set_ellipsize(pango.ELLIPSIZE_END)
+
+
+ context.set_line_width(0)
+
+ # bars and labels
self.layout.set_width(legend_width * pango.SCALE)
- # keys
- set_color(self.context, dark[8])
for i in range(rowcount):
+ self.layout.set_width(legend_width * pango.SCALE)
+ set_color(context, dark[8])
label = keys[i]
self.layout.set_text(label)
label_w, label_h = self.layout.get_pixel_size()
- self.context.move_to(0, (bar_width * i) + (bar_width - label_h) / 2)
- self.context.show_layout(self.layout)
-
-
-
- self.context.set_line_width(1)
-
-
-
- self.context.set_line_width(0)
-
+ context.move_to(0, (bar_width * i) + (bar_width - label_h) / 2)
+ context.show_layout(self.layout)
- # bars and labels
- self.layout.set_width(-1)
-
- for i in range(rowcount):
bar_start = 0
base_color = self.bar_base_color or (220, 220, 220)
gap = bar_width * 0.05
- bar_y = graph_y + (bar_width * i) + gap
+ bar_y = self.graph_y + (bar_width * i) + gap
for j in range(len(self.integrators[i])):
factor = self.integrators[i][j].value
-
if factor > 0:
bar_size = max_bar_size * factor
bar_height = bar_width - (gap * 2)
- self.draw_bar(graph_x + bar_start,
+ self.draw_bar(self.graph_x + bar_start,
bar_y,
bar_size,
bar_height,
@@ -590,19 +558,21 @@
bar_start += bar_size
- set_color(self.context, dark[8])
+
+ # values on bars
+ set_color(context, dark[8])
label = self.value_format % sum(self.data[i])
+ self.layout.set_width(-1)
self.layout.set_text(label)
label_w, label_h = self.layout.get_pixel_size()
vertical_padding = (bar_width + label_h) / 2.0 - label_h
-
if bar_start - vertical_padding < label_w:
- label_x = graph_x + bar_start + vertical_padding
+ label_x = self.graph_x + bar_start + vertical_padding
else:
- label_x = graph_x + bar_start - label_w - vertical_padding
+ label_x = self.graph_x + bar_start - label_w - vertical_padding
- self.context.move_to(label_x, graph_y + (bar_width * i) + (bar_width - label_h) / 2.0)
- self.context.show_layout(self.layout)
-
+ context.move_to(label_x, self.graph_y + (bar_width * i) + (bar_width - label_h) / 2.0)
+ context.show_layout(self.layout)
+ context.stroke()
Modified: trunk/hamster/edit_activity.py
==============================================================================
--- trunk/hamster/edit_activity.py (original)
+++ trunk/hamster/edit_activity.py Sun Mar 1 17:31:07 2009
@@ -81,11 +81,11 @@
def call_parent_time_changed(self):
#now calculate back from pixels into minutes
- start_time = int(self.highlight_start / self.minute_pixel)
- start_time = self.range_start.value + dt.timedelta(minutes = start_time) + dt.timedelta(hours=4)
+ start_time = self.get_value_at_pos(x = self.highlight_start)
+ start_time = self.range_start.value + dt.timedelta(minutes = start_time)
- end_time = int(self.highlight_end / self.minute_pixel)
- end_time = self.range_start.value + dt.timedelta(minutes = end_time) + dt.timedelta(hours=4)
+ end_time = self.get_value_at_pos(x = self.highlight_end)
+ end_time = self.range_start.value + dt.timedelta(minutes = end_time)
if self.on_time_changed:
self.on_time_changed(start_time, end_time)
@@ -186,7 +186,8 @@
self.redraw_canvas()
if self.move_type == "scale_drag":
- self.range_start.target(self.drag_start_time + dt.timedelta(minutes = ((self.drag_start - x) / self.minute_pixel)))
+ self.range_start.target(self.drag_start_time +
+ dt.timedelta(minutes = self.get_value_at_pos(x = self.drag_start) - self.get_value_at_pos(x = x)))
self.scroll_to_range_start()
self.call_parent_time_changed()
@@ -233,14 +234,12 @@
context.set_line_width(1)
#we will buffer 4 hours to both sides so partial labels also appear
- range_end = self.range_start.value + dt.timedelta(hours = 12 + 2*4)
+ range_end = self.range_start.value + dt.timedelta(hours = 12 + 2 * 4)
+ self.graph_x = -self.width / 3 #so x moves one third out of screen
+ self.set_value_range(x_min = 0, x_max = 12 * 60)
minutes = self._minutes_from_start(range_end)
- self.minute_pixel = self.width / float(12 * 60)
- minute_pixel = self.minute_pixel
-
- self.graph_x = -minute_pixel * 4 * 60
graph_y = 4
@@ -263,8 +262,8 @@
if label_time.minute == 0 and label_time.hour % 2 == 0:
if label_time.hour == 0:
context.set_source_rgb(0.8, 0.8, 0.8)
- context.move_to(self.graph_x + minute_pixel * i, graph_y)
- context.line_to(self.graph_x + minute_pixel * i, graph_y2)
+ self.move_to(i, graph_y)
+ self.line_to(i, graph_y2)
label_minutes = label_time.strftime("%b %d.")
else:
label_minutes = label_time.strftime("%H:%M")
@@ -273,7 +272,7 @@
self.layout.set_text(label_minutes)
label_w, label_h = self.layout.get_pixel_size()
- context.move_to(self.graph_x + minute_pixel * i - label_w/2,
+ context.move_to(self.get_pixel(x_value=i) - label_w/2,
graph_y2 + 6)
context.show_layout(self.layout)
@@ -290,17 +289,17 @@
if fact["start_time"].date() == dt.date.today():
end_minutes = self._minutes_from_start(dt.datetime.now())
- if (self.graph_x + end_minutes * minute_pixel) > 0 and \
- (self.graph_x + start_minutes * minute_pixel) < self.width:
- context.rectangle(self.graph_x + start_minutes * minute_pixel, graph_y,
- minute_pixel * (end_minutes - start_minutes), graph_height - 1)
+ if self.get_pixel(x_value = end_minutes) > 0 and \
+ self.get_pixel(x_value = start_minutes) < self.width:
+ context.rectangle(self.get_pixel(x_value = start_minutes), graph_y,
+ self.get_pixel(x_value=end_minutes) - self.get_pixel(x_value=start_minutes), graph_height - 1)
context.fill()
if self.highlight:
- self.highlight_start = self.graph_x + self._minutes_from_start(self.highlight[0]) * self.minute_pixel
- self.highlight_end = self.graph_x + self._minutes_from_start(self.highlight[1]) * self.minute_pixel
+ self.highlight_start =self.get_pixel(x_value= self._minutes_from_start(self.highlight[0]))
+ self.highlight_end = self.get_pixel(x_value=self._minutes_from_start(self.highlight[1]))
self.highlight = None
Modified: trunk/hamster/graphics.py
==============================================================================
--- trunk/hamster/graphics.py (original)
+++ trunk/hamster/graphics.py Sun Mar 1 17:31:07 2009
@@ -12,6 +12,11 @@
self.connect("expose_event", self._on_expose)
self.width = None
self.height = None
+ self.value_boundaries = None #x_min, x_max, y_min, y_max
+
+ # use these to mark area where the "real" drawing is going on
+ self.graph_x, self.graph_y = 0, 0
+ self.graph_width, self.graph_height = None, None
def redraw_canvas(self):
"""Force graph redraw"""
@@ -38,6 +43,84 @@
alloc = self.get_allocation() #x, y, width, height
self.width, self.height = alloc.width, alloc.height
+
+ def set_value_range(self, x_min = None, x_max = None, y_min = None, y_max = None):
+ """sets up our internal conversion matrix, because cairo one will
+ scale also fonts and we need something in between!"""
+
+ #store given params, we might redo the math later
+ if not self.value_boundaries:
+ self.value_boundaries = [x_min, x_max, y_min, y_max]
+ else:
+ if x_min != None:
+ self.value_boundaries[0] = x_min
+ if x_max != None:
+ self.value_boundaries[1] = x_max
+ if y_min != None:
+ self.value_boundaries[2] = y_min
+ if y_max != None:
+ self.value_boundaries[3] = y_max
+ self.x_factor, self.y_factor = None, None #set those to none to be recalculated on next call
+
+ def _get_factors(self):
+ if not self.x_factor:
+ self.x_factor = 1
+ if self.value_boundaries[0] != None and self.value_boundaries[1] != None:
+ self.x_factor = float(self.graph_width or self.width) / abs(self.value_boundaries[1] - self.value_boundaries[0])
+
+ if not self.y_factor:
+ self.y_factor = 1
+ if self.value_boundaries[2] != None and self.value_boundaries[3] != None:
+ self.y_factor = float(self.graph_height or self.height) / abs(self.value_boundaries[3] - self.value_boundaries[2])
+
+ return self.x_factor, self.y_factor
+
+
+ def get_pixel(self, x_value = None, y_value = None):
+ """returns screen pixel position for value x and y. Useful to
+ get and then pad something
+
+ x = min1 + (max1 - min1) * (x / abs(max2-min2))
+ => min1 + const1 * x / const2
+ => const3 = const1 / const2
+ => min + x * const3
+ """
+ x_factor, y_factor = self._get_factors()
+
+ if x_value != None:
+ if self.value_boundaries[0] != None:
+ if self.value_boundaries[1] > self.value_boundaries[0]:
+ x_value = self.value_boundaries[0] + x_value * x_factor
+ else: #case when min is larger than max (flipped)
+ x_value = self.value_boundaries[1] - x_value * x_factor
+ if y_value == None:
+ return x_value + self.graph_x
+
+ if y_value != None:
+ if self.value_boundaries[2] != None:
+ if self.value_boundaries[3] > self.value_boundaries[2]:
+ y_value = self.value_boundaries[2] + y_value * y_factor
+ else: #case when min is larger than max (flipped)
+ y_value = self.value_boundaries[2] - y_value * y_factor
+ if x_value == None:
+ return y_value + self.graph_y
+
+ return x_value + self.graph_x, y_value + self.graph_y
+
+ def get_value_at_pos(self, x = None, y = None):
+ """returns mapped value at the coordinates x,y"""
+ x_factor, y_factor = self._get_factors()
+
+ if x != None:
+ x = (x - self.graph_x) / x_factor
+ if y == None:
+ return x
+ if y != None:
+ y = (y - self.graph_x) / y_factor
+ if x == None:
+ return y
+ return x, y
+
def fill_area(self, x, y, w, h, color):
if color[0] > 1: color = [c / 256.0 for c in color]
@@ -54,6 +137,13 @@
max_extent = max(label_w + 5, max_extent)
return max_extent
+
+ def move_to(self, x, y):
+ """our copy of moveto that takes into account our transformations"""
+ self.context.move_to(*self.get_pixel(x, y))
+
+ def line_to(self, x, y):
+ self.context.line_to(*self.get_pixel(x, y))
class Integrator(object):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]