|
1 /* |
|
2 * Hedgewars, a free turn based strategy game |
|
3 * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com> |
|
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; version 2 of the License |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU General Public License |
|
15 * along with this program; if not, write to the Free Software |
|
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
|
17 */ |
|
18 |
|
19 #include "keybinder.h" |
|
20 #include "HWApplication.h" |
|
21 #include "DataManager.h" |
|
22 #include <QHBoxLayout> |
|
23 #include <QScrollArea> |
|
24 #include <QTableWidget> |
|
25 #include <QTableWidgetItem> |
|
26 #include <QStandardItemModel> |
|
27 #include <QAbstractItemModel> |
|
28 #include <QListWidget> |
|
29 #include <QListWidgetItem> |
|
30 #include <QPushButton> |
|
31 #include <QHeaderView> |
|
32 #include <QComboBox> |
|
33 #include <QLabel> |
|
34 #include <QFrame> |
|
35 #include <QDebug> |
|
36 |
|
37 KeyBinder::KeyBinder(QWidget * parent, const QString & helpText, const QString & defaultText, const QString & resetButtonText) : QWidget(parent) |
|
38 { |
|
39 this->defaultText = defaultText; |
|
40 enableSignal = false; |
|
41 |
|
42 // Two-column tab layout |
|
43 QHBoxLayout * pageKeysLayout = new QHBoxLayout(this); |
|
44 pageKeysLayout->setSpacing(0); |
|
45 pageKeysLayout->setContentsMargins(0, 0, 0, 0); |
|
46 |
|
47 // Table for category list |
|
48 QVBoxLayout * catListContainer = new QVBoxLayout(); |
|
49 catListContainer->setContentsMargins(10, 10, 10, 10); |
|
50 catList = new QListWidget(); |
|
51 catList->setFixedWidth(180); |
|
52 catList->setStyleSheet("QListWidget::item { font-size: 14px; } QListWidget:hover { border-color: #F6CB1C; } QListWidget::item:selected { background: #150A61; color: yellow; }"); |
|
53 catList->setFocusPolicy(Qt::NoFocus); |
|
54 connect(catList, SIGNAL(currentRowChanged(int)), this, SLOT(changeBindingsPage(int))); |
|
55 catListContainer->addWidget(catList); |
|
56 pageKeysLayout->addLayout(catListContainer); |
|
57 |
|
58 // Reset all binds button |
|
59 if (!resetButtonText.isEmpty()) |
|
60 { |
|
61 QPushButton * btnResetAll = new QPushButton(resetButtonText); |
|
62 catListContainer->addWidget(btnResetAll); |
|
63 btnResetAll->setFixedHeight(40); |
|
64 catListContainer->setStretch(1, 0); |
|
65 catListContainer->setSpacing(10); |
|
66 connect(btnResetAll, SIGNAL(clicked()), this, SIGNAL(resetAllBinds())); |
|
67 } |
|
68 |
|
69 // Container for pages of key bindings |
|
70 QWidget * bindingsPagesContainer = new QWidget(); |
|
71 QVBoxLayout * rightLayout = new QVBoxLayout(bindingsPagesContainer); |
|
72 |
|
73 // Scroll area for key bindings |
|
74 QScrollArea * scrollArea = new QScrollArea(); |
|
75 scrollArea->setContentsMargins(0, 0, 0, 0); |
|
76 scrollArea->setWidget(bindingsPagesContainer); |
|
77 scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); |
|
78 scrollArea->setWidgetResizable(true); |
|
79 scrollArea->setFrameShape(QFrame::NoFrame); |
|
80 scrollArea->setStyleSheet("background: #130F2A;"); |
|
81 |
|
82 // Add key binding pages to bindings tab |
|
83 pageKeysLayout->addWidget(scrollArea); |
|
84 pageKeysLayout->setStretch(1, 1); |
|
85 |
|
86 // Custom help text |
|
87 QLabel * helpLabel = new QLabel(); |
|
88 helpLabel->setText(helpText); |
|
89 helpLabel->setStyleSheet("color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-radius: 10px; padding: auto 20px;"); |
|
90 helpLabel->setFixedHeight(24); |
|
91 rightLayout->addWidget(helpLabel, 0, Qt::AlignCenter); |
|
92 |
|
93 // Category list and bind table row heights |
|
94 const int rowHeight = 20; |
|
95 QSize catSize, headerSize; |
|
96 catSize.setHeight(36); |
|
97 headerSize.setHeight(24); |
|
98 |
|
99 // Category list header |
|
100 QListWidgetItem * catListHeader = new QListWidgetItem(tr("Category")); |
|
101 catListHeader->setSizeHint(headerSize); |
|
102 catListHeader->setFlags(Qt::NoItemFlags); |
|
103 catListHeader->setForeground(QBrush(QColor("#130F2A"))); |
|
104 catListHeader->setBackground(QBrush(QColor("#F6CB1C"))); |
|
105 catListHeader->setTextAlignment(Qt::AlignCenter); |
|
106 catList->addItem(catListHeader); |
|
107 |
|
108 // Populate |
|
109 bindingsPages = new QHBoxLayout(); |
|
110 bindingsPages->setContentsMargins(0, 0, 0, 0); |
|
111 rightLayout->addLayout(bindingsPages); |
|
112 QWidget * curPage = NULL; |
|
113 QVBoxLayout * curLayout = NULL; |
|
114 QTableWidget * curTable = NULL; |
|
115 bool bFirstPage = true; |
|
116 selectedBindTable = NULL; |
|
117 bindComboBoxCellMappings = new QHash<QObject *, QTableWidgetItem *>(); |
|
118 bindCellComboBoxMappings = new QHash<QTableWidgetItem *, QComboBox *>(); |
|
119 for (int i = 0; i < BINDS_NUMBER; i++) |
|
120 { |
|
121 if (cbinds[i].category != NULL) |
|
122 { |
|
123 // Add stretch at end of previous layout |
|
124 if (curLayout != NULL) curLayout->insertStretch(-1, 1); |
|
125 |
|
126 // Category list item |
|
127 QListWidgetItem * catItem = new QListWidgetItem(HWApplication::translate("binds (categories)", cbinds[i].category)); |
|
128 catItem->setSizeHint(catSize); |
|
129 catList->addItem(catItem); |
|
130 |
|
131 // Create new page |
|
132 curPage = new QWidget(); |
|
133 curLayout = new QVBoxLayout(curPage); |
|
134 curLayout->setSpacing(2); |
|
135 bindingsPages->addWidget(curPage); |
|
136 if (!bFirstPage) curPage->setVisible(false); |
|
137 } |
|
138 |
|
139 // Description |
|
140 if (cbinds[i].description != NULL) |
|
141 { |
|
142 QLabel * desc = new QLabel(HWApplication::translate("binds (descriptions)", cbinds[i].description)); |
|
143 curLayout->addWidget(desc, 0); |
|
144 QFrame * divider = new QFrame(); |
|
145 divider->setFrameShape(QFrame::HLine); |
|
146 divider->setFrameShadow(QFrame::Plain); |
|
147 curLayout->addWidget(divider, 0); |
|
148 } |
|
149 |
|
150 // New table |
|
151 if (cbinds[i].category != NULL || cbinds[i].description != NULL) |
|
152 { |
|
153 curTable = new QTableWidget(0, 2); |
|
154 curTable->verticalHeader()->setVisible(false); |
|
155 curTable->horizontalHeader()->setVisible(false); |
|
156 curTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch); |
|
157 curTable->verticalHeader()->setDefaultSectionSize(rowHeight); |
|
158 curTable->setShowGrid(false); |
|
159 curTable->setStyleSheet("QTableWidget { border: none; } "); |
|
160 curTable->setSelectionBehavior(QAbstractItemView::SelectRows); |
|
161 curTable->setSelectionMode(QAbstractItemView::SingleSelection); |
|
162 curTable->setFocusPolicy(Qt::NoFocus); |
|
163 connect(curTable, SIGNAL(itemSelectionChanged()), this, SLOT(bindSelectionChanged())); |
|
164 connect(curTable, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(bindCellClicked(QTableWidgetItem *))); |
|
165 curLayout->addWidget(curTable, 0); |
|
166 } |
|
167 |
|
168 // Hidden combo box |
|
169 QComboBox * comboBox = CBBind[i] = new QComboBox(curTable); |
|
170 comboBox->setModel((QAbstractItemModel*)DataManager::instance().bindsModel()); |
|
171 comboBox->setVisible(false); |
|
172 comboBox->setFixedWidth(200); |
|
173 |
|
174 // Table row |
|
175 int row = curTable->rowCount(); |
|
176 QTableWidgetItem * nameCell = new QTableWidgetItem(HWApplication::translate("binds", cbinds[i].name)); |
|
177 nameCell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); |
|
178 curTable->insertRow(row); |
|
179 curTable->setItem(row, 0, nameCell); |
|
180 QTableWidgetItem * bindCell = new QTableWidgetItem(comboBox->currentText()); |
|
181 bindCell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); |
|
182 curTable->setItem(row, 1, bindCell); |
|
183 curTable->resizeColumnsToContents(); |
|
184 curTable->setFixedHeight(curTable->verticalHeader()->length() + 10); |
|
185 |
|
186 // Updates the text in the table cell |
|
187 connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(bindChanged(const QString &))); |
|
188 |
|
189 // Map combo box and that row's cells to each other |
|
190 bindComboBoxCellMappings->insert(comboBox, bindCell); |
|
191 bindCellComboBoxMappings->insert(nameCell, comboBox); |
|
192 bindCellComboBoxMappings->insert(bindCell, comboBox); |
|
193 } |
|
194 |
|
195 // Add stretch at end of last layout |
|
196 if (curLayout != NULL) curLayout->insertStretch(-1, 1); |
|
197 |
|
198 // Go to first page |
|
199 catList->setCurrentItem(catList->item(1)); |
|
200 |
|
201 enableSignal = true; |
|
202 } |
|
203 |
|
204 KeyBinder::~KeyBinder() |
|
205 { |
|
206 delete bindComboBoxCellMappings; |
|
207 delete bindCellComboBoxMappings; |
|
208 } |
|
209 |
|
210 // Switches between different pages of key binds |
|
211 void KeyBinder::changeBindingsPage(int page) |
|
212 { |
|
213 page--; // Disregard first item (the list header) |
|
214 int pages = bindingsPages->count(); |
|
215 for (int i = 0; i < pages; i++) |
|
216 bindingsPages->itemAt(i)->widget()->setVisible(false); |
|
217 bindingsPages->itemAt(page)->widget()->setVisible(true); |
|
218 } |
|
219 |
|
220 // When a key bind combobox value is changed, updates the table cell text |
|
221 void KeyBinder::bindChanged(const QString & text) |
|
222 { |
|
223 bindComboBoxCellMappings->value(sender())->setText(text); |
|
224 |
|
225 if (enableSignal) |
|
226 { |
|
227 for (int i = 0; i < BINDS_NUMBER; i++) |
|
228 { |
|
229 if (CBBind[i] == sender()) |
|
230 { |
|
231 emit bindUpdate(i); |
|
232 break; |
|
233 } |
|
234 } |
|
235 } |
|
236 } |
|
237 |
|
238 // When a row in a key bind table is clicked, this shows the popup |
|
239 void KeyBinder::bindCellClicked(QTableWidgetItem * item) |
|
240 { |
|
241 QComboBox * box = bindCellComboBoxMappings->value(item); |
|
242 QTableWidget * table = item->tableWidget(); |
|
243 QFrame * frame = box->findChild<QFrame*>(); |
|
244 |
|
245 box->showPopup(); |
|
246 frame->move( |
|
247 frame->x() + table->horizontalHeader()->sectionSize(0), |
|
248 frame->y() + (table->verticalHeader()->defaultSectionSize() * item->row()) |
|
249 ); |
|
250 } |
|
251 |
|
252 // When a new row in a bind table is *selected*, this clears selection in any other table |
|
253 void KeyBinder::bindSelectionChanged() |
|
254 { |
|
255 QTableWidget * theSender = (QTableWidget*)sender(); |
|
256 if (theSender != selectedBindTable) |
|
257 { |
|
258 if (selectedBindTable != NULL) |
|
259 selectedBindTable->clearSelection(); |
|
260 selectedBindTable = theSender; |
|
261 } |
|
262 } |
|
263 |
|
264 // Set a combobox's index |
|
265 void KeyBinder::setBindIndex(int keyIndex, int bindIndex) |
|
266 { |
|
267 enableSignal = false; |
|
268 CBBind[keyIndex]->setCurrentIndex(bindIndex); |
|
269 enableSignal = true; |
|
270 } |
|
271 |
|
272 // Return a combobox's selected index |
|
273 int KeyBinder::bindIndex(int keyIndex) |
|
274 { |
|
275 return CBBind[keyIndex]->currentIndex(); |
|
276 } |
|
277 |
|
278 // Clears selection and goes to first category |
|
279 void KeyBinder::resetInterface() |
|
280 { |
|
281 enableSignal = false; |
|
282 |
|
283 catList->setCurrentItem(catList->item(1)); |
|
284 changeBindingsPage(1); |
|
285 if (selectedBindTable != NULL) |
|
286 { |
|
287 selectedBindTable->clearSelection(); |
|
288 selectedBindTable = NULL; |
|
289 } |
|
290 |
|
291 // Default bind text |
|
292 DataManager::instance().bindsModel()->item(0)->setData(defaultText, Qt::DisplayRole); |
|
293 for (int i = 0; i < BINDS_NUMBER; i++) |
|
294 { |
|
295 CBBind[i]->setModel(DataManager::instance().bindsModel()); |
|
296 CBBind[i]->setCurrentIndex(0); |
|
297 bindComboBoxCellMappings->value(CBBind[i])->setText(defaultText); |
|
298 } |
|
299 |
|
300 enableSignal = true; |
|
301 } |