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