ckb-next  beta-v0.2.8 at branch testing
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
keywidget.cpp
Go to the documentation of this file.
1 #include <cmath>
2 #include <QGraphicsDropShadowEffect>
3 #include <QGraphicsPixmapItem>
4 #include <QGraphicsScene>
5 #include <QPainter>
6 #include "keywidget.h"
7 #include "keyaction.h"
8 #include "kbbind.h"
9 
10 static const int KEY_SIZE = 12;
11 
12 static QImage* m65Overlay = 0, *sabOverlay = 0, *scimOverlay = 0;
13 
14 // KbLight.cpp
15 extern QRgb monoRgb(float r, float g, float b);
16 
17 KeyWidget::KeyWidget(QWidget *parent, bool rgbMode) :
18  QWidget(parent), mouseDownX(-1), mouseDownY(-1), mouseCurrentX(-1), mouseCurrentY(-1), mouseDownMode(NONE), _rgbMode(rgbMode), _monochrome(false)
19 {
20  setMouseTracking(true);
21  setAutoFillBackground(false);
22 }
23 
24 void KeyWidget::map(const KeyMap& newMap){
25  keyMap = newMap;
26  selection = QBitArray(keyMap.count());
27  newSelection = QBitArray(keyMap.count());
28  animation = QBitArray(keyMap.count());
29  int width, height;
30  if(keyMap.isMouse()){
31  width = (keyMap.width() + KEY_SIZE) * 2.6;
32  height = (keyMap.height() + KEY_SIZE) * 2.6;
33  } else {
34  width = (keyMap.width() + KEY_SIZE) * 2.3;
35  height = (keyMap.height() + KEY_SIZE) * 2.3;
36  }
37  if(width < 500)
38  width = 500;
39  setFixedSize(width, height);
40  update();
41 }
42 
43 void KeyWidget::drawInfo(float& scale, float& offsetX, float& offsetY, int ratio){
44  int w = width() * ratio, h = height() * ratio;
45  float xScale = (float)w / (keyMap.width() + KEY_SIZE);
46  float yScale = (float)h / (keyMap.height() + KEY_SIZE);
47  scale = fmin(xScale, yScale);
48  offsetX = (w / scale - keyMap.width()) / 2.f;
49  offsetY = (h / scale - keyMap.height()) / 2.f;
50 }
51 
52 void KeyWidget::colorMap(const QColorMap& newColorMap){
53  _colorMap = newColorMap;
54  update();
55 }
56 
57 void KeyWidget::displayColorMap(const ColorMap &newDisplayMap, const QSet<QString> &indicators){
58  if(!isVisible())
59  return;
60  _displayColorMap = newDisplayMap;
61  _indicators = indicators;
62  update();
63 }
64 
65 void KeyWidget::bindMap(const BindMap& newBindMap){
66  _bindMap = newBindMap;
67  update();
68 }
69 
70 void KeyWidget::paintEvent(QPaintEvent*){
71  const QColor bgColor(68, 64, 64);
72  const QColor keyColor(112, 110, 110);
73  const QColor sniperColor(130, 90, 90);
74  const QColor thumbColor(34, 32, 32);
75  const QColor transparentColor(0, 0, 0, 0);
76  const QColor highlightColor(136, 176, 240);
77  const QColor highlightAnimColor(136, 200, 240);
78  const QColor animColor(112, 200, 110);
79 
80  // Determine which keys to highlight
81  QBitArray highlight;
82  switch(mouseDownMode){
83  case SET:
84  highlight = newSelection;
85  break;
86  case ADD:
87  highlight = selection | newSelection;
88  break;
89  case SUBTRACT:
90  highlight = selection & ~newSelection;
91  break;
92  case TOGGLE:
93  highlight = selection ^ newSelection;
94  break;
95  default:
96  highlight = selection;
97  }
98 
99  QPainter painter(this);
100 #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
101  int ratio = painter.device()->devicePixelRatio();
102 #else
103  int ratio = 1;
104 #endif
105  int wWidth = width(), wHeight = height();
106  KeyMap::Model model = keyMap.model();
107  KeyMap::Layout layout = keyMap.layout();
108  float scale, offX, offY;
109  drawInfo(scale, offX, offY, ratio);
110  // Draw background
111  painter.setPen(Qt::NoPen);
112  painter.setRenderHint(QPainter::Antialiasing, true);
113 
114  if(keyMap.isMouse()){
115  // Draw mouse overlays
116  const QImage* overlay = 0;
117  float xpos = 0.f, ypos = 0.f;
118  if(model == KeyMap::M65){
119  if(!m65Overlay)
120  m65Overlay = new QImage(":/img/overlay_m65.png");
121  overlay = m65Overlay;
122  xpos = 2.f;
123  ypos = -2.f;
124  } else if(model == KeyMap::SABRE){
125  if(!sabOverlay)
126  sabOverlay = new QImage(":/img/overlay_sabre.png");
127  overlay = sabOverlay;
128  xpos = 1.f;
129  ypos = -2.f;
130  } else if(model == KeyMap::SCIMITAR){
131  if(!scimOverlay)
132  scimOverlay = new QImage(":/img/overlay_scimitar.png");
133  overlay = scimOverlay;
134  xpos = 3.5f;
135  ypos = -2.f;
136  }
137  if(overlay){
138  painter.setBrush(palette().brush(QPalette::Window));
139  painter.drawRect(0, 0, width(), height());
140  float oXScale = scale / 9.f, oYScale = scale / 9.f; // The overlay has a resolution of 9px per keymap unit
141  float x = (xpos + offX) * scale, y = (ypos + offY) * scale;
142  int w = overlay->width() * oXScale, h = overlay->height() * oYScale;
143  // We need to transform the image with QImage::scaled() because painter.drawImage() will butcher it, even with smoothing enabled
144  // However, the width/height need to be rounded to integers
145  int iW = round(w), iH = round(h);
146  painter.drawImage(QRectF((x - (iW - w) / 2.f) / ratio, (y - (iH - h) / 2.f) / ratio, iW / ratio, iH / ratio), overlay->scaled(iW, iH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
147  }
148  } else {
149  // Otherwise, draw a solid background
150  painter.setBrush(QBrush(bgColor));
151  painter.drawRect(0, 0, width(), height());
152  }
153 
154  // Draw mouse highlight (if any)
160  painter.setPen(QPen(highlightColor, 0.5));
161  QColor bColor = highlightColor;
162  bColor.setAlpha(128);
163  painter.setBrush(QBrush(bColor));
164  painter.drawRect(x1, y1, x2 - x1, y2 - y1);
165  }
166 
167  // Draw key backgrounds on a separate pixmap so that a drop shadow can be applied to them.
168  QPixmap keyBG(wWidth * ratio, wHeight * ratio);
169  keyBG.fill(QColor(0, 0, 0, 0));
170  QPainter bgPainter(&keyBG);
171  bgPainter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
172  bgPainter.setPen(Qt::NoPen);
173  QHashIterator<QString, Key> k(keyMap);
174  uint i = -1;
175  while(k.hasNext()){
176  k.next();
177  i++;
178  const Key& key = k.value();
179  float x = key.x + offX - key.width / 2.f + 1.f;
180  float y = key.y + offY - key.height / 2.f + 1.f;
181  float w = key.width - 2.f;
182  float h = key.height - 2.f;
183  // In RGB mode, ignore keys without LEDs
184  if((_rgbMode && !key.hasLed)
185  || (!_rgbMode && !key.hasScan))
186  continue;
187  // Set color based on key highlight
188  bgPainter.setOpacity(1.);
189  if(highlight.testBit(i)){
190  if(animation.testBit(i))
191  bgPainter.setBrush(QBrush(highlightAnimColor));
192  else
193  bgPainter.setBrush(QBrush(highlightColor));
194  } else if(animation.testBit(i)){
195  bgPainter.setBrush(QBrush(animColor));
196  } else {
197  if(!strcmp(key.name, "sniper"))
198  // Sniper key uses a reddish base color instead of the usual grey
199  bgPainter.setBrush(QBrush(sniperColor));
200  else if(model == KeyMap::SCIMITAR && !strncmp(key.name, "thumb", 5) && strcmp(key.name, "thumb"))
201  // Thumbgrid keys use a black color
202  bgPainter.setBrush(QBrush(thumbColor));
203  else if(!strcmp(key.name, "lsidel") || !strcmp(key.name, "rsidel") || !strcmp(key.name, "logo"))
204  // Strafe side lights have different background
205  bgPainter.setBrush(QBrush(transparentColor));
206  else {
207  bgPainter.setBrush(QBrush(keyColor));
208  if(KeyMap::isMouse(model))
209  bgPainter.setOpacity(0.7);
210  }
211  }
212  if(model != KeyMap::STRAFE && (!strcmp(key.name, "mr") || !strcmp(key.name, "m1") || !strcmp(key.name, "m2") || !strcmp(key.name, "m3")
213  || !strcmp(key.name, "light") || !strcmp(key.name, "lock") || (model == KeyMap::K65 && !strcmp(key.name, "mute")))){
214  // Switch keys are circular except for Strafe. All Strafe keys are square
215  x += w / 8.f;
216  y += h / 8.f;
217  w *= 0.75f;
218  h *= 0.75f;
219  bgPainter.drawEllipse(QRectF(x * scale, y * scale, w * scale, h * scale));
220  } else {
221  if(!strcmp(key.name, "enter")){
222  if(key.height == 24){
223  // ISO enter key isn't rectangular
224  y = key.y + 1.f;
225  h = 10.f;
226  bgPainter.drawRect(QRectF((x + w - 13.f) * scale, y * scale, 13.f * scale, 22.f * scale));
227  } else {
228  // US enter key isn't perfectly centered, needs an extra pixel on the left to appear correctly
229  x -= 1.f;
230  w += 1.f;
231  }
232  } else if(!strcmp(key.name, "rshift") || !strcmp(key.name, "stop")){
233  // A few other keys also need extra pixels
234  x -= 1.f;
235  w += 1.f;
236  } else if(!strcmp(key.name, "caps") || !strcmp(key.name, "lshift") || !strcmp(key.name, "next")){
237  w += 1.f;
238  }
239  bgPainter.drawRect(QRectF(x * scale, y * scale, w * scale, h * scale));
240  }
241  }
242 
243  // Render the key decorations (RGB -> light circles, binding -> key names) on yet another layer
244  QPixmap decoration(wWidth * ratio, wHeight * ratio);
245  decoration.fill(QColor(0, 0, 0, 0));
246  QPainter decPainter(&decoration);
247  decPainter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
248  if(_rgbMode){
249  // Draw key colors (RGB mode)
250  QHashIterator<QString, Key> k(keyMap);
251  uint i = -1;
252  while(k.hasNext()){
253  k.next();
254  i++;
255  const Key& key = k.value();
256  if(!key.hasLed)
257  continue;
258  float x = key.x + offX - 1.8f;
259  float y = key.y + offY - 1.8f;
260  float w = 3.6f;
261  float h = 3.6f;
262  // Display a white circle around regular keys, red circle around indicators
263  if(_indicators.contains(key.name))
264  decPainter.setPen(QPen(QColor(255, 248, 136), 1.5));
265  else
266  decPainter.setPen(QPen(QColor(255, 255, 255), 1.5));
267  QRgb color;
268  const QRgb* inDisplay = _displayColorMap.colorForName(key.name);
269  if(inDisplay)
270  // Color in display map? Grab it from there
271  // (monochrome conversion not necessary as this would have been done by the animation)
272  color = *inDisplay;
273  else {
274  // Otherwise, read from base map
275  color = _colorMap.value(k.key());
276  if(_monochrome)
277  color = monoRgb(qRed(color), qGreen(color), qBlue(color));
278  }
279  decPainter.setBrush(QBrush(color));
280  if (model == KeyMap::STRAFE) { // STRAFE custom design and special keys
281  float kx = key.x + offX - key.width / 2.f + 1.f;
282  float ky = key.y + offY - key.height / 2.f + 1.f;
283  float kw = key.width - 2.f;
284  float kh = key.height - 2.f;
285  decPainter.setPen(QPen(QColor(255, 255, 255), 1.2)); // less invasive outline to show the key color better
286  if(!strcmp(key.name, "logo")) { // stylized logo
287  float lx = key.x + offX - key.width / 2.f + 2.f;
288  float ly = key.y + offY - key.height / 2.f + 2.f;
289  float lw = key.width - 4.f;
290  float lh = key.height - 4.f;
291  QPainterPath logo;
292  logo.moveTo(lx*scale,(ly+lh)*scale);
293  logo.quadTo((lx+2.f)*scale,(ly+lh/2.f)*scale,lx*scale,ly*scale);
294  logo.quadTo((lx+lw)*scale,ly*scale,(lx+lw)*scale,(ly+lh)*scale);
295  logo.quadTo((lx+lw/2.f)*scale,(ly+lh-4.f)*scale,lx*scale,(ly+lh)*scale);
296  decPainter.drawPath(logo);
297  //decPainter.setPen(QPen(Qt::green, 1.2)); //QColor(125,125,125)
298  //decPainter.drawRect(QRectF(lx * scale, ly * scale, lw * scale, lh * scale)); // don't really know why the 12 and 24 make it work here, but they do
299  } else if(!strcmp(key.name, "lsidel") || !strcmp(key.name, "rsidel")) { // Strafe side lights (toggle lights with no animation)
300  QRadialGradient gradient(QPointF(wWidth/2.f * ratio, wHeight/2.f * ratio), wWidth/2.f * ratio);//,QPointF(10, 5));
301  gradient.setColorAt(0, color);
302  gradient.setColorAt(0.9, color); // bring up intensity
303  gradient.setColorAt(1, bgColor);
304  decPainter.setBrush(QBrush(gradient));
305  decPainter.setPen(QPen(keyColor, 1.2)); //QColor(125,125,125)
306  decPainter.drawRect(QRectF(kx * scale, ky * scale - 12 , kw * scale, kh * scale+24)); // don't really know why the 12 and 24 make it work here, but they do
307  } else if(_indicators.contains(key.name)) { // FIX: This check fails whenever _indicators is empty because "show animated" is unchecked
308  decPainter.setPen(QPen(QColor(0,0,0,0), 1)); // no outline for the indicators, you can't change their color the standard way
309  decPainter.drawRect(QRectF((kx+2.f) * scale, (ky+2.f) * scale, (kw-4.f) * scale, (kh-4.f) * scale)); // square indicators
310  } else //everything else is a circle, just a tad bigger to show the key color better
311  decPainter.drawEllipse(QRectF((x-1.f) * scale, (y-1.f) * scale, (w+2.f) * scale, (h+2.f) * scale));
312  } else
313  decPainter.drawEllipse(QRectF(x * scale, y * scale, w * scale, h * scale));
314  }
315  } else {
316  // Draw key names
317  decPainter.setBrush(Qt::NoBrush);
318  QFont font = painter.font();
319  font.setBold(true);
320  font.setPixelSize(5.25f * scale);
321  QFont font0 = font;
322  QHashIterator<QString, Key> k(keyMap);
323  uint i = -1;
324  while(k.hasNext()){
325  k.next();
326  i++;
327  const Key& key = k.value();
328  if(!key.hasScan)
329  continue;
330  float x = key.x + offX - key.width / 2.f + 1.f;
331  float y = key.y + offY - key.height / 2.f;
332  float w = key.width - 2.f;
333  float h = key.height;
334  // Print the key's friendly name (with some exceptions)
335  QString keyName = KbBind::globalRemap(key.name);
336  QString name = key.friendlyName(false);
337  name = name.split(" ").last();
338  struct {
339  const char* keyName, *displayName;
340  } names[] = {
341  {"light", "☼"}, {"lock", "☒"}, {"mute", "◖⊘"}, {"volup", keyMap.model() == KeyMap::K65 ? "◖))" : "▲"}, {"voldn", keyMap.model() == KeyMap::K65 ? "◖)" : "▼"},
342  {"prtscn", "PrtScn\nSysRq"}, {"scroll", "Scroll\nLock"}, {"pause", "Pause\nBreak"}, {"stop", "▪"}, {"prev", "|◂◂"}, {"play", "▸||"}, {"next", "▸▸|"},
343  {"pgup", "Page\nUp"}, {"pgdn", "Page\nDown"}, {"numlock", "Num\nLock"},
344  {"caps", "Caps"}, {"lshift", "Shift"}, {"rshift", "Shift"},
345 #ifdef Q_OS_MACX
346  {"lctrl", "⌃"}, {"rctrl", "⌃"}, {"lwin", "⌘"}, {"rwin", "⌘"}, {"lalt", "⌥"}, {"ralt", "⌥"},
347 #else
348  {"lctrl", "Ctrl"}, {"rctrl", "Ctrl"}, {"lwin", "❖"}, {"rwin", "❖"}, {"lalt", "Alt"}, {"ralt", "Alt"},
349 #endif
350  {"rmenu", "▤"}, {"up", "▲"}, {"left", "◀"}, {"down", "▼"}, {"right", "▶"}, {"fn","Fn"},
351  {"mouse1", ""}, {"mouse2", ""}, {"mouse3", "∙"}, {"dpiup", "▲"}, {"dpidn", "▼"}, {"wheelup", "▲"}, {"wheeldn", "▼"}, {"dpi", "◉"}, {"mouse5", "▲"}, {"mouse4", "▼"}, {"sniper", "⊕"}
352  };
353  for(uint k = 0; k < sizeof(names) / sizeof(names[0]); k++){
354  if(keyName == names[k].keyName){
355  name = names[k].displayName;
356  break;
357  }
358  }
359  if(keyName == "thumb1" && model == KeyMap::SABRE)
360  name = "∙";
361  if(keyName == "mr" || keyName == "m1" || keyName == "m2" || keyName == "m3" || keyName == "up" || keyName == "down" || keyName == "left" || keyName == "right")
362  // Use a smaller size for MR, M1 - M3, and arrow keys
363  font.setPixelSize(font.pixelSize() * 0.75);
364  else if(keyName == "end")
365  // Use a smaller size for "End" to match everything else in that area
366  font.setPixelSize(font.pixelSize() * 0.65);
367  else if(keyName == "light"
368 #ifndef Q_OS_MACX
369  || keyName == "lwin" || keyName == "rwin"
370 #endif
371  )
372  // Use a larger font size for Super (Linux only) and Brightness to compensate for the unicode symbols looking smaller
373  font.setPixelSize(font.pixelSize() * 1.3);
374  if((layout == KeyMap::EU || layout == KeyMap::EU_DVORAK) && (keyName == "hash" || keyName == "bslash_iso"))
375  // Don't differentiate backslashes on the EU layout
376  name = "\\";
377  // Determine the appropriate size to draw the text at
378  decPainter.setFont(font);
379  QRectF rect(x * scale, y * scale - 1, w * scale, h * scale);
380  int flags = Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextWordWrap;
381  QRectF bounds = decPainter.boundingRect(rect, flags, name);
382  while((bounds.height() >= rect.height() - 8. || bounds.width() >= rect.width() - 2.) && font.pixelSize() >= 5){
383  // Scale font size down until it fits inside the key
384  font.setPixelSize(font.pixelSize() - 2);
385  decPainter.setFont(font);
386  bounds = decPainter.boundingRect(rect, flags, name);
387  }
388  // Pick color based on key function
389  QString bind = _bindMap.value(key.name);
390  QString def = KbBind::defaultAction(key.name);
391  if(bind.isEmpty())
392  // Unbound - red
393  decPainter.setPen(QColor(255, 136, 136));
394  else if(KeyAction(bind).isProgram())
395  // Custom program - orange
396  decPainter.setPen(QColor(255, 224, 192));
397  else if(KeyAction(bind).isSpecial() && (bind == def || !KeyAction(def).isSpecial()))
398  // Special function - blue (only if not mapped to a different function - if a special function is remapped, color it yellow)
399  decPainter.setPen(QColor(128, 224, 255));
400  else if(KeyAction(bind).isMedia() && (bind == def || !KeyAction(def).isMedia()))
401  // Media key - green
402  decPainter.setPen(QColor(160, 255, 168));
403  else if(bind == def)
404  // Standard key - white
405  decPainter.setPen(QColor(255, 255, 255));
406  else
407  // Remapped key - yellow
408  decPainter.setPen(QColor(255, 248, 128));
409  decPainter.drawText(rect, flags, name);
410  font = font0;
411  }
412  }
413  // Create drop shadow effects
414  QGraphicsDropShadowEffect* bgEffect = new QGraphicsDropShadowEffect; // Have to use "new", creating these on the stack causes a crash...
415  bgEffect->setBlurRadius(2.);
416  bgEffect->setColor(QColor(0, 0, 0, 32));
417  bgEffect->setOffset(0, 1);
418  QGraphicsDropShadowEffect* decEffect = new QGraphicsDropShadowEffect;
419  decEffect->setBlurRadius(4.);
420  decEffect->setColor(QColor(0, 0, 0, 104));
421  decEffect->setOffset(0, 1);
422  // Apply them to the pixmaps
423  QGraphicsPixmapItem* bgItem = new QGraphicsPixmapItem(keyBG);
424  bgItem->setGraphicsEffect(bgEffect);
425  QGraphicsPixmapItem* decItem = new QGraphicsPixmapItem(decoration);
426  decItem->setGraphicsEffect(decEffect);
427  // Render everything
428  QGraphicsScene* scene = new QGraphicsScene;
429  scene->addItem(bgItem);
430  scene->addItem(decItem);
431  // It has to be rendered onto yet another pixmap or else DPI scaling will look terrible...
432  QPixmap final(wWidth * ratio, wHeight * ratio);
433  final.fill(QColor(0, 0, 0, 0));
434  QPainter finalPainter(&final);
435  scene->render(&finalPainter, QRectF(0, 0, wWidth * ratio, wHeight * ratio), QRectF(0, 0, wWidth * ratio, wHeight * ratio));
436  delete scene; // <- Automatically cleans up the rest of the objects
437 #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
438  final.setDevicePixelRatio(ratio);
439 #endif
440  painter.drawPixmap(QPointF(0., 0.), final);
441 }
442 
443 void KeyWidget::mousePressEvent(QMouseEvent* event){
444  event->accept();
445  mouseDownMode = (event->modifiers() & Qt::AltModifier) ? SUBTRACT : (event->modifiers() & Qt::ShiftModifier) ? ADD : (event->modifiers() & Qt::ControlModifier) ? TOGGLE : SET;
446  mouseDownX = mouseCurrentX = event->x();
447  mouseDownY = mouseCurrentY = event->y();
448  // See if the event hit a key
449  float scale, offX, offY;
450  drawInfo(scale, offX, offY);
451  float mx = mouseCurrentX / scale - offX, my = mouseCurrentY / scale - offY;
452  QHashIterator<QString, Key> k(keyMap);
453  uint i = -1;
454  while(k.hasNext()){
455  k.next();
456  i++;
457  const Key& key = k.value();
458  if((_rgbMode && !key.hasLed)
459  || (!_rgbMode && !key.hasScan))
460  continue;
461  if(fabs(key.x - mx) <= key.width / 2.f - 1.f && fabs(key.y - my) <= key.height / 2.f - 1.f){
462  // Sidelights can't have a color, but they can be toggled
463  if(!strcmp(key.name, "lsidel") || !strcmp(key.name, "rsidel")){
464  emit sidelightToggled(); // get the kblightwidget to record it
465  update();
466  break;
467  }
468  newSelection.setBit(i);
469  update();
470  break;
471  }
472  }
473 }
474 
475 void KeyWidget::mouseMoveEvent(QMouseEvent* event){
476  event->accept();
477  QString tooltip;
478 
479  // Find selection rectangle
480  mouseCurrentX = event->x();
481  mouseCurrentY = event->y();
482  float scale, offX, offY;
483  drawInfo(scale, offX, offY);
484  float mx = mouseCurrentX / scale - offX, my = mouseCurrentY / scale - offY;
485  float mx1, mx2, my1, my2;
486  if(mouseCurrentX >= mouseDownX){
487  mx1 = mouseDownX / scale - offX;
488  mx2 = mouseCurrentX / scale - offX;
489  } else {
490  mx1 = mouseCurrentX / scale - offX;
491  mx2 = mouseDownX / scale - offX;
492  }
493  if(mouseCurrentY >= mouseDownY){
494  my1 = mouseDownY / scale - offY;
495  my2 = mouseCurrentY / scale - offY;
496  } else {
497  my1 = mouseCurrentY / scale - offY;
498  my2 = mouseDownY / scale - offY;
499  }
500  // Clear new selection
501  if(mouseDownMode != NONE)
502  newSelection.fill(false);
503  // See if the event hit any keys
504  QHashIterator<QString, Key> k(keyMap);
505  uint i = -1;
506  while(k.hasNext()){
507  k.next();
508  i++;
509  const Key& key = k.value();
510  if((_rgbMode && !key.hasLed)
511  || (!_rgbMode && !key.hasScan))
512  continue;
513  // Update tooltip with the mouse hover (if any), even if it's not selectable
514  if(fabs(key.x - mx) <= key.width / 2.f - 1.f && fabs(key.y - my) <= key.height / 2.f - 1.f
515  && tooltip.isEmpty())
516  tooltip = key.friendlyName(false);
517  // on STRAFE Sidelights and indicators can't be assigned color the way other keys are colored
518  if(keyMap.model() == KeyMap::STRAFE && (!strcmp(key.name, "lsidel") || !strcmp(key.name, "rsidel") || _indicators.contains(key.name))) // FIX: _indicators check fails whenever _indicators is empty because "show animated" is unchecked
519  continue;
520  float kx1 = key.x - key.width / 2.f + 1.f;
521  float ky1 = key.y - key.height / 2.f + 1.f;
522  float kx2 = kx1 + key.width - 2.f;
523  float ky2 = ky1 + key.height - 2.f;
524  // If they overlap, add the key to the selection
525  if(!(mx1 >= kx2 || kx1 >= mx2)
526  && !(my1 >= ky2 || ky1 >= my2)
527  && mouseDownMode != NONE)
528  newSelection.setBit(i);
529  }
530 
531  if(mouseDownMode != NONE)
532  update();
533  setToolTip(tooltip);
534 }
535 
536 void KeyWidget::mouseReleaseEvent(QMouseEvent* event){
537  event->accept();
538  if(mouseDownMode == NONE)
539  return;
540  // Apply the new selection
541  switch(mouseDownMode){
542  case SET:
544  break;
545  case ADD:
547  break;
548  case SUBTRACT:
550  break;
551  case TOGGLE:
553  break;
554  default:;
555  }
556  // Clear mousedown state.
557  newSelection.fill(false);
559  // Emit signal with the names of the keys
560  QStringList selectedNames;
561  uint i = 0;
562  foreach(const QString& key, keyMap.keys()){
563  if(selection.testBit(i++))
564  selectedNames << key;
565  }
566  emit selectionChanged(selectedNames);
567  update();
568 }
569 
570 void KeyWidget::setSelection(const QStringList& keys){
571  selection.fill(false);
572  QStringList allNames = keyMap.keys();
573  foreach(const QString& key, keys){
574  int index = allNames.indexOf(key);
575  if(index >= 0)
576  selection.setBit(index);
577  }
578  newSelection.fill(false);
580  update();
581  emit selectionChanged(keys);
582 }
583 
585  selection.fill(false);
586  // Fill the selection with all keys that have an LED/scancode (depending on widget mode)
587  int i = 0;
588  QStringList selectedNames;
589  foreach(const Key& key, keyMap.positions()){
590  // Sidelights can't be selected
591  if(strcmp(key.name, "lsidel") && strcmp(key.name, "rsidel")
592  && ((_rgbMode && key.hasLed) || !(_rgbMode && key.hasScan))){
593  selection.setBit(i);
594  selectedNames << key.name;
595  }
596  i++;
597  }
598  // Clear mousedown state
599  newSelection.fill(false);
601  update();
602  emit selectionChanged(selectedNames);
603 }
604 
606  selection.fill(false);
607  newSelection.fill(false);
609  update();
610  emit selectionChanged(QStringList());
611 }
612 
613 void KeyWidget::setAnimation(const QStringList& keys){
614  animation.fill(false);
615  QStringList allNames = keyMap.keys();
616  foreach(const QString& key, keys){
617  // Sidelights can't be selected
618  if(!strcmp(key.toLatin1(), "lsidel") || !strcmp(key.toLatin1(), "rsidel"))
619  continue;
620  int index = allNames.indexOf(key);
621  if(index >= 0)
622  animation.setBit(index);
623  }
624  update();
625 }
626 
629  update();
630 }
631 
633  animation.fill(false);
634  update();
635 }
Layout
Definition: keymap.h:65
uint width() const
Definition: keymap.h:120
void clearSelection()
Definition: keywidget.cpp:605
void selectAll()
Definition: keywidget.cpp:584
float y
Definition: main.c:66
void clearAnimation()
Definition: keywidget.cpp:632
static bool isMouse(Model model)
Definition: keymap.h:95
static const int KEY_SIZE
Definition: keywidget.cpp:10
static QString globalRemap(const QString &key)
Definition: kbbind.cpp:98
const BindMap & bindMap() const
Definition: keywidget.h:31
QString friendlyName(bool os=true) const
Definition: keymap.h:23
bool isMouse() const
Definition: keymap.h:96
float x
Definition: main.c:66
short width
Definition: keymap.h:17
void setSelection(const QStringList &keys)
Definition: keywidget.cpp:570
void drawInfo(float &scale, float &offsetX, float &offsetY, int ratio=1)
Definition: keywidget.cpp:43
int mouseDownX
Definition: keywidget.h:64
const KeyMap & map() const
Definition: keywidget.h:24
bool hasLed
Definition: keymap.h:19
void mouseReleaseEvent(QMouseEvent *event)
Definition: keywidget.cpp:536
double width
Definition: main.c:52
QHash< QString, QString > BindMap
Definition: keywidget.h:30
short height
Definition: keymap.h:17
int mouseCurrentY
Definition: keywidget.h:65
QRgb monoRgb(float r, float g, float b)
Definition: kblight.cpp:284
void selectionChanged(QStringList selected)
Definition: keymap.h:49
bool _monochrome
Definition: keywidget.h:73
Definition: command.h:9
void mouseMoveEvent(QMouseEvent *event)
Definition: keywidget.cpp:475
static QImage * sabOverlay
Definition: keywidget.cpp:12
const QColorMap & colorMap() const
Definition: keywidget.h:27
QRgb * colorForName(const char *name)
Definition: colormap.cpp:72
ColorMap _displayColorMap
Definition: keywidget.h:57
void sidelightToggled()
enum KeyWidget::@2 mouseDownMode
bool _rgbMode
Definition: keywidget.h:73
void mousePressEvent(QMouseEvent *event)
Definition: keywidget.cpp:443
static QImage * m65Overlay
Definition: keywidget.cpp:12
static QString defaultAction(const QString &key)
Definition: kbbind.cpp:145
short x
Definition: keymap.h:16
Layout layout() const
Definition: keymap.h:114
QBitArray selection
Definition: keywidget.h:61
void paintEvent(QPaintEvent *)
Definition: keywidget.cpp:70
QBitArray animation
Definition: keywidget.h:63
KeyMap keyMap
Definition: keywidget.h:55
void setAnimationToSelection()
Definition: keywidget.cpp:627
bool hasScan
Definition: keymap.h:20
QHash< QString, QRgb > QColorMap
Definition: colormap.h:9
const char * name
Definition: keymap.h:14
Model
Definition: keymap.h:51
static QImage * scimOverlay
Definition: keywidget.cpp:12
int mouseDownY
Definition: keywidget.h:64
KeyWidget(QWidget *parent=0, bool rgbMode=true)
Definition: keywidget.cpp:17
Definition: keymap.h:8
QStringList keys() const
Definition: keymap.h:131
Definition: keymap.h:49
BindMap _bindMap
Definition: keywidget.h:58
QSet< QString > _indicators
Definition: keywidget.h:59
Model model() const
Definition: keymap.h:113
QList< Key > positions() const
Definition: keymap.h:132
QColorMap _colorMap
Definition: keywidget.h:56
void displayColorMap(const ColorMap &newDisplayMap, const QSet< QString > &indicators=QSet< QString >())
Definition: keywidget.cpp:57
uint height() const
Definition: keymap.h:122
QBitArray newSelection
Definition: keywidget.h:62
uint count() const
Definition: keymap.h:118
void setAnimation(const QStringList &keys)
Definition: keywidget.cpp:613
int mouseCurrentX
Definition: keywidget.h:65
short y
Definition: keymap.h:16