Changeset 1637

Show
Ignore:
Timestamp:
07/16/07 08:26:30 (1 year ago)
Author:
wrobe..@pld-linux.org
Message:

- added canvas constraint projector to convert variables into canvas space

before constraint solving

- use constraint projector to keep line's handle on box's side
- added Item._iconstraints dictionary to

  • add and remove inter-item constraints easily
  • request resolve of inter-item constraints by canvas in case of matrix
    changes

- added Item._constraints list to add/remove item's constraints by

Item.{setup,teardown}_canvas methods

- use positional arguments instead of dictionary for projection callable to

provide nicer interface for deriving classes

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gaphas/branches/hw/gaphas/canvas.py

    r1625 r1637  
    1515from gaphas.decorators import nonrecursive, async, PRIORITY_HIGH_IDLE 
    1616from state import observed, reversible_method, reversible_pair 
     17from gaphas.constraint import Projector 
    1718 
    1819 
     
    7172        self._registered_views = set() 
    7273        self._cache = WeakKeyDictionary() 
     74 
     75        self.proj = CanvasProjector(self) 
    7376 
    7477    solver = property(lambda s: s._solver) 
     
    497500        # Make sure handles are marked (for constraint solving) 
    498501        request_resolve = self._solver.request_resolve 
    499         for h in item.handles(): 
    500             request_resolve(h.x) 
    501             request_resolve(h.y) 
     502        for c in item.iconstraints(): 
     503            request_resolve(c) 
    502504             
    503505        if recursive: 
     
    597599 
    598600 
     601 
     602class CanvasProjector(Projector): 
     603    def __init__(self, canvas): 
     604        super(CanvasProjector, self).__init__() 
     605        self._canvas = canvas 
     606 
     607 
     608    def _cproj(self, c, x=None, y=None, xy=None, **kw): 
     609        if x is not None: 
     610            for v, item in x.items(): 
     611                i2c = self._canvas.get_matrix_i2c(item).transform_point 
     612                v._value, _ = i2c(v._value, 0) 
     613        if y is not None: 
     614            for v, item in y.items(): 
     615                i2c = self._canvas.get_matrix_i2c(item).transform_point 
     616                _, v._value = i2c(0, v._value) 
     617 
     618 
     619    def _iproj(self, c, x=None, y=None, xy=None, **kw): 
     620        if x is not None: 
     621            for v, item in x.items(): 
     622                c2i = self._canvas.get_matrix_c2i(item).transform_point 
     623                v._value, _ = c2i(v._value, 0) 
     624                item.request_update() 
     625        if y is not None: 
     626            for v, item in y.items(): 
     627                c2i = self._canvas.get_matrix_c2i(item).transform_point 
     628                _, v._value = c2i(0, v._value) 
     629                item.request_update() 
     630 
     631 
    599632# Additional tests in @observed methods 
    600633__test__ = { 
  • gaphas/branches/hw/gaphas/constraint.py

    r1634 r1637  
    490490 
    491491 
    492     def __call__(self, c, data): 
     492    def __call__(self, c, *args, **kw): 
    493493        """ 
    494494        Decorator for Constraint.solve_for method to perform 
     
    498498        f = c.solve_for 
    499499        def wrapper(var): 
    500             self._cproj(c, data
     500            self._cproj(c, *args, **kw
    501501            f(var) 
    502             self._iproj(c, data
     502            self._iproj(c, *args, **kw
    503503        c.solve_for = wrapper 
    504504 
  • gaphas/branches/hw/gaphas/examples.py

    r1625 r1637  
    4545        """ 
    4646        h = self._handles 
    47         hnw = h[NW] 
    48         hse = h[SE] 
    49         x0, y0 = float(hnw.x), float(hnw.y) 
    50         x1, y1 = float(hse.x), float(hse.y) 
    51         r = (x0, y0, x1 - x0, y1 - y0) 
     47        h_se = h[SE] 
     48        r = (0, 0, h_se.x, h_se.y) 
    5249        por = point_on_rectangle(r, (x, y), border=True) 
    5350        p = distance_rectangle_point(r, (x, y)) 
     
    172169        inverse = Matrix(*view.matrix) 
    173170        inverse.invert() 
    174         glue_distance, dummy = inverse.transform_distance(10, 0) 
     171        #glue_distance, dummy = inverse.transform_distance(10, 0) 
     172        glue_distance = 10 
    175173        glue_point = None 
    176174        glue_item = None 
    177175        for i in view.canvas.get_all_items(): 
    178176            if not i is item: 
    179                 #ix, iy = matrix_w2i(i).transform_point(wx, wy) 
    180                 ix, iy = wx, wy 
     177                v2i = view.get_matrix_v2i(i).transform_point 
     178                ix, iy = v2i(wx, wy) 
    181179                try: 
    182180                    distance, point = i.glue(item, handle, ix, iy) 
     
    185183                    if distance <= glue_distance: 
    186184                        glue_distance = distance 
    187                         glue_point = point 
     185                        i2v = view.get_matrix_i2v(i).transform_point 
     186                        glue_point = i2v(*point) 
    188187                        glue_item = i 
    189188                except AttributeError: 
    190189                    pass 
    191190        if glue_point: 
    192             x, y = glue_point 
    193             handle.x, handle.y = glue_point 
     191            v2i = view.get_matrix_v2i(item).transform_point 
     192            handle.x, handle.y = v2i(*glue_point) 
    194193        return glue_item 
    195194 
     
    205204        def side(handle, glued): 
    206205            handles = glued.handles() 
    207             hx, hy = handle.x, handle.y 
    208             ax, ay = handles[NW].x, handles[NW].y 
    209             bx, by = handles[SE].x, handles[SE].y 
     206            hx, hy = view.get_matrix_i2v(item).transform_point(handle.x, handle.y) 
     207            ax, ay = view.get_matrix_i2v(glued).transform_point(handles[NW].x, handles[NW].y) 
     208            bx, by = view.get_matrix_i2v(glued).transform_point(handles[SE].x, handles[SE].y) 
     209 
    210210            if abs(hx - ax) < 0.01: 
    211                 return handles[NW], handles[SW] 
     211                return handles[NW], handles[SW], (hy - ay) / (by - ay) 
    212212            elif abs(hy - ay) < 0.01: 
    213                 return handles[NW], handles[NE] 
     213                return handles[NW], handles[NE], (hx - ax) / (bx - ax) 
    214214            elif abs(hx - bx) < 0.01: 
    215                 return handles[NE], handles[SE] 
     215                return handles[NE], handles[SE],  (hy - ay) / (by - ay) 
    216216            else: 
    217                 return handles[SW], handles[SE] 
     217                return handles[SW], handles[SE], (hx - ax) / (bx - ax) 
    218218            assert False 
    219219 
     
    221221        def handle_disconnect(): 
    222222            try: 
    223                 view.canvas.solver.remove_constraint(handle._c1) 
    224                 view.canvas.solver.remove_constraint(handle._c2) 
     223                item.remove_iconstraint(handle) 
    225224            except KeyError: 
    226225                pass # constraint was alreasy removed 
     
    240239 
    241240 
    242             h1, h2 = side(handle, glue_item) 
     241            assert False, 'not now!' 
     242            h1, h2, b = side(handle, glue_item) 
    243243            handle._c1 = BalanceConstraint(band=(h1.x, h1.x), v=handle.x) 
    244244            handle._c2 = BalanceConstraint(band=(h2.y, h2.y), v=handle.y) 
     
    254254        if glue_item: 
    255255            if isinstance(glue_item, Box): 
    256                 h1, h2 = side(handle, glue_item) 
     256                h1, h2, b = side(handle, glue_item) 
    257257 
    258258                # Make a constraint that keeps into account item coordinates. 
    259                 handle._c1 = BalanceConstraint(band=(h1.x, h2.x), v=handle.x) 
    260                 handle._c2 = BalanceConstraint(band=(h1.y, h2.y), v=handle.y) 
    261                 view.canvas.solver.add_constraint(handle._c1) 
    262                 view.canvas.solver.add_constraint(handle._c2) 
     259                c1 = BalanceConstraint(band=(h1.x, h2.x), v=handle.x, balance=b) 
     260                c2 = BalanceConstraint(band=(h1.y, h2.y), v=handle.y, balance=b) 
     261                view.canvas.proj(c1, x={h1.x: glue_item, h2.x: glue_item, handle.x: item}) 
     262                view.canvas.proj(c2, y={h1.y: glue_item, h2.y: glue_item, handle.y: item}) 
     263                item.add_iconstraint(handle, c1) 
     264                item.add_iconstraint(handle, c2) 
    263265 
    264266                handle.connected_to = glue_item 
     
    268270        if handle.connected_to: 
    269271            #print 'Handle.disconnect', view, item, handle 
    270             view.canvas.solver.remove_constraint(handle._c1) 
    271             view.canvas.solver.remove_constraint(handle._c2) 
     272            item.remove_iconstraint(handle) 
    272273 
    273274 
  • gaphas/branches/hw/gaphas/item.py

    r1620 r1637  
    126126        self._matrix = Matrix() 
    127127        self._handles = [] 
     128        self._constraints = [] 
     129        self._iconstraints = {} 
     130 
     131 
     132    def add_iconstraint(self, h, c): 
     133        if h not in self._iconstraints: 
     134            self._iconstraints[h] = set() 
     135        self._iconstraints[h].add(c) 
     136        self._canvas.solver.add_constraint(c) 
     137 
     138 
     139    def remove_iconstraint(self, h, c=None): 
     140        if c is None: # remove all handle's constraints 
     141            cons = self._iconstraints[h] 
     142            for c in cons: 
     143                self._canvas.solver.remove_constraint(c) 
     144            cons.clear() 
     145        else: 
     146            # remove specific constraint 
     147            self._canvas.solver.remove_constraint(c) 
     148            self._iconstraints[h].remove(c) 
     149 
     150 
     151    def iconstraints(self): 
     152        for cons in self._iconstraints.values(): 
     153            for c in cons: 
     154                yield c 
     155 
    128156 
    129157    @observed 
     
    149177                    "Canvas.add() and Canvas.remove().") 
    150178 
     179 
    151180    def setup_canvas(self): 
    152181        """ 
     
    154183        This method can be used to create constraints. 
    155184        """ 
    156         pass 
     185        add = self.canvas.solver.add_constraint 
     186        for c in self._constraints: 
     187            add(c) 
     188 
    157189 
    158190    def teardown_canvas(self): 
     
    161193        This method can be used to dispose constraints. 
    162194        """ 
     195        super(Item, self).teardown_canvas() 
    163196        for h in self.handles(): 
    164197            h.disconnect() 
     198 
     199        for c in self._constraints: 
     200            self.canvas.solver.remove_constraint(c) 
     201 
    165202 
    166203    @observed 
     
    238275        super(Element, self).__init__() 
    239276        self._handles = [ h(strength=VERY_STRONG) for h in [Handle]*4 ] 
    240         self._constraints = [] 
    241  
    242         # create minimal size constraints 
     277 
     278        eq = EqualsConstraint 
     279        lt = LessThanConstraint 
    243280        handles = self._handles 
    244281        h_nw = handles[NW] 
     282        h_ne = handles[NE] 
     283        h_sw = handles[SW] 
    245284        h_se = handles[SE] 
     285 
     286        # create minimal size constraints 
    246287        self._c_min_w = LessThanConstraint(smaller=h_nw.y, bigger=h_se.y, delta=10) 
    247288        self._c_min_h = LessThanConstraint(smaller=h_nw.x, bigger=h_se.x, delta=10) 
     289 
     290        # setup constraints 
     291        self._constraints.extend([ 
     292            eq(a=h_nw.y, b=h_ne.y), 
     293            eq(a=h_nw.x, b=h_sw.x), 
     294            eq(a=h_se.y, b=h_sw.y), 
     295            eq(a=h_se.x, b=h_ne.x), 
     296            # set h_nw < h_se constraints 
     297            # with minimal size functionality 
     298            self._c_min_w, 
     299            self._c_min_h, 
     300        ]) 
    248301 
    249302        # set width/height when minimal size constraints exist 
    250303        self.width = width 
    251304        self.height = height 
     305 
     306        # immediately solve the constraints, ensuring the box is drawn okay 
     307        solve_for = (h_ne.y, h_sw.y, h_sw.x, h_ne.x) 
     308        for c, v in zip(self._constraints, solve_for): 
     309            c.solve_for(v) 
    252310 
    253311 
     
    336394    min_height = reversible_property(lambda s: s._c_min_h.delta, _set_min_height) 
    337395 
    338     def setup_canvas(self): 
    339         """ 
    340         >>> from canvas import Canvas 
    341         >>> c=Canvas() 
    342         >>> c.solver._constraints 
    343         set([]) 
    344         >>> b = Element() 
    345         >>> c.add(b) 
    346         >>> b.canvas is c 
    347         True 
    348         >>> len(c.solver._constraints) 
    349         8 
    350         >>> len(c.solver._marked_cons) 
    351         0 
    352         >>> c.solver.solve() 
    353         >>> len(c.solver._constraints) 
    354         8 
    355         >>> len(c.solver._marked_cons) 
    356         0 
    357         >>> b._handles[SE].pos = (25,30) 
    358         >>> len(c.solver._marked_cons) 
    359         4 
    360         >>> c.solver.solve() 
    361         >>> float(b._handles[NE].x) 
    362         25.0 
    363         >>> float(b._handles[SW].y) 
    364         30.0 
    365         """ 
    366         eq = EqualsConstraint 
    367         lt = LessThanConstraint 
    368  
    369         handles = self._handles 
    370         h_nw = handles[NW] 
    371         h_ne = handles[NE] 
    372         h_sw = handles[SW] 
    373         h_se = handles[SE] 
    374  
    375         add = self.canvas.solver.add_constraint 
    376         self._constraints = [ 
    377             add(eq(a=h_nw.y, b=h_ne.y)), 
    378             add(eq(a=h_nw.x, b=h_sw.x)), 
    379             add(eq(a=h_se.y, b=h_sw.y)), 
    380             add(eq(a=h_se.x, b=h_ne.x)), 
    381             # set h_nw < h_se constraints 
    382             # with minimal size functionality 
    383             add(self._c_min_w), 
    384             add(self._c_min_h), 
    385         ] 
    386  
    387         # Immediately solve the constraints, ensuring the box is drawn okay 
    388         solve_for = (h_ne.y, h_sw.y, h_sw.x, h_ne.x) 
    389         for c, v in zip(self._constraints, solve_for): 
    390             c.solve_for(v) 
    391  
    392396         
    393     def teardown_canvas(self): 
    394         """ 
    395         Remove constraints created in setup_canvas(). 
    396         >>> from canvas import Canvas 
    397         >>> c=Canvas() 
    398         >>> c.solver._constraints 
    399         set([]) 
    400         >>> b = Element() 
    401         >>> c.add(b) 
    402         >>> b.canvas is c 
    403         True 
    404         >>> len(c.solver._constraints) 
    405         8 
    406         >>> b.teardown_canvas() 
    407         >>> len(c.solver._constraints) 
    408         0 
    409         """ 
    410         super(Element, self).teardown_canvas() 
    411         for c in self._constraints: 
    412             self.canvas.solver.remove_constraint(c) 
    413  
    414  
    415397    def point(self, x, y): 
    416398        """ 
  • gaphas/branches/hw/gaphas/solver.py

    r1631 r1637  
    350350 
    351351 
    352     def request_resolve(self, variable): 
    353         """ 
    354         Request resolving of the constraints for a variable. This does not 
    355         mark the variable itself as dirty. 
    356         """ 
    357         for c in variable._constraints: 
    358             if c not in self._marked_cons: 
    359                 self._marked_cons.append(c) 
     352    def request_resolve(self, c): 
     353        """ 
     354        Request resolving of the constraint. 
     355        """ 
     356        self._marked_cons.append(c) 
     357 
    360358 
    361359    @observed 
  • gaphas/branches/hw/gaphas/tool.py

    r1618 r1637  
    475475            view = context.view 
    476476            if self._grabbed_handle and self._grabbed_handle.connectable: 
    477                 wx, wy = view.get_matrix_v2i(self._grabbed_item).transform_point(event.x, event.y) 
    478                 self.connect(view, self._grabbed_item, self._grabbed_handle, wx, wy) 
     477                x, y = event.x, event.y 
     478                self.connect(view, self._grabbed_item, self._grabbed_handle, x, y) 
    479479        finally: 
    480480            context.view.queue_draw_item(context.view.hovered_item) 
     
    507507             
    508508            item.request_update() 
    509             #canvas.update_matrix(item) 
    510509            try: 
    511510                if self._grabbed_handle.connectable: 
    512                     self.glue(view, item, handle, x, y) 
     511                    self.glue(view, item, handle, event.x, event.y) 
    513512            finally: 
    514513                pass