1 /*
2 SPDX-FileCopyrightText: 2010-2021 Graeme Gott <graeme@gottcode.org>
3
4 SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7 #include "new_game_dialog.h"
8
9 #include "board.h"
10 #include "clock.h"
11
12 #include <QComboBox>
13 #include <QCommandLinkButton>
14 #include <QDialogButtonBox>
15 #include <QFormLayout>
16 #include <QLabel>
17 #include <QScrollArea>
18 #include <QScrollBar>
19 #include <QSettings>
20 #include <QToolButton>
21 #include <QVBoxLayout>
22
23 //-----------------------------------------------------------------------------
24
NewGameDialog(QWidget * parent)25 NewGameDialog::NewGameDialog(QWidget* parent)
26 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
27 , m_minimum(3)
28 {
29 setWindowTitle(tr("New Game"));
30
31 QVBoxLayout* layout = new QVBoxLayout(this);
32
33 QSettings settings;
34 int previous_timer = settings.value("Board/TimerMode", Clock::Tanglet).toInt();
35
36 // Create size buttons
37 m_normal_size = new QToolButton(this);
38 m_normal_size->setAutoExclusive(true);
39 m_normal_size->setAutoRaise(true);
40 m_normal_size->setCheckable(true);
41 m_normal_size->setIconSize(QSize(64, 64));
42 m_normal_size->setIcon(QIcon(":/preview/normal.png"));
43 m_normal_size->setText(Board::sizeToString(4));
44 m_normal_size->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
45 connect(m_normal_size, &QToolButton::clicked, this, &NewGameDialog::sizeChanged);
46
47 m_large_size = new QToolButton(this);
48 m_large_size->setAutoExclusive(true);
49 m_large_size->setAutoRaise(true);
50 m_large_size->setCheckable(true);
51 m_large_size->setIconSize(QSize(64, 64));
52 m_large_size->setIcon(QIcon(":/preview/large.png"));
53 m_large_size->setText(Board::sizeToString(5));
54 m_large_size->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
55 connect(m_large_size, &QToolButton::clicked, this, &NewGameDialog::sizeChanged);
56
57 if (settings.value("Board/Size", 4).toInt() == 4) {
58 m_normal_size->setChecked(true);
59 } else {
60 m_large_size->setChecked(true);
61 }
62
63 QHBoxLayout* size_buttons = new QHBoxLayout;
64 size_buttons->setContentsMargins(0, 0, 0, 0);
65 size_buttons->addStretch();
66 size_buttons->addWidget(m_normal_size);
67 size_buttons->addWidget(m_large_size);
68 size_buttons->addStretch();
69 layout->addLayout(size_buttons);
70 layout->addSpacing(6);
71
72 // Create word options
73 m_density = new QComboBox(this);
74 for (int i = 0; i < 4; ++i) {
75 m_density->addItem(densityString(i));
76 }
77 m_density->setCurrentIndex(settings.value("Board/Density", 1).toInt());
78
79 m_length = new QComboBox(this);
80 for (int i = 0; i < 4; ++i) {
81 m_length->addItem("");
82 }
83 connect(m_length, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &NewGameDialog::lengthChanged);
84 m_minimum = settings.value("Board/Minimum", 3).toInt();
85 if (m_large_size->isChecked()) {
86 --m_minimum;
87 }
88 m_length->setCurrentIndex(qBound(0, m_minimum - 3, 4));
89 sizeChanged();
90
91 QFormLayout* options_layout = new QFormLayout;
92 options_layout->setFormAlignment(Qt::AlignHCenter | Qt::AlignTop);
93 options_layout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter);
94 options_layout->addRow(tr("Amount of Words:"), m_density);
95 options_layout->addRow(tr("Minimum Word Length:"), m_length);
96 layout->addLayout(options_layout);
97 layout->addSpacing(6);
98
99 // Create timer buttons
100 m_timers_area = new QScrollArea(this);
101 layout->addWidget(m_timers_area);
102
103 QWidget* timers_widget = new QWidget(m_timers_area);
104 QVBoxLayout* timers_layout = new QVBoxLayout(timers_widget);
105 m_timers_area->setWidget(timers_widget);
106 m_timers_area->setWidgetResizable(true);
107 m_timers_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
108
109 QCommandLinkButton* active_timer = nullptr;
110 for (int timer = 0; timer < Clock::TotalTimers; ++timer) {
111 const QString name = Clock::timerToString(timer);
112
113 QCommandLinkButton* button = new QCommandLinkButton(name, Clock::timerDescription(timer), timers_widget);
114 button->setMinimumWidth(500);
115 connect(button, &QCommandLinkButton::clicked, this, [this, timer] { timerChosen(timer); });
116
117 int i;
118 for (i = 0; i < m_timers.size(); ++i) {
119 if (m_timers[i]->text().localeAwareCompare(name) >= 0) {
120 break;
121 }
122 }
123 m_timers.insert(i, button);
124 timers_layout->insertWidget(i, button);
125
126 if (timer == previous_timer) {
127 button->setDefault(true);
128 button->setFocus();
129 active_timer = button;
130 }
131 }
132
133 // Create cancel button
134 m_buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults, Qt::Horizontal, this);
135 connect(m_buttons, &QDialogButtonBox::rejected, this, &NewGameDialog::reject);
136 connect(m_buttons, &QDialogButtonBox::clicked, this, &NewGameDialog::restoreDefaults);
137 layout->addSpacing(6);
138 layout->addWidget(m_buttons);
139
140 // Show contents
141 m_timers_area->setMinimumWidth(timers_widget->sizeHint().width()
142 + m_timers_area->verticalScrollBar()->sizeHint().width()
143 + (m_timers_area->frameWidth() * 2));
144 QSize size = sizeHint();
145 size.setHeight(size.height() - (m_timers_area->sizeHint().height() / 3));
146 resize(QSettings().value("NewGameDialog/Size", size).toSize());
147 show();
148 if (active_timer) {
149 m_timers_area->ensureWidgetVisible(active_timer);
150 }
151 }
152
153 //-----------------------------------------------------------------------------
154
densityString(int density)155 QString NewGameDialog::densityString(int density)
156 {
157 static QStringList densities = QStringList()
158 << tr("Low")
159 << tr("Medium")
160 << tr("High")
161 << tr("Random");
162 return densities.at(qBound(0, density, densities.count() - 1));
163 }
164
165 //-----------------------------------------------------------------------------
166
lengthChanged(int length)167 void NewGameDialog::lengthChanged(int length)
168 {
169 m_minimum = length + 3;
170 }
171
172 //-----------------------------------------------------------------------------
173
sizeChanged()174 void NewGameDialog::sizeChanged()
175 {
176 int minimum = (m_normal_size->isChecked()) ? 3 : 4;
177 for (int i = 0; i < 4; ++i) {
178 m_length->setItemText(i, tr("%n letter(s)", "", i + minimum));
179 }
180 }
181
182 //-----------------------------------------------------------------------------
183
timerChosen(int timer)184 void NewGameDialog::timerChosen(int timer)
185 {
186 QSettings settings;
187 if (m_normal_size->isChecked()) {
188 settings.setValue("Board/Size", 4);
189 settings.setValue("Board/Minimum", m_minimum);
190 } else {
191 settings.setValue("Board/Size", 5);
192 settings.setValue("Board/Minimum", m_minimum + 1);
193 }
194 settings.setValue("Board/Density", m_density->currentIndex());
195 settings.setValue("Board/TimerMode", timer);
196 settings.setValue("NewGameDialog/Size", size());
197 QDialog::accept();
198 }
199
200 //-----------------------------------------------------------------------------
201
restoreDefaults(QAbstractButton * button)202 void NewGameDialog::restoreDefaults(QAbstractButton* button)
203 {
204 if (m_buttons->buttonRole(button) != QDialogButtonBox::ResetRole) {
205 return;
206 }
207
208 m_normal_size->setChecked(true);
209 m_density->setCurrentIndex(1);
210 sizeChanged();
211 m_length->setCurrentIndex(0);
212
213 const QString name = Clock::timerToString(Clock::Tanglet);
214 QCommandLinkButton* timer = nullptr;
215 for (QCommandLinkButton* b : qAsConst(m_timers)) {
216 if (b->text() == name) {
217 timer = b;
218 break;
219 }
220 }
221 if (timer) {
222 timer->setDefault(true);
223 timer->setFocus();
224 m_timers_area->ensureWidgetVisible(timer);
225 }
226 }
227
228 //-----------------------------------------------------------------------------
229