278 lines
11 KiB
QML
278 lines
11 KiB
QML
import QtQuick 2.12
|
|
import QtQuick.Controls 2.12
|
|
import QtQuick.Layouts 1.12
|
|
|
|
import qt.koriolan.shipheart 1.0
|
|
|
|
// ============================================================================
|
|
// home.qml (client shipheart_wasm) - 4 domaines (circuit/batterie/capteur/
|
|
// reservoir), via l'API réelle (DataProvider). Écriture (consigne) sur
|
|
// circuit uniquement pour l'instant.
|
|
//
|
|
// Architecture : les onglets (familles) partagent UN SEUL ListModel (forme
|
|
// identique dans les 4 domaines : id/libelle/etat/actif). Les ÉLÉMENTS, en
|
|
// revanche, utilisent UN MODÈLE SÉPARÉ PAR DOMAINE - piège QML rencontré en
|
|
// pratique : un ListModel fige les champs reconnus ("rôles") dès sa première
|
|
// utilisation, même après clear() ; réutiliser un même modèle pour des formes
|
|
// JSON différentes (tension/intensite pour circuit, valeur/unite pour
|
|
// capteur...) laisse les champs propres à chaque domaine à 'undefined'.
|
|
// ============================================================================
|
|
|
|
Shipheart_page {
|
|
id: page_accueil
|
|
|
|
readonly property var domaines: ["circuit", "batterie", "capteur", "reservoir"]
|
|
readonly property var domaines_libelles: [qsTr("Circuits"), qsTr("Batteries"), qsTr("Capteurs"), qsTr("Réservoirs")]
|
|
property int domaine_actif_index: 0
|
|
readonly property string domaine_actif: domaines[domaine_actif_index]
|
|
|
|
readonly property int espace_onglets: 10
|
|
readonly property int rayon_onglets: 20
|
|
|
|
property int id_groupe: 0
|
|
|
|
ListModel { id: modele_onglets }
|
|
|
|
// Un ListModel par domaine, pour éviter le piège des "rôles" figés de QML :
|
|
ListModel { id: modele_elements_circuit }
|
|
ListModel { id: modele_elements_batterie }
|
|
ListModel { id: modele_elements_capteur }
|
|
ListModel { id: modele_elements_reservoir }
|
|
|
|
property var modele_elements_actuel: modele_elements_circuit
|
|
|
|
function modele_elements_pour(type) {
|
|
switch (type) {
|
|
case "circuit": return modele_elements_circuit;
|
|
case "batterie": return modele_elements_batterie;
|
|
case "capteur": return modele_elements_capteur;
|
|
case "reservoir": return modele_elements_reservoir;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
property DataProvider dataProvider: DataProvider {}
|
|
|
|
function charger_domaine(index) {
|
|
domaine_actif_index = index;
|
|
id_groupe = 0;
|
|
modele_onglets.clear();
|
|
modele_elements_actuel = modele_elements_pour(domaine_actif);
|
|
modele_elements_actuel.clear();
|
|
dataProvider.get_familles(domaine_actif);
|
|
}
|
|
|
|
Connections {
|
|
target: dataProvider
|
|
|
|
function onFamillesRecues(type, familles) {
|
|
if (type !== domaine_actif) return; // Réponse d'un domaine quitté entretemps - ignorée
|
|
modele_onglets.clear();
|
|
for (var i = 0; i < familles.length; i++) {
|
|
var f = familles[i];
|
|
modele_onglets.append({
|
|
"id": f.id,
|
|
"libelle": f.nom,
|
|
"etat": f.etat,
|
|
"actif": (f.id === id_groupe)
|
|
});
|
|
if (id_groupe === 0 && i === 0) {
|
|
id_groupe = f.id;
|
|
dataProvider.get_elements(domaine_actif, id_groupe);
|
|
}
|
|
}
|
|
}
|
|
|
|
function onElementsRecus(type, famille, elements) {
|
|
if (type !== domaine_actif || famille !== id_groupe) return;
|
|
var m = modele_elements_pour(type);
|
|
m.clear();
|
|
for (var j = 0; j < elements.length; j++) m.append(elements[j]);
|
|
}
|
|
|
|
function onCircuitModifie(id, succes) {
|
|
if (!succes) console.log("Échec de la commande sur le circuit " + id);
|
|
if (domaine_actif === "circuit" && id_groupe > 0) dataProvider.get_elements("circuit", id_groupe);
|
|
}
|
|
|
|
function onErreur(message) {
|
|
console.log("DataProvider erreur : " + message);
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: charger_domaine(0)
|
|
|
|
Timer {
|
|
interval: 1000
|
|
running: true
|
|
repeat: true
|
|
onTriggered: {
|
|
if (id_groupe > 0) {
|
|
dataProvider.get_elements(domaine_actif, id_groupe);
|
|
dataProvider.get_familles(domaine_actif);
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
spacing: 10
|
|
|
|
//-----------------------------------------------------------
|
|
// Sélecteur de domaine :
|
|
Row {
|
|
Layout.fillWidth: true
|
|
height: shipheart_hauteur_bandeau_haut
|
|
spacing: espace_onglets
|
|
|
|
Repeater {
|
|
model: domaines_libelles
|
|
delegate: Rectangle {
|
|
width: (page_accueil.width - 3 * espace_onglets) / 4
|
|
height: shipheart_hauteur_bandeau_haut
|
|
radius: rayon_onglets
|
|
color: (index === domaine_actif_index) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: modelData
|
|
color: couleur_blanc_casse
|
|
font.pixelSize: 13
|
|
font.bold: (index === domaine_actif_index)
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: charger_domaine(index)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Onglets (familles du domaine actif) :
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
height: shipheart_hauteur_bandeau_haut
|
|
color: "transparent"
|
|
visible: modele_onglets.count > 1
|
|
|
|
GridView {
|
|
id: grille_onglets
|
|
anchors.fill: parent
|
|
cellWidth: width / Math.max(1, Math.min(modele_onglets.count, 5))
|
|
cellHeight: shipheart_hauteur_bandeau_haut
|
|
model: modele_onglets
|
|
clip: true
|
|
|
|
delegate: Rectangle {
|
|
width: grille_onglets.cellWidth - 2
|
|
height: grille_onglets.cellHeight
|
|
radius: rayon_onglets
|
|
color: model.actif ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton
|
|
border.color: (model.etat === 2) ? "red" : (model.etat === 1) ? "orange" : "transparent"
|
|
border.width: 2
|
|
|
|
Text {
|
|
text: model.libelle
|
|
anchors.centerIn: parent
|
|
color: couleur_blanc_casse
|
|
font.pixelSize: 14
|
|
font.bold: model.actif
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
id_groupe = model.id;
|
|
for (var k = 0; k < modele_onglets.count; k++) {
|
|
modele_onglets.set(k, {"actif": (modele_onglets.get(k).id === model.id)});
|
|
}
|
|
dataProvider.get_elements(domaine_actif, id_groupe);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Éléments de la famille sélectionnée, dans le domaine actif :
|
|
GridView {
|
|
id: elements_grid
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
cellWidth: width / 2
|
|
cellHeight: height / 4
|
|
model: modele_elements_actuel
|
|
clip: true
|
|
|
|
delegate: Rectangle {
|
|
width: elements_grid.cellWidth - 4
|
|
height: elements_grid.cellHeight - 4
|
|
radius: 10
|
|
color: shipheart_couleur_fond_bouton
|
|
border.color: (model.etat === 2) ? "red" : (model.etat === 1) ? "orange" : "transparent"
|
|
border.width: 2
|
|
|
|
Column {
|
|
anchors.centerIn: parent
|
|
spacing: 4
|
|
|
|
Text {
|
|
text: model.nom
|
|
color: couleur_blanc_casse
|
|
font.pixelSize: 14
|
|
font.bold: true
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
Text {
|
|
text: {
|
|
switch (domaine_actif) {
|
|
case "circuit":
|
|
return model.tension.toFixed(1) + " V " + model.intensite.toFixed(2) + " A";
|
|
case "batterie":
|
|
return model.niveau.toFixed(0) + " % " + model.tension.toFixed(2) + " V";
|
|
case "capteur":
|
|
return model.valeur + (model.unite ? (" " + model.unite) : "");
|
|
case "reservoir":
|
|
return model.niveau.toFixed(0) + " % (" + model.capacite.toFixed(0) + " L)";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
color: couleur_blanc_casse
|
|
font.pixelSize: 12
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
// Indication visuelle discrète que l'élément est cliquable (circuits) :
|
|
Text {
|
|
visible: (domaine_actif === "circuit")
|
|
text: (model.consigne > 0) ? qsTr("● Marche (toucher pour arrêter)") : qsTr("○ Arrêt (toucher pour démarrer)")
|
|
color: (model.consigne > 0) ? "lightgreen" : couleur_blanc_casse
|
|
font.pixelSize: 10
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
enabled: (domaine_actif === "circuit")
|
|
onClicked: {
|
|
var nouvelle_consigne = (model.consigne > 0) ? 0 : 100;
|
|
dataProvider.set_circuit(model.id, nouvelle_consigne);
|
|
}
|
|
}
|
|
}
|
|
|
|
Label {
|
|
anchors.centerIn: parent
|
|
visible: elements_grid.count === 0
|
|
text: qsTr("Aucun élément dans ce groupe.")
|
|
color: couleur_rouge_transparent
|
|
}
|
|
}
|
|
}
|
|
}
|