Fem: Use new material editor in materials task panels - fixes #16814
This commit is contained in:
@@ -15,122 +15,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_desc">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>1677215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Material</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Category</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_category">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Material card</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="cb_materials">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>choose...</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Material name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="l_mat_name">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="l_mat_description">
|
||||
<property name="text">
|
||||
<string>Material Description</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_basic_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>1677215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Editing material</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_28">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="pushButton_editMat">
|
||||
<property name="text">
|
||||
<string>Use FreeCAD material editor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QCheckBox" name="chbu_allow_edit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use this task panel</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="MatGui::MaterialTreeWidget" name="wgt_material_tree"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_basic">
|
||||
@@ -590,18 +475,21 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="chbu_allow_edit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
<property name="text">
|
||||
<string>Use this task panel</string>
|
||||
</property>
|
||||
</spacer>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -611,6 +499,11 @@
|
||||
<extends>QLineEdit</extends>
|
||||
<header>Gui/InputField.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MatGui::MaterialTreeWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Mod/Material/Gui/MaterialTreeWidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
||||
@@ -70,6 +70,16 @@ class MaterialCommon(base_fempythonobject.BaseFemPythonObject):
|
||||
value=["Solid", "Fluid"],
|
||||
)
|
||||
)
|
||||
prop.append(
|
||||
_PropHelper(
|
||||
type="App::PropertyString",
|
||||
name="UUID",
|
||||
group="Material",
|
||||
doc="Material UUID",
|
||||
hidden=True,
|
||||
value="",
|
||||
)
|
||||
)
|
||||
|
||||
return prop
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ from PySide import QtGui
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from FreeCAD import Units
|
||||
import Materials
|
||||
import MatGui
|
||||
|
||||
from femguiutils import selection_widgets
|
||||
from . import base_femtaskpanel
|
||||
@@ -50,35 +52,25 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
|
||||
self.material = self.obj.Material # FreeCAD material dictionary of current material
|
||||
self.card_path = ""
|
||||
self.materials = {} # { card_path : FreeCAD material dict, ... }
|
||||
self.cards = {} # { card_path : card_names, ... }
|
||||
self.icons = {} # { card_path : icon_path, ... }
|
||||
# mat_card is the FCMat file
|
||||
# card_name is the file name of the mat_card
|
||||
# card_path is the whole file path of the mat_card
|
||||
# material_name is the value of the key name in FreeCAD material dictionary
|
||||
# they might not match because of special letters in the material_name
|
||||
# which are changed in the card_name to english standard characters
|
||||
self.has_transient_mat = False
|
||||
# FreeCAD material dictionary of current material
|
||||
self.material = self.obj.Material
|
||||
self.uuid = self.obj.UUID
|
||||
self.material_manager = Materials.MaterialManager()
|
||||
|
||||
# parameter widget
|
||||
self.parameterWidget = FreeCADGui.PySideUic.loadUi(
|
||||
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/Material.ui"
|
||||
)
|
||||
# globals
|
||||
QtCore.QObject.connect(
|
||||
self.parameterWidget.cb_materials, QtCore.SIGNAL("activated(int)"), self.choose_material
|
||||
)
|
||||
self.material_tree = MatGui.MaterialTreeWidget(self.parameterWidget.wgt_material_tree)
|
||||
self.material_tree.expanded = False
|
||||
self.material_tree.IncludeEmptyFolders = False
|
||||
self.material_tree.IncludeEmptyLibraries = False
|
||||
|
||||
QtCore.QObject.connect(
|
||||
self.parameterWidget.chbu_allow_edit,
|
||||
QtCore.SIGNAL("clicked()"),
|
||||
self.toggleInputFieldsReadOnly,
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.parameterWidget.pushButton_editMat, QtCore.SIGNAL("clicked()"), self.edit_material
|
||||
)
|
||||
# basic properties must be provided
|
||||
QtCore.QObject.connect(
|
||||
self.parameterWidget.input_fd_density,
|
||||
@@ -123,6 +115,11 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
QtCore.SIGNAL("editingFinished()"),
|
||||
self.vtec_changed,
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.parameterWidget.wgt_material_tree,
|
||||
QtCore.SIGNAL("onMaterial(QString)"),
|
||||
self.set_from_editor,
|
||||
)
|
||||
|
||||
# init all parameter input files with read only
|
||||
self.parameterWidget.chbu_allow_edit.setCheckState(QtCore.Qt.CheckState.Unchecked)
|
||||
@@ -131,8 +128,8 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
# hide some groupBox according to material category
|
||||
# note: input_fd_vol_expansion_coefficient is currently not used
|
||||
# it might be used in future for solids
|
||||
self.parameterWidget.label_category.setText(self.obj.Category)
|
||||
if self.obj.Category == "Fluid":
|
||||
self.filter_models(self.obj.Category)
|
||||
self.parameterWidget.groupBox_mechanical.setVisible(0)
|
||||
self.parameterWidget.label_vol_expansion_coefficient.setVisible(0)
|
||||
self.parameterWidget.input_fd_vol_expansion_coefficient.setVisible(0)
|
||||
@@ -141,43 +138,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
self.parameterWidget.label_vol_expansion_coefficient.setVisible(0)
|
||||
self.parameterWidget.input_fd_vol_expansion_coefficient.setVisible(0)
|
||||
|
||||
# get all available materials (fill self.materials, self.cards and self.icons)
|
||||
from materialtools.cardutils import import_materials as getmats
|
||||
|
||||
# Note: import_materials(category="Solid", ...),
|
||||
# category default to Solid, but must be given for FluidMaterial to be imported
|
||||
self.materials, self.cards, self.icons = getmats(self.obj.Category)
|
||||
# fill the material comboboxes with material cards
|
||||
self.add_cards_to_combo_box()
|
||||
|
||||
# search for exact this mat_card in all known cards, choose the current material
|
||||
self.card_path = self.get_material_card(self.material)
|
||||
FreeCAD.Console.PrintLog(f"card_path: {self.card_path}\n")
|
||||
if not self.card_path:
|
||||
# we have not found our material in self.materials dict :-(
|
||||
# we're going to add a user-defined temporary material: a document material
|
||||
FreeCAD.Console.PrintMessage(
|
||||
"Previously used material card can not be found in material directories. "
|
||||
"Add document material.\n"
|
||||
)
|
||||
self.card_path = "_document_material"
|
||||
self.materials[self.card_path] = self.material
|
||||
self.parameterWidget.cb_materials.addItem(
|
||||
QtGui.QIcon(":/icons/help-browser.svg"), self.card_path, self.card_path
|
||||
)
|
||||
index = self.parameterWidget.cb_materials.findData(self.card_path)
|
||||
# fill input fields and set the current material in the cb widget
|
||||
self.choose_material(index)
|
||||
else:
|
||||
# we found our exact material in self.materials dict :-)
|
||||
FreeCAD.Console.PrintLog(
|
||||
"Previously used material card was found in material directories. "
|
||||
"We will use this material.\n"
|
||||
)
|
||||
index = self.parameterWidget.cb_materials.findData(self.card_path)
|
||||
# fill input fields and set the current material in the cb widget
|
||||
self.choose_material(index)
|
||||
|
||||
# geometry selection widget
|
||||
self.selectionWidget = selection_widgets.GeometryElementsSelection(
|
||||
obj.References, ["Solid", "Face", "Edge"], False, True
|
||||
@@ -187,21 +147,21 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
self.form = [self.parameterWidget, self.selectionWidget]
|
||||
|
||||
# check references, has to be after initialisation of selectionWidget
|
||||
self.material_tree.UUID = self.get_material_uuid(self.material)
|
||||
self.check_material_keys()
|
||||
self.set_mat_params_in_input_fields(self.material)
|
||||
|
||||
self.selectionWidget.has_equal_references_shape_types()
|
||||
|
||||
# leave task panel ***************************************************************************
|
||||
def accept(self):
|
||||
# print(self.material)
|
||||
if self.material == {}: # happens if material editor was canceled
|
||||
FreeCAD.Console.PrintError("Empty material dictionary, nothing was changed.\n")
|
||||
self.recompute_and_set_back_all()
|
||||
return True
|
||||
if self.selectionWidget.has_equal_references_shape_types():
|
||||
self.do_not_set_thermal_zeros()
|
||||
from materialtools.cardutils import check_mat_units as checkunits
|
||||
|
||||
if checkunits(self.material) is True:
|
||||
self.obj.Material = self.material
|
||||
self.obj.UUID = self.uuid
|
||||
self.obj.References = self.selectionWidget.references
|
||||
else:
|
||||
error_message = (
|
||||
@@ -249,20 +209,39 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
return False
|
||||
|
||||
# choose material ****************************************************************************
|
||||
def get_material_card(self, material):
|
||||
for a_mat in self.materials:
|
||||
def filter_models(self, category):
|
||||
material_filter = Materials.MaterialFilter()
|
||||
models = set(Materials.ModelManager().Models.keys())
|
||||
uuids = Materials.UUIDs()
|
||||
if category == "Fluid":
|
||||
material_filter.RequiredModels = [uuids.Fluid]
|
||||
self.material_tree.setFilter(material_filter)
|
||||
|
||||
def get_material_uuid(self, material):
|
||||
if self.uuid:
|
||||
try:
|
||||
self.material_manager.getMaterial(self.uuid)
|
||||
return self.uuid
|
||||
except:
|
||||
return ""
|
||||
|
||||
if not self.material:
|
||||
return ""
|
||||
|
||||
for a_mat in self.material_manager.Materials:
|
||||
# check if every item of the current material fits to a known material card
|
||||
# if all items were found we know it is the right card
|
||||
# we can hereby not simply perform
|
||||
# set(self.materials[a_mat].items()) ^ set(material.items())
|
||||
# because entries are often identical, just appear in the set in a different order
|
||||
unmatched_item = False
|
||||
a_mat_prop = self.material_manager.getMaterial(a_mat).Properties.items()
|
||||
for item in material.items():
|
||||
if item not in self.materials[a_mat].items():
|
||||
if item not in a_mat_prop:
|
||||
unmatched_item = True
|
||||
# often the difference is just a decimal e.g. "120" to "120.0"
|
||||
# therefore first check if the item name exists
|
||||
for a_mat_item in self.materials[a_mat].items():
|
||||
for a_mat_item in a_mat_prop:
|
||||
if item[0] == a_mat_item[0]:
|
||||
# now check if we have a number value in a unit
|
||||
if item[1].split() and not self.isfloat(item[1].split()[0]):
|
||||
@@ -282,99 +261,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
return a_mat
|
||||
return ""
|
||||
|
||||
def choose_material(self, index):
|
||||
if index < 0:
|
||||
return
|
||||
self.card_path = self.parameterWidget.cb_materials.itemData(index) # returns whole path
|
||||
FreeCAD.Console.PrintMessage(f"Material card chosen:\n {self.card_path}\n")
|
||||
self.material = self.materials[self.card_path]
|
||||
self.check_material_keys()
|
||||
self.set_mat_params_in_input_fields(self.material)
|
||||
self.parameterWidget.cb_materials.setCurrentIndex(index) # set after input fields
|
||||
gen_mat_desc = ""
|
||||
gen_mat_name = ""
|
||||
if "Description" in self.material:
|
||||
gen_mat_desc = self.material["Description"]
|
||||
if "Name" in self.material:
|
||||
gen_mat_name = self.material["Name"]
|
||||
self.parameterWidget.l_mat_description.setText(gen_mat_desc)
|
||||
self.parameterWidget.l_mat_name.setText(gen_mat_name)
|
||||
# print("choose_material: done")
|
||||
|
||||
def set_transient_material(self):
|
||||
self.card_path = "_transient_material"
|
||||
self.materials[self.card_path] = self.material # = the current input fields data
|
||||
index = self.parameterWidget.cb_materials.findData(self.card_path)
|
||||
self.choose_material(index)
|
||||
|
||||
def add_transient_material(self):
|
||||
self.has_transient_mat = True
|
||||
self.card_path = "_transient_material"
|
||||
self.parameterWidget.cb_materials.addItem(
|
||||
QtGui.QIcon(":/icons/help-browser.svg"), self.card_path, self.card_path
|
||||
)
|
||||
self.set_transient_material()
|
||||
|
||||
# how to edit a material *********************************************************************
|
||||
def edit_material(self):
|
||||
# opens the material editor to choose a material or edit material params
|
||||
import MaterialEditor
|
||||
|
||||
if self.card_path not in self.cards:
|
||||
FreeCAD.Console.PrintLog(
|
||||
"Card path not in cards, material dict will be used to open Material Editor.\n"
|
||||
)
|
||||
new_material_params = MaterialEditor.editMaterial(
|
||||
material=self.material, category=self.obj.Category
|
||||
)
|
||||
else:
|
||||
new_material_params = MaterialEditor.editMaterial(
|
||||
card_path=self.card_path, category=self.obj.Category
|
||||
)
|
||||
# material editor returns the mat_dict only, not a card_path
|
||||
# if the material editor was canceled a empty dict will be returned
|
||||
# do not change the self.material
|
||||
# check if dict is not empty (do not use "is True")
|
||||
if new_material_params:
|
||||
# check material quantity units
|
||||
from materialtools.cardutils import check_mat_units as checkunits
|
||||
|
||||
if checkunits(new_material_params) is True:
|
||||
self.material = new_material_params
|
||||
self.card_path = self.get_material_card(self.material)
|
||||
self.check_material_keys()
|
||||
self.set_mat_params_in_input_fields(self.material)
|
||||
if not self.card_path:
|
||||
FreeCAD.Console.PrintMessage(
|
||||
"Material card chosen by the material editor "
|
||||
"was not found in material directories.\n"
|
||||
"Either the card does not exist or some material "
|
||||
"parameter where changed in material editor.\n"
|
||||
)
|
||||
if self.has_transient_mat is False:
|
||||
self.add_transient_material()
|
||||
else:
|
||||
self.set_transient_material()
|
||||
else:
|
||||
# we found our exact material in self.materials dict :-)
|
||||
FreeCAD.Console.PrintLog(
|
||||
"Material card chosen by the material editor "
|
||||
"was found in material directories. "
|
||||
"The found material card will be used.\n"
|
||||
)
|
||||
index = self.parameterWidget.cb_materials.findData(self.card_path)
|
||||
# set the current material in the cb widget
|
||||
self.choose_material(index)
|
||||
else:
|
||||
error_message = (
|
||||
"Due to some wrong material quantity units in data passed "
|
||||
"by the material editor, the material data was not changed.\n"
|
||||
)
|
||||
FreeCAD.Console.PrintError(error_message)
|
||||
QtGui.QMessageBox.critical(None, "Material data not changed", error_message)
|
||||
else:
|
||||
FreeCAD.Console.PrintLog("No changes where made by the material editor.\n")
|
||||
|
||||
def toggleInputFieldsReadOnly(self):
|
||||
if self.parameterWidget.chbu_allow_edit.isChecked():
|
||||
self.parameterWidget.input_fd_density.setReadOnly(False)
|
||||
@@ -575,11 +461,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
else:
|
||||
material[matProperty] = str(value)
|
||||
self.material = material
|
||||
if self.has_transient_mat is False:
|
||||
self.add_transient_material()
|
||||
else:
|
||||
self.set_transient_material()
|
||||
# print(inputfield_text)
|
||||
|
||||
# mechanical input fields
|
||||
def ym_changed(self):
|
||||
@@ -616,10 +497,6 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
material = self.material
|
||||
material["PoissonRatio"] = str(value)
|
||||
self.material = material
|
||||
if self.has_transient_mat is False:
|
||||
self.add_transient_material()
|
||||
else:
|
||||
self.set_transient_material()
|
||||
|
||||
# thermal input fields
|
||||
def tc_changed(self):
|
||||
@@ -712,29 +589,9 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
q = Units.Quantity(f"{sh_with_new_unit} {sh_new_unit}")
|
||||
self.parameterWidget.input_fd_specific_heat.setText(q.UserString)
|
||||
|
||||
# fill the combo box with cards **************************************************************
|
||||
def add_cards_to_combo_box(self):
|
||||
# fill combobox, in combo box the card name is used not the material name
|
||||
self.parameterWidget.cb_materials.clear()
|
||||
|
||||
mat_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Cards")
|
||||
sort_by_resources = mat_prefs.GetBool("SortByResources", False)
|
||||
|
||||
card_name_list = [] # [ [card_name, card_path, icon_path], ... ]
|
||||
|
||||
if sort_by_resources is True:
|
||||
for a_path in sorted(self.materials):
|
||||
card_name_list.append([self.cards[a_path], a_path, self.icons[a_path]])
|
||||
else:
|
||||
card_names_tmp = {}
|
||||
for path, name in self.cards.items():
|
||||
card_names_tmp[name] = path
|
||||
for a_name in sorted(card_names_tmp):
|
||||
a_path = card_names_tmp[a_name]
|
||||
card_name_list.append([a_name, a_path, self.icons[a_path]])
|
||||
|
||||
for mat in card_name_list:
|
||||
self.parameterWidget.cb_materials.addItem(QtGui.QIcon(mat[2]), mat[0], mat[1])
|
||||
# the whole card path is added to the combo box to make it unique
|
||||
# see def choose_material:
|
||||
# for assignment of self.card_path the path form the parameterWidget is used
|
||||
def set_from_editor(self, value):
|
||||
mat = self.material_manager.getMaterial(value)
|
||||
self.material = mat.Properties
|
||||
self.uuid = mat.UUID
|
||||
self.check_material_keys()
|
||||
self.set_mat_params_in_input_fields(self.material)
|
||||
|
||||
Reference in New Issue
Block a user