[Material] fix major bug of wrong decimals
This PR fixes the long-standing major bug that for languages using ',' as decimal separator the material editor was useless. (bug no. 10 in https://forum.freecad.org/viewtopic.php?t=56912) the issue was that the value was handled as text. This PR: - using a spinbox instead if a text edit to modify numbers (has also the advantage to be able to change values by spinning) - sets min/max properly for all number data types - also avoid rounding artifacts when changing Float values
This commit is contained in:
@@ -25,6 +25,7 @@ __author__ = "Yorik van Havre, Bernd Hahnebach"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
import os
|
||||
import sys
|
||||
from PySide import QtCore, QtGui, QtSvg
|
||||
|
||||
import FreeCAD
|
||||
@@ -617,6 +618,8 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate):
|
||||
def __init__(self):
|
||||
""
|
||||
|
||||
self.matproperty = ""
|
||||
self.Value = ""
|
||||
super(MaterialsDelegate, self).__init__()
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
@@ -635,7 +638,7 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate):
|
||||
row = index.row()
|
||||
|
||||
PP = group.child(row, 0)
|
||||
matproperty = PP.text().replace(" ", "") # remove spaces
|
||||
self.matproperty = PP.text().replace(" ", "") # remove spaces
|
||||
|
||||
TT = group.child(row, 2)
|
||||
if TT:
|
||||
@@ -644,9 +647,9 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate):
|
||||
Type = "String"
|
||||
|
||||
VV = group.child(row, 1)
|
||||
Value = VV.text()
|
||||
self.Value = VV.text()
|
||||
|
||||
editor = matProperWidget(parent, matproperty, Type, Value)
|
||||
editor = matProperWidget(parent, self.matproperty, Type, self.Value)
|
||||
|
||||
elif column == 0:
|
||||
if group.text() == "User defined":
|
||||
@@ -676,11 +679,39 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate):
|
||||
lineEdit = editor.children()[1]
|
||||
item.setText(lineEdit.text())
|
||||
|
||||
elif Type == "Float":
|
||||
# avoid rounding artifacts
|
||||
inputValue = float('%.6g' % editor.value())
|
||||
item.setText(str(inputValue))
|
||||
|
||||
elif Type == "Quantity":
|
||||
if not hasattr(FreeCAD.Units, self.matproperty):
|
||||
FreeCAD.Console.PrintError(
|
||||
"Error: property '{}' is a quantity but has no unit defined\n"
|
||||
.format(self.matproperty)
|
||||
)
|
||||
return
|
||||
# we must use the unit of the input value because the
|
||||
# "Gui::QuantitySpinBox" uses e.g. for the density always the mm-based unit
|
||||
# kg/mm^3, also when the input value is in kg/^3.
|
||||
# E.g. when the input is e.g. "7875 kg/m^3" and we would pass "7875" as rawValue
|
||||
# and "kg/m^3" as unit, we would get "7875 kg/mm^3" as result. If we try to be
|
||||
# clever and input "7875e-6" as rawValue and "kg/m^3" as unit we get
|
||||
# "7875e-6 kg/m^3" as result. If we input "7875e-6" as rawValue and "kg/mm^3"
|
||||
# as unit we get also "7875e-6 kg/m^3" as result.
|
||||
if not self.Value:
|
||||
# for empty (not yet set properties) we use the matproperty unit
|
||||
unit = getattr(FreeCAD.Units, self.matproperty)
|
||||
quantity = FreeCAD.Units.Quantity(1, unit)
|
||||
item.setText(str(editor.value()) + " " + quantity.getUserPreferred()[2])
|
||||
else:
|
||||
# since we checked we have a quantity, we can use split() to get the unit
|
||||
item.setText(str(editor.value()) + " " + self.Value.split()[1])
|
||||
|
||||
else:
|
||||
super(MaterialsDelegate, self).setEditorData(editor, index)
|
||||
|
||||
|
||||
|
||||
# ************************************************************************************************
|
||||
# ************************************************************************************************
|
||||
def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
|
||||
@@ -715,9 +746,26 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
|
||||
lineEdit.setText(Value)
|
||||
|
||||
elif Type == "Quantity":
|
||||
widget = ui.createWidget("Gui::InputField")
|
||||
# We don't use a Gui::QuantitySpinBox widget because depending on the value,
|
||||
# the unit might change. For some inputs there is no way to do this right,
|
||||
# see the comment above in "def setEditorData". Moreover it is error-prone to provide
|
||||
# a unit as in the Gui::QuantitySpinBox widget because users likely delete the unit or
|
||||
# change it accidentally. It is therefore better not to display the unit while editing.
|
||||
widget = ui.createWidget("Gui::DoubleSpinBox")
|
||||
|
||||
if minimum is None:
|
||||
widget.setMinimum(-1*sys.float_info.max)
|
||||
else:
|
||||
widget.setMinimum(minimum)
|
||||
if maximum is None:
|
||||
widget.setMaximum(sys.float_info.max)
|
||||
else:
|
||||
widget.setMaximum(maximum)
|
||||
|
||||
# we must increase the digits before we can set the value
|
||||
# 6 is sufficient as some metarial cards use e.g. "0.000011"
|
||||
widget.setDecimals(6)
|
||||
|
||||
# set quantity if possible
|
||||
# for properties with an underscored number (vectorial values),
|
||||
# we must strip the part after the first underscore to obtain the bound unit
|
||||
# since in cardutils.py in def get_material_template
|
||||
@@ -727,30 +775,36 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
|
||||
matpropertyNum = matproperty.rstrip('0123456789')
|
||||
matproperty = matpropertyNum
|
||||
|
||||
if hasattr(FreeCAD.Units, matproperty):
|
||||
unit = getattr(FreeCAD.Units, matproperty)
|
||||
quantity = FreeCAD.Units.Quantity(1, unit)
|
||||
widget.setProperty("unit", quantity.getUserPreferred()[2])
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning(
|
||||
"Not known unit for property: {}. Probably the Quantity does not have a unit.\n"
|
||||
.format(matproperty)
|
||||
)
|
||||
if Value:
|
||||
widget.setValue(float(Value.split()[0]))
|
||||
|
||||
elif Type == "Integer":
|
||||
widget = ui.createWidget("Gui::UIntSpinBox")
|
||||
if minimum is None:
|
||||
widget.setMinimum(0)
|
||||
else:
|
||||
widget.setMinimum(minimum)
|
||||
if maximum is None:
|
||||
widget.setMaximum(sys.maxsize)
|
||||
else:
|
||||
widget.setMaximum(maximum)
|
||||
|
||||
elif Type == "Float":
|
||||
widget = ui.createWidget("Gui::PrefDoubleSpinBox")
|
||||
widget = ui.createWidget("Gui::DoubleSpinBox")
|
||||
# the magnetic permeability is the parameter for which many decimals matter
|
||||
# the most however, even for this, 6 digits are sufficient
|
||||
widget.setDecimals(6)
|
||||
# for almost all Float parameters of materials a step of 1 would be too large
|
||||
widget.setSingleStep(0.1)
|
||||
if minimum is None:
|
||||
widget.setProperty("minimum", -1e12)
|
||||
widget.setMinimum(sys.float_info.min)
|
||||
else:
|
||||
widget.setMinimum(minimum)
|
||||
if maximum is None:
|
||||
widget.setProperty("maximum", 1e12)
|
||||
widget.setMaximum(sys.float_info.max)
|
||||
else:
|
||||
widget.setMaximum(maximum)
|
||||
widget.setValue(float(Value))
|
||||
|
||||
elif Type == "Enumerator":
|
||||
widget = ui.createWidget("Gui::PrefComboBox")
|
||||
@@ -773,15 +827,6 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
|
||||
else:
|
||||
widget = QtGui.QLineEdit()
|
||||
|
||||
if minimum is not None:
|
||||
widget.setProperty("minimum", minimum)
|
||||
if maximum is not None:
|
||||
widget.setProperty("maximum", maximum)
|
||||
if stepsize is not None:
|
||||
widget.setProperty("stepsize", stepsize)
|
||||
if precision is not None:
|
||||
widget.setProperty("precision", precision)
|
||||
|
||||
widget.setProperty("Type", Type)
|
||||
|
||||
widget.setParent(parent)
|
||||
|
||||
Reference in New Issue
Block a user