#*************************************************************************** #* Copyright (c) 2015 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * #* as published by the Free Software Foundation; either version 2 of * #* the License, or (at your option) any later version. * #* for detail see the LICENCE text file. * #* * #* This program is distributed in the hope that it will be useful, * #* but WITHOUT ANY WARRANTY; without even the implied warranty of * #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * #* GNU Library General Public License for more details. * #* * #* You should have received a copy of the GNU Library General Public * #* License along with this program; if not, write to the Free Software * #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * #* USA * #* * #*************************************************************************** import FreeCAD if FreeCAD.GuiUp: import FreeCADGui, Arch_rc, os from PySide import QtCore, QtGui from DraftTools import translate from PySide.QtCore import QT_TRANSLATE_NOOP else: # \cond def translate(ctxt,txt): return txt def QT_TRANSLATE_NOOP(ctxt,txt): return txt # \endcond __title__ = "Arch Material Management" __author__ = "Yorik van Havre" __url__ = "http://www.freecadweb.org" ## @package ArchMaterial # \ingroup ARCH # \brief The Material object and tools # # This module provides tools to add materials to # Arch objects def makeMaterial(name="Material",color=None,transparency=None): '''makeMaterial(name): makes an Material object''' if not FreeCAD.ActiveDocument: FreeCAD.Console.PrintError("No active document. Aborting\n") return obj = FreeCAD.ActiveDocument.addObject("App::MaterialObjectPython",name) obj.Label = name _ArchMaterial(obj) if FreeCAD.GuiUp: _ViewProviderArchMaterial(obj.ViewObject) getMaterialContainer().addObject(obj) if color: obj.Color = color[:3] if len(color) > 3: obj.Transparency = color[3]*100 if transparency: obj.Transparency = transparency return obj def getMaterialContainer(): '''getMaterialContainer(): returns a group object to put materials in''' for obj in FreeCAD.ActiveDocument.Objects: if obj.Name == "MaterialContainer": return obj obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython","MaterialContainer") obj.Label = "Materials" _ArchMaterialContainer(obj) if FreeCAD.GuiUp: _ViewProviderArchMaterialContainer(obj.ViewObject) return obj def makeMultiMaterial(name="MultiMaterial"): '''makeMultiMaterial(name): makes an Material object''' obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",name) obj.Label = name _ArchMultiMaterial(obj) if FreeCAD.GuiUp: _ViewProviderArchMultiMaterial(obj.ViewObject) getMaterialContainer().addObject(obj) return obj def getDocumentMaterials(): '''getDocumentMaterials(): returns all the arch materials of the document''' for obj in FreeCAD.ActiveDocument.Objects: if obj.Name == "MaterialContainer": mats = [] for o in obj.Group: if o.isDerivedFrom("App::MaterialObjectPython"): mats.append(o) return mats return [] class _CommandArchMaterial: "the Arch Material command definition" def GetResources(self): return {'Pixmap': 'Arch_Material_Group', 'MenuText': QT_TRANSLATE_NOOP("Arch_Material","Material"), 'Accel': "M, T", 'ToolTip': QT_TRANSLATE_NOOP("Arch_Material","Creates or edits the material definition of a selected object.")} def Activated(self): sel = FreeCADGui.Selection.getSelection() FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create material")) FreeCADGui.addModule("Arch") FreeCADGui.Control.closeDialog() FreeCADGui.doCommand("mat = Arch.makeMaterial()") for obj in sel: if hasattr(obj,"Material"): FreeCADGui.doCommand("FreeCAD.ActiveDocument.getObject(\""+obj.Name+"\").Material = mat") FreeCADGui.doCommandGui("mat.ViewObject.Document.setEdit(mat.ViewObject, 0)") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False class _CommandArchMultiMaterial: "the Arch MultiMaterial command definition" def GetResources(self): return {'Pixmap': 'Arch_Material_Multi', 'MenuText': QT_TRANSLATE_NOOP("Arch_MultiMaterial","Multi-Material"), 'Accel': "M, T", 'ToolTip': QT_TRANSLATE_NOOP("Arch_MultiMaterial","Creates or edits multi-materials")} def Activated(self): sel = FreeCADGui.Selection.getSelection() FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create multi-material")) FreeCADGui.addModule("Arch") FreeCADGui.Control.closeDialog() FreeCADGui.doCommand("mat = Arch.makeMultiMaterial()") for obj in sel: if hasattr(obj,"Material"): if not obj.isDerivedFrom("App::MaterialObject"): FreeCADGui.doCommand("FreeCAD.ActiveDocument."+obj.Name+".Material = mat") FreeCADGui.doCommandGui("mat.ViewObject.Document.setEdit(mat.ViewObject, 0)") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False class _ArchMaterialContainer: "The Material Container" def __init__(self,obj): self.Type = "MaterialContainer" obj.Proxy = self def execute(self,obj): return def __getstate__(self): if hasattr(self,"Type"): return self.Type def __setstate__(self,state): if state: self.Type = state class _ViewProviderArchMaterialContainer: "A View Provider for the Material Container" def __init__(self,vobj): vobj.Proxy = self def getIcon(self): return ":/icons/Arch_Material_Group.svg" def attach(self,vobj): self.Object = vobj.Object def setupContextMenu(self,vobj,menu): from PySide import QtCore,QtGui action1 = QtGui.QAction(QtGui.QIcon(":/icons/Arch_Material_Group.svg"),"Merge duplicates",menu) QtCore.QObject.connect(action1,QtCore.SIGNAL("triggered()"),self.mergeByName) menu.addAction(action1) action2 = QtGui.QAction(QtGui.QIcon(),"Reorder children alphabetically",menu) QtCore.QObject.connect(action2,QtCore.SIGNAL("triggered()"),self.reorder) menu.addAction(action2) def mergeByName(self): if hasattr(self,"Object"): mats = [o for o in self.Object.Group if o.isDerivedFrom("App::MaterialObject")] todelete = [] for mat in mats: orig = None for om in mats: if om.Label == mat.Label: orig = om break else: if mat.Label[-1].isdigit() and mat.Label[-2].isdigit() and mat.Label[-3].isdigit(): for om in mats: if om.Label == mat.Label[:-3].strip(): orig = om break if orig: for par in mat.InList: for prop in par.PropertiesList: if getattr(par,prop) == mat: FreeCAD.Console.PrintMessage("Changed property '"+prop+"' of object "+par.Label+" from "+mat.Label+" to "+orig.Label+"\n") setattr(par,prop,orig) todelete.append(mat) for tod in todelete: if not tod.InList: FreeCAD.Console.PrintMessage("Merging duplicate material "+tod.Label+"\n") FreeCAD.ActiveDocument.removeObject(tod.Name) elif (len(tod.InList) == 1) and (tod.InList[0].isDerivedFrom("App::DocumentObjectGroup")): FreeCAD.Console.PrintMessage("Merging duplicate material "+tod.Label+"\n") FreeCAD.ActiveDocument.removeObject(tod.Name) else: FreeCAD.Console.PrintMessage("Unable to delete material "+tod.Label+": InList not empty\n") def reorder(self): if hasattr(self,"Object"): if hasattr(self.Object,"Group") and self.Object.Group: g = self.Object.Group g.sort(key=lambda obj: obj.Label) self.Object.Group = g FreeCAD.ActiveDocument.recompute() def __getstate__(self): return None def __setstate__(self,state): return None class _ArchMaterial: "The Material object" def __init__(self,obj): self.Type = "Material" obj.Proxy = self obj.addProperty("App::PropertyString","Description","Arch",QT_TRANSLATE_NOOP("App::Property","A description for this material")) obj.addProperty("App::PropertyString","StandardCode","Arch",QT_TRANSLATE_NOOP("App::Property","A standard code (MasterFormat, OmniClass,...)")) obj.addProperty("App::PropertyString","ProductURL","Arch",QT_TRANSLATE_NOOP("App::Property","A URL where to find information about this material")) obj.addProperty("App::PropertyPercent","Transparency","Arch",QT_TRANSLATE_NOOP("App::Property","The transparency value of this material")) obj.addProperty("App::PropertyColor","Color","Arch",QT_TRANSLATE_NOOP("App::Property","The color of this material")) def isSameColor(self,c1,c2): r = 4 if round(c1[0],r) == round(c2[0],r): if round(c1[1],r) == round(c2[1],r): if round(c1[2],r) == round(c2[2],r): return True return False def onChanged(self,obj,prop): d = obj.Material if prop == "Material": if "DiffuseColor" in obj.Material: c = tuple([float(f) for f in obj.Material['DiffuseColor'].strip("()").strip("[]").split(",")]) if hasattr(obj,"Color"): if not self.isSameColor(obj.Color,c): obj.Color = c if "Transparency" in obj.Material: t = int(obj.Material['Transparency']) if hasattr(obj,"Transparency"): if obj.Transparency != t: obj.Transparency = t if "ProductURL" in obj.Material: if hasattr(obj,"ProductURL"): if obj.ProductURL != obj.Material["ProductURL"]: obj.ProductURL = obj.Material["ProductURL"] if "StandardCode" in obj.Material: if hasattr(obj,"StandardCode"): if obj.StandardCode != obj.Material["StandardCode"]: obj.StandardCode = obj.Material["StandardCode"] if "Description" in obj.Material: if hasattr(obj,"Description"): if obj.Description != obj.Material["Description"]: obj.Description = obj.Material["Description"] if "Name" in obj.Material: if hasattr(obj,"Label"): if obj.Label != obj.Material["Name"]: obj.Label = obj.Material["Name"] elif prop == "Label": if "Name" in d: if d["Name"] == obj.Label: return d["Name"] = obj.Label elif prop == "Color": if hasattr(obj,"Color"): if "DiffuseColor" in d: if self.isSameColor(tuple([float(f) for f in d['DiffuseColor'].strip("()").strip("[]").split(",")]),obj.Color[:3]): return d["DiffuseColor"] = str(obj.Color[:3]) elif prop == "Transparency": if hasattr(obj,"Transparency"): val = str(obj.Transparency) if "Transparency" in d: if d["Transparency"] == val: return d["Transparency"] = val elif prop == "ProductURL": if hasattr(obj,"ProductURL"): val = obj.ProductURL if "ProductURL" in d: if d["ProductURL"] == val: return obj.Material["ProductURL"] = val elif prop == "StandardCode": if hasattr(obj,"StandardCode"): val = obj.StandardCode if "StandardCode" in d: if d["StandardCode"] == val: return d["StandardCode"] = val elif prop == "Description": if hasattr(obj,"Description"): val = obj.Description if "Description" in d: if d["Description"] == val: return d["Description"] = val if d and (d != obj.Material): obj.Material = d #if FreeCAD.GuiUp: #import FreeCADGui # not sure why this is needed, but it is... #FreeCADGui.ActiveDocument.resetEdit() def execute(self,obj): if obj.Material: if FreeCAD.GuiUp: if "DiffuseColor" in obj.Material: c = tuple([float(f) for f in obj.Material['DiffuseColor'].strip("()").strip("[]").split(",")]) for p in obj.InList: if hasattr(p,"Material") and ( (not hasattr(p.ViewObject,"UseMaterialColor")) or p.ViewObject.UseMaterialColor): if p.Material.Name == obj.Name: p.ViewObject.ShapeColor = c return def __getstate__(self): if hasattr(self,"Type"): return self.Type def __setstate__(self,state): if state: self.Type = state class _ViewProviderArchMaterial: "A View Provider for the Material object" def __init__(self,vobj): vobj.Proxy = self def getIcon(self): if hasattr(self,"icondata"): return self.icondata return ":/icons/Arch_Material.svg" def attach(self, vobj): self.Object = vobj.Object return def updateData(self, obj, prop): if prop == "Color": from PySide import QtCore,QtGui # custom icon if hasattr(obj,"Color"): c = obj.Color matcolor = QtGui.QColor(int(c[0]*255),int(c[1]*255),int(c[2]*255)) darkcolor = QtGui.QColor(int(c[0]*125),int(c[1]*125),int(c[2]*125)) im = QtGui.QImage(48,48,QtGui.QImage.Format_ARGB32) im.fill(QtCore.Qt.transparent) pt = QtGui.QPainter(im) pt.setPen(QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, QtCore.Qt.FlatCap)) #pt.setBrush(QtGui.QBrush(matcolor, QtCore.Qt.SolidPattern)) gradient = QtGui.QLinearGradient(0,0,48,48) gradient.setColorAt(0,matcolor) gradient.setColorAt(1,darkcolor) pt.setBrush(QtGui.QBrush(gradient)) pt.drawEllipse(6,6,36,36) pt.setPen(QtGui.QPen(QtCore.Qt.white, 1, QtCore.Qt.SolidLine, QtCore.Qt.FlatCap)) pt.setBrush(QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern)) pt.drawEllipse(12,12,12,12) pt.end() ba = QtCore.QByteArray() b = QtCore.QBuffer(ba) b.open(QtCore.QIODevice.WriteOnly) im.save(b,"XPM") self.icondata = ba.data().decode("latin1") def onChanged(self, vobj, prop): if prop == "Material": if "Father" in vobj.Object.Material: for o in FreeCAD.ActiveDocument.Objects: if o.isDerivedFrom("App::MaterialObject"): if o.Label == vobj.Object.Material["Father"]: o.touch() def setEdit(self,vobj,mode): self.taskd = _ArchMaterialTaskPanel(vobj.Object) FreeCADGui.Control.showDialog(self.taskd) self.taskd.form.FieldName.setFocus() self.taskd.form.FieldName.selectAll() return True def unsetEdit(self,vobj,mode): FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() if hasattr(self,"taskd"): del self.taskd return def setTaskValue(self,widgetname,value): if hasattr(self,"taskd"): if hasattr(self.taskd,"form"): if hasattr(self.taskd.form,widgetname): widget = getattr(self.taskd.form,widgetname) if hasattr(widget,"setText"): widget.setText(value) elif hasattr(widget,"setValue"): widget.setText(value) def __getstate__(self): return None def __setstate__(self,state): return None def claimChildren(self): ch = [] if hasattr(self,"Object"): for o in self.Object.Document.Objects: if o.isDerivedFrom("App::MaterialObject"): if o.Material: if "Father" in o.Material: if o.Material["Father"] == self.Object.Label: ch.append(o) return ch class _ArchMaterialTaskPanel: '''The editmode TaskPanel for Arch Material objects''' def __init__(self,obj=None): self.cards = None self.existingmaterials = [] self.obj = obj self.form = FreeCADGui.PySideUic.loadUi(":/ui/ArchMaterial.ui") self.color = QtGui.QColor(128,128,128) colorPix = QtGui.QPixmap(16,16) colorPix.fill(self.color) self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix)) self.form.ButtonUrl.setIcon(QtGui.QIcon(":/icons/internet-web-browser.svg")) QtCore.QObject.connect(self.form.comboBox_MaterialsInDir, QtCore.SIGNAL("currentIndexChanged(QString)"), self.chooseMat) QtCore.QObject.connect(self.form.comboBox_FromExisting, QtCore.SIGNAL("currentIndexChanged(int)"), self.fromExisting) QtCore.QObject.connect(self.form.comboFather, QtCore.SIGNAL("currentIndexChanged(QString)"), self.setFather) QtCore.QObject.connect(self.form.comboFather, QtCore.SIGNAL("currentTextChanged(QString)"), self.setFather) QtCore.QObject.connect(self.form.ButtonColor,QtCore.SIGNAL("pressed()"),self.getColor) QtCore.QObject.connect(self.form.ButtonUrl,QtCore.SIGNAL("pressed()"),self.openUrl) QtCore.QObject.connect(self.form.ButtonEditor,QtCore.SIGNAL("pressed()"),self.openEditor) QtCore.QObject.connect(self.form.ButtonCode,QtCore.SIGNAL("pressed()"),self.getCode) self.fillMaterialCombo() self.fillExistingCombo() try: import BimClassification except: self.form.ButtonCode.hide() else: import os self.form.ButtonCode.setIcon(QtGui.QIcon(os.path.join(os.path.dirname(BimClassification.__file__),"icons","BIM_Classification.svg"))) if self.obj: if hasattr(self.obj,"Material"): self.material = self.obj.Material self.setFields() def setFields(self): "sets the task box contents from self.material" if 'Name' in self.material: self.form.FieldName.setText(self.material['Name']) elif self.obj: self.form.FieldName.setText(self.obj.Label) if 'Description' in self.material: self.form.FieldDescription.setText(self.material['Description']) col = None if 'DiffuseColor' in self.material: col = self.material["DiffuseColor"] elif 'ViewColor' in self.material: col = self.material["ViewColor"] elif 'Color' in self.material: col = self.material["Color"] if col: if "(" in col: c = tuple([float(f) for f in col.strip("()").split(",")]) self.color = QtGui.QColor() self.color.setRgbF(c[0],c[1],c[2]) colorPix = QtGui.QPixmap(16,16) colorPix.fill(self.color) self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix)) if 'StandardCode' in self.material: self.form.FieldCode.setText(self.material['StandardCode']) if 'ProductURL' in self.material: self.form.FieldUrl.setText(self.material['ProductURL']) if 'Transparency' in self.material: self.form.SpinBox_Transparency.setValue(int(self.material["Transparency"])) if "Father" in self.material: father = self.material["Father"] else: father = None found = False self.form.comboFather.addItem("None") for o in FreeCAD.ActiveDocument.Objects: if o.isDerivedFrom("App::MaterialObject"): if o != self.obj: self.form.comboFather.addItem(o.Label) if o.Label == father: self.form.comboFather.setCurrentIndex(self.form.comboFather.count()-1) found = True if father and not found: self.form.comboFather.addItem(father) self.form.comboFather.setCurrentIndex(self.form.comboFather.count()-1) def getFields(self): "sets self.material from the contents of the task box" self.material['Name'] = self.form.FieldName.text() self.material['Description'] = self.form.FieldDescription.text() self.material['DiffuseColor'] = str(self.color.getRgbF()[:3]) self.material['ViewColor'] = self.material['DiffuseColor'] self.material['Color'] = self.material['DiffuseColor'] self.material['StandardCode'] = self.form.FieldCode.text() self.material['ProductURL'] = self.form.FieldUrl.text() self.material['Transparency'] = str(self.form.SpinBox_Transparency.value()) def accept(self): self.getFields() if self.obj: if hasattr(self.obj,"Material"): self.obj.Material = self.material self.obj.Label = self.material['Name'] FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() def chooseMat(self, card): "sets self.material from a card" if card in self.cards: import importFCMat self.material = importFCMat.read(self.cards[card]) self.setFields() def fromExisting(self,index): "sets the contents from an existing material" if index > 0: if index <= len(self.existingmaterials): m = self.existingmaterials[index-1] if m.Material: self.material = m.Material self.setFields() def setFather(self,text): "sets the father" if text: if text != "None": self.material["Father"] = text def getColor(self): "opens a color picker dialog" self.color = QtGui.QColorDialog.getColor() colorPix = QtGui.QPixmap(16,16) colorPix.fill(self.color) self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix)) def fillMaterialCombo(self): "fills the combo with the existing FCMat cards" # look for cards in both resources dir and a Materials sub-folder in the user folder. # User cards with same name will override system cards paths = [FreeCAD.getResourceDir() + os.sep + "Mod" + os.sep + "Material" + os.sep + "StandardMaterial"] ap = FreeCAD.ConfigGet("UserAppData") + os.sep + "Materials" if os.path.exists(ap): paths.append(ap) self.cards = {} for p in paths: for f in os.listdir(p): b,e = os.path.splitext(f) if e.upper() == ".FCMAT": self.cards[b] = p + os.sep + f if self.cards: for k in sorted(self.cards.keys()): self.form.comboBox_MaterialsInDir.addItem(k) def fillExistingCombo(self): "fills the existing materials combo" self.existingmaterials = [] for obj in FreeCAD.ActiveDocument.Objects: if obj.isDerivedFrom("App::MaterialObject"): if obj != self.obj: self.existingmaterials.append(obj) for m in self.existingmaterials: self.form.comboBox_FromExisting.addItem(m.Label) def openEditor(self): "opens the full material editor from the material module" self.getFields() if self.material: import MaterialEditor self.material = MaterialEditor.editMaterial(self.material) self.setFields() def openUrl(self): self.getFields() if self.material: if 'ProductURL' in self.material: QtGui.QDesktopServices.openUrl(self.material['ProductURL']) def getCode(self): FreeCADGui.Selection.addSelection(self.obj) FreeCADGui.runCommand("BIM_Classification") class _ArchMultiMaterial: "The MultiMaterial object" def __init__(self,obj): self.Type = "MultiMaterial" obj.Proxy = self obj.addProperty("App::PropertyString","Description","Arch",QT_TRANSLATE_NOOP("App::Property","A description for this material")) obj.addProperty("App::PropertyStringList","Names","Arch",QT_TRANSLATE_NOOP("App::Property","The list of layer names")) obj.addProperty("App::PropertyLinkList","Materials","Arch",QT_TRANSLATE_NOOP("App::Property","The list of layer materials")) obj.addProperty("App::PropertyFloatList","Thicknesses","Arch",QT_TRANSLATE_NOOP("App::Property","The list of layer thicknesses")) def __getstate__(self): if hasattr(self,"Type"): return self.Type def __setstate__(self,state): if state: self.Type = state class _ViewProviderArchMultiMaterial: "A View Provider for the MultiMaterial object" def __init__(self,vobj): vobj.Proxy = self def getIcon(self): return ":/icons/Arch_Material_Multi.svg" def setEdit(self,vobj,mode=0): taskd = _ArchMultiMaterialTaskPanel(vobj.Object) FreeCADGui.Control.showDialog(taskd) return True def unsetEdit(self,vobj,mode=0): FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() return True def __getstate__(self): return None def __setstate__(self,state): return None def doubleClicked(self,vobj): self.setEdit(vobj) def isShow(self): return True if FreeCAD.GuiUp: class MultiMaterialDelegate(QtGui.QStyledItemDelegate): def __init__(self, parent=None, *args): self.mats = [] for obj in FreeCAD.ActiveDocument.Objects: if obj.isDerivedFrom("App::MaterialObject"): self.mats.append(obj) QtGui.QStyledItemDelegate.__init__(self, parent, *args) def createEditor(self,parent,option,index): if index.column() == 0: editor = QtGui.QComboBox(parent) editor.setEditable(True) elif index.column() == 1: editor = QtGui.QComboBox(parent) elif index.column() == 2: ui = FreeCADGui.UiLoader() editor = ui.createWidget("Gui::InputField") editor.setSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Minimum) editor.setParent(parent) else: editor = QtGui.QLineEdit(parent) return editor def setEditorData(self, editor, index): if index.column() == 0: import ArchWindow editor.addItems([index.data()]+ArchWindow.WindowPartTypes) elif index.column() == 1: idx = -1 for i,m in enumerate(self.mats): editor.addItem(m.Label) if m.Label == index.data(): idx = i editor.setCurrentIndex(idx) else: QtGui.QStyledItemDelegate.setEditorData(self, editor, index) def setModelData(self, editor, model, index): if index.column() == 0: if editor.currentIndex() == -1: model.setData(index, "") else: model.setData(index, editor.currentText()) elif index.column() == 1: if editor.currentIndex() == -1: model.setData(index, "") else: model.setData(index, self.mats[editor.currentIndex()].Label) else: QtGui.QStyledItemDelegate.setModelData(self, editor, model, index) class _ArchMultiMaterialTaskPanel: '''The editmode TaskPanel for MultiMaterial objects''' def __init__(self,obj=None): self.obj = obj self.form = FreeCADGui.PySideUic.loadUi(":/ui/ArchMultiMaterial.ui") self.model = QtGui.QStandardItemModel() self.model.setHorizontalHeaderLabels([translate("Arch","Name"),translate("Arch","Material"),translate("Arch","Thickness")]) self.form.tree.setModel(self.model) self.form.tree.setUniformRowHeights(True) self.form.tree.setItemDelegate(MultiMaterialDelegate()) QtCore.QObject.connect(self.form.chooseCombo, QtCore.SIGNAL("currentIndexChanged(int)"), self.fromExisting) QtCore.QObject.connect(self.form.addButton,QtCore.SIGNAL("pressed()"),self.addLayer) QtCore.QObject.connect(self.form.upButton,QtCore.SIGNAL("pressed()"),self.upLayer) QtCore.QObject.connect(self.form.downButton,QtCore.SIGNAL("pressed()"),self.downLayer) QtCore.QObject.connect(self.form.delButton,QtCore.SIGNAL("pressed()"),self.delLayer) QtCore.QObject.connect(self.form.invertButton,QtCore.SIGNAL("pressed()"),self.invertLayer) QtCore.QObject.connect(self.model,QtCore.SIGNAL("itemChanged(QStandardItem*)"),self.recalcThickness) self.fillExistingCombo() self.fillData() def fillData(self,obj=None): if not obj: obj = self.obj if obj: self.model.clear() self.model.setHorizontalHeaderLabels([translate("Arch","Name"),translate("Arch","Material"),translate("Arch","Thickness")]) # restore widths p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") self.form.tree.setColumnWidth(0,p.GetInt("MultiMaterialColumnWidth0",60)) self.form.tree.setColumnWidth(1,p.GetInt("MultiMaterialColumnWidth1",60)) for i in range(len(obj.Names)): item1 = QtGui.QStandardItem(obj.Names[i]) item2 = QtGui.QStandardItem(obj.Materials[i].Label) item3 = QtGui.QStandardItem(FreeCAD.Units.Quantity(obj.Thicknesses[i],FreeCAD.Units.Length).getUserPreferred()[0]) self.model.appendRow([item1,item2,item3]) self.form.nameField.setText(obj.Label) def fillExistingCombo(self): "fills the existing multimaterials combo" import Draft self.existingmaterials = [] for obj in FreeCAD.ActiveDocument.Objects: if Draft.getType(obj) == "MultiMaterial": if obj != self.obj: self.existingmaterials.append(obj) for m in self.existingmaterials: self.form.chooseCombo.addItem(m.Label) def fromExisting(self,index): "sets the contents from an existing material" if index > 0: if index <= len(self.existingmaterials): m = self.existingmaterials[index-1] if m: self.fillData(m) def addLayer(self): item1 = QtGui.QStandardItem(translate("Arch","New layer")) item2 = QtGui.QStandardItem() item3 = QtGui.QStandardItem() self.model.appendRow([item1,item2,item3]) def delLayer(self): sel = self.form.tree.selectedIndexes() if sel: row = sel[0].row() if row >= 0: self.model.takeRow(row) self.recalcThickness() def moveLayer(self,mvt=0): sel = self.form.tree.selectedIndexes() if sel and mvt: row = sel[0].row() if row >= 0: if row+mvt >= 0: data = self.model.takeRow(row) self.model.insertRow(row+mvt,data) ind = self.model.index(row+mvt,0) self.form.tree.setCurrentIndex(ind) def upLayer(self): self.moveLayer(mvt=-1) def downLayer(self): self.moveLayer(mvt=1) def invertLayer(self): items = [self.model.takeRow(row) for row in range(self.model.rowCount()-1,-1,-1)] items.reverse() for item in items: self.model.insertRow(0,item) def recalcThickness(self,item=None): prefix = translate("Arch","Total thickness")+": " th = 0 suffix = "" for row in range(self.model.rowCount()): thick = 0 d = self.model.item(row,2).text() try: d = float(d) except: thick = FreeCAD.Units.Quantity(d).Value else: thick = FreeCAD.Units.Quantity(d,FreeCAD.Units.Length).Value th += abs(thick) if not thick: suffix = " ("+translate("Arch","depends on the object")+")" val = FreeCAD.Units.Quantity(th,FreeCAD.Units.Length).UserString self.form.labelTotalThickness.setText(prefix + val + suffix) def accept(self): # store widths p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") p.SetInt("MultiMaterialColumnWidth0",self.form.tree.columnWidth(0)) p.SetInt("MultiMaterialColumnWidth1",self.form.tree.columnWidth(1)) if self.obj: mats = [] for m in FreeCAD.ActiveDocument.Objects: if m.isDerivedFrom("App::MaterialObject"): mats.append(m) names = [] materials = [] thicknesses = [] for row in range(self.model.rowCount()): name = self.model.item(row,0).text() mat = None ml = self.model.item(row,1).text() for m in mats: if m.Label == ml: mat = m d = self.model.item(row,2).text() try: d = float(d) except: thick = FreeCAD.Units.Quantity(d).Value else: thick = FreeCAD.Units.Quantity(d,FreeCAD.Units.Length).Value if round(thick,32) == 0: thick = 0.0 if name and mat: names.append(name) materials.append(mat) thicknesses.append(thick) self.obj.Names = names self.obj.Materials = materials self.obj.Thicknesses = thicknesses if self.form.nameField.text(): self.obj.Label = self.form.nameField.text() FreeCAD.ActiveDocument.recompute() return True if FreeCAD.GuiUp: FreeCADGui.addCommand('Arch_Material',_CommandArchMaterial()) FreeCADGui.addCommand('Arch_MultiMaterial',_CommandArchMultiMaterial()) class _ArchMaterialToolsCommand: def GetCommands(self): return tuple(['Arch_Material','Arch_MultiMaterial']) def GetResources(self): return { 'MenuText': QT_TRANSLATE_NOOP("Arch_MaterialTools",'Material tools'), 'ToolTip': QT_TRANSLATE_NOOP("Arch_MaterialTools",'Material tools') } def IsActive(self): return not FreeCAD.ActiveDocument is None FreeCADGui.addCommand('Arch_MaterialTools', _ArchMaterialToolsCommand())