| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | __title__ = "Arch Material Management" |
| | __author__ = "Yorik van Havre" |
| | __url__ = "https://www.freecad.org" |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import FreeCAD |
| |
|
| | from draftutils import params |
| |
|
| | if FreeCAD.GuiUp: |
| | import os |
| | from PySide import QtCore, QtGui |
| | from PySide.QtCore import QT_TRANSLATE_NOOP |
| | import FreeCADGui |
| | import Arch_rc |
| | from draftutils.translate import translate |
| | else: |
| | |
| | def translate(ctxt, txt): |
| | return txt |
| |
|
| | def QT_TRANSLATE_NOOP(ctxt, txt): |
| | return txt |
| |
|
| | |
| |
|
| |
|
| | class _ArchMaterialContainer: |
| | "The Material Container" |
| |
|
| | def __init__(self, obj): |
| | self.Type = "MaterialContainer" |
| | obj.Proxy = self |
| |
|
| | def execute(self, obj): |
| | return |
| |
|
| | def dumps(self): |
| | if hasattr(self, "Type"): |
| | return self.Type |
| |
|
| | def loads(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): |
| | if FreeCADGui.activeWorkbench().name() != "BIMWorkbench": |
| | return |
| | actionMergeByName = QtGui.QAction( |
| | QtGui.QIcon(":/icons/Arch_Material_Group.svg"), |
| | translate("Arch", "Merge Duplicates"), |
| | menu, |
| | ) |
| | actionMergeByName.triggered.connect(self.mergeByName) |
| | menu.addAction(actionMergeByName) |
| |
|
| | actionReorder = QtGui.QAction(translate("Arch", "Reorder Children Alphabetically"), menu) |
| | actionReorder.triggered.connect(self.reorder) |
| | menu.addAction(actionReorder) |
| |
|
| | def doubleClicked(self, vobj): |
| | """Handle double-click on the materials group in the Tree View. |
| | |
| | Open the BIM Materials dialog and return True to indicate the event was handled |
| | (prevents the tree from starting inline label editing, Qt's default behavior if the event |
| | is not handled). |
| | """ |
| | FreeCADGui.runCommand("BIM_Material") |
| | return True |
| |
|
| | 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 dumps(self): |
| | return None |
| |
|
| | def loads(self, state): |
| | return None |
| |
|
| |
|
| | class _ArchMaterial: |
| | "The Material object" |
| |
|
| | def __init__(self, obj): |
| |
|
| | self.Type = "Material" |
| | obj.Proxy = self |
| | self.setProperties(obj) |
| |
|
| | def onDocumentRestored(self, obj): |
| |
|
| | self.setProperties(obj) |
| |
|
| | def setProperties(self, obj): |
| |
|
| | if not "Description" in obj.PropertiesList: |
| | obj.addProperty( |
| | "App::PropertyString", |
| | "Description", |
| | "Material", |
| | QT_TRANSLATE_NOOP("App::Property", "A description for this material"), |
| | locked=True, |
| | ) |
| | if not "StandardCode" in obj.PropertiesList: |
| | obj.addProperty( |
| | "App::PropertyString", |
| | "StandardCode", |
| | "Material", |
| | QT_TRANSLATE_NOOP("App::Property", "A standard code (MasterFormat, OmniClass,…)"), |
| | locked=True, |
| | ) |
| | if not "ProductURL" in obj.PropertiesList: |
| | obj.addProperty( |
| | "App::PropertyString", |
| | "ProductURL", |
| | "Material", |
| | QT_TRANSLATE_NOOP( |
| | "App::Property", "A URL where to find information about this material" |
| | ), |
| | locked=True, |
| | ) |
| | if not "Transparency" in obj.PropertiesList: |
| | obj.addProperty( |
| | "App::PropertyPercent", |
| | "Transparency", |
| | "Material", |
| | QT_TRANSLATE_NOOP("App::Property", "The transparency value of this material"), |
| | locked=True, |
| | ) |
| | if not "Color" in obj.PropertiesList: |
| | obj.addProperty( |
| | "App::PropertyColor", |
| | "Color", |
| | "Material", |
| | QT_TRANSLATE_NOOP("App::Property", "The color of this material"), |
| | locked=True, |
| | ) |
| | if not "SectionColor" in obj.PropertiesList: |
| | obj.addProperty( |
| | "App::PropertyColor", |
| | "SectionColor", |
| | "Material", |
| | QT_TRANSLATE_NOOP("App::Property", "The color of this material when cut"), |
| | locked=True, |
| | ) |
| |
|
| | 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 "SectionColor" in obj.Material: |
| | c = tuple( |
| | [ |
| | float(f) |
| | for f in obj.Material["SectionColor"].strip("()").strip("[]").split(",") |
| | ] |
| | ) |
| | if hasattr(obj, "SectionColor"): |
| | if not self.isSameColor(obj.SectionColor, c): |
| | obj.SectionColor = c |
| | 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 == "SectionColor": |
| | if hasattr(obj, "SectionColor"): |
| | if "SectionColor" in d: |
| | if self.isSameColor( |
| | tuple( |
| | [float(f) for f in d["SectionColor"].strip("()").strip("[]").split(",")] |
| | ), |
| | obj.SectionColor[:3], |
| | ): |
| | return |
| | d["SectionColor"] = str(obj.SectionColor[:3]) |
| | 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 |
| | |
| | |
| | |
| | |
| |
|
| | def execute(self, obj): |
| | if obj.Material: |
| | if FreeCAD.GuiUp: |
| | c = None |
| | t = None |
| | if "DiffuseColor" in obj.Material: |
| | c = tuple( |
| | [ |
| | float(f) |
| | for f in obj.Material["DiffuseColor"].strip("()").strip("[]").split(",") |
| | ] |
| | ) |
| | if "Transparency" in obj.Material: |
| | t = int(obj.Material["Transparency"]) |
| | for p in obj.InList: |
| | if ( |
| | hasattr(p, "Material") |
| | and p.Material.Name == obj.Name |
| | and getattr(obj.ViewObject, "UseMaterialColor", True) |
| | ): |
| | if c: |
| | p.ViewObject.ShapeColor = c |
| | if t: |
| | p.ViewObject.Transparency = t |
| | return |
| |
|
| | def dumps(self): |
| | if hasattr(self, "Type"): |
| | return self.Type |
| |
|
| | def loads(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 |
| |
|
| | def updateData(self, obj, prop): |
| | if prop == "Color": |
| | from PySide import QtCore, QtGui |
| |
|
| | |
| | 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)) |
| | |
| | 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") |
| | obj.ViewObject.signalChangeIcon() |
| |
|
| | 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): |
| | if mode != 0: |
| | return None |
| |
|
| | 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): |
| | if mode != 0: |
| | return None |
| |
|
| | FreeCADGui.Control.closeDialog() |
| | return True |
| |
|
| | def setupContextMenu(self, vobj, menu): |
| | if FreeCADGui.activeWorkbench().name() != "BIMWorkbench": |
| | return |
| | actionEdit = QtGui.QAction(translate("Arch", "Edit"), menu) |
| | actionEdit.triggered.connect(self.edit) |
| | menu.addAction(actionEdit) |
| |
|
| | def edit(self): |
| | FreeCADGui.ActiveDocument.setEdit(self.Object, 0) |
| |
|
| | 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.setValue(value) |
| |
|
| | def dumps(self): |
| | return None |
| |
|
| | def loads(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") |
| | colorPix = QtGui.QPixmap(16, 16) |
| | colorPix.fill(QtGui.QColor(204, 204, 204)) |
| | self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix)) |
| | self.form.ButtonSectionColor.setIcon(QtGui.QIcon(colorPix)) |
| | self.form.ButtonUrl.setIcon(QtGui.QIcon(":/icons/internet-web-browser.svg")) |
| | self.form.comboBox_MaterialsInDir.currentIndexChanged.connect(self.chooseMat) |
| | self.form.comboBox_FromExisting.currentIndexChanged.connect(self.fromExisting) |
| | self.form.comboFather.currentTextChanged.connect(self.setFather) |
| | self.form.ButtonColor.pressed.connect(self.getColor) |
| | self.form.ButtonSectionColor.pressed.connect(self.getSectionColor) |
| | self.form.ButtonUrl.pressed.connect(self.openUrl) |
| | self.form.ButtonEditor.pressed.connect(self.openEditor) |
| | self.form.ButtonCode.pressed.connect(self.getCode) |
| | self.fillMaterialCombo() |
| | self.fillExistingCombo() |
| | try: |
| | from bimcommands import BimClassification |
| | except Exception: |
| | self.form.ButtonCode.hide() |
| | else: |
| | self.form.ButtonCode.setIcon(QtGui.QIcon(":/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"]) |
| | if "DiffuseColor" in self.material: |
| | self.form.ButtonColor.setIcon(self.getColorIcon(self.material["DiffuseColor"])) |
| | elif "ViewColor" in self.material: |
| | self.form.ButtonColor.setIcon(self.getColorIcon(self.material["ViewColor"])) |
| | elif "Color" in self.material: |
| | self.form.ButtonColor.setIcon(self.getColorIcon(self.material["Color"])) |
| | if "SectionColor" in self.material: |
| | self.form.ButtonSectionColor.setIcon(self.getColorIcon(self.material["SectionColor"])) |
| | 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 getColorIcon(self, color): |
| | if color: |
| | if "(" in color: |
| | c = tuple([float(f) for f in color.strip("()").split(",")]) |
| | qcolor = QtGui.QColor() |
| | qcolor.setRgbF(c[0], c[1], c[2]) |
| | colorPix = QtGui.QPixmap(16, 16) |
| | colorPix.fill(qcolor) |
| | icon = QtGui.QIcon(colorPix) |
| | return icon |
| | return QtGui.QIcon() |
| |
|
| | 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"] = self.getColorFromIcon(self.form.ButtonColor.icon()) |
| | self.material["ViewColor"] = self.material["DiffuseColor"] |
| | self.material["Color"] = self.material["DiffuseColor"] |
| | self.material["SectionColor"] = self.getColorFromIcon(self.form.ButtonSectionColor.icon()) |
| | self.material["StandardCode"] = self.form.FieldCode.text() |
| | self.material["ProductURL"] = self.form.FieldUrl.text() |
| | self.material["Transparency"] = str(self.form.SpinBox_Transparency.value()) |
| |
|
| | def getColorFromIcon(self, icon): |
| | "gets pixel color from the given icon" |
| | pixel = icon.pixmap(16, 16).toImage().pixel(0, 0) |
| | return str(QtGui.QColor(pixel).getRgbF()) |
| |
|
| | def accept(self): |
| | self.getFields() |
| | if self.obj: |
| | if hasattr(self.obj, "Material"): |
| | self.obj.Material = self.material |
| | self.obj.Label = self.material["Name"] |
| | FreeCAD.ActiveDocument.recompute() |
| | FreeCADGui.ActiveDocument.resetEdit() |
| | return True |
| |
|
| | def reject(self): |
| | FreeCADGui.ActiveDocument.resetEdit() |
| | return True |
| |
|
| | def chooseMat(self, card): |
| | "sets self.material from a card" |
| | card = self.form.comboBox_MaterialsInDir.currentText() |
| | 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": |
| | if "Father" in self.material: |
| | |
| | self.material.pop("Father") |
| | else: |
| | self.material["Father"] = text |
| |
|
| | def getColor(self): |
| | self.getColorForButton(self.form.ButtonColor) |
| |
|
| | def getSectionColor(self): |
| | self.getColorForButton(self.form.ButtonSectionColor) |
| |
|
| | def getColorForButton(self, button): |
| | "opens a color picker dialog" |
| | icon = button.icon() |
| | pixel = icon.pixmap(16, 16).toImage().pixel(0, 0) |
| | color = QtGui.QColorDialog.getColor(QtGui.QColor(pixel)) |
| | if color.isValid(): |
| | colorPix = QtGui.QPixmap(16, 16) |
| | colorPix.fill(color) |
| | button.setIcon(QtGui.QIcon(colorPix)) |
| |
|
| | def fillMaterialCombo(self): |
| | "fills the combo with the existing FCMat cards" |
| | |
| | |
| | resources_mat_path = os.path.join( |
| | FreeCAD.getResourceDir(), "Mod", "Material", "Resources", "Materials" |
| | ) |
| | resources_mat_path_std = os.path.join(resources_mat_path, "Standard") |
| | user_mat_path = os.path.join(FreeCAD.ConfigGet("UserAppData"), "Material") |
| |
|
| | paths = [resources_mat_path_std] |
| | if os.path.exists(user_mat_path): |
| | paths.append(user_mat_path) |
| | self.cards = {} |
| | for p in paths: |
| | for root, _, f_names in os.walk(p): |
| | for f in f_names: |
| | b, e = os.path.splitext(f) |
| | if e.upper() == ".FCMAT": |
| | self.cards[b] = os.path.join(root, f) |
| | if self.cards: |
| | for k in sorted(self.cards): |
| | 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"), |
| | locked=True, |
| | ) |
| | obj.addProperty( |
| | "App::PropertyStringList", |
| | "Names", |
| | "Arch", |
| | QT_TRANSLATE_NOOP("App::Property", "The list of layer names"), |
| | locked=True, |
| | ) |
| | obj.addProperty( |
| | "App::PropertyLinkList", |
| | "Materials", |
| | "Arch", |
| | QT_TRANSLATE_NOOP("App::Property", "The list of layer materials"), |
| | locked=True, |
| | ) |
| | obj.addProperty( |
| | "App::PropertyFloatList", |
| | "Thicknesses", |
| | "Arch", |
| | QT_TRANSLATE_NOOP("App::Property", "The list of layer thicknesses"), |
| | locked=True, |
| | ) |
| |
|
| | def dumps(self): |
| | if hasattr(self, "Type"): |
| | return self.Type |
| |
|
| | def loads(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 attach(self, vobj): |
| | self.Object = vobj.Object |
| |
|
| | def setEdit(self, vobj, mode): |
| | if mode != 0: |
| | return None |
| |
|
| | taskd = _ArchMultiMaterialTaskPanel(vobj.Object) |
| | FreeCADGui.Control.showDialog(taskd) |
| | return True |
| |
|
| | def unsetEdit(self, vobj, mode): |
| | if mode != 0: |
| | return None |
| |
|
| | FreeCADGui.Control.closeDialog() |
| | return True |
| |
|
| | def doubleClicked(self, vobj): |
| | self.edit() |
| | return True |
| |
|
| | def setupContextMenu(self, vobj, menu): |
| | if FreeCADGui.activeWorkbench().name() != "BIMWorkbench": |
| | return |
| | actionEdit = QtGui.QAction(translate("Arch", "Edit"), menu) |
| | actionEdit.triggered.connect(self.edit) |
| | menu.addAction(actionEdit) |
| |
|
| | def edit(self): |
| | FreeCADGui.ActiveDocument.setEdit(self.Object, 0) |
| |
|
| | def dumps(self): |
| | return None |
| |
|
| | def loads(self, state): |
| | return None |
| |
|
| | 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.setRootIsDecorated(False) |
| | self.form.tree.setModel(self.model) |
| | self.form.tree.setUniformRowHeights(True) |
| | self.form.tree.setItemDelegate(MultiMaterialDelegate()) |
| | self.form.chooseCombo.currentIndexChanged.connect(self.fromExisting) |
| | self.form.addButton.pressed.connect(self.addLayer) |
| | self.form.upButton.pressed.connect(self.upLayer) |
| | self.form.downButton.pressed.connect(self.downLayer) |
| | self.form.delButton.pressed.connect(self.delLayer) |
| | self.form.invertButton.pressed.connect(self.invertLayer) |
| | self.model.itemChanged.connect(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"), |
| | ] |
| | ) |
| | |
| | self.form.tree.setColumnWidth(0, params.get_param_arch("MultiMaterialColumnWidth0")) |
| | self.form.tree.setColumnWidth(1, params.get_param_arch("MultiMaterialColumnWidth1")) |
| | 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 Exception: |
| | 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): |
| | |
| | params.set_param_arch("MultiMaterialColumnWidth0", self.form.tree.columnWidth(0)) |
| | params.set_param_arch("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 Exception: |
| | 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() |
| | FreeCADGui.ActiveDocument.resetEdit() |
| | return True |
| |
|
| | def reject(self): |
| | FreeCADGui.ActiveDocument.resetEdit() |
| | return True |
| |
|