Qt Utilities  5.6.0
Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models
paletteeditor.cpp
Go to the documentation of this file.
1 #include "./paletteeditor.h"
2 #include "./colorbutton.h"
3 
4 #include "ui_paletteeditor.h"
5 
6 #include <QMetaProperty>
7 #include <QPainter>
8 #include <QToolButton>
9 #include <QLabel>
10 #include <QHeaderView>
11 
12 using namespace Widgets;
13 
14 namespace Dialogs {
15 
16 enum { BrushRole = 33 };
17 
18 PaletteEditor::PaletteEditor(QWidget *parent) :
19  QDialog(parent),
20  m_ui(new Ui::PaletteEditor),
21  m_currentColorGroup(QPalette::Active),
22  m_paletteModel(new PaletteModel(this)),
23  m_modelUpdated(false),
24  m_paletteUpdated(false),
25  m_compute(true)
26 {
27  m_ui->setupUi(this);
28  m_ui->paletteView->setModel(m_paletteModel);
29  updatePreviewPalette();
30  updateStyledButton();
31  m_ui->paletteView->setModel(m_paletteModel);
32  ColorDelegate *delegate = new ColorDelegate(this);
33  m_ui->paletteView->setItemDelegate(delegate);
34  m_ui->paletteView->setEditTriggers(QAbstractItemView::AllEditTriggers);
35  connect(m_paletteModel, &PaletteModel::paletteChanged,
36  this, &PaletteEditor::paletteChanged);
37  m_ui->paletteView->setSelectionBehavior(QAbstractItemView::SelectRows);
38  m_ui->paletteView->setDragEnabled(true);
39  m_ui->paletteView->setDropIndicatorShown(true);
40  m_ui->paletteView->setRootIsDecorated(false);
41  m_ui->paletteView->setColumnHidden(2, true);
42  m_ui->paletteView->setColumnHidden(3, true);
43 }
44 
46 {}
47 
48 QPalette PaletteEditor::palette() const
49 {
50  return m_editPalette;
51 }
52 
53 void PaletteEditor::setPalette(const QPalette &palette)
54 {
55  m_editPalette = palette;
56  const uint mask = palette.resolve();
57  for (int i = 0; i < (int)QPalette::NColorRoles; i++) {
58  if (!(mask & (1 << i))) {
59  m_editPalette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(i),
60  m_parentPalette.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i)));
61  m_editPalette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i),
62  m_parentPalette.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i)));
63  m_editPalette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i),
64  m_parentPalette.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i)));
65  }
66  }
67  m_editPalette.resolve(mask);
68  updatePreviewPalette();
69  updateStyledButton();
70  m_paletteUpdated = true;
71  if (!m_modelUpdated)
72  m_paletteModel->setPalette(m_editPalette, m_parentPalette);
73  m_paletteUpdated = false;
74 }
75 
76 void PaletteEditor::setPalette(const QPalette &palette, const QPalette &parentPalette)
77 {
78  m_parentPalette = parentPalette;
79  setPalette(palette);
80 }
81 
82 void PaletteEditor::on_buildButton_colorChanged(const QColor &)
83 {
84  buildPalette();
85 }
86 
87 void PaletteEditor::on_activeRadio_clicked()
88 {
89  m_currentColorGroup = QPalette::Active;
90  updatePreviewPalette();
91 }
92 
93 void PaletteEditor::on_inactiveRadio_clicked()
94 {
95  m_currentColorGroup = QPalette::Inactive;
96  updatePreviewPalette();
97 }
98 
99 void PaletteEditor::on_disabledRadio_clicked()
100 {
101  m_currentColorGroup = QPalette::Disabled;
102  updatePreviewPalette();
103 }
104 
105 void PaletteEditor::on_computeRadio_clicked()
106 {
107  if (m_compute)
108  return;
109  m_ui->paletteView->setColumnHidden(2, true);
110  m_ui->paletteView->setColumnHidden(3, true);
111  m_compute = true;
112  m_paletteModel->setCompute(true);
113 }
114 
115 void PaletteEditor::on_detailsRadio_clicked()
116 {
117  if (!m_compute)
118  return;
119  const int w = m_ui->paletteView->columnWidth(1);
120  m_ui->paletteView->setColumnHidden(2, false);
121  m_ui->paletteView->setColumnHidden(3, false);
122  QHeaderView *header = m_ui->paletteView->header();
123  header->resizeSection(1, w / 3);
124  header->resizeSection(2, w / 3);
125  header->resizeSection(3, w / 3);
126  m_compute = false;
127  m_paletteModel->setCompute(false);
128 }
129 
130 void PaletteEditor::paletteChanged(const QPalette &palette)
131 {
132  m_modelUpdated = true;
133  if (!m_paletteUpdated) {
134  setPalette(palette);
135  }
136  m_modelUpdated = false;
137 }
138 
139 void PaletteEditor::buildPalette()
140 {
141  const QColor btn(m_ui->buildButton->color());
142  const QPalette temp(btn);
143  setPalette(temp);
144 }
145 
146 void PaletteEditor::updatePreviewPalette()
147 {
148  const QPalette::ColorGroup g = currentColorGroup();
149  // build the preview palette
150  const QPalette currentPalette = palette();
151  QPalette previewPalette;
152  for(int i = QPalette::WindowText; i < QPalette::NColorRoles; ++i) {
153  const QPalette::ColorRole r = static_cast<QPalette::ColorRole>(i);
154  const QBrush br = currentPalette.brush(g, r);
155  previewPalette.setBrush(QPalette::Active, r, br);
156  previewPalette.setBrush(QPalette::Inactive, r, br);
157  previewPalette.setBrush(QPalette::Disabled, r, br);
158  }
159 }
160 
161 void PaletteEditor::updateStyledButton()
162 {
163  m_ui->buildButton->setColor(palette().color(QPalette::Active, QPalette::Button));
164 }
165 
166 QPalette PaletteEditor::getPalette(QWidget *parent, const QPalette &init,
167  const QPalette &parentPal, int *ok)
168 {
169  PaletteEditor dlg(parent);
170  QPalette parentPalette(parentPal);
171  uint mask = init.resolve();
172  for (int i = 0; i < (int)QPalette::NColorRoles; ++i) {
173  if (!(mask & (1 << i))) {
174  parentPalette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(i),
175  init.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i)));
176  parentPalette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i),
177  init.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i)));
178  parentPalette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i),
179  init.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i)));
180  }
181  }
182  dlg.setPalette(init, parentPalette);
183 
184  const int result = dlg.exec();
185  if (ok) *ok = result;
186 
187  return result == QDialog::Accepted ? dlg.palette() : init;
188 }
189 
191 
192 PaletteModel::PaletteModel(QObject *parent) :
193  QAbstractTableModel(parent),
194  m_compute(true)
195 {
196  const QMetaObject *meta = metaObject();
197  const int index = meta->indexOfProperty("colorRole");
198  const QMetaProperty p = meta->property(index);
199  const QMetaEnum e = p.enumerator();
200  for (int r = QPalette::WindowText; r < QPalette::NColorRoles; r++) {
201  m_roleNames[static_cast<QPalette::ColorRole>(r)] = QLatin1String(e.key(r));
202  }
203 }
204 
205 int PaletteModel::rowCount(const QModelIndex &) const
206 {
207  return m_roleNames.count();
208 }
209 
210 int PaletteModel::columnCount(const QModelIndex &) const
211 {
212  return 4;
213 }
214 
215 QVariant PaletteModel::data(const QModelIndex &index, int role) const
216 {
217  if (!index.isValid())
218  return QVariant();
219  if (index.row() < 0 || index.row() >= QPalette::NColorRoles)
220  return QVariant();
221  if (index.column() < 0 || index.column() >= 4)
222  return QVariant();
223 
224  if (index.column() == 0) {
225  if (role == Qt::DisplayRole)
226  return m_roleNames[static_cast<QPalette::ColorRole>(index.row())];
227  if (role == Qt::EditRole) {
228  const uint mask = m_palette.resolve();
229  if (mask & (1 << index.row()))
230  return true;
231  return false;
232  }
233  return QVariant();
234  }
235  if (role == BrushRole)
236  return m_palette.brush(columnToGroup(index.column()),
237  static_cast<QPalette::ColorRole>(index.row()));
238  return QVariant();
239 }
240 
241 bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int role)
242 {
243  if (!index.isValid())
244  return false;
245 
246  if (index.column() != 0 && role == BrushRole) {
247  const QBrush br = qvariant_cast<QBrush>(value);
248  const QPalette::ColorRole r = static_cast<QPalette::ColorRole>(index.row());
249  const QPalette::ColorGroup g = columnToGroup(index.column());
250  m_palette.setBrush(g, r, br);
251 
252  QModelIndex idxBegin = PaletteModel::index(r, 0);
253  QModelIndex idxEnd = PaletteModel::index(r, 3);
254  if (m_compute) {
255  m_palette.setBrush(QPalette::Inactive, r, br);
256  switch (r) {
257  case QPalette::WindowText:
258  case QPalette::Text:
259  case QPalette::ButtonText:
260  case QPalette::Base:
261  break;
262  case QPalette::Dark:
263  m_palette.setBrush(QPalette::Disabled, QPalette::WindowText, br);
264  m_palette.setBrush(QPalette::Disabled, QPalette::Dark, br);
265  m_palette.setBrush(QPalette::Disabled, QPalette::Text, br);
266  m_palette.setBrush(QPalette::Disabled, QPalette::ButtonText, br);
267  idxBegin = PaletteModel::index(0, 0);
268  idxEnd = PaletteModel::index(m_roleNames.count() - 1, 3);
269  break;
270  case QPalette::Window:
271  m_palette.setBrush(QPalette::Disabled, QPalette::Base, br);
272  m_palette.setBrush(QPalette::Disabled, QPalette::Window, br);
273  idxBegin = PaletteModel::index(QPalette::Base, 0);
274  break;
275  case QPalette::Highlight:
276  //m_palette.setBrush(QPalette::Disabled, QPalette::Highlight, c.dark(120));
277  break;
278  default:
279  m_palette.setBrush(QPalette::Disabled, r, br);
280  break;
281  }
282  }
283  emit paletteChanged(m_palette);
284  emit dataChanged(idxBegin, idxEnd);
285  return true;
286  }
287  if (index.column() == 0 && role == Qt::EditRole) {
288  uint mask = m_palette.resolve();
289  const bool isMask = qvariant_cast<bool>(value);
290  const int r = index.row();
291  if (isMask)
292  mask |= (1 << r);
293  else {
294  m_palette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(r),
295  m_parentPalette.brush(QPalette::Active, static_cast<QPalette::ColorRole>(r)));
296  m_palette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(r),
297  m_parentPalette.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(r)));
298  m_palette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(r),
299  m_parentPalette.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(r)));
300 
301  mask &= ~(1 << index.row());
302  }
303  m_palette.resolve(mask);
304  emit paletteChanged(m_palette);
305  const QModelIndex idxEnd = PaletteModel::index(r, 3);
306  emit dataChanged(index, idxEnd);
307  return true;
308  }
309  return false;
310 }
311 
312 Qt::ItemFlags PaletteModel::flags(const QModelIndex &index) const
313 {
314  if (!index.isValid())
315  return Qt::ItemIsEnabled;
316  return Qt::ItemIsEditable | Qt::ItemIsEnabled;
317 }
318 
319 QVariant PaletteModel::headerData(int section, Qt::Orientation orientation,
320  int role) const
321 {
322  if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
323  if (section == 0)
324  return tr("Color Role");
325  if (section == groupToColumn(QPalette::Active))
326  return tr("Active");
327  if (section == groupToColumn(QPalette::Inactive))
328  return tr("Inactive");
329  if (section == groupToColumn(QPalette::Disabled))
330  return tr("Disabled");
331  }
332  return QVariant();
333 }
334 
335 QPalette PaletteModel::getPalette() const
336 {
337  return m_palette;
338 }
339 
340 void PaletteModel::setPalette(const QPalette &palette, const QPalette &parentPalette)
341 {
342  m_parentPalette = parentPalette;
343  m_palette = palette;
344  const QModelIndex idxBegin = index(0, 0);
345  const QModelIndex idxEnd = index(m_roleNames.count() - 1, 3);
346  emit dataChanged(idxBegin, idxEnd);
347 }
348 
349 QPalette::ColorGroup PaletteModel::columnToGroup(int index) const
350 {
351  if (index == 1)
352  return QPalette::Active;
353  if (index == 2)
354  return QPalette::Inactive;
355  return QPalette::Disabled;
356 }
357 
358 int PaletteModel::groupToColumn(QPalette::ColorGroup group) const
359 {
360  if (group == QPalette::Active)
361  return 1;
362  if (group == QPalette::Inactive)
363  return 2;
364  return 3;
365 }
366 
368 
369 BrushEditor::BrushEditor(QWidget *parent) :
370  QWidget(parent),
371  m_button(new ColorButton(this)),
372  m_changed(false)
373 {
374  QLayout *layout = new QHBoxLayout(this);
375  layout->setMargin(0);
376  layout->addWidget(m_button);
377  connect(m_button, &ColorButton::colorChanged, this, &BrushEditor::brushChanged);
378  setFocusProxy(m_button);
379 }
380 
381 void BrushEditor::setBrush(const QBrush &brush)
382 {
383  m_button->setColor(brush.color());
384  m_changed = false;
385 }
386 
387 QBrush BrushEditor::brush() const
388 {
389  return QBrush(m_button->color());
390 }
391 
392 void BrushEditor::brushChanged()
393 {
394  m_changed = true;
395  emit changed(this);
396 }
397 
399 {
400  return m_changed;
401 }
402 
404 
405 RoleEditor::RoleEditor(QWidget *parent) :
406  QWidget(parent),
407  m_label(new QLabel(this)),
408  m_edited(false)
409 {
410  QHBoxLayout *layout = new QHBoxLayout(this);
411  layout->setMargin(0);
412  layout->setSpacing(0);
413 
414  layout->addWidget(m_label);
415  m_label->setAutoFillBackground(true);
416  m_label->setIndent(3); // ### hardcode it should have the same value of textMargin in QItemDelegate
417  setFocusProxy(m_label);
418 
419  QToolButton *button = new QToolButton(this);
420  button->setToolButtonStyle(Qt::ToolButtonIconOnly);
421  button->setIcon(QIcon(QStringLiteral(":/qtutilities/icons/hicolor/48x48/actions/edit-clear.png")));
422  button->setIconSize(QSize(8,8));
423  button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding));
424  layout->addWidget(button);
425  connect(button, &QAbstractButton::clicked, this, &RoleEditor::emitResetProperty);
426 }
427 
428 void RoleEditor::setLabel(const QString &label)
429 {
430  m_label->setText(label);
431 }
432 
434 {
435  QFont font;
436  if (on == true) {
437  font.setBold(on);
438  }
439  m_label->setFont(font);
440  m_edited = on;
441 }
442 
443 bool RoleEditor::edited() const
444 {
445  return m_edited;
446 }
447 
448 void RoleEditor::emitResetProperty()
449 {
450  setEdited(false);
451  emit changed(this);
452 }
453 
456  QItemDelegate(parent)
457 {
458 }
459 
460 QWidget *ColorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
461 {
462  QWidget *ed = nullptr;
463  if (index.column() == 0) {
464  RoleEditor *editor = new RoleEditor(parent);
465  connect(editor, &RoleEditor::changed, this, &ColorDelegate::commitData);
466  //editor->setFocusPolicy(Qt::NoFocus);
467  //editor->installEventFilter(const_cast<ColorDelegate *>(this));
468  ed = editor;
469  } else {
470  typedef void (BrushEditor::*BrushEditorWidgetSignal)(QWidget *);
471 
472  BrushEditor *editor = new BrushEditor(parent);
473  connect(editor, static_cast<BrushEditorWidgetSignal>(&BrushEditor::changed),
474  this, &ColorDelegate::commitData);
475  editor->setFocusPolicy(Qt::NoFocus);
476  editor->installEventFilter(const_cast<ColorDelegate *>(this));
477  ed = editor;
478  }
479  return ed;
480 }
481 
482 void ColorDelegate::setEditorData(QWidget *ed, const QModelIndex &index) const
483 {
484  if (index.column() == 0) {
485  const bool mask = qvariant_cast<bool>(index.model()->data(index, Qt::EditRole));
486  RoleEditor *editor = static_cast<RoleEditor *>(ed);
487  editor->setEdited(mask);
488  const QString colorName = qvariant_cast<QString>(index.model()->data(index, Qt::DisplayRole));
489  editor->setLabel(colorName);
490  } else {
491  const QBrush br = qvariant_cast<QBrush>(index.model()->data(index, BrushRole));
492  BrushEditor *editor = static_cast<BrushEditor *>(ed);
493  editor->setBrush(br);
494  }
495 }
496 
497 void ColorDelegate::setModelData(QWidget *ed, QAbstractItemModel *model,
498  const QModelIndex &index) const
499 {
500  if (index.column() == 0) {
501  RoleEditor *editor = static_cast<RoleEditor *>(ed);
502  const bool mask = editor->edited();
503  model->setData(index, mask, Qt::EditRole);
504  } else {
505  BrushEditor *editor = static_cast<BrushEditor *>(ed);
506  if (editor->changed()) {
507  QBrush br = editor->brush();
508  model->setData(index, br, BrushRole);
509  }
510  }
511 }
512 
514  const QStyleOptionViewItem &option, const QModelIndex &index) const
515 {
516  QItemDelegate::updateEditorGeometry(ed, option, index);
517  ed->setGeometry(ed->geometry().adjusted(0, 0, -1, -1));
518 }
519 
520 void ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const
521 {
522  QStyleOptionViewItem option = opt;
523  const bool mask = qvariant_cast<bool>(index.model()->data(index, Qt::EditRole));
524  if (index.column() == 0 && mask) {
525  option.font.setBold(true);
526  }
527  QBrush br = qvariant_cast<QBrush>(index.model()->data(index, BrushRole));
528  if (br.style() == Qt::LinearGradientPattern ||
529  br.style() == Qt::RadialGradientPattern ||
530  br.style() == Qt::ConicalGradientPattern) {
531  painter->save();
532  painter->translate(option.rect.x(), option.rect.y());
533  painter->scale(option.rect.width(), option.rect.height());
534  QGradient gr = *(br.gradient());
535  gr.setCoordinateMode(QGradient::LogicalMode);
536  br = QBrush(gr);
537  painter->fillRect(0, 0, 1, 1, br);
538  painter->restore();
539  } else {
540  painter->save();
541  painter->setBrushOrigin(option.rect.x(), option.rect.y());
542  painter->fillRect(option.rect, br);
543  painter->restore();
544  }
545  QItemDelegate::paint(painter, option, index);
546 
547 
548  const QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &option));
549  const QPen oldPen = painter->pen();
550  painter->setPen(QPen(color));
551 
552  painter->drawLine(option.rect.right(), option.rect.y(),
553  option.rect.right(), option.rect.bottom());
554  painter->drawLine(option.rect.x(), option.rect.bottom(),
555  option.rect.right(), option.rect.bottom());
556  painter->setPen(oldPen);
557 }
558 
559 QSize ColorDelegate::sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const
560 {
561  return QItemDelegate::sizeHint(opt, index) + QSize(4, 4);
562 }
563 
564 }
QPalette getPalette() const
void paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const
The BrushEditor class is used by PaletteEditor.
Qt::ItemFlags flags(const QModelIndex &index) const
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
The ColorButton class is used by PaletteEditor.
Definition: colorbutton.h:15
PaletteModel(QObject *parent=nullptr)
void setModelData(QWidget *ed, QAbstractItemModel *model, const QModelIndex &index) const
The ColorDelegate class is used by PaletteEditor.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
void setColor(const QColor &color)
The PaletteEditor class provides a dialog to customize a QPalette.
Definition: paletteeditor.h:32
ColorDelegate(QObject *parent=nullptr)
QT_UTILITIES_EXPORT void init()
Initiates the resources used and provided by this library.
Definition: resources.cpp:50
static QPalette getPalette(QWidget *parent, const QPalette &init=QPalette(), const QPalette &parentPal=QPalette(), int *result=nullptr)
QBrush brush() const
void setCompute(bool on)
Definition: paletteeditor.h:99
QColor color() const
bool setData(const QModelIndex &index, const QVariant &value, int role)
BrushEditor(QWidget *parent=nullptr)
void paletteChanged(const QPalette &palette)
int columnCount(const QModelIndex &parent=QModelIndex()) const
Provides common dialogs such as AboutDialog, EnterPasswordDialog and SettingsDialog.
Definition: dialogutils.h:12
void setEditorData(QWidget *ed, const QModelIndex &index) const
void updateEditorGeometry(QWidget *ed, const QStyleOptionViewItem &option, const QModelIndex &index) const
void changed(QWidget *widget)
QPalette palette() const
Provides a set of extended widgets such as ClearLineEdit and ClearComboBox.
Definition: buttonoverlay.h:13
void setLabel(const QString &label)
The RoleEditor class is used by PaletteEditor.
RoleEditor(QWidget *parent=nullptr)
int rowCount(const QModelIndex &parent=QModelIndex()) const
QSize sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const
void setPalette(const QPalette &palette)
void setBrush(const QBrush &brush)
QVariant data(const QModelIndex &index, int role) const
void setEdited(bool on)
void setPalette(const QPalette &palette, const QPalette &parentPalette)
The PaletteModel class is used by PaletteEditor.
Definition: paletteeditor.h:80