]> git.mxchange.org Git - flightgear.git/blob - src/GUI/AircraftItemDelegate.cxx
Hacking on the delegate height.
[flightgear.git] / src / GUI / AircraftItemDelegate.cxx
1 // AircraftItemDelegate.cxx - part of GUI launcher using Qt5
2 //
3 // Written by James Turner, started March 2015.
4 //
5 // Copyright (C) 2014 James Turner <zakalawe@mac.com>
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21
22 #include "AircraftItemDelegate.hxx"
23
24 #include <QDebug>
25 #include <QPainter>
26 #include <QLinearGradient>
27 #include <QListView>
28 #include <QMouseEvent>
29 #include <QFontMetrics>
30
31 #include "AircraftModel.hxx"
32
33 AircraftItemDelegate::AircraftItemDelegate(QListView* view) :
34     m_view(view)
35 {
36     view->viewport()->installEventFilter(this);
37     view->viewport()->setMouseTracking(true);
38
39     m_leftArrowIcon.load(":/left-arrow-icon");
40     m_rightArrowIcon.load(":/right-arrow-icon");
41 }
42
43 void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option,
44     const QModelIndex & index) const
45 {
46     painter->setRenderHint(QPainter::Antialiasing);
47     // selection feedback rendering
48     if (option.state & QStyle::State_Selected) {
49         QLinearGradient grad(option.rect.topLeft(), option.rect.bottomLeft());
50         grad.setColorAt(0.0, QColor(152, 163, 180));
51         grad.setColorAt(1.0, QColor(90, 107, 131));
52
53         QBrush backgroundBrush(grad);
54         painter->fillRect(option.rect, backgroundBrush);
55
56         painter->setPen(QColor(90, 107, 131));
57         painter->drawLine(option.rect.topLeft(), option.rect.topRight());
58     }
59
60     QRect contentRect = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
61
62     QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
63     quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
64     painter->drawPixmap(contentRect.left(), yPos, thumbnail);
65
66     // draw 1px frame
67     painter->setPen(QColor(0x7f, 0x7f, 0x7f));
68     painter->setBrush(Qt::NoBrush);
69     painter->drawRect(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
70
71     int variantCount = index.data(AircraftVariantCountRole).toInt();
72     int currentVariant =index.data(AircraftVariantRole).toInt();
73     QString description = index.data(Qt::DisplayRole).toString();
74     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
75
76     painter->setPen(Qt::black);
77     QFont f;
78     f.setPointSize(18);
79     painter->setFont(f);
80
81     QRect descriptionRect = contentRect.adjusted(ARROW_SIZE, 0, -ARROW_SIZE, 0),
82         actualBounds;
83
84     if (variantCount > 0) {
85         bool canLeft = (currentVariant > 0);
86         bool canRight =  (currentVariant < variantCount );
87
88         QRect leftArrowRect = leftCycleArrowRect(option.rect, index);
89         if (canLeft) {
90             painter->drawPixmap(leftArrowRect.topLeft() + QPoint(2, 2), m_leftArrowIcon);
91         }
92
93         QRect rightArrowRect = rightCycleArrowRect(option.rect, index);
94         if (canRight) {
95             painter->drawPixmap(rightArrowRect.topLeft() + QPoint(2, 2), m_rightArrowIcon);
96         }
97     }
98
99     painter->drawText(descriptionRect, Qt::TextWordWrap, description, &actualBounds);
100
101     QString authors = index.data(AircraftAuthorsRole).toString();
102
103     f.setPointSize(12);
104     painter->setFont(f);
105
106     if (!authors.isEmpty()) {
107         QRect authorsRect = descriptionRect;
108         authorsRect.moveTop(actualBounds.bottom() + MARGIN);
109         painter->drawText(authorsRect, Qt::TextWordWrap,
110                           QString("by: %1").arg(authors),
111                           &actualBounds);
112     }
113
114     QString longDescription = index.data(AircraftLongDescriptionRole).toString();
115     if (!longDescription.isEmpty()) {
116         QRect longDescriptionRect = descriptionRect;
117         longDescriptionRect.moveTop(actualBounds.bottom() + MARGIN);
118         painter->drawText(longDescriptionRect, Qt::TextWordWrap,
119                           longDescription, &actualBounds);
120     }
121
122     QRect r = contentRect;
123     r.setWidth(contentRect.width() / 3);
124     r.moveTop(actualBounds.bottom() + MARGIN);
125     r.moveLeft(r.right());
126     r.setHeight(24);
127
128     drawRating(painter, "Flight model:", r, index.data(AircraftRatingRole).toInt());
129     r.moveTop(r.bottom());
130     drawRating(painter, "Systems:", r, index.data(AircraftRatingRole + 1).toInt());
131
132     r.moveTop(actualBounds.bottom() + MARGIN);
133     r.moveLeft(r.right());
134     drawRating(painter, "Cockpit:", r, index.data(AircraftRatingRole + 2).toInt());
135     r.moveTop(r.bottom());
136     drawRating(painter, "Exterior model:", r, index.data(AircraftRatingRole + 3).toInt());
137
138     QVariant v = index.data(AircraftPackageStatusRole);
139     AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
140     status = PackageNotInstalled;
141     if (status != PackageInstalled) {
142         painter->setBrush(Qt::NoBrush);
143         QRect buttonRect = packageButtonRect(option.rect, index);
144         painter->setPen(Qt::NoPen);
145         painter->setBrush(QColor(27, 122, 211));
146         painter->drawRoundedRect(buttonRect, 5, 5);
147         painter->setPen(Qt::white);
148
149         if (status == PackageNotInstalled) {
150             painter->drawText(buttonRect, Qt::AlignCenter, "Install");
151         } else if (status == PackageUpdateAvailable) {
152             painter->drawText(buttonRect, Qt::AlignCenter, "Update");
153         }
154     }
155 }
156
157 QSize AircraftItemDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
158 {
159     QRect contentRect = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
160     QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
161     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
162
163     QFont f;
164     f.setPointSize(18);
165     QFontMetrics metrics(f);
166
167     int textHeight = metrics.boundingRect(contentRect, Qt::TextWordWrap,
168                                           index.data().toString()).height();
169
170     f.setPointSize(12);
171     QFontMetrics smallMetrics(f);
172
173     QString authors = index.data(AircraftAuthorsRole).toString();
174     if (!authors.isEmpty()) {
175         textHeight += MARGIN;
176         textHeight += smallMetrics.boundingRect(contentRect, Qt::TextWordWrap, authors).height();
177     }
178
179     QString desc = index.data(AircraftLongDescriptionRole).toString();
180     if (!desc.isEmpty()) {
181         textHeight += MARGIN;
182         textHeight += smallMetrics.boundingRect(contentRect, Qt::TextWordWrap, desc).height();
183     }
184
185     // ratings
186     textHeight += 48; // (24px per rating box)
187
188     textHeight = qMax(textHeight, 128);
189
190     return QSize(option.rect.width(), textHeight + (MARGIN * 2));
191 }
192
193 bool AircraftItemDelegate::eventFilter( QObject*, QEvent* event )
194 {
195     if ( event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease )
196     {
197         QMouseEvent* me = static_cast< QMouseEvent* >( event );
198         QModelIndex index = m_view->indexAt( me->pos() );
199         int variantCount = index.data(AircraftVariantCountRole).toInt();
200         int variantIndex = index.data(AircraftVariantRole).toInt();
201
202         if ( (event->type() == QEvent::MouseButtonRelease) && (variantCount > 0) )
203         {
204             QRect vr = m_view->visualRect(index);
205             QRect leftCycleRect = leftCycleArrowRect(vr, index),
206                 rightCycleRect = rightCycleArrowRect(vr, index);
207
208             if ((variantIndex > 0) && leftCycleRect.contains(me->pos())) {
209                 m_view->model()->setData(index, variantIndex - 1, AircraftVariantRole);
210                 emit variantChanged(index);
211                 return true;
212             } else if ((variantIndex < variantCount) && rightCycleRect.contains(me->pos())) {
213                 m_view->model()->setData(index, variantIndex + 1, AircraftVariantRole);
214                 emit variantChanged(index);
215                 return true;
216             }
217         }
218     } else if ( event->type() == QEvent::MouseMove ) {
219         QMouseEvent* me = static_cast< QMouseEvent* >( event );
220         QModelIndex index = m_view->indexAt( me->pos() );
221         QRect vr = m_view->visualRect(index);
222
223         if (packageButtonRect(vr, index).contains(me->pos())) {
224             qDebug() << "mouse inside button";
225         }
226
227     }
228     
229     return false;
230 }
231
232
233 QRect AircraftItemDelegate::leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const
234 {
235     QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
236     QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
237     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
238
239     QRect r = contentRect;
240     r.setRight(r.left() + ARROW_SIZE);
241     r.setBottom(r.top() + ARROW_SIZE);
242     return r;
243
244 }
245
246 QRect AircraftItemDelegate::rightCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const
247 {
248     QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
249     QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
250     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
251
252     QRect r = contentRect;
253     r.setLeft(r.right() - ARROW_SIZE);
254     r.setBottom(r.top() + ARROW_SIZE);
255     return r;
256
257 }
258
259 QRect AircraftItemDelegate::packageButtonRect(const QRect& visualRect, const QModelIndex& index) const
260 {
261     QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
262     QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
263     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
264
265     return QRect(contentRect.left() + ARROW_SIZE, contentRect.bottom() - 24, 60, 24);
266 }
267
268 void AircraftItemDelegate::drawRating(QPainter* painter, QString label, const QRect& box, int value) const
269 {
270     const int DOT_SIZE = 10;
271     const int DOT_MARGIN = 4;
272
273     QRect dotBox = box;
274     dotBox.setLeft(box.right() - (DOT_MARGIN * 6 + DOT_SIZE * 5));
275
276     painter->setPen(Qt::black);
277     QRect textBox = box;
278     textBox.setRight(dotBox.left() - DOT_MARGIN);
279     painter->drawText(textBox, Qt::AlignVCenter | Qt::AlignRight, label);
280
281     painter->setPen(Qt::NoPen);
282     QRect dot(dotBox.left() + DOT_MARGIN,
283               dotBox.center().y() - (DOT_SIZE / 2),
284               DOT_SIZE,
285               DOT_SIZE);
286     for (int i=0; i<5; ++i) {
287         painter->setBrush((i < value) ? QColor(0x3f, 0x3f, 0x3f) : QColor(0xaf, 0xaf, 0xaf));
288         painter->drawEllipse(dot);
289         dot.moveLeft(dot.right() + DOT_MARGIN);
290     }
291 }