import QtQuick 2.12 import QtQuick.Controls 2.12 import"fonctions_date_heure.js" as Fonctions_date_heure Popup { id: boite_dialogue_condition_horaire // Propriétés fixes : readonly property double pourcentage_largeur_page_popup: 0.7 readonly property double pourcentage_hauteur_page_popup: 0.7 readonly property int padding_popup: 20 readonly property double pourcentage_boite_dialogue_titre: 0.20 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.2 readonly property int hauteur_icones_tumblers: 35 readonly property int bouton_largeur: 200 readonly property int espace_tumblers: 20 readonly property int periode_init_raffraichissement_parametres: 1 // En ms readonly property int periode_raffraichissement_parametres: 1000 // En ms readonly property int step_timer_appui_long: 30 // en ms // Propriétés : property int valeur_timer_appui_long: 0 property int jour_en_cours: 0 property int valeur_tumbler_jour: 0 property int valeur_tumbler_heure: 0 property int valeur_tumbler_minute: 0 // Propriétés alias : property alias boutonOk: bouton_ok.visible property alias boutonAnnuler: bouton_annuler.visible property alias boutonSupprimer: bouton_supprimer.visible //------------------------------------------------- // Signaux : //------------------------------------------------- signal clicked(int bouton, int jour, int heure, int minute) // Valeurs à lire lorsque le "OnClicked' est activé //------------------------------------------------- // Init : //------------------------------------------------- onOpened: { // Activé une fois que le popup est complètement affiché mise_a_jour(); // Met à jour les valeurs courantes des 3 tumbler en fonction des paramètres passés } //=========================================================== // Timer periode raffraichissement parametres : //=========================================================== Timer { id: timer_raffraichissement_parametres interval: periode_init_raffraichissement_parametres triggeredOnStart: false running: true repeat: true onTriggered: { if (interval == periode_init_raffraichissement_parametres) { // Premier passage, 1ms après le premier chargement interval = periode_raffraichissement_parametres; init(); // Charge le modèle des 3 tumblers (dès l'ouverture de "config_event.qml" !) } } } //=========================================================== // Timer pour gérer les appuis longs : //=========================================================== Timer { id: timer_appui_long interval: step_timer_appui_long triggeredOnStart: false repeat: true onTriggered: { if (valeur_timer_appui_long < shipheart_mouse_press_and_hold_interval_tres_long) valeur_timer_appui_long+= step_timer_appui_long; else // Le fait de ne pas utilise le OnPressandHold permet d'être sût que la sortie se fait au même moment que la fin du comptage (sinon, on peut avoir de petits décalages) { timer_appui_long.running = false; valeur_timer_appui_long = 0; if (mousearea_bouton_supprimer.pressed) { boite_dialogue_condition_horaire.clicked(shipheart_boite_dialogue_bouton_3, 0, 0, 0); } } } } 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_condition_horaire.width - (2 * padding_popup) height: (boite_dialogue_condition_horaire.height - (2 * padding_popup) - (2 * affichage_boite_dialogue.spacing)) * pourcentage_boite_dialogue_titre color: "transparent" Image { id: image_titre source: "/images/condition_horaire.png" sourceSize.height: 80 anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } } } //========================================================================= // Choix : //========================================================================= Rectangle { id: zone_choix width: boite_dialogue_condition_horaire.width - (2 * padding_popup) height: (boite_dialogue_condition_horaire.height - (2 * padding_popup) - (2 * affichage_boite_dialogue.spacing)) * pourcentage_boite_dialogue_message color: "transparent" Row { anchors.horizontalCenter: parent.horizontalCenter spacing: espace_tumblers //----------------------------------- // Jour de la semaine : //----------------------------------- Rectangle { width: zone_choix.width * 0.3 height: zone_choix.height color: "transparent" Image { source: "/images/calendrier.png" sourceSize.height: hauteur_icones_tumblers anchors { top: parent.top horizontalCenter: parent.horizontalCenter } } Tumbler { id: tumbler_jour width: parent.width height: parent.height * 0.85 anchors { bottom: parent.bottom } visibleItemCount: 5 model: ListModel { } delegate: bouton_jour Component { id: bouton_jour 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_jour.currentIndex) ? couleur_blanc_casse : couleur_gris_pale font.pixelSize: 18 font.bold: (index === tumbler_jour.currentIndex) } } } background: Rectangle { color: couleur_gris_tres_fonce radius: shipheart_grand_rayon_bouton } } } //----------------------------------- // Heure : //----------------------------------- Rectangle { width: zone_choix.width * 0.3 height: zone_choix.height color: "transparent" Image { source: "/images/heure.png" sourceSize.height: hauteur_icones_tumblers anchors { top: parent.top horizontalCenter: parent.horizontalCenter } } 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.pixelSize: 18 font.bold: (index === tumbler_heure.currentIndex) } } } background: Rectangle { color: couleur_gris_tres_fonce radius: shipheart_grand_rayon_bouton } } } //----------------------------------- // Minute : //----------------------------------- Rectangle { width: zone_choix.width * 0.3 height: zone_choix.height color: "transparent" Image { source: "/images/minute.png" sourceSize.height: hauteur_icones_tumblers anchors { top: parent.top horizontalCenter: parent.horizontalCenter } visible: (tumbler_minute.opacity > 0) } 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 Behavior on opacity { NumberAnimation { duration: 300 } } 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.pixelSize: 18 font.bold: (index === tumbler_minute.currentIndex) } } } background: Rectangle { color: couleur_gris_tres_fonce radius: shipheart_grand_rayon_bouton } } } } } //========================================================================= // Boutons : //========================================================================= Row { height: (boite_dialogue_condition_horaire.height - (2 * padding_popup) - (2 * affichage_boite_dialogue.spacing)) * pourcentage_boite_dialogue_ligne_boutons anchors.horizontalCenter: parent.horizontalCenter spacing: 20 //....................................................... // Bouton Ok : //....................................................... Rectangle { id: bouton_ok width: bouton_largeur height: parent.height * 0.75 anchors.verticalCenter: parent.verticalCenter radius: shipheart_rayon_bouton color: couleur_gris_tres_fonce Label { id: bouton_ok_label anchors.centerIn: parent text: qsTr("OK") color: couleur_blanc_casse font.pixelSize:20 } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); boite_dialogue_condition_horaire.clicked(shipheart_boite_dialogue_bouton_1, tumbler_jour.model.get(tumbler_jour.currentIndex).valeur, tumbler_heure.model.get(tumbler_heure.currentIndex).valeur, tumbler_minute.model.get(tumbler_minute.currentIndex).valeur); } } } //....................................................... // Bouton Annuler : //....................................................... Rectangle { id: bouton_annuler width: bouton_largeur height: parent.height * 0.75 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_condition_horaire.clicked(shipheart_boite_dialogue_bouton_2, 0, 0, 0); } } } //....................................................... // Bouton de suppression //....................................................... Rectangle { id: bouton_supprimer width: bouton_largeur height: parent.height * 0.75 anchors.verticalCenter: parent.verticalCenter radius: shipheart_rayon_bouton color: couleur_gris_tres_fonce Rectangle { // Barre grandissante pour montrer durée d'appui vs tempo nécessaire : width: (valeur_timer_appui_long / shipheart_mouse_press_and_hold_interval_tres_long) * parent.width height: parent.height color: couleur_rouge_transparent radius: shipheart_rayon_bouton visible: mousearea_bouton_supprimer.pressed } Text { anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } font.pixelSize: 20 text: qsTr("Supprimer") color: couleur_blanc_casse } MouseArea { id: mousearea_bouton_supprimer anchors.fill: parent onPressed: { // Déclenché lors de l'appui inital timer_appui_long.running = true; valeur_timer_appui_long = 0; shipheart_clic(); } onClicked: { // Déclenché si l'appui n'a pas été suffisement long pour avoir un Press&Hold : timer_appui_long.running = false; valeur_timer_appui_long = 0; } onExited: { // Déclenché si le doigt sort de la zone du bouton (sinon, on continue à compter alors qu'on est sorti de la zone et même relaché le doigt !!) timer_appui_long.running = false; valeur_timer_appui_long = 0; } } } } } //============================================================================================================= // 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; //------------------------------------- // Jours de la semaine : //------------------------------------- tumbler_jour.model.clear(); // "Tous les jours" en premier : tumbler_jour.model.append( { "valeur": 8, "libelle": Fonctions_date_heure.nom_jour_semaine(8) } ); // Ajout de lundi à dimanche : for (i = 0; i < 7; i ++) { tumbler_jour.model.append( { "valeur": (i+1), "libelle": Fonctions_date_heure.nom_jour_semaine(i+1) } ); } //------------------------------------- // Heures : //------------------------------------- tumbler_heure.model.clear(); // Heures normales : for (i = 0; i < 24; i ++) { tumbler_heure.model.append( { "valeur": i, "libelle": ((i < 10) ? "0"+i : ""+i)} ); } // Heures spéciales // tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_fin_nuit, "libelle": qsTr("Fin de nuit") } ); tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_aube_nautique, "libelle": qsTr("Aube nautique") } ); // tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_aube, "libelle": qsTr("Aube") } ); tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_lever_soleil, "libelle": qsTr("Lever du soleil") } ); tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_zenith, "libelle": qsTr("Zénith") } ); tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_coucher_soleil, "libelle": qsTr("Coucher du soleil") } ); // tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_crepuscule, "libelle": qsTr("Crépuscule") } ); tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_crepuscule_nautique, "libelle": qsTr("Crépuscule nautique") } ); // tumbler_heure.model.append( { "valeur": shipheart_heure_speciale_debut_nuit, "libelle": qsTr("Début de nuit") } ); //------------------------------------- // Minutes : //------------------------------------- tumbler_minute.model.clear(); // Heures normales : for (i = 0; i < 60; i ++) { tumbler_minute.model.append( { "valeur": i, "libelle": ((i < 10) ? "0"+i : ""+i) } ); } } //============================================================================================================= // Mise à jour des données de la boite de dialogue //============================================================================================================= function mise_a_jour() { var i; //------------------------------------- // Jours de la semaine : //------------------------------------- // Rercherche de la valeur courante : for (i = 0; i < tumbler_jour.model.count; i ++) { if (tumbler_jour.model.get(i).valeur === valeur_tumbler_jour) { tumbler_jour.currentIndex = i; break; } } //------------------------------------- // 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; } } } }