In SMTK 23.01, a designer can set the units of any ValueItemDefinition which is the base class used to represent String, Integer, and DoubleItem Definitions. The units are represented as a string and is used in the UI to indicate the units the value is assumed to be specified in.
There is now a call to take this to the next level and formally support units and unit conversion.
When setting the value of the DoubleItem with the current setValue(double) method, it would be assumed that the value is in the default units specified by the designer. If the value is specified with its own units then if the units are different from the default, a unit conversion would take place. In either case, the value() method would always return the value in the default units. In the case of unit conversion there would be the need to access the value the user entered as well as the units specified.
We could support either specifying the value and units using two separate line edit widgets (line edit and combobox) or with a single line edit with a validator and completer.
Note that the second approach would require the UI to somehow display the default units (in this case I’ve added them to the label),
The UI should also provide a mechanism to display the value in the default/preferred units. This could be as simple as having over the widget and using a tooltip or providing a checkbox to display the converted form. The former would take up less space.
Note: if there are no default units specified then SMTK would assume the value is unites and no unit information would be displayed.
SMTK would delegate the task of doing the conversion to an existing Open-Source library such as:
- Move the units specification to DoubleItemDefinition instead of ValueItemDefinition, unless folks can think of use cases where Integers and/or Strings can also benefit from having unit support.
- Add one of the two possible APIs to DoubleItem to specify a value with units:
- setValue(double val, const std::string& units)
- setValue(const std::string& valueWithUnits)
- Add one of the two possible API’s to DoubleItem to retrieve the original information:
- double value(std::string& units) const
- std::string value() const - Note that we could also use the existing valueAsString method
- Add the ability to save the original entries in the XML/JSON file formats
In the original post we had said that we would be using an existing open source units library. We took a closer look at:
Both these libraries had conversion issues when dealing with fractional powers. Though the cases in which these are needs are very few, the fact that they process these cases incorrectly means that if a fractional power is specified in error, the software will in some cases not catch it.
In the case of Boost::units, the focus is on compiler-time support and not run-time which is what is needed in this situation.
As a result we are writing our own open source units library.
- DoubleItemDefinition - no changes are needed since the concept of units is supported by ValueItemDefinition
- value(int i) - will return the item’s ith value in the units specified in its definition. If the definition’s units is empty then units are not supported and no conversion of the value that was specified is performed.
- specifiedValue(int i, std::string& units) - will return the item’s ith value in the units specified in setValue(…) methods. In this case no conversion is performed.
- convertValue(int i, const std::string& units, double& val) - will attempt to return the value in the specified units. If no conversion is possible it will return false
- setValue(int i, double val) - assumes that the ith value being specified is in the same units as its definition
- setValue(int i, double val, const std::string& units) - will convert the value if needed to appropriate units. If there is not possible conversion between the units specified in the definition and those passed into setValue, no assignment is performed and the method will return false
- setStringValue(int i, const std::string& val, const std::string& units)
setValueAsString(int i, const std::string& valAndUnits)
- Edge Cases
- Either Definition or Specified units are not specified- in this case the method will fail
- Edge Cases
In terms of member variables:
- m_value (current) - the value of the item in the units of the definition.
- m_specifiedString (new) - the specified value as a string
- m_specifiedUnits (new) - the specified value of the units (maybe)