Difference between revisions of "Python/ShapeDrawingFunction"
From Apache OpenOffice Wiki
< Python
Marcoagpinto (Talk | contribs) ([Python, Calc] Shape Drawing Add-In Function) |
m |
||
Line 1: | Line 1: | ||
{{DISPLAYTITLE:Shape Drawing Add-In Function}} | {{DISPLAYTITLE:Shape Drawing Add-In Function}} | ||
− | This script was published by Charlie Young at the [ | + | This script was published by Charlie Young at the [https://forum.openoffice.org/en/forum/viewtopic.php?f=21&t=57754 Code Snippets Forum]. |
A recent thread in the Calc forum got me started on this. As discussed there, it is possible for a cell function to insert shapes into a sheet's DrawPage. In that thread I posted a Basic function, which I have now considerably extended using Python. | A recent thread in the Calc forum got me started on this. As discussed there, it is possible for a cell function to insert shapes into a sheet's DrawPage. In that thread I posted a Basic function, which I have now considerably extended using Python. | ||
== Original code == | == Original code == | ||
− | < | + | <syntaxhighlight lang="Python"> |
import uno | import uno | ||
import unohelper | import unohelper | ||
Line 331: | Line 331: | ||
− | </ | + | </syntaxhighlight> |
== Process of the script == | == Process of the script == | ||
[[Category:Python]] | [[Category:Python]] |
Latest revision as of 14:05, 15 May 2021
This script was published by Charlie Young at the Code Snippets Forum.
A recent thread in the Calc forum got me started on this. As discussed there, it is possible for a cell function to insert shapes into a sheet's DrawPage. In that thread I posted a Basic function, which I have now considerably extended using Python.
Original code
import uno import unohelper import math from com.pydraw import XPyDraw from com.sun.star.awt import Size, Point from com.sun.star.drawing import HomogenMatrix3, HomogenMatrixLine3 #Set up enum classes. class FillStyle(): from com.sun.star.drawing.FillStyle import (NONE, SOLID, GRADIENT, HATCH, BITMAP) class BitmapMode(): from com.sun.star.drawing.BitmapMode import (REPEAT, STRETCH, NO_REPEAT) class FontWeight(): from com.sun.star.awt.FontWeight import (NORMAL, BOLD) class FontUnderline(): from com.sun.star.awt.FontUnderline import (SINGLE, NONE) class FontSlant(): from com.sun.star.awt.FontSlant import (NONE, ITALIC) class TextHorizontalAdjust(): from com.sun.star.drawing.TextHorizontalAdjust import (LEFT, CENTER, RIGHT, BLOCK) class TextVerticalAdjust(): from com.sun.star.drawing.TextVerticalAdjust import (TOP, CENTER, BOTTOM, BLOCK) # Draw Shapes add-in function. class PyDrawImpl( unohelper.Base, XPyDraw ): def __init__( self, ctx ): self.ctx = ctx def PyDraw(self, dims, ShapeName, FillSpecs, ShapeText): desktop = self.ctx.getServiceManager().createInstanceWithContext("com.sun.star.frame.Desktop", self.ctx) oDoc = desktop.getCurrentComponent() oSheets = oDoc.getSheets() #Gets style for default text properties. defaultStyle = oDoc.getStyleFamilies().getByName("CellStyles").getByName("Default") ShapeServices = ["com.sun.star.drawing.RectangleShape","com.sun.star.drawing.EllipseShape","com.sun.star.drawing.TextShape"] ShapesIn = getShapes(dims) #Erase any existing shapes named ShapeName_number self.delPyDraw(ShapeName) ReturnStr = ShapeName hasError = False pyShapes= [] #Check shapes for valid coordinates and type. for i in range(len(ShapesIn)): ShapeError = False pyShape = ShapesIn[i] sheet, x, y, w, h, Rotate, ShapeType = map(float,pyShape) sheet = int(sheet) if sheet < 0 or sheet >= oSheets.getCount(): if not ShapeError: ShapeError = True ReturnStr = ReturnStr + ": " if not hasError else ReturnStr + ", " else: ReturnStr = ReturnStr + ", " ReturnStr = ReturnStr + "Shape " + str(i) + " Sheet out of range" else: oSheet = oSheets.getByIndex(sheet) x, y, w, h, ShapeType = long(1000*x), long(1000*y), long(1000*w), long(1000*h), int(ShapeType) SheetPos = oSheet.Position SheetSize = oSheet.Size if (x < SheetPos.X or x + w > SheetPos.X + SheetSize.Width) or (y < SheetPos.Y or y + h > SheetPos.Y + SheetSize.Height) or (w <= 0 or h <= 0): if not ShapeError: ShapeError = True ReturnStr = ReturnStr + ": " if not hasError else ReturnStr + ", " else: ReturnStr = ReturnStr + ", " ReturnStr = ReturnStr + "Shape " + str(i) + " dimensions out of range" elif ShapeType < 0 or ShapeType > 2: if not ShapeError: ShapeError = True ReturnStr = ReturnStr + ": " if not hasError else ReturnStr + ", " else: ReturnStr = ReturnStr + ", " ReturnStr = ReturnStr + "Shape " + str(i) + " Invalid shape type" #add shape if it's OK. if not ShapeError: pyShapes.append(pyShape) else: hasError = True #pyShape = [sheet,x,y,width,height,theta,type] fillList = [FillStyle.NONE,FillStyle.SOLID,FillStyle.GRADIENT,FillStyle.HATCH,FillStyle.BITMAP,FillStyle.BITMAP] #Set defaults for Gradient, Hatch, and Bitmap fill. fillDefaults = ["Gradient 1","Black 0 degrees","Blank"] #Insert the shapes for i in range(len(pyShapes)): pyShape = pyShapes[i] sheet, x, y, w, h, Rotate, ShapeType = map(float,pyShape) x, y, w, h, ShapeType = long(1000*x), long(1000*y), long(1000*w), long(1000*h), int(ShapeType) filltrans = 0 fillurl = False if type(FillSpecs) == tuple: FillSpec = FillSpecs[i] if len(FillSpecs) > i else [float(-1)] if type(FillSpec[0]) == float: fillstyle = FillStyle.SOLID FillColor = int(FillSpec[0]) # Read transparency value from second column. filltrans = 0 if len(FillSpec) < 2 or type(FillSpec[1]) != float else int(FillSpec[1]) if 0 < FillSpec[1] <= 100 else 0 elif type(FillSpec[0]) == unicode: if len(FillSpec[0]) > 0: #Get fill type from letter code. fillIndex = "nsghbu".find(FillSpec[0][0].lower()) if fillIndex != -1: fillstyle = fillList[fillIndex] fillurl = False if fillIndex < 5 else True else: ReturnStr = ReturnStr + ": " if not hasError else ReturnStr + ", " ReturnStr = ReturnStr + "Shape " + str(i) + " Invalid fill, set to SOLID" hasError = True else: fillstyle = FillStyle.SOLID #default to solid color. if fillstyle in [FillStyle.GRADIENT,FillStyle.HATCH,FillStyle.BITMAP]: #Get the fill name if len(FillSpec) > 1 and type(FillSpec[1]) == unicode: fillname = FillSpec[1] if len(FillSpec[1]) > 0 else fillDefaults[fillIndex - 2] else: fillname = fillDefaults[fillIndex - 2] #Read transparency value from third column filltrans = 0 if len(FillSpec) < 3 or type(FillSpec[2]) != float else int(FillSpec[2]) if 0 < FillSpec[2] <= 100 else 0 elif type(FillSpecs) == float: #Default to solid color fill for all shapes with color FillSpecs fillstyle = FillStyle.SOLID FillColor = int(FillSpecs) else: fillstyle = FillStyle.SOLID FillColor = -1 hasText = False if type(ShapeText) == tuple: TextSpec = ShapeText[i] if len(ShapeText) > i else [""] ShapeString = "" if type(TextSpec[0]) == unicode and len(TextSpec[0]) > 0: hasText = True ShapeString = TextSpec[0] if hasText: if len(TextSpec) > 1 and type(TextSpec[1]) == unicode and len(TextSpec[1]) > 0: TextBold = FontWeight.BOLD if "b" in TextSpec[1].lower() else FontWeight.NORMAL TextUnder = FontUnderline.SINGLE if "u" in TextSpec[1].lower() else FontUnderline.NONE TextItalic = FontSlant.ITALIC if "i" in TextSpec[1].lower() else FontSlant.NONE else: TextBold = FontWeight.NORMAL TextUnder = FontUnderline.NONE TextItalic = FontSlant.NONE if len(TextSpec) > 2 and type(TextSpec[2]) == unicode: if TextSpec[2].upper() == "TOP": TextVertical = TextVerticalAdjust.TOP elif TextSpec[2].upper() == "BOTTOM": TextVertical = TextVerticalAdjust.BOTTOM elif TextSpec[2].upper() == "BLOCK": TextVertical = TextVerticalAdjust.BLOCK else: TextVertical = TextVerticalAdjust.CENTER else: TextVertical = TextVerticalAdjust.CENTER if len(TextSpec) > 3 and type(TextSpec[3]) == unicode: if TextSpec[3].upper() == "LEFT": TextHorizontal = TextHorizontalAdjust.LEFT elif TextSpec[3].upper() == "RIGHT": TextHorizontal = TextHorizontalAdjust.RIGHT elif TextSpec[3].upper() == "BLOCK": TextHorizontal = TextHorizontalAdjust.BLOCK else: TextHorizontal = TextHorizontalAdjust.CENTER else: TextHorizontal = TextHorizontalAdjust.CENTER if len(TextSpec) > 4 and type(TextSpec[4]) == float: TextHeight = TextSpec[4] if TextSpec[4] > 0 else defaultStyle.CharHeight else: TextHeight = defaultStyle.CharHeight if len(TextSpec) > 5 and type(TextSpec[5]) == float: TextColor = long(TextSpec[5]) if TextSpec[5] > 0 else defaultStyle.CharColor else: TextColor = defaultStyle.CharColor if len(TextSpec) > 6 and type(TextSpec[6]) == unicode: TextFontName = TextSpec[6] if len(TextSpec[6]) > 0 else defaultStyle.CharFontName else: TextFontName = defaultStyle.CharFontName oShape = oDoc.createInstance(ShapeServices[ShapeType]) oShape.Name = ShapeName + "_" + str(i) sheet = pyShape[0] oShapes = oSheets.getByIndex(sheet).getDrawPage() oShapes.add(oShape) oShape.FillStyle = fillstyle try: if fillstyle == FillStyle.GRADIENT: oShape.FillGradientName = fillname elif fillstyle == FillStyle.HATCH: oShape.FillHatchName = fillname elif fillstyle == FillStyle.BITMAP: if not fillurl: oShape.FillBitmapName = fillname else: oShape.FillBitmapURL = fillname oShape.FillBitmapMode = BitmapMode.STRETCH else: oShape.FillColor = FillColor except: ReturnStr = ReturnStr + ": " if not hasError else ReturnStr + ", " ReturnStr = ReturnStr + "Shape " + str(i) + " Invalid fill name, set to default." hasError = True if fillstyle == FillStyle.GRADIENT: oShape.FillGradientName = "Gradient 1" elif fillstyle == FillStyle.HATCH: oShape.FillHatchName = "Black 0 degrees" elif fillstyle == FillStyle.BITMAP: oShape.FillBitmapName = "Blank" else: oShape.FillColor = FillColor if hasText: try: oShape.String = ShapeString oShape.CharWeight = TextBold oShape.CharUnderline = TextUnder oShape.CharPosture = TextItalic oShape.CharHeight = TextHeight oShape.CharColor = TextColor oShape.CharFontName = TextFontName oShape.TextHorizontalAdjust = TextHorizontal oShape.TextVerticalAdjust = TextVertical except: ReturnStr = ReturnStr + ": " if not hasError else ReturnStr + ", " ReturnStr = ReturnStr + "Shape " + str(i) + " Invalid text format, set to default" hasError = True oShape.String = ShapeString oShape.CharWeight = defaultStyle.CharWeight oShape.CharUnderline = defaultStyle.CharUnderline oShape.CharPosture = defaultStyle.CharPosture oShape.CharHeight = defaultStyle.CharHeight oShape.CharColor = defaultStyle.CharColor oShape.CharFontName = defaultStyle.CharFontName oShape.TextHorizontalAdjust = TextHorizontalAdjust.CENTER oShape.TextVerticalAdjust = TextVerticalAdjust.CENTER oShape.FillTransparence = filltrans s = Size(w, h) p = Point(x, y) theta = math.radians(Rotate) oShape.setSize(s) oShape.setPosition(p) #Apply rotation if theta != 0: tMatrix = HomogenMatrix3() l1 = HomogenMatrixLine3() l2 = HomogenMatrixLine3() X = oShape.getPropertyValue("Transformation") xMatrix = [[0,0],[0,0]] xMatrix[0][0] = X.Line1.Column1 xMatrix[0][1] = X.Line1.Column2 xMatrix[1][0] = X.Line2.Column1 xMatrix[1][1] = X.Line2.Column2 #Rotate the transformation matrix. stheta = math.sin(theta) ctheta = math.cos(theta) l1.Column1 = xMatrix[0][0] * ctheta + xMatrix[1][0] * stheta l2.Column1 = -xMatrix[0][0] * stheta + xMatrix[1][0] * ctheta l1.Column2 = xMatrix[0][1] * ctheta + xMatrix[1][1] * stheta l2.Column2 = -xMatrix[0][1] * stheta + xMatrix[1][1] * ctheta #Adjust position to rotate about center. l1.Column3 = X.Line1.Column3 + long((w - w * ctheta - h * stheta)/2) l2.Column3 = X.Line2.Column3 + long((h - h * ctheta + w * stheta)/2) tMatrix.Line1 = l1 tMatrix.Line2 = l2 tMatrix.Line3 = X.Line3 oShape.setPropertyValue("Transformation",tMatrix) return ReturnStr #Deletes all shapes named ShapeName_number def delPyDraw(self, ShapeName): desktop = self.ctx.getServiceManager().createInstanceWithContext("com.sun.star.frame.Desktop", self.ctx) oDoc = desktop.getCurrentComponent() ShapeServices = ["com.sun.star.drawing.RectangleShape","com.sun.star.drawing.EllipseShape","com.sun.star.drawing.TextShape"] oSheets = oDoc.getSheets() delCount = 0 for i in range(oSheets.getCount()): oSheet = oSheets.getByIndex(i) oShapes = oSheet.getDrawPage() c = oShapes.getCount() while c > 0: oShape = oShapes.getByIndex(c - 1) if oShape.getShapeType() in ShapeServices and oShape.getName().startswith(ShapeName + "_"): oShapes.remove(oShape) delCount += 1 c -= 1 return delCount def getShapes(dims): dimlen = len(dims) dimlen0 = len(dims[0]) pyShapes = [tuple([int(dims[i][0]) if type(dims[i][0]) == float else 0] + [dims[i][j] if j < dimlen0 else 0 for j in range(1,7)]) for i in range(dimlen)] return pyShapes def createInstance( ctx ): return PyDrawImpl( ctx ) g_ImplementationHelper = unohelper.ImplementationHelper() g_ImplementationHelper.addImplementation( createInstance,"com.pydraw.python.PyDrawImpl", ("com.sun.star.sheet.AddIn",),)