ckb-next  v0.2.8 at branch master
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
kbwidget.cpp
Go to the documentation of this file.
1 #include <cmath>
2 #include <QFileDialog>
3 #include <QMenu>
4 #include <QMessageBox>
5 #include <QUrl>
6 #include "ckbsettings.h"
7 #include "fwupgradedialog.h"
8 #include "kbfirmware.h"
9 #include "kbwidget.h"
10 #include "kblightwidget.h"
11 #include "kbprofiledialog.h"
12 #include "ui_kbwidget.h"
13 #include "ui_kblightwidget.h"
14 
15 KbWidget::KbWidget(QWidget *parent, Kb *_device) :
16  QWidget(parent),
17  device(_device), hasShownNewFW(false),
18  ui(new Ui::KbWidget),
19  currentMode(0)
20 {
21  ui->setupUi(this);
22  connect(ui->modesList, SIGNAL(orderChanged()), this, SLOT(modesList_reordered()));
23 
24  connect(device, SIGNAL(infoUpdated()), this, SLOT(devUpdate()));
25  connect(device, SIGNAL(profileAdded()), this, SLOT(updateProfileList()));
26  connect(device, SIGNAL(profileChanged()), this, SLOT(profileChanged()));
27  connect(device, SIGNAL(profileRenamed()), this, SLOT(updateProfileList()));
28  connect(device, SIGNAL(modeRenamed()), this, SLOT(profileChanged()));
29  connect(device, SIGNAL(modeRenamed()), this, SLOT(modeChanged()));
30  connect(device, SIGNAL(modeChanged(bool)), this, SLOT(modeChanged(bool)));
31 
32  // Remove the Lighting and Performance tabs from non-RGB keyboards
33  if(!device->features.contains("rgb")){
34  ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->lightTab));
35  ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->kPerfTab));
36  ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->mPerfTab));
37  } else {
38  // Remove mouse Performance tab from non-mice
39  if(!device->isMouse())
40  ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->mPerfTab));
41  // Remove keyboard Performance tab from non-keyboards
42  if(!device->isKeyboard())
43  ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->kPerfTab));
44  }
45  // Hide poll rate and FW update as appropriate
46  if(!device->features.contains("pollrate")){
47  ui->pollLabel->hide();
48  ui->pollLabel2->hide();
49  }
50  if(!device->features.contains("fwupdate")){
51  ui->fwUpdButton->hide();
52  ui->fwUpdLabel->hide();
53  ui->fwUpdLayout->removeItem(ui->fwUpdLayout->itemAt(1));
54  }
55  // Set monochrome mode according to hardware
56  if(device->monochrome)
58 }
59 
61  delete ui;
62 }
63 
65  ui->tabWidget->setCurrentIndex(0);
66 }
67 
69  ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
70 }
71 
72 
74  // Clear profile list and rebuild
75  KbProfile* hwProfile = device->hwProfile(), *currentProfile = device->currentProfile();
76  ui->profileBox->clear();
77  int i = 0;
78  foreach(KbProfile* profile, device->profiles()){
79  ui->profileBox->addItem((profile == hwProfile) ? QIcon(":/img/icon_profile_hardware.png") : QIcon(":/img/icon_profile.png"),
80  profile->name());
81  if(profile == currentProfile)
82  ui->profileBox->setCurrentIndex(i);
83  i++;
84  }
85  ui->profileBox->addItem(QIcon(":/img/icon_blank.png"), "Manage profiles...");
86  QFont font = ui->profileBox->font();
87  font.setItalic(true);
88  ui->profileBox->setItemData(ui->profileBox->count() - 1, font, Qt::FontRole);
89 }
90 
92  // Rebuild mode list
93  ui->modesList->clear();
94  int i = 0;
95  QListWidgetItem* current = 0;
96  foreach(KbMode* mode, device->currentProfile()->modes()){
97  QListWidgetItem* item = new QListWidgetItem(modeIcon(i), mode->name(), ui->modesList);
98  item->setData(GUID, mode->id().guid);
99  item->setFlags(item->flags() | Qt::ItemIsEditable);
100  if(mode == currentMode){
101  item->setSelected(true);
102  current = item;
103  }
104  ui->modesList->addItem(item);
105  i++;
106  }
107  if(current)
108  ui->modesList->setCurrentItem(current);
109  addNewModeItem();
110  // Wait for modeChanged() to refresh the rest of the UI
111 }
112 
114  if(index < 0)
115  return;
116  if(index >= device->profiles().count()){
117  // "Manage profiles" option
118  KbProfileDialog dialog(this);
119  dialog.exec();
121  return;
122  }
124  // Device will emit profileChanged() and modeChanged() signals to update UI
125 }
126 
127 QIcon KbWidget::modeIcon(int i){
128  KbProfile* currentProfile = device->currentProfile(), *hwProfile = device->hwProfile();
129  int hwModeCount = device->hwModeCount;
130  if(i >= hwModeCount)
131  return QIcon(":/img/icon_mode.png");
132  else
133  return QIcon(QString(currentProfile == hwProfile ? ":/img/icon_mode%1_hardware.png" : ":/img/icon_mode%1.png").arg(i + 1));
134 }
135 
137  // Add an item for creating a new mode. Make it editable but not dragable.
138  QListWidgetItem* item = new QListWidgetItem("New mode...", ui->modesList);
139  item->setFlags((item->flags() | Qt::ItemIsEditable) & ~Qt::ItemIsDragEnabled & ~Qt::ItemIsDropEnabled);
140  item->setData(NEW_FLAG, 1);
141  QFont font = item->font();
142  font.setItalic(true);
143  item->setFont(font);
144  item->setIcon(QIcon(":/img/icon_plus.png"));
145  ui->modesList->addItem(item);
146 }
147 
148 void KbWidget::modeChanged(bool spontaneous){
149  int index = device->currentProfile()->indexOf(device->currentMode());
150  if(index < 0)
151  return;
152  // Update tabs
157  // Update selection
158  if(spontaneous)
159  ui->modesList->setCurrentRow(index);
160  // Connect signals
161  if(currentMode)
162  disconnect(currentMode, SIGNAL(updated()), this, SLOT(modeUpdate()));
164  connect(currentMode, SIGNAL(updated()), this, SLOT(modeUpdate()));
165  modeUpdate();
166 }
167 
168 void KbWidget::on_modesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous){
169  if(!current)
170  return;
171  KbMode* mode = device->currentProfile()->find(current->data(GUID).toUuid());
172  if(!mode)
173  return;
174  device->setCurrentMode(mode, false);
175 }
176 
178  KbProfile* currentProfile = device->currentProfile();
179  // Rebuild mode list from items
180  QList<KbMode*> newModes;
181  int count = ui->modesList->count();
182  for(int i = 0; i < count; i++){
183  QListWidgetItem* item = ui->modesList->item(i);
184  KbMode* mode = currentProfile->find(item->data(GUID).toUuid());
185  if(mode && !newModes.contains(mode))
186  newModes.append(mode);
187  if(item->data(NEW_FLAG).toInt() != 1)
188  item->setIcon(modeIcon(i));
189  item->setFlags(item->flags() | Qt::ItemIsEditable);
190  }
191  // Add any missing modes at the end of the list
192  foreach(KbMode* mode, currentProfile->modes()){
193  if(!newModes.contains(mode))
194  newModes.append(mode);
195  }
196  currentProfile->modes(newModes);
197 }
198 
199 void KbWidget::on_modesList_itemChanged(QListWidgetItem *item){
200  if(!item || !currentMode || item->data(GUID).toUuid() != currentMode->id().guid)
201  return;
202  currentMode->name(item->text());
203  // Set the text to the actual name (trimmed, "" replaced with "Unnamed")
204  item->setText(currentMode->name());
205 }
206 
207 void KbWidget::on_modesList_itemClicked(QListWidgetItem* item){
208  QUuid guid = item->data(GUID).toUuid();
209  if(guid.isNull() && item->data(NEW_FLAG).toInt() == 1){
210  // "New mode" item. Clear text and start editing
211  item->setText("");
212  ui->modesList->editItem(item);
213  item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
214  QFont font = item->font();
215  font.setItalic(false);
216  item->setFont(font);
217  item->setIcon(QIcon(":/img/icon_mode.png"));
218  // Add the new mode and assign it to this item
219  KbMode* newMode = device->newMode();
220  device->currentProfile()->append(newMode);
221  item->setData(GUID, newMode->id().guid);
222  item->setData(NEW_FLAG, 0);
223  device->setCurrentMode(newMode, false);
224  // Create another "new mode" item to replace this one
225  addNewModeItem();
226  }
227 }
228 
237  QListWidgetItem* item = ui->modesList->itemAt(pos);
238  if(!item || !currentMode || item->data(GUID).toUuid() != currentMode->id().guid)
239  return;
240  KbProfile* currentProfile = device->currentProfile();
241  int index = currentProfile->indexOf(currentMode);
242 
243  QMenu menu(this);
244  QAction* rename = new QAction("Rename...", this);
245  QAction* duplicate = new QAction("Duplicate", this);
246  QAction* del = new QAction("Delete", this);
247  bool canDelete = (device->currentProfile()->modeCount() > device->hwModeCount);
248  if(!canDelete)
249  // Can't delete modes if they're required by hardware
250  del->setEnabled(false);
251  QAction* moveup = new QAction("Move Up", this);
252  if(index == 0)
253  moveup->setEnabled(false);
254  QAction* movedown = new QAction("Move Down", this);
255  if(index >= currentProfile->modeCount() - 1)
256  movedown->setEnabled(false);
257  menu.addAction(rename);
258  menu.addAction(duplicate);
259  menu.addAction(del);
260  menu.addSeparator();
261  menu.addAction(moveup);
262  menu.addAction(movedown);
263  QAction* result = menu.exec(QCursor::pos());
264  if(result == rename){
265  ui->modesList->editItem(item);
266  } else if(result == duplicate){
267  KbMode* newMode = device->newMode(currentMode);
268  newMode->newId();
269  currentProfile->insert(index + 1, newMode);
270  // Update UI
271  profileChanged();
272  device->setCurrentMode(newMode);
273  } else if(result == del){
274  if(!canDelete)
275  return;
276  currentProfile->removeAll(currentMode);
277  currentMode->deleteLater();
278  currentMode = 0;
279  // Select next mode
280  profileChanged();
281  if(index < currentProfile->modeCount())
282  device->setCurrentMode(currentProfile->modes()[index]);
283  else
284  device->setCurrentMode(currentProfile->modes().last());
285  } else if(result == moveup){
286  currentProfile->removeAll(currentMode);
287  currentProfile->insert(index - 1, currentMode);
288  // Update UI
289  profileChanged();
290  modeChanged(true);
291  } else if(result == movedown){
292  currentProfile->removeAll(currentMode);
293  currentProfile->insert(index + 1, currentMode);
294  // Update UI
295  profileChanged();
296  modeChanged(true);
297  }
298 }
299 
301  // Update device tab
302  ui->serialLabel->setText(device->usbSerial);
303  ui->fwLabel->setText(device->firmware);
304  ui->pollLabel->setText(device->pollrate);
305 }
306 
308 }
309 
311  device->save();
312  device->hwSave();
314  profileChanged();
315 }
316 
318  if(!device)
319  return;
320  if(index == ui->tabWidget->count() - 1){
321  // Device tab
322  updateFwButton();
323  }
324 }
325 
328  ui->fwUpdButton->setText("Check for updates");
329  else {
330  float newVersion = KbFirmware::versionForBoard(device->features);
331  float oldVersion = device->firmware.toFloat();
332  if(newVersion <= 0.f || newVersion <= oldVersion)
333  ui->fwUpdButton->setText("Up to date");
334  else
335  ui->fwUpdButton->setText(tr("Upgrade to v%1").arg(QString::number(newVersion, 'f', 2)));
336  }
337 }
338 
340  // If alt is pressed, ignore upgrades and go straight to the manual prompt
341  if(!(qApp->keyboardModifiers() & Qt::AltModifier)){
342  // Check version numbers
344  ui->fwUpdButton->setText("Checking...");
345  ui->fwUpdButton->setEnabled(false);
346  }
347  float newVersion = KbFirmware::versionForBoard(device->features, true);
348  float oldVersion = device->firmware.toFloat();
349  ui->fwUpdButton->setEnabled(true);
350  updateFwButton();
351  if(newVersion == -1.f){
352  QMessageBox::information(this, "Firmware update", "<center>There is a new firmware available for this device.<br />However, it requires a newer version of ckb.<br />Please upgrade ckb and try again.</center>");
353  return;
354  } else if(newVersion == 0.f){
355  if(QMessageBox::question(this, "Firmware update", "<center>There was a problem getting the status for this device.<br />Would you like to select a file manually?</center>") != QMessageBox::Yes)
356  return;
357  // "Yes" -> fall through to browse file
358  } else if(newVersion <= oldVersion){
359  if(QMessageBox::question(this, "Firmware update", "<center>Your firmware is already up to date.<br />Would you like to select a file manually?</center>") != QMessageBox::Yes)
360  return;
361  // "Yes" -> fall through to browse file
362  } else {
363  // Automatic upgrade. Fetch file from web.
364  // FwUpgradeDialog can't be parented to KbWidget because KbWidget may be deleted before the dialog exits
365  FwUpgradeDialog dialog(parentWidget(), newVersion, "", device);
366  dialog.exec();
367  return;
368  }
369  }
370  // Browse for file
371  QString path = QFileDialog::getOpenFileName(this, "Select firmware file", QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), "Firmware blobs (*.bin)");
372  if(path.isEmpty())
373  return;
374  QFile file(path);
375  if(!file.open(QIODevice::ReadOnly)){
376  QMessageBox::warning(parentWidget(), "Error", "<center>File could not be read.</center>");
377  return;
378  }
379  QByteArray blob = file.readAll();
380  FwUpgradeDialog dialog(parentWidget(), 0.f, blob, device);
381  dialog.exec();
382 }
const ModeList & modes() const
Definition: kbprofile.h:42
UsbId & id()
Definition: kbmode.h:52
QUuid guid
Definition: kbmode.h:12
rgb * current
Definition: main.c:46
void setCurrentMode(KbProfile *profile, KbMode *mode, bool spontaneous=true)
Definition: kb.cpp:769
void modeUpdate()
Definition: kbwidget.cpp:307
static const int GUID
Definition: kbwidget.h:46
int hwModeCount
Definition: kb.h:49
void updateFwButton()
Definition: kbwidget.cpp:326
KbMode * currentMode()
Definition: kb.h:65
void setMonochrome()
QPushButton * fwUpdButton
Definition: ui_kbwidget.h:62
bool isKeyboard() const
Definition: kb.h:23
QHBoxLayout * fwUpdLayout
Definition: ui_kbwidget.h:61
KbBindWidget * bindWidget
Definition: ui_kbwidget.h:45
QWidget * kPerfTab
Definition: ui_kbwidget.h:46
RListWidget * modesList
Definition: ui_kbwidget.h:66
KbPerf * currentPerf()
Definition: kb.h:68
QString pollrate
Definition: kb.h:18
KbMode * currentMode
Definition: kbwidget.h:44
KbProfile * currentProfile()
Definition: kb.h:56
KbMode * find(const QUuid &id)
Definition: kbprofile.h:51
QString firmware
Definition: kb.h:18
void on_modesList_itemClicked(QListWidgetItem *item)
Definition: kbwidget.cpp:207
void on_tabWidget_currentChanged(int index)
Definition: kbwidget.cpp:317
void on_hwSaveButton_clicked()
Definition: kbwidget.cpp:310
bool isMouse() const
Definition: kb.h:24
KbWidget(QWidget *parent, Kb *_device)
Definition: kbwidget.cpp:15
QLabel * serialLabel
Definition: ui_kbwidget.h:60
void setCurrentProfile(KbProfile *profile, bool spontaneous=true)
Definition: kb.cpp:760
void setLight(KbLight *newLight)
void append(KbMode *newMode)
Definition: kbprofile.h:44
void modeChanged(bool spontaneous=true)
Definition: kbwidget.cpp:148
void setBind(KbBind *newBind, KbProfile *newProfile)
KbMode * newMode()
Definition: kb.h:79
bool monochrome
Definition: kb.h:19
Definition: kbmode.h:36
int modeCount() const
Definition: kbprofile.h:49
QWidget * mPerfTab
Definition: ui_kbwidget.h:49
void showLastTab()
Definition: kbwidget.cpp:68
Definition: kb.h:11
KbBind * currentBind()
Definition: kb.h:67
QLabel * fwUpdLabel
Definition: ui_kbwidget.h:54
void hwSave()
Definition: kb.cpp:297
QLabel * fwLabel
Definition: ui_kbwidget.h:56
void on_profileBox_activated(int index)
Definition: kbwidget.cpp:113
static const int NEW_FLAG
Definition: kbwidget.h:47
KbLightWidget * lightWidget
Definition: ui_kbwidget.h:41
static bool hasDownloaded()
Definition: kbfirmware.h:18
MPerfWidget * mPerfWidget
Definition: ui_kbwidget.h:51
KbProfile * hwProfile()
Definition: kb.h:46
const QList< KbProfile * > & profiles() const
Definition: kb.h:58
QLabel * pollLabel
Definition: ui_kbwidget.h:65
void setupUi(QWidget *KbWidget)
Definition: ui_kbwidget.h:69
QWidget * lightTab
Definition: ui_kbwidget.h:39
const QString & name() const
Definition: kbmode.h:50
void showFirstTab()
Definition: kbwidget.cpp:64
QTabWidget * tabWidget
Definition: ui_kbwidget.h:38
QString features
Definition: kb.h:18
QString usbSerial
Definition: kb.h:16
KPerfWidget * kPerfWidget
Definition: ui_kbwidget.h:48
void modesList_reordered()
Definition: kbwidget.cpp:177
void removeAll(KbMode *mode)
Definition: kbprofile.h:46
Ui::KbWidget * ui
Definition: kbwidget.h:41
~KbWidget()
Definition: kbwidget.cpp:60
void devUpdate()
Definition: kbwidget.cpp:300
int indexOf(KbMode *mode) const
Definition: kbprofile.h:50
void save()
Definition: kb.cpp:273
Kb * device
Definition: kbwidget.h:24
QLabel * pollLabel2
Definition: ui_kbwidget.h:64
QString name() const
Definition: kbprofile.h:28
void setPerf(KbPerf *newPerf, KbProfile *newProfile)
void profileChanged()
Definition: kbwidget.cpp:91
void on_fwUpdButton_clicked()
Definition: kbwidget.cpp:339
void on_modesList_itemChanged(QListWidgetItem *item)
Definition: kbwidget.cpp:199
void setPerf(KbPerf *newPerf, KbProfile *newProfile)
Definition: mperfwidget.cpp:60
void insert(int index, KbMode *newMode)
Definition: kbprofile.h:45
void addNewModeItem()
Definition: kbwidget.cpp:136
static float versionForBoard(const QString &features, bool waitForComplete=false)
Definition: kbfirmware.h:22
KbLight * currentLight()
Definition: kb.h:66
void on_modesList_customContextMenuRequested(const QPoint &pos)
KbWidget::on_modesList_customContextMenuRequested.
Definition: kbwidget.cpp:236
QIcon modeIcon(int i)
Definition: kbwidget.cpp:127
void on_modesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
Definition: kbwidget.cpp:168
QComboBox * profileBox
Definition: ui_kbwidget.h:37
void updateProfileList()
Definition: kbwidget.cpp:73
void newId()
Definition: kbmode.cpp:52