Changeset 1149
- Timestamp:
- 03/07/07 23:33:51 (2 years ago)
- Files:
-
- gaphas/trunk/demo.py (modified) (3 diffs)
- gaphas/trunk/ez_setup.py (modified) (4 diffs)
- gaphas/trunk/gaphas/canvas.py (modified) (6 diffs)
- gaphas/trunk/gaphas/item.py (modified) (17 diffs)
- gaphas/trunk/gaphas/state.py (modified) (6 diffs)
- gaphas/trunk/gaphas/tree.py (modified) (5 diffs)
- gaphas/trunk/state.txt (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gaphas/trunk/demo.py
r1145 r1149 19 19 from gaphas.painter import ItemPainter 20 20 21 from gaphas import state 22 23 21 24 class MyBox(Box): 22 25 """Box with an example connection protocol. … … 125 128 b.connect('clicked', on_clicked) 126 129 v.add(b) 130 131 v.add(gtk.Label('Export:')) 127 132 128 133 b = gtk.Button('Write demo.png') … … 255 260 c.add(t) 256 261 262 ## 263 ## State handling (a.k.a. undo handlers) 264 ## 265 266 # First, activate the revert handler: 267 state.subscribers.append(state.revert_handler) 268 269 def print_handler(event): 270 print 'event:', event 271 272 state.observers.append(print_handler) 273 274 275 ## 276 ## Start the main application 277 ## 257 278 258 279 gtk.main() gaphas/trunk/ez_setup.py
r945 r1149 15 15 """ 16 16 import sys 17 DEFAULT_VERSION = "0.6 b4"17 DEFAULT_VERSION = "0.6c5" 18 18 DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3] 19 19 … … 27 27 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 28 28 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 29 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 30 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 31 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 32 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 33 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 34 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 35 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 36 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 37 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 38 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 39 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 40 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 41 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 29 42 } 30 43 … … 76 89 pkg_resources.require("setuptools>="+version) 77 90 78 except pkg_resources.VersionConflict :91 except pkg_resources.VersionConflict, e: 79 92 # XXX could we install in a subprocess here? 80 93 print >>sys.stderr, ( 81 94 "The required version of setuptools (>=%s) is not available, and\n" 82 95 "can't be installed while this script is running. Please install\n" 83 " a more recent version first. "84 ) % version96 " a more recent version first.\n\n(Currently using %r)" 97 ) % (version, e.args[0]) 85 98 sys.exit(2) 86 99 … … 138 151 import setuptools 139 152 except ImportError: 140 import tempfile, shutil 141 tmpdir = tempfile.mkdtemp(prefix="easy_install-") 153 egg = None 142 154 try: 143 egg = download_setuptools(version, to_dir=tmpdir,delay=0)155 egg = download_setuptools(version, delay=0) 144 156 sys.path.insert(0,egg) 145 157 from setuptools.command.easy_install import main 146 158 return main(list(argv)+[egg]) # we're done here 147 159 finally: 148 shutil.rmtree(tmpdir) 160 if egg and os.path.exists(egg): 161 os.unlink(egg) 149 162 else: 150 163 if setuptools.__version__ == '0.0.1': gaphas/trunk/gaphas/canvas.py
r1136 r1149 16 16 from gaphas.geometry import Matrix 17 17 from gaphas.decorators import async, PRIORITY_HIGH_IDLE 18 from state import observed, reversible_pair 18 19 19 20 class Context(object): … … 53 54 solver = property(lambda s: s._solver) 54 55 56 @observed 55 57 def add(self, item, parent=None): 56 58 """ … … 70 72 self._tree.add(item, parent) 71 73 self.request_update(item) 72 #self._dirty_items.add(item) 73 #self._dirty_matrix_items.add(item) 74 74 75 @observed 75 76 def remove(self, item): 76 77 """ … … 302 303 0 303 304 """ 304 if True: #not self._in_update:305 if True: 305 306 self._dirty_items.add(item) 306 307 self._dirty_matrix_items.add(item) … … 311 312 self._dirty_items.add(parent) 312 313 parent = self._tree.get_parent(parent) 313 314 # TODO: Schedule update, directly or through a view.315 314 self.update() 316 315 … … 382 381 self.update_matrices() 383 382 384 #for item in dirty_items:385 # item.update(context_map[item])386 383 for item in dirty_items: 387 384 c = Context(parent=self._tree.get_parent(item), gaphas/trunk/gaphas/item.py
r1136 r1149 11 11 from solver import solvable, WEAK, NORMAL, STRONG 12 12 from constraint import EqualsConstraint, LessThanConstraint 13 from state import observed, reversible_pair, reversible_property 14 13 15 14 16 class Handle(object): … … 21 23 """ 22 24 23 x = solvable()24 y = solvable()25 _x = solvable() 26 _y = solvable() 25 27 26 28 def __init__(self, x=0, y=0, strength=NORMAL, connectable=False, movable=True): 27 self.x = x 28 self.y = y 29 self.x.strength = strength 30 self.y.strength = strength 29 self._x = x 30 self._y = y 31 self._x.strength = strength 32 self._y.strength = strength 33 31 34 # Flags.. can't have enough of those 32 self.connectable = connectable 33 self.movable = movable 34 self.visible = True 35 self.connected_to = None 35 self._connectable = connectable 36 self._movable = movable 37 self._visible = True 38 self._connected_to = None 39 36 40 # The constraint used to keep the handle visually connected 37 self.disconnect = lambda: 0 38 41 self._disconnect = lambda: 0 42 43 @observed 44 def _set_x(self, x): 45 self._x = x 46 47 x = reversible_property(lambda s: s._x, _set_x) 48 49 @observed 50 def _set_y(self, y): 51 self._y = y 52 53 y = reversible_property(lambda s: s._y, _set_y) 54 55 @observed 56 def _set_connectable(self, connectable): 57 self._connectable = connectable 58 59 connectable = reversible_property(lambda s: s._connectable, _set_connectable) 60 61 @observed 62 def _set_movable(self, movable): 63 self._movable = movable 64 65 movable = reversible_property(lambda s: s._movable, _set_movable) 66 67 @observed 68 def _set_visible(self, visible): 69 self._visible = visible 70 71 visible = reversible_property(lambda s: s._visible, _set_visible) 72 73 @observed 74 def _set_connected_to(self, connected_to): 75 self._connected_to = connected_to 76 77 connected_to = reversible_property(lambda s: s._connected_to, _set_connected_to) 78 79 @observed 80 def _set_disconnect(self, disconnect): 81 self._disconnect = disconnect 82 83 disconnect = reversible_property(lambda s: s._disconnect, _set_disconnect) 84 85 @observed 39 86 def _set_pos(self, pos): 40 87 """ … … 71 118 self._matrix = Matrix() 72 119 120 @observed 73 121 def _set_canvas(self, canvas): 74 122 """ … … 86 134 Unset the canvas. 87 135 """ 88 self.teardown_canvas() 89 self._canvas = None 90 91 canvas = property(lambda s: s._canvas, _set_canvas, _del_canvas) 136 self._set_canvas(None) 137 138 canvas = reversible_property(lambda s: s._canvas, _set_canvas, _del_canvas) 92 139 93 140 def setup_canvas(self): … … 105 152 pass 106 153 154 @observed 107 155 def _set_matrix(self, matrix): 108 156 """ … … 113 161 self._matrix = matrix 114 162 115 matrix = property(lambda s: s._matrix, _set_matrix)163 matrix = reversible_property(lambda s: s._matrix, _set_matrix) 116 164 117 165 def request_update(self): … … 220 268 Variable(0, 30) 221 269 >>> b._handles[SE].y 222 Variable( 20, 30)270 Variable(10, 30) 223 271 """ 224 272 if height < self.min_height: … … 236 284 height = property(_get_height, _set_height) 237 285 286 @observed 238 287 def _set_min_width(self, min_width): 239 288 """ … … 243 292 self.width = min_width 244 293 245 min_width = property(lambda s: s._min_width, _set_min_width) 246 294 min_width = reversible_property(lambda s: s._min_width, _set_min_width) 295 296 @observed 247 297 def _set_min_height(self, min_height): 248 298 """ … … 252 302 self.height = min_height 253 303 254 min_height = property(lambda s: s._min_height, _set_min_height)304 min_height = reversible_property(lambda s: s._min_height, _set_min_height) 255 305 256 306 def setup_canvas(self): … … 267 317 8 268 318 >>> len(c.solver._marked_cons) 269 8319 0 270 320 >>> c.solver.solve() 271 321 >>> len(c.solver._constraints) … … 311 361 >>> len(c.solver._constraints) 312 362 8 313 >>> b.teardown ()363 >>> b.teardown_canvas() 314 364 >>> len(c.solver._constraints) 315 365 0 … … 387 437 self._handles = [Handle(connectable=True), Handle(10, 10, connectable=True)] 388 438 389 self. line_width = 2390 self. fuzzyness = 0439 self._line_width = 2 440 self._fuzzyness = 0 391 441 self._orthogonal = [] 392 442 self._horizontal = False 393 443 self._head_angle = self._tail_angle = 0 394 444 445 @observed 446 def _set_line_width(self, line_width): 447 self._line_width = line_width 448 449 line_width = reversible_property(lambda s: s._line_width, _set_line_width) 450 451 @observed 452 def _set_fuzzyness(self, fuzzyness): 453 self._fuzzyness = fuzzyness 454 455 fuzzyness = reversible_property(lambda s: s._fuzzyness, _set_fuzzyness) 456 457 @observed 395 458 def _set_orthogonal(self, orthogonal): 396 459 """ … … 421 484 self.request_update() 422 485 423 orthogonal = property(lambda s: s._orthogonal != [], _set_orthogonal) 424 486 orthogonal = reversible_property(lambda s: s._orthogonal != [], _set_orthogonal) 487 488 @observed 425 489 def _set_horizontal(self, horizontal): 426 490 self._horizontal = horizontal 427 491 self._set_orthogonal(self._orthogonal) 428 492 429 horizontal = property(lambda s: s._horizontal != [], _set_horizontal)493 horizontal = reversible_property(lambda s: s._horizontal != [], _set_horizontal) 430 494 431 495 def setup_canvas(self): … … 442 506 self.canvas.solver.remove_constraint(c) 443 507 508 @observed 444 509 def split_segment(self, segment, parts=2): 445 510 """ 446 Split one segment in the Line in @parts pieces.511 Split one segment in the Line in @parts equal pieces. 447 512 @segment 0 is the first segment (between handles 0 and 1). 448 513 The min number of parts is 2. … … 481 546 self.orthogonal = self.orthogonal 482 547 483 def merge_segment(self, segment): 548 @observed 549 def merge_segment(self, segment, parts=2): 484 550 """ 485 551 Merge the @segment and the next. 552 The parts parameter indicates how many segments should be merged 486 553 487 554 >>> a = Line() … … 500 567 if 0 >= segment > len(self._handles) - 1: 501 568 raise IndexError("index out of range (0 > %d > %d)" % (segment, len(self._handles) - 1)) 502 # TODO: recreate constraints that use self._handles[segment + 1]503 569 if segment == 0: segment = 1 504 570 del self._handles[segment] 505 self.orthogonal = self.orthogonal 571 if parts > 2: 572 merge_segment(segment, parts - 1) 573 else: 574 # Force orthogonal constraints to be recreated 575 self.orthogonal = self.orthogonal 576 577 reversible_pair(split_segment, merge_segment) 506 578 507 579 def handles(self): gaphas/trunk/gaphas/state.py
r1148 r1149 50 50 decorator is called from within the decorator it's hard to find out where 51 51 the decorated function lives (is it even possible?). 52 Solution: add a special __observer__ attribute to the inner function. 52 53 """ 53 54 … … 63 64 subscribers = list() 64 65 65 class StateChange(object):66 """67 Simple StateChange event68 """69 70 def __init__(self, func, spec, args, kwargs):71 self.func = func72 self.spec = spec73 self.args = args74 self.kwargs = kwargs75 76 def __call__(self):77 pass78 79 66 80 67 # Subscribe to low-level change events: 81 68 observers = list() 82 83 #def decorator(func):84 # def _apply(*args, **kwargs):85 # print 'DECORATOR', func86 # return func(*args, **kwargs)87 # return _apply88 69 89 70 … … 97 78 """ 98 79 def wrapper(func, *args, **kwargs): 99 #print 'DISPATCHING', func, func.__observer__100 80 dispatch((func.__observer__, args, kwargs), queue=observers) 101 81 return func(*args, **kwargs) 102 82 dec = decorator(wrapper, func) 103 104 83 func.__observer__ = dec 105 84 return dec … … 135 114 def reversible_pair(func1, func2, bind1={}, bind2={}): 136 115 global _reverse 137 #print 'reversible_pair' ,func1, dir(func1), func1.im_func, func1.im_func138 #print func1, type(func1), func1.im_func, type(func1.im_func)139 116 # We need the funcion, since that's what's in the events 140 117 if isinstance(func1, types.UnboundMethodType): func1 = func1.im_func … … 143 120 _reverse[func2] = (func1, inspect.getargspec(func1), bind1) 144 121 145 def reverse_handler(event): 122 123 def reversible_property(fget=None, fset=None, fdel=None, doc=None): 124 """ 125 Replacement for the property descriptor. In addition to creating a 126 property instance, the property is registered as reversible and 127 reverse events can be send out when changes occur. 128 """ 129 # given fset, read the value argument name (second arg) and create a 130 # bind {value: lambda self: fget(self)} 131 132 # TODO! 133 134 return property(fget=fget, fset=fset, fdel=fdel, doc=doc) 135 136 137 def revert_handler(event): 146 138 """ 147 139 Event handler, generates undoable statements and puts them on the 148 140 subscribers queue. 149 141 142 First thing to do is to actually enable the revert_handler: 143 >>> observers.append(revert_handler) 144 150 145 First let's define our simple list: 151 146 >>> class SList(object): … … 202 197 dispatch((reverse, kwargs)) 203 198 204 observers.append(reverse_handler)205 206 199 207 200 def saveapply(func, kw): gaphas/trunk/gaphas/tree.py
r1013 r1149 6 6 __version__ = "$Revision$" 7 7 # $HeadURL$ 8 9 from state import observed, reversible_pair 8 10 9 11 … … 41 43 """ 42 44 parent = self.get_parent(node) 43 return self._children[parent] #[ n for n in self._children[parent] if not n is node ]45 return self._children[parent] 44 46 45 47 def get_next_sibling(self, node): … … 91 93 nodes.append(node) 92 94 95 @observed 93 96 def add(self, node, parent=None): 94 97 """Add @node to the tree. @parent is the parent node, which may … … 102 105 self._children[node] = [] 103 106 107 @observed 104 108 def remove(self, node): 105 109 """Remove @node from the tree. … … 115 119 self._nodes.remove(node) 116 120 121 reversible_pair(add, remove, 122 bind1={'parent': lambda self, node: self.get_parent(node) }) 123 117 124 118 125 def test_add():
