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
gradientdialogwidget.cpp
Go to the documentation of this file.
1 #include <cmath>
2 #include <QPainter>
3 #include <QPropertyAnimation>
4 #include "gradientdialogwidget.h"
5 
7  QWidget(parent), selectedPos(-1), _current(-1)
8 {
9  setMouseTracking(true);
10 }
11 
12 void GradientDialogWidget::setStops(const QGradientStops& stops){
13  _stops = stops;
14  _colors.clear();
15  foreach(const QGradientStop& stop, stops){
16  double pos = stop.first;
17  if(pos < 0. || pos > 1.)
18  continue;
19  _colors[round(pos * 100.)] = stop.second;
20  }
21  _current = 0;
22 #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
23  emit currentChanged(_colors.first(), false, 0);
24 #else
25  emit currentChanged(_colors.value(_colors.keys().first()), false, 0);
26 #endif
27  update();
28 }
29 
31  _stops.clear();
32  QMap<int, QColor> colors = selectionColors();
33  // If there's only a single color, put it at the beginning and end
34  if(colors.count() == 1){
35 #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
36  QColor color = colors.first();
37 #else
38  QColor color = colors.value(colors.keys().first());
39 #endif
40  _stops.append(QGradientStop(0., color));
41  _stops.append(QGradientStop(1., color));
42  update();
43  return;
44  }
45  // Add colors at 0 and 100 if needed
46 #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
47  if(!colors.contains(0))
48  colors[0] = colors.first();
49  if(!colors.contains(100))
50  colors[100] = colors.last();
51 #else
52  if(!colors.contains(0))
53  colors[0] = colors.value(colors.keys().first());
54  if(!colors.contains(100))
55  colors[100] = colors.value(colors.keys().last());
56 #endif
57  QMapIterator<int, QColor> i(colors);
58  while(i.hasNext()){
59  i.next();
60  _stops.append(QGradientStop(i.key() / 100., i.value()));
61  }
62  update();
63 }
64 
65 QColor GradientDialogWidget::colorAt(int position){
66  // Find which stops the position is between
67  qreal pos = position / 100.;
68  QVectorIterator<QGradientStop> i(_stops);
69  QGradientStop previous = i.next();
70  while(i.hasNext()){
71  QGradientStop next = i.next();
72  if(next.first >= pos){
73  // Get color by linear interpolation. Premultiply the alpha value so that it returns the expected color
74  // (i.e. stops with zero opacity won't contribute to color)
75  QColor c1 = next.second, c2 = previous.second;
76  qreal distance = next.first - previous.first;
77  qreal dx = (pos - previous.first) / distance;
78  qreal a1 = c1.alphaF(), a2 = c2.alphaF();
79  qreal a3 = a1 * dx + a2 * (1.f - dx);
80  if(a3 == 0.){
81  c2.setAlpha(0);
82  return c2;
83  }
84  qreal r = (c1.redF() * a1 * dx + c2.redF() * a2 * (1.f - dx)) / a3;
85  qreal g = (c1.greenF() * a1 * dx + c2.greenF() * a2 * (1.f - dx)) / a3;
86  qreal b = (c1.blueF() * a1 * dx + c2.blueF() * a2 * (1.f - dx)) / a3;
87  return QColor::fromRgbF(r, g, b, a3);
88  }
89  previous = next;
90  }
91  return QColor();
92 }
93 
95  if(_current < 0 || to == _current || selected.isValid())
96  return _current;
97  // If there's a point in the way, skip past it by continuing in the current direction
98  if(_current < to){
99  while(_colors.contains(to)){
100  to++;
101  if(to > 100)
102  return _current;
103  }
104  } else {
105  while(_colors.contains(to)){
106  to--;
107  if(to < 0)
108  return _current;
109  }
110  }
111  _colors[to] = _colors.take(_current);
112  _current = to;
113  makeStops();
114  return to;
115 }
116 
117 void GradientDialogWidget::setCurrentColor(const QColor& color){
118  if(_current < 0 || selected.isValid())
119  return;
120  QRgb rgb = _colors.value(_current).rgb();
121  _colors[_current] = color;
122  // If any points follow with the same color but different opacity, change them to match
123  QMutableMapIterator<int, QColor> i(_colors);
124  while(i.hasNext()){
125  i.next();
126  if(i.key() <= _current)
127  continue;
128  QColor& value = i.value();
129  if(value.rgb() != rgb)
130  break;
131  int alpha = value.alpha();
132  value = color;
133  value.setAlpha(alpha);
134  }
135  makeStops();
136 }
137 
139  int x = 8, y = 1;
140  int w = (width() - x * 2) / 16 * 16, h = (height() - 24) / 16 * 16;
141  return QRect(x, y, w, h);
142 }
143 
145  QRect fill = fillRect();
146  int sx = round(pos / 100. * fill.width()) + fill.x() - 6;
147  int sw = 12, sh = 18;
148  int sy = height() - sh - 2;
149  return QRect(sx, sy, sw, sh);
150 }
151 
153  QRect rect = fillRect();
154  int res = round((selectedPos - rect.x()) * 100. / rect.width());
155  if(res < 0 || res > 100)
156  return -1;
157  return res;
158 }
159 
161  if(!selected.isValid())
162  return _colors;
163  // Determine selected stop position
164  int selPos = selectedStop();
165  // Re-add if in range
166  QMap<int, QColor> res = _colors;
167  if(selPos >= 0 && selPos <= 100)
168  res[selPos] = selected;
169  return res;
170 }
171 
173  QPainter painter(this);
174  QRect fill = fillRect();
175  int x = fill.x(), y = fill.y(), w = fill.width(), h = fill.height();
176 
177  // Draw border around gradient
178  painter.setPen(palette().color(QPalette::Dark));
179  painter.drawLine(x - 1, y - 1, x + w, y - 1);
180  painter.drawLine(x - 1, y - 1, x - 1, y + h);
181  painter.setPen(palette().color(QPalette::Light));
182  painter.drawLine(x - 1, y + h, x + w, y + h);
183  painter.drawLine(x + w, y - 1, x + w, y + h);
184  // Draw background grid
185  for(int i = 0; i < w; i += 16){
186  for(int iy = 0; iy < h; iy += 16){
187  if(i % 32 != iy % 32)
188  painter.fillRect(x + i, y + iy, 16, 16, QColor(192, 192, 192));
189  else
190  painter.fillRect(x + i, y + iy, 16, 16, QColor(255, 255, 255));
191  }
192  }
193  // Draw gradient
194  painter.setRenderHint(QPainter::Antialiasing);
195  QLinearGradient gradient(x, 0, x + w, 0);
196  gradient.setStops(_stops);
197  painter.fillRect(fill, QBrush(gradient));
198 
199  // Draw stops
200  QMapIterator<int, QColor> i(_colors);
201  painter.setPen(palette().color(QPalette::Shadow));
202  while(i.hasNext()){
203  i.next();
204  painter.setBrush(QBrush(i.value()));
205  int index = i.key();
206  if(index == _current){
207  // Highlight currently-edited stop
208  painter.setPen(QPen(palette().color(QPalette::Highlight), 2));
209  painter.drawRoundedRect(stopRect(index), 4, 4);
210  painter.setPen(palette().color(QPalette::Shadow));
211  } else
212  painter.drawRoundedRect(stopRect(index), 4, 4);
213  }
214  // Draw selection (if any)
215  if(selected.isValid() && selectedPos >= x && selectedPos <= x + w){
216  painter.setPen(QPen(palette().color(QPalette::Highlight), 2.5));
217  painter.setBrush(selected);
218  painter.drawRoundedRect(selectedPos - 6, height() - 18 - 2, 12, 18, 4, 4);
219  }
220 }
221 
222 void GradientDialogWidget::mousePressEvent(QMouseEvent* event){
223  int x = event->x(), y = event->y();
224  if(y < height() - 24)
225  return;
226  QMapIterator<int, QColor> i(_colors);
227  while(i.hasNext()){
228  i.next();
229  // If a point was selected, remove it from the color map and set it as the selected point
230  QRect stop = stopRect(i.key());
231  if(x >= stop.left() - 1 && x <= stop.right() + 1){
232  selected = i.value();
233  selectedPos = stop.x() + stop.width() / 2;
235  _colors.remove(i.key());
236  // On right click, delete the point
237  if(event->button() == Qt::RightButton && _colors.count() > 1){
238  selectedPos = -1;
239  mouseReleaseEvent(event);
240  } else
241  update();
242  return;
243  }
244  }
245  // If nothing was selected, create a new point
246  QRect fill = fillRect();
247  if(x > fill.left() && x < fill.right() && event->button() != Qt::RightButton){
248  selectedPos = x;
249  selectedOffset = 0;
251  makeStops();
252  }
253 }
254 
255 void GradientDialogWidget::mouseMoveEvent(QMouseEvent* event){
256  if(!selected.isValid()){
257  if(event->y() >= height() - 24)
258  setCursor(QCursor(Qt::PointingHandCursor));
259  else
260  setCursor(QCursor(Qt::ArrowCursor));
261  return;
262  }
263  // Move selected point (if any)
264  setCursor(QCursor(Qt::ClosedHandCursor));
265  selectedPos = event->x() + selectedOffset;
266  // Allow the point to be deleted as long as there is at least 1 other point
267  bool last = (_colors.count() == 0);
268  // Hug the left/right edges
269  QRect rect = fillRect();
270  int left = rect.left(), right = rect.right();
271  if(selectedPos < left && (last || selectedPos >= left - 30))
272  selectedPos = left;
273  else if(selectedPos > right && (last || selectedPos <= right + 30))
274  selectedPos = right;
275  // Remove point if it's too far above/below the widget
276  int top = -30, bottom = height() + 30;
277  if(!last && (event->y() < top || event->y() > bottom))
278  selectedPos = -1;
279  makeStops();
280 }
281 
283  if(selected.isValid()){
284  // Rejoin selection with gradient
287  emit currentChanged(_colors.value(_current), true, _current);
288  selectedPos = -1;
289  selected = QColor();
290  makeStops();
291  }
292  if(event->y() >= height() - 24)
293  setCursor(QCursor(Qt::PointingHandCursor));
294  else
295  setCursor(QCursor(Qt::ArrowCursor));
296 }
QColor colorAt(int position)
float y
Definition: main.c:66
void mouseMoveEvent(QMouseEvent *event)
void mousePressEvent(QMouseEvent *event)
void currentChanged(QColor color, bool spontaneous, int position)
float x
Definition: main.c:66
double width
Definition: main.c:52
void setStops(const QGradientStops &stops)
double top
Definition: main.c:51
QMap< int, QColor > selectionColors()
Definition: main.c:42
void setCurrentColor(const QColor &color)
double left
Definition: main.c:51
static QString right(const QString &left)
void mouseReleaseEvent(QMouseEvent *event)
GradientDialogWidget(QWidget *parent=0)
QMap< int, QColor > _colors
void paintEvent(QPaintEvent *)