Qt Utilities  5.7.1
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 <QHeaderView>
7 #include <QLabel>
8 #include <QMetaProperty>
9 #include <QPainter>
10 #include <QToolButton>
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, this, &PaletteEditor::paletteChanged);
36  m_ui->paletteView->setSelectionBehavior(QAbstractItemView::SelectRows);
37  m_ui->paletteView->setDragEnabled(true);
38  m_ui->paletteView->setDropIndicatorShown(true);
39  m_ui->paletteView->setRootIsDecorated(false);
40  m_ui->paletteView->setColumnHidden(2, true);
41  m_ui->paletteView->setColumnHidden(3, true);
42 }
43 
45 {
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(
60  QPalette::Active, static_cast<QPalette::ColorRole>(i), 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, const QPalette &parentPal, int *ok)
167 {
168  PaletteEditor dlg(parent);
169  QPalette parentPalette(parentPal);
170  uint mask = init.resolve();
171  for (int i = 0; i < (int)QPalette::NColorRoles; ++i) {
172  if (!(mask & (1 << i))) {
173  parentPalette.setBrush(
174  QPalette::Active, static_cast<QPalette::ColorRole>(i), init.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i)));
175  parentPalette.setBrush(
176  QPalette::Inactive, static_cast<QPalette::ColorRole>(i), init.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i)));
177  parentPalette.setBrush(
178  QPalette::Disabled, static_cast<QPalette::ColorRole>(i), init.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i)));
179  }
180  }
181  dlg.setPalette(init, parentPalette);
182 
183  const int result = dlg.exec();
184  if (ok)
185  *ok = result;
186 
187  return result == QDialog::Accepted ? dlg.palette() : init;
188 }
189 
191 
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()), static_cast<QPalette::ColorRole>(index.row()));
237  return QVariant();
238 }
239 
240 bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int role)
241 {
242  if (!index.isValid())
243  return false;
244 
245  if (index.column() != 0 && role == BrushRole) {
246  const QBrush br = qvariant_cast<QBrush>(value);
247  const QPalette::ColorRole r = static_cast<QPalette::ColorRole>(index.row());
248  const QPalette::ColorGroup g = columnToGroup(index.column());
249  m_palette.setBrush(g, r, br);
250 
251  QModelIndex idxBegin = PaletteModel::index(r, 0);
252  QModelIndex idxEnd = PaletteModel::index(r, 3);
253  if (m_compute) {
254  m_palette.setBrush(QPalette::Inactive, r, br);
255  switch (r) {
256  case QPalette::WindowText:
257  case QPalette::Text:
258  case QPalette::ButtonText:
259  case QPalette::Base:
260  break;
261  case QPalette::Dark:
262  m_palette.setBrush(QPalette::Disabled, QPalette::WindowText, br);
263  m_palette.setBrush(QPalette::Disabled, QPalette::Dark, br);
264  m_palette.setBrush(QPalette::Disabled, QPalette::Text, br);
265  m_palette.setBrush(QPalette::Disabled, QPalette::ButtonText, br);
266  idxBegin = PaletteModel::index(0, 0);
267  idxEnd = PaletteModel::index(m_roleNames.count() - 1, 3);
268  break;
269  case QPalette::Window:
270  m_palette.setBrush(QPalette::Disabled, QPalette::Base, br);
271  m_palette.setBrush(QPalette::Disabled, QPalette::Window, br);
272  idxBegin = PaletteModel::index(QPalette::Base, 0);
273  break;
274  case QPalette::Highlight:
275  // m_palette.setBrush(QPalette::Disabled, QPalette::Highlight,
276  // 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(
295  QPalette::Active, static_cast<QPalette::ColorRole>(r), 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, int role) const
320 {
321  if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
322  if (section == 0)
323  return tr("Color Role");
324  if (section == groupToColumn(QPalette::Active))
325  return tr("Active");
326  if (section == groupToColumn(QPalette::Inactive))
327  return tr("Inactive");
328  if (section == groupToColumn(QPalette::Disabled))
329  return tr("Disabled");
330  }
331  return QVariant();
332 }
333 
334 QPalette PaletteModel::getPalette() const
335 {
336  return m_palette;
337 }
338 
339 void PaletteModel::setPalette(const QPalette &palette, const QPalette &parentPalette)
340 {
341  m_parentPalette = parentPalette;
342  m_palette = palette;
343  const QModelIndex idxBegin = index(0, 0);
344  const QModelIndex idxEnd = index(m_roleNames.count() - 1, 3);
345  emit dataChanged(idxBegin, idxEnd);
346 }
347 
348 QPalette::ColorGroup PaletteModel::columnToGroup(int index) const
349 {
350  if (index == 1)
351  return QPalette::Active;
352  if (index == 2)
353  return QPalette::Inactive;
354  return QPalette::Disabled;
355 }
356 
357 int PaletteModel::groupToColumn(QPalette::ColorGroup group) const
358 {
359  if (group == QPalette::Active)
360  return 1;
361  if (group == QPalette::Inactive)
362  return 2;
363  return 3;
364 }
365 
367 
368 BrushEditor::BrushEditor(QWidget *parent)
369  : QWidget(parent)
370  , m_button(new ColorButton(this))
371  , m_changed(false)
372 {
373  QLayout *layout = new QHBoxLayout(this);
374  layout->setMargin(0);
375  layout->addWidget(m_button);
376  connect(m_button, &ColorButton::colorChanged, this, &BrushEditor::brushChanged);
377  setFocusProxy(m_button);
378 }
379 
380 void BrushEditor::setBrush(const QBrush &brush)
381 {
382  m_button->setColor(brush.color());
383  m_changed = false;
384 }
385 
386 QBrush BrushEditor::brush() const
387 {
388  return QBrush(m_button->color());
389 }
390 
391 void BrushEditor::brushChanged()
392 {
393  m_changed = true;
394  emit changed(this);
395 }
396 
398 {
399  return m_changed;
400 }
401 
403 
404 RoleEditor::RoleEditor(QWidget *parent)
405  : QWidget(parent)
406  , m_label(new QLabel(this))
407  , m_edited(false)
408 {
409  QHBoxLayout *layout = new QHBoxLayout(this);
410  layout->setMargin(0);
411  layout->setSpacing(0);
412 
413  layout->addWidget(m_label);
414  m_label->setAutoFillBackground(true);
415  m_label->setIndent(3); // ### hardcode it should have the same value of
416  // 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), this, &ColorDelegate::commitData);
474  editor->setFocusPolicy(Qt::NoFocus);
475  editor->installEventFilter(const_cast<ColorDelegate *>(this));
476  ed = editor;
477  }
478  return ed;
479 }
480 
481 void ColorDelegate::setEditorData(QWidget *ed, const QModelIndex &index) const
482 {
483  if (index.column() == 0) {
484  const bool mask = qvariant_cast<bool>(index.model()->data(index, Qt::EditRole));
485  RoleEditor *editor = static_cast<RoleEditor *>(ed);
486  editor->setEdited(mask);
487  const QString colorName = qvariant_cast<QString>(index.model()->data(index, Qt::DisplayRole));
488  editor->setLabel(colorName);
489  } else {
490  const QBrush br = qvariant_cast<QBrush>(index.model()->data(index, BrushRole));
491  BrushEditor *editor = static_cast<BrushEditor *>(ed);
492  editor->setBrush(br);
493  }
494 }
495 
496 void ColorDelegate::setModelData(QWidget *ed, QAbstractItemModel *model, const QModelIndex &index) const
497 {
498  if (index.column() == 0) {
499  RoleEditor *editor = static_cast<RoleEditor *>(ed);
500  const bool mask = editor->edited();
501  model->setData(index, mask, Qt::EditRole);
502  } else {
503  BrushEditor *editor = static_cast<BrushEditor *>(ed);
504  if (editor->changed()) {
505  QBrush br = editor->brush();
506  model->setData(index, br, BrushRole);
507  }
508  }
509 }
510 
511 void ColorDelegate::updateEditorGeometry(QWidget *ed, const QStyleOptionViewItem &option, const QModelIndex &index) const
512 {
513  QItemDelegate::updateEditorGeometry(ed, option, index);
514  ed->setGeometry(ed->geometry().adjusted(0, 0, -1, -1));
515 }
516 
517 void ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const
518 {
519  QStyleOptionViewItem option = opt;
520  const bool mask = qvariant_cast<bool>(index.model()->data(index, Qt::EditRole));
521  if (index.column() == 0 && mask) {
522  option.font.setBold(true);
523  }
524  QBrush br = qvariant_cast<QBrush>(index.model()->data(index, BrushRole));
525  if (br.style() == Qt::LinearGradientPattern || br.style() == Qt::RadialGradientPattern || br.style() == Qt::ConicalGradientPattern) {
526  painter->save();
527  painter->translate(option.rect.x(), option.rect.y());
528  painter->scale(option.rect.width(), option.rect.height());
529  QGradient gr = *(br.gradient());
530  gr.setCoordinateMode(QGradient::LogicalMode);
531  br = QBrush(gr);
532  painter->fillRect(0, 0, 1, 1, br);
533  painter->restore();
534  } else {
535  painter->save();
536  painter->setBrushOrigin(option.rect.x(), option.rect.y());
537  painter->fillRect(option.rect, br);
538  painter->restore();
539  }
540  QItemDelegate::paint(painter, option, index);
541 
542  const QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &option));
543  const QPen oldPen = painter->pen();
544  painter->setPen(QPen(color));
545 
546  painter->drawLine(option.rect.right(), option.rect.y(), option.rect.right(), option.rect.bottom());
547  painter->drawLine(option.rect.x(), option.rect.bottom(), option.rect.right(), option.rect.bottom());
548  painter->setPen(oldPen);
549 }
550 
551 QSize ColorDelegate::sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const
552 {
553  return QItemDelegate::sizeHint(opt, index) + QSize(4, 4);
554 }
555 }
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:33
ColorDelegate(QObject *parent=nullptr)
QT_UTILITIES_EXPORT void init()
Initiates the resources used and provided by this library.
Definition: resources.cpp:52
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:79