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