def __init__(self, owner: AssociationItem, end: Optional[str] = None): self._canvas = None self._owner = owner self._end = end # Rendered text for name and multiplicity self._name = "" self._mult = "" self._name_bounds = Rectangle() self._mult_bounds = Rectangle() self._name_layout = Layout("") self._mult_layout = Layout("") self._inline_style: Style = {"font-size": 10}
def __init__(self, owner, end=None): super().__init__(id=False) # Transient object self.canvas = None self._owner = owner self._end = end # Rendered text for name and multiplicity self._name = "" self._mult = "" self._name_bounds = Rectangle() self._mult_bounds = Rectangle() self._name_layout = Layout("") self._mult_layout = Layout("") self._inline_style: Style = {"font-size": 10}
def test_text_with_font_as_dict_with_values_set_to_none(): w, h = Layout( "Example", { "font-family": "sans", "font-size": 9.5, "font-style": None, "font-weight": FontWeight.BOLD, "text-decoration": TextDecoration.NONE, }, ).size() assert w assert h
def test_text_with_font_as_dict(): w, h = Layout( "Example", { "font-family": "sans", "font-size": 10, "font-style": FontStyle.ITALIC, "font-weight": FontWeight.BOLD, "text-decoration": TextDecoration.UNDERLINE, }, ).size() assert w assert h
def draw_partitions(self, bounding_box: Rectangle, context: DrawContext) -> None: """Draw partition separators and add the name.""" cr = context.cairo if self.partition: partition_width = bounding_box.width / len(self.partition) else: partition_width = bounding_box.width / 2 layout = Layout() style = context.style padding_top = context.style["padding"][0] for num, partition in enumerate(self.partition): cr.move_to(partition_width * num, 0) cr.line_to(partition_width * num, bounding_box.height) layout.set(text=partition.name, font=style) cr.move_to(partition_width * num, padding_top * 3) layout.show_layout( cr, partition_width, default_size=(partition_width, HEADER_HEIGHT), )
def __init__(self, text=lambda: "", width=lambda: -1, style: Style = {}): self._text = text if callable(text) else lambda: text self.width = width if callable(width) else lambda: width self._inline_style = style self._layout = Layout()
class AssociationEnd: """An association end represents one end of an association. An association has two ends. An association end has two labels: one for the name and one for the multiplicity (and maybe one for tagged values in the future). An AsociationEnd has no ID, hence it will not be stored, but it will be recreated by the owning Association. """ def __init__(self, owner: AssociationItem, end: Optional[str] = None): self._canvas = None self._owner = owner self._end = end # Rendered text for name and multiplicity self._name = "" self._mult = "" self._name_bounds = Rectangle() self._mult_bounds = Rectangle() self._name_layout = Layout("") self._mult_layout = Layout("") self._inline_style: Style = {"font-size": 10} name_bounds = property(lambda s: s._name_bounds) @property def owner(self) -> AssociationItem: """Override Element.owner.""" return self._owner @property def owner_handle(self) -> Handle: # handle(event) is the event handler method return self._owner.head if self is self._owner.head_end else self._owner.tail @property def subject(self) -> Optional[UML.Property]: return getattr(self.owner, f"{self._end}_subject") # type:ignore[no-any-return] def request_update(self): self._owner.request_update() def set_text(self): """Set the text on the association end.""" if self.subject: try: n, m = format_association_end(self.subject) except ValueError: # need more than 0 values to unpack: property was rendered as # attribute while in a UNDO action for example. pass else: self._name = n self._mult = m self.request_update() def get_name(self): return self._name def get_mult(self): return self._mult def post_update(self, context, p1, p2): """Update label placement for association's name and multiplicity label. p1 is the line end and p2 is the last but one point of the line. """ style = combined_style(context.style, self._inline_style) ofs = 5 dx = float(p2[0]) - float(p1[0]) dy = float(p2[1]) - float(p1[1]) def max_text_size(size1, size2): w1, h1 = size1 w2, h2 = size2 return (max(w1, w2), max(h1, h2)) name_layout = self._name_layout name_layout.set_text(self._name) name_layout.set_font(style) name_w, name_h = max_text_size(name_layout.size(), (10, 10)) mult_layout = self._mult_layout mult_layout.set_text(self._mult) mult_layout.set_font(style) mult_w, mult_h = max_text_size(mult_layout.size(), (10, 10)) if dy == 0: rc = 1000.0 # quite a lot... else: rc = dx / dy abs_rc = abs(rc) h = dx > 0 # right side of the box v = dy > 0 # bottom side if abs_rc > 6: # horizontal line if h: name_dx = ofs name_dy = -ofs - name_h mult_dx = ofs mult_dy = ofs else: name_dx = -ofs - name_w name_dy = -ofs - name_h mult_dx = -ofs - mult_w mult_dy = ofs elif 0 <= abs_rc <= 0.2: # vertical line if v: name_dx = -ofs - name_w name_dy = ofs mult_dx = ofs mult_dy = ofs else: name_dx = -ofs - name_w name_dy = -ofs - name_h mult_dx = ofs mult_dy = -ofs - mult_h else: # Should both items be placed on the same side of the line? r = abs_rc < 1.0 # Find out alignment of text (depends on the direction of the line) align_left = h ^ r align_bottom = v ^ r if align_left: name_dx = ofs mult_dx = ofs else: name_dx = -ofs - name_w mult_dx = -ofs - mult_w if align_bottom: name_dy = -ofs - name_h mult_dy = -ofs - name_h - mult_h else: name_dy = ofs mult_dy = ofs + mult_h self._name_bounds = Rectangle( p1[0] + name_dx, p1[1] + name_dy, width=name_w, height=name_h ) self._mult_bounds = Rectangle( p1[0] + mult_dx, p1[1] + mult_dy, width=mult_w, height=mult_h ) def point(self, x, y): """Given a point (x, y) return the distance to the diagram item.""" drp = distance_rectangle_point pos = (x, y) d1 = drp(self._name_bounds, pos) d2 = drp(self._mult_bounds, pos) d3 = 1000.0 return min(d1, d2, d3) def draw(self, context): """Draw name and multiplicity of the line end.""" if not self.subject: return cr = context.cairo text_color = context.style.get("text-color") if text_color: cr.set_source_rgba(*text_color) cr.move_to(self._name_bounds.x, self._name_bounds.y) self._name_layout.show_layout(cr) cr.move_to(self._mult_bounds.x, self._mult_bounds.y) self._mult_layout.show_layout(cr) for b in (self._name_bounds, self._mult_bounds): text_draw_focus_box(context, b.x, b.y, b.width, b.height)
def test_text_with_just_font_as_dict(): w, h = Layout("Example", {"font-family": "sans", "font-size": 10}).size() assert w assert h