import QtQuick 2.12 import QtQuick.Controls 2.12 Popup { id: boite_dialogue_minuteur // Propriétés fixes : readonly property double pourcentage_largeur_page_popup: 0.8 readonly property double pourcentage_hauteur_page_popup: 0.8 readonly property int padding_popup: 20 readonly property double pourcentage_boite_dialogue_titre: 0.2 readonly property double pourcentage_boite_dialogue_message: 1 - pourcentage_boite_dialogue_titre - pourcentage_boite_dialogue_ligne_boutons readonly property double pourcentage_boite_dialogue_ligne_boutons: 0.15 readonly property int bouton_hauteur: 60 readonly property double pourcentage_zone_tumblers: 0.75 readonly property int bouton_largeur: 200 readonly property int espace_tumblers: 20 // Propriétés : property bool flag_init: true property int valeur_tumbler_heure: 0 property int valeur_tumbler_minute: 0 property int valeur_tumbler_seconde: 0 // Propriétés alias : //------------------------------------------------- // Signaux : //------------------------------------------------- signal clicked(int bouton, int heure, int minute, int seconde) // Valeurs à lire lorsque le "OnClicked' est activé //------------------------------------------------- // Ouverture : //------------------------------------------------- onAboutToShow: { // Activé une fois quand le popup va être affiché init(); // L'init n'a d'utilité que lorsqu'on va l'afficher... } onOpened: { // Quand la page est affichée mise_a_jour(); // Nb : si on le fait à la suite de l'init, la première maj ne se fait pas car la page n'est pas encore ouverte... } //------------------------------------------------- // Fermeture : //------------------------------------------------- onAboutToHide: { } x: (shipheart_largeur_page * (1 - pourcentage_largeur_page_popup)) / 2; y: (shipheart_hauteur_page * (1 - pourcentage_hauteur_page_popup)) / 2; width: shipheart_largeur_page * pourcentage_largeur_page_popup; height: shipheart_hauteur_page * pourcentage_hauteur_page_popup; padding: padding_popup modal: true // focus: true // SDIR # 224 : Il ne faut PAS activer le focus. Sinon, à la fermeture, le focus précédent est réactivé (comme le dernier TextField par exemple) closePolicy: Popup.NoAutoClose //Popup.CloseOnPressOutside background: Rectangle { color: shipheart_couleur_fond_boite_dialogue_niveau_0 radius: 20 } Column { id: affichage_boite_dialogue spacing: 20 //========================================================================= // Titre : //========================================================================= Rectangle { id: titre_boite_dialogue width: boite_dialogue_minuteur.width - (2 * padding_popup) height: (boite_dialogue_minuteur.height - (2 * padding_popup) - (2 * affichage_boite_dialogue.spacing)) * pourcentage_boite_dialogue_titre color: "transparent" Image { id: image_titre source: "/images/sablier.png" sourceSize.height: 100 anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } } } //========================================================================= // Zone principale : //========================================================================= Rectangle { id: zone_principale width: boite_dialogue_minuteur.width - (2 * padding_popup) height: (boite_dialogue_minuteur.height - (2 * padding_popup) - (2 * affichage_boite_dialogue.spacing)) * pourcentage_boite_dialogue_message color: "transparent" //------------------------------------------ // Tumblers de sélection manuelle : //------------------------------------------ Row { id: zone_tumblers width: parent.width * pourcentage_zone_tumblers height: parent.height spacing: espace_tumblers //----------------------------------- // Heure : //----------------------------------- Rectangle { width: zone_tumblers.width * 0.3 height: zone_tumblers.height color: "transparent" Text { anchors.top: parent.top width: parent.width height: parent.height - tumbler_heure.height horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: qsTr("Heures") color: couleur_blanc_casse font.pixelSize: 18 } Tumbler { id: tumbler_heure width: parent.width height: parent.height * 0.85 anchors { bottom: parent.bottom } visibleItemCount: 5 model: ListModel { } delegate: bouton_heure Component { id: bouton_heure Rectangle { color: couleur_gris_fonce opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) text: model.libelle color: (index === tumbler_heure.currentIndex) ? couleur_blanc_casse : couleur_gris_pale font.family: "Montserrat" font.pixelSize: 26 font.bold: (index === tumbler_heure.currentIndex) } } } background: Rectangle { color: couleur_gris_tres_fonce radius: shipheart_grand_rayon_bouton } } } //----------------------------------- // Minute : //----------------------------------- Rectangle { width: zone_tumblers.width * 0.3 height: zone_tumblers.height color: "transparent" Text { anchors.top: parent.top width: parent.width height: parent.height - tumbler_minute.height visible: (tumbler_heure.model.get(tumbler_heure.currentIndex) !== undefined) ? // Sinon, génère un warning au démarrage... (tumbler_heure.model.get(tumbler_heure.currentIndex).valeur <= 23) : true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: qsTr("Minutes") color: couleur_blanc_casse font.pixelSize: 18 } Tumbler { id: tumbler_minute width: parent.width height: parent.height * 0.85 anchors { bottom: parent.bottom } visibleItemCount: 5 model: ListModel { } delegate: bouton_minute opacity : (tumbler_heure.model.get(tumbler_heure.currentIndex) !== undefined) ? // Sinon, génère un warning au démarrage... ((tumbler_heure.model.get(tumbler_heure.currentIndex).valeur <= 23) ? 1.0 : 0) : 1.0 Component { id: bouton_minute Rectangle { color: couleur_gris_fonce opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) text: model.libelle color: (index === tumbler_minute.currentIndex) ? couleur_blanc_casse : couleur_gris_pale font.family: "Montserrat" font.pixelSize: 26 font.bold: (index === tumbler_minute.currentIndex) } } } background: Rectangle { color: couleur_gris_tres_fonce radius: shipheart_grand_rayon_bouton } } } //----------------------------------- // Secondes : //----------------------------------- Rectangle { width: zone_tumblers.width * 0.3 height: zone_tumblers.height color: "transparent" Text { anchors.top: parent.top width: parent.width height: parent.height - tumbler_minute.height visible: (tumbler_heure.model.get(tumbler_heure.currentIndex) !== undefined) ? // Sinon, génère un warning au démarrage... (tumbler_heure.model.get(tumbler_heure.currentIndex).valeur <= 23) : true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: qsTr("Secondes") color: couleur_blanc_casse font.pixelSize: 18 } Tumbler { id: tumbler_seconde width: parent.width height: parent.height * 0.85 anchors { bottom: parent.bottom } visibleItemCount: 5 model: ListModel { } delegate: bouton_seconde opacity : (tumbler_heure.model.get(tumbler_heure.currentIndex) !== undefined) ? // Sinon, génère un warning au démarrage... ((tumbler_heure.model.get(tumbler_heure.currentIndex).valeur <= 23) ? 1.0 : 0) : 1.0 Component { id: bouton_seconde Rectangle { color: couleur_gris_fonce opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) text: model.libelle color: (index === tumbler_seconde.currentIndex) ? couleur_blanc_casse : couleur_gris_pale font.family: "Montserrat" font.pixelSize: 26 font.bold: (index === tumbler_seconde.currentIndex) } } } background: Rectangle { color: couleur_gris_tres_fonce radius: shipheart_grand_rayon_bouton } } } } //------------------------------------------ // Boutons de droite : //------------------------------------------ Column { id: colonne_boutons height: parent.height width: parent.width * (1 - pourcentage_zone_tumblers) anchors.right: parent.right spacing: 5 Repeater { model: ListModel { id: modele_boutons_preprogrammes } // Bouton proprement dit : Rectangle { width: parent.width height: (colonne_boutons.height - ((modele_boutons_preprogrammes.count - 1) * colonne_boutons.spacing)) / modele_boutons_preprogrammes.count radius: shipheart_rayon_bouton color: couleur_gris_tres_fonce Label { anchors.centerIn: parent text: model.libelle color: couleur_blanc_casse font.pixelSize:18 } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); valeur_tumbler_heure = model.heure; valeur_tumbler_minute = model.minute; valeur_tumbler_seconde = model.seconde; mise_a_jour(); } } } } } } //========================================================================= // Boutons de bas de fenêtre : //========================================================================= Row { height: (boite_dialogue_minuteur.height - (2 * padding_popup) - (2 * affichage_boite_dialogue.spacing)) * pourcentage_boite_dialogue_ligne_boutons anchors.horizontalCenter: parent.horizontalCenter spacing: 20 //....................................................... // Bouton Annuler : //....................................................... Rectangle { id: bouton_annuler width: bouton_largeur height: bouton_hauteur anchors.verticalCenter: parent.verticalCenter radius: shipheart_rayon_bouton color: couleur_gris_tres_fonce Label { id: bouton_annuler_label anchors.centerIn: parent text: qsTr("Annuler") color: couleur_blanc_casse font.pixelSize:20 } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); boite_dialogue_minuteur.clicked(shipheart_boite_dialogue_bouton_2, 0, 0, 0); } } } //....................................................... // Bouton Ok / Démarrer : //....................................................... Rectangle { id: bouton_ok width: bouton_largeur height: bouton_hauteur anchors.verticalCenter: parent.verticalCenter radius: shipheart_rayon_bouton color: couleur_gris_tres_fonce Label { anchors.centerIn: parent text: qsTr("Démarrer") color: mousearea_demarrer.enabled ? couleur_blanc_casse : couleur_gris_moyen font.pixelSize:20 } MouseArea { id: mousearea_demarrer anchors.fill: parent enabled: (!flag_init) && ( (tumbler_heure.model.get(tumbler_heure.currentIndex).valeur !== 0) || (tumbler_minute.model.get(tumbler_minute.currentIndex).valeur !== 0) || (tumbler_seconde.model.get(tumbler_seconde.currentIndex).valeur !== 0) ) onClicked: { shipheart_clic(); boite_dialogue_minuteur.clicked(shipheart_boite_dialogue_bouton_1, tumbler_heure.model.get(tumbler_heure.currentIndex).valeur, tumbler_minute.model.get(tumbler_minute.currentIndex).valeur, tumbler_seconde.model.get(tumbler_seconde.currentIndex).valeur); } } } } } //============================================================================================================= // Transitions d'ouverture et de fermeture de la boite de dialogue //============================================================================================================= enter: Transition { ParallelAnimation { NumberAnimation { property: "opacity" from: 0.0 to: 1.0 //easing.type: Easing.InElastic duration: 200 } NumberAnimation { property: "scale" from: 0.0 to: 1.0 // easing.type: Easing.OutBack duration: 200 } } } exit: Transition { ParallelAnimation { NumberAnimation { property: "opacity" from: 1.0 to: 0.0 duration: 200 } NumberAnimation { property: "scale" from: 1.0 to: 0.0 duration: 200 } } } //============================================================================================================= // Init des données de la boite de dialogue //============================================================================================================= function init() { var i; flag_init = true; // On est obligé de le renseigne manuellement car la fonction 'init()' est appelée à chaque ouverture (et la valeur par défaut, qu'à l'ouverture initiale...) //------------------------------------- // Heures : //------------------------------------- tumbler_heure.model.clear(); for (i = 0; i < 24; i ++) { tumbler_heure.model.append( { "valeur": i, "libelle": ((i < 10) ? "0"+i : ""+i)} ); } //------------------------------------- // Minutes : //------------------------------------- tumbler_minute.model.clear(); for (i = 0; i < 60; i ++) { tumbler_minute.model.append( { "valeur": i, "libelle": ((i < 10) ? "0"+i : ""+i) } ); } //------------------------------------- // secondes : //------------------------------------- tumbler_seconde.model.clear(); for (i = 0; i < 60; i ++) { tumbler_seconde.model.append( { "valeur": i, "libelle": ((i < 10) ? "0"+i : ""+i) } ); } modele_boutons_preprogrammes.clear(); modele_boutons_preprogrammes.append( {"libelle": "00:01:00", "heure": 0, "minute": 1, "seconde": 0 } ); modele_boutons_preprogrammes.append( {"libelle": "00:03:00", "heure": 0, "minute": 3, "seconde": 0 } ); modele_boutons_preprogrammes.append( {"libelle": "00:05:00", "heure": 0, "minute": 5, "seconde": 0 } ); modele_boutons_preprogrammes.append( {"libelle": "00:15:00", "heure": 0, "minute": 15, "seconde": 0 } ); modele_boutons_preprogrammes.append( {"libelle": "00:30:00", "heure": 0, "minute": 30, "seconde": 0 } ); modele_boutons_preprogrammes.append( {"libelle": "01:00:00", "heure": 1, "minute": 0, "seconde": 0 } ); flag_init = false; } //============================================================================================================= // Mise à jour des données de la boite de dialogue //============================================================================================================= function mise_a_jour() { var i; //------------------------------------- // Heures : //------------------------------------- // Rercherche de la valeur courante : for (i = 0; i < tumbler_heure.model.count; i ++) { if (tumbler_heure.model.get(i).valeur === valeur_tumbler_heure) { tumbler_heure.currentIndex = i; break; } } //------------------------------------- // Minutes : //------------------------------------- // Rercherche de la valeur courante : for (i = 0; i < tumbler_minute.model.count; i ++) { if (tumbler_minute.model.get(i).valeur === valeur_tumbler_minute) { tumbler_minute.currentIndex = i; break; } } //------------------------------------- // Secondes : //------------------------------------- // Rercherche de la valeur courante : for (i = 0; i < tumbler_seconde.model.count; i ++) { if (tumbler_seconde.model.get(i).valeur === valeur_tumbler_seconde) { tumbler_seconde.currentIndex = i; break; } } } }