1 /*****************************************************************************
2  * LibreMines                                                                *
3  * Copyright (C) 2020-2021  Bruno Bollos Correa                              *
4  *                                                                           *
5  * This program is free software: you can redistribute it and/or modify      *
6  * it under the terms of the GNU General Public License as published by      *
7  * the Free Software Foundation, either version 3 of the License, or         *
8  * (at your option) any later version.                                       *
9  *                                                                           *
10  * This program is distributed in the hope that it will be useful,           *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
13  * GNU General Public License for more details.                              *
14  *                                                                           *
15  * You should have received a copy of the GNU General Public License         *
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
17  *****************************************************************************
18  */
19 
20 
21 #include "libreminespreferencesdialog.h"
22 #include "ui_libreminespreferencesdialog.h"
23 
24 #include <QStyleFactory>
25 #include <QMessageBox>
26 
27 #include "minefieldextratheme.h"
28 
LibreMinesPreferencesDialog(QWidget * parent)29 LibreMinesPreferencesDialog::LibreMinesPreferencesDialog(QWidget *parent) :
30     QDialog(parent),
31     ui(new Ui::LibreMinesPreferencesDialog),
32     updateLanguageDialog(true)
33 {
34     ui->setupUi(this);
35 
36     // Default system theme
37     ui->comboBoxApplicationStyle->addItem("default");
38 
39     // Dark and light fusion
40     ui->comboBoxApplicationStyle->addItems({"Fusion Dark", "Fusion Light"});
41 
42     // QSS
43     ui->comboBoxApplicationStyle->addItems({"ConsoleStyle", "NeonButtons"});
44 
45     // QDarkStyle
46     ui->comboBoxApplicationStyle->addItems({"QDarkStyle", "QDarkStyle Light"});
47 
48     // Breeze
49     ui->comboBoxApplicationStyle->addItems({"Breeze Dark", "Breeze Light"});
50 
51     // Styles from system
52     ui->comboBoxApplicationStyle->addItems(QStyleFactory::keys());
53 
54     // Default Minefield themes
55     ui->comboBoxMinefieldTheme->addItems({"Classic Dark", "Classic Light", "TwEmoji"});
56 
57     // Load extra minefield theme (if found).
58     for(const QString& path :
59         QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation))
60     {
61         QDir dir(path);
62 
63         // Continue if the directory does not exist
64         if(!dir.exists() || !dir.cd("minefield_extra_themes"))
65             continue;
66 
67         for(const QString& themeName :
68             dir.entryList(QDir::AllDirs | QDir::NoDot | QDir::NoDotDot))
69         {
70             // Add the new theme to the check box if it has a valid format
71             if(MinefieldExtraTheme::isValidTheme(dir.path(), themeName))
72             {
73                 if(ui->comboBoxMinefieldTheme->findText(themeName) != -1)
74                 {
75                     qWarning() << "The minefield theme \'" << themeName
76                                << "\' seems to be duplicate.";
77                 }
78                 else
79                 {
80                     ui->comboBoxMinefieldTheme->addItem(themeName);
81                 }
82             }
83         }
84 
85     }
86 
87     ui->comboBoxFacesReaction->addItems({"Open Emoji Colored", "Open Emoji Black", "Open Emoji White",
88                                          "TwEmoji Colored", "Disable"});
89     ui->comboBoxWhenCtrlIsPressed->addItems({tr("Go to the Edge"), tr("Jump 3 Cells"), tr("Jump 5 Cells"), tr("Jump 10 Cells")});
90 
91     ui->comboBoxLanguage->addItems({"English", "Português do Brasil"});
92 
93     ui->comboBoxMinefieldGenerationAnimation->addItems({tr("On"), tr("Limited"), tr("Off")});
94 
95 
96     // Space character is not allowed. This will remove every space character of the line edit
97 //    ui->lineEditUsername->setValidator(new QRegExpValidator(QRegExp("^(?i)[a-z][a-z0-9]*$")));
98     connect(ui->lineEditUsername, &QLineEdit::textChanged,
99             this, [this](QString text)
100     { ui->lineEditUsername->setText(text.remove(" ", Qt::CaseInsensitive)); });
101 
102     connect(ui->comboBoxApplicationStyle, &QComboBox::currentTextChanged,
103             this, [this](QString text)
104     {
105         text.remove(" ", Qt::CaseInsensitive);
106         Q_EMIT SIGNAL_optionChanged("ApplicationTheme", text);
107     });
108 
109     connect(ui->comboBoxMinefieldTheme, &QComboBox::currentTextChanged,
110             this, [this](QString text)
111     {
112         text.remove(" ", Qt::CaseInsensitive);
113         Q_EMIT SIGNAL_optionChanged("MinefieldTheme", text);
114     });
115 
116     connect(ui->sbMinimumCellLength, QOverload<int>::of(&QSpinBox::valueChanged),
117             this, &LibreMinesPreferencesDialog::SLOT_updateCellLengthParameters);
118     connect(ui->sbMaximumCellLength, QOverload<int>::of(&QSpinBox::valueChanged),
119             this, &LibreMinesPreferencesDialog::SLOT_updateCellLengthParameters);
120 
121     connect(ui->comboBoxLanguage, &QComboBox::currentTextChanged,
122             this, &LibreMinesPreferencesDialog::SLOT_updateLanguage);
123 
124     ui->keyInputMoveLeft->setKey(Qt::Key_A);
125     ui->keyInputMoveUp->setKey(Qt::Key_W);
126     ui->keyInputMoveRight->setKey(Qt::Key_D);
127     ui->keyInputMoveDown->setKey(Qt::Key_S);
128     ui->keyInputReleaseCell->setKey(Qt::Key_O);
129     ui->keyInputFlagCell->setKey(Qt::Key_P);
130     ui->keyInputCenterCell->setKey(Qt::Key_Space);
131 }
132 
~LibreMinesPreferencesDialog()133 LibreMinesPreferencesDialog::~LibreMinesPreferencesDialog()
134 {
135     delete ui;
136 }
137 
optionFirstCellClean() const138 bool LibreMinesPreferencesDialog::optionFirstCellClean() const
139 {
140     return ui->cbFirstCellClean->isChecked();
141 }
142 
optionCleanNeighborCellsWhenClickedOnShowedCell() const143 bool LibreMinesPreferencesDialog::optionCleanNeighborCellsWhenClickedOnShowedCell() const
144 {
145     return ui->cbCleanNeighborCellsWhenClickedOnShowedCell->isChecked();
146 }
147 
optionProgressBar() const148 bool LibreMinesPreferencesDialog::optionProgressBar() const
149 {
150     return ui->cbProgressBarInGame->isChecked();
151 }
152 
optionApplicationStyle() const153 QString LibreMinesPreferencesDialog::optionApplicationStyle() const
154 {
155     QString s = ui->comboBoxApplicationStyle->currentText();
156     s.remove(" ", Qt::CaseInsensitive);
157     return s;
158 }
159 
optionMinefieldTheme() const160 QString LibreMinesPreferencesDialog::optionMinefieldTheme() const
161 {
162     QString s = ui->comboBoxMinefieldTheme->currentText();
163     s.remove(" ", Qt::CaseInsensitive);
164     return s;
165 }
166 
optionFacesReaction() const167 QString LibreMinesPreferencesDialog::optionFacesReaction() const
168 {
169     QString s = ui->comboBoxFacesReaction->currentText();
170     s.remove(" ", Qt::CaseInsensitive);
171     return s;
172 }
173 
optionUsername() const174 QString LibreMinesPreferencesDialog::optionUsername() const
175 {
176     return ui->lineEditUsername->text();
177 }
178 
optionWhenCtrlIsPressed() const179 uchar LibreMinesPreferencesDialog::optionWhenCtrlIsPressed() const
180 {
181     return ui->comboBoxWhenCtrlIsPressed->currentIndex();
182 }
183 
optionMinimumCellLength() const184 int LibreMinesPreferencesDialog::optionMinimumCellLength() const
185 {
186     return ui->sbMinimumCellLength->value();
187 }
188 
optionMaximumCellLength() const189 int LibreMinesPreferencesDialog::optionMaximumCellLength() const
190 {
191     return ui->sbMaximumCellLength->value();
192 }
193 
optionsLanguage() const194 QString LibreMinesPreferencesDialog::optionsLanguage() const
195 {
196     if(ui->comboBoxLanguage->currentText().compare("English", Qt::CaseInsensitive) == 0)
197         return "en";
198     if(ui->comboBoxLanguage->currentText().compare("Português do Brasil", Qt::CaseInsensitive) == 0)
199         return "pt_BR";
200     return "";
201 }
202 
optionMinefieldGenerationAnimation() const203 uchar LibreMinesPreferencesDialog::optionMinefieldGenerationAnimation() const
204 {
205     return ui->comboBoxMinefieldGenerationAnimation->currentIndex();
206 }
207 
optionMinefieldGenerationAnimationString() const208 QString LibreMinesPreferencesDialog::optionMinefieldGenerationAnimationString() const
209 {
210     return ui->comboBoxMinefieldGenerationAnimation->currentText();
211 }
212 
optionAskToSaveMatchScoreBehaviour() const213 AskToSaveMatchScore LibreMinesPreferencesDialog::optionAskToSaveMatchScoreBehaviour() const
214 {
215     if(ui->rbSaveScoreNever->isChecked())
216         return LibreMines::SaveNever;
217     if(ui->rbSaveScoreAlways->isChecked())
218         return LibreMines::SaveAlways;
219     if(ui->rbSaveScoreWhenHighScore->isChecked())
220         return LibreMines::SaveWhenNewHighScore;
221     if(ui->rbSaveScoreWhenGameCompleted->isChecked())
222         return LibreMines::SaveWhenGameCompleted;
223     if(ui->rbSaveScoreWhenHighScoreAndGameCompleted->isChecked())
224         return LibreMines::SaveWhenGameCompleted | LibreMines::SaveWhenNewHighScore;
225     return LibreMines::SaveNever;
226 }
227 
setOptionFirstCellClean(const QString & option)228 void LibreMinesPreferencesDialog::setOptionFirstCellClean(const QString &option)
229 {
230     ui->cbFirstCellClean->setChecked(option.compare("On", Qt::CaseInsensitive) == 0);
231 }
232 
setOptionCleanNeighborCellsWhenClickedOnShowedCell(const QString & option)233 void LibreMinesPreferencesDialog::setOptionCleanNeighborCellsWhenClickedOnShowedCell(const QString &option)
234 {
235     ui->cbCleanNeighborCellsWhenClickedOnShowedCell->setChecked(option.compare("On", Qt::CaseInsensitive) == 0);
236 }
237 
setOptionProgressBar(const QString & option)238 void LibreMinesPreferencesDialog::setOptionProgressBar(const QString &option)
239 {
240     ui->cbProgressBarInGame->setChecked(option.compare("On", Qt::CaseInsensitive) == 0);
241 }
242 
setOptionApplicationStyle(const QString & option)243 void LibreMinesPreferencesDialog::setOptionApplicationStyle(const QString &option)
244 {
245     QString s = option;
246     if(option.compare("FusionDark", Qt::CaseInsensitive) == 0){ s = "Fusion Dark"; }
247     else if(option.compare("FusionLight", Qt::CaseInsensitive) == 0){ s = "Fusion Light"; }
248     else if(option.compare("QDarkStyleLight", Qt::CaseInsensitive) == 0){ s = "QDarkStyle Light"; }
249     else if(option.compare("BreezeDark", Qt::CaseInsensitive) == 0){ s = "Breeze Dark"; }
250     else if(option.compare("BreezeLight", Qt::CaseInsensitive) == 0){ s = "Breeze Light"; }
251 
252     ui->comboBoxApplicationStyle->setCurrentText(s);
253 }
254 
setOptionMinefieldTheme(const QString & option)255 void LibreMinesPreferencesDialog::setOptionMinefieldTheme(const QString &option)
256 {
257     QString s = option;
258     if(option.compare("ClassicLight", Qt::CaseInsensitive) == 0){ s = "Classic Light"; }
259     else if(option.compare("ClassicDark", Qt::CaseInsensitive) == 0){ s = "Classic Dark"; }
260     else if(option.compare("TwEmoji", Qt::CaseInsensitive) == 0){ s = "TwEmoji"; }
261 
262     ui->comboBoxMinefieldTheme->setCurrentText(s);
263 }
264 
setOptionFacesReaction(const QString & option)265 void LibreMinesPreferencesDialog::setOptionFacesReaction(const QString &option)
266 {
267     QString s = "Disable";
268     if(option.compare("OpenEmojiColored", Qt::CaseInsensitive) == 0){ s = "Open Emoji Colored"; }
269     else if(option.compare("OpenEmojiBlack", Qt::CaseInsensitive) == 0){ s = "Open Emoji Black"; }
270     else if(option.compare("OpenEmojiWhite", Qt::CaseInsensitive) == 0){ s = "Open Emoji White"; }
271     else if(option.compare("TwEmojiColored", Qt::CaseInsensitive) == 0){ s = "TwEmoji Colored"; }
272 
273     ui->comboBoxFacesReaction->setCurrentText(s);
274 }
275 
setOptionUsername(const QString & username)276 void LibreMinesPreferencesDialog::setOptionUsername(const QString &username)
277 {
278     ui->lineEditUsername->setText(username);
279 }
280 
setOptionWhenCtrlIsPressed(const uchar option)281 void LibreMinesPreferencesDialog::setOptionWhenCtrlIsPressed(const uchar option)
282 {
283     if(ui->comboBoxWhenCtrlIsPressed->count() > option)
284         ui->comboBoxWhenCtrlIsPressed->setCurrentIndex(option);
285 }
286 
setOptionMinimumCellLength(const int option)287 void LibreMinesPreferencesDialog::setOptionMinimumCellLength(const int option)
288 {
289     ui->sbMinimumCellLength->setValue(option);
290 }
291 
setOptionMaximumCellLength(const int option)292 void LibreMinesPreferencesDialog::setOptionMaximumCellLength(const int option)
293 {
294     ui->sbMaximumCellLength->setValue(option);
295 }
296 
setOptionLanguage(const QString & option)297 void LibreMinesPreferencesDialog::setOptionLanguage(const QString &option)
298 {
299     QString s = "English";
300     if(option.compare("pt_BR", Qt::CaseInsensitive) == 0)
301         s = "Português do Brasil";
302 
303     // Ugly way to avoid the creation of the dialog when this function is called
304     updateLanguageDialog = false;
305     ui->comboBoxLanguage->setCurrentText(s);
306     QTimer::singleShot(10, this, [this](){ updateLanguageDialog = true; });
307 }
308 
setOptionMinefieldGenerationAnimation(const uchar option)309 void LibreMinesPreferencesDialog::setOptionMinefieldGenerationAnimation(const uchar option)
310 {
311     if(ui->comboBoxMinefieldGenerationAnimation->count() > option)
312         ui->comboBoxMinefieldGenerationAnimation->setCurrentIndex(option);
313 }
314 
setOptionMinefieldGenerationAnimation(const QString & option)315 void LibreMinesPreferencesDialog::setOptionMinefieldGenerationAnimation(const QString &option)
316 {
317     ui->comboBoxMinefieldGenerationAnimation->setCurrentText(option);
318 }
319 
setOptionAskToSaveMatchScoreBehaviour(const uchar option)320 void LibreMinesPreferencesDialog::setOptionAskToSaveMatchScoreBehaviour(const uchar option)
321 {
322     switch(option)
323     {
324         case LibreMines::SaveNever:
325             return ui->rbSaveScoreNever->setChecked(true);
326         case LibreMines::SaveWhenNewHighScore:
327             return ui->rbSaveScoreWhenHighScore->setChecked(true);
328         case LibreMines::SaveWhenGameCompleted:
329             return ui->rbSaveScoreWhenGameCompleted->setChecked(true);
330         case LibreMines::SaveWhenGameCompleted | LibreMines::SaveWhenNewHighScore:
331             return ui->rbSaveScoreWhenHighScoreAndGameCompleted->setChecked(true);
332         case LibreMines::SaveAlways:
333             return ui->rbSaveScoreAlways->setChecked(true);
334     }
335 
336     return ui->rbSaveScoreNever->setChecked(true);
337 }
338 
optionKeyboardControllerKeys() const339 QList<int> LibreMinesPreferencesDialog::optionKeyboardControllerKeys() const
340 {
341     return
342     {
343         ui->keyInputMoveLeft->currentKey(),
344         ui->keyInputMoveUp->currentKey(),
345         ui->keyInputMoveRight->currentKey(),
346         ui->keyInputMoveDown->currentKey(),
347         ui->keyInputReleaseCell->currentKey(),
348         ui->keyInputFlagCell->currentKey(),
349         ui->keyInputCenterCell->currentKey()
350     };
351 }
352 
optionKeyboardControllerKeysString() const353 QString LibreMinesPreferencesDialog::optionKeyboardControllerKeysString() const
354 {
355     QString s;
356 
357     s += QString::number(ui->keyInputMoveLeft->currentKey(), 16);
358     s += ' ';
359     s += QString::number(ui->keyInputMoveUp->currentKey(), 16);
360     s += ' ';
361     s += QString::number(ui->keyInputMoveRight->currentKey(), 16);
362     s += ' ';
363     s += QString::number(ui->keyInputMoveDown->currentKey(), 16);
364     s += ' ';
365     s += QString::number(ui->keyInputReleaseCell->currentKey(), 16);
366     s += ' ';
367     s += QString::number(ui->keyInputFlagCell->currentKey(), 16);
368     s += ' ';
369     s += QString::number(ui->keyInputCenterCell->currentKey(), 16);
370 
371     return s;
372 }
373 
setOptionKeyboardControllerKeys(const QList<int> & keys)374 void LibreMinesPreferencesDialog::setOptionKeyboardControllerKeys(const QList<int> &keys)
375 {
376     ui->keyInputMoveLeft->setKey(keys.at(0));
377     ui->keyInputMoveUp->setKey(keys.at(1));
378     ui->keyInputMoveRight->setKey(keys.at(2));
379     ui->keyInputMoveDown->setKey(keys.at(3));
380     ui->keyInputReleaseCell->setKey(keys.at(4));
381     ui->keyInputFlagCell->setKey(keys.at(5));
382     if(keys.size() == 7)
383     {
384         ui->keyInputCenterCell->setKey(keys.at(6));
385     }
386 }
387 
closeEvent(QCloseEvent * e)388 void LibreMinesPreferencesDialog::closeEvent(QCloseEvent *e)
389 {
390     Q_UNUSED(e);
391     this->hide();
392 }
393 
hideEvent(QHideEvent * e)394 void LibreMinesPreferencesDialog::hideEvent(QHideEvent *e)
395 {
396     Q_UNUSED(e);
397     Q_EMIT SIGNAL_visibilityChanged(false);
398 }
399 
showEvent(QShowEvent * e)400 void LibreMinesPreferencesDialog::showEvent(QShowEvent *e)
401 {
402     Q_UNUSED(e);
403     Q_EMIT SIGNAL_visibilityChanged(true);
404 }
405 
SLOT_updateCellLengthParameters()406 void LibreMinesPreferencesDialog::SLOT_updateCellLengthParameters()
407 {
408     ui->sbMinimumCellLength->setMaximum(ui->sbMaximumCellLength->value());
409     ui->sbMaximumCellLength->setMinimum(ui->sbMinimumCellLength->value());
410 }
411 
SLOT_updateLanguage()412 void LibreMinesPreferencesDialog::SLOT_updateLanguage()
413 {
414     if(updateLanguageDialog)
415     {
416         QMessageBox::information(this, tr("Restart LibreMines to apply this preference!"),
417                                  tr("Please restart the application to redefine your language"));
418     }
419 }
420 
421