Parameter
This section describes the interface of the Parameter class, along with
Component one of two pillar concepts of the VSlib. This class
provides a representation for a runtime-settable, via specialized web-hosted GUI,
parameters of Component class. They are strongly bound, and Parameters
can only be defined in Component and Component-derived classes.
General interface
Parameter is a templated class, and the template parameter is the stored
type. Currently, the following types are supported:
Type class |
Types |
|---|---|
Boolean |
|
Signed integer |
|
Unsigned integer |
|
Floating point |
|
Strings |
|
Enumerations |
User-defined |
Parameters holding numerical types (integers, floating-point) can optionally have defined
lower and upper limits.
Parameter is always defined inside a Component class, for example:
#include "component.h"
using namespace vslib;
class CustomComponent : public Component
{
CustomComponent(std::string_view name, Component& parent)
: Component("CustomType", name, parent),
param(*this, "scalar", 0.0, 10.0)
{
}
Parameter<double> param;
};
In the example above, the 0.0 and 10.0 are lower and upper limits for param
Parameter, respectively.
Parameter provides seamless interactions with scalar types, that means
you can use the Parameter as if it was the scalar type it stores:
#include "customComponent.h"
void your_function(RootComponent& root)
{
CustomComponent component("custom", root);
component.param; // returns the current double-type value of the CustomComponent's param
component.param.value(); // returns the same value as above but explicitly
}
In case of Parameters that are holding std::arrays, there three ways to interact with that array.
Assuming the following definition:
#include "component.h"
using namespace vslib;
class CustomComponent : public Component
{
CustomComponent(std::string_view name, Component& parent)
: Component("CustomType", name, parent),
param(*this, "array", 0.0, 10.0)
{
}
Parameter<std::array<double, 3>> param; // the array's size is fixed at definition
};
where limits 0.0 and 10.0 apply to each array element, individually.
#include "customComponent.h"
void your_function(RootComponent& root)
{
CustomComponent component("custom", root);
// 1. Get the reference to the entire array:
auto& array = component.param.value();
// 2. Refer to an array element by operator[]:
auto& element = component.param.value()[2]; // returns the third element
// 3. Iterate over the array as if it was an std::array:
for (const auto& element : component.param.value())
{
// use element as if it was just a double-type value
}
}
For more details regarding the API, see the API documentation for Parameter.
Parameter setting
The Parameter value is not code-settable. The interface to set values directly is not enabled,
and they can be treated as read-only in the code. This is why it is safe to place them in the public
interface of you Component. The Parameter value can be only set via specialized GUI,
the Vloop parameter setter, a part of the FGC Commander.
The values stored by the Parameter are double-buffered to ensure safety of read-write cycle.
Whenever you access the value, the read-buffer value is returned. The value-setter GUI interacts only
with the write-buffer. The buffers are swapped and synchronised by the Component owning this
Parameter when all the checks performed by the setter and Component’s verifyParameters()
method were successful. If any of the checks showed an issue, the new value is not accepted, and
the write buffer is re-synchronised with the read-buffer.
The value-setting logic includes the following checks:
type correctness
for numerical types: whether the new value fits in the limits
for arrays: the length must agree
for enums: whether the new value exists in the enum
any validation logic implemented by the user in
Component’sverifyParameters()method
Type correctness checks that there is no loss of information. For example, there will be no warning when
you set a 32-bit integer value to a float Parameter, but the opposite combination would
return a warning. Equally, C++ would not warn the user in case an implicit cast is done between boolean and
integer type (e.g. value of 2 would be interpreted as true), and signed and unsigned integers,
potentially leading to confusing values being set like -1 to an unsigned integer due to overflow.
Parameters have a special method to inform whether their value has been already set by the external
GUI: isInitialized(). Until the Parameter is successfully set for the first time, this method
will return false.