1 /*
2 * wangcolorview.h
3 * Copyright 2017, Benjamin Trotter <bdtrotte@ucsc.edu>
4 *
5 * This file is part of Tiled.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "wangcolorview.h"
22
23 #include "utils.h"
24 #include "wangcolormodel.h"
25
26 #include <QAbstractProxyModel>
27 #include <QColorDialog>
28 #include <QContextMenuEvent>
29 #include <QLineEdit>
30 #include <QMenu>
31 #include <QPainter>
32 #include <QStyledItemDelegate>
33
34 using namespace Tiled;
35
36 namespace {
37
38 class WangColorDelegate : public QStyledItemDelegate
39 {
40 public:
WangColorDelegate(QObject * parent=nullptr)41 WangColorDelegate(QObject *parent = nullptr)
42 : QStyledItemDelegate(parent)
43 {}
44
45 protected:
46 void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override;
47 };
48
initStyleOption(QStyleOptionViewItem * option,const QModelIndex & index) const49 void WangColorDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
50 {
51 QSize decorationSize = option->decorationSize;
52 QPixmap tileImage = index.data(Qt::DecorationRole).value<QPixmap>();
53
54 QPixmap pixmap(decorationSize);
55 pixmap.fill(Qt::transparent);
56
57 QPainter painter(&pixmap);
58
59 // Draw the tile image in the background
60 const QSizeF size = tileImage.size();
61 if (!size.isEmpty()) {
62 const qreal scaleX = decorationSize.width() / size.width();
63 const qreal scaleY = decorationSize.height() / size.height();
64 const qreal scale = std::max(scaleX, scaleY);
65 const QSizeF targetSize = size * scale;
66
67 painter.setRenderHint(QPainter::SmoothPixmapTransform, scale < 1.0);
68 painter.drawPixmap(QRectF(decorationSize.width() - targetSize.width(),
69 decorationSize.height() - targetSize.height(),
70 targetSize.width(),
71 targetSize.height()),
72 tileImage, tileImage.rect());
73 }
74
75 // Draw the Wang color on top
76 const QColor wangColor = index.data(WangColorModel::ColorRole).value<QColor>();
77 const QPointF topRight = QPointF(pixmap.width() * 0.75, 0);
78 const QPointF bottomLeft = QPointF(0, pixmap.height() * 0.75);
79 painter.setBrush(wangColor);
80 painter.setPen(Qt::NoPen);
81 painter.drawPolygon(QVector<QPointF> { QPointF(), topRight, bottomLeft });
82 QColor border(Qt::black);
83 border.setAlpha(128);
84 painter.setPen(QPen(border, 2.0));
85 painter.drawLine(topRight, bottomLeft);
86
87 QStyledItemDelegate::initStyleOption(option, index);
88
89 // Reset the icon
90 option->features |= QStyleOptionViewItem::HasDecoration;
91 option->decorationSize = decorationSize;
92 option->icon = pixmap;
93 }
94
95 } // anonymous namespace
96
WangColorView(QWidget * parent)97 WangColorView::WangColorView(QWidget *parent)
98 : QTreeView(parent)
99 {
100 setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
101 setHeaderHidden(true);
102 setItemsExpandable(false);
103 setIndentation(0);
104 setUniformRowHeights(true);
105 setItemDelegate(new WangColorDelegate(this));
106 }
107
~WangColorView()108 WangColorView::~WangColorView()
109 {
110 }
111
setTileSize(QSize size)112 void WangColorView::setTileSize(QSize size)
113 {
114 static const int minSize = 16;
115 static const int maxSize = Utils::dpiScaled(32);
116 setIconSize(QSize(qBound(minSize, size.width(), maxSize),
117 qBound(minSize, size.height(), maxSize)));
118 }
119
setReadOnly(bool readOnly)120 void WangColorView::setReadOnly(bool readOnly)
121 {
122 static const auto defaultTriggers = editTriggers();
123 mReadOnly = readOnly;
124 setEditTriggers(readOnly ? NoEditTriggers : defaultTriggers);
125 }
126
contextMenuEvent(QContextMenuEvent * event)127 void WangColorView::contextMenuEvent(QContextMenuEvent *event)
128 {
129 if (mReadOnly)
130 return;
131
132 const QAbstractProxyModel *proxyModel = static_cast<QAbstractProxyModel *>(model());
133 const WangColorModel *wangColorModel = static_cast<WangColorModel *>(proxyModel->sourceModel());
134 const QModelIndex filterModelIndex = indexAt(event->pos());
135
136 if (!wangColorModel || !filterModelIndex.isValid())
137 return;
138
139 const QModelIndex index = proxyModel->mapToSource(filterModelIndex);
140 mClickedWangColor = wangColorModel->wangColorAt(index);
141
142 QMenu menu;
143
144 QAction *pickColor = menu.addAction(tr("Pick Custom Color"));
145 connect(pickColor, &QAction::triggered,
146 this, &WangColorView::pickColor);
147
148 menu.exec(event->globalPos());
149 }
150
pickColor()151 void WangColorView::pickColor()
152 {
153 QColorDialog *colorPicker = new QColorDialog(this);
154 colorPicker->setAttribute(Qt::WA_DeleteOnClose);
155 colorPicker->setCurrentColor(mClickedWangColor->color());
156 connect(colorPicker, &QColorDialog::colorSelected,
157 this, &WangColorView::colorPicked);
158
159 colorPicker->open();
160 }
161
colorPicked(const QColor & color)162 void WangColorView::colorPicked(const QColor &color)
163 {
164 if (!mClickedWangColor)
165 return;
166
167 if (mClickedWangColor->color() != color)
168 emit wangColorColorPicked(mClickedWangColor.data(), color);
169
170 mClickedWangColor.clear();
171 }
172
173 #include "moc_wangcolorview.cpp"
174