]> git.mxchange.org Git - flightgear.git/blob - src/GUI/AircraftItemDelegate.cxx
Remove some debug noise
[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     // draw bottom dividing line
72     painter->drawLine(contentRect.left(), contentRect.bottom() + MARGIN,
73                       contentRect.right(), contentRect.bottom() + MARGIN);
74
75     int variantCount = index.data(AircraftVariantCountRole).toInt();
76     int currentVariant =index.data(AircraftVariantRole).toInt();
77     QString description = index.data(Qt::DisplayRole).toString();
78     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
79
80     painter->setPen(Qt::black);
81     QFont f;
82     f.setPointSize(18);
83     painter->setFont(f);
84
85     QRect descriptionRect = contentRect.adjusted(ARROW_SIZE, 0, -ARROW_SIZE, 0),
86         actualBounds;
87
88     if (variantCount > 0) {
89         bool canLeft = (currentVariant > 0);
90         bool canRight =  (currentVariant < variantCount );
91
92         QRect leftArrowRect = leftCycleArrowRect(option.rect, index);
93         if (canLeft) {
94             painter->drawPixmap(leftArrowRect.topLeft() + QPoint(2, 2), m_leftArrowIcon);
95         }
96
97         QRect rightArrowRect = rightCycleArrowRect(option.rect, index);
98         if (canRight) {
99             painter->drawPixmap(rightArrowRect.topLeft() + QPoint(2, 2), m_rightArrowIcon);
100         }
101     }
102
103     painter->drawText(descriptionRect, Qt::TextWordWrap, description, &actualBounds);
104
105     QString authors = index.data(AircraftAuthorsRole).toString();
106
107     f.setPointSize(12);
108     painter->setFont(f);
109
110     if (!authors.isEmpty()) {
111         QRect authorsRect = descriptionRect;
112         authorsRect.moveTop(actualBounds.bottom() + MARGIN);
113         painter->drawText(authorsRect, Qt::TextWordWrap,
114                           QString("by: %1").arg(authors),
115                           &actualBounds);
116     }
117
118     QString longDescription = index.data(AircraftLongDescriptionRole).toString();
119     if (!longDescription.isEmpty()) {
120         QRect longDescriptionRect = descriptionRect;
121         longDescriptionRect.moveTop(actualBounds.bottom() + MARGIN);
122         painter->drawText(longDescriptionRect, Qt::TextWordWrap,
123                           longDescription, &actualBounds);
124     }
125
126     QRect r = contentRect;
127     r.setWidth(contentRect.width() / 3);
128     r.moveTop(actualBounds.bottom() + MARGIN);
129     r.moveLeft(r.right());
130     r.setHeight(24);
131
132     if (index.data(AircraftHasRatingsRole).toBool()) {
133         drawRating(painter, "Flight model:", r, index.data(AircraftRatingRole).toInt());
134         r.moveTop(r.bottom());
135         drawRating(painter, "Systems:", r, index.data(AircraftRatingRole + 1).toInt());
136
137         r.moveTop(actualBounds.bottom() + MARGIN);
138         r.moveLeft(r.right());
139         drawRating(painter, "Cockpit:", r, index.data(AircraftRatingRole + 2).toInt());
140         r.moveTop(r.bottom());
141         drawRating(painter, "Exterior model:", r, index.data(AircraftRatingRole + 3).toInt());
142     }
143
144     QVariant v = index.data(AircraftPackageStatusRole);
145     AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
146     double downloadFraction = 0.0;
147     
148     if (status != PackageInstalled) {
149         QString buttonText, infoText;
150         QColor buttonColor(27, 122, 211);
151         
152         double sizeInMBytes = index.data(AircraftPackageSizeRole).toInt();
153         sizeInMBytes /= 0x100000;
154         
155         if (status == PackageDownloading) {
156             buttonText = tr("Cancel");
157             double downloadedMB = index.data(AircraftInstallDownloadedSizeRole).toInt();
158             downloadedMB /= 0x100000;
159             infoText = QStringLiteral("%1 MB of %2 MB").arg(downloadedMB, 0, 'f', 1).arg(sizeInMBytes, 0, 'f', 1);
160             buttonColor = QColor(0xcf, 0xcf, 0xcf);
161             downloadFraction = downloadedMB / sizeInMBytes;
162         } else if (status == PackageQueued) {
163             buttonText = tr("Cancel");
164             infoText = tr("Waiting to download %1 MB").arg(sizeInMBytes, 0, 'f', 1);
165             buttonColor = QColor(0xcf, 0xcf, 0xcf);
166         } else {
167             infoText = QStringLiteral("%1MB").arg(sizeInMBytes, 0, 'f', 1);
168             if (status == PackageNotInstalled) {
169                 buttonText = "Install";
170             } else if (status == PackageUpdateAvailable) {
171                 buttonText = "Update";
172             }
173         }
174         
175         painter->setBrush(Qt::NoBrush);
176         QRect buttonRect = packageButtonRect(option.rect, index);
177         painter->setPen(Qt::NoPen);
178         painter->setBrush(buttonColor);
179         painter->drawRoundedRect(buttonRect, 5, 5);
180         painter->setPen(Qt::white);
181         painter->drawText(buttonRect, Qt::AlignCenter, buttonText);
182         
183         QRect infoTextRect = buttonRect;
184         infoTextRect.setLeft(buttonRect.right() + MARGIN);
185         infoTextRect.setWidth(200);
186         
187         if (status == PackageDownloading) {
188             QRect progressRect = infoTextRect;
189             progressRect.setHeight(6);
190             painter->setPen(QPen(QColor(0xcf, 0xcf, 0xcf), 0));
191             painter->setBrush(Qt::NoBrush);
192             painter->drawRoundedRect(progressRect, 3, 3);
193             infoTextRect.setTop(progressRect.bottom() + 1);
194
195             QRect progressBarRect = progressRect.marginsRemoved(QMargins(2, 2, 2, 2));
196             
197             progressBarRect.setWidth(static_cast<int>(progressBarRect.width() * downloadFraction));
198             
199             painter->setBrush(QColor(27, 122, 211));
200             painter->setPen(Qt::NoPen);
201             painter->drawRoundedRect(progressBarRect, 2, 2);
202         }
203         
204         painter->setPen(Qt::black);
205         painter->drawText(infoTextRect, Qt::AlignLeft | Qt::AlignVCenter, infoText);
206     } // of update / install / download status
207 }
208
209 QSize AircraftItemDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
210 {
211     QRect contentRect = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
212
213     const int THUMBNAIL_WIDTH = 172;
214     // don't request the thumbnail here for remote sources. Assume the default
215     //QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
216     //contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
217     contentRect.setLeft(contentRect.left() + MARGIN + THUMBNAIL_WIDTH);
218     
219     QFont f;
220     f.setPointSize(18);
221     QFontMetrics metrics(f);
222
223     int textHeight = metrics.boundingRect(contentRect, Qt::TextWordWrap,
224                                           index.data().toString()).height();
225
226     f.setPointSize(12);
227     QFontMetrics smallMetrics(f);
228
229     QString authors = index.data(AircraftAuthorsRole).toString();
230     if (!authors.isEmpty()) {
231         textHeight += MARGIN;
232         textHeight += smallMetrics.boundingRect(contentRect, Qt::TextWordWrap, authors).height();
233     }
234
235     QString desc = index.data(AircraftLongDescriptionRole).toString();
236     if (!desc.isEmpty()) {
237         textHeight += MARGIN;
238         textHeight += smallMetrics.boundingRect(contentRect, Qt::TextWordWrap, desc).height();
239     }
240
241     if (index.data(AircraftHasRatingsRole).toBool()) {
242         // ratings
243         textHeight += 48; // (24px per rating box)
244     } else {
245         // just the button height
246         textHeight += BUTTON_HEIGHT;
247     }
248
249     textHeight = qMax(textHeight, 128);
250
251     return QSize(option.rect.width(), textHeight + (MARGIN * 2));
252 }
253
254 bool AircraftItemDelegate::eventFilter( QObject*, QEvent* event )
255 {
256     if ( event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease )
257     {
258         QMouseEvent* me = static_cast< QMouseEvent* >( event );
259         QModelIndex index = m_view->indexAt( me->pos() );
260         int variantCount = index.data(AircraftVariantCountRole).toInt();
261         int variantIndex = index.data(AircraftVariantRole).toInt();
262         QRect vr = m_view->visualRect(index);
263
264         if ( (event->type() == QEvent::MouseButtonRelease) && (variantCount > 0) )
265         {
266             QRect leftCycleRect = leftCycleArrowRect(vr, index),
267                 rightCycleRect = rightCycleArrowRect(vr, index);
268
269             if ((variantIndex > 0) && leftCycleRect.contains(me->pos())) {
270                 m_view->model()->setData(index, variantIndex - 1, AircraftVariantRole);
271                 emit variantChanged(index);
272                 return true;
273             } else if ((variantIndex < variantCount) && rightCycleRect.contains(me->pos())) {
274                 m_view->model()->setData(index, variantIndex + 1, AircraftVariantRole);
275                 emit variantChanged(index);
276                 return true;
277             }
278         }
279         
280         if ((event->type() == QEvent::MouseButtonRelease) &&
281             packageButtonRect(vr, index).contains(me->pos()))
282         {
283             QVariant v = index.data(AircraftPackageStatusRole);
284             AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
285             if (status == PackageNotInstalled) {
286                 emit requestInstall(index);
287             } else if ((status == PackageDownloading) || (status == PackageQueued)) {
288                 emit cancelDownload(index);
289             } else if (status == PackageUpdateAvailable) {
290                 emit requestInstall(index);
291             }
292             
293             return true;
294         }
295     } else if ( event->type() == QEvent::MouseMove ) {
296 #if 0
297         QMouseEvent* me = static_cast< QMouseEvent* >( event );
298         QModelIndex index = m_view->indexAt( me->pos() );
299         QRect vr = m_view->visualRect(index);
300
301         if (packageButtonRect(vr, index).contains(me->pos())) {
302             qDebug() << "mouse inside button";
303         }
304 #endif
305     }
306     
307     return false;
308 }
309
310
311 QRect AircraftItemDelegate::leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const
312 {
313     QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
314     QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
315     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
316
317     QRect r = contentRect;
318     r.setRight(r.left() + ARROW_SIZE);
319     r.setBottom(r.top() + ARROW_SIZE);
320     return r;
321
322 }
323
324 QRect AircraftItemDelegate::rightCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const
325 {
326     QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
327     QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
328     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
329
330     QRect r = contentRect;
331     r.setLeft(r.right() - ARROW_SIZE);
332     r.setBottom(r.top() + ARROW_SIZE);
333     return r;
334
335 }
336
337 QRect AircraftItemDelegate::packageButtonRect(const QRect& visualRect, const QModelIndex& index) const
338 {
339     QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
340     QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
341     contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
342
343     return QRect(contentRect.left() + ARROW_SIZE, contentRect.bottom() - 24,
344                  BUTTON_WIDTH, BUTTON_HEIGHT);
345 }
346
347 void AircraftItemDelegate::drawRating(QPainter* painter, QString label, const QRect& box, int value) const
348 {
349     const int DOT_SIZE = 10;
350     const int DOT_MARGIN = 2;
351
352     QRect dotBox = box;
353     dotBox.setLeft(box.right() - (DOT_MARGIN * 6 + DOT_SIZE * 5));
354
355     painter->setPen(Qt::black);
356     QRect textBox = box;
357     textBox.setRight(dotBox.left() - DOT_MARGIN);
358     painter->drawText(textBox, Qt::AlignVCenter | Qt::AlignRight, label);
359
360     painter->setPen(Qt::NoPen);
361     QRect dot(dotBox.left() + DOT_MARGIN,
362               dotBox.center().y() - (DOT_SIZE / 2),
363               DOT_SIZE,
364               DOT_SIZE);
365     for (int i=0; i<5; ++i) {
366         painter->setBrush((i < value) ? QColor(0x3f, 0x3f, 0x3f) : QColor(0xaf, 0xaf, 0xaf));
367         painter->drawEllipse(dot);
368         dot.moveLeft(dot.right() + DOT_MARGIN);
369     }
370 }