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