Previews displayed in the launcher.
This commit is contained in:
parent
38554f629f
commit
17fe0460a9
16 changed files with 1004 additions and 786 deletions
|
@ -305,7 +305,7 @@ endif (USE_DBUS)
|
|||
## Qt5 setup setup
|
||||
if (ENABLE_QT)
|
||||
message(STATUS "Qt launcher enabled, checking for Qt 5.1 / qmake")
|
||||
find_package(Qt5 5.1 COMPONENTS Widgets)
|
||||
find_package(Qt5 5.1 COMPONENTS Widgets Network)
|
||||
if (Qt5Widgets_FOUND)
|
||||
message(STATUS "Will enable Qt launcher GUI")
|
||||
message(STATUS " Qt5Widgets version: ${Qt5Widgets_VERSION_STRING}")
|
||||
|
|
|
@ -46,6 +46,8 @@ AircraftItemDelegate::AircraftItemDelegate(QListView* view) :
|
|||
|
||||
m_leftArrowIcon.load(":/left-arrow-icon");
|
||||
m_rightArrowIcon.load(":/right-arrow-icon");
|
||||
m_openPreviewsIcon.load(":/preview-icon");
|
||||
m_openPreviewsIcon = m_openPreviewsIcon.scaled(32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option,
|
||||
|
@ -79,15 +81,22 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
|
|||
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
|
||||
}
|
||||
|
||||
|
||||
// thumbnail
|
||||
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
||||
quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
|
||||
painter->drawPixmap(contentRect.left(), yPos, thumbnail);
|
||||
|
||||
// draw 1px frame
|
||||
QRect thumbFrame(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
|
||||
painter->setPen(QColor(0x7f, 0x7f, 0x7f));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
|
||||
painter->drawRect(thumbFrame);
|
||||
|
||||
if (!index.data(AircraftPreviewsRole).toList().empty()) {
|
||||
QRect previewIconRect = m_openPreviewsIcon.rect();
|
||||
previewIconRect.moveBottomLeft(thumbFrame.bottomLeft());
|
||||
painter->drawPixmap(previewIconRect, m_openPreviewsIcon);
|
||||
}
|
||||
|
||||
// draw bottom dividing line
|
||||
painter->drawLine(contentRect.left(), contentRect.bottom() + MARGIN,
|
||||
|
@ -337,6 +346,13 @@ bool AircraftItemDelegate::eventFilter( QObject*, QEvent* event )
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((event->type() == QEvent::MouseButtonRelease) &&
|
||||
!index.data(AircraftPreviewsRole).toList().empty() &&
|
||||
showPreviewsRect(vr, index).contains(me->pos()))
|
||||
{
|
||||
emit showPreviews(index);
|
||||
}
|
||||
} else if ( event->type() == QEvent::MouseMove ) {
|
||||
|
||||
}
|
||||
|
@ -381,6 +397,18 @@ QRect AircraftItemDelegate::packageButtonRect(const QRect& visualRect, const QMo
|
|||
BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
}
|
||||
|
||||
QRect AircraftItemDelegate::showPreviewsRect(const QRect& visualRect, const QModelIndex& index) const
|
||||
{
|
||||
QRect contentRect = visualRect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
|
||||
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
||||
const quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
|
||||
QRect thumbFrame(contentRect.left(), yPos, thumbnail.width(), thumbnail.height());
|
||||
|
||||
QRect previewIconRect = m_openPreviewsIcon.rect();
|
||||
previewIconRect.moveBottomLeft(thumbFrame.bottomLeft());
|
||||
return previewIconRect;
|
||||
}
|
||||
|
||||
void AircraftItemDelegate::drawRating(QPainter* painter, QString label, const QRect& box, int value) const
|
||||
{
|
||||
QRect dotBox = box;
|
||||
|
|
|
@ -50,17 +50,23 @@ Q_SIGNALS:
|
|||
void requestUninstall(const QModelIndex& index);
|
||||
|
||||
void cancelDownload(const QModelIndex& index);
|
||||
|
||||
void showPreviews(const QModelIndex& index);
|
||||
|
||||
private:
|
||||
QRect leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||
QRect rightCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||
|
||||
QRect packageButtonRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||
|
||||
QRect showPreviewsRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||
|
||||
void drawRating(QPainter* painter, QString label, const QRect& box, int value) const;
|
||||
|
||||
QListView* m_view;
|
||||
QPixmap m_leftArrowIcon,
|
||||
m_rightArrowIcon;
|
||||
m_rightArrowIcon,
|
||||
m_openPreviewsIcon;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,28 +40,18 @@
|
|||
// FlightGear
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
|
||||
const int STANDARD_THUMBNAIL_HEIGHT = 128;
|
||||
const int STANDARD_THUMBNAIL_WIDTH = 172;
|
||||
static quint32 CACHE_VERSION = 6;
|
||||
|
||||
using namespace simgear::pkg;
|
||||
|
||||
AircraftItem::AircraftItem() :
|
||||
excluded(false),
|
||||
usesHeliports(false),
|
||||
usesSeaports(false)
|
||||
AircraftItem::AircraftItem()
|
||||
{
|
||||
// oh for C++11 initialisers
|
||||
for (int i=0; i<4; ++i) ratings[i] = 0;
|
||||
}
|
||||
|
||||
AircraftItem::AircraftItem(QDir dir, QString filePath) :
|
||||
excluded(false),
|
||||
usesHeliports(false),
|
||||
usesSeaports(false)
|
||||
AircraftItem::AircraftItem(QDir dir, QString filePath)
|
||||
{
|
||||
for (int i=0; i<4; ++i) ratings[i] = 0;
|
||||
|
||||
SGPropertyNode root;
|
||||
readProperties(filePath.toStdString(), &root);
|
||||
|
||||
|
@ -113,6 +103,16 @@ AircraftItem::AircraftItem(QDir dir, QString filePath) :
|
|||
}
|
||||
} // of tags iteration
|
||||
} // of set-xml has tags
|
||||
|
||||
if (sim->hasChild("previews")) {
|
||||
SGPropertyNode_ptr previewsNode = sim->getChild("previews");
|
||||
for (auto previewNode : previewsNode->getChildren("preview")) {
|
||||
// add file path as url
|
||||
QString pathInXml = QString::fromStdString(previewNode->getStringValue("path"));
|
||||
QString previewPath = dir.absoluteFilePath(pathInXml);
|
||||
previews.append(QUrl::fromLocalFile(previewPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString AircraftItem::baseName() const
|
||||
|
@ -131,6 +131,7 @@ void AircraftItem::fromDataStream(QDataStream& ds)
|
|||
|
||||
ds >> description >> longDescription >> authors >> variantOf;
|
||||
for (int i=0; i<4; ++i) ds >> ratings[i];
|
||||
ds >> previews;
|
||||
}
|
||||
|
||||
void AircraftItem::toDataStream(QDataStream& ds) const
|
||||
|
@ -142,6 +143,7 @@ void AircraftItem::toDataStream(QDataStream& ds) const
|
|||
|
||||
ds << description << longDescription << authors << variantOf;
|
||||
for (int i=0; i<4; ++i) ds << ratings[i];
|
||||
ds << previews;
|
||||
}
|
||||
|
||||
QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
||||
|
@ -161,9 +163,6 @@ QPixmap AircraftItem::thumbnail(bool loadIfRequired) const
|
|||
return m_thumbnail;
|
||||
}
|
||||
|
||||
|
||||
static quint32 CACHE_VERSION = 5;
|
||||
|
||||
class AircraftScanThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -402,14 +401,22 @@ protected:
|
|||
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT, Qt::SmoothTransformation);
|
||||
}
|
||||
m_model->m_thumbnailPixmapCache.insert(QString::fromStdString(aThumbnailUrl), pix);
|
||||
|
||||
// notify any affected items. Linear scan here avoids another map/dict
|
||||
// structure.
|
||||
m_model->m_downloadedPixmapCache.insert(QString::fromStdString(aThumbnailUrl), pix);
|
||||
|
||||
// notify any affected items. Linear scan here avoids another map/dict structure.
|
||||
for (auto pkg : m_model->m_packages) {
|
||||
const string_list& urls(pkg->thumbnailUrls());
|
||||
auto cit = std::find(urls.begin(), urls.end(), aThumbnailUrl);
|
||||
if (cit != urls.end()) {
|
||||
const int variantCount = pkg->variants().size();
|
||||
bool notifyChanged = false;
|
||||
|
||||
for (int v=0; v < variantCount; ++v) {
|
||||
const Package::Thumbnail& thumb(pkg->thumbnailForVariant(v));
|
||||
if (thumb.url == aThumbnailUrl) {
|
||||
notifyChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (notifyChanged) {
|
||||
QModelIndex mi = indexForPackage(pkg);
|
||||
m_model->dataChanged(mi, mi);
|
||||
}
|
||||
|
@ -432,7 +439,7 @@ private:
|
|||
AircraftItemModel* m_model;
|
||||
};
|
||||
|
||||
AircraftItemModel::AircraftItemModel(QObject* pr ) :
|
||||
AircraftItemModel::AircraftItemModel(QObject* pr) :
|
||||
QAbstractListModel(pr)
|
||||
{
|
||||
}
|
||||
|
@ -593,10 +600,6 @@ QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
|
|||
return m_delegateStates.at(row).variant;
|
||||
}
|
||||
|
||||
if (role == AircraftCurrentThumbnailRole) {
|
||||
return m_delegateStates.at(row).thumbnail;
|
||||
}
|
||||
|
||||
if (row >= m_items.size()) {
|
||||
quint32 packageIndex = row - m_items.size();
|
||||
const PackageRef& pkg(m_packages[packageIndex]);
|
||||
|
@ -623,20 +626,7 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
|||
return item->variants.count();
|
||||
}
|
||||
|
||||
if (role == AircraftThumbnailCountRole) {
|
||||
QPixmap p = item->thumbnail();
|
||||
return p.isNull() ? 0 : 1;
|
||||
}
|
||||
|
||||
if (role == AircraftThumbnailSizeRole) {
|
||||
QPixmap pm = item->thumbnail(false);
|
||||
if (pm.isNull()) {
|
||||
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
||||
}
|
||||
return pm.size();
|
||||
}
|
||||
|
||||
if ((role >= AircraftVariantDescriptionRole) && (role < AircraftThumbnailRole)) {
|
||||
if (role >= AircraftVariantDescriptionRole) {
|
||||
int variantIndex = role - AircraftVariantDescriptionRole;
|
||||
return item->variants.at(variantIndex)->description;
|
||||
}
|
||||
|
@ -648,6 +638,14 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
|||
}
|
||||
}
|
||||
|
||||
if (role == AircraftThumbnailSizeRole) {
|
||||
QPixmap pm = item->thumbnail(false);
|
||||
if (pm.isNull()) {
|
||||
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
||||
}
|
||||
return pm.size();
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (item->description.isEmpty()) {
|
||||
return tr("Missing description for: %1").arg(item->baseName());
|
||||
|
@ -662,7 +660,13 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
|||
return item->authors;
|
||||
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
|
||||
return item->ratings[role - AircraftRatingRole];
|
||||
} else if (role >= AircraftThumbnailRole) {
|
||||
} else if (role == AircraftPreviewsRole) {
|
||||
QVariantList result;
|
||||
Q_FOREACH(QUrl u, item->previews) {
|
||||
result.append(u);
|
||||
}
|
||||
return result;
|
||||
} else if (role == AircraftThumbnailRole) {
|
||||
return item->thumbnail();
|
||||
} else if (role == AircraftPackageIdRole) {
|
||||
// can we fake an ID? otherwise fall through to a null variant
|
||||
|
@ -692,10 +696,10 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateSta
|
|||
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const DelegateState& state, int role) const
|
||||
{
|
||||
if (role == Qt::DecorationRole) {
|
||||
role = AircraftThumbnailRole; // use first thumbnail
|
||||
role = AircraftThumbnailRole;
|
||||
}
|
||||
|
||||
if ((role >= AircraftVariantDescriptionRole) && (role < AircraftThumbnailRole)) {
|
||||
if (role >= AircraftVariantDescriptionRole) {
|
||||
int variantIndex = role - AircraftVariantDescriptionRole;
|
||||
QString desc = QString::fromStdString(item->nameForVariant(variantIndex));
|
||||
if (desc.isEmpty()) {
|
||||
|
@ -743,11 +747,10 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const Delega
|
|||
if (pm.isNull())
|
||||
return QSize(STANDARD_THUMBNAIL_WIDTH, STANDARD_THUMBNAIL_HEIGHT);
|
||||
return pm.size();
|
||||
} else if (role >= AircraftThumbnailRole) {
|
||||
DelegateState changedState(state);
|
||||
// override the current thumbnail as required
|
||||
changedState.thumbnail = (role - AircraftThumbnailRole);
|
||||
return packageThumbnail(item, changedState);
|
||||
} else if (role == AircraftThumbnailRole) {
|
||||
return packageThumbnail(item, state);
|
||||
} else if (role == AircraftPreviewsRole) {
|
||||
return packagePreviews(item, state);
|
||||
} else if (role == AircraftAuthorsRole) {
|
||||
std::string authors = item->getLocalisedProp("author", state.variant);
|
||||
if (!authors.empty()) {
|
||||
|
@ -776,46 +779,69 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const Delega
|
|||
|
||||
QVariant AircraftItemModel::packageThumbnail(PackageRef p, const DelegateState& ds, bool download) const
|
||||
{
|
||||
const string_list& thumbnails(p->thumbnailUrls());
|
||||
if (ds.thumbnail >= static_cast<int>(thumbnails.size())) {
|
||||
const Package::Thumbnail& thumb(p->thumbnailForVariant(ds.variant));
|
||||
if (thumb.url.empty()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
std::string thumbnailUrl = thumbnails.at(ds.thumbnail);
|
||||
QString urlQString(QString::fromStdString(thumbnailUrl));
|
||||
if (m_thumbnailPixmapCache.contains(urlQString)) {
|
||||
QString urlQString(QString::fromStdString(thumb.url));
|
||||
if (m_downloadedPixmapCache.contains(urlQString)) {
|
||||
// cache hit, easy
|
||||
return m_thumbnailPixmapCache.value(urlQString);
|
||||
return m_downloadedPixmapCache.value(urlQString);
|
||||
}
|
||||
|
||||
// check the on-disk store. This relies on the order of thumbnails in the
|
||||
// results of thumbnailUrls and thumbnails corresponding
|
||||
// check the on-disk store.
|
||||
InstallRef ex = p->existingInstall();
|
||||
if (ex.valid()) {
|
||||
const string_list& thumbNames(p->thumbnails());
|
||||
if (!thumbNames.empty()) {
|
||||
SGPath path(ex->path());
|
||||
path.append(p->thumbnails()[ds.thumbnail]);
|
||||
if (path.exists()) {
|
||||
SGPath thumbPath = ex->path() / thumb.path;
|
||||
if (thumbPath.exists()) {
|
||||
QPixmap pix;
|
||||
pix.load(QString::fromStdString(path.utf8Str()));
|
||||
pix.load(QString::fromStdString(thumbPath.utf8Str()));
|
||||
// resize to the standard size
|
||||
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
|
||||
}
|
||||
m_thumbnailPixmapCache[urlQString] = pix;
|
||||
m_downloadedPixmapCache[urlQString] = pix;
|
||||
return pix;
|
||||
}
|
||||
} // of have thumbnail file names
|
||||
} // of have existing install
|
||||
|
||||
if (download) {
|
||||
m_packageRoot->requestThumbnailData(thumbnailUrl);
|
||||
m_packageRoot->requestThumbnailData(thumb.url);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant AircraftItemModel::packagePreviews(PackageRef p, const DelegateState& ds) const
|
||||
{
|
||||
const Package::PreviewVec& previews = p->previewsForVariant(ds.variant);
|
||||
if (previews.empty()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariantList result;
|
||||
// if we have an install, return file URLs, not remote (http) ones
|
||||
InstallRef ex = p->existingInstall();
|
||||
if (ex.valid()) {
|
||||
for (auto p : previews) {
|
||||
SGPath localPreviewPath = ex->path() / p.path;
|
||||
if (!localPreviewPath.exists()) {
|
||||
qWarning() << "missing local preview" << QString::fromStdString(localPreviewPath.utf8Str());
|
||||
continue;
|
||||
}
|
||||
result.append(QUrl::fromLocalFile(QString::fromStdString(localPreviewPath.utf8Str())));
|
||||
}
|
||||
}
|
||||
|
||||
// return remote urls
|
||||
for (auto p : previews) {
|
||||
result.append(QUrl(QString::fromStdString(p.url)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
int row = index.row();
|
||||
|
@ -831,16 +857,6 @@ bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (role == AircraftCurrentThumbnailRole) {
|
||||
if (m_delegateStates[row].thumbnail == newValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
m_delegateStates[row].thumbnail = newValue;
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ const int AircraftPathRole = Qt::UserRole + 1;
|
|||
const int AircraftAuthorsRole = Qt::UserRole + 2;
|
||||
const int AircraftVariantRole = Qt::UserRole + 3;
|
||||
const int AircraftVariantCountRole = Qt::UserRole + 4;
|
||||
const int AircraftThumbnailCountRole = Qt::UserRole + 5;
|
||||
const int AircraftPackageIdRole = Qt::UserRole + 6;
|
||||
const int AircraftPackageStatusRole = Qt::UserRole + 7;
|
||||
const int AircraftPackageProgressRole = Qt::UserRole + 8;
|
||||
|
@ -51,12 +50,12 @@ const int AircraftURIRole = Qt::UserRole + 14;
|
|||
const int AircraftThumbnailSizeRole = Qt::UserRole + 15;
|
||||
const int AircraftIsHelicopterRole = Qt::UserRole + 16;
|
||||
const int AircraftIsSeaplaneRole = Qt::UserRole + 17;
|
||||
const int AircraftCurrentThumbnailRole = Qt::UserRole + 18;
|
||||
const int AircraftPackageRefRole = Qt::UserRole + 19;
|
||||
const int AircraftThumbnailRole = Qt::UserRole + 20;
|
||||
const int AircraftPreviewsRole = Qt::UserRole + 21;
|
||||
|
||||
const int AircraftRatingRole = Qt::UserRole + 100;
|
||||
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
|
||||
const int AircraftThumbnailRole = Qt::UserRole + 300;
|
||||
|
||||
class AircraftScanThread;
|
||||
class QDataStream;
|
||||
|
@ -81,17 +80,18 @@ struct AircraftItem
|
|||
|
||||
QPixmap thumbnail(bool loadIfRequired = true) const;
|
||||
|
||||
bool excluded;
|
||||
bool excluded = false;
|
||||
QString path;
|
||||
QString description;
|
||||
QString longDescription;
|
||||
QString authors;
|
||||
int ratings[4];
|
||||
int ratings[4] = {0, 0, 0, 0};
|
||||
QString variantOf;
|
||||
QDateTime pathModTime;
|
||||
QList<AircraftItemPtr> variants;
|
||||
bool usesHeliports;
|
||||
bool usesSeaports;
|
||||
bool usesHeliports = false;
|
||||
bool usesSeaports = false;
|
||||
QList<QUrl> previews;
|
||||
private:
|
||||
mutable QPixmap m_thumbnail;
|
||||
};
|
||||
|
@ -199,6 +199,8 @@ private:
|
|||
QVariant packageThumbnail(simgear::pkg::PackageRef p,
|
||||
const DelegateState& state, bool download = true) const;
|
||||
|
||||
QVariant packagePreviews(simgear::pkg::PackageRef p, const DelegateState &ds) const;
|
||||
|
||||
void abandonCurrentScan();
|
||||
void refreshPackages();
|
||||
|
||||
|
@ -217,7 +219,7 @@ private:
|
|||
simgear::pkg::RootRef m_packageRoot;
|
||||
simgear::pkg::PackageList m_packages;
|
||||
|
||||
mutable QHash<QString, QPixmap> m_thumbnailPixmapCache;
|
||||
mutable QHash<QString, QPixmap> m_downloadedPixmapCache;
|
||||
};
|
||||
|
||||
#endif // of FG_GUI_AIRCRAFT_MODEL
|
||||
|
|
|
@ -117,11 +117,13 @@ if (HAVE_QT)
|
|||
InstallSceneryDialog.cxx
|
||||
EditCustomMPServerDialog.cxx
|
||||
EditCustomMPServerDialog.hxx
|
||||
PreviewWindow.cpp
|
||||
PreviewWindow.h
|
||||
${uic_sources}
|
||||
${qrc_sources})
|
||||
|
||||
set_property(TARGET fglauncher PROPERTY AUTOMOC ON)
|
||||
target_link_libraries(fglauncher Qt5::Core Qt5::Widgets SimGearCore)
|
||||
target_link_libraries(fglauncher Qt5::Core Qt5::Widgets Qt5::Network SimGearCore)
|
||||
target_include_directories(fglauncher PRIVATE ${PROJECT_BINARY_DIR}/src/GUI)
|
||||
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="summaryTab">
|
||||
<attribute name="title">
|
||||
|
@ -698,4 +698,4 @@
|
|||
<include location="resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
</ui>
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#include "AircraftModel.hxx"
|
||||
#include "PathsDialog.hxx"
|
||||
#include "EditCustomMPServerDialog.hxx"
|
||||
#include "previewwindow.h"
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
@ -854,6 +855,8 @@ QtLauncher::QtLauncher() :
|
|||
this, &QtLauncher::onRequestPackageUninstall);
|
||||
connect(delegate, &AircraftItemDelegate::cancelDownload,
|
||||
this, &QtLauncher::onCancelDownload);
|
||||
connect(delegate, &AircraftItemDelegate::showPreviews,
|
||||
this, &QtLauncher::onShowPreviews);
|
||||
|
||||
connect(m_aircraftModel, &AircraftItemModel::aircraftInstallCompleted,
|
||||
this, &QtLauncher::onAircraftInstalledCompleted);
|
||||
|
@ -1401,6 +1404,14 @@ void QtLauncher::onRequestPackageUninstall(const QModelIndex& index)
|
|||
}
|
||||
}
|
||||
|
||||
void QtLauncher::onShowPreviews(const QModelIndex &index)
|
||||
{
|
||||
QVariant urls = index.data(AircraftPreviewsRole);
|
||||
|
||||
PreviewWindow* previewWindow = new PreviewWindow;
|
||||
previewWindow->setUrls(urls.toList());
|
||||
}
|
||||
|
||||
void QtLauncher::onCancelDownload(const QModelIndex& index)
|
||||
{
|
||||
QString pkg = index.data(AircraftPackageIdRole).toString();
|
||||
|
|
|
@ -75,7 +75,7 @@ private slots:
|
|||
void onAircraftSelected(const QModelIndex& index);
|
||||
void onRequestPackageInstall(const QModelIndex& index);
|
||||
void onRequestPackageUninstall(const QModelIndex& index);
|
||||
|
||||
void onShowPreviews(const QModelIndex& index);
|
||||
void onCancelDownload(const QModelIndex& index);
|
||||
|
||||
void onPopupAircraftHistory();
|
||||
|
|
BIN
src/GUI/preview-close.png
Normal file
BIN
src/GUI/preview-close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
src/GUI/preview-icon.png
Normal file
BIN
src/GUI/preview-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 771 B |
BIN
src/GUI/preview-left-arrow.png
Normal file
BIN
src/GUI/preview-left-arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1,016 B |
BIN
src/GUI/preview-right-arrow.png
Normal file
BIN
src/GUI/preview-right-arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 964 B |
108
src/GUI/previewwindow.cpp
Normal file
108
src/GUI/previewwindow.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "previewwindow.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QNetworkReply>
|
||||
|
||||
const int BORDER_SIZE = 16;
|
||||
|
||||
PreviewWindow::PreviewWindow(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_netAccess(new QNetworkAccessManager(this))
|
||||
{
|
||||
setWindowFlags(Qt::Popup);
|
||||
setModal(true);
|
||||
|
||||
m_closeIcon.load(":/preview/close-icon");
|
||||
m_leftIcon.load(":/preview/left-arrow-icon");
|
||||
m_rightIcon.load(":/preview/right-arrow-icon");
|
||||
}
|
||||
|
||||
void PreviewWindow::setUrls(QVariantList urls)
|
||||
{
|
||||
m_cache.clear();
|
||||
|
||||
Q_FOREACH (QVariant v, urls) {
|
||||
QUrl url = v.toUrl();
|
||||
qWarning() << v;
|
||||
m_urls.append(url);
|
||||
QNetworkReply* reply = m_netAccess->get(QNetworkRequest(url));
|
||||
connect(reply, &QNetworkReply::finished, this, &PreviewWindow::onDownloadFinished);
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewWindow::paintEvent(QPaintEvent *pe)
|
||||
{
|
||||
QUrl key = m_urls.at(m_currentPreview);
|
||||
QPixmap pm = m_cache.value(key.toString());
|
||||
if (pm.isNull()) {
|
||||
qWarning() << "null pixmap";
|
||||
}
|
||||
|
||||
QPainter painter(this);
|
||||
painter.fillRect(rect(), Qt::black);
|
||||
|
||||
QRect imgRect = rect().adjusted(BORDER_SIZE, BORDER_SIZE, -BORDER_SIZE, -BORDER_SIZE);
|
||||
painter.drawPixmap(imgRect, pm);
|
||||
|
||||
QRect closeIconRect = m_closeIcon.rect();
|
||||
closeIconRect.moveTopRight(rect().topRight());
|
||||
painter.drawPixmap(closeIconRect, m_closeIcon);
|
||||
|
||||
QRect leftArrowRect = m_leftIcon.rect();
|
||||
unsigned int iconTop = rect().center().y() - (m_leftIcon.size().height() / 2);
|
||||
leftArrowRect.moveTopLeft(QPoint(0, iconTop));
|
||||
painter.drawPixmap(leftArrowRect, m_leftIcon);
|
||||
|
||||
QRect rightArrowRect = m_rightIcon.rect();
|
||||
rightArrowRect.moveTopRight(QPoint(width(), iconTop));
|
||||
painter.drawPixmap(rightArrowRect, m_rightIcon);
|
||||
}
|
||||
|
||||
void PreviewWindow::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QRect closeIconRect = m_closeIcon.rect();
|
||||
closeIconRect.moveTopRight(rect().topRight());
|
||||
|
||||
QRect leftArrowRect = m_leftIcon.rect();
|
||||
unsigned int iconTop = rect().center().y() - (m_leftIcon.size().height() / 2);
|
||||
leftArrowRect.moveTopLeft(QPoint(0, iconTop));
|
||||
|
||||
QRect rightArrowRect = m_rightIcon.rect();
|
||||
rightArrowRect.moveTopRight(QPoint(width(), iconTop));
|
||||
|
||||
if (closeIconRect.contains(event->pos())) {
|
||||
close();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
if (leftArrowRect.contains(event->pos())) {
|
||||
m_currentPreview = (m_currentPreview - 1) % m_urls.size();
|
||||
update();
|
||||
}
|
||||
|
||||
if (rightArrowRect.contains(event->pos())) {
|
||||
m_currentPreview = (m_currentPreview + 1) % m_urls.size();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewWindow::onDownloadFinished()
|
||||
{
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||
|
||||
QImage img;
|
||||
if (!img.load(reply, nullptr)) {
|
||||
qWarning() << "failed to read image data from" << reply->url();
|
||||
return;
|
||||
}
|
||||
|
||||
m_cache.insert(reply->url().toString(), QPixmap::fromImage(img));
|
||||
|
||||
if (!isVisible()) {
|
||||
QSize winSize(img.width() + BORDER_SIZE * 2, img.height() + BORDER_SIZE * 2);
|
||||
resize(winSize);
|
||||
|
||||
show();
|
||||
}
|
||||
}
|
39
src/GUI/previewwindow.h
Normal file
39
src/GUI/previewwindow.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef PREVIEWWINDOW_H
|
||||
#define PREVIEWWINDOW_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <QVariant>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QMap>
|
||||
|
||||
class PreviewWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PreviewWindow(QWidget *parent = 0);
|
||||
|
||||
void setUrls(QVariantList urls);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *pe) override;
|
||||
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
void onDownloadFinished();
|
||||
|
||||
|
||||
unsigned int m_currentPreview = 0;
|
||||
QNetworkAccessManager* m_netAccess;
|
||||
QList<QUrl> m_urls;
|
||||
QMap<QUrl, QPixmap> m_cache;
|
||||
|
||||
QPixmap m_leftIcon, m_rightIcon, m_closeIcon;
|
||||
};
|
||||
|
||||
#endif // PREVIEWWINDOW_H
|
|
@ -19,5 +19,11 @@
|
|||
<file alias="ndb-large-icon">ndb-large-icon.png</file>
|
||||
<file alias="airplane-icon">airplane-icon.png</file>
|
||||
<file alias="airport-closed-icon">airport-closed-icon.png</file>
|
||||
<file alias="preview-icon">preview-icon.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/preview">
|
||||
<file alias="close-icon">preview-close.png</file>
|
||||
<file alias="left-arrow-icon">preview-left-arrow.png</file>
|
||||
<file alias="right-arrow-icon">preview-right-arrow.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
Loading…
Reference in a new issue