The type catalog

Example module: hellotypes.

Element types fall into two families.

Types that are necessarily read-only on the interface side

ElementLight (status indicator), ElementImg (image), ElementVideo (video stream), ElementPrg (progress bar or spinner) — none of them make sense as a direct write from a client.

Image: the webroot convention

A module writes its file to getWebroot() + "/" + getModuleName() + "/...", and gives the element a URL relative to that location:

QDir dir;
dir.mkdir(getWebroot() + "/" + getModuleName());
atomicSaveJpeg(img, getWebroot() + "/" + getModuleName() + "/photo.jpeg");

OST::ImgData data;
data.mUrlJpeg = getModuleName() + "/photo.jpeg";
getEltImg("display", "photo")->setValue(data, true);
getWebroot() isn’t defined yet inside the constructor

The controller only calls setWebroot() on a module after its constructor has returned. Any code that writes a file depending on the webroot must therefore be deferred to the next iteration of the event loop:

QTimer::singleShot(0, this, [this]() {
    // getWebroot() est maintenant garanti défini.
});

ElementVideo follows exactly the same URL convention (OST::VideoData::url), for a stream that already exists elsewhere.

Progress bar and spinner: both driven by a value

ElementPrg has two presentations (prgtype: "bar" or "spinner"), but both are driven by a 0-100 value — a spinner is not an indeterminate activity indicator, it’s a ring whose fill follows setPrgValue(), exactly like the bar:

getEltPrg("display", "progress")->setPrgValue(42.0, true);
getEltPrg("display", "spinner")->setPrgValue(42.0, true);   // oui, le spinner aussi
getEltPrg("display", "spinner")->setDynLabel("En cours...", true);

Normally editable types

ElementBool, ElementString, ElementInt, ElementFloat, ElementDate, ElementTime, ElementDateTime — all of them can be locked to read-only at the level of their property (permission:0), independently of any per-element setting (directedit, autoupdate): the permission check is the first one applied, ahead of everything else.

Numeric constraints and tooltip

For int/float, four additional optional JSON keys:

"gain": { "type": "float", "directedit": true, "min": 0, "max": 100, "step": 1, "format": "%.0f", "hint": "Gain capteur" }
  • min/max: accepted bounds.
  • step: increment of the control on the client side.
  • format: display format (printf-style).
  • hint: tooltip — available on all element types, not just numeric ones.

Mixing types within a single property

Unlike INDI, where a vector only ever contains a single element type, an OST property can freely mix different types:

"editabledata": {
  "permission": 2,
  "e": {
    "bool1":   { "type": "bool",   "directedit": true },
    "string1": { "type": "string", "directedit": true },
    "int1":    { "type": "int" },
    "float1":  { "type": "float" },
    "date1":   { "type": "date",   "directedit": true }
  }
}

directedit:true vs directedit:false

  • directedit:true: the client edits the element individually and sends it on its own (SV) — applied immediately.
  • directedit:false: the element can only be modified via a grouped send of the whole property (SA) — all editable elements of the property must be included in that send, otherwise nothing is applied. On a typical client, this corresponds to two different presentations: an immediate-edit control for each directedit:true element, and a form with a “Save” button grouping all the directedit:false elements.

This distinction is independent of type: in the example above, bool1/string1/date1 are edited immediately, int1/float1 only through the grouped form.