diff --git a/src/Mod/Arch/Arch.py b/src/Mod/Arch/Arch.py index c06fdbb2658d..714894081c84 100644 --- a/src/Mod/Arch/Arch.py +++ b/src/Mod/Arch/Arch.py @@ -48,3 +48,4 @@ from ArchEquipment import * from ArchCutPlane import * from ArchServer import * +from ArchMaterial import * diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index d140a8dd64c4..9ccfeaf1a4fd 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -193,7 +193,7 @@ def removeComponents(objectsList,host=None): a.remove(o) h.Objects = a -def makeComponent(baseobj=None,name="Component"): +def makeComponent(baseobj=None,name="Component",delete=False): '''makeComponent([baseobj]): creates an undefined, non-parametric Arch component from the given base object''' obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) @@ -206,6 +206,8 @@ def makeComponent(baseobj=None,name="Component"): if baseobj.isDerivedFrom("Part::Feature"): obj.Shape = baseobj.Shape obj.Placement = baseobj.Placement + if delete: + FreeCAD.ActiveDocument.removeObject(baseobj.Name) elif isinstance(baseobj,Part.Shape): obj.Shape = baseobj return obj diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index a5f229ec71ac..921bebb03eb3 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -296,7 +296,7 @@ def __init__(self,obj): obj.addProperty("App::PropertyString","Description","Arch",translate("Arch","An optional description for this component")) obj.addProperty("App::PropertyString","Tag","Arch",translate("Arch","An optional tag for this component")) obj.addProperty("App::PropertyMap","IfcAttributes","Arch",translate("Arch","Custom IFC properties and attributes")) - obj.addProperty("App::PropertyMap","Material","Arch",translate("Arch","A material for this object")) + obj.addProperty("App::PropertyLink","BaseMaterial","Material",translate("Arch","A material for this object")) obj.addProperty("App::PropertyEnumeration","Role","Arch",translate("Arch","The role of this object")) obj.addProperty("App::PropertyBool","MoveWithHost","Arch",translate("Arch","Specifies if this object must move together when its host is moved")) obj.Proxy = self @@ -326,6 +326,9 @@ def clone(self,obj): pl = obj.Placement obj.Shape = obj.CloneOf.Shape.copy() obj.Placement = pl + if hasattr(obj,"BaseMaterial"): + if hasattr(obj.CloneOf,"BaseMaterial"): + obj.BaseMaterial = obj.CloneOf.BaseMaterial return True return False @@ -654,6 +657,13 @@ def __init__(self,vobj): self.Object = vobj.Object def updateData(self,obj,prop): + if prop == "BaseMaterial": + if obj.BaseMaterial: + if 'Color' in obj.BaseMaterial.Material: + if "(" in obj.BaseMaterial.Material['Color']: + c = tuple([float(f) for f in obj.BaseMaterial.Material['Color'].strip("()").split(",")]) + if obj.ViewObject: + obj.ViewObject.ShapeColor = c return def getIcon(self): diff --git a/src/Mod/Arch/ArchMaterial.py b/src/Mod/Arch/ArchMaterial.py new file mode 100644 index 000000000000..d6da24b24465 --- /dev/null +++ b/src/Mod/Arch/ArchMaterial.py @@ -0,0 +1,230 @@ +#*************************************************************************** +#* * +#* 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 + +__title__ = "Arch Material Managment" +__author__ = "Yorik van Havre" +__url__ = "http://www.freecadweb.org" + + +def makeMaterial(name="Material"): + '''makeMaterial(name): makes an Material object''' + obj = FreeCAD.ActiveDocument.addObject("App::MaterialObjectPython",name) + obj.Label = name + _ArchMaterial(obj) + _ViewProviderArchMaterial(obj.ViewObject) + getMaterialContainer().addObject(obj) + 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::DocumentObjectGroup","MaterialContainer") + obj.Label = "Materials" + return obj + + +class _CommandArchMaterial: + "the Arch Material command definition" + def GetResources(self): + return {'Pixmap': 'Arch_Material', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Material","Set material..."), + 'Accel': "M, T", + 'ToolTip': QtCore.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,"BaseMaterial"): + FreeCADGui.doCommand("FreeCAD.ActiveDocument."+obj.Name+".BaseMaterial = mat") + FreeCADGui.doCommandGui("mat.ViewObject.startEditing()") + FreeCAD.ActiveDocument.commitTransaction() + + def IsActive(self): + if FreeCAD.ActiveDocument: + return True + else: + return False + + +class _ArchMaterial: + "The Material object" + def __init__(self,obj): + self.Type = "Material" + obj.Proxy = self + + def execute(self,obj): + return + + +class _ViewProviderArchMaterial: + "A View Provider for the MechanicalMaterial object" + + def __init__(self,vobj): + vobj.Proxy = self + + def getIcon(self): + return ":/icons/Arch_Material.svg" + + def attach(self, vobj): + return + + def updateData(self, obj, prop): + return + + def onChanged(self, vobj, prop): + return + + def setEdit(self,vobj,mode): + taskd = _ArchMaterialTaskPanel(vobj.Object) + FreeCADGui.Control.showDialog(taskd) + return True + + def unsetEdit(self,vobj,mode): + FreeCADGui.Control.closeDialog() + return + + def __getstate__(self): + return None + + def __setstate__(self,state): + return None + + +class _ArchMaterialTaskPanel: + '''The editmode TaskPanel for MechanicalMaterial objects''' + def __init__(self,obj=None): + self.cards = None + self.obj = obj + self.form = FreeCADGui.PySideUic.loadUi(os.path.splitext(__file__)[0]+".ui") + self.color = QtGui.QColor(128,128,128) + colorPix = QtGui.QPixmap(16,16) + colorPix.fill(self.color) + self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix)) + QtCore.QObject.connect(self.form.comboBox_MaterialsInDir, QtCore.SIGNAL("currentIndexChanged(QString)"), self.chooseMat) + 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) + self.fillMaterialCombo() + 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']) + if 'Description' in self.material: + self.form.FieldDescription.setText(self.material['Description']) + if 'Color' in self.material: + if "(" in self.material['Color']: + c = tuple([float(f) for f in self.material['Color'].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)) + self.form.FieldColor.setText(self.material['Color']) + if 'StandardCode' in self.material: + self.form.FieldCode.setText(self.material['StandardCode']) + if 'ProductURL' in self.material: + self.form.FieldUrl.setText(self.material['ProductURL']) + + 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['Color'] = str(self.color.getRgbF()[:3]) + self.material['StandardCode'] = self.form.FieldCode.text() + self.material['ProductURL'] = self.form.FieldUrl.text() + + 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.Control.closeDialog() + + def reject(self): + FreeCADGui.Control.closeDialog() + + 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 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 user folder. + # User cards with same name will override system cards + paths = [FreeCAD.getResourceDir() + os.sep + "Mod" + os.sep + "Material" + os.sep + "StandardMaterial"] + paths.append(FreeCAD.ConfigGet("UserAppData")) + 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,i in self.cards.items(): + self.form.comboBox_MaterialsInDir.addItem(k) + + 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']) + + +if FreeCAD.GuiUp: + FreeCADGui.addCommand('Arch_Material',_CommandArchMaterial()) diff --git a/src/Mod/Arch/ArchMaterial.ui b/src/Mod/Arch/ArchMaterial.ui new file mode 100644 index 000000000000..5d75191f30d5 --- /dev/null +++ b/src/Mod/Arch/ArchMaterial.ui @@ -0,0 +1,182 @@ + + + ArchMaterial + + + + 0 + 0 + 223 + 233 + + + + Arch material + + + + + + + + + Choose preset... + + + + + + + + + + + + Name + + + + + + + + + + + 30 + 16777215 + + + + + + + + + + + + + + + + + + + + Description + + + + + + + + + + + + + + Color + + + + + + + () + + + + + + + + 30 + 16777215 + + + + + + + + + + + + + + + Code + + + + + + + + + + + 30 + 16777215 + + + + + + + + + + + + + + + + + + + + URL + + + + + + + + 0 + 0 + + + + + + + + + 30 + 16777215 + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index dd15ad16434c..a7018bc1eba3 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -693,6 +693,7 @@ def updateData(self,obj,prop): self.coords.point.setValues(0,len(p),p) self.pointset.numPoints.setValue(len(p)) self.lineset.coordIndex.setValues(0,len(p)+1,range(len(p))+[-1]) + ArchComponent.ViewProviderComponent.updateData(self,obj,prop) def onChanged(self,vobj,prop): if prop == "ShowNodes": diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 830aafd9a5c7..8de0e9198a64 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -605,6 +605,8 @@ def __init__(self,obj): obj.addProperty("App::PropertyLength","Height","Arch",translate("Arch","The height of this window (for preset windows only)")) obj.addProperty("App::PropertyVector","Normal","Arch",translate("Arch","The normal direction of this window")) obj.addProperty("App::PropertyInteger","Preset","Arch","") + obj.addProperty("App::PropertyLink","PanelMaterial","Material",translate("Arch","A material for this object")) + obj.addProperty("App::PropertyLink","GlassMaterial","Material",translate("Arch","A material for this object")) obj.setEditorMode("Preset",2) self.Type = "Window" diff --git a/src/Mod/Arch/CMakeLists.txt b/src/Mod/Arch/CMakeLists.txt index f9560582043d..e4020f3e14b7 100644 --- a/src/Mod/Arch/CMakeLists.txt +++ b/src/Mod/Arch/CMakeLists.txt @@ -30,6 +30,8 @@ SET(Arch_SRCS ArchEquipment.py ArchCutPlane.py ArchServer.py + ArchMaterial.py + ArchMaterial.ui ) SOURCE_GROUP("" FILES ${Arch_SRCS}) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 655001bae53e..e2d19454b7b1 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -74,7 +74,8 @@ def Initialize(self): "Arch_Window","Arch_Roof","Arch_Axis", "Arch_SectionPlane","Arch_Space","Arch_Stairs", "Arch_Panel","Arch_Equipment", - "Arch_Frame","Arch_CutPlane","Arch_Add","Arch_Remove","Arch_Survey"] + "Arch_Frame","Arch_Material","Arch_CutPlane", + "Arch_Add","Arch_Remove","Arch_Survey"] self.utilities = ["Arch_Component","Arch_SplitMesh","Arch_MeshToShape", "Arch_SelectNonSolidMeshes","Arch_RemoveShape", "Arch_CloseHoles","Arch_MergeWalls","Arch_Check", diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc index 733740346515..143d8c271e96 100644 --- a/src/Mod/Arch/Resources/Arch.qrc +++ b/src/Mod/Arch/Resources/Arch.qrc @@ -54,6 +54,7 @@ icons/Arch_Bimserver.svg icons/Git.svg icons/Arch_Component.svg + icons/Arch_Material.svg ui/archprefs-base.ui ui/archprefs-defaults.ui ui/archprefs-import.ui diff --git a/src/Mod/Arch/Resources/icons/Arch_Material.svg b/src/Mod/Arch/Resources/icons/Arch_Material.svg new file mode 100644 index 000000000000..a9a3ec05cbbd --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Material.svg @@ -0,0 +1,510 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index d2c8c46ff8b8..54862bda33d0 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -444,9 +444,9 @@ def insert(filename,docname,skip=[],only=[],root=None): obj.IfcAttributes = a break if not obj: - obj = baseobj + obj = Arch.makeComponent(baseobj,name=name,delete=True) if obj: - sols = str(baseobj.Shape.Solids) if hasattr(baseobj,"Shape") else "[]" + sols = str(obj.Shape.Solids) if hasattr(obj,"Shape") else "[]" if DEBUG: print sols objects[pid] = obj diff --git a/src/Mod/Material/MaterialEditor.py b/src/Mod/Material/MaterialEditor.py index ad95aa7d28a5..6f6be8a70e39 100644 --- a/src/Mod/Material/MaterialEditor.py +++ b/src/Mod/Material/MaterialEditor.py @@ -45,19 +45,21 @@ def createWidget(self, class_name, parent=None, name=''): class MaterialEditor(QtGui.QDialog): - def __init__(self, obj = None, prop = None): - "Initializes, optionally with an object name and a material property name to edit" + 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.""" QtGui.QDialog.__init__(self) self.obj = obj self.prop = prop + self.material = material self.customprops = [] # load the UI file from the same directory as this script loader = UiLoader(self) widget = loader.load(os.path.dirname(__file__)+os.sep+"materials-editor.ui") #QtCore.QMetaObject.connectSlotsByName(widget) self.ui = self - print self.ui - print dir(self.ui) + #print self.ui + #print dir(self.ui) # additional UI fixes and tweaks self.ButtonURL.setIcon(QtGui.QIcon(":/icons/internet-web-browser.svg")) self.ButtonDeleteProperty.setEnabled(False) @@ -81,8 +83,12 @@ def __init__(self, obj = None, prop = None): QtCore.QObject.connect(self.ButtonOpen, QtCore.SIGNAL("clicked()"), self.openfile) QtCore.QObject.connect(self.ButtonSave, QtCore.SIGNAL("clicked()"), self.savefile) # update the editor with the contents of the property, if we have one + d = None if self.prop and self.obj: d = FreeCAD.ActiveDocument.getObject(self.obj).getPropertyByName(self.prop) + elif self.material: + d = self.material + if d: self.updateContents(d) def updateCards(self): @@ -100,7 +106,7 @@ def updateCards(self): if self.cards: self.ComboMaterial.clear() self.ComboMaterial.addItem("") # add a blank item first - for k,i in self.cards.iteritems(): + for k,i in self.cards.items(): self.ComboMaterial.addItem(k) def updateContents(self,data): @@ -108,7 +114,7 @@ def updateContents(self,data): #print type(data) if isinstance(data,dict): self.clearEditor() - for k,i in data.iteritems(): + for k,i in data.items(): k = self.expandKey(k) slot = self.Editor.findItems(k,QtCore.Qt.MatchRecursive,0) if len(slot) == 1: @@ -257,4 +263,14 @@ def openEditor(obj = None, prop = None): 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.""" + editor = MaterialEditor(material=material) + result = editor.exec_() + if result: + return editor.getDict() + else: + return material