Le catalogue des types
Module d’exemple : hellotypes.
Les types d’élément se répartissent en deux familles.
Types forcément en lecture seule côté interface
ElementLight (indicateur d’état), ElementImg (image), ElementVideo (flux vidéo), ElementPrg (barre de progression ou spinner) — aucun d’entre eux n’a de sens en écriture directe depuis un client.
Image : la convention webroot
Un module écrit son fichier dans getWebroot() + "/" + getModuleName() + "/...", et donne à l’élément une URL relative à cet emplacement :
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);Le contrôleur n’appelle setWebroot() sur un module qu’après le retour de son constructeur. Tout code qui écrit un fichier dépendant du webroot doit donc être différé à l’itération suivante de la boucle d’événements :
QTimer::singleShot(0, this, [this]() {
// getWebroot() est maintenant garanti défini.
});ElementVideo suit exactement la même convention d’URL (OST::VideoData::url), pour un flux déjà existant par ailleurs.
Barre de progression et spinner : tous deux pilotés par une valeur
ElementPrg a deux présentations (prgtype: "bar" ou "spinner"), mais les deux sont déterminées par une valeur 0-100 — un spinner n’est pas un indicateur d’activité indéterminé, c’est un anneau dont le remplissage suit setPrgValue(), exactement comme la barre :
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);Types normalement éditables
ElementBool, ElementString, ElementInt, ElementFloat, ElementDate, ElementTime, ElementDateTime — tous peuvent être verrouillés en lecture seule au niveau de leur propriété (permission:0), indépendamment de tout réglage par élément (directedit, autoupdate) : le contrôle de permission est le premier vérifié, avant tout le reste.
Contraintes numériques et infobulle
Pour int/float, quatre clés JSON optionnelles supplémentaires :
"gain": { "type": "float", "directedit": true, "min": 0, "max": 100, "step": 1, "format": "%.0f", "hint": "Gain capteur" }min/max: bornes acceptées.step: incrément du contrôle côté client.format: format d’affichage (printf-style).hint: infobulle — disponible sur tous les types d’élément, pas seulement numériques.
Mélanger les types dans une seule propriété
Contrairement à INDI, où un vecteur ne contient qu’un seul type d’élément, une propriété OST peut librement mélanger des types différents :
"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: le client édite l’élément individuellement et l’envoie seul (SV) — appliqué immédiatement.directedit:false: l’élément ne peut être modifié que via un envoi groupé de toute la propriété (SA) — tous les éléments éditables de la propriété doivent être inclus dans cet envoi, sinon rien n’est appliqué. Côté client type, ça correspond à deux présentations différentes : un contrôle d’édition immédiate pour chaque élémentdirectedit:true, et un formulaire avec bouton “Enregistrer” regroupant tous les élémentsdirectedit:false.
Cette distinction est indépendante du type : dans l’exemple ci-dessus, bool1/string1/date1 s’éditent immédiatement, int1/float1 seulement via le formulaire groupé.