Changeset 1161
- Timestamp:
- 03/14/07 23:56:20 (2 years ago)
- Files:
-
- gaphas/trunk/ChangeLog (modified) (1 diff)
- gaphas/trunk/README.txt (modified) (7 diffs)
- gaphas/trunk/demo.py (modified) (2 diffs)
- gaphas/trunk/gaphas/canvas.py (modified) (1 diff)
- gaphas/trunk/gaphas/item.py (modified) (4 diffs)
- gaphas/trunk/gaphas/view.py (modified) (1 diff)
- gaphas/trunk/setup.py (modified) (1 diff)
- gaphas/trunk/state.txt (modified) (7 diffs)
- gaphas/trunk/undo.txt (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gaphas/trunk/ChangeLog
r1094 r1161 1 2007-03-16 Arjan Molenaar <arjan_at_yirdis_dot_nl> 2 3 * Implemented Undo system. State changes can be recorded and reverse 4 operations can be determined. 5 6 [ for intermediate change log entries, see svn log ] 7 1 8 2006-12-05 Arjan Molenaar <arjan_at_yirdis_dot_nl> 2 9 gaphas/trunk/README.txt
r1160 r1161 21 21 v a render cycle. 22 22 v zoom and move functionality (canvas2world). 23 v scroll bars work.23 v scroll-bars work. 24 24 v a set of tools and a ToolChain (to chain them together). 25 25 v rubberband selection … … 30 30 v placement tool 31 31 v connection protocol 32 v make update cycle independ ant from render (expose) event.32 v make update cycle independent from render (expose) event. 33 33 This is something we might do if the response is getting bad. 34 34 ? rotating and shearing for Element items. … … 40 40 41 41 Stage n: 42 - Drop zone tool42 - Drop-zone tool 43 43 the idea is that for example you have a Package and when you drag 44 44 a Class into it it automatically makes the Package its owning element. 45 -undo management45 v undo management 46 46 47 47 … … 53 53 54 54 An Item can have a set of Handle's (also from item.py) which can be used to 55 manipulate the item (although this is not ne ssesary). Each item has it's own55 manipulate the item (although this is not necessary). Each item has it's own 56 56 coordinate system (a (0, 0) point). Item.matrix is the transformation 57 57 relative to the parent item of the Item, as defined in the Canvas. … … 59 59 The Canvas also contains a constraint Solver (from solver.py) that can be used 60 60 to solve mathematical dependencies between items (such as Handles that should 61 be al ligned).61 be aligned). 62 62 63 63 View (from view.py) is used to visualize a canvas. On a View, a Tool … … 108 108 parent: parent item of the item, or None 109 109 children: child items of this item (do not need to force updates for those) 110 selected: True if the item is ac utally selected in the view110 selected: True if the item is actually selected in the view 111 111 focused: True if the item has the focus 112 112 hovered: True if the mouse pointer if over the item. Only the top-most item … … 149 149 ==== 150 150 151 Gaphas has a simple build-in system for regist ring changes in it's classes and151 Gaphas has a simple build-in system for registering changes in it's classes and 152 152 notifying the application. This code resides in state.py. 153 153 gaphas/trunk/demo.py
r1160 r1161 2 2 """ 3 3 A simple demo app. 4 5 It sports a small canvas and some trivial operations: 6 7 - Add a line/box 8 - Zoom in/out 9 - Split a line segment 10 - Delete focused item 11 - Record state changes 12 - Play back state changes (= undo !) With visual updates 13 - Exports to SVG and PNG 14 4 15 """ 5 16 … … 161 172 for event in apply_me: 162 173 saveapply(*event) 174 # Visualize each event: 175 while gtk.events_pending(): 176 gtk.main_iteration() 163 177 164 178 b.connect('clicked', on_clicked) gaphas/trunk/gaphas/canvas.py
r1160 r1161 93 93 94 94 reversible_pair(add, remove, 95 bind1={'parent': lambda self, node: self.get_parent(node) })95 bind1={'parent': lambda self, item: self.get_parent(item) }) 96 96 97 97 def remove_connections_to_item(self, item): gaphas/trunk/gaphas/item.py
r1160 r1161 422 422 423 423 Properties: 424 - fuzz yness (0.0..n): an extra margin that should be taken into account424 - fuzziness (0.0..n): an extra margin that should be taken into account 425 425 when calculating the distance from the line (using point()). 426 426 - orthogonal (bool): wherther or not the line should be orthogonal … … 441 441 442 442 self._line_width = 2 443 self._fuzz yness = 0443 self._fuzziness = 0 444 444 self._orthogonal = [] 445 445 self._horizontal = False … … 453 453 454 454 @observed 455 def _set_fuzz yness(self, fuzzyness):456 self._fuzz yness = fuzzyness457 458 fuzz yness = reversible_property(lambda s: s._fuzzyness, _set_fuzzyness)455 def _set_fuzziness(self, fuzziness): 456 self._fuzziness = fuzziness 457 458 fuzziness = reversible_property(lambda s: s._fuzziness, _set_fuzziness) 459 459 460 460 @observed … … 649 649 h = self._handles 650 650 distance, point, segment = self.closest_segment(x, y) 651 return max(0, distance - self.fuzz yness)651 return max(0, distance - self.fuzziness) 652 652 653 653 def draw_head(self, context): gaphas/trunk/gaphas/view.py
r1157 r1161 679 679 doctest.testmod() 680 680 681 682 681 # vim: sw=4:et: gaphas/trunk/setup.py
r1145 r1161 8 8 setup( 9 9 name='gaphas', 10 version='0.1. 1',10 version='0.1.2', 11 11 description='Gaphas is a GTK+ based diagramming widget', 12 12 long_description="""\ 13 13 Gaphas is a GTK+ based diagramming widget written in Python. 14 14 It is the logical successor of the DiaCanvas library. 15 16 GTK+ and PyGTK is required. 15 17 """, 16 18 gaphas/trunk/state.txt
r1160 r1161 20 20 >>> tree = Tree() 21 21 22 For this demon istration let's use the Tree class (which contains an add/remove22 For this demonstration let's use the Tree class (which contains an add/remove 23 23 method pair). It's methods are not dispatched by default though (because they're 24 24 only used in the Canvas class. So first dispatching should be enabled: … … 88 88 1. Property setters should be declared with reversible_property() 89 89 2. Method (or function) pairs that implement each others reverse operation 90 (e.g. add and remove) should be registere sas reversible_pair()'s in the90 (e.g. add and remove) should be registered as reversible_pair()'s in the 91 91 reverser engine. 92 92 The reverser will construct a tuple (callable, arguments) which are send … … 101 101 2. you might want to add some additional filtering. 102 102 103 Point 2 may require some expla ination. First of all observers have been added103 Point 2 may require some explanation. First of all observers have been added 104 104 to almost every method that involves a state change. As a result multiple 105 105 (conflicting) revert actions may be generated (e.g. Canvas.add calls Tree.add, … … 125 125 applied to that function. 126 126 127 The inverse operation is easiest performed by the function saveapply . Of course127 The inverse operation is easiest performed by the function saveapply(). Of course 128 128 an inverse operation is emitting a change event too: 129 129 … … 156 156 Function wrappers should have an extra property indicating if a function needs 157 157 to be dispatched or not. If it needs to be dispatched an extra flag should be 158 set. This will prevent the system from slowing down due to emit ing signals that158 set. This will prevent the system from slowing down due to emitting signals that 159 159 are filtered out later on. 160 160 … … 174 174 x, y, connectable, movable, visible, connected_to and disconnect properties 175 175 Item: 176 canvas and matri cproperties176 canvas and matrix properties 177 177 Element: 178 178 min_height and min_width properties 179 179 Line: 180 line_width, fuzz yness, orthogonal and horizontal properties;180 line_width, fuzziness, orthogonal and horizontal properties; 181 181 split_segment() and merge_segment() 182 182 … … 195 195 invert, translate, rotate and scale 196 196 197 Testcases are described in test_state.txt.197 Testcases are described in undo.txt. 198 198 gaphas/trunk/undo.txt
r1160 r1161 67 67 rotate(radians): 68 68 69 >>> def matrix_approx(m): 70 ... a = [] 71 ... for i in tuple(m): 72 ... if -1e-10 < i < 1e-10: i=0 73 ... a.append(i) 74 ... return tuple(a) 75 69 76 >>> m.rotate(0.5) 70 77 >>> m 71 78 Matrix(0.877583, 0.479426, -0.479426, 0.877583, 0, 0) 72 79 >>> undo() 73 >>> m 74 Matrix(1, 2.58022e-17, 2.58022e-17, 1, 0, 0)80 >>> matrix_approx(m) 81 (1.0, 0, 0, 1.0, 0, 0) 75 82 76 83 Okay, nearly, close enough IMHO... … … 86 93 Matrix(0.585055, -0.319617, 0.319617, 0.585055, -10.2168, -2.01515) 87 94 >>> undo() 88 >>> m 89 Matrix(1, 5.37489e-17, -8.52201e-17, 1, 1.77636e-15, 0)95 >>> matrix_approx(m) 96 (1.0, 0, 0, 1.0, 0, 0) 90 97 91 98 Again, rotate does not result in an exact match, but it's close enough. … … 96 103 canvas.py: Canvas 97 104 ----------------- 98 99 On the canvas only add() and remove() are monitored:100 105 101 106 >>> from gaphas import Canvas, Item … … 105 110 >>> item = Item() 106 111 >>> canvas.add(item) 112 113 The request_update() method is observed: 114 115 >>> len(undo_list) 116 3 117 >>> canvas.request_update(item) 118 >>> len(undo_list) 119 4 120 121 On the canvas only add() and remove() are monitored: 122 107 123 >>> canvas.get_all_items() # doctest: +ELLIPSIS 108 124 [<gaphas.item.Item object at 0x...>] … … 125 141 [] 126 142 127 The request_update() method is observed too: 128 129 >>> canvas.request_update(item) 130 >>> len(undo_list) 131 1 143 Parent-child relationships are restored as well: 144 145 TODO! 146 >>> child = Item() 147 >>> canvas.add(child, parent=item) 148 >>> child.canvas is canvas 149 True 150 >>> canvas.get_parent(child) is item 151 True 152 >>> canvas.get_all_items() # doctest: +ELLIPSIS 153 [<gaphas.item.Item object at 0x...>, <gaphas.item.Item object at 0x...>] 154 >>> undo() 155 >>> child.canvas is None 156 True 157 >>> canvas.get_all_items() # doctest: +ELLIPSIS 158 [<gaphas.item.Item object at 0x...>] 159 >>> child in canvas.get_all_items() 160 False 161 162 Now redo the previous undo action: 163 164 >>> undo_list[:] = redo_list[:] 165 >>> undo() 166 >>> child.canvas is canvas 167 True 168 >>> canvas.get_parent(child) is item 169 True 170 >>> canvas.get_all_items() # doctest: +ELLIPSIS 171 [<gaphas.item.Item object at 0x...>, <gaphas.item.Item object at 0x...>] 172 132 173 133 174 NOTE: If remove() is invoked recursively (e.i. when the to-be removed item has … … 214 255 ------------- 215 256 216 A line has the following properties: line_width, fuzz yness, orthogonal and257 A line has the following properties: line_width, fuzziness, orthogonal and 217 258 horizontal. Each one of then is observed for changes: 218 259 219 260 >>> from gaphas import Line 220 261 >>> l = Line() 221 >>> l.line_width, l.fuzz yness, l.orthogonal, l.horizontal262 >>> l.line_width, l.fuzziness, l.orthogonal, l.horizontal 222 263 (2, 0, False, False) 223 264 … … 225 266 226 267 >>> l.line_width = 4 227 >>> l.fuzz yness = 2268 >>> l.fuzziness = 2 228 269 >>> l.orthogonal = True 229 270 >>> l.horizontal = True 230 >>> l.line_width, l.fuzz yness, l.orthogonal, l.horizontal271 >>> l.line_width, l.fuzziness, l.orthogonal, l.horizontal 231 272 (4, 2, True, True) 232 273 … … 234 275 235 276 >>> undo() 236 >>> l.line_width, l.fuzz yness, l.orthogonal, l.horizontal277 >>> l.line_width, l.fuzziness, l.orthogonal, l.horizontal 237 278 (2, 0, False, False) 238 279 … … 242 283 >>> l.handles() 243 284 [<Handle object on (0, 0)>, <Handle object on (10, 10)>] 285 286 This is our basis for further testing. 287 288 >>> del undo_list[:] 244 289 245 290 >>> l.split_segment(0)
