[hamster-applet] mouse handling routines



commit c1eaaa93e9ed89cbdaffe93e2c312f2634f6ed5e
Author: Toms Bauģis <toms baugis gmail com>
Date:   Mon Jun 22 11:57:43 2009 +0100

    mouse handling routines

 hamster/graphics.py |   95 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 85 insertions(+), 10 deletions(-)
---
diff --git a/hamster/graphics.py b/hamster/graphics.py
index 9431e7b..7443255 100644
--- a/hamster/graphics.py
+++ b/hamster/graphics.py
@@ -1,13 +1,16 @@
 import time, datetime as dt
-import gtk
+import gtk, gobject
 
 import pango, cairo
+import colorsys
 
 class Area(gtk.DrawingArea):
     """Abstraction on top of DrawingArea to work specifically with cairo"""
     __gsignals__ = {
         "expose-event": "override",
         "configure_event": "override",
+        "mouse-over": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )),
+        "button-release": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )),
     }
 
     def do_configure_event ( self, event ):
@@ -28,17 +31,25 @@ class Area(gtk.DrawingArea):
         default_font = pango.FontDescription(gtk.Style().font_desc.to_string())
         default_font.set_size(8 * pango.SCALE)
         self.layout.set_font_description(default_font)
-        
-
         alloc = self.get_allocation()  #x, y, width, height
         self.width, self.height = alloc.width, alloc.height
         
+        self.mouse_regions = [] #reset since these can move in each redraw
         self._render()
 
-
-
     def __init__(self):
         gtk.DrawingArea.__init__(self)
+        self.set_events(gtk.gdk.EXPOSURE_MASK
+                                 | gtk.gdk.LEAVE_NOTIFY_MASK
+                                 | gtk.gdk.BUTTON_PRESS_MASK
+                                 | gtk.gdk.BUTTON_RELEASE_MASK
+                                 | gtk.gdk.POINTER_MOTION_MASK
+                                 | gtk.gdk.POINTER_MOTION_HINT_MASK)
+        self.connect("button_release_event", self.__on_button_release)
+        self.connect("motion_notify_event", self.__on_mouse_move)
+        self.connect("leave_notify_event", self.__on_mouse_out)
+
+
         self.context = None
         self.layout = None
         self.width = None
@@ -47,7 +58,17 @@ class Area(gtk.DrawingArea):
         
         # 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 
+        self.graph_width, self.graph_height = None, None
+        
+        self.mouse_regions = [] #regions of drawing that respond to hovering/clicking
+        self.__prev_mouse_regions = None
+
+    def register_mouse_region(self, x1, y1, x2, y2, region_name):
+        self.mouse_regions.append((x1, y1, x2, y2, region_name))
+
+    def hls(self, color):
+        # converts hls to rgb
+        return colorsys.hls_to_rgb(*color)
 
     def redraw_canvas(self):
         """Force graph redraw"""
@@ -138,18 +159,31 @@ class Area(gtk.DrawingArea):
                 return y
         return x, y            
         
-    def fill_area(self, x, y, w, h, color):
-        self.context.save()
+    def __rectangle(self, x, y, w, h, color, opacity = 0):
         if color[0] > 1: color = [c / 256.0 for c in color]
 
-        if len(color) == 3:
+        if opacity:
+            self.context.set_source_rgba(color[0], color[1], color[2], opacity)
+        elif len(color) == 3:
             self.context.set_source_rgb(*color)
         else:
             self.context.set_source_rgba(*color)
             
         self.context.rectangle(x, y, w, h)
+    
+    def fill_area(self, x, y, w, h, color, opacity = 0):
+        self.context.save()
+        self.__rectangle(x, y, w, h, color, opacity)
         self.context.fill()
         self.context.restore()
+        
+    def fill_rectangle(self, x, y, w, h, color, opacity = 0):
+        self.context.save()
+        self.__rectangle(x, y, w, h, color, opacity)
+        self.context.fill()
+        self.__rectangle(x, y, w, h, color, 0)
+        self.context.stroke()
+        self.context.restore()
 
     def longest_label(self, labels):
         """returns width of the longest label"""
@@ -168,6 +202,47 @@ class Area(gtk.DrawingArea):
     def line_to(self, x, y):
         self.context.line_to(*self.get_pixel(x, y))
         
+    def __on_mouse_out(self, area, event):
+        self.__prev_mouse_regions = None
+        self.emit("mouse-over", [])
+
+    def __on_mouse_move(self, area, event):
+        if not self.mouse_regions:
+            return
+
+        if event.is_hint:
+            x, y, state = event.window.get_pointer()
+        else:
+            x = event.x
+            y = event.y
+            state = event.state
+        
+        mouse_regions = []
+        for region in self.mouse_regions:
+            if region[0] < x < region[2] and region[1] < y < region[3]:
+                mouse_regions.append(region[4])
+
+        if mouse_regions or self.__prev_mouse_regions:
+            self.emit("mouse-over", mouse_regions)
+
+        self.__prev_mouse_regions = mouse_regions
+
+    def __on_button_release(self, area, event):
+        if not self.mouse_regions:
+            return
+
+        x = event.x
+        y = event.y
+        state = event.state
+        
+        mouse_regions = []
+        for region in self.mouse_regions:
+            if region[0] < x < region[2] and region[1] < y < region[3]:
+                mouse_regions.append(region[4])
+
+        if mouse_regions:
+            self.emit("button-release", mouse_regions)
+
 
 class Integrator(object):
     """an iterator, inspired by "visualizing data" book to simplify animation"""
@@ -226,4 +301,4 @@ class Integrator(object):
             return dt.datetime.fromtimestamp(self.current_value)
         else:
             return self.current_value
- 
\ No newline at end of file
+ 



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