def __init__(self, properties = None, duplicate = None): GraphicsObject.__init__(self, duplicate = duplicate) if duplicate is not None: self.properties = duplicate.properties.Duplicate() if duplicate.tie_info: self.tie_info = duplicate.tie_info else: if properties is not None: self.properties = properties else: self.properties = PropertyStack()
def __init__(self, trafo=None, text='', halign=const.ALIGN_LEFT, valign=const.ALIGN_BASE, properties=None, duplicate=None): CommonText.__init__(self, text, duplicate) RectangularPrimitive.__init__(self, trafo, properties=properties, duplicate=duplicate) if duplicate != None: self.halign = duplicate.halign self.valign = duplicate.valign self.atrafo = duplicate.atrafo else: self.halign = halign self.valign = valign if properties is None: self.properties = PropertyStack(base=FactoryTextStyle()) self.properties.align = self.halign self.properties.valign = self.valign self.cache = {}
class SimpleText(CommonText, RectangularPrimitive): has_edit_mode = 1 is_Text = 1 is_SimpleText = 1 is_curve = 1 is_clip = 1 has_font = 1 has_fill = 1 has_line = 0 commands = CommonText.commands + RectangularPrimitive.commands _lazy_attrs = RectangularPrimitive._lazy_attrs.copy() _lazy_attrs['atrafo'] = 'update_atrafo' def __init__(self, trafo=None, text='', halign=const.ALIGN_LEFT, valign=const.ALIGN_BASE, properties=None, duplicate=None): CommonText.__init__(self, text, duplicate) RectangularPrimitive.__init__(self, trafo, properties=properties, duplicate=duplicate) if duplicate != None: self.halign = duplicate.halign self.valign = duplicate.valign self.atrafo = duplicate.atrafo else: self.halign = halign self.valign = valign if properties is None: self.properties = PropertyStack(base=FactoryTextStyle()) self.properties.align = self.halign self.properties.valign = self.valign self.cache = {} def Disconnect(self): self.cache = {} RectangularPrimitive.Disconnect(self) def Hit(self, p, rect, device, clip=0): a = self.properties llx, lly, urx, ury = a.font.TextBoundingBox(self.text, a.font_size, a) trafo = self.trafo(self.atrafo) trafo = trafo(Trafo(urx - llx, 0, 0, ury - lly, llx, lly)) return device.ParallelogramHit(p, trafo, 1, 1, 1, ignore_outline_mode=1) def GetObjectHandle(self, multiple): trafo = self.trafo(self.atrafo(Scale(self.properties.font_size))) if multiple: return trafo(NullPoint) else: pts = self.properties.font.TypesetText(self.text, self.properties) return map(trafo, pts) def SetAlignment(self, horizontal, vertical): undo = (self.SetAlignment, self.halign, self.valign) if horizontal is not None: self.halign = horizontal self.properties.align = horizontal if vertical is not None: self.valign = vertical self.properties.valign = vertical self._changed() return undo #AddCmd(commands, 'AlignLeft', _("Align Left"), SetAlignment, args = (const.ALIGN_LEFT, None)) #AddCmd(commands, 'AlignRight', _("Align Right"), SetAlignment, args =(const.ALIGN_RIGHT,None)) #AddCmd(commands, 'AlignHCenter', _("Align H. Center"), SetAlignment, args = (const.ALIGN_CENTER, None)) #AddCmd(commands, 'AlignTop', _("Align Top"), SetAlignment, args = (None, const.ALIGN_TOP)) #AddCmd(commands, 'AlignVCenter', _("Align V. Center"), SetAlignment, args =(None, const.ALIGN_CENTER)) #AddCmd(commands, 'AlignBase', _("Align Baseline"), SetAlignment, args = (None, const.ALIGN_BASE)) #AddCmd(commands, 'AlignBottom', _("Align Bottom"), SetAlignment, args = (None, const.ALIGN_BOTTOM)) def Alignment(self): return self.properties.align, self.properties.valign def RemoveTransformation(self): if self.trafo.matrix() != IdentityMatrix: a = self.properties trafo = self.trafo llx, lly, urx, ury = a.font.TextCoordBox(self.text, a.font_size, a) try: undostyle = Primitive.Transform(self, trafo.inverse()) except SingularMatrix: undostyle = None undotrafo = self.set_transformation(Translation(trafo.offset())) return CreateMultiUndo(undostyle, undotrafo) return NullUndo def DrawShape(self, device, rect=None, clip=0): RectangularPrimitive.DrawShape(self, device) base_trafo = self.trafo(self.atrafo) base_trafo = base_trafo(Scale(self.properties.font_size)) paths = self.properties.font.GetPaths(self.text, self.properties) obj = PolyBezier(paths, self.properties.Duplicate()) obj.Transform(base_trafo) device.MultiBezier(obj.paths, rect, clip) def update_atrafo(self): # a = self.properties # llx, lly, urx, ury = a.font.TextCoordBox(self.text, a.font_size, a) # hj = self.halign # if hj == ALIGN_RIGHT: # xoff = llx - urx # elif hj == ALIGN_CENTER: # xoff = (llx - urx) / 2 # else: # xoff = 0 xoff = 0 yoff = 0 # vj = self.valign # if vj == ALIGN_TOP: # yoff = -ury # elif vj == ALIGN_CENTER: # yoff = (lly - ury) / 2 - lly # elif vj == ALIGN_BOTTOM: # yoff = -lly # else: # yoff = 0 self.atrafo = Translation(xoff, yoff) def update_rects(self): trafo = self.trafo(self.atrafo) a = self.properties rect = apply(Rect, a.font.TextBoundingBox(self.text, a.font_size, a)) self.bounding_rect = trafo(rect).grown(2) rect = apply(Rect, a.font.TextCoordBox(self.text, a.font_size, a)) self.coord_rect = trafo(rect) def Info(self): text = self.text.replace('\n', '') text = text.replace('\r', '') text = text.replace('\t', '') text = text.strip() if len(text) > 25: text = text[:25] + '...' text = text.encode('utf-8') return (_("Text `%(text)s' at %(position)[position]"), { 'text': text, 'position': self.trafo.offset() }) def FullTrafo(self): # XXX perhaps the Trafo method should return # self.trafo(self.atrafo) for a SimpleText object as well. return self.trafo(self.atrafo) def SaveToFile(self, file): RectangularPrimitive.SaveToFile(self, file) file.SimpleText(self.text, self.trafo, self.properties.align, self.properties.valign, self.properties.chargap, self.properties.wordgap, self.properties.linegap) def Blend(self, other, p, q): if self.__class__ != other.__class__ \ or self.properties.font != other.properties.font \ or self.text != other.text: raise MismatchError blended = self.__class__(BlendTrafo(self.trafo, other.trafo, p, q), self.text) self.set_blended_properties(blended, other, p, q) return blended def AsBezier(self): if self.text: text = split(self.text, '\n')[0] base_trafo = self.trafo(self.atrafo) base_trafo = base_trafo(Scale(self.properties.font_size)) paths = self.properties.font.GetPaths(self.text, self.properties) obj = PolyBezier(paths, self.properties.Duplicate()) obj.Transform(base_trafo) return obj def Paths(self): # paths = [] if self.text: text = split(self.text, '\n')[0] base_trafo = self.trafo(self.atrafo) base_trafo = base_trafo(Scale(self.properties.font_size)) paths = self.properties.font.GetPaths(self.text, self.properties) obj = PolyBezier(paths, self.properties.Duplicate()) obj.Transform(base_trafo) return obj.paths # base_trafo = self.trafo(self.atrafo) # base_trafo = base_trafo(Scale(self.properties.font_size)) # pos = self.properties.font.TypesetText(self.text) # for i in range(len(self.text)): # outline = self.properties.font.GetOutline(self.text[i]) # trafo = base_trafo(Translation(pos[i])) # for path in outline: # path.Transform(trafo) # paths.append(path) # return tuple(paths) def Editor(self): return SimpleTextEditor(self) context_commands = ('AlignLeft', 'AlignRight', 'AlignHCenter', None, 'AlignTop', 'AlignVCenter', 'AlignBase', 'AlignBottom')
class Primitive(GraphicsObject): has_fill = 1 has_line = 1 has_properties = 1 is_Primitive = 1 tie_info = None script_access = GraphicsObject.script_access.copy() def __init__(self, properties = None, duplicate = None): GraphicsObject.__init__(self, duplicate = duplicate) if duplicate is not None: self.properties = duplicate.properties.Duplicate() if duplicate.tie_info: self.tie_info = duplicate.tie_info else: if properties is not None: self.properties = properties else: self.properties = PropertyStack() def Destroy(self): GraphicsObject.Destroy(self) def UntieFromDocument(self): info = self.properties.Untie() if info: self.tie_info = info GraphicsObject.UntieFromDocument(self) def TieToDocument(self): if self.tie_info: self.properties.Tie(self.document, self.tie_info) del self.tie_info def Transform(self, trafo, rects = None): # Apply the affine transformation trafo to all coordinates and # the properties. undo = self.properties.Transform(trafo, rects) if undo is not NullUndo: return self.properties_changed(undo) return undo def Translate(self, offset): # Move all points by OFFSET. OFFSET is an SKPoint instance. return NullUndo def DrawShape(self, device): # Draw the object on device. Here we just set the properties. device.SetProperties(self.properties, self.bounding_rect) # The following functions manage the properties def set_property_stack(self, properties): self.properties = properties load_SetProperties = set_property_stack def properties_changed(self, undo): if undo is not NullUndo: return (UndoAfter, undo, self._changed()) return undo def AddStyle(self, style): return self.properties_changed(self.properties.AddStyle(style)) script_access['AddStyle'] = SCRIPT_UNDO def Filled(self): return self.properties.HasFill() script_access['Filled'] = SCRIPT_GET def Properties(self): return self.properties script_access['Properties'] = SCRIPT_OBJECT def SetProperties(self, if_type_present = 0, **kw): if if_type_present: # change properties of that type if properties of that are # already present. prop_types = properties.property_types LineProperty = properties.LineProperty FillProperty = properties.FillProperty FontProperty = properties.FontProperty types = map(prop_types.get, kw.keys()) if LineProperty in types and not self.properties.HasLine(): for key in kw.keys(): if prop_types[key] == LineProperty: del kw[key] if FillProperty in types and not self.properties.HasFill(): for key in kw.keys(): if prop_types[key] == FillProperty: del kw[key] if FontProperty in types and not self.properties.HasFont(): for key in kw.keys(): if prop_types[key] == FontProperty: del kw[key] return self.properties_changed(apply(self.properties.SetProperty, (), kw)) script_access['SetProperties'] = SCRIPT_UNDO def LineWidth(self): if self.properties.HasLine: return self.properties.line_width return 0 script_access['LineWidth'] = SCRIPT_GET def ObjectChanged(self, obj): if self.properties.ObjectChanged(obj): rect = self.bounding_rect self.del_lazy_attrs() self.document.AddClearRect(UnionRects(rect, self.bounding_rect)) self.issue_changed() return 1 return 0 def ObjectRemoved(self, obj): return self.properties.ObjectRemoved(obj) def set_blended_properties(self, blended, other, frac1, frac2): blended.set_property_stack(Blend(self.properties, other.properties, frac1, frac2)) def SaveToFile(self, file): # save object to file. Must be extended by the subclasses. Here, # we just save the properties. self.properties.SaveToFile(file)
class SimpleText(CommonText, RectangularPrimitive): has_edit_mode = 1 is_Text = 1 is_SimpleText = 1 is_curve = 1 is_clip = 1 has_font = 1 has_fill = 1 has_line = 0 cid = cids.TEXT commands = CommonText.commands + RectangularPrimitive.commands _lazy_attrs = RectangularPrimitive._lazy_attrs.copy() _lazy_attrs['atrafo'] = 'update_atrafo' def __init__(self, trafo=None, text='', halign=const.ALIGN_LEFT, valign=const.ALIGN_BASE, properties=None, duplicate=None): CommonText.__init__(self, text, duplicate) RectangularPrimitive.__init__(self, trafo, properties=properties, duplicate=duplicate) if duplicate != None: self.halign = duplicate.halign self.valign = duplicate.valign self.atrafo = duplicate.atrafo else: self.halign = halign self.valign = valign if properties is None: self.properties = PropertyStack(base=FactoryTextStyle()) self.properties.align = self.halign self.properties.valign = self.valign self.cache = {} def Disconnect(self): self.cache = {} RectangularPrimitive.Disconnect(self) def Hit(self, p, rect, device, clip=0): a = self.properties if self.bounding_rect_cache is None: res = tuple(a.font.text_bbox(self.text, a)) self.bounding_rect_cache = copy.deepcopy(res) else: res = copy.deepcopy(self.bounding_rect_cache) llx, lly, urx, ury = res trafo = self.trafo(self.atrafo) trafo = trafo(Trafo(urx - llx, 0, 0, ury - lly, llx, lly)) return device.ParallelogramHit(p, trafo, 1, 1, 1, ignore_outline_mode=1) def GetObjectHandle(self, multiple): trafo = self.trafo(self.atrafo) if multiple: return trafo(NullPoint) else: if self.typesets_cache is None: a = self.properties pts = self.convert_typeset(a.font.typeset_text(self.text, a)) self.typesets_cache = self.duplicate_typeset(pts) else: pts = self.duplicate_typeset(self.typesets_cache) return map(trafo, pts) def convert_typeset(self, pts): result = [] for item in pts: result.append(Point(*item)) return result def duplicate_typeset(self, typeset): result = [] for point in typeset: result.append(Point(point.x, point.y)) return result def SetAlignment(self, horizontal, vertical): undo = (self.SetAlignment, self.halign, self.valign) if horizontal is not None: self.halign = horizontal self.properties.align = horizontal if vertical is not None: self.valign = vertical self.properties.valign = vertical self._changed() return undo AddCmd(commands, 'AlignLeft', _("Align Left"), SetAlignment, args=(const.ALIGN_LEFT, None)) AddCmd(commands, 'AlignRight', _("Align Right"), SetAlignment, args=(const.ALIGN_RIGHT, None)) AddCmd(commands, 'AlignHCenter', _("Align H. Center"), SetAlignment, args=(const.ALIGN_CENTER, None)) AddCmd(commands, 'AlignTop', _("Align Top"), SetAlignment, args=(None, const.ALIGN_TOP)) AddCmd(commands, 'AlignVCenter', _("Align V. Center"), SetAlignment, args=(None, const.ALIGN_CENTER)) AddCmd(commands, 'AlignBase', _("Align Baseline"), SetAlignment, args=(None, const.ALIGN_BASE)) AddCmd(commands, 'AlignBottom', _("Align Bottom"), SetAlignment, args=(None, const.ALIGN_BOTTOM)) def Alignment(self): return self.properties.align, self.properties.valign def RemoveTransformation(self): if self.trafo.matrix() != IdentityMatrix: trafo = self.trafo try: undostyle = Primitive.Transform(self, trafo.inverse()) except SingularMatrix: undostyle = None undotrafo = self.set_transformation(Translation(trafo.offset())) return CreateMultiUndo(undostyle, undotrafo) return NullUndo def DrawShape(self, device, rect=None, clip=0): RectangularPrimitive.DrawShape(self, device) base_trafo = self.trafo(self.atrafo) if self.curves_cache is None: a = self.properties paths = a.font.get_paths(self.text, a) self.curves_cache = self.convert_paths(paths) paths = self.duplicate_paths(self.curves_cache) obj = PolyBezier(paths, self.properties.Duplicate()) obj.Transform(base_trafo) device.MultiBezier(obj.paths, rect, clip) def convert_paths(self, paths_list): paths = () for path in paths_list: p = CreatePath() p.AppendLine(Point(*path[0])) points = path[1] for point in points: if len(point) == 2: p.AppendLine(Point(*point)) else: point0 = Point(*point[0]) point1 = Point(*point[1]) point2 = Point(*point[2]) p.AppendBezier(point0, point1, point2, point[3]) if path[2]: p.AppendLine(Point(*path[0])) p.ClosePath() paths = paths + (p,) return paths def duplicate_paths(self, paths): copy = [] for path in paths: copy.append(path.Duplicate()) return tuple(copy) def update_atrafo(self): # a = self.properties # llx, lly, urx, ury = a.font.TextCoordBox(self.text, a.font_size, a) # hj = self.halign # if hj == ALIGN_RIGHT: # xoff = llx - urx # elif hj == ALIGN_CENTER: # xoff = (llx - urx) / 2 # else: # xoff = 0 xoff = 0 yoff = 0 # vj = self.valign # if vj == ALIGN_TOP: # yoff = -ury # elif vj == ALIGN_CENTER: # yoff = (lly - ury) / 2 - lly # elif vj == ALIGN_BOTTOM: # yoff = -lly # else: # yoff = 0 self.atrafo = Translation(xoff, yoff) def update_rects(self): trafo = self.trafo(self.atrafo) a = self.properties if self.bounding_rect_cache is None: res = a.font.text_bbox(self.text, a) self.bounding_rect_cache = copy.deepcopy(res) else: res = copy.deepcopy(self.bounding_rect_cache) rect = apply(Rect, res) self.bounding_rect = trafo(rect).grown(2) if self.coord_rect_cache is None: res = a.font.text_bbox(self.text, a) self.coord_rect_cache = copy.deepcopy(res) else: res = copy.deepcopy(self.coord_rect_cache) rect = apply(Rect, res) self.coord_rect = trafo(rect) def Info(self): text = self.text.replace('\n', '') text = text.replace('\r', '') text = text.replace('\t', '') text = text.strip() if len(text) > 25: text = text[:25] + '...' text = text.encode('utf-8') return (_("Text `%(text)s' at %(position)[position]"), {'text':text, 'position':self.trafo.offset()}) def FullTrafo(self): # XXX perhaps the Trafo method should return return self.trafo(self.atrafo) def SaveToFile(self, file): RectangularPrimitive.SaveToFile(self, file) file.SimpleText(self.text, self.trafo, self.properties.align, self.properties.valign, self.properties.chargap, self.properties.wordgap, self.properties.linegap) def Blend(self, other, p, q): if self.__class__ != other.__class__ \ or self.properties.font != other.properties.font \ or self.text != other.text: raise MismatchError blended = self.__class__(BlendTrafo(self.trafo, other.trafo, p, q), self.text) self.set_blended_properties(blended, other, p, q) return blended def AsBezier(self): if self.text: base_trafo = self.trafo(self.atrafo) if self.curves_cache is None: a = self.properties paths = a.font.get_paths(self.text, a) self.curves_cache = self.convert_paths(paths) paths = self.duplicate_paths(self.curves_cache) obj = PolyBezier(paths, self.properties.Duplicate()) obj.Transform(base_trafo) return obj def Paths(self): if self.text: base_trafo = self.trafo(self.atrafo) if self.curves_cache is None: a = self.properties paths = a.font.get_paths(self.text, a) self.curves_cache = self.convert_paths(paths) paths = self.duplicate_paths(self.curves_cache) obj = PolyBezier(paths, self.properties.Duplicate()) obj.Transform(base_trafo) return obj.paths def Editor(self): return SimpleTextEditor(self) context_commands = ('AlignLeft', 'AlignRight', 'AlignHCenter', None, 'AlignTop', 'AlignVCenter', 'AlignBase', 'AlignBottom')