|
From: <fli...@li...> - 2026-08-07 10:13:05
|
unknown user pushed a commit to branch next
in repository flightgear.
The following commit(s) were added to refs/heads/next by this push:
new 141fb82f9 Implement user sorting
141fb82f9 is described below
SF URL: http://sourceforge.net/p/flightgear/flightgear/ci/141fb82f9c00be28c06b854884e84095ca032dcb/
Commit: 141fb82f9c00be28c06b854884e84095ca032dcb
Author: James Turner
Committer: James Turner
AuthorDate: Fri Aug 7 11:12:55 2026 +0100
Implement user sorting
---
src/GUI/AircraftFavouritesModel.cxx | 14 +-----
src/GUI/AircraftFavouritesModel.hxx | 3 --
src/GUI/AircraftFilterModel.cxx | 70 +++++++++++-----------------
src/GUI/AircraftFilterModel.hxx | 11 +----
src/GUI/AircraftInstalledModel.cxx | 14 +-----
src/GUI/AircraftInstalledModel.hxx | 5 +-
src/GUI/AircraftItemModel.hxx | 1 +
src/GUI/AircraftRatingsProxyModel.cxx | 33 +++++++++++++
src/GUI/AircraftRatingsProxyModel.hxx | 24 ++++++++++
src/GUI/AircraftUpdatesModel.cxx | 12 -----
src/GUI/AircraftUpdatesModel.hxx | 3 --
src/GUI/CMakeLists.txt | 2 +
src/GUI/LauncherController.cxx | 39 ++++++++++++++--
src/GUI/LauncherController.hxx | 7 +++
src/GUI/QmlStringListModel.cxx | 22 +++++++++
src/GUI/QmlStringListModel.hxx | 8 ++++
src/GUI/assets/mask-star-filled.png | Bin 479 -> 0 bytes
src/GUI/assets/mask-star-outline.png | Bin 544 -> 0 bytes
src/GUI/assets/tabler-mask-star-filled.svg | 3 ++
src/GUI/assets/tabler-mask-star-outline.svg | 3 ++
src/GUI/qml/AircraftCompactDelegate.qml | 35 ++++++++++----
src/GUI/qml/AircraftGridView.qml | 7 ++-
src/GUI/qml/AircraftListView.qml | 3 +-
src/GUI/qml/AircraftRating.qml | 63 +++++++++++++++----------
src/GUI/qml/AircraftRatingsPanel.qml | 17 +++++++
src/GUI/resources.qrc | 6 ++-
26 files changed, 262 insertions(+), 143 deletions(-)
diff --git a/src/GUI/AircraftFavouritesModel.cxx b/src/GUI/AircraftFavouritesModel.cxx
index d9b0c56aa..539b23366 100644
--- a/src/GUI/AircraftFavouritesModel.cxx
+++ b/src/GUI/AircraftFavouritesModel.cxx
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2020 James Turner
+// SPDX-FileCopyrightText: 2026 James Turner
// SPDX-License-Identifier: GPL-2.0-or-later
#include "AircraftFavouritesModel.hxx"
@@ -18,18 +18,6 @@ AircraftFavouritesModel::AircraftFavouritesModel(QObject* pr, QAbstractItemModel
[this]() { this->invalidate(); });
}
-int AircraftFavouritesModel::indexForURI(QUrl uri) const
-{
- auto srcIdx = qobject_cast<AircraftItemModel*>(sourceModel())->indexOfAircraftURI(uri);
- auto ourIdx = mapFromSource(srcIdx);
- return ourIdx.isValid() ? ourIdx.row() : -1;
-}
-
-void AircraftFavouritesModel::selectVariantForAircraftURI(QUrl uri)
-{
- qobject_cast<AircraftItemModel*>(sourceModel())->selectVariantForAircraftURI(uri);
-}
-
int AircraftFavouritesModel::count() const
{
return rowCount();
diff --git a/src/GUI/AircraftFavouritesModel.hxx b/src/GUI/AircraftFavouritesModel.hxx
index 77a901bdb..a3e7ff000 100644
--- a/src/GUI/AircraftFavouritesModel.hxx
+++ b/src/GUI/AircraftFavouritesModel.hxx
@@ -20,9 +20,6 @@ public:
Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_INVOKABLE int indexForURI(QUrl uri) const;
- Q_INVOKABLE void selectVariantForAircraftURI(QUrl uri);
-
int count() const;
signals:
diff --git a/src/GUI/AircraftFilterModel.cxx b/src/GUI/AircraftFilterModel.cxx
index 7b4bfc953..d6b7f471e 100644
--- a/src/GUI/AircraftFilterModel.cxx
+++ b/src/GUI/AircraftFilterModel.cxx
@@ -25,15 +25,23 @@ AircraftFilterModel::AircraftFilterModel(QObject* pr, QAbstractItemModel* source
AircraftItemModel* AircraftFilterModel::resolveItemModel() const
{
- auto* itemModel = qobject_cast<AircraftItemModel*>(sourceModel());
- if (!itemModel) {
- // Source is a proxy (e.g. AircraftSearchModel); look one level deeper.
- auto* proxySource = qobject_cast<QAbstractProxyModel*>(sourceModel());
- Q_ASSERT(proxySource);
- itemModel = qobject_cast<AircraftItemModel*>(proxySource->sourceModel());
+ auto m = sourceModel();
+ while (m) {
+ auto* itemModel = qobject_cast<AircraftItemModel*>(m);
+ if (itemModel) {
+ return itemModel;
+ }
+
+ auto pm = qobject_cast<QAbstractProxyModel*>(m);
+ if (!pm) {
+ break;
+ }
+
+ m = pm->sourceModel();
}
- Q_ASSERT(itemModel);
- return itemModel;
+
+ qFatal("AircraftFilterModel::resolveItemModel() failed to find AircraftItemModel in the source model chain");
+ return nullptr;
}
void AircraftFilterModel::setRatings(QList<int> ratings)
@@ -46,36 +54,6 @@ void AircraftFilterModel::setRatings(QList<int> ratings)
emit summaryTextChanged();
}
-int AircraftFilterModel::indexForURI(QUrl uri) const
-{
- auto* itemModel = qobject_cast<AircraftItemModel*>(sourceModel());
- QModelIndex sourceIdx;
-
- if (itemModel) {
- // Direct chain: AircraftItemModel → AircraftFilterModel
- sourceIdx = mapFromSource(itemModel->indexOfAircraftURI(uri));
- } else {
- // Indirect chain through a proxy (e.g. AircraftSearchModel)
- auto* proxySource = qobject_cast<QAbstractProxyModel*>(sourceModel());
- Q_ASSERT(proxySource);
- itemModel = qobject_cast<AircraftItemModel*>(proxySource->sourceModel());
- Q_ASSERT(itemModel);
- auto proxyIdx = proxySource->mapFromSource(itemModel->indexOfAircraftURI(uri));
- sourceIdx = mapFromSource(proxyIdx);
- }
-
- if (!sourceIdx.isValid()) {
- return -1;
- }
-
- return sourceIdx.row();
-}
-
-void AircraftFilterModel::selectVariantForAircraftURI(QUrl uri)
-{
- resolveItemModel()->selectVariantForAircraftURI(uri);
-}
-
void AircraftFilterModel::setRatingFilterEnabled(bool e)
{
if (e == m_ratingsFilter) {
@@ -179,7 +157,6 @@ void AircraftFilterModel::saveCompatibilityAndRatingsSettings()
vRatings.append(m_ratings.at(i));
}
settings.setValue("ratings-filter", vRatings);
- qInfo() << "Did save ratings";
}
int AircraftFilterModel::filteredOutCount() const
@@ -205,23 +182,32 @@ void AircraftFilterModel::setSorting(Sorting s)
void AircraftFilterModel::updateSorting()
{
+ auto order = Qt::AscendingOrder;
switch (m_sorting) {
case Sorting::SortByName:
setSortRole(AircraftVariantDescriptionRole);
setSortCaseSensitivity(Qt::CaseInsensitive);
+
break;
case Sorting::SortByRating:
- setSortRole(AircraftRatingRole);
- setSortCaseSensitivity(Qt::CaseSensitive); // doesn't matter, it's an int
+ setSortRole(AircraftCombinedRatingRole);
+ // highest-rated at the top
+ order = Qt::DescendingOrder;
break;
}
setDynamicSortFilter(true);
- sort(0);
+ sort(0, order);
}
bool AircraftFilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
{
+ if (m_sorting == Sorting::SortByRating) {
+ // use default impl
+ return QSortFilterProxyModel::lessThan(left, right);
+ }
+
+ // custom imply for SortByName
const QString variantLeft = left.data(AircraftVariantDescriptionRole).toString();
const QString variantRight = right.data(AircraftVariantDescriptionRole).toString();
diff --git a/src/GUI/AircraftFilterModel.hxx b/src/GUI/AircraftFilterModel.hxx
index 409e1a46b..b7133bb91 100644
--- a/src/GUI/AircraftFilterModel.hxx
+++ b/src/GUI/AircraftFilterModel.hxx
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2020 James Turner
+// SPDX-FileCopyrightText: 2026 James Turner
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -44,15 +44,6 @@ public:
Q_PROPERTY(Sorting sorting READ sorting WRITE setSorting NOTIFY sortingChanged)
- /**
- * Compute the row (index in QML / ListView speak) based on an aircraft URI.
- * Returns -1 if the URI is not present in the (filtered) model.
- * Handles both direct AircraftItemModel sources and proxy-chained sources.
- */
- Q_INVOKABLE int indexForURI(QUrl uri) const;
-
- Q_INVOKABLE void selectVariantForAircraftURI(QUrl uri);
-
Q_INVOKABLE void loadCompatibilityAndRatingsSettings();
Q_INVOKABLE void saveCompatibilityAndRatingsSettings();
diff --git a/src/GUI/AircraftInstalledModel.cxx b/src/GUI/AircraftInstalledModel.cxx
index 900ea2852..ada96c639 100644
--- a/src/GUI/AircraftInstalledModel.cxx
+++ b/src/GUI/AircraftInstalledModel.cxx
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2020 James Turner
+// SPDX-FileCopyrightText: 2026 James Turner
// SPDX-License-Identifier: GPL-2.0-or-later
#include "AircraftInstalledModel.hxx"
@@ -14,18 +14,6 @@ AircraftInstalledModel::AircraftInstalledModel(QObject* pr, QAbstractItemModel*
connect(this, &QAbstractItemModel::modelReset, this, &AircraftInstalledModel::countChanged);
}
-int AircraftInstalledModel::indexForURI(QUrl uri) const
-{
- auto srcIdx = qobject_cast<AircraftItemModel*>(sourceModel())->indexOfAircraftURI(uri);
- auto ourIdx = mapFromSource(srcIdx);
- return ourIdx.isValid() ? ourIdx.row() : -1;
-}
-
-void AircraftInstalledModel::selectVariantForAircraftURI(QUrl uri)
-{
- qobject_cast<AircraftItemModel*>(sourceModel())->selectVariantForAircraftURI(uri);
-}
-
int AircraftInstalledModel::count() const
{
return rowCount();
diff --git a/src/GUI/AircraftInstalledModel.hxx b/src/GUI/AircraftInstalledModel.hxx
index 2d1219478..4da0f7b11 100644
--- a/src/GUI/AircraftInstalledModel.hxx
+++ b/src/GUI/AircraftInstalledModel.hxx
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2020 James Turner
+// SPDX-FileCopyrightText: 2026 James Turner
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -19,9 +19,6 @@ public:
Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_INVOKABLE int indexForURI(QUrl uri) const;
- Q_INVOKABLE void selectVariantForAircraftURI(QUrl uri);
-
int count() const;
signals:
diff --git a/src/GUI/AircraftItemModel.hxx b/src/GUI/AircraftItemModel.hxx
index 44006dc93..5810dcd71 100644
--- a/src/GUI/AircraftItemModel.hxx
+++ b/src/GUI/AircraftItemModel.hxx
@@ -40,6 +40,7 @@ const int AircraftStatusRole = Qt::UserRole + 22;
const int AircraftCompatibleRole = Qt::UserRole + 23;
const int AircraftRatingRole = Qt::UserRole + 100;
+const int AircraftCombinedRatingRole = Qt::UserRole + 150;
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
class PackageDelegate;
diff --git a/src/GUI/AircraftRatingsProxyModel.cxx b/src/GUI/AircraftRatingsProxyModel.cxx
new file mode 100644
index 000000000..dc17c40f5
--- /dev/null
+++ b/src/GUI/AircraftRatingsProxyModel.cxx
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "AircraftRatingsProxyModel.hxx"
+
+#include "AircraftItemModel.hxx"
+
+AircraftRatingsProxyModel::AircraftRatingsProxyModel(QObject* parent)
+ : QSortFilterProxyModel(parent)
+{
+}
+
+QVariant AircraftRatingsProxyModel::data(const QModelIndex& index, int role) const
+{
+ if (role == AircraftCombinedRatingRole) {
+ QModelIndex srcIndex = mapToSource(index);
+ double sum = 0;
+ for (int i = 0; i < 4; ++i) {
+ QVariant v = sourceModel()->data(srcIndex, AircraftRatingRole + i);
+ sum += v.toDouble();
+ }
+ return sum / 4.0;
+ }
+
+ return QSortFilterProxyModel::data(index, role);
+}
+
+QHash<int, QByteArray> AircraftRatingsProxyModel::roleNames() const
+{
+ QHash<int, QByteArray> roles = QSortFilterProxyModel::roleNames();
+ roles[AircraftCombinedRatingRole] = "combinedRating";
+ return roles;
+}
diff --git a/src/GUI/AircraftRatingsProxyModel.hxx b/src/GUI/AircraftRatingsProxyModel.hxx
new file mode 100644
index 000000000..12b70157b
--- /dev/null
+++ b/src/GUI/AircraftRatingsProxyModel.hxx
@@ -0,0 +1,24 @@
+// SPDX-FileCopyrightText: 2026 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <QSortFilterProxyModel>
+
+/**
+ * Proxy model that adds a combined/average rating to each aircraft row.
+ *
+ * The combined rating is computed from the four existing ratings
+ * (AircraftRatingRole .. AircraftRatingRole+3) and exposed via
+ * AircraftCombinedRatingRole.
+ */
+class AircraftRatingsProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ explicit AircraftRatingsProxyModel(QObject* parent = nullptr);
+
+ QVariant data(const QModelIndex& index, int role) const override;
+
+ QHash<int, QByteArray> roleNames() const override;
+};
diff --git a/src/GUI/AircraftUpdatesModel.cxx b/src/GUI/AircraftUpdatesModel.cxx
index ba57f2d2f..69cfae236 100644
--- a/src/GUI/AircraftUpdatesModel.cxx
+++ b/src/GUI/AircraftUpdatesModel.cxx
@@ -14,18 +14,6 @@ AircraftUpdatesModel::AircraftUpdatesModel(QObject* pr, QAbstractItemModel* sour
connect(this, &QAbstractItemModel::modelReset, this, &AircraftUpdatesModel::countChanged);
}
-int AircraftUpdatesModel::indexForURI(QUrl uri) const
-{
- auto srcIdx = qobject_cast<AircraftItemModel*>(sourceModel())->indexOfAircraftURI(uri);
- auto ourIdx = mapFromSource(srcIdx);
- return ourIdx.isValid() ? ourIdx.row() : -1;
-}
-
-void AircraftUpdatesModel::selectVariantForAircraftURI(QUrl uri)
-{
- qobject_cast<AircraftItemModel*>(sourceModel())->selectVariantForAircraftURI(uri);
-}
-
int AircraftUpdatesModel::count() const
{
return rowCount();
diff --git a/src/GUI/AircraftUpdatesModel.hxx b/src/GUI/AircraftUpdatesModel.hxx
index 34bef136d..fc7644608 100644
--- a/src/GUI/AircraftUpdatesModel.hxx
+++ b/src/GUI/AircraftUpdatesModel.hxx
@@ -19,9 +19,6 @@ public:
Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_INVOKABLE int indexForURI(QUrl uri) const;
- Q_INVOKABLE void selectVariantForAircraftURI(QUrl uri);
-
int count() const;
signals:
diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt
index a1c752f88..cf9021b4a 100644
--- a/src/GUI/CMakeLists.txt
+++ b/src/GUI/CMakeLists.txt
@@ -120,6 +120,8 @@ if (HAVE_QT)
AircraftFavouritesModel.hxx
AircraftFilterModel.cxx
AircraftFilterModel.hxx
+ AircraftRatingsProxyModel.cxx
+ AircraftRatingsProxyModel.hxx
AircraftInstalledModel.cxx
AircraftInstalledModel.hxx
AircraftSearchModel.cxx
diff --git a/src/GUI/LauncherController.cxx b/src/GUI/LauncherController.cxx
index 54cf1ff18..3a9d51598 100644
--- a/src/GUI/LauncherController.cxx
+++ b/src/GUI/LauncherController.cxx
@@ -41,8 +41,10 @@
#include "AircraftFavouritesModel.hxx"
#include "AircraftFilterModel.hxx"
#include "AircraftItemModel.hxx"
+#include "AircraftRatingsProxyModel.hxx"
#include "AircraftSearchModel.hxx"
#include "AircraftUpdatesModel.hxx"
+
#include "AirportDiagram.hxx"
#include "CarrierDiagram.hxx"
#include "CarriersLocationModel.hxx"
@@ -110,14 +112,16 @@ LauncherController::LauncherController(QObject *parent, QWindow* window) :
this, &LauncherController::summaryChanged);
m_aircraftModel = new AircraftItemModel(this);
+ auto ratingsProxy = new AircraftRatingsProxyModel(this);
+ ratingsProxy->setSourceModel(m_aircraftModel);
- m_aircraftInstalledModel = new AircraftInstalledModel(this, m_aircraftModel);
- m_aircraftWithUpdatesModel = new AircraftUpdatesModel(this, m_aircraftModel);
- m_favouriteAircraftModel = new AircraftFavouritesModel(this, m_aircraftModel);
+ m_aircraftInstalledModel = new AircraftInstalledModel(this, ratingsProxy);
+ m_aircraftWithUpdatesModel = new AircraftUpdatesModel(this, ratingsProxy);
+ m_favouriteAircraftModel = new AircraftFavouritesModel(this, ratingsProxy);
// m_aircraftSearchModel sits between the base model and the filter model,
// allowing text-based searching and rating/compat filtering to be separated.
- m_aircraftSearchModel = new AircraftSearchModel(this, m_aircraftModel);
+ m_aircraftSearchModel = new AircraftSearchModel(this, ratingsProxy);
// Single filter model; its source is swapped by setSelectedModel().
// Initial state is "installed" (the default QML tab).
@@ -1094,3 +1098,30 @@ void LauncherController::onReachabilityChanged()
emit networkAvailableChanged();
#endif
}
+
+int LauncherController::selectedAircraftIndex(QAbstractItemModel* model)
+{
+ if (!m_selectedAircraftInfo) {
+ return -1;
+ }
+
+ // hit the base case, stop descending
+ AircraftItemModel* itemModel = qobject_cast<AircraftItemModel*>(model);
+ if (itemModel) {
+ QModelIndex idx = itemModel->indexOfAircraftURI(m_selectedAircraft);
+ if (idx.isValid()) {
+ itemModel->selectVariantForAircraftURI(m_selectedAircraft);
+ return idx.row();
+ }
+
+ return -1;
+ }
+
+ auto* proxy = qobject_cast<QAbstractProxyModel*>(model);
+ if (!proxy) {
+ return -1; // should never happen
+ }
+
+ // recurse into the proxy
+ return selectedAircraftIndex(proxy->sourceModel());
+}
diff --git a/src/GUI/LauncherController.hxx b/src/GUI/LauncherController.hxx
index 03089fbc2..6ef007ae0 100644
--- a/src/GUI/LauncherController.hxx
+++ b/src/GUI/LauncherController.hxx
@@ -120,6 +120,13 @@ public:
Q_INVOKABLE bool matchesSearch(QString term, QStringList keywords) const;
+ /**
+ * given a (proxy) model, find the row which corresponds to selectedAircraft.
+ *
+ * Also sets the active variant of the underlying model
+ */
+ Q_INVOKABLE int selectedAircraftIndex(QAbstractItemModel* model);
+
bool isSearchActive() const;
QString settingsSearchTerm() const
diff --git a/src/GUI/QmlStringListModel.cxx b/src/GUI/QmlStringListModel.cxx
index 4f5aca6f4..61d81b057 100644
--- a/src/GUI/QmlStringListModel.cxx
+++ b/src/GUI/QmlStringListModel.cxx
@@ -20,6 +20,7 @@ void QmlStringListModel::setValues(QStringList v)
beginResetModel();
m_values = v;
endResetModel();
+ emit valuesChanged();
}
QStringList QmlStringListModel::values() const
@@ -27,6 +28,19 @@ QStringList QmlStringListModel::values() const
return m_values;
}
+void QmlStringListModel::setKeys(QVariantList v)
+{
+ beginResetModel();
+ m_keys = v;
+ endResetModel();
+ emit keysChanged();
+}
+
+QVariantList QmlStringListModel::keys() const
+{
+ return m_keys;
+}
+
int QmlStringListModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
@@ -53,10 +67,18 @@ void QmlStringListModel::clear()
{
beginResetModel();
m_values.clear();
+ m_keys.clear();
endResetModel();
+ emit valuesChanged();
+ emit keysChanged();
}
bool QmlStringListModel::empty() const
{
return m_values.isEmpty();
}
+
+int QmlStringListModel::indexOfKey(const QVariant& key) const
+{
+ return m_keys.indexOf(key);
+}
diff --git a/src/GUI/QmlStringListModel.hxx b/src/GUI/QmlStringListModel.hxx
index f39f6256b..ffb4205d7 100644
--- a/src/GUI/QmlStringListModel.hxx
+++ b/src/GUI/QmlStringListModel.hxx
@@ -14,6 +14,8 @@ class QmlStringListModel : public QAbstractListModel
Q_OBJECT
Q_PROPERTY(QStringList values READ values WRITE setValues NOTIFY valuesChanged)
+ Q_PROPERTY(QVariantList keys READ keys WRITE setKeys NOTIFY keysChanged)
+
Q_PROPERTY(bool empty READ empty NOTIFY valuesChanged)
public:
QmlStringListModel(QObject* parent = nullptr);
@@ -22,6 +24,8 @@ public:
void setValues(QStringList v);
QStringList values() const;
+ void setKeys(QVariantList v);
+ QVariantList keys() const;
int rowCount(const QModelIndex& parent) const override;
@@ -32,9 +36,13 @@ public:
void clear();
bool empty() const;
+
+ Q_INVOKABLE int indexOfKey(const QVariant& key) const;
signals:
void valuesChanged();
+ void keysChanged();
private:
QStringList m_values;
+ QVariantList m_keys;
};
diff --git a/src/GUI/assets/mask-star-filled.png b/src/GUI/assets/mask-star-filled.png
deleted file mode 100644
index 1ee4f8e53..000000000
Binary files a/src/GUI/assets/mask-star-filled.png and /dev/null differ
diff --git a/src/GUI/assets/mask-star-outline.png b/src/GUI/assets/mask-star-outline.png
deleted file mode 100644
index 6c9846e1d..000000000
Binary files a/src/GUI/assets/mask-star-outline.png and /dev/null differ
diff --git a/src/GUI/assets/tabler-mask-star-filled.svg b/src/GUI/assets/tabler-mask-star-filled.svg
new file mode 100644
index 000000000..937eceb30
--- /dev/null
+++ b/src/GUI/assets/tabler-mask-star-filled.svg
@@ -0,0 +1,3 @@
+<!-- SPDX-FileCopyrightText: Tabler Icons Contributors -->
+<!-- SPDX-License-Identifier: MIT -->
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="#ffffff" class="icon icon-tabler icons-tabler-filled icon-tabler-star"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M8.243 7.34l-6.38 .925l-.113 .023a1 1 0 0 0 -.44 1.684l4.622 4.499l-1.09 6.355l-.013 .11a1 1 0 0 0 1.464 .944l5.706 -3l5.693 3l.1 .046a1 1 0 0 0 1.352 -1.1l-1.091 -6.355l4.624 -4.5l.078 -.085a1 1 0 0 0 -.633 -1.62l-6.38 -.926l-2.852 -5.78a1 1 0 0 0 -1.794 0l-2.853 5.78z" [...]
diff --git a/src/GUI/assets/tabler-mask-star-outline.svg b/src/GUI/assets/tabler-mask-star-outline.svg
new file mode 100644
index 000000000..32f98ca1b
--- /dev/null
+++ b/src/GUI/assets/tabler-mask-star-outline.svg
@@ -0,0 +1,3 @@
+<!-- SPDX-FileCopyrightText: Tabler Icons Contributors -->
+<!-- SPDX-License-Identifier: MIT -->
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-star"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873l-6.158 -3.245" /></svg>
diff --git a/src/GUI/qml/AircraftCompactDelegate.qml b/src/GUI/qml/AircraftCompactDelegate.qml
index fb3c62713..3937d3c7a 100644
--- a/src/GUI/qml/AircraftCompactDelegate.qml
+++ b/src/GUI/qml/AircraftCompactDelegate.qml
@@ -147,16 +147,33 @@ Item {
visible: (model.description !== "") || root.__showAlternateText
}
- AircraftDownloadPanel
- {
- id: downloadPanel
- visible: (model.package !== undefined)
- packageSize: model.packageSizeBytes
- installStatus: model.packageStatus
- downloadedBytes: model.downloadedBytes
- uri: model.uri
+ Row {
width: parent.width
- compact: true
+ height: Math.max(combinedRating.height, downloadPanel.height)
+ spacing: Style.margin
+
+ AircraftRating
+ {
+ id: combinedRating
+ showValue: true
+ title: qsTr("Rating")
+ anchors.verticalCenter: parent.verticalCenter
+ value: model.combinedRating
+ }
+
+ AircraftDownloadPanel
+ {
+ id: downloadPanel
+ visible: (model.package !== undefined)
+ packageSize: model.packageSizeBytes
+ installStatus: model.packageStatus
+ downloadedBytes: model.downloadedBytes
+ uri: model.uri
+ compact: true
+
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width - (combinedRating.width + Style.margin)
+ }
}
} // of content column
diff --git a/src/GUI/qml/AircraftGridView.qml b/src/GUI/qml/AircraftGridView.qml
index 7676e4a2d..cd293912f 100644
--- a/src/GUI/qml/AircraftGridView.qml
+++ b/src/GUI/qml/AircraftGridView.qml
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2018 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
import QtQuick 2.0
import QtQuick.Controls 2.2
@@ -17,7 +20,7 @@ Item {
if (!model)
return;
- var row = model.indexForURI(_launcher.selectedAircraft);
+ var row = _launcher.findSelectedAircraftIndex(model)
if (row >= 0) {
view.currentIndex = row;
} else {
@@ -44,7 +47,7 @@ Item {
cellWidth: width / colCount
cellHeight: 128 + Style.strutSize
highlightMoveDuration: 0
-
+
ScrollBar.vertical: ScrollBar {}
readonly property int baseCellWidth: 172 + (Style.strutSize * 2)
diff --git a/src/GUI/qml/AircraftListView.qml b/src/GUI/qml/AircraftListView.qml
index ea7538b6e..20edd24db 100644
--- a/src/GUI/qml/AircraftListView.qml
+++ b/src/GUI/qml/AircraftListView.qml
@@ -20,8 +20,7 @@ Item {
if (!model)
return;
- model.selectVariantForAircraftURI(_launcher.selectedAircraft);
- var row = model.indexForURI(_launcher.selectedAircraft);
+ var row = _launcher.selectedAircraftIndex(model)
if (row >= 0) {
// sequence here is necessary so programmatic moves
// are instant
diff --git a/src/GUI/qml/AircraftRating.qml b/src/GUI/qml/AircraftRating.qml
index 24fb81c9f..4671e4e2b 100644
--- a/src/GUI/qml/AircraftRating.qml
+++ b/src/GUI/qml/AircraftRating.qml
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2018 James Turner
+// SPDX-License-Identifier: GPL-2.0-or-later
+
import QtQuick 2.4
import FlightGear 1.0
@@ -5,38 +8,50 @@ Item {
id: root
property string title: ""
- property int value: 3
-
- implicitWidth: label.implicitWidth + ratingRow.implicitWidth + Style.margin
- implicitHeight: label.height
+ property double value: 3
- StyledText {
- id: label
- anchors.right: ratingRow.left
- anchors.rightMargin: Style.margin
- anchors.left: parent.left
+ property alias showValue: ratingValue.visible
- horizontalAlignment: Text.AlignRight
- text: root.title + ":"
- }
+ implicitWidth: childrenRect.width
+ implicitHeight: Math.max(label.height, 24)
Row {
- id: ratingRow
+ id: contentRow
+ spacing: Style.margin
+
+ StyledText {
+ id: label
+ anchors.verticalCenter: parent.verticalCenter
+
+ horizontalAlignment: Text.AlignRight
+ text: root.title + ":"
+ }
+
+ Row {
+ id: ratingRow
- spacing: 2
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
+ spacing: 0 // keep this really tight
+ anchors.verticalCenter: parent.verticalCenter
- Repeater {
- model: 5
+ Repeater {
+ model: 5
- delegate: Rectangle {
- color: ((model.index + 1) <= root.value) ? Style.themeColor : Style.disabledTextColor
- width: radius * 2
- height: radius * 2
- radius: Style.roundRadius
+ delegate: Image {
+ source: {
+ var b = (model.index + 1) <= root.value;
+ return b ? "image://colored-icon/star-filled?theme" : "image://colored-icon/star-outline?text";
+ }
+ }
}
}
- }
+ StyledText {
+ id: ratingValue
+ visible: false // hidden by default
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignLeft
+ text: "(" + Number(root.value).toLocaleString(null, 'f', 2) + ")"
+ width: Style.strutSize
+ }
+ }
}
diff --git a/src/GUI/qml/AircraftRatingsPanel.qml b/src/GUI/qml/AircraftRatingsPanel.qml
index a50004d74..1850f7774 100644
--- a/src/GUI/qml/AircraftRatingsPanel.qml
+++ b/src/GUI/qml/AircraftRatingsPanel.qml
@@ -35,6 +35,23 @@ Rectangle
anchors.horizontalCenter: parent.horizontalCenter
}
+ PopupChoice {
+ id: sortChoice
+ model: StringListModel{
+ values: [qsTr("By name"), qsTr("By rating")]
+ keys: [FG.AircraftFilterModel.SortByName, FG.AircraftFilterModel.SortByRating]
+ }
+
+ currentIndex: model.indexOfKey(_launcher.currentAircraftModel.sorting)
+ onCurrentIndexChanged: {
+ _launcher.currentAircraftModel.sorting = model.keys[currentIndex]
+ }
+
+ label: qsTr("Sort aircraft by: ")
+ width: parent.width - Style.inset
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
ToggleSwitch {
id: doCompatibilityCheck
checked: _launcher.currentAircraftModel.compatibilityFilterEnabled
diff --git a/src/GUI/resources.qrc b/src/GUI/resources.qrc
index c6b00e31f..af42ac147 100644
--- a/src/GUI/resources.qrc
+++ b/src/GUI/resources.qrc
@@ -151,8 +151,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="hide">assets/mask-hide.png</file>
<file alias="preview">assets/mask-preview.png</file>
<file alias="up-down">assets/mask-up-down.png</file>
- <file alias="star-filled">assets/mask-star-filled.png</file>
- <file alias="star-outline">assets/mask-star-outline.png</file>
+
<file alias="back">assets/mask-back.png</file>
<file alias="cancel-small">assets/mask-cancel-small.png</file>
<file alias="reorder-list">assets/mask-reorder-list.png</file>
@@ -180,5 +179,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="heart-filled">assets/tabler-mask-heart-filled.svg</file>
<file alias="heart-outline">assets/tabler-mask-heart-outline.svg</file>
<file alias="heart-plus">assets/tabler-mask-heart-plus.svg</file>
+
+ <file alias="star-filled">assets/tabler-mask-star-filled.svg</file>
+ <file alias="star-outline">assets/tabler-mask-star-outline.svg</file>
</qresource>
</RCC>
|