[pypy-svn] r5963 - pypy/trunk/src/pypy/translator/tool/pygame

arigo at codespeak.net arigo at codespeak.net
Sun Aug 15 13:10:06 CEST 2004


Author: arigo
Date: Sun Aug 15 13:10:05 2004
New Revision: 5963

Modified:
   pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py
   pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py
Log:
Clicking on nodes and edges to move around is definitely more convenient than
doing mouse drags all the time (particularly on laptop's touchpads!).


Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py	(original)
+++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py	Sun Aug 15 13:10:05 2004
@@ -113,6 +113,24 @@
                        y0*t0 + y1*t1 + y2*t2 + y3*t3))
     return result
 
+def segmentdistance((x0,y0), (x1,y1), (x,y)):
+    "Distance between the point (x,y) and the segment (x0,y0)-(x1,y1)."
+    vx = x1-x0
+    vy = y1-y0
+    l = math.sqrt(vx*vx+vy*vy)
+    if l < 0.00001:
+        dlong = -1
+    else:
+        vx /= l
+        vy /= l
+        dlong = vx*(x-x0) + vy*(y-y0)
+    if dlong < 0.0:
+        return math.sqrt((x-x0)*(x-x0) + (y-y0)*(y-y0))
+    elif dlong > l:
+        return math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1))
+    else:
+        return abs(vy*(x-x0) - vx*(y-y0))
+
 def splitline(line, re_word = re.compile(r'[^\s"]\S*|["]["]|["].*?[^\\]["]')):
     result = []
     for word in re_word.findall(line):
@@ -159,6 +177,15 @@
         self.ofsx += dx
         self.ofsy += dy
 
+    def getcenter(self):
+        w, h = self.screen.get_size()
+        return self.revmap(w//2, h//2)
+
+    def setcenter(self, x, y):
+        w, h = self.screen.get_size()
+        x, y = self.map(x, y)
+        self.shiftoffset(x-w//2, y-h//2)
+
     def shiftscale(self, factor, fix=None):
         if fix is None:
             fixx, fixy = self.screen.get_size()
@@ -316,6 +343,29 @@
                 return word
         return None
 
+    def node_at_position(self, (x, y)):
+        """Return the Node under the cursor."""
+        x, y = self.revmap(x, y)
+        for node in self.graphlayout.nodes.itervalues():
+            if 2.0*abs(x-node.x) <= node.w and 2.0*abs(y-node.y) <= node.h:
+                return node
+        return None
+
+    def edge_at_position(self, (x, y), distmax=14):
+        """Return the Edge near the cursor."""
+        distmax /= self.scale
+        xy = self.revmap(x, y)
+        closest_edge = None
+        for edge in self.graphlayout.edges:
+            pts = edge.bezierpoints()
+            for i in range(1, len(pts)):
+                d = segmentdistance(pts[i-1], pts[i], xy)
+                if d < distmax:
+                    distmax = d
+                    closest_edge = edge
+        return closest_edge
+
+
 class TextSnippet:
     
     def __init__(self, renderer, text, fgcolor, bgcolor=None):

Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py	(original)
+++ pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py	Sun Aug 15 13:10:05 2004
@@ -1,6 +1,6 @@
 from __future__ import generators
 import autopath
-import sys, os, re
+import sys, os, re, time
 import pygame
 from pygame.locals import *
 from drawgraph import GraphRenderer, build_layout
@@ -21,6 +21,7 @@
 class GraphDisplay(Display):
     STATUSBARFONT = os.path.join(autopath.this_dir, 'VeraMoBd.ttf')
     SCALE = 60
+    ANIM_STEP = 0.07
 
     def __init__(self, translator, functions=None):
         super(GraphDisplay, self).__init__()
@@ -47,8 +48,7 @@
         self.sethighlight()
         self.statusbarinfo = None
         self.must_redraw = True
-        self.setstatusbar('Drag left mouse button to scroll; '
-                          'drag right mouse button to zoom')
+        self.setstatusbar('Click to move around, or drag mouse buttons (left to zoom, right to scroll)')
 
     def setstatusbar(self, text, fgcolor=(255,255,80), bgcolor=(128,0,0)):
         info = (text, fgcolor, bgcolor)
@@ -100,8 +100,43 @@
         if word:
             self.viewer.highlightwords[word] = ((255,255,80), (128,0,0))
 
+    def animation(self, expectedtime=0.6):
+        start = time.time()
+        step = 0.0
+        n = 0
+        while True:
+            step += self.ANIM_STEP
+            if step >= expectedtime:
+                break
+            yield step / expectedtime
+            n += 1
+            now = time.time()
+            frametime = (now-start) / n
+            self.ANIM_STEP = self.ANIM_STEP * 0.9 + frametime * 0.1
+        yield 1.0
+
+    def look_at_node(self, node):
+        """Shift the node in view."""
+        endscale = min(float(self.width-40) / node.w,
+                       float(self.height-40) / node.h,
+                       75)
+        startscale = self.viewer.scale
+        cx1, cy1 = self.viewer.getcenter()
+        cx2, cy2 = node.x, node.y
+        moving = (abs(startscale-endscale) + abs(cx1-cx2) + abs(cy1-cy2)
+                  > 2.0)
+        if moving:
+            self.statusbarinfo = None
+            self.sethighlight(None)
+            for t in self.animation():
+                self.viewer.setscale(startscale*(1-t) + endscale*t)
+                self.viewer.setcenter(cx1*(1-t) + cx2*t, cy1*(1-t) + cy2*t)
+                self.viewer.render()
+                pygame.display.flip()
+        return moving
+
     def run(self):
-        dragging = None
+        dragging = click_origin = click_time = None
         while 1:
             if self.must_redraw:
                 self.viewer.render()
@@ -116,9 +151,12 @@
                 if pygame.event.peek([MOUSEMOTION]):
                     continue
                 if dragging:
+                    if (abs(event.pos[0] - click_origin[0]) +
+                        abs(event.pos[1] - click_origin[1])) > 12:
+                        click_time = None
                     dx = event.pos[0] - dragging[0]
                     dy = event.pos[1] - dragging[1]
-                    if event.buttons[2]:   # right mouse button
+                    if event.buttons[0]:   # left mouse button
                         self.viewer.shiftscale(1.003 ** dy)
                     else:
                         self.viewer.shiftoffset(-2*dx, -2*dy)
@@ -127,11 +165,23 @@
                 else:
                     self.notifymousepos(event.pos)
             if event.type == MOUSEBUTTONDOWN:
-                dragging = event.pos
+                dragging = click_origin = event.pos
+                click_time = time.time()
                 pygame.event.set_grab(True)
             if event.type == MOUSEBUTTONUP:
                 dragging = None
                 pygame.event.set_grab(False)
+                if click_time is not None and abs(time.time() - click_time) < 1:
+                    # click (no significant dragging)
+                    node = self.viewer.node_at_position(click_origin)
+                    if node:
+                        self.look_at_node(node)
+                    else:
+                        edge = self.viewer.edge_at_position(click_origin)
+                        if edge:
+                            if not self.look_at_node(edge.head):
+                                self.look_at_node(edge.tail)
+                click_time = None
                 self.notifymousepos(event.pos)
             if event.type == VIDEORESIZE:
                 # short-circuit if there are more resize events pending



More information about the Pypy-commit mailing list