diff --git a/qml.qrc b/qml.qrc index 0555682..aa4e73f 100644 --- a/qml.qrc +++ b/qml.qrc @@ -9,6 +9,7 @@ qml/detail_reservoir.qml qml/detail_circuit.qml qml/detail_batterie.qml + qml/responsive.js images/4g_lte_off.png images/4g_lte_on_1.png images/4g_lte_on_2.png diff --git a/qml/detail_batterie.qml b/qml/detail_batterie.qml index 4931004..26239d7 100644 --- a/qml/detail_batterie.qml +++ b/qml/detail_batterie.qml @@ -4,6 +4,8 @@ import QtQuick.Layouts 1.12 import qt.koriolan.shipheart 1.0 +import "responsive.js" as Responsive + // ============================================================================ // detail_batterie.qml - page de détail d'une batterie (valeur + historique). // ---------------------------------------------------------------------------- @@ -110,15 +112,16 @@ Shipheart_page { Text { text: nomElement - font.pixelSize: 22 + font.pixelSize: Responsive.police(22, page_detail_batterie.width) font.bold: true color: couleur_gris_pale } - // Sélecteur de variable (8 valeurs simples + énergie) : + // Sélecteur de variable (8 valeurs simples + énergie) - 4 colonnes + // normalement, 2 si écran étroit : GridLayout { Layout.fillWidth: true - columns: 4 + columns: Responsive.colonnesSelonLargeur(page_detail_batterie.width, variablesLibelles.length) columnSpacing: 8 rowSpacing: 8 @@ -126,7 +129,7 @@ Shipheart_page { model: variablesLibelles delegate: Rectangle { Layout.fillWidth: true - height: 34 + height: Math.max(34, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: (index === variableIndex) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton @@ -134,7 +137,7 @@ Shipheart_page { anchors.centerIn: parent text: modelData color: couleur_blanc_casse - font.pixelSize: 12 + font.pixelSize: Responsive.police(12, page_detail_batterie.width) font.bold: (index === variableIndex) } @@ -161,13 +164,13 @@ Shipheart_page { text: modeEnergie ? (totalWh >= 1000 ? (totalWh / 1000).toFixed(2) : totalWh.toFixed(1)) : valeurActuelle.toFixed(precisionAffichage) - font.pixelSize: 64 + font.pixelSize: Responsive.police(64, page_detail_batterie.width) font.bold: true color: couleur_blanc_casse } Text { text: modeEnergie ? (totalWh >= 1000 ? "kWh" : "Wh") : uniteAffichage - font.pixelSize: 20 + font.pixelSize: Responsive.police(20, page_detail_batterie.width) color: couleur_gris_pale Layout.alignment: Qt.AlignTop } @@ -179,22 +182,22 @@ Shipheart_page { visible: !modeEnergie spacing: 10 RowLayout { - Text { text: qsTr("Max"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMax.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } - Text { text: "[" + formater_date(tempsMax) + "]"; color: couleur_gris_moyen } + Text { text: qsTr("Max"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_batterie.width); Layout.preferredWidth: 90 } + Text { text: valeurMax.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_batterie.width); Layout.preferredWidth: 100 } + Text { text: "[" + formater_date(tempsMax) + "]"; color: couleur_gris_moyen; font.pixelSize: Responsive.police(13, page_detail_batterie.width) } } RowLayout { - Text { text: qsTr("Moyen"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMoyenne.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } + Text { text: qsTr("Moyen"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_batterie.width); Layout.preferredWidth: 90 } + Text { text: valeurMoyenne.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_batterie.width); Layout.preferredWidth: 100 } } RowLayout { - Text { text: qsTr("Min"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMin.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } - Text { text: "[" + formater_date(tempsMin) + "]"; color: couleur_gris_moyen } + Text { text: qsTr("Min"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_batterie.width); Layout.preferredWidth: 90 } + Text { text: valeurMin.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_batterie.width); Layout.preferredWidth: 100 } + Text { text: "[" + formater_date(tempsMin) + "]"; color: couleur_gris_moyen; font.pixelSize: Responsive.police(13, page_detail_batterie.width) } } RowLayout { - Text { text: qsTr("Delta (Max - Min)"); color: couleur_gris_pale; Layout.preferredWidth: 160 } - Text { text: (valeurMax - valeurMin).toFixed(precisionAffichage + 1) + " " + uniteAffichage; color: couleur_blanc_casse } + Text { text: qsTr("Delta (Max - Min)"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_batterie.width); Layout.preferredWidth: 160 } + Text { text: (valeurMax - valeurMin).toFixed(precisionAffichage + 1) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_batterie.width) } } } @@ -202,7 +205,7 @@ Shipheart_page { visible: modeEnergie text: qsTr("Consommation totale sur la période - détail par circuit ci-dessous") color: couleur_gris_pale - font.pixelSize: 13 + font.pixelSize: Responsive.police(13, page_detail_batterie.width) } } @@ -412,20 +415,20 @@ Shipheart_page { Text { text: modelData.nom color: (modelData.consigne > 0) ? couleur_blanc_casse : couleur_gris_moyen - font.pixelSize: 13 + font.pixelSize: Responsive.police(13, page_detail_batterie.width) Layout.preferredWidth: parent.width * 0.4 elide: Text.ElideRight } Text { text: modelData.energie_wh.toFixed(2) + " Wh" color: couleur_blanc_casse - font.pixelSize: 13 + font.pixelSize: Responsive.police(13, page_detail_batterie.width) Layout.preferredWidth: parent.width * 0.3 } Text { text: modelData.pourcentage.toFixed(1) + " %" color: couleur_gris_pale - font.pixelSize: 13 + font.pixelSize: Responsive.police(13, page_detail_batterie.width) Layout.fillWidth: true } } @@ -439,7 +442,7 @@ Shipheart_page { model: periodesLibelles delegate: Rectangle { Layout.preferredWidth: 140 - Layout.preferredHeight: 40 + Layout.preferredHeight: Math.max(40, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: (index === periodeIndex) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton @@ -447,6 +450,7 @@ Shipheart_page { anchors.centerIn: parent text: modelData color: couleur_blanc_casse + font.pixelSize: Responsive.police(14, page_detail_batterie.width) font.bold: (index === periodeIndex) } @@ -465,14 +469,14 @@ Shipheart_page { // Bouton retour : Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 44 + Layout.preferredHeight: Math.max(44, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: shipheart_couleur_fond_bouton Text { anchors.centerIn: parent text: "↩" - font.pixelSize: 20 + font.pixelSize: Responsive.police(20, page_detail_batterie.width) color: couleur_blanc_casse } diff --git a/qml/detail_capteur.qml b/qml/detail_capteur.qml index f6c2702..319c525 100644 --- a/qml/detail_capteur.qml +++ b/qml/detail_capteur.qml @@ -4,6 +4,8 @@ import QtQuick.Layouts 1.12 import qt.koriolan.shipheart 1.0 +import "responsive.js" as Responsive + // ============================================================================ // detail_capteur.qml - page de détail d'un capteur (valeur + historique). // ---------------------------------------------------------------------------- @@ -99,7 +101,7 @@ Shipheart_page { Text { text: nomElement - font.pixelSize: 22 + font.pixelSize: Responsive.police(22, page_detail_capteur.width) font.bold: true color: couleur_gris_pale } @@ -114,13 +116,13 @@ Shipheart_page { spacing: 4 Text { text: valeurActuelle.toFixed(precisionAffichage) - font.pixelSize: 64 + font.pixelSize: Responsive.police(64, page_detail_capteur.width) font.bold: true color: couleur_blanc_casse } Text { text: uniteAffichage - font.pixelSize: 20 + font.pixelSize: Responsive.police(20, page_detail_capteur.width) color: couleur_gris_pale Layout.alignment: Qt.AlignTop } @@ -131,22 +133,22 @@ Shipheart_page { ColumnLayout { spacing: 10 RowLayout { - Text { text: qsTr("Max"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMax.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } - Text { text: "[" + formater_date(tempsMax) + "]"; color: couleur_gris_moyen } + Text { text: qsTr("Max"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_capteur.width); Layout.preferredWidth: 90 } + Text { text: valeurMax.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_capteur.width); Layout.preferredWidth: 100 } + Text { text: "[" + formater_date(tempsMax) + "]"; color: couleur_gris_moyen; font.pixelSize: Responsive.police(13, page_detail_capteur.width) } } RowLayout { - Text { text: qsTr("Moyen"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMoyenne.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } + Text { text: qsTr("Moyen"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_capteur.width); Layout.preferredWidth: 90 } + Text { text: valeurMoyenne.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_capteur.width); Layout.preferredWidth: 100 } } RowLayout { - Text { text: qsTr("Min"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMin.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } - Text { text: "[" + formater_date(tempsMin) + "]"; color: couleur_gris_moyen } + Text { text: qsTr("Min"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_capteur.width); Layout.preferredWidth: 90 } + Text { text: valeurMin.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_capteur.width); Layout.preferredWidth: 100 } + Text { text: "[" + formater_date(tempsMin) + "]"; color: couleur_gris_moyen; font.pixelSize: Responsive.police(13, page_detail_capteur.width) } } RowLayout { - Text { text: qsTr("Delta (Max - Min)"); color: couleur_gris_pale; Layout.preferredWidth: 160 } - Text { text: (valeurMax - valeurMin).toFixed(precisionAffichage + 1) + " " + uniteAffichage; color: couleur_blanc_casse } + Text { text: qsTr("Delta (Max - Min)"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_capteur.width); Layout.preferredWidth: 160 } + Text { text: (valeurMax - valeurMin).toFixed(precisionAffichage + 1) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_capteur.width) } } } } @@ -271,7 +273,7 @@ Shipheart_page { model: periodesLibelles delegate: Rectangle { Layout.preferredWidth: 140 - Layout.preferredHeight: 40 + Layout.preferredHeight: Math.max(40, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: (index === periodeIndex) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton @@ -279,6 +281,7 @@ Shipheart_page { anchors.centerIn: parent text: modelData color: couleur_blanc_casse + font.pixelSize: Responsive.police(14, page_detail_capteur.width) font.bold: (index === periodeIndex) } @@ -297,14 +300,14 @@ Shipheart_page { // Bouton retour : Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 44 + Layout.preferredHeight: Math.max(44, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: shipheart_couleur_fond_bouton Text { anchors.centerIn: parent text: "↩" - font.pixelSize: 20 + font.pixelSize: Responsive.police(20, page_detail_capteur.width) color: couleur_blanc_casse } diff --git a/qml/detail_circuit.qml b/qml/detail_circuit.qml index 4c78bf1..c8c8bca 100644 --- a/qml/detail_circuit.qml +++ b/qml/detail_circuit.qml @@ -4,6 +4,8 @@ import QtQuick.Layouts 1.12 import qt.koriolan.shipheart 1.0 +import "responsive.js" as Responsive + // ============================================================================ // detail_circuit.qml - page de détail d'un circuit (valeur + historique). // ---------------------------------------------------------------------------- @@ -93,20 +95,24 @@ Shipheart_page { Text { text: nomElement - font.pixelSize: 22 + font.pixelSize: Responsive.police(22, page_detail_circuit.width) font.bold: true color: couleur_gris_pale } - // Sélecteur de variable (propre aux circuits/batteries) : - Row { + // Sélecteur de variable (propre aux circuits/batteries) - 4 colonnes + // normalement, 2x2 si écran étroit : + GridLayout { Layout.fillWidth: true - spacing: 8 + columns: Responsive.colonnesSelonLargeur(page_detail_circuit.width, variablesLibelles.length) + rowSpacing: 8 + columnSpacing: 8 + Repeater { model: variablesLibelles delegate: Rectangle { - width: (page_detail_circuit.width - 40 - 3 * 8) / 4 - height: 36 + Layout.fillWidth: true + Layout.preferredHeight: Responsive.HAUTEUR_MIN_TACTILE radius: 8 color: (index === variableIndex) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton @@ -114,7 +120,7 @@ Shipheart_page { anchors.centerIn: parent text: modelData color: couleur_blanc_casse - font.pixelSize: 13 + font.pixelSize: Responsive.police(13, page_detail_circuit.width) font.bold: (index === variableIndex) } @@ -139,13 +145,13 @@ Shipheart_page { spacing: 4 Text { text: valeurActuelle.toFixed(precisionAffichage) - font.pixelSize: 64 + font.pixelSize: Responsive.police(64, page_detail_circuit.width) font.bold: true color: couleur_blanc_casse } Text { text: uniteAffichage - font.pixelSize: 20 + font.pixelSize: Responsive.police(20, page_detail_circuit.width) color: couleur_gris_pale Layout.alignment: Qt.AlignTop } @@ -156,22 +162,22 @@ Shipheart_page { ColumnLayout { spacing: 10 RowLayout { - Text { text: qsTr("Max"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMax.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } - Text { text: "[" + formater_date(tempsMax) + "]"; color: couleur_gris_moyen } + Text { text: qsTr("Max"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_circuit.width); Layout.preferredWidth: 90 } + Text { text: valeurMax.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_circuit.width); Layout.preferredWidth: 100 } + Text { text: "[" + formater_date(tempsMax) + "]"; color: couleur_gris_moyen; font.pixelSize: Responsive.police(13, page_detail_circuit.width) } } RowLayout { - Text { text: qsTr("Moyen"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMoyenne.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } + Text { text: qsTr("Moyen"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_circuit.width); Layout.preferredWidth: 90 } + Text { text: valeurMoyenne.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_circuit.width); Layout.preferredWidth: 100 } } RowLayout { - Text { text: qsTr("Min"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMin.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } - Text { text: "[" + formater_date(tempsMin) + "]"; color: couleur_gris_moyen } + Text { text: qsTr("Min"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_circuit.width); Layout.preferredWidth: 90 } + Text { text: valeurMin.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_circuit.width); Layout.preferredWidth: 100 } + Text { text: "[" + formater_date(tempsMin) + "]"; color: couleur_gris_moyen; font.pixelSize: Responsive.police(13, page_detail_circuit.width) } } RowLayout { - Text { text: qsTr("Delta (Max - Min)"); color: couleur_gris_pale; Layout.preferredWidth: 160 } - Text { text: (valeurMax - valeurMin).toFixed(precisionAffichage + 1) + " " + uniteAffichage; color: couleur_blanc_casse } + Text { text: qsTr("Delta (Max - Min)"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_circuit.width); Layout.preferredWidth: 160 } + Text { text: (valeurMax - valeurMin).toFixed(precisionAffichage + 1) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_circuit.width) } } } } @@ -293,7 +299,7 @@ Shipheart_page { model: periodesLibelles delegate: Rectangle { Layout.preferredWidth: 140 - Layout.preferredHeight: 40 + Layout.preferredHeight: Math.max(40, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: (index === periodeIndex) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton @@ -301,6 +307,7 @@ Shipheart_page { anchors.centerIn: parent text: modelData color: couleur_blanc_casse + font.pixelSize: Responsive.police(14, page_detail_circuit.width) font.bold: (index === periodeIndex) } @@ -319,14 +326,14 @@ Shipheart_page { // Bouton retour : Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 44 + Layout.preferredHeight: Math.max(44, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: shipheart_couleur_fond_bouton Text { anchors.centerIn: parent text: "↩" - font.pixelSize: 20 + font.pixelSize: Responsive.police(20, page_detail_circuit.width) color: couleur_blanc_casse } diff --git a/qml/detail_reservoir.qml b/qml/detail_reservoir.qml index 146fbf9..1cb1063 100644 --- a/qml/detail_reservoir.qml +++ b/qml/detail_reservoir.qml @@ -4,6 +4,8 @@ import QtQuick.Layouts 1.12 import qt.koriolan.shipheart 1.0 +import "responsive.js" as Responsive + // ============================================================================ // detail_reservoir.qml - page de détail d'un réservoir (valeur + historique). // ---------------------------------------------------------------------------- @@ -90,7 +92,7 @@ Shipheart_page { Text { text: nomElement - font.pixelSize: 22 + font.pixelSize: Responsive.police(22, page_detail_reservoir.width) font.bold: true color: couleur_gris_pale } @@ -105,13 +107,13 @@ Shipheart_page { spacing: 4 Text { text: valeurActuelle.toFixed(precisionAffichage) - font.pixelSize: 64 + font.pixelSize: Responsive.police(64, page_detail_reservoir.width) font.bold: true color: couleur_blanc_casse } Text { text: uniteAffichage - font.pixelSize: 20 + font.pixelSize: Responsive.police(20, page_detail_reservoir.width) color: couleur_gris_pale Layout.alignment: Qt.AlignTop } @@ -122,22 +124,22 @@ Shipheart_page { ColumnLayout { spacing: 10 RowLayout { - Text { text: qsTr("Max"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMax.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } - Text { text: "[" + formater_date(tempsMax) + "]"; color: couleur_gris_moyen } + Text { text: qsTr("Max"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_reservoir.width); Layout.preferredWidth: 90 } + Text { text: valeurMax.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_reservoir.width); Layout.preferredWidth: 100 } + Text { text: "[" + formater_date(tempsMax) + "]"; color: couleur_gris_moyen; font.pixelSize: Responsive.police(13, page_detail_reservoir.width) } } RowLayout { - Text { text: qsTr("Moyen"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMoyenne.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } + Text { text: qsTr("Moyen"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_reservoir.width); Layout.preferredWidth: 90 } + Text { text: valeurMoyenne.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_reservoir.width); Layout.preferredWidth: 100 } } RowLayout { - Text { text: qsTr("Min"); color: couleur_gris_pale; Layout.preferredWidth: 90 } - Text { text: valeurMin.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; Layout.preferredWidth: 100 } - Text { text: "[" + formater_date(tempsMin) + "]"; color: couleur_gris_moyen } + Text { text: qsTr("Min"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_reservoir.width); Layout.preferredWidth: 90 } + Text { text: valeurMin.toFixed(precisionAffichage) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_reservoir.width); Layout.preferredWidth: 100 } + Text { text: "[" + formater_date(tempsMin) + "]"; color: couleur_gris_moyen; font.pixelSize: Responsive.police(13, page_detail_reservoir.width) } } RowLayout { - Text { text: qsTr("Delta (Max - Min)"); color: couleur_gris_pale; Layout.preferredWidth: 160 } - Text { text: (valeurMax - valeurMin).toFixed(precisionAffichage + 1) + " " + uniteAffichage; color: couleur_blanc_casse } + Text { text: qsTr("Delta (Max - Min)"); color: couleur_gris_pale; font.pixelSize: Responsive.police(13, page_detail_reservoir.width); Layout.preferredWidth: 160 } + Text { text: (valeurMax - valeurMin).toFixed(precisionAffichage + 1) + " " + uniteAffichage; color: couleur_blanc_casse; font.pixelSize: Responsive.police(13, page_detail_reservoir.width) } } } } @@ -262,7 +264,7 @@ Shipheart_page { model: periodesLibelles delegate: Rectangle { Layout.preferredWidth: 140 - Layout.preferredHeight: 40 + Layout.preferredHeight: Math.max(40, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: (index === periodeIndex) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton @@ -270,6 +272,7 @@ Shipheart_page { anchors.centerIn: parent text: modelData color: couleur_blanc_casse + font.pixelSize: Responsive.police(14, page_detail_reservoir.width) font.bold: (index === periodeIndex) } @@ -288,14 +291,14 @@ Shipheart_page { // Bouton retour : Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 44 + Layout.preferredHeight: Math.max(44, Responsive.HAUTEUR_MIN_TACTILE) radius: 8 color: shipheart_couleur_fond_bouton Text { anchors.centerIn: parent text: "↩" - font.pixelSize: 20 + font.pixelSize: Responsive.police(20, page_detail_reservoir.width) color: couleur_blanc_casse } diff --git a/qml/home.qml b/qml/home.qml index 4f1accb..1b460fb 100644 --- a/qml/home.qml +++ b/qml/home.qml @@ -4,6 +4,8 @@ import QtQuick.Layouts 1.12 import qt.koriolan.shipheart 1.0 +import "responsive.js" as Responsive + // ============================================================================ // home.qml (client shipheart_wasm) - 4 domaines (circuit/batterie/capteur/ // reservoir), via l'API réelle (DataProvider). Écriture (consigne) sur @@ -210,7 +212,7 @@ Shipheart_page { Text { anchors.centerIn: parent color: couleur_orange - font.pixelSize: 13 + font.pixelSize: Responsive.police(13, page_accueil.width) font.bold: true text: dataProvider.aDejaEteConnecte ? qsTr("⚠ Bateau non connecté depuis le %1").arg( @@ -220,17 +222,19 @@ Shipheart_page { } //----------------------------------------------------------- - // Sélecteur de domaine : - Row { + // Sélecteur de domaine - 4 colonnes normalement, 2x2 si écran étroit + // (téléphone en portrait, typiquement) : + GridLayout { Layout.fillWidth: true - height: shipheart_hauteur_bandeau_haut - spacing: espace_onglets + columns: Responsive.colonnesSelonLargeur(page_accueil.width, domaines_libelles.length) + rowSpacing: espace_onglets + columnSpacing: espace_onglets Repeater { model: domaines_libelles delegate: Rectangle { - width: (page_accueil.width - 3 * espace_onglets) / 4 - height: shipheart_hauteur_bandeau_haut + Layout.fillWidth: true + Layout.preferredHeight: Math.max(shipheart_hauteur_bandeau_haut, Responsive.HAUTEUR_MIN_TACTILE) radius: rayon_onglets color: (index === domaine_actif_index) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton @@ -238,7 +242,7 @@ Shipheart_page { anchors.centerIn: parent text: modelData color: couleur_blanc_casse - font.pixelSize: 13 + font.pixelSize: Responsive.police(13, page_accueil.width) font.bold: (index === domaine_actif_index) } @@ -253,18 +257,25 @@ Shipheart_page { } //----------------------------------------------------------- - // Onglets (familles du domaine actif) : + // Onglets (familles du domaine actif) - nombre de colonnes limité + // selon la largeur d'écran (2 si étroit, 5 sinon), hauteur du + // conteneur calculée pour s'adapter au nombre de lignes nécessaires + // (peut donc passer sur 2+ lignes sur un écran étroit) : Rectangle { + id: zone_onglets_familles + readonly property int colonnesOnglets: Responsive.colonnesSelonLargeur(page_accueil.width, modele_onglets_actuel.count) + readonly property int lignesOnglets: Math.ceil(modele_onglets_actuel.count / colonnesOnglets) + Layout.fillWidth: true - height: shipheart_hauteur_bandeau_haut + Layout.preferredHeight: lignesOnglets * Math.max(shipheart_hauteur_bandeau_haut, Responsive.HAUTEUR_MIN_TACTILE) color: "transparent" visible: modele_onglets_actuel.count > 1 GridView { id: grille_onglets anchors.fill: parent - cellWidth: width / Math.max(1, Math.min(modele_onglets_actuel.count, 5)) - cellHeight: shipheart_hauteur_bandeau_haut + cellWidth: width / zone_onglets_familles.colonnesOnglets + cellHeight: Math.max(shipheart_hauteur_bandeau_haut, Responsive.HAUTEUR_MIN_TACTILE) model: modele_onglets_actuel clip: true @@ -280,7 +291,7 @@ Shipheart_page { text: model.libelle anchors.centerIn: parent color: couleur_blanc_casse - font.pixelSize: 14 + font.pixelSize: Responsive.police(14, page_accueil.width) font.bold: model.actif } @@ -333,7 +344,7 @@ Shipheart_page { Text { text: model.nom color: couleur_blanc_casse - font.pixelSize: 16 + font.pixelSize: Responsive.police(16, page_accueil.width) font.bold: true anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter @@ -362,7 +373,7 @@ Shipheart_page { } } color: couleur_blanc_casse - font.pixelSize: 12 + font.pixelSize: Responsive.police(12, page_accueil.width) anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter } @@ -378,7 +389,7 @@ Shipheart_page { text: (model.consigne > 0) ? qsTr("On") : qsTr("Off") color: (model.consigne > 0) ? couleur_green_yellow : couleur_blanc_casse - font.pixelSize: 18 + font.pixelSize: Responsive.police(18, page_accueil.width) anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter } diff --git a/qml/responsive.js b/qml/responsive.js new file mode 100644 index 0000000..e29274f --- /dev/null +++ b/qml/responsive.js @@ -0,0 +1,47 @@ +.pragma library + +// ============================================================================ +// responsive.js - fonctions utilitaires pour un affichage adaptatif (PC, +// tablette, téléphone). Même principe que fonctions.js/fonctions_date_heure.js +// côté natif (bibliothèque JS partagée, importée par les pages qui en ont +// besoin) - cf synthèse, chantier "responsive". +// ============================================================================ + +// Seuil en dessous duquel l'écran est considéré "étroit" (bascule en mise en +// page compacte - typiquement un téléphone en portrait) : +var SEUIL_ECRAN_ETROIT = 700; + +function estEtroit(largeur) { + return largeur < SEUIL_ECRAN_ETROIT; +} + +// Taille de police proportionnelle à la largeur d'écran disponible, avec un +// plancher et un plafond pour rester lisible sur petit écran et raisonnable +// sur grand écran PC. 'base' est la taille pensée pour un écran de référence +// (~950px de large, l'ordre de grandeur habituel de test de ce projet). +function police(base, largeur) { + var largeurReference = 950; + var taille = base * (largeur / largeurReference); + var plancher = base * 0.6; + var plafond = base * 1.3; + if (taille < plancher) taille = plancher; + if (taille > plafond) taille = plafond; + return Math.round(taille); +} + +// Nombre de colonnes adapté à la largeur RÉELLEMENT disponible et au nombre +// d'éléments à afficher, plutôt qu'un simple seuil binaire "écran étroit/ +// large" - chaque bouton reste au moins 'largeurMinBouton' de large, quel que +// soit le nombre d'éléments (qui peut varier dynamiquement - ex: familles +// créées/supprimées par l'utilisateur, différent d'un domaine à l'autre) : +var LARGEUR_MIN_BOUTON = 130; + +function colonnesSelonLargeur(largeurDisponible, nombreElements, largeurMinBouton) { + if (largeurMinBouton === undefined) largeurMinBouton = LARGEUR_MIN_BOUTON; + var colonnesPossibles = Math.max(1, Math.floor(largeurDisponible / largeurMinBouton)); + return Math.max(1, Math.min(nombreElements, colonnesPossibles)); +} + +// Hauteur minimale garantie pour une cible tactile (bouton), quelle que soit +// l'échelle par ailleurs - recommandation usuelle d'accessibilité (~44px) : +var HAUTEUR_MIN_TACTILE = 44;