class Position(object): """ A point constructed of two `Variable`'s. >>> vp = Position((3, 5)) >>> vp.x, vp.y (Variable(3, 20), Variable(5, 20)) >>> vp.pos (Variable(3, 20), Variable(5, 20)) >>> vp[0], vp[1] (Variable(3, 20), Variable(5, 20)) """ _x = solvable(varname='_v_x') _y = solvable(varname='_v_y') def __init__(self, pos, strength=NORMAL): self._x, self._y = pos self._x.strength = strength self._y.strength = strength # _x is a Variable, therefore observed def _set_x(self, x): self._x = x x = property(lambda s: s._x, _set_x) # _y is a Variable, therefore observed def _set_y(self, y): self._y = y y = property(lambda s: s._y, _set_y) @observed def _set_pos(self, pos): """ Set handle position (Item coordinates). """ self.x, self.y = pos pos = property(lambda s: (s.x, s.y), _set_pos) def __str__(self): return '<%s object on (%g, %g)>' % (self.__class__.__name__, float(self._x), float(self._y)) __repr__ = __str__ def __getitem__(self, index): """ Shorthand for returning the x(0) or y(1) component of the point. >>> h = Position((3, 5)) >>> h[0] Variable(3, 20) >>> h[1] Variable(5, 20) """ return (self.x, self.y)[index]
class Position: """ A point constructed of two `Variable`'s. >>> vp = Position((3, 5)) >>> vp.x, vp.y (Variable(3, 20), Variable(5, 20)) >>> vp.pos (Variable(3, 20), Variable(5, 20)) >>> vp[0], vp[1] (Variable(3, 20), Variable(5, 20)) """ x = solvable(varname="_v_x") y = solvable(varname="_v_y") def __init__(self, pos, strength=NORMAL): self.x, self.y = pos self.x.strength = strength self.y.strength = strength def _set_pos(self, pos): """ Set handle position (Item coordinates). """ self.x, self.y = pos pos = property(lambda s: (s.x, s.y), _set_pos) def __str__(self): return f"<{self.__class__.__name__} object on ({self.x}, {self.y})>" __repr__ = __str__ def __getitem__(self, index): """ Shorthand for returning the x(0) or y(1) component of the point. >>> h = Position((3, 5)) >>> h[0] Variable(3, 20) >>> h[1] Variable(5, 20) """ return (self.x, self.y)[index]
class ElementNoPorts(Element): """ This is a copy of the Element class, but without the declaration of the LinePorts in the __init__ method. It will be proposed to the Gaphor team that the Element class be modified like this, because there is quite a lot of useful code aside from the LinePort definition. """ min_width = solvable(strength=REQUIRED, varname='_min_width') min_height = solvable(strength=REQUIRED, varname='_min_height') def __init__(self, width=10, height=10): super(Element, self).__init__() self._handles = [ h(strength=VERY_STRONG) for h in [Handle]*4 ] handles = self._handles h_nw = handles[NW] h_ne = handles[NE] h_sw = handles[SW] h_se = handles[SE] # Share variables h_sw.pos.set_x(h_nw.pos.x) h_se.pos.set_x(h_ne.pos.x) h_ne.pos.set_y(h_nw.pos.y) h_se.pos.set_y(h_sw.pos.y) # No ports by default self._ports = [] # initialize min_x variables self.min_width, self.min_height = 10, 10 factor = 7 delta_w = len(self.blockinstance.name)*factor delta_h = 10 self.min_width = delta_w self.min_height = delta_h # create minimal size constraints self.constraint(left_of=(h_nw.pos, h_se.pos), delta=self._min_width) self.constraint(above=(h_nw.pos, h_se.pos), delta=self._min_height) self.width = width self.height = height
class Position(object): """ A point constructed of two `Variable`'s. >>> vp = Position((3, 5)) >>> vp.x, vp.y (Variable(3, 20), Variable(5, 20)) >>> vp.pos (Variable(3, 20), Variable(5, 20)) >>> vp[0], vp[1] (Variable(3, 20), Variable(5, 20)) """ x = solvable(varname="_v_x") y = solvable(varname="_v_y") def __init__(self, pos, strength=NORMAL): self.x, self.y = pos self.x.strength = strength self.y.strength = strength @observed def _set_pos(self, pos): """ Set handle position (Item coordinates). """ self.x, self.y = pos pos = property(lambda s: (s.x, s.y), _set_pos) def set_x(self, vx): """ Set the variable for x. NOTE: This changes the variable object itself, not only the value! """ self._v_x = vx def set_y(self, vy): """ Set the variable for y. NOTE: This changes the variable object itself, not only the value! """ self._v_y = vy def __str__(self): return "<%s object on (%g, %g)>" % ( self.__class__.__name__, float(self.x), float(self.y), ) __repr__ = __str__ def __getitem__(self, index): """ Shorthand for returning the x(0) or y(1) component of the point. >>> h = Position((3, 5)) >>> h[0] Variable(3, 20) >>> h[1] Variable(5, 20) """ return (self.x, self.y)[index]
class Element(Item): """ An Element has 4 handles (for a start):: NW +---+ NE | | SW +---+ SE """ min_width = solvable(strength=REQUIRED, varname="_min_width") min_height = solvable(strength=REQUIRED, varname="_min_height") def __init__(self, width=10, height=10): super(Element, self).__init__() self._handles = [h(strength=VERY_STRONG) for h in [Handle] * 4] handles = self._handles h_nw = handles[NW] h_ne = handles[NE] h_sw = handles[SW] h_se = handles[SE] # Share variables h_sw.pos.set_x(h_nw.pos.x) h_se.pos.set_x(h_ne.pos.x) h_ne.pos.set_y(h_nw.pos.y) h_se.pos.set_y(h_sw.pos.y) # edge of element define default element ports self._ports = [ LinePort(h_nw.pos, h_ne.pos), LinePort(h_ne.pos, h_se.pos), LinePort(h_se.pos, h_sw.pos), LinePort(h_sw.pos, h_nw.pos), ] # initialize min_x variables self.min_width, self.min_height = 10, 10 # create minimal size constraints self.constraint(left_of=(h_nw.pos, h_se.pos), delta=self._min_width) self.constraint(above=(h_nw.pos, h_se.pos), delta=self._min_height) self.width = width self.height = height # TODO: constraints that calculate width and height based on handle pos # self.constraints.append(EqualsConstraint(p1[1], p2[1], delta)) def setup_canvas(self): super(Element, self).setup_canvas() # Trigger solver to honour width/height by SE handle pos self._handles[SE].pos.x.dirty() self._handles[SE].pos.y.dirty() def _set_width(self, width): """ >>> b=Element() >>> b.width = 20 >>> b.width 20.0 >>> b._handles[NW].pos.x Variable(0, 40) >>> b._handles[SE].pos.x Variable(20, 40) """ h = self._handles h[SE].pos.x = h[NW].pos.x + width def _get_width(self): """ Width of the box, calculated as the distance from the left and right handle. """ h = self._handles return float(h[SE].pos.x) - float(h[NW].pos.x) width = property(_get_width, _set_width) def _set_height(self, height): """ >>> b=Element() >>> b.height = 20 >>> b.height 20.0 >>> b.height = 2 >>> b.height 2.0 >>> b._handles[NW].pos.y Variable(0, 40) >>> b._handles[SE].pos.y Variable(2, 40) """ h = self._handles h[SE].pos.y = h[NW].pos.y + height def _get_height(self): """ Height. """ h = self._handles return float(h[SE].pos.y) - float(h[NW].pos.y) height = property(_get_height, _set_height) def normalize(self): """ Normalize only NW and SE handles """ updated = False handles = self._handles handles = (handles[NW], handles[SE]) x, y = list(map(float, handles[0].pos)) if x: self.matrix.translate(x, 0) updated = True for h in handles: h.pos.x -= x if y: self.matrix.translate(0, y) updated = True for h in handles: h.pos.y -= y return updated def point(self, pos): """ Distance from the point (x, y) to the item. >>> e = Element() >>> e.point((20, 10)) 10.0 """ h = self._handles pnw, pse = h[NW].pos, h[SE].pos return distance_rectangle_point( list(map(float, (pnw.x, pnw.y, pse.x, pse.y))), pos)