529 lines
25 KiB
QML
529 lines
25 KiB
QML
//========================================================================================================================================================================
|
|
// CONFIG_PAGES.QML
|
|
// Ce fichier traite la configuration des pages. La page permet notamment de :
|
|
// - Afficher, pour toutes les pages déjà configurées (et donc d'accéder à la configuration détaillée de l'une d'elle ; ou sa création)
|
|
// - valider/dévalider l'affichage d'une page via un bouton en bout de ligne basculable par clic-droit
|
|
// - Changer l'ordre d'affichage sur la page d'accueil
|
|
// La page est appelée depuis la page PARAMETRES_AVANCES, en cliquant sur "Batteries"
|
|
//========================================================================================================================================================================
|
|
|
|
import QtQuick 2.12
|
|
import QtQuick.Controls 2.12
|
|
import QtQml.Models 2.1
|
|
|
|
import qt.koriolan.shipheart 1.0
|
|
|
|
|
|
Shipheart_page {
|
|
id: page_config_pages
|
|
|
|
|
|
// Mis en forme :
|
|
readonly property double affichage_hauteur_utile: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas
|
|
readonly property int hauteur_bouton_droit: 80
|
|
|
|
readonly property double pourcentage_largeur_colonne_gauche: 0.75
|
|
readonly property double pourcentage_bandeau_bas_largeur_zone_retour: 1.0
|
|
readonly property int espace_colonnes_principales: 20
|
|
readonly property double pourcentage_largeur_bouton_affichage_dans_colonne_gauche: 0.15
|
|
|
|
readonly property int nombre_pages_affiches_sur_une_colonne: 8
|
|
|
|
readonly property int periode_init_raffraichissement_parametres: 1 // En ms
|
|
readonly property int periode_raffraichissement_parametres: 100 // En ms
|
|
|
|
// Affichage :
|
|
property int niveau_page: 0
|
|
|
|
// Modèles :
|
|
// Note : les modèles chargés dans 'main.qml' n'ont pas à être rechargés dans les pages suivantes
|
|
|
|
|
|
//===========================================================
|
|
// 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;
|
|
}
|
|
else {
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================
|
|
// Lorsque la page est sur le point d'être affichée dans la pile :
|
|
//===========================================================
|
|
StackView.onActivating: {
|
|
init_page(); // Permet que lors du retour sur la page, l'état des différentes variables soit mise à jour avant l'affichage proprement dit. Y compris lors de l'ouverture initiale...
|
|
}
|
|
|
|
// Titre de la page :
|
|
Shipheart_titre_1 {titre:qsTr("Configuration des pages"); hauteur: shipheart_hauteur_bandeau_haut}
|
|
|
|
//-------------------------------------------------------
|
|
// Ecran de gauche (liste des pages) :
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_affichage_gauche
|
|
x: 0
|
|
y: shipheart_hauteur_bandeau_haut;
|
|
width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2)
|
|
height: affichage_hauteur_utile
|
|
color: "transparent"
|
|
|
|
//-------------------------------------------------------------------
|
|
// Grille pour afficher les pages :
|
|
ListView {
|
|
id: grille_principale
|
|
|
|
property bool deplacement_en_cours: false // Indique si un déplacement (au global) est en cours ou pas
|
|
property int save_current_index: 0 // Permet de garder le Current_index du début du déplacement et de compenser les changements qui sont fait automatiquement, notamment en début et fin de liste. Le principe est qu'une fois le mouvement déclenché, ON NE CHANGE PAS de CurrentIndex !!
|
|
|
|
x: 0
|
|
y: 0
|
|
width: parent.width
|
|
height: parent.height
|
|
|
|
clip: true // Limite l'affichage des délégués dans la zone de ListView (sinon, on affiche au moins un délégué au-dessus et un en dessous...)
|
|
highlightRangeMode: ListView.StrictlyEnforceRange // Permet de faire défiler la liste jusqu'à ne garder que le dernier élément affiché
|
|
|
|
displaced: Transition { // Gère la transition lors d'un déplacement
|
|
NumberAnimation{
|
|
properties: "x,y" // Ici, on devrait pouvoir limiter à Y
|
|
duration: 500 // Vitesse à laquelle se déplacent les boutons lorsqu'on les déplace
|
|
}
|
|
}
|
|
|
|
model: modele_grille_principale
|
|
delegate: bouton_page
|
|
|
|
Component {
|
|
id: bouton_page
|
|
|
|
MouseArea {
|
|
id: dragArea_groupe // Zone correspondant à un seul bouton (on est dans le Delegate)
|
|
|
|
width: grille_principale.width
|
|
height: grille_principale.height / nombre_pages_affiches_sur_une_colonne
|
|
|
|
property bool bouton_appuye: false // On ne peut pas utiliser la propriété globale "deplacement_en_cours" car il faut une propriété par délégué
|
|
|
|
pressAndHoldInterval: 500; // Temporise avant de passer en mode "déplacement"
|
|
|
|
drag.target: bouton_appuye ? contenu_bouton_page : undefined
|
|
drag.axis: Drag.YAxis // On ne se déplace que sur l'axe Y
|
|
|
|
onClicked: {
|
|
shipheart_clic();
|
|
if (model.configurable) stackView.push("config_page_edition.qml", {"id_page": model.id})
|
|
}
|
|
|
|
onPressAndHold: {
|
|
shipheart_clic();
|
|
bouton_appuye = true // Indication (au niveau du bouton seul) du début de l'appui long donc du déplacement
|
|
grille_principale.deplacement_en_cours = true // Indication (au niveau de ListView) du début du déplacement
|
|
grille_principale.save_current_index = grille_principale.currentIndex; // Sauvegarde du CurrentIndex au début du déplacement
|
|
}
|
|
onReleased: {
|
|
bouton_appuye = false // Indication (au niveau du bouton seul) de la fin de l'appui long donc du déplacement
|
|
grille_principale.deplacement_en_cours = false // Indication (au niveau de ListView) de la fin du déplacement
|
|
grille_principale.currentIndex = grille_principale.save_current_index; // Restitution de la valeur initiale du CurrentIndex (a priori, pas nécessaire car mis à jour au fur et à mesure des changements dans "onCurrentIndexChanged")
|
|
|
|
}
|
|
|
|
Rectangle {
|
|
id: contenu_bouton_page
|
|
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
width: dragArea_groupe.width - 5
|
|
height: dragArea_groupe.height - 5
|
|
color: "transparent"
|
|
opacity: dragArea_groupe.bouton_appuye ? 0.6 : 1.0
|
|
|
|
//------------------------------------
|
|
// Bouton avec le nom de la page :
|
|
//------------------------------------
|
|
Rectangle {
|
|
height: parent.height - 5
|
|
width: (model.masquable) ?
|
|
((parent.width * (1 - pourcentage_largeur_bouton_affichage_dans_colonne_gauche)) - 10) :
|
|
parent.width
|
|
color: model.configurable ?
|
|
shipheart_couleur_fond_bouton :
|
|
"transparent"
|
|
border.width: 2
|
|
border.color: shipheart_couleur_fond_bouton
|
|
radius: shipheart_rayon_bouton
|
|
anchors {
|
|
left: parent.left
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Icone du bouton :
|
|
Rectangle { // Le passage par un rectangle avant l'image permet de centrer l'image sur le rectangle et pas juste caler les images à gauche (elles n'ont pas la même largeur donc elles n'étaient pas centrées les unes par rapport aux autres)
|
|
width: 35
|
|
height: parent.height
|
|
x: 20
|
|
color: "transparent"
|
|
visible: (model.type < shipheart_type_page_personnalisee_non_masquable)
|
|
Image {
|
|
source: (model.icone !== "") ? ("/images/" + model.icone) : "" // Sans le test, on génère un warning lorsque 'icone' est vide
|
|
sourceSize.height: parent.height * 0.5
|
|
sourceSize.width: parent.width
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
visible: (model.icone !== "")
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Texte du bouton :
|
|
Text {
|
|
visible: (model.type >= shipheart_type_page_personnalisee_non_masquable)
|
|
anchors.fill: parent
|
|
horizontalAlignment: Qt.AlignLeft
|
|
verticalAlignment: Qt.AlignVCenter
|
|
leftPadding: 20
|
|
text: model.nom
|
|
color: couleur_blanc_casse
|
|
font.pixelSize: 18
|
|
wrapMode: Label.Wrap
|
|
}
|
|
}
|
|
|
|
//------------------------------------
|
|
// Bouton Visible :
|
|
//------------------------------------
|
|
Rectangle {
|
|
x: (parent.width * (1 - pourcentage_largeur_bouton_affichage_dans_colonne_gauche))
|
|
height: parent.height - 10
|
|
width:(parent.width * pourcentage_largeur_bouton_affichage_dans_colonne_gauche)
|
|
anchors {
|
|
right: parent.right
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
radius: shipheart_rayon_bouton
|
|
color: shipheart_couleur_fond_bouton
|
|
visible: model.masquable
|
|
|
|
//----------------------------
|
|
// Coche verte ou croix rouge :
|
|
Image {
|
|
source: (model.priorite_affichage <= 0) ? "/images/faux.png" : "/images/vrai.png"
|
|
sourceSize.height: parent.height * 0.5
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
|
|
//----------------------------
|
|
MouseArea {
|
|
id: mouse_area_cdes_auto
|
|
x: 0
|
|
y: 0
|
|
width: parent.width
|
|
height: parent.height
|
|
pressAndHoldInterval: shipheart_mouse_press_and_hold_interval_long
|
|
|
|
onPressAndHold: {
|
|
shipheart_clic();
|
|
toggle_validite(model.index);
|
|
}
|
|
}
|
|
}
|
|
|
|
Drag.active: dragArea_groupe.bouton_appuye
|
|
Drag.source: dragArea_groupe
|
|
Drag.hotSpot.x: width / 2
|
|
Drag.hotSpot.y: height / 2
|
|
|
|
states: State{
|
|
when: dragArea_groupe.bouton_appuye
|
|
ParentChange {
|
|
target: contenu_bouton_page
|
|
parent: grille_principale
|
|
}
|
|
AnchorChanges {
|
|
target: contenu_bouton_page
|
|
anchors { // Necessaire pour autoriser le mouvement
|
|
horizontalCenter: undefined
|
|
verticalCenter: undefined
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DropArea {
|
|
enabled: (index !== 0) // On interdit de bouger la première ligne (Ephéméride)
|
|
anchors.fill: parent
|
|
onEntered: {
|
|
|
|
if (drag.source.DelegateModel.itemsIndex !== dragArea_groupe.DelegateModel.itemsIndex)
|
|
{
|
|
//console.log("\tMouvement de Source index = " + drag.source.DelegateModel.itemsIndex + " vers Dest index = " + dragArea.DelegateModel.itemsIndex)
|
|
modele_grille_principale.move(drag.source.DelegateModel.itemsIndex, dragArea_groupe.DelegateModel.itemsIndex, 1)
|
|
mise_a_jour_ordre_pages();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ListModel {
|
|
id: modele_grille_principale
|
|
}
|
|
|
|
Label {
|
|
anchors.fill: parent
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
verticalAlignment: Qt.AlignVCenter
|
|
visible: parent.count === 0
|
|
text: qsTr("Aucune page n'est encore configurée...")
|
|
color: couleur_rouge_transparent
|
|
font.pixelSize: 15
|
|
font.bold: true
|
|
wrapMode: Label.Wrap
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Ecran Droite :
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_affichage_droite
|
|
x: zone_affichage_gauche.width + espace_colonnes_principales
|
|
y: shipheart_hauteur_bandeau_haut + 5; // Le +5 permet d'aligner le haut du premier bouton de droite avec le haut du premier bouton de la liste de gauche (
|
|
width: (shipheart_largeur_page * (1 - pourcentage_largeur_colonne_gauche)) - (espace_colonnes_principales / 2)
|
|
height: affichage_hauteur_utile
|
|
color: "transparent"
|
|
|
|
Column {
|
|
anchors.fill: parent
|
|
spacing: 10
|
|
|
|
//----------------------
|
|
// Bouton + :
|
|
Rectangle {
|
|
width: parent.width
|
|
height: hauteur_bouton_droit
|
|
color: shipheart_couleur_fond_bouton
|
|
radius: shipheart_rayon_bouton
|
|
visible: !clavier.active
|
|
Text {
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.pixelSize: 40
|
|
text: qsTr("+")
|
|
color: couleur_blanc_casse
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
stackView.push("config_page_edition.qml", {"id_page": 0})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Bandeau bas :
|
|
//-------------------------------------------------------
|
|
Row {
|
|
x: 0
|
|
y: shipheart_hauteur_page - shipheart_hauteur_bandeau_bas;
|
|
width: shipheart_largeur_page;
|
|
height: shipheart_hauteur_bandeau_bas;
|
|
padding: 5
|
|
spacing: 5
|
|
|
|
//.................................................
|
|
// Bouton retour
|
|
//.................................................
|
|
Rectangle {
|
|
id: bandeau_bas_zone_retour
|
|
width: (parent.width * pourcentage_bandeau_bas_largeur_zone_retour) - parent.leftPadding - (parent.spacing / 2)
|
|
height: shipheart_hauteur_bandeau_bas - parent.topPadding - parent.bottomPadding;
|
|
radius: shipheart_rayon_bouton
|
|
color: shipheart_couleur_fond_bouton
|
|
Image {
|
|
source: "/images/icone_retour.png"
|
|
sourceSize.height: 30
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille.
|
|
id: mouse_area_bandeau_bas_zone_retour
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
stackView.pop()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Note : il est inutile de prévoir un Mousearea pour sortir de l'économiseur sur cette page puisqu'il
|
|
// est systématiquement bloqué pour toutes les pages lancées depuis 'Paramètres Avancés'.
|
|
|
|
|
|
|
|
//=============================================================================================================
|
|
// Init de la page
|
|
//=============================================================================================================
|
|
function init_page()
|
|
{
|
|
niveau_page = stackView.depth - 1; // Permet de stocker le niveau de la page dans la Stackview
|
|
|
|
mise_a_jour_donnees();
|
|
}
|
|
|
|
//=============================================================================================================
|
|
// Mise à jour des données
|
|
//=============================================================================================================
|
|
function mise_a_jour_donnees()
|
|
{
|
|
var req, res;
|
|
var i;
|
|
var nb_pages;
|
|
var type;
|
|
var configurable;
|
|
var masquable;
|
|
|
|
modele_grille_principale.clear(); // RAZ des valeurs existantes
|
|
|
|
req = 'SELECT Cle_primaire, ';
|
|
req += ' Nom, ';
|
|
req += ' Type, ';
|
|
req += ' Fichier, ';
|
|
req += ' Priorite_affichage ';
|
|
req += ' FROM TB_Pages ORDER BY ABS(Priorite_affichage), Cle_primaire';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb_pages = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb_pages; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
// Recherche du caractère configurable et/ou masquable de la page :
|
|
type = Number(res[2]);
|
|
switch(type)
|
|
{
|
|
//-------------------------------------------------
|
|
case shipheart_type_page_preconfiguree_ephemeride:
|
|
configurable = false;
|
|
masquable = false;
|
|
break;
|
|
|
|
//-------------------------------------------------
|
|
case shipheart_type_page_preconfiguree_chronometre:
|
|
case shipheart_type_page_personnalisee_minuteur:
|
|
case shipheart_type_page_preconfiguree_reveil:
|
|
configurable = false;
|
|
masquable = true;
|
|
break;
|
|
|
|
//-------------------------------------------------
|
|
case shipheart_type_page_personnalisee_non_masquable:
|
|
configurable = true;
|
|
masquable = false;
|
|
break;
|
|
|
|
//-------------------------------------------------
|
|
case shipheart_type_page_personnalisee_masquable:
|
|
configurable = true;
|
|
masquable = true;
|
|
break;
|
|
|
|
//-------------------------------------------------
|
|
case shipheart_type_page_inconnu:
|
|
continue;
|
|
}
|
|
|
|
// Mise à jour du modèle :
|
|
modele_grille_principale.append({
|
|
"id": Number(res[0]),
|
|
"nom": res[1],
|
|
"type": type,
|
|
"configurable": configurable,
|
|
"masquable": masquable,
|
|
"icone": (Number(res[2]) >= shipheart_type_page_personnalisee_non_masquable) ? "" : res[3], // On n'utilise les icones que pour les pages préconfigurées (et il faut bien faire la distinctions car les fichiers icones sont stockées dans 'images' alors que les fichiers silhouette sont stockées dans 'docs/images_silhouette')
|
|
"priorite_affichage": Number(res[4]) });
|
|
|
|
}
|
|
else break; // Ne devrait pas arriver....
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================================================
|
|
// Mise à jour de l'ordre des pages
|
|
//=============================================================================================================
|
|
function mise_a_jour_ordre_pages()
|
|
{
|
|
var req;
|
|
var i;
|
|
var new_priorite_affichage;
|
|
|
|
for (i = 0; i < modele_grille_principale.count; i++)
|
|
{
|
|
new_priorite_affichage = i + 1; // Nouvelle valeur arbitraire
|
|
|
|
if (modele_grille_principale.get(i).priorite_affichage < 0) new_priorite_affichage *= (-1); // Passage en négatif pour les pages déjà dévalidées
|
|
|
|
// Mise à jour dans le modele :
|
|
modele_grille_principale.set(i, { "priorite_affichage": new_priorite_affichage } );
|
|
|
|
// Mis à jour de la nouvelle valeur dans la BDD :
|
|
req = 'UPDATE TB_Pages SET Priorite_affichage=' + new_priorite_affichage + ' WHERE Cle_primaire=' + modele_grille_principale.get(i).id + ' ';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
bdd.requete_unique(req);
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================================================
|
|
// Bascule de la visibilité d'une page
|
|
//=============================================================================================================
|
|
function toggle_validite(index)
|
|
{
|
|
var req;
|
|
var priorite_affichage;
|
|
|
|
// Recherche de la valeur actuelle et calcul de la nouvelle :
|
|
priorite_affichage = modele_grille_principale.get(index).priorite_affichage * (-1);
|
|
|
|
// Mise à jour de la nouvelle valeur dans le modèle :
|
|
modele_grille_principale.set(index, {"priorite_affichage": priorite_affichage});
|
|
|
|
// Mis à jour de la nouvelle valeur dans la BDD :
|
|
req = 'UPDATE TB_Pages SET Priorite_affichage=' + priorite_affichage + ' WHERE Cle_primaire=' + modele_grille_principale.get(index).id + ' ';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
bdd.requete_unique(req);
|
|
}
|
|
}
|
|
|