diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bdd4811d..a1d8c1b87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,7 +207,7 @@ endif() include(QtVersionlessBackport) if(Launcher_QT_VERSION_MAJOR EQUAL 5) set(QT_VERSION_MAJOR 5) - find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml) + find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network QuickWidgets Test Xml) if(NOT Launcher_FORCE_BUNDLED_LIBS) find_package(QuaZip-Qt5 1.3 QUIET) @@ -221,7 +221,7 @@ if(Launcher_QT_VERSION_MAJOR EQUAL 5) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE") elseif(Launcher_QT_VERSION_MAJOR EQUAL 6) set(QT_VERSION_MAJOR 6) - find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat) + find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network QuickWidgets Test Xml Core5Compat) list(APPEND Launcher_QT_LIBS Qt6::Core5Compat) if(NOT Launcher_FORCE_BUNDLED_LIBS) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index cb4adabf4..fa0e2175d 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -611,6 +611,11 @@ SET(LAUNCHER_SOURCES icons/MMCIcon.cpp icons/IconList.h icons/IconList.cpp + icons/IconImageProvider.h + icons/IconImageProvider.cpp + + # GUI + ui/resources.qrc # GUI - windows ui/GuiUtil.h @@ -999,6 +1004,7 @@ target_link_libraries(Launcher_logic Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::QuickWidgets Qt${QT_VERSION_MAJOR}::Widgets ${Launcher_QT_LIBS} ) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 86b1610bf..838a5a8c0 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -137,6 +137,17 @@ int InstanceList::columnCount(const QModelIndex& parent) const return ColumnCount; } +QHash InstanceList::roleNames() const +{ + QHash roles; + roles[SortRole] = "sort"; + roles[IconRole] = "icon"; + roles[NameRole] = "name"; + roles[CategoryRole] = "category"; + roles[InstanceIDRole] = "instanceId"; + return roles; +} + QVariant InstanceList::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { @@ -251,11 +262,19 @@ QVariant InstanceList::data(const QModelIndex& index, int role) const break; } + case IconRole: { + return inst->iconKey(); + } + + case NameRole: { + return inst->name(); + } + case InstanceIDRole: { return inst->id(); } - case GroupRole: { + case CategoryRole: { return instanceGroup; } } @@ -337,7 +356,7 @@ void InstanceList::setInstanceGroup(const InstancePtr inst, const GroupId& name) if (changed) { m_groupNameCache.insert(name); auto idx = getInstIndex(inst.get()); - emit dataChanged(index(idx, NameColumn), index(idx, NameColumn), { GroupRole }); + emit dataChanged(index(idx, NameColumn), index(idx, NameColumn), { CategoryRole }); saveGroupList(); } } @@ -377,7 +396,7 @@ void InstanceList::deleteGroup(const QString& name) removed = true; auto idx = getInstIndex(instance.get()); if (idx > 0) { - emit dataChanged(index(idx, NameColumn), index(idx, NameColumn), { GroupRole }); + emit dataChanged(index(idx, NameColumn), index(idx, NameColumn), { CategoryRole }); } } } diff --git a/launcher/InstanceList.h b/launcher/InstanceList.h index efee64e41..7a2f6925e 100644 --- a/launcher/InstanceList.h +++ b/launcher/InstanceList.h @@ -67,7 +67,9 @@ class InstanceList : public QAbstractTableModel { ColumnCount }; - enum AdditionalRoles { SortRole = Qt::UserRole + 1, GroupRole, InstanceIDRole }; + enum AdditionalRoles { SortRole = Qt::UserRole + 1, IconRole, NameRole, CategoryRole, InstanceIDRole }; + + QHash roleNames() const override; InstancePtr at(int i) const { return m_instances.at(i); } diff --git a/launcher/icons/IconImageProvider.cpp b/launcher/icons/IconImageProvider.cpp new file mode 100644 index 000000000..85268d127 --- /dev/null +++ b/launcher/icons/IconImageProvider.cpp @@ -0,0 +1,14 @@ +#include "IconImageProvider.h" + +IconImageProvider::IconImageProvider(std::shared_ptr iconList, int iconSize) : QQuickImageProvider(QQuickImageProvider::Pixmap), m_iconList(iconList), m_iconSize(iconSize) +{ +} + +QPixmap IconImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +{ + if (size) + *size = QSize(m_iconSize, m_iconSize); + + QIcon i = m_iconList->getIcon(id); + return i.pixmap(requestedSize.width() > 0 ? requestedSize.width() : m_iconSize, requestedSize.height() > 0 ? requestedSize.height() : m_iconSize); +} diff --git a/launcher/icons/IconImageProvider.h b/launcher/icons/IconImageProvider.h new file mode 100644 index 000000000..b8393f33b --- /dev/null +++ b/launcher/icons/IconImageProvider.h @@ -0,0 +1,16 @@ +#pragma once +#include "IconList.h" + +#include + +class IconImageProvider : public QQuickImageProvider +{ +public: + IconImageProvider(std::shared_ptr iconList, int iconSize = 48); + + QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override; + +private: + std::shared_ptr m_iconList; + int m_iconSize; +}; diff --git a/launcher/main.cpp b/launcher/main.cpp index b63f8bfd0..4157036cd 100644 --- a/launcher/main.cpp +++ b/launcher/main.cpp @@ -76,6 +76,7 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(backgrounds); Q_INIT_RESOURCE(documents); Q_INIT_RESOURCE(prismlauncher); + Q_INIT_RESOURCE(resources); Q_INIT_RESOURCE(pe_dark); Q_INIT_RESOURCE(pe_light); diff --git a/launcher/ui/dialogs/IconPickerDialog.cpp b/launcher/ui/dialogs/IconPickerDialog.cpp index 2e021aaa7..3c5d5c21e 100644 --- a/launcher/ui/dialogs/IconPickerDialog.cpp +++ b/launcher/ui/dialogs/IconPickerDialog.cpp @@ -50,7 +50,7 @@ IconPickerDialog::IconPickerDialog(QWidget *parent, int iconSize) contentsWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); contentsWidget->setFrameStyle(QFrame::NoFrame); contentsWidget->setGridSize(QSize(m_iconSize * 2, m_iconSize * 2)); - contentsWidget->setItemDelegate(new InstanceDelegate(this, m_iconSize, true)); + contentsWidget->setItemDelegate(new InstanceDelegate(this, m_iconSize)); contentsWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // contentsWidget->setAcceptDrops(true); diff --git a/launcher/ui/instanceview/InstanceDelegate.cpp b/launcher/ui/instanceview/InstanceDelegate.cpp index ef81c5334..59a4db1fb 100644 --- a/launcher/ui/instanceview/InstanceDelegate.cpp +++ b/launcher/ui/instanceview/InstanceDelegate.cpp @@ -19,8 +19,8 @@ #include "InstanceDelegate.h" #include "InstanceList.h" -InstanceDelegate::InstanceDelegate(QObject* parent, int iconSize, bool isGrid) - : QStyledItemDelegate(parent), m_iconSize(iconSize), m_isGrid(isGrid) +InstanceDelegate::InstanceDelegate(QObject* parent, int iconSize) + : QStyledItemDelegate(parent), m_iconSize(iconSize) {} void InstanceDelegate::initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const @@ -28,9 +28,5 @@ void InstanceDelegate::initStyleOption(QStyleOptionViewItem* option, const QMode QStyledItemDelegate::initStyleOption(option, index); if (index.column() == InstanceList::NameColumn) { option->decorationSize = QSize(m_iconSize, m_iconSize); - if (m_isGrid) { - // FIXME: kinda hacky way to add vertical padding. This assumes that the icon is square in the first place - option->decorationSize.rheight() += 8; - } } } diff --git a/launcher/ui/instanceview/InstanceDelegate.h b/launcher/ui/instanceview/InstanceDelegate.h index 9539dabc0..b745335b4 100644 --- a/launcher/ui/instanceview/InstanceDelegate.h +++ b/launcher/ui/instanceview/InstanceDelegate.h @@ -24,11 +24,10 @@ class InstanceDelegate : public QStyledItemDelegate { Q_OBJECT public: - InstanceDelegate(QObject* parent = 0, int iconSize = 48, bool isGrid = false); + InstanceDelegate(QObject* parent = 0, int iconSize = 48); void initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const override; private: int m_iconSize; - bool m_isGrid; }; diff --git a/launcher/ui/instanceview/InstanceGridProxyModel.cpp b/launcher/ui/instanceview/InstanceGridProxyModel.cpp index cb9812e84..63455cbf0 100644 --- a/launcher/ui/instanceview/InstanceGridProxyModel.cpp +++ b/launcher/ui/instanceview/InstanceGridProxyModel.cpp @@ -24,3 +24,21 @@ // Placeholder model, as we might need this in the future InstanceGridProxyModel::InstanceGridProxyModel(QObject* parent) : InstanceTableProxyModel(parent) {} + +QVariant InstanceGridProxyModel::data(const QModelIndex& index, int role) const +{ + QVariant data = InstanceTableProxyModel::data(index, role); + QVariant displayData = data; + if (role != Qt::DisplayRole) + displayData = InstanceTableProxyModel::data(index, Qt::DisplayRole); + + switch (role) { + case InstanceList::IconRole: { + QString iconKey = data.toString(); + if (iconKey.isEmpty()) + break; + return "image://instance/" + iconKey; + } + } + return data; +} diff --git a/launcher/ui/instanceview/InstanceGridProxyModel.h b/launcher/ui/instanceview/InstanceGridProxyModel.h index 86b89ee1c..c2e0c31e7 100644 --- a/launcher/ui/instanceview/InstanceGridProxyModel.h +++ b/launcher/ui/instanceview/InstanceGridProxyModel.h @@ -25,4 +25,7 @@ class InstanceGridProxyModel : public InstanceTableProxyModel { public: InstanceGridProxyModel(QObject* parent = 0); + + protected: + QVariant data(const QModelIndex& index, int role) const override; }; diff --git a/launcher/ui/instanceview/InstancesGrid.qml b/launcher/ui/instanceview/InstancesGrid.qml new file mode 100644 index 000000000..af0e409b1 --- /dev/null +++ b/launcher/ui/instanceview/InstancesGrid.qml @@ -0,0 +1,49 @@ +import QtQuick 2.0 + +GridView { + id: grid + model: instances + anchors.fill: parent + cellWidth: iconSize*2 + cellHeight: iconSize*2 + + highlight: Rectangle { + width: grid.cellWidth; height: grid.cellHeight + color: "lightsteelblue"; radius: 5 + x: grid.currentItem.x + y: grid.currentItem.y + Behavior on x { SmoothedAnimation { duration: 150 } } + Behavior on y { SmoothedAnimation { duration: 150 } } + } + + interactive: true + focus: true + + delegate: Item { + required property int index + required property string name + required property string icon + width: iconSize*2 + height: iconSize*2 + + MouseArea { + anchors.fill: parent + onClicked: currentIndex = index; + } + + Image { + id: icon + width: iconSize + height: iconSize + anchors.top: parent.top + source: parent.icon + anchors.horizontalCenter: parent.horizontalCenter + } + + Text { + anchors.top: icon.bottom + text: parent.name + anchors.horizontalCenter: parent.horizontalCenter + } + } +} diff --git a/launcher/ui/instanceview/InstancesView.cpp b/launcher/ui/instanceview/InstancesView.cpp index 9b8c583cc..774086248 100644 --- a/launcher/ui/instanceview/InstancesView.cpp +++ b/launcher/ui/instanceview/InstancesView.cpp @@ -27,11 +27,14 @@ #include "InstanceDelegate.h" #include "InstanceList.h" +#include "icons/IconImageProvider.h" #include "ui/instanceview/InstanceGridProxyModel.h" #include "ui/instanceview/InstanceTableProxyModel.h" #include #include +#include +#include #include #include @@ -59,8 +62,8 @@ void InstancesView::switchDisplayMode(InstancesView::DisplayMode mode) QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); setCurrentWidget(m_table); } else { - m_grid->selectionModel()->setCurrentIndex(m_gridProxy->mapFromSource(sourceIndex), - QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + //m_grid->selectionModel()->setCurrentIndex(m_gridProxy->mapFromSource(sourceIndex), + // QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); setCurrentWidget(m_grid); } m_displayMode = mode; @@ -92,7 +95,7 @@ void InstancesView::createTable() m_table = new QTableView(this); m_table->installEventFilter(this); m_table->setModel(m_tableProxy); - m_table->setItemDelegate(new InstanceDelegate(this, m_iconSize, false)); + m_table->setItemDelegate(new InstanceDelegate(this, m_iconSize)); m_table->setTabKeyNavigation(false); m_table->setSelectionMode(QAbstractItemView::SingleSelection); @@ -138,27 +141,18 @@ void InstancesView::createTable() void InstancesView::createGrid() { - m_grid = new QListView(this); + m_grid = new QQuickWidget(this); + m_grid->rootContext()->setContextProperty("instances", m_gridProxy); + m_grid->rootContext()->setContextProperty("iconSize", m_iconSize); + m_grid->engine()->addImageProvider("instance", new IconImageProvider(APPLICATION->icons(), m_iconSize)); + m_grid->setResizeMode(QQuickWidget::SizeRootObjectToView); + m_grid->setSource(QUrl("qrc:/instanceview/InstancesGrid.qml")); m_grid->installEventFilter(this); - m_grid->setModel(m_gridProxy); - m_grid->setModelColumn(InstanceList::NameColumn); - m_grid->setItemDelegate(new InstanceDelegate(this, m_iconSize, true)); - - m_grid->setSelectionMode(QAbstractItemView::SingleSelection); - m_grid->setSelectionBehavior(QAbstractItemView::SelectRows); - m_grid->setEditTriggers(QAbstractItemView::EditKeyPressed); - m_grid->setCurrentIndex(QModelIndex()); m_grid->setContextMenuPolicy(Qt::CustomContextMenu); - m_grid->setWordWrap(true); - m_grid->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - m_grid->setViewMode(QListView::IconMode); - m_grid->setMovement(QListView::Static); - m_grid->setResizeMode(QListView::Adjust); - m_grid->setFrameStyle(QFrame::NoFrame); - m_grid->setGridSize(QSize(m_iconSize * 2, m_iconSize * 2)); + m_grid->show(); - connect(m_grid, &QAbstractItemView::doubleClicked, this, &InstancesView::activateInstance); - connect(m_grid->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &InstancesView::currentRowChanged); + //connect(m_grid, &QAbstractItemView::doubleClicked, this, &InstancesView::activateInstance); + //connect(m_grid->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &InstancesView::currentRowChanged); connect(m_grid, &QWidget::customContextMenuRequested, this, &InstancesView::contextMenuRequested); } diff --git a/launcher/ui/instanceview/InstancesView.h b/launcher/ui/instanceview/InstancesView.h index dfcc85945..b08cba886 100644 --- a/launcher/ui/instanceview/InstancesView.h +++ b/launcher/ui/instanceview/InstancesView.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "BaseInstance.h" #include "InstanceList.h" @@ -41,7 +42,7 @@ class InstancesView : public QStackedWidget { QAbstractItemView* currentView() { if (m_displayMode == GridMode) - return m_grid; + return nullptr; // TODO return m_table; } @@ -82,7 +83,7 @@ class InstancesView : public QStackedWidget { DisplayMode m_displayMode = TableMode; QTableView* m_table; - QListView* m_grid; + QQuickWidget* m_grid; InstanceTableProxyModel* m_tableProxy; InstanceGridProxyModel* m_gridProxy; InstanceList* m_instances; diff --git a/launcher/ui/resources.qrc b/launcher/ui/resources.qrc new file mode 100644 index 000000000..84f29189d --- /dev/null +++ b/launcher/ui/resources.qrc @@ -0,0 +1,5 @@ + + + instanceview/InstancesGrid.qml + +