[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