diff --git a/src/Mod/Drawing/DrawingPatterns.py b/src/Mod/Drawing/DrawingPatterns.py index 1fe00ac95..97ef5b929 100644 --- a/src/Mod/Drawing/DrawingPatterns.py +++ b/src/Mod/Drawing/DrawingPatterns.py @@ -138,9 +138,10 @@ def buildPattern(name,scale=5,thickness=1,color="#000000"): """buildPattern(name,scale=5,thickness=1,color="#000000") builds an SVG fragment from a name and path data""" + name,scale,thickness = decodeName(name,scale,thickness) if not (name in Patterns.keys()): return None - pname = name + "_" + str(scale) + "_" + str(thickness) + pname = name + "_" + str(scale).replace(".","") + "_" + str(thickness).replace(".","") data = Patterns[name] template=''' @@ -155,25 +156,74 @@ def buildPattern(name,scale=5,thickness=1,color="#000000"): return t -def buildTextureImage(name,scale,thickness,color="#000000",size=64): +def buildTextureImage(name,scale=5,thickness=1,color="#000000",size=64): """buildTextureImage(name,scale,thickness,color="#000000",size=64) builds a 64x64 SVG image filled with the given texture""" + name,scale,thickness = decodeName(name,scale,thickness) + if not (name in Patterns.keys()): + return None s = str(size) template = '''$pattern''' - if not (name in Patterns.keys()): - return None pat = buildPattern(name,scale,thickness,color) t = template.replace("\n","") t = t.replace("$pattern",pat+"\n") - t = t.replace("$name",name+"_"+str(scale)+"_"+str(thickness)) + t = t.replace("$name",name+"_"+str(scale).replace(".","")+"_"+str(thickness).replace(".","")) return t +def buildSwatch(name,scale=5,thickness=1,color="#000000",size=64): + + """buildSwatch(name,scale,thickness,color="#000000",size=64) + builds a 64x64 SVG image filled with the given texture, a + white background and a border, to serve as a sample""" + + name,scale,thickness = decodeName(name,scale,thickness) + if not (name in Patterns.keys()): + return None + s = str(size) + template = '''$pattern''' + pat = buildPattern(name,scale,thickness,color) + t = template.replace("\n","") + t = t.replace("$pattern",pat+"\n") + t = t.replace("$name",name+"_"+str(scale).replace(".","")+"_"+str(thickness).replace(".","")) + return t + + +def buildFileSwatch(name,scale=5,thickness=1,color="#000000",size=64,png=False): + + """buildFileSwatch(name,scale,thickness,color="#000000",size=64,png=False) + builds a 64x64 SVG image filled with the given texture, a + white background and a border, to serve as a sample. The image + is saved as a temp file, the filepath is returned""" + s = buildSwatch(name,scale,thickness,color,size) + if s: + import tempfile + tf = tempfile.mkstemp(suffix=".svg")[1] + f = open(tf,"wb") + f.write(s) + f.close() + if png: + # we use imagemagick's convert because Qt4 doesn't support SVG patterns... + import os + if os.system("convert -version") == 0: + ptf = os.path.splitext(tf)[0]+".png" + os.system('convert "'+tf+'" "'+ptf+'"') + return ptf + else: + return tf + return None + + def saveTestImage(filename,scales=[2.5,5],thicknesses=[0.1,0.2,1]): """saveTestImage(filename,scales=[2.5,5],thicknesses=[0.1,0.2,1]) @@ -212,6 +262,24 @@ def saveTestImage(filename,scales=[2.5,5],thicknesses=[0.1,0.2,1]): f = open(filename,"wb") f.write(t) f.close() + + +def decodeName(name,scale,thickness): + + """decodeName(name,scale,thickness) : decodes names written in the form 'name_5_1'""" + + name = name.split("_") + if len(name) > 1: + try: + scale = float(name[1]) + except: + pass + if len(name) > 2: + try: + thickness = float(name[2]) + except: + pass + return name[0],scale,thickness def getPatternNames(): diff --git a/src/Mod/Material/MaterialEditor.py b/src/Mod/Material/MaterialEditor.py index e6533fd13..23c905acd 100644 --- a/src/Mod/Material/MaterialEditor.py +++ b/src/Mod/Material/MaterialEditor.py @@ -21,7 +21,7 @@ #*************************************************************************** import FreeCAD, FreeCADGui, os -from PySide import QtCore, QtGui, QtUiTools +from PySide import QtCore, QtGui, QtUiTools, QtSvg __title__="FreeCAD material editor" __author__ = "Yorik van Havre" @@ -30,6 +30,7 @@ __url__ = "http://www.freecadweb.org" class MaterialEditor: + def __init__(self, obj = None, prop = None, material = None): """Initializes, optionally with an object name and a material property name to edit, or directly with a material dictionary.""" @@ -58,6 +59,7 @@ class MaterialEditor: QtCore.QObject.connect(self.widget.EditProperty, QtCore.SIGNAL("returnPressed()"), self.addCustomProperty) QtCore.QObject.connect(self.widget.ButtonDeleteProperty, QtCore.SIGNAL("clicked()"), self.deleteCustomProperty) QtCore.QObject.connect(self.widget.Editor, QtCore.SIGNAL("itemDoubleClicked(QTreeWidgetItem*,int)"), self.itemClicked) + QtCore.QObject.connect(self.widget.Editor, QtCore.SIGNAL("itemChanged(QTreeWidgetItem*,int)"), self.itemChanged) QtCore.QObject.connect(self.widget.Editor, QtCore.SIGNAL("currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)"), self.checkDeletable) QtCore.QObject.connect(self.widget.ButtonOpen, QtCore.SIGNAL("clicked()"), self.openfile) QtCore.QObject.connect(self.widget.ButtonSave, QtCore.SIGNAL("clicked()"), self.savefile) @@ -67,8 +69,7 @@ class MaterialEditor: d = FreeCAD.ActiveDocument.getObject(self.obj).getPropertyByName(self.prop) elif self.material: d = self.material - if d: - self.updateContents(d) + def updateCards(self): "updates the contents of the materials combo with existing material cards" @@ -90,6 +91,7 @@ class MaterialEditor: for k,i in self.cards.items(): self.widget.ComboMaterial.addItem(k) + def updateContents(self,data): "updates the contents of the editor with the given data (can be the name of a card or a dictionary)" #print type(data) @@ -112,12 +114,14 @@ class MaterialEditor: if d: self.updateContents(d) + def openProductURL(self): "opens the contents of the ProductURL field in an external browser" url = str(self.widget.Editor.findItems(translate("Material","Product URL"),QtCore.Qt.MatchRecursive,0)[0].text(1)) if url: QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode)) + def accept(self): "if we are editing a property, set the property values" if self.prop and self.obj: @@ -125,10 +129,12 @@ class MaterialEditor: o = FreeCAD.ActiveDocument.getObject(self.obj) setattr(o,self.prop,d) QtGui.QDialog.accept(self.widget) - + + def reject(self): QtGui.QDialog.reject(self.widget) - + + def expandKey(self, key): "adds spaces before caps in a KeyName" nk = "" @@ -141,6 +147,7 @@ class MaterialEditor: nk += l return nk + def collapseKey(self, key): "removes the spaces in a Key Name" nk = "" @@ -148,7 +155,8 @@ class MaterialEditor: if l != " ": nk += l return nk - + + def clearEditor(self): "Clears the contents of the editor" for i1 in range(self.widget.Editor.topLevelItemCount()): @@ -158,7 +166,8 @@ class MaterialEditor: c.setText(1,"") for k in self.customprops: self.deleteCustomProperty(k) - + + def addCustomProperty(self, key = None, value = None): "Adds a custom property to the editor, optionally with a value" if not key: @@ -175,7 +184,8 @@ class MaterialEditor: self.widget.EditProperty.setText("") if value: i.setText(1,value) - + + def deleteCustomProperty(self, key = None): "Deletes a custom property from the editor" if not key: @@ -191,19 +201,29 @@ class MaterialEditor: if ii >= 0: top.takeChild(ii) self.customprops.remove(key) - + + def itemClicked(self, item, column): "Edits an item if it is not in the first column" if column > 0: self.widget.Editor.editItem(item, column) + + def itemChanged(self, item, column): + "Handles text changes" + if item.text(0) == "Section Fill Pattern": + if column == 1: + self.setTexture(item.text(1)) + + def checkDeletable(self,current,previous): "Checks if the current item is a custom property, if yes enable the delete button" if str(current.text(0)) in self.customprops: self.widget.ButtonDeleteProperty.setEnabled(True) else: self.widget.ButtonDeleteProperty.setEnabled(False) - + + def getDict(self): "returns a dictionnary from the contents of the editor" d = {} @@ -214,7 +234,28 @@ class MaterialEditor: # TODO the following should be translated back to english,since text(0) could be translated d[self.collapseKey(str(c.text(0)))] = unicode(c.text(1)) return d - + + + if d: + self.updateContents(d) + self.widget.Editor.topLevelItem(6).child(4).setToolTip(1,self.getPatternsList()) + + + def setTexture(self,pattern): + "displays a texture preview if needed" + self.widget.PreviewVector.hide() + if pattern: + try: + import DrawingPatterns + except: + print "DrawingPatterns not found" + else: + pattern = DrawingPatterns.buildFileSwatch(pattern,size=96,png=True) + if pattern: + self.widget.PreviewVector.setPixmap(QtGui.QPixmap(pattern)) + self.widget.PreviewVector.show() + + def openfile(self): "Opens a FCMat file" filename = QtGui.QFileDialog.getOpenFileName(QtGui.qApp.activeWindow(),'Open FreeCAD Material file','*.FCMat') @@ -224,7 +265,8 @@ class MaterialEditor: d = importFCMat.read(filename[0]) if d: self.updateContents(d) - + + def savefile(self): "Saves a FCMat file" name = str(self.widget.Editor.findItems(translate("Material","Name"),QtCore.Qt.MatchRecursive,0)[0].text(1)) @@ -237,22 +279,29 @@ class MaterialEditor: import importFCMat importFCMat.write(filename,d) + def show(self): return self.widget.show() - + + def exec_(self): return self.widget.exec_() + + + def translate(context,text): "translates text" return text #TODO use Qt translation mechanism here + def openEditor(obj = None, prop = None): """openEditor([obj,prop]): opens the editor, optionally with an object name and material property name to edit""" editor = MaterialEditor(obj,prop) editor.show() - + + def editMaterial(material): """editMaterial(material): opens the editor to edit the contents of the given material dictionary. Returns the modified material.""" diff --git a/src/Mod/Material/materials-editor.ui b/src/Mod/Material/materials-editor.ui index 020ccaf5d..de864a5c4 100644 --- a/src/Mod/Material/materials-editor.ui +++ b/src/Mod/Material/materials-editor.ui @@ -1,4 +1,4 @@ - + MaterialEditor @@ -6,7 +6,7 @@ 0 0 - 450 + 441 604 @@ -109,34 +109,28 @@ - + 96 96 - - - 96 - 96 - + + - + 96 96 - - - 96 - 96 - + +