InterfaceGPS 0.1.0
Interface embarquée Qt pour navigation, multimédia, caméra et télémétrie
Chargement...
Recherche...
Aucune correspondance
clavier.cpp
Aller à la documentation de ce fichier.
1
9#include "clavier.h"
10#include <QVBoxLayout>
11#include <QHBoxLayout>
12#include <QRegularExpression>
13
14Clavier::Clavier(QWidget *parent) : QDialog(parent), majusculeActive(true), isSymbolMode(false)
15{
16 setWindowTitle("Clavier GPS");
17
18 // Dimensions fixes adaptées à l'écran embarqué
19 this->setWindowState(Qt::WindowFullScreen);
20 currentLayout = AZERTY;
21
22 QVBoxLayout *mainLayout = new QVBoxLayout(this);
23 mainLayout->setSpacing(5);
24 mainLayout->setContentsMargins(8, 8, 8, 8);
25
26 // Pousse le clavier vers le bas de l'écran
27 mainLayout->addStretch(1);
28
29 // --- LISTE DE SUGGESTIONS ---
30 suggestionList = new QListWidget(this);
31 suggestionList->setVisible(false);
32 suggestionList->setMaximumHeight(100);
33 suggestionList->setStyleSheet("font-size: 16px; background: white; color: black; border-radius: 10px;");
34 mainLayout->addWidget(suggestionList);
35
36 // --- CHAMP DE SAISIE ---
37 lineEdit = new QLineEdit(this);
38 lineEdit->setFixedHeight(45);
39 lineEdit->setStyleSheet("font-size: 18px; padding: 10px; font-weight: bold; background: #2a2f3a; color: white; border-radius: 8px;");
40 mainLayout->addWidget(lineEdit);
41
42 // Si on clique sur une suggestion, on remplit le champ de saisie et on masque la liste
43 connect(suggestionList, &QListWidget::itemClicked, this, [=](QListWidgetItem *item){
44 lineEdit->setText(item->text());
45 suggestionList->hide();
46 emit textChangedExternally(lineEdit->text());
47 });
48
49 // --- GRILLE DES TOUCHES ---
50 gridLayout = new QGridLayout();
51 gridLayout->setSpacing(4);
52
53 int btnW = 65;
54 int btnH = 50;
55 QString keyStyle = "QPushButton { font-size: 16px; font-weight: bold; border-radius: 8px; background: #333a4a; color: white; } "
56 "QPushButton:pressed { background: #4a5468; }";
57
58 // 1. Ligne des chiffres
59 QStringList chiffres = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"};
60 for (int i = 0; i < chiffres.size(); ++i) {
61 QPushButton *btn = new QPushButton(chiffres[i], this);
62 btn->setFixedSize(btnW, btnH);
63 btn->setStyleSheet(keyStyle);
64 connect(btn, &QPushButton::clicked, this, &Clavier::handleButton);
65 gridLayout->addWidget(btn, 0, i);
66 }
67
68 // Bouton de suppression (Backspace)
69 QPushButton *btnDel = new QPushButton("⌫", this);
70 btnDel->setFixedSize(80, btnH);
71 btnDel->setStyleSheet("QPushButton { font-size: 26px; background: #852222; color: white; border-radius: 8px; font-weight: bold; }");
72 connect(btnDel, &QPushButton::pressed, this, &Clavier::startDeleteDelay);
73 connect(btnDel, &QPushButton::released, this, &Clavier::stopDelete);
74 gridLayout->addWidget(btnDel, 0, 10);
75
76 // 2. Lignes de lettres
77 QStringList r1 = {"A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P"};
78 QStringList r2 = {"Q", "S", "D", "F", "G", "H", "J", "K", "L", "M"};
79 QStringList r3 = {"W", "X", "C", "V", "B", "N"};
80
81 // Lambda générique pour instancier les rangées de lettres
82 auto createRow = [&](const QStringList& keys, int rowIdx, QList<QPushButton*>& list, int colOffset = 0) {
83 for (int i = 0; i < keys.size(); ++i) {
84 QPushButton *btn = new QPushButton(keys[i], this);
85 btn->setFixedSize(btnW, btnH);
86 btn->setStyleSheet(keyStyle);
87 list.append(btn);
88 allButtons.append(btn);
89 connect(btn, &QPushButton::pressed, this, &Clavier::startLongPress);
90 connect(btn, &QPushButton::released, this, &Clavier::stopLongPress);
91 connect(btn, &QPushButton::clicked, this, &Clavier::handleButton);
92 gridLayout->addWidget(btn, rowIdx, i + colOffset);
93 }
94 };
95
96 createRow(r1, 1, row1Buttons);
97 createRow(r2, 2, row2Buttons);
98 createRow(r3, 3, row3Buttons, 1);
99
100 // 3. Boutons spéciaux
101 apostropheButton = new QPushButton("'", this);
102 apostropheButton->setFixedSize(btnW, btnH);
103 apostropheButton->setStyleSheet(keyStyle);
104 allButtons.append(apostropheButton);
105 connect(apostropheButton, &QPushButton::clicked, this, &Clavier::handleButton);
106 gridLayout->addWidget(apostropheButton, 3, 8);
107
108 shiftButton = new QPushButton("⇧", this);
109 shiftButton->setFixedSize(80, btnH);
110 shiftButton->setStyleSheet(keyStyle);
111 connect(shiftButton, &QPushButton::clicked, this, &Clavier::toggleShift);
112 gridLayout->addWidget(shiftButton, 3, 9, 1, 2);
113
114 langueButton = new QPushButton("🌍 AZERTY", this);
115 langueButton->setFixedSize(140, btnH);
116 langueButton->setStyleSheet(keyStyle);
117 connect(langueButton, &QPushButton::clicked, this, &Clavier::switchLayout);
118 gridLayout->addWidget(langueButton, 4, 0, 1, 2);
119
120 switchButton = new QPushButton("123?", this);
121 switchButton->setFixedSize(100, btnH);
122 switchButton->setStyleSheet(keyStyle);
123 connect(switchButton, &QPushButton::clicked, this, &Clavier::switchKeyboard);
124 gridLayout->addWidget(switchButton, 4, 2);
125
126 QPushButton *btnSpace = new QPushButton("ESPACE", this);
127 btnSpace->setFixedSize(250, btnH);
128 btnSpace->setStyleSheet(keyStyle);
129 connect(btnSpace, &QPushButton::clicked, this, &Clavier::addSpace);
130 gridLayout->addWidget(btnSpace, 4, 3, 1, 4);
131
132 QPushButton *btnUnderscore = new QPushButton("_", this);
133 btnUnderscore->setFixedSize(btnW, btnH);
134 btnUnderscore->setStyleSheet(keyStyle);
135 connect(btnUnderscore, &QPushButton::clicked, this, &Clavier::addUnderscore);
136 gridLayout->addWidget(btnUnderscore, 4, 7);
137
138 QPushButton *btnVal = new QPushButton("✔", this);
139 btnVal->setFixedSize(100, btnH);
140 btnVal->setStyleSheet("QPushButton { background-color: #2e7d32; color: white; font-size: 28px; font-weight: bold; border-radius: 8px; }");
141 connect(btnVal, &QPushButton::clicked, this, &Clavier::validateText);
142 gridLayout->addWidget(btnVal, 4, 9, 1, 2);
143
144 // 4. Clavier des symboles alternatifs (Masqué par défaut)
145 QStringList syms = {"@","#","$","%","&","*","(",")","-","+","=","/","\\","{","}","[","]",";",":","\"","<",">",",",".","?","!","|"};
146 int sRow = 1, sCol = 0;
147 for (const QString &s : syms) {
148 QPushButton *sb = new QPushButton(s, this);
149 sb->setFixedSize(btnW, btnH);
150 sb->setStyleSheet(keyStyle);
151 sb->setVisible(false);
152 symbolButtons.append(sb);
153 connect(sb, &QPushButton::clicked, this, &Clavier::handleButton);
154 gridLayout->addWidget(sb, sRow, sCol++);
155 if (sCol > 9) { sCol = 0; sRow++; }
156 }
157
158 mainLayout->addLayout(gridLayout);
159
160 // --- CONFIGURATION DES TIMERS (Interaction prolongée) ---
161 deleteTimer = new QTimer(this);
162 deleteDelayTimer = new QTimer(this);
163 deleteDelayTimer->setSingleShot(true);
164 connect(deleteDelayTimer, &QTimer::timeout, this, &Clavier::startDelete);
165 connect(deleteTimer, &QTimer::timeout, this, &Clavier::deleteChar);
166
167 longPressTimer = new QTimer(this);
168 longPressTimer->setSingleShot(true);
169 connect(longPressTimer, &QTimer::timeout, this, &Clavier::handleLongPress);
170
171 // --- DICTIONNAIRE DES ACCENTS ---
172 accentMap.insert("e", {"é", "è", "ê", "ë"});
173 accentMap.insert("a", {"à", "â"});
174 accentMap.insert("i", {"î", "ï"});
175 accentMap.insert("o", {"ô", "ö"});
176 accentMap.insert("u", {"û", "ù"});
177 accentMap.insert("c", {"ç"});
178
179 // --- INITIALISATION FINALE ---
180 loadUsageHistory();
181 updateKeyboardLayout();
182}
183
184void Clavier::handleButton() {
185 QPushButton *btn = qobject_cast<QPushButton *>(sender());
186 if (btn) {
187 lineEdit->insert(btn->text());
188 emit textChangedExternally(lineEdit->text());
189
190 // Si la majuscule (non verrouillée) était active, on repasse en minuscules après 1 lettre
191 if (majusculeActive && !shiftLock) {
192 majusculeActive = false;
193 updateKeys();
194 }
195 }
196}
197
198void Clavier::deleteChar() {
199 lineEdit->backspace();
200 emit textChangedExternally(lineEdit->text());
201}
202
203void Clavier::validateText() {
204 saveUsageHistory();
205 accept(); // Ferme la boîte de dialogue modale
206}
207
208void Clavier::toggleShift() {
209 // Logique cyclique: Minuscule -> Majuscule 1 lettre -> Caps Lock -> Minuscule
210 if (!majusculeActive) {
211 majusculeActive = true;
212 shiftLock = false;
213 }
214 else if (!shiftLock) {
215 shiftLock = true;
216 }
217 else {
218 majusculeActive = false;
219 shiftLock = false;
220 }
221 updateKeys();
222}
223
224void Clavier::updateKeys() {
225 for (QPushButton *btn : allButtons) {
226 QString t = btn->text();
227 btn->setText((majusculeActive || shiftLock) ? t.toUpper() : t.toLower());
228 }
229}
230
231void Clavier::addSpace() {
232 lineEdit->insert(" ");
233 emit textChangedExternally(lineEdit->text());
234}
235
236void Clavier::addUnderscore() {
237 lineEdit->insert("_");
238 emit textChangedExternally(lineEdit->text());
239}
240
241void Clavier::switchKeyboard() {
242 isSymbolMode = !isSymbolMode;
243 // Bascule la visibilité des tableaux de touches
244 for (QPushButton *b : allButtons) b->setVisible(!isSymbolMode);
245 for (QPushButton *b : symbolButtons) b->setVisible(isSymbolMode);
246 switchButton->setText(isSymbolMode ? "ABC" : "123?");
247}
248
249void Clavier::switchLayout() {
250 currentLayout = (currentLayout == AZERTY) ? QWERTY : AZERTY;
251 updateKeyboardLayout();
252}
253
254void Clavier::updateKeyboardLayout() {
255 QStringList n1, n2, n3;
256 if (currentLayout == AZERTY) {
257 n1 = {"A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P"};
258 n2 = {"Q", "S", "D", "F", "G", "H", "J", "K", "L", "M"};
259 n3 = {"W", "X", "C", "V", "B", "N"};
260 langueButton->setText("🌍 AZERTY");
261 } else {
262 n1 = {"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"};
263 n2 = {"A", "S", "D", "F", "G", "H", "J", "K", "L", ";"};
264 n3 = {"Z", "X", "C", "V", "B", "N", "M"};
265 langueButton->setText("🌍 QWERTY");
266 }
267
268 // Réaffectation des textes sur les boutons existants
269 for (int i = 0; i < row1Buttons.size() && i < n1.size(); ++i) row1Buttons[i]->setText(n1[i]);
270 for (int i = 0; i < row2Buttons.size() && i < n2.size(); ++i) row2Buttons[i]->setText(n2[i]);
271 for (int i = 0; i < row3Buttons.size() && i < n3.size(); ++i) row3Buttons[i]->setText(n3[i]);
272
273 updateKeys();
274}
275
276void Clavier::startLongPress() {
277 currentLongPressButton = qobject_cast<QPushButton*>(sender());
278 longPressTimer->start(500);
279}
280
281void Clavier::stopLongPress() {
282 longPressTimer->stop();
283}
284
285void Clavier::handleLongPress() {
286 if (currentLongPressButton && accentMap.contains(currentLongPressButton->text().toLower())) {
287 showAccentPopup(currentLongPressButton);
288 }
289}
290
291void Clavier::showAccentPopup(QPushButton* btn) {
292 if (accentPopup) return;
293
294 accentPopup = new QWidget(this, Qt::Popup);
295 accentPopup->setAttribute(Qt::WA_DeleteOnClose);
296
297 QHBoxLayout *l = new QHBoxLayout(accentPopup);
298 QStringList accs = accentMap.value(btn->text().toLower());
299
300 // Création des touches d'accents dynamiques
301 for (const QString &a : accs) {
302 QPushButton *ab = new QPushButton(majusculeActive ? a.toUpper() : a, accentPopup);
303 ab->setFixedSize(50, 50);
304 connect(ab, &QPushButton::clicked, this, &Clavier::insertAccent);
305 l->addWidget(ab);
306 }
307
308 // Positionnement de la popup juste au-dessus de la touche pressée
309 accentPopup->move(btn->mapToGlobal(QPoint(0, -60)));
310 accentPopup->show();
311}
312
313void Clavier::insertAccent() {
314 QPushButton *b = qobject_cast<QPushButton*>(sender());
315 if (b) {
316 lineEdit->insert(b->text());
317 emit textChangedExternally(lineEdit->text());
318 }
319 if (accentPopup) {
320 accentPopup->close();
321 accentPopup = nullptr;
322 }
323}
324
325void Clavier::startDeleteDelay() {
326 deleteChar();
327 deleteDelayTimer->start(500); // Attend 500ms avant de supprimer à la chaîne
328}
329
330void Clavier::startDelete() {
331 deleteTimer->start(75); // Supprime 1 caractère toutes les 75ms
332}
333
334void Clavier::stopDelete() {
335 deleteTimer->stop();
336 deleteDelayTimer->stop();
337}
338
339void Clavier::loadUsageHistory() {
340 QSettings s("EliasCorp", "GPSApp");
341 usageHistory = s.value("Clavier/UsageHistory").toStringList();
342}
343
344void Clavier::saveUsageHistory() const {
345 QSettings s("EliasCorp", "GPSApp");
346 s.setValue("Clavier/UsageHistory", usageHistory);
347}
348
349QString Clavier::getText() const {
350 return lineEdit->text();
351}
352
353void Clavier::setInitialText(const QString &text) {
354 lineEdit->setText(text);
355 lineEdit->setCursorPosition(text.length());
356}
357
358void Clavier::displaySuggestions(const QStringList &suggestions) {
359 suggestionList->clear();
360 if (!suggestions.isEmpty()) {
361 suggestionList->addItems(suggestions);
362 suggestionList->show();
363 } else {
364 suggestionList->hide();
365 }
366}
367
368void Clavier::hideAccentPopup() {
369 if (accentPopup) accentPopup->hide();
370}
QString getText() const
Récupère le texte final saisi par l'utilisateur une fois le clavier validé.
Definition clavier.cpp:349
Clavier(QWidget *parent=nullptr)
Constructeur du clavier virtuel.
Definition clavier.cpp:14
void textChangedExternally(const QString &text)
Émis à chaque fois qu'une touche modifie le texte. Permet à l'application en arrière-plan (ex: Naviga...
void displaySuggestions(const QStringList &suggestions)
Met à jour la liste déroulante des suggestions au-dessus du clavier.
Definition clavier.cpp:358
void setInitialText(const QString &text)
Pré-remplit la barre de saisie à l'ouverture du clavier.
Definition clavier.cpp:353
Rôle architectural : Clavier virtuel propriétaire utilisé par les écrans de saisie.