diff --git a/src/Mod/Arch/ArchMaterial.py b/src/Mod/Arch/ArchMaterial.py index 04537d684b..2edaa0c754 100644 --- a/src/Mod/Arch/ArchMaterial.py +++ b/src/Mod/Arch/ArchMaterial.py @@ -516,16 +516,17 @@ class _ArchMaterialTaskPanel: 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) + 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")) 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.ButtonSectionColor,QtCore.SIGNAL("pressed()"),self.getSectionColor) 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) @@ -551,21 +552,14 @@ class _ArchMaterialTaskPanel: 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"] + self.form.ButtonColor.setIcon(self.getColorIcon(self.material["DiffuseColor"])) elif 'ViewColor' in self.material: - col = self.material["ViewColor"] + self.form.ButtonColor.setIcon(self.getColorIcon(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)) + 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: @@ -589,18 +583,35 @@ class _ArchMaterialTaskPanel: 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'] = str(self.color.getRgbF()[:3]) + 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: @@ -635,11 +646,18 @@ class _ArchMaterialTaskPanel: def getColor(self): "opens a color picker dialog" - self.color = QtGui.QColorDialog.getColor() + color = QtGui.QColorDialog.getColor() colorPix = QtGui.QPixmap(16,16) - colorPix.fill(self.color) + colorPix.fill(color) self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix)) + def getSectionColor(self): + "opens a color picker dialog" + color = QtGui.QColorDialog.getColor() + colorPix = QtGui.QPixmap(16,16) + colorPix.fill(color) + self.form.ButtonSectionColor.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. diff --git a/src/Mod/Arch/Resources/ui/ArchMaterial.ui b/src/Mod/Arch/Resources/ui/ArchMaterial.ui index 59065164a8..f195beaad0 100644 --- a/src/Mod/Arch/Resources/ui/ArchMaterial.ui +++ b/src/Mod/Arch/Resources/ui/ArchMaterial.ui @@ -131,6 +131,30 @@ + + + + + + Section Color + + + + + + + + 30 + 16777215 + + + + + + + + + diff --git a/src/Mod/Material/MaterialEditor.py b/src/Mod/Material/MaterialEditor.py index c9713cce28..019104bcde 100644 --- a/src/Mod/Material/MaterialEditor.py +++ b/src/Mod/Material/MaterialEditor.py @@ -26,11 +26,11 @@ __url__ = "http://www.freecadweb.org" import os import sys -from PySide import QtCore, QtGui -# from PySide import QtUiTools, QtSvg +from PySide import QtCore, QtGui, QtSvg import FreeCAD import FreeCADGui +import Material_rc # is this still needed after the move to card utils??? if sys.version_info.major >= 3: @@ -61,6 +61,14 @@ class MaterialEditor: os.path.dirname(__file__) + os.sep + "materials-editor.ui" ) + self.widget.setWindowIcon(QtGui.QIcon(":/icons/preview-rendered.svg")) + + # restore size and position + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material") + w = p.GetInt("MaterialEditorWidth",441) + h = p.GetInt("MaterialEditorHeight",626) + self.widget.resize(w,h) + # additional UI fixes and tweaks widget = self.widget buttonURL = widget.ButtonURL @@ -72,9 +80,17 @@ class MaterialEditor: comboMaterial = widget.ComboMaterial treeView = widget.treeView - # temporarily hide preview fields, as they are not used yet - # TODO : implement previews - widget.PreviewGroup.hide() + + # create preview svg slots + self.widget.PreviewRender = QtSvg.QSvgWidget(":/icons/preview-rendered.svg") + self.widget.PreviewRender.setMaximumWidth(64) + self.widget.PreviewRender.setMinimumHeight(64) + self.widget.topLayout.addWidget(self.widget.PreviewRender) + self.widget.PreviewVector = QtSvg.QSvgWidget(":/icons/preview-vector.svg") + self.widget.PreviewVector.setMaximumWidth(64) + self.widget.PreviewVector.setMinimumHeight(64) + self.widget.topLayout.addWidget(self.widget.PreviewVector) + self.updatePreviews(mat=material) buttonURL.setIcon(QtGui.QIcon(":/icons/internet-web-browser.svg")) buttonDeleteProperty.setEnabled(False) @@ -92,7 +108,7 @@ class MaterialEditor: comboMaterial.currentIndexChanged[int].connect(self.chooseMaterial) buttonAddProperty.clicked.connect(self.addCustomProperty) buttonDeleteProperty.clicked.connect(self.deleteCustomProperty) - treeView.clicked.connect(self.checkDeletable) + treeView.clicked.connect(self.onClickTree) model = QtGui.QStandardItemModel() treeView.setModel(model) @@ -126,6 +142,7 @@ class MaterialEditor: '''implements the model with the material attribute structure.''' + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material") widget = self.widget treeView = widget.treeView model = treeView.model() @@ -147,18 +164,20 @@ class MaterialEditor: for properName in group[gg]: pp = properName # property name item = QtGui.QStandardItem(pp) + item.setToolTip(group[gg][properName]['Description']) self.internalprops.append(pp) it = QtGui.QStandardItem() + it.setToolTip(group[gg][properName]['Description']) tt = group[gg][properName]['Type'] itType = QtGui.QStandardItem(tt) top.appendRow([item, it, itType]) + treeView.setExpanded(top.index(),p.GetBool("TreeExpand"+gg,True)) + #top.sortChildren(0) - top.sortChildren(0) - - treeView.expandAll() + #treeView.expandAll() def updateMatParamsInTree(self, data): @@ -181,6 +200,11 @@ class MaterialEditor: it.setText(value) del data[kk] except KeyError: + # treat here changes in Material Card Template + # Norm -> StandardCode + if (kk == "Standard Code") and ("Norm" in data) and data["Norm"]: + it.setText(data["Norm"]) + del data["Norm"] it.setText("") userGroup = root.child(gg + 1, 0) @@ -195,6 +219,7 @@ class MaterialEditor: self.customprops.append(k) def chooseMaterial(self, index): + if index < 0: return self.card_path = self.widget.ComboMaterial.itemData(index) @@ -256,13 +281,26 @@ class MaterialEditor: def accept(self): "" + self.storeSize() QtGui.QDialog.accept(self.widget) def reject(self): "" + self.storeSize() QtGui.QDialog.reject(self.widget) + def storeSize(self): + "stores the widget size" + # store widths + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material") + p.SetInt("MaterialEditorWidth",self.widget.width()) + p.SetInt("MaterialEditorHeight",self.widget.height()) + root = self.widget.treeView.model().invisibleRootItem() + for gg in range(root.rowCount()): + group = root.child(gg) + p.SetBool("TreeExpand"+group.text(),self.widget.treeView.isExpanded(group.index())) + def expandKey(self, key): "adds spaces before caps in a KeyName" nk = "" @@ -338,7 +376,7 @@ class MaterialEditor: buttonDeleteProperty.setEnabled(False) - def checkDeletable(self, index): + def onClickTree(self, index): '''Checks if the current item is a custom or an internal property, and enable the delete property or delete value button.''' @@ -370,6 +408,8 @@ class MaterialEditor: buttonDeleteProperty.setEnabled(False) buttonDeleteProperty.setProperty("text", "Delete property") + self.updatePreviews() + def getDict(self): "returns a dictionary from the contents of the editor." @@ -414,6 +454,52 @@ class MaterialEditor: self.widget.PreviewVector.show() ''' + def updatePreviews(self,mat=None): + "updates the preview images from the content of the editor" + if not mat: + mat = self.getDict() + diffcol = None + highlightcol = None + sectioncol = None + if "DiffuseColor" in mat: + diffcol = mat["DiffuseColor"] + elif "ViewColor" in mat: + diffcol = mat["ViwColor"] + elif "Color" in mat: + diffcol = mat["Color"] + if "SpecularColor" in mat: + highlightcol = mat["SpecularColor"] + if "SectionColor" in mat: + sectioncol = mat["SectionColor"] + if diffcol or highlightcol: + fd = QtCore.QFile(":/icons/preview-rendered.svg") + if fd.open(QtCore.QIODevice.ReadOnly | QtCore.QIODevice.Text): + svg = QtCore.QTextStream(fd).readAll() + fd.close() + if diffcol: + svg = svg.replace("#d3d7cf",self.getColorHash(diffcol,val=255)) + svg = svg.replace("#555753",self.getColorHash(diffcol,val=125)) + if highlightcol: + svg = svg.replace("#fffffe",self.getColorHash(highlightcol,val=255)) + self.widget.PreviewRender.load(QtCore.QByteArray(bytes(svg,encoding="utf8"))) + if diffcol or sectioncol: + fd = QtCore.QFile(":/icons/preview-vector.svg") + if fd.open(QtCore.QIODevice.ReadOnly | QtCore.QIODevice.Text): + svg = QtCore.QTextStream(fd).readAll() + fd.close() + if diffcol: + svg = svg.replace("#d3d7cf",self.getColorHash(diffcol,val=255)) + svg = svg.replace("#555753",self.getColorHash(diffcol,val=125)) + if sectioncol: + svg = svg.replace("#ffffff",self.getColorHash(sectioncol,val=255)) + self.widget.PreviewVector.load(QtCore.QByteArray(bytes(svg,encoding="utf8"))) + + def getColorHash(self,col,val=255): + "returns a '#000000' string from a '(0.1,0.2,0.3)' string" + col = [float(x.strip()) for x in col.strip("()").split(",")] + color = QtGui.QColor(int(col[0]*val),int(col[1]*val),int(col[2]*val)) + return color.name() + def openfile(self): "Opens a FCMat file" filetuple = QtGui.QFileDialog.getOpenFileName( @@ -550,7 +636,7 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate): if Type == "Color": color = editor.property('color') - color = color.getRgb() + color = tuple([v/255.0 for v in color.getRgb()]) item.setText(str(color)) elif Type == "File": @@ -650,7 +736,7 @@ def string2tuple(string): "provisionally" value = string[1:-1] value = value.split(',') - value = [int(v) for v in value] + value = [int(float(v)*255) for v in value] value = tuple(value) return value diff --git a/src/Mod/Material/Resources/icons/preview-rendered.svg b/src/Mod/Material/Resources/icons/preview-rendered.svg index 188558ef45..bf21c95ac5 100644 --- a/src/Mod/Material/Resources/icons/preview-rendered.svg +++ b/src/Mod/Material/Resources/icons/preview-rendered.svg @@ -58,8 +58,8 @@ - - + + diff --git a/src/Mod/Material/Resources/icons/preview-vector.svg b/src/Mod/Material/Resources/icons/preview-vector.svg index ba65341c53..c2d7383cb0 100644 --- a/src/Mod/Material/Resources/icons/preview-vector.svg +++ b/src/Mod/Material/Resources/icons/preview-vector.svg @@ -134,7 +134,7 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" /> - + - - - - 22 - 22 - - - - Opens the Product URL of this material in an external browser - - - - - - - - - - - 120 - 0 - - - - Existing material cards - - + + + + + + + + 22 + 22 + + + + Opens the Product URL of this material in an external browser + + + + + + + + + + + 120 + 0 + + + + Existing material cards + + + + + + + + + + + Opens an existing material card + + + Open... + + + + + + + Saves this material as a card + + + Save as... + + + + + + - - - - - - Opens an existing material card - - - Open... - - - - - - - Saves this material as a card - - - Save as... - - - - - - - - - - - - Preview - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 96 - 96 - - - - - - - - - - - - 96 - 96 - - - - - - - diff --git a/src/Mod/Material/materialtools/cardutils.py b/src/Mod/Material/materialtools/cardutils.py index e5048e1127..7af3deb437 100644 --- a/src/Mod/Material/materialtools/cardutils.py +++ b/src/Mod/Material/materialtools/cardutils.py @@ -99,11 +99,12 @@ def get_material_resources(category='Solid'): custom_mat_dir = mat_prefs.GetString("CustomMaterialsDir", "") if os.path.exists(custom_mat_dir): resources[custom_mat_dir] = ":/icons/user.svg" - else: - FreeCAD.Console.PrintError( - 'Custom material directory set by user: {} does not exist.\n' - .format(custom_mat_dir) - ) + # fail silently + #else: + # FreeCAD.Console.PrintError( + # 'Custom material directory set by user: {} does not exist.\n' + # .format(custom_mat_dir) + # ) return resources @@ -229,14 +230,18 @@ def get_material_template(withSpaces=False): # on attributes, add a space before a capital letter # will be used for better display in the ui import re + new_template = [] for group in template_data: + new_group = {} gg = list(group.keys())[0] # group dict has only one key # iterating over a dict and changing it is not allowed # thus it is iterated over a list of the keys + new_group[gg] = {} for proper in list(group[gg].keys()): new_proper = re.sub(r"(\w)([A-Z]+)", r"\1 \2", proper) - group[gg][new_proper] = group[gg][proper] - del group[gg][proper] + new_group[gg][new_proper] = group[gg][proper] + new_template.append(new_group) + template_data = new_template return template_data