Changeset 1160

Show
Ignore:
Timestamp:
03/14/07 13:13:54 (2 years ago)
Author:
arjanmol
Message:

Gaphas' undo works!

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gaphas/trunk/README.txt

    r1094 r1160  
    146146 
    147147 
     148Undo 
     149==== 
     150 
     151Gaphas has a simple build-in system for registring changes in it's classes and 
     152notifying the application. This code resides in state.py. 
     153 
     154There is also a "reverter" framework in place. This "framework" is notified 
     155when objects change their state and will figure out the reverse operation that 
     156has to be applied in order to undo the operation. 
     157 
     158See state.txt and undo.txt for details and usage examples. 
     159 
     160 
    148161Files 
    149162===== 
  • gaphas/trunk/demo.py

    r1159 r1160  
    306306    print 'event:', event 
    307307 
    308 state.subscribers.add(print_handler) 
     308#state.subscribers.add(print_handler) 
    309309 
    310310 
  • gaphas/trunk/gaphas/canvas.py

    r1159 r1160  
    77# $HeadURL$ 
    88 
    9 if __name__ == '__main__': 
    10     import pygtk 
    11     pygtk.require('2.0') 
    129 
    1310import cairo 
     
    1613from gaphas import solver 
    1714from gaphas.decorators import async, PRIORITY_HIGH_IDLE 
    18 from state import observed, reversible_pair 
     15from state import observed, reversible_method, reversible_pair 
     16 
    1917 
    2018class Context(object): 
     
    288286                raise e 
    289287 
     288    @observed 
    290289    def request_update(self, item): 
    291290        """ 
     
    314313                parent = self._tree.get_parent(parent) 
    315314        self.update() 
     315 
     316    reversible_method(request_update, reverse=request_update) 
    316317 
    317318    def request_matrix_update(self, item): 
  • gaphas/trunk/gaphas/item.py

    r1159 r1160  
    465465        False 
    466466        """ 
     467        if not self.canvas: 
     468            self._orthogonal = orthogonal and [ None ] or [] 
     469            return 
     470 
    467471        for c in self._orthogonal: 
    468472            self.canvas.solver.remove_constraint(c) 
     
    487491        self.request_update() 
    488492 
    489     orthogonal = reversible_property(lambda s: s._orthogonal != [], _set_orthogonal) 
     493    orthogonal = reversible_property(lambda s: bool(s._orthogonal), _set_orthogonal) 
    490494 
    491495    @observed 
    492496    def _set_horizontal(self, horizontal): 
     497        """ 
     498        >>> line = Line() 
     499        >>> line.horizontal 
     500        True 
     501        >>> line.horizontal = False 
     502        >>> line.horizontal 
     503        False 
     504        """ 
    493505        self._horizontal = horizontal 
    494506        self._set_orthogonal(self._orthogonal) 
    495507 
    496     horizontal = reversible_property(lambda s: s._horizontal != [], _set_horizontal) 
     508    horizontal = reversible_property(lambda s: s._horizontal, _set_horizontal) 
    497509 
    498510    def setup_canvas(self): 
     
    558570        >>> a.handles()[1].pos = (20, 0) 
    559571        >>> a.split_segment(0) 
    560         >>> len(a.handles()
    561         3 
     572        >>> a.handles(
     573        [<Handle object on (0, 0)>, <Handle object on (10, 0)>, <Handle object on (20, 0)>] 
    562574        >>> a.merge_segment(0) 
    563575        >>> len(a.handles()) 
  • gaphas/trunk/state.txt

    r1159 r1160  
    3232    ...     print 'event handled', event 
    3333    >>> state.observers.add(handler) 
    34     >>> tree.add(1) # doctest: +ELLIPSIS 
     34    >>> tree.add(1)                                     # doctest: +ELLIPSIS 
    3535    event handled (<function add at ...>, (<gaphas.tree.Tree object at 0x...>, 1, None), {}) 
    36     >>> tree.add(2, parent=1) # doctest: +ELLIPSIS 
     36    >>> tree.add(2, parent=1)                           # doctest: +ELLIPSIS 
    3737    event handled (<function add at ...>, (<gaphas.tree.Tree object at 0x...>, 2, 1), {}) 
    3838    >>> tree.nodes 
     
    4343recursively calls remove() for each of it's children): 
    4444 
    45     >>> tree.remove(1) # doctest: +ELLIPSIS 
     45    >>> tree.remove(1)                                  # doctest: +ELLIPSIS 
    4646    event handled (<function remove at ...>, (<gaphas.tree.Tree object at 0x...>, 1), {}) 
    4747    event handled (<function remove at ...>, (<gaphas.tree.Tree object at 0x...>, 2), {}) 
     
    5454    >>> from gaphas.solver import Variable 
    5555    >>> var = Variable() 
    56     >>> var.value = 10  # doctest: +ELLIPSIS 
     56    >>> var.value = 10                                  # doctest: +ELLIPSIS 
    5757    event handled (<function set_value at 0x...>, (Variable(0, 20), 10), {}) 
    5858 
     
    6363 
    6464    >>> state.observers.remove(handler) 
    65     >>> state.observers # doctest: +ELLIPSIS 
     65    >>> state.observers                                 # doctest: +ELLIPSIS 
    6666    set([]) 
    6767 
     
    116116After that, signals can be received of undoable (reverse-)events: 
    117117 
    118     >>> tree.add(3) # doctest: +ELLIPSIS 
     118    >>> tree.add(3)                                     # doctest: +ELLIPSIS 
    119119    event handler (<function remove at ...>, {'node': 3, 'self': <gaphas.tree.Tree object at 0x...>}) 
    120120    >>> tree.nodes 
     
    128128an inverse operation is emitting a change event too: 
    129129 
    130     >>> state.saveapply(*events.pop()) # doctest: +ELLIPSIS 
     130    >>> state.saveapply(*events.pop())                  # doctest: +ELLIPSIS 
    131131    event handler (<function add at 0x...>, {'node': 3, 'self': <gaphas.tree.Tree object at 0x...>, 'parent': None}) 
    132132    >>> tree.nodes 
     
    143143 
    144144    >>> var = Variable() 
    145     >>> var.value = 10 # doctest: +ELLIPSIS 
     145    >>> var.value = 10                                  # doctest: +ELLIPSIS 
    146146    event handler (<function set_value at 0x...>, {'self': Variable(0, 20), 'value': 0.0}) 
    147147     
  • gaphas/trunk/undo.txt

    r1159 r1160  
    1 =================================================== 
    21Undo - implementing basic undo behavior with Gaphas 
    32=================================================== 
     
    9291Again, rotate does not result in an exact match, but it's close enough. 
    9392 
    94  
    95 canvas.py: 
    96    Canvas: 
    97      add() and remove() 
    98  
    99 item.py: 
    100    Handle: 
     93    >>> undo_list 
     94    [] 
     95 
     96canvas.py: Canvas 
     97----------------- 
     98 
     99On the canvas only add() and remove() are monitored: 
     100 
     101    >>> from gaphas import Canvas, Item 
     102    >>> canvas = Canvas() 
     103    >>> canvas.get_all_items() 
     104    [] 
     105    >>> item = Item() 
     106    >>> canvas.add(item) 
     107    >>> canvas.get_all_items()                          # doctest: +ELLIPSIS 
     108    [<gaphas.item.Item object at 0x...>] 
     109    >>> item.canvas is canvas 
     110    True 
     111    >>> undo() 
     112    >>> canvas.get_all_items() 
     113    [] 
     114    >>> item.canvas is None 
     115    True 
     116    >>> canvas.add(item) 
     117    >>> del undo_list[:] 
     118    >>> canvas.remove(item) 
     119    >>> canvas.get_all_items() 
     120    [] 
     121    >>> undo() 
     122    >>> canvas.get_all_items()                          # doctest: +ELLIPSIS 
     123    [<gaphas.item.Item object at 0x...>] 
     124    >>> undo_list 
     125    [] 
     126 
     127The request_update() method is observed too: 
     128 
     129    >>> canvas.request_update(item) 
     130    >>> len(undo_list) 
     131    1 
     132 
     133NOTE: If remove() is invoked recursively (e.i. when the to-be removed item has 
     134      children), the remove items can not simply be applied in reverse order. 
     135 
     136    >>> child = Item() 
     137    >>> canvas.add(child, parent=item) 
     138    >>> canvas.get_all_items()                          # doctest: +ELLIPSIS 
     139    [<gaphas.item.Item object at 0x...>, <gaphas.item.Item object at 0x...>] 
     140    >>> del undo_list[:] 
     141    >>> canvas.remove(item) 
     142    >>> canvas.get_all_items() 
     143    [] 
     144 
     145 
     146item.py: Handle 
     147--------------- 
    101148     x, y, connectable, movable, visible, connected_to and disconnect properties 
    102    Item: 
    103      canvas and matric properties 
    104    Element: 
    105      min_height and min_width properties 
    106    Line: 
    107      line_width, fuzzyness, orthogonal and horizontal properties; 
    108      split_segment() and merge_segment() 
    109  
    110 solver.py: 
    111    Variable: 
    112      strength and value properties 
    113 solver.py: 
    114 Solver: 
    115      add_constraint() and remove_constraint()  
    116  
    117  
     149Changing the Handle's position is reversible: 
     150 
     151    >>> from gaphas import Handle 
     152    >>> handle = Handle() 
     153    >>> handle.x, handle.y = 10, 12 
     154    >>> handle.pos 
     155    (Variable(10, 20), Variable(12, 20)) 
     156    >>> undo() 
     157    >>> handle.pos 
     158    (Variable(0, 20), Variable(0, 20)) 
     159 
     160As are all other properties: 
     161 
     162    >>> handle.connectable, handle.movable, handle.visible, handle.connected_to 
     163    (False, True, True, None) 
     164    >>> handle.disconnect                               # doctest: +ELLIPSIS 
     165    <function <lambda> at 0x...> 
     166    >>> handle.connectable = True 
     167    >>> handle.movable = False 
     168    >>> handle.visible = False 
     169    >>> handle.connected_to = item 
     170    >>> def my_fancy_disconnect(): pass 
     171    >>> handle.disconnect = my_fancy_disconnect 
     172    >>> handle.connectable, handle.movable, handle.visible 
     173    (True, False, False) 
     174    >>> handle.connected_to                             # doctest: +ELLIPSIS 
     175    <gaphas.item.Item object at 0x...> 
     176    >>> handle.disconnect                               # doctest: +ELLIPSIS 
     177    <function my_fancy_disconnect at 0x...> 
     178 
     179And now undo the whole lot at once: 
     180 
     181    >>> undo() 
     182    >>> handle.connectable, handle.movable, handle.visible, handle.connected_to 
     183    (False, True, True, None) 
     184    >>> handle.disconnect                               # doctest: +ELLIPSIS 
     185    <function <lambda> at 0x...> 
     186 
     187item.py: Item 
     188------------- 
     189 
     190The basic Item properties are canvas and matrix. Canvas has been tested before, 
     191while testing the Canvas class. 
     192 
     193The Matrix has been tested in section matrix.y: Matrix. 
     194 
     195item.py: Element 
     196---------------- 
     197 
     198An element has min_height and min_width properties. 
     199 
     200    >>> from gaphas import Element 
     201    >>> e = Element() 
     202    >>> e.min_height, e.min_width 
     203    (10, 10) 
     204    >>> e.min_height, e.min_width = 30, 40 
     205    >>> e.min_height, e.min_width 
     206    (30, 40) 
     207 
     208    >>> undo() 
     209    >>> e.min_height, e.min_width 
     210    (10, 10) 
     211     
     212 
     213item.py: Line 
     214------------- 
     215 
     216A line has the following properties: line_width, fuzzyness, orthogonal and 
     217horizontal. Each one of then is observed for changes: 
     218 
     219    >>> from gaphas import Line 
     220    >>> l = Line() 
     221    >>> l.line_width, l.fuzzyness, l.orthogonal, l.horizontal 
     222    (2, 0, False, False) 
     223 
     224Now change the properties: 
     225 
     226    >>> l.line_width = 4 
     227    >>> l.fuzzyness = 2 
     228    >>> l.orthogonal = True 
     229    >>> l.horizontal = True 
     230    >>> l.line_width, l.fuzzyness, l.orthogonal, l.horizontal 
     231    (4, 2, True, True) 
     232 
     233And undo the changes: 
     234 
     235    >>> undo() 
     236    >>> l.line_width, l.fuzzyness, l.orthogonal, l.horizontal 
     237    (2, 0, False, False) 
     238 
     239In addition to those properties, line segments can be split and merged. 
     240 
     241    >>> l.handles()[1].pos = 10, 10 
     242    >>> l.handles() 
     243    [<Handle object on (0, 0)>, <Handle object on (10, 10)>] 
     244 
     245    >>> l.split_segment(0) 
     246    >>> l.handles() 
     247    [<Handle object on (0, 0)>, <Handle object on (5, 5)>, <Handle object on (10, 10)>] 
     248 
     249The opposite operation is performed with the merge_segment() method: 
     250 
     251    >>> undo() 
     252    >>> l.handles() 
     253    [<Handle object on (0, 0)>, <Handle object on (10, 10)>] 
     254 
     255solver.py: Variable 
     256------------------- 
     257 
     258Variable's strength and value properties are observed: 
     259 
     260    >>> from gaphas.solver import Variable 
     261    >>> v = Variable() 
     262    >>> v.value = 10 
     263    >>> v.strength = 100 
     264    >>> v 
     265    Variable(10, 100) 
     266    >>> undo() 
     267    >>> v 
     268    Variable(0, 20) 
     269 
     270solver.py: Solver 
     271----------------- 
     272 
     273Solvers add_constraint() and remove_constraint() are observed.  
     274 
     275    >>> from gaphas.solver import Solver 
     276    >>> from gaphas.constraint import EquationConstraint 
     277    >>> s = Solver() 
     278    >>> a, b = Variable(1.0), Variable(2.0) 
     279    >>> s.add_constraint(EquationConstraint(lambda a,b: a+b, a=a, b=b)) 
     280    EquationConstraint(<lambda>, a=Variable(1, 20), b=Variable(2, 20)) 
     281    >>> list(s.constraints_with_variable(a)) 
     282    [EquationConstraint(<lambda>, a=Variable(1, 20), b=Variable(2, 20))] 
     283     
     284    >>> undo() 
     285    >>> list(s.constraints_with_variable(a)) 
     286    [] 
     287