Créer des propriétés dynamiquement, en C++
Module d’exemple : hellodyn.
loadOstPropertiesFromFile() n’est qu’une commodité : elle appelle, pour chaque propriété et chaque élément du JSON, exactement les mêmes primitives qu’un module peut appeler lui-même directement, à tout moment de sa vie — à l’instanciation, ou bien plus tard, en réaction à une action utilisateur.
Construire une propriété à la main
OST::PropertyMulti *pm = new OST::PropertyMulti(
"hello", "Hello", OST::Permission::ReadOnly,
/* level1 */ "", /* level2 */ "", /* order */ "1",
/* hasProfile */ false, /* hasGrid */ false);
createProperty(pm);
OST::ElementString *message = new OST::ElementString("message", "Message", "1", "");
message->setValue("Hello, world!");
pm->addElt(message);Le constructeur de PropertyMulti nomme ses deux paramètres de hiérarchie level1/level2 (et c’est aussi le nom renvoyé au client dans le dump JSON). Mais la clé JSON d’un fichier .json de module est devcat/group, pas level1/level2 — deux noms différents pour la même chose, selon qu’on écrit du C++ ou du JSON. Une confusion facile à faire.
Chaque type d’élément a le même schéma de constructeur : ElementXxx(clé, libellé, ordre, info-bulle). addElt() doit être appelé après createProperty().
Pour ElementInt/ElementFloat, les contraintes numériques (min/max/step/format — mêmes clés qu’en JSON, voir Le catalogue des types) se posent après construction, par des setters dédiés :
OST::ElementFloat *step = new OST::ElementFloat("step", "Step size", "2", "");
step->setMinMax(1.0, 1000.0, false);
step->setStep(1.0, false);
step->setFormat("%.0f", false);
pm->addElt(step);Le dernier argument (false ici) est le même emitEvent que setValue() — pas la peine de prévenir le client d’un changement de métadonnée au moment où l’élément n’existe pas encore côté frontend.
Créer une propriété à la demande, pas au démarrage
Un bouton (ElementBool, directedit:true) peut déclencher la création plutôt que de la faire au démarrage :
void HelloDyn::onExternalEvent(OST::ExtEvent event)
{
if (event.ev != OST::ExtEvType::SV || event.prpkey != "actions") return;
if (event.eltkey == "create")
{
if (!getStore().contains("hello"))
{
OST::PropertyMulti *pm = new OST::PropertyMulti("hello", "Hello",
OST::Permission::ReadOnly, "", "", "2", false, false);
createProperty(pm);
OST::ElementString *message = new OST::ElementString("message", "Message", "1", "");
message->setValue("Hello, world! (créé à la demande)");
pm->addElt(message);
}
getEltBool("actions", "create")->setValue(false, true);
}
}Chaque branche repasse son propre bouton à false une fois l’action traitée — un bouton d’action est un déclencheur ponctuel, pas un interrupteur persistant.
Ajouter ou retirer un élément d’une propriété déjà existante
if (event.eltkey == "addfield")
{
OST::ElementString *field = new OST::ElementString(key, label, "", "");
field->setValue(value);
getProperty("hello")->addElt(field);
}
if (event.eltkey == "removefield")
{
getProperty("hello")->deleteElt(key);
}addElt()/deleteElt() notifient le client de la modification (un nouvel élément apparaît, ou disparaît, sans qu’un rechargement de page soit nécessaire).
PropertyMulti ne numérote pas ses éléments lui-même — c’est au module de générer des clés uniques (un compteur, par exemple) pour savoir lesquelles existent et dans quel ordre les retirer.