1 /*
2 * wangtemplateview.cpp
3 * Copyright 2017, Benjamin Trotter <bdtrotte@ucsc.edu>
4 * Copyright 2020, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
5 *
6 * This file is part of Tiled.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "wangtemplateview.h"
23
24 #include "utils.h"
25 #include "wangoverlay.h"
26 #include "wangset.h"
27 #include "wangtemplatemodel.h"
28 #include "zoomable.h"
29
30 #include <QAbstractItemDelegate>
31 #include <QApplication>
32 #include <QCoreApplication>
33 #include <QGesture>
34 #include <QGestureEvent>
35 #include <QPainter>
36 #include <QPinchGesture>
37 #include <QWheelEvent>
38
39 using namespace Tiled;
40
41 namespace {
42
43 /**
44 * The delegate for drawing the Wang tile templates.
45 */
46 class WangTemplateDelegate : public QAbstractItemDelegate
47 {
48 public:
WangTemplateDelegate(WangTemplateView * wangtemplateView,QObject * parent=nullptr)49 WangTemplateDelegate(WangTemplateView *wangtemplateView, QObject *parent = nullptr)
50 : QAbstractItemDelegate(parent)
51 , mWangTemplateView(wangtemplateView)
52 {}
53
54 void paint(QPainter *painter,
55 const QStyleOptionViewItem &option,
56 const QModelIndex &index) const override;
57
58 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
59
60 private:
61 WangTemplateView *mWangTemplateView;
62 };
63
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const64 void WangTemplateDelegate::paint(QPainter *painter,
65 const QStyleOptionViewItem &option,
66 const QModelIndex &index) const
67 {
68 const WangTemplateModel *model = static_cast<const WangTemplateModel*>(index.model());
69 const WangId wangId = model->wangIdAt(index);
70 if (!wangId)
71 return;
72
73 painter->setClipRect(option.rect);
74
75 if (WangSet *wangSet = mWangTemplateView->wangSet())
76 paintWangOverlay(painter, wangId, *wangSet, option.rect, WO_Outline);
77
78 // Highlight currently selected tile.
79 if (mWangTemplateView->currentIndex() == index) {
80 QColor high = option.palette.highlight().color();
81 painter->setBrush(Qt::NoBrush);
82 painter->setPen(QPen(high, 4));
83 painter->drawRect(option.rect);
84 }
85
86 // Shade tile if used already
87 if (mWangTemplateView->wangIdIsUsed(wangId)) {
88 painter->setBrush(QColor(0,0,0,100));
89 painter->setPen(Qt::NoPen);
90 painter->drawRect(option.rect.adjusted(2,2,-2,-2));
91 }
92 }
93
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const94 QSize WangTemplateDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
95 {
96 Q_UNUSED(option)
97 Q_UNUSED(index)
98
99 return QSize(32 * mWangTemplateView->scale(),
100 32 * mWangTemplateView->scale());
101 }
102
103 } // anonymous namespace
104
WangTemplateView(QWidget * parent)105 WangTemplateView::WangTemplateView(QWidget *parent)
106 : QListView(parent)
107 , mZoomable(new Zoomable(this))
108 {
109 setWrapping(true);
110 setFlow(QListView::LeftToRight);
111 setResizeMode(QListView::Adjust);
112 setSelectionMode(QAbstractItemView::SingleSelection);
113 setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
114 setItemDelegate(new WangTemplateDelegate(this, this));
115 setUniformItemSizes(true);
116
117 connect(mZoomable, &Zoomable::scaleChanged,
118 this, &WangTemplateView::adjustScale);
119 }
120
scale() const121 qreal WangTemplateView::scale() const
122 {
123 return mZoomable->scale();
124 }
125
wangSet() const126 WangSet *WangTemplateView::wangSet() const
127 {
128 const WangTemplateModel *model = wangTemplateModel();
129 return model ? model->wangSet() : nullptr;
130 }
131
wangIdIsUsed(WangId wangId) const132 bool WangTemplateView::wangIdIsUsed(WangId wangId) const
133 {
134 if (WangSet *set = wangSet())
135 return set->wangIdIsUsed(wangId);
136
137 return false;
138 }
139
event(QEvent * event)140 bool WangTemplateView::event(QEvent *event)
141 {
142 if (event->type() == QEvent::Gesture) {
143 QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event);
144 if (QGesture *gesture = gestureEvent->gesture(Qt::PinchGesture))
145 mZoomable->handlePinchGesture(static_cast<QPinchGesture *>(gesture));
146 } else if (event->type() == QEvent::ShortcutOverride) {
147 auto keyEvent = static_cast<QKeyEvent*>(event);
148 if (Utils::isZoomInShortcut(keyEvent) ||
149 Utils::isZoomOutShortcut(keyEvent) ||
150 Utils::isResetZoomShortcut(keyEvent)) {
151 event->accept();
152 return true;
153 }
154 }
155
156 return QListView::event(event);
157 }
158
keyPressEvent(QKeyEvent * event)159 void WangTemplateView::keyPressEvent(QKeyEvent *event)
160 {
161 if (Utils::isZoomInShortcut(event)) {
162 mZoomable->zoomIn();
163 return;
164 }
165 if (Utils::isZoomOutShortcut(event)) {
166 mZoomable->zoomOut();
167 return;
168 }
169 if (Utils::isResetZoomShortcut(event)) {
170 mZoomable->resetZoom();
171 return;
172 }
173 return QListView::keyPressEvent(event);
174 }
175
wheelEvent(QWheelEvent * event)176 void WangTemplateView::wheelEvent(QWheelEvent *event)
177 {
178 if (event->modifiers() & Qt::ControlModifier &&
179 event->angleDelta().y())
180 {
181 mZoomable->handleWheelDelta(event->angleDelta().y());
182 return;
183 }
184
185 QListView::wheelEvent(event);
186 }
187
adjustScale()188 void WangTemplateView::adjustScale()
189 {
190 scheduleDelayedItemsLayout();
191 }
192
193 #include "moc_wangtemplateview.cpp"
194