1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28
29 #include "paletteeditor.h"
30
31 #include <iconloader_p.h>
32 #include <qtcolorbutton.h>
33
34 #include <private/formbuilderextra_p.h>
35 #include <private/ui4_p.h>
36
37 #include <QtDesigner/abstractformeditor.h>
38 #include <QtDesigner/abstractformwindowmanager.h>
39
40 #include <QtCore/qfile.h>
41 #include <QtCore/qmetaobject.h>
42 #include <QtCore/qsavefile.h>
43 #include <QtCore/qxmlstream.h>
44 #include <QtGui/qguiapplication.h>
45 #include <QtGui/qpainter.h>
46 #include <QtGui/qscreen.h>
47 #if QT_CONFIG(clipboard)
48 # include <QtGui/qclipboard.h>
49 #endif
50 #include <QtWidgets/qaction.h>
51 #include <QtWidgets/qfiledialog.h>
52 #include <QtWidgets/qmessagebox.h>
53 #include <QtWidgets/qpushbutton.h>
54 #include <QtWidgets/qtoolbutton.h>
55 #include <QtWidgets/qlabel.h>
56 #include <QtWidgets/qmenu.h>
57 #include <QtWidgets/qheaderview.h>
58
59 QT_BEGIN_NAMESPACE
60
61 namespace qdesigner_internal {
62
63 enum { BrushRole = 33 };
64
PaletteEditor(QDesignerFormEditorInterface * core,QWidget * parent)65 PaletteEditor::PaletteEditor(QDesignerFormEditorInterface *core, QWidget *parent) :
66 QDialog(parent),
67 m_paletteModel(new PaletteModel(this)),
68 m_core(core)
69 {
70 ui.setupUi(this);
71 auto saveButton = ui.buttonBox->addButton(tr("Save..."), QDialogButtonBox::ActionRole);
72 connect(saveButton, &QPushButton::clicked, this, &PaletteEditor::save);
73 auto loadButton = ui.buttonBox->addButton(tr("Load..."), QDialogButtonBox::ActionRole);
74 connect(loadButton, &QPushButton::clicked, this, &PaletteEditor::load);
75
76 ui.paletteView->setModel(m_paletteModel);
77 updatePreviewPalette();
78 updateStyledButton();
79 ui.paletteView->setModel(m_paletteModel);
80 ColorDelegate *delegate = new ColorDelegate(core, this);
81 ui.paletteView->setItemDelegate(delegate);
82 ui.paletteView->setEditTriggers(QAbstractItemView::AllEditTriggers);
83 connect(m_paletteModel, &PaletteModel::paletteChanged,
84 this, &PaletteEditor::paletteChanged);
85 ui.paletteView->setSelectionBehavior(QAbstractItemView::SelectRows);
86 ui.paletteView->setDragEnabled(true);
87 ui.paletteView->setDropIndicatorShown(true);
88 ui.paletteView->setRootIsDecorated(false);
89 ui.paletteView->setColumnHidden(2, true);
90 ui.paletteView->setColumnHidden(3, true);
91 ui.paletteView->setContextMenuPolicy(Qt::CustomContextMenu);
92 connect(ui.paletteView, &QWidget::customContextMenuRequested,
93 this, &PaletteEditor::viewContextMenuRequested);
94
95 const auto itemRect = ui.paletteView->visualRect(m_paletteModel->index(0, 0));
96 const int minHeight = qMin(itemRect.height() * QPalette::NColorRoles,
97 (screen()->geometry().height() * 2) / 3);
98 ui.paletteView->setMinimumSize({itemRect.width() * 4, minHeight});
99 }
100
101 PaletteEditor::~PaletteEditor() = default;
102
palette() const103 QPalette PaletteEditor::palette() const
104 {
105 return m_editPalette;
106 }
107
setPalette(const QPalette & palette)108 void PaletteEditor::setPalette(const QPalette &palette)
109 {
110 m_editPalette = palette;
111 const uint mask = palette.resolve();
112 for (int i = 0; i < static_cast<int>(QPalette::NColorRoles); ++i) {
113 if (!(mask & (1 << i))) {
114 m_editPalette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(i),
115 m_parentPalette.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i)));
116 m_editPalette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i),
117 m_parentPalette.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i)));
118 m_editPalette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i),
119 m_parentPalette.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i)));
120 }
121 }
122 m_editPalette.resolve(mask);
123 updatePreviewPalette();
124 updateStyledButton();
125 m_paletteUpdated = true;
126 if (!m_modelUpdated)
127 m_paletteModel->setPalette(m_editPalette, m_parentPalette);
128 m_paletteUpdated = false;
129 }
130
setPalette(const QPalette & palette,const QPalette & parentPalette)131 void PaletteEditor::setPalette(const QPalette &palette, const QPalette &parentPalette)
132 {
133 m_parentPalette = parentPalette;
134 setPalette(palette);
135 }
136
on_buildButton_colorChanged(const QColor &)137 void PaletteEditor::on_buildButton_colorChanged(const QColor &)
138 {
139 buildPalette();
140 }
141
on_activeRadio_clicked()142 void PaletteEditor::on_activeRadio_clicked()
143 {
144 m_currentColorGroup = QPalette::Active;
145 updatePreviewPalette();
146 }
147
on_inactiveRadio_clicked()148 void PaletteEditor::on_inactiveRadio_clicked()
149 {
150 m_currentColorGroup = QPalette::Inactive;
151 updatePreviewPalette();
152 }
153
on_disabledRadio_clicked()154 void PaletteEditor::on_disabledRadio_clicked()
155 {
156 m_currentColorGroup = QPalette::Disabled;
157 updatePreviewPalette();
158 }
159
on_computeRadio_clicked()160 void PaletteEditor::on_computeRadio_clicked()
161 {
162 if (m_compute)
163 return;
164 ui.paletteView->setColumnHidden(2, true);
165 ui.paletteView->setColumnHidden(3, true);
166 m_compute = true;
167 m_paletteModel->setCompute(true);
168 }
169
on_detailsRadio_clicked()170 void PaletteEditor::on_detailsRadio_clicked()
171 {
172 if (!m_compute)
173 return;
174 const int w = ui.paletteView->columnWidth(1);
175 ui.paletteView->setColumnHidden(2, false);
176 ui.paletteView->setColumnHidden(3, false);
177 QHeaderView *header = ui.paletteView->header();
178 header->resizeSection(1, w / 3);
179 header->resizeSection(2, w / 3);
180 header->resizeSection(3, w / 3);
181 m_compute = false;
182 m_paletteModel->setCompute(false);
183 }
184
paletteChanged(const QPalette & palette)185 void PaletteEditor::paletteChanged(const QPalette &palette)
186 {
187 m_modelUpdated = true;
188 if (!m_paletteUpdated)
189 setPalette(palette);
190 m_modelUpdated = false;
191 }
192
buildPalette()193 void PaletteEditor::buildPalette()
194 {
195 const QColor btn = ui.buildButton->color();
196 const QPalette temp = QPalette(btn);
197 setPalette(temp);
198 }
199
updatePreviewPalette()200 void PaletteEditor::updatePreviewPalette()
201 {
202 const QPalette::ColorGroup g = currentColorGroup();
203 // build the preview palette
204 const QPalette currentPalette = palette();
205 QPalette previewPalette;
206 for (int i = QPalette::WindowText; i < QPalette::NColorRoles; i++) {
207 const QPalette::ColorRole r = static_cast<QPalette::ColorRole>(i);
208 const QBrush &br = currentPalette.brush(g, r);
209 previewPalette.setBrush(QPalette::Active, r, br);
210 previewPalette.setBrush(QPalette::Inactive, r, br);
211 previewPalette.setBrush(QPalette::Disabled, r, br);
212 }
213 ui.previewFrame->setPreviewPalette(previewPalette);
214
215 const bool enabled = g != QPalette::Disabled;
216 ui.previewFrame->setEnabled(enabled);
217 ui.previewFrame->setSubWindowActive(g != QPalette::Inactive);
218 }
219
updateStyledButton()220 void PaletteEditor::updateStyledButton()
221 {
222 ui.buildButton->setColor(palette().color(QPalette::Active, QPalette::Button));
223 }
224
getPalette(QDesignerFormEditorInterface * core,QWidget * parent,const QPalette & init,const QPalette & parentPal,int * ok)225 QPalette PaletteEditor::getPalette(QDesignerFormEditorInterface *core, QWidget* parent, const QPalette &init,
226 const QPalette &parentPal, int *ok)
227 {
228 PaletteEditor dlg(core, parent);
229 QPalette parentPalette(parentPal);
230 uint mask = init.resolve();
231 for (int i = 0; i < static_cast<int>(QPalette::NColorRoles); ++i) {
232 if (!(mask & (1 << i))) {
233 parentPalette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(i),
234 init.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i)));
235 parentPalette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i),
236 init.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i)));
237 parentPalette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i),
238 init.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i)));
239 }
240 }
241 dlg.setPalette(init, parentPalette);
242
243 const int result = dlg.exec();
244 if (ok) *ok = result;
245
246 return result == QDialog::Accepted ? dlg.palette() : init;
247 }
248
viewContextMenuRequested(const QPoint & pos)249 void PaletteEditor::viewContextMenuRequested(const QPoint &pos)
250 {
251 const auto index = ui.paletteView->indexAt(pos);
252 if (!index.isValid())
253 return;
254 auto brush = m_paletteModel->brushAt(index);
255 const auto color = brush.color();
256 if (!m_contextMenu) {
257 m_contextMenu = new QMenu(this);
258 m_lighterAction = m_contextMenu->addAction(tr("Lighter"));
259 m_darkerAction = m_contextMenu->addAction(tr("Darker"));
260 m_copyColorAction = m_contextMenu->addAction(QString());
261 }
262 const auto rgb = color.rgb() & 0xffffffu;
263 const bool isBlack = rgb == 0u;
264 m_lighterAction->setEnabled(rgb != 0xffffffu);
265 m_darkerAction->setDisabled(isBlack);
266 m_copyColorAction->setText(tr("Copy color %1").arg(color.name()));
267 auto action = m_contextMenu->exec(ui.paletteView->viewport()->mapToGlobal(pos));
268 if (!action)
269 return;
270 if (action == m_copyColorAction) {
271 #if QT_CONFIG(clipboard)
272 QGuiApplication::clipboard()->setText(color.name());
273 #endif
274 return;
275 }
276 // Fall through to darker/lighter. Note: black cannot be made lighter due
277 // to QTBUG-9343.
278 enum : int { factor = 120 };
279 const QColor newColor = action == m_darkerAction
280 ? color.darker(factor)
281 : (isBlack ? QColor(0x404040u) : color.lighter(factor));
282 brush.setColor(newColor);
283 m_paletteModel->setData(index, QVariant(brush), BrushRole);
284 }
285
paletteSuffix()286 static inline QString paletteSuffix() { return QStringLiteral("xml"); }
287
paletteFilter()288 static inline QString paletteFilter()
289 {
290 return PaletteEditor::tr("QPalette UI file (*.xml)");
291 }
292
savePalette(const QString & fileName,const QPalette & pal,QString * errorMessage)293 static bool savePalette(const QString &fileName, const QPalette &pal, QString *errorMessage)
294 {
295 QSaveFile file;
296 file.setFileName(fileName);
297 if (!file.open(QIODevice::WriteOnly)) {
298 *errorMessage = PaletteEditor::tr("Cannot open %1 for writing: %2")
299 .arg(QDir::toNativeSeparators(fileName), file.errorString());
300 return false;
301 }
302 {
303 QScopedPointer<DomPalette> domPalette(QFormBuilderExtra::savePalette(pal));
304 QXmlStreamWriter writer(&file);
305 writer.setAutoFormatting(true);
306 writer.setAutoFormattingIndent(1);
307 writer.writeStartDocument();
308 domPalette->write(writer);
309 writer.writeEndDocument();
310 }
311 const bool result = file.commit();
312 if (!result) {
313 *errorMessage = PaletteEditor::tr("Cannot write %1: %2")
314 .arg(QDir::toNativeSeparators(fileName), file.errorString());
315 }
316 return result;
317 }
318
msgCannotReadPalette(const QString & fileName,const QXmlStreamReader & reader,const QString & why)319 static QString msgCannotReadPalette(const QString &fileName, const QXmlStreamReader &reader,
320 const QString &why)
321 {
322 return PaletteEditor::tr("Cannot read palette from %1:%2:%3")
323 .arg(QDir::toNativeSeparators(fileName)).arg(reader.lineNumber()).arg(why);
324 }
325
msgCannotReadPalette(const QString & fileName,const QXmlStreamReader & reader)326 static inline QString msgCannotReadPalette(const QString &fileName, const QXmlStreamReader &reader)
327 {
328 return msgCannotReadPalette(fileName, reader, reader.errorString());
329 }
330
loadPalette(const QString & fileName,QPalette * pal,QString * errorMessage)331 static bool loadPalette(const QString &fileName, QPalette *pal, QString *errorMessage)
332 {
333 QFile file(fileName);
334 if (!file.open(QIODevice::ReadOnly)) {
335 *errorMessage = PaletteEditor::tr("Cannot open %1 for reading: %2")
336 .arg(QDir::toNativeSeparators(fileName), file.errorString());
337 return false;
338 }
339 QXmlStreamReader reader(&file);
340 if (!reader.readNextStartElement()) {
341 *errorMessage = msgCannotReadPalette(fileName, reader);
342 return false;
343 }
344 if (reader.name() != QLatin1String("palette")) {
345 const auto why = PaletteEditor::tr("Invalid element \"%1\", expected \"palette\".")
346 .arg(reader.name().toString());
347 *errorMessage = msgCannotReadPalette(fileName, reader, why);
348 return false;
349 }
350 QScopedPointer<DomPalette> domPalette(new DomPalette);
351 domPalette->read(reader);
352 if (reader.hasError()) {
353 *errorMessage = msgCannotReadPalette(fileName, reader);
354 return false;
355 }
356 *pal = QFormBuilderExtra::loadPalette(domPalette.data());
357 return true;
358 }
359
save()360 void PaletteEditor::save()
361 {
362 QFileDialog dialog(this, tr("Save Palette"), QString(), paletteFilter());
363 dialog.setAcceptMode(QFileDialog::AcceptSave);
364 dialog.setDefaultSuffix(paletteSuffix());
365 while (dialog.exec() == QDialog::Accepted) {
366 QString errorMessage;
367 if (savePalette(dialog.selectedFiles().constFirst(), palette(), &errorMessage))
368 break;
369 QMessageBox::warning(this, tr("Error Writing Palette"), errorMessage);
370 }
371 }
372
load()373 void PaletteEditor::load()
374 {
375 QFileDialog dialog(this, tr("Load Palette"), QString(), paletteFilter());
376 dialog.setAcceptMode(QFileDialog::AcceptOpen);
377 while (dialog.exec() == QDialog::Accepted) {
378 QPalette pal;
379 QString errorMessage;
380 if (loadPalette(dialog.selectedFiles().constFirst(), &pal, &errorMessage)) {
381 setPalette(pal);
382 break;
383 }
384 QMessageBox::warning(this, tr("Error Reading Palette"), errorMessage);
385 }
386 }
387
388 //////////////////////
389
PaletteModel(QObject * parent)390 PaletteModel::PaletteModel(QObject *parent) :
391 QAbstractTableModel(parent)
392 {
393 const QMetaObject *meta = metaObject();
394 const int index = meta->indexOfProperty("colorRole");
395 const QMetaProperty p = meta->property(index);
396 const QMetaEnum e = p.enumerator();
397 m_roleEntries.reserve(QPalette::NColorRoles);
398 for (int r = QPalette::WindowText; r < QPalette::NColorRoles; r++) {
399 const auto role = static_cast<QPalette::ColorRole>(r);
400 if (role != QPalette::NoRole)
401 m_roleEntries.append({QLatin1String(e.key(r)), role});
402 }
403 }
404
rowCount(const QModelIndex &) const405 int PaletteModel::rowCount(const QModelIndex &) const
406 {
407 return m_roleEntries.size();
408 }
409
columnCount(const QModelIndex &) const410 int PaletteModel::columnCount(const QModelIndex &) const
411 {
412 return 4;
413 }
414
brushAt(const QModelIndex & index) const415 QBrush PaletteModel::brushAt(const QModelIndex &index) const
416 {
417 return m_palette.brush(columnToGroup(index.column()), roleAt(index.row()));
418 }
419
data(const QModelIndex & index,int role) const420 QVariant PaletteModel::data(const QModelIndex &index, int role) const
421 {
422 if (!index.isValid())
423 return QVariant();
424 if (index.row() < 0 || index.row() >= m_roleEntries.size())
425 return QVariant();
426 if (index.column() < 0 || index.column() >= 4)
427 return QVariant();
428
429 if (index.column() == 0) {
430 if (role == Qt::DisplayRole)
431 return m_roleEntries.at(index.row()).name;
432 if (role == Qt::EditRole) {
433 const uint mask = m_palette.resolve();
434 if (mask & (1 << int(roleAt(index.row()))))
435 return true;
436 return false;
437 }
438 return QVariant();
439 }
440 if (role == Qt::ToolTipRole)
441 return brushAt(index).color().name();
442 if (role == BrushRole)
443 return brushAt(index);
444 return QVariant();
445 }
446
setData(const QModelIndex & index,const QVariant & value,int role)447 bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int role)
448 {
449 if (!index.isValid())
450 return false;
451
452 const int row = index.row();
453 const auto colorRole = roleAt(row);
454
455 if (index.column() != 0 && role == BrushRole) {
456 const QBrush br = qvariant_cast<QBrush>(value);
457 const QPalette::ColorGroup g = columnToGroup(index.column());
458 m_palette.setBrush(g, colorRole, br);
459
460 QModelIndex idxBegin = PaletteModel::index(row, 0);
461 QModelIndex idxEnd = PaletteModel::index(row, 3);
462 if (m_compute) {
463 m_palette.setBrush(QPalette::Inactive, colorRole, br);
464 switch (colorRole) {
465 case QPalette::WindowText:
466 case QPalette::Text:
467 case QPalette::ButtonText:
468 case QPalette::Base:
469 break;
470 case QPalette::Dark:
471 m_palette.setBrush(QPalette::Disabled, QPalette::WindowText, br);
472 m_palette.setBrush(QPalette::Disabled, QPalette::Dark, br);
473 m_palette.setBrush(QPalette::Disabled, QPalette::Text, br);
474 m_palette.setBrush(QPalette::Disabled, QPalette::ButtonText, br);
475 idxBegin = PaletteModel::index(0, 0);
476 idxEnd = PaletteModel::index(m_roleEntries.size() - 1, 3);
477 break;
478 case QPalette::Window:
479 m_palette.setBrush(QPalette::Disabled, QPalette::Base, br);
480 m_palette.setBrush(QPalette::Disabled, QPalette::Window, br);
481 idxBegin = PaletteModel::index(rowOf(QPalette::Base), 0);
482 break;
483 case QPalette::Highlight:
484 //m_palette.setBrush(QPalette::Disabled, QPalette::Highlight, c.dark(120));
485 break;
486 default:
487 m_palette.setBrush(QPalette::Disabled, colorRole, br);
488 break;
489 }
490 }
491 emit paletteChanged(m_palette);
492 emit dataChanged(idxBegin, idxEnd);
493 return true;
494 }
495 if (index.column() == 0 && role == Qt::EditRole) {
496 uint mask = m_palette.resolve();
497 const bool isMask = qvariant_cast<bool>(value);
498 if (isMask)
499 mask |= (1 << int(colorRole));
500 else {
501 m_palette.setBrush(QPalette::Active, colorRole,
502 m_parentPalette.brush(QPalette::Active, colorRole));
503 m_palette.setBrush(QPalette::Inactive, colorRole,
504 m_parentPalette.brush(QPalette::Inactive, colorRole));
505 m_palette.setBrush(QPalette::Disabled, colorRole,
506 m_parentPalette.brush(QPalette::Disabled, colorRole));
507
508 mask &= ~(1 << int(colorRole));
509 }
510 m_palette.resolve(mask);
511 emit paletteChanged(m_palette);
512 const QModelIndex idxEnd = PaletteModel::index(row, 3);
513 emit dataChanged(index, idxEnd);
514 return true;
515 }
516 return false;
517 }
518
flags(const QModelIndex & index) const519 Qt::ItemFlags PaletteModel::flags(const QModelIndex &index) const
520 {
521 if (!index.isValid())
522 return Qt::ItemIsEnabled;
523 return Qt::ItemIsEditable | Qt::ItemIsEnabled;
524 }
525
headerData(int section,Qt::Orientation orientation,int role) const526 QVariant PaletteModel::headerData(int section, Qt::Orientation orientation,
527 int role) const
528 {
529 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
530 if (section == 0)
531 return tr("Color Role");
532 if (section == groupToColumn(QPalette::Active))
533 return tr("Active");
534 if (section == groupToColumn(QPalette::Inactive))
535 return tr("Inactive");
536 if (section == groupToColumn(QPalette::Disabled))
537 return tr("Disabled");
538 }
539 return QVariant();
540 }
541
getPalette() const542 QPalette PaletteModel::getPalette() const
543 {
544 return m_palette;
545 }
546
setPalette(const QPalette & palette,const QPalette & parentPalette)547 void PaletteModel::setPalette(const QPalette &palette, const QPalette &parentPalette)
548 {
549 m_parentPalette = parentPalette;
550 m_palette = palette;
551 const QModelIndex idxBegin = index(0, 0);
552 const QModelIndex idxEnd = index(m_roleEntries.size() - 1, 3);
553 emit dataChanged(idxBegin, idxEnd);
554 }
555
columnToGroup(int index) const556 QPalette::ColorGroup PaletteModel::columnToGroup(int index) const
557 {
558 if (index == 1)
559 return QPalette::Active;
560 if (index == 2)
561 return QPalette::Inactive;
562 return QPalette::Disabled;
563 }
564
groupToColumn(QPalette::ColorGroup group) const565 int PaletteModel::groupToColumn(QPalette::ColorGroup group) const
566 {
567 if (group == QPalette::Active)
568 return 1;
569 if (group == QPalette::Inactive)
570 return 2;
571 return 3;
572 }
573
rowOf(QPalette::ColorRole role) const574 int PaletteModel::rowOf(QPalette::ColorRole role) const
575 {
576 for (int row = 0, size = m_roleEntries.size(); row < size; ++row) {
577 if (m_roleEntries.at(row).role == role)
578 return row;
579 }
580 return -1;
581 }
582
583 //////////////////////////
584
BrushEditor(QDesignerFormEditorInterface * core,QWidget * parent)585 BrushEditor::BrushEditor(QDesignerFormEditorInterface *core, QWidget *parent) :
586 QWidget(parent),
587 m_button(new QtColorButton(this)),
588 m_core(core)
589 {
590 QLayout *layout = new QHBoxLayout(this);
591 layout->setContentsMargins(QMargins());
592 layout->addWidget(m_button);
593 connect(m_button, &QtColorButton::colorChanged, this, &BrushEditor::brushChanged);
594 setFocusProxy(m_button);
595 }
596
setBrush(const QBrush & brush)597 void BrushEditor::setBrush(const QBrush &brush)
598 {
599 m_button->setColor(brush.color());
600 m_changed = false;
601 }
602
brush() const603 QBrush BrushEditor::brush() const
604 {
605 return QBrush(m_button->color());
606 }
607
brushChanged()608 void BrushEditor::brushChanged()
609 {
610 m_changed = true;
611 emit changed(this);
612 }
613
changed() const614 bool BrushEditor::changed() const
615 {
616 return m_changed;
617 }
618
619 //////////////////////////
620
RoleEditor(QWidget * parent)621 RoleEditor::RoleEditor(QWidget *parent) :
622 QWidget(parent),
623 m_label(new QLabel(this))
624 {
625 QHBoxLayout *layout = new QHBoxLayout(this);
626 layout->setContentsMargins(QMargins());
627 layout->setSpacing(0);
628
629 layout->addWidget(m_label);
630 m_label->setAutoFillBackground(true);
631 m_label->setIndent(3); // ### hardcode it should have the same value of textMargin in QItemDelegate
632 setFocusProxy(m_label);
633
634 QToolButton *button = new QToolButton(this);
635 button->setToolButtonStyle(Qt::ToolButtonIconOnly);
636 button->setIcon(createIconSet(QStringLiteral("resetproperty.png")));
637 button->setIconSize(QSize(8,8));
638 button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding));
639 layout->addWidget(button);
640 connect(button, &QAbstractButton::clicked, this, &RoleEditor::emitResetProperty);
641 }
642
setLabel(const QString & label)643 void RoleEditor::setLabel(const QString &label)
644 {
645 m_label->setText(label);
646 }
647
setEdited(bool on)648 void RoleEditor::setEdited(bool on)
649 {
650 QFont font;
651 if (on)
652 font.setBold(on);
653 m_label->setFont(font);
654 m_edited = on;
655 }
656
edited() const657 bool RoleEditor::edited() const
658 {
659 return m_edited;
660 }
661
emitResetProperty()662 void RoleEditor::emitResetProperty()
663 {
664 setEdited(false);
665 emit changed(this);
666 }
667
668 //////////////////////////
ColorDelegate(QDesignerFormEditorInterface * core,QObject * parent)669 ColorDelegate::ColorDelegate(QDesignerFormEditorInterface *core, QObject *parent) :
670 QItemDelegate(parent),
671 m_core(core)
672 {
673 }
674
createEditor(QWidget * parent,const QStyleOptionViewItem &,const QModelIndex & index) const675 QWidget *ColorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &,
676 const QModelIndex &index) const
677 {
678 QWidget *ed = nullptr;
679 if (index.column() == 0) {
680 RoleEditor *editor = new RoleEditor(parent);
681 connect(editor, &RoleEditor::changed, this, &ColorDelegate::commitData);
682 //editor->setFocusPolicy(Qt::NoFocus);
683 //editor->installEventFilter(const_cast<ColorDelegate *>(this));
684 ed = editor;
685 } else {
686 BrushEditor *editor = new BrushEditor(m_core, parent);
687 connect(editor, QOverload<QWidget *>::of(&BrushEditor::changed),
688 this, &ColorDelegate::commitData);
689 editor->setFocusPolicy(Qt::NoFocus);
690 editor->installEventFilter(const_cast<ColorDelegate *>(this));
691 ed = editor;
692 }
693 return ed;
694 }
695
setEditorData(QWidget * ed,const QModelIndex & index) const696 void ColorDelegate::setEditorData(QWidget *ed, const QModelIndex &index) const
697 {
698 if (index.column() == 0) {
699 const bool mask = qvariant_cast<bool>(index.model()->data(index, Qt::EditRole));
700 RoleEditor *editor = static_cast<RoleEditor *>(ed);
701 editor->setEdited(mask);
702 const QString colorName = qvariant_cast<QString>(index.model()->data(index, Qt::DisplayRole));
703 editor->setLabel(colorName);
704 } else {
705 const QBrush br = qvariant_cast<QBrush>(index.model()->data(index, BrushRole));
706 BrushEditor *editor = static_cast<BrushEditor *>(ed);
707 editor->setBrush(br);
708 }
709 }
710
setModelData(QWidget * ed,QAbstractItemModel * model,const QModelIndex & index) const711 void ColorDelegate::setModelData(QWidget *ed, QAbstractItemModel *model,
712 const QModelIndex &index) const
713 {
714 if (index.column() == 0) {
715 RoleEditor *editor = static_cast<RoleEditor *>(ed);
716 const bool mask = editor->edited();
717 model->setData(index, mask, Qt::EditRole);
718 } else {
719 BrushEditor *editor = static_cast<BrushEditor *>(ed);
720 if (editor->changed()) {
721 QBrush br = editor->brush();
722 model->setData(index, br, BrushRole);
723 }
724 }
725 }
726
updateEditorGeometry(QWidget * ed,const QStyleOptionViewItem & option,const QModelIndex & index) const727 void ColorDelegate::updateEditorGeometry(QWidget *ed,
728 const QStyleOptionViewItem &option, const QModelIndex &index) const
729 {
730 QItemDelegate::updateEditorGeometry(ed, option, index);
731 ed->setGeometry(ed->geometry().adjusted(0, 0, -1, -1));
732 }
733
paint(QPainter * painter,const QStyleOptionViewItem & opt,const QModelIndex & index) const734 void ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt,
735 const QModelIndex &index) const
736 {
737 QStyleOptionViewItem option = opt;
738 const bool mask = qvariant_cast<bool>(index.model()->data(index, Qt::EditRole));
739 if (index.column() == 0 && mask) {
740 option.font.setBold(true);
741 }
742 QBrush br = qvariant_cast<QBrush>(index.model()->data(index, BrushRole));
743 if (br.style() == Qt::LinearGradientPattern ||
744 br.style() == Qt::RadialGradientPattern ||
745 br.style() == Qt::ConicalGradientPattern) {
746 painter->save();
747 painter->translate(option.rect.x(), option.rect.y());
748 painter->scale(option.rect.width(), option.rect.height());
749 QGradient gr = *(br.gradient());
750 gr.setCoordinateMode(QGradient::LogicalMode);
751 br = QBrush(gr);
752 painter->fillRect(0, 0, 1, 1, br);
753 painter->restore();
754 } else {
755 painter->save();
756 painter->setBrushOrigin(option.rect.x(), option.rect.y());
757 painter->fillRect(option.rect, br);
758 painter->restore();
759 }
760 QItemDelegate::paint(painter, option, index);
761
762
763 const QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &option));
764 const QPen oldPen = painter->pen();
765 painter->setPen(QPen(color));
766
767 painter->drawLine(option.rect.right(), option.rect.y(),
768 option.rect.right(), option.rect.bottom());
769 painter->drawLine(option.rect.x(), option.rect.bottom(),
770 option.rect.right(), option.rect.bottom());
771 painter->setPen(oldPen);
772 }
773
sizeHint(const QStyleOptionViewItem & opt,const QModelIndex & index) const774 QSize ColorDelegate::sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const
775 {
776 return QItemDelegate::sizeHint(opt, index) + QSize(4, 4);
777 }
778 }
779
780 QT_END_NAMESPACE
781