Browse Source
[cmake, desktop] feat: show dependencies and versions
[cmake, desktop] feat: show dependencies and versions
Signed-off-by: crueter <crueter@eden-emu.dev>pull/238/head
15 changed files with 433 additions and 9 deletions
-
27CMakeLists.txt
-
17CMakeModules/CPMUtil.cmake
-
21CMakeModules/GenerateDepHashes.cmake
-
2externals/CMakeLists.txt
-
2src/CMakeLists.txt
-
3src/common/CMakeLists.txt
-
20src/dep_hashes.h.in
-
4src/yuzu/CMakeLists.txt
-
2src/yuzu/aboutdialog.ui
-
121src/yuzu/deps_dialog.cpp
-
41src/yuzu/deps_dialog.h
-
166src/yuzu/deps_dialog.ui
-
9src/yuzu/main.cpp
-
1src/yuzu/main.h
-
6src/yuzu/main.ui
@ -0,0 +1,21 @@ |
|||||
|
# SPDX-FileCopyrightText: 2025 Eden Emulator Project |
||||
|
# SPDX-License-Identifier: GPL-3.0-or-later |
||||
|
|
||||
|
get_property(NAMES GLOBAL PROPERTY CPM_PACKAGE_NAMES) |
||||
|
get_property(SHAS GLOBAL PROPERTY CPM_PACKAGE_SHAS) |
||||
|
get_property(URLS GLOBAL PROPERTY CPM_PACKAGE_URLS) |
||||
|
|
||||
|
list(LENGTH NAMES DEPS_LENGTH) |
||||
|
|
||||
|
list(JOIN NAMES "\",\n\t\"" DEP_NAME_DIRTY) |
||||
|
set(DEP_NAMES "\t\"${DEP_NAME_DIRTY}\"") |
||||
|
|
||||
|
list(JOIN SHAS "\",\n\t\"" DEP_SHAS_DIRTY) |
||||
|
set(DEP_SHAS "\t\"${DEP_SHAS_DIRTY}\"") |
||||
|
|
||||
|
list(JOIN URLS "\",\n\t\"" DEP_URLS_DIRTY) |
||||
|
set(DEP_URLS "\t\"${DEP_URLS_DIRTY}\"") |
||||
|
|
||||
|
configure_file(dep_hashes.h.in dep_hashes.h @ONLY) |
||||
|
target_sources(common PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/dep_hashes.h) |
||||
|
target_include_directories(common PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) |
||||
@ -0,0 +1,20 @@ |
|||||
|
// SPDX-FileCopyrightText: 2025 Eden Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-3.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
namespace Common { |
||||
|
|
||||
|
static const constexpr std::array<const char *, @DEPS_LENGTH@> dep_names = { |
||||
|
@DEP_NAMES@ |
||||
|
}; |
||||
|
|
||||
|
static const constexpr std::array<const char *, @DEPS_LENGTH@> dep_hashes = { |
||||
|
@DEP_SHAS@ |
||||
|
}; |
||||
|
|
||||
|
static const constexpr std::array<const char *, @DEPS_LENGTH@> dep_urls = { |
||||
|
@DEP_URLS@ |
||||
|
}; |
||||
|
|
||||
|
} // namespace Common |
||||
@ -0,0 +1,121 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
|
||||
|
#include "yuzu/deps_dialog.h"
|
||||
|
#include <QAbstractTextDocumentLayout>
|
||||
|
#include <QDesktopServices>
|
||||
|
#include <QIcon>
|
||||
|
#include <QPainter>
|
||||
|
#include <QTableWidget>
|
||||
|
#include <QTextEdit>
|
||||
|
#include "dep_hashes.h"
|
||||
|
#include "ui_deps_dialog.h"
|
||||
|
#include <fmt/ranges.h>
|
||||
|
|
||||
|
DepsDialog::DepsDialog(QWidget* parent) |
||||
|
: QDialog(parent) |
||||
|
, ui{std::make_unique<Ui::DepsDialog>()} |
||||
|
{ |
||||
|
ui->setupUi(this); |
||||
|
|
||||
|
constexpr size_t rows = Common::dep_hashes.size(); |
||||
|
ui->tableDeps->setRowCount(rows); |
||||
|
|
||||
|
QStringList labels; |
||||
|
labels << tr("Dependency") << tr("Version"); |
||||
|
|
||||
|
ui->tableDeps->setHorizontalHeaderLabels(labels); |
||||
|
ui->tableDeps->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch); |
||||
|
ui->tableDeps->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeMode::Fixed); |
||||
|
ui->tableDeps->horizontalHeader()->setMinimumSectionSize(200); |
||||
|
|
||||
|
for (size_t i = 0; i < rows; ++i) { |
||||
|
const std::string name = Common::dep_names.at(i); |
||||
|
const std::string sha = Common::dep_hashes.at(i); |
||||
|
const std::string url = Common::dep_urls.at(i); |
||||
|
|
||||
|
std::string dependency = fmt::format("<a href=\"{}\">{}</a>", url, name); |
||||
|
|
||||
|
QTableWidgetItem *nameItem = new QTableWidgetItem(QString::fromStdString(dependency)); |
||||
|
QTableWidgetItem *shaItem = new QTableWidgetItem(QString::fromStdString(sha)); |
||||
|
|
||||
|
ui->tableDeps->setItem(i, 0, nameItem); |
||||
|
ui->tableDeps->setItem(i, 1, shaItem); |
||||
|
} |
||||
|
|
||||
|
ui->tableDeps->setItemDelegateForColumn(0, new LinkItemDelegate(this)); |
||||
|
} |
||||
|
|
||||
|
DepsDialog::~DepsDialog() = default; |
||||
|
|
||||
|
LinkItemDelegate::LinkItemDelegate(QObject *parent) |
||||
|
: QStyledItemDelegate(parent) |
||||
|
{} |
||||
|
|
||||
|
void LinkItemDelegate::paint(QPainter *painter, |
||||
|
const QStyleOptionViewItem &option, |
||||
|
const QModelIndex &index) const |
||||
|
{ |
||||
|
auto options = option; |
||||
|
initStyleOption(&options, index); |
||||
|
|
||||
|
QTextDocument doc; |
||||
|
QString html = index.data(Qt::DisplayRole).toString(); |
||||
|
doc.setHtml(html); |
||||
|
|
||||
|
options.text.clear(); |
||||
|
|
||||
|
painter->save(); |
||||
|
painter->translate(options.rect.topLeft()); |
||||
|
doc.drawContents(painter, QRectF(0, 0, options.rect.width(), options.rect.height())); |
||||
|
painter->restore(); |
||||
|
} |
||||
|
|
||||
|
QSize LinkItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const |
||||
|
{ |
||||
|
QStyleOptionViewItem options = option; |
||||
|
initStyleOption(&options, index); |
||||
|
|
||||
|
QTextDocument doc; |
||||
|
doc.setHtml(options.text); |
||||
|
doc.setTextWidth(options.rect.width()); |
||||
|
return QSize(doc.idealWidth(), doc.size().height()); |
||||
|
} |
||||
|
|
||||
|
bool LinkItemDelegate::editorEvent(QEvent *event, |
||||
|
QAbstractItemModel *model, |
||||
|
const QStyleOptionViewItem &option, |
||||
|
const QModelIndex &index) |
||||
|
{ |
||||
|
if (event->type() == QEvent::MouseButtonRelease) { |
||||
|
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); |
||||
|
if (mouseEvent->button() == Qt::LeftButton) { |
||||
|
QString html = index.data(Qt::DisplayRole).toString(); |
||||
|
QTextDocument doc; |
||||
|
doc.setHtml(html); |
||||
|
doc.setTextWidth(option.rect.width()); |
||||
|
|
||||
|
// this is kinda silly but it werks
|
||||
|
QAbstractTextDocumentLayout *layout = doc.documentLayout(); |
||||
|
|
||||
|
QPoint pos = mouseEvent->pos() - option.rect.topLeft(); |
||||
|
int charPos = layout->hitTest(pos, Qt::ExactHit); |
||||
|
|
||||
|
if (charPos >= 0) { |
||||
|
QTextCursor cursor(&doc); |
||||
|
cursor.setPosition(charPos); |
||||
|
|
||||
|
QTextCharFormat format = cursor.charFormat(); |
||||
|
|
||||
|
if (format.isAnchor()) { |
||||
|
QString href = format.anchorHref(); |
||||
|
if (!href.isEmpty()) { |
||||
|
QDesktopServices::openUrl(QUrl(href)); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return QStyledItemDelegate::editorEvent(event, model, option, index); |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-3.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <QDialog> |
||||
|
#include <QStyledItemDelegate> |
||||
|
#include <QTableView> |
||||
|
#include <memory> |
||||
|
|
||||
|
namespace Ui { class DepsDialog; } |
||||
|
|
||||
|
class DepsDialog : public QDialog |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
|
||||
|
public: |
||||
|
explicit DepsDialog(QWidget *parent); |
||||
|
~DepsDialog() override; |
||||
|
|
||||
|
private: |
||||
|
std::unique_ptr<Ui::DepsDialog> ui; |
||||
|
}; |
||||
|
|
||||
|
class LinkItemDelegate : public QStyledItemDelegate |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
|
||||
|
public: |
||||
|
explicit LinkItemDelegate(QObject *parent = 0); |
||||
|
|
||||
|
protected: |
||||
|
void paint(QPainter *painter, |
||||
|
const QStyleOptionViewItem &option, |
||||
|
const QModelIndex &index) const override; |
||||
|
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; |
||||
|
bool editorEvent(QEvent *event, |
||||
|
QAbstractItemModel *model, |
||||
|
const QStyleOptionViewItem &option, |
||||
|
const QModelIndex &index) override; |
||||
|
}; |
||||
@ -0,0 +1,166 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<ui version="4.0"> |
||||
|
<class>DepsDialog</class> |
||||
|
<widget class="QDialog" name="DepsDialog"> |
||||
|
<property name="geometry"> |
||||
|
<rect> |
||||
|
<x>0</x> |
||||
|
<y>0</y> |
||||
|
<width>701</width> |
||||
|
<height>500</height> |
||||
|
</rect> |
||||
|
</property> |
||||
|
<property name="windowTitle"> |
||||
|
<string>Eden Dependencies</string> |
||||
|
</property> |
||||
|
<layout class="QVBoxLayout" name="verticalLayout_3"> |
||||
|
<item> |
||||
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1"> |
||||
|
<item> |
||||
|
<layout class="QVBoxLayout" name="verticalLayout_2"> |
||||
|
<item> |
||||
|
<widget class="QLabel" name="labelLogo"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> |
||||
|
<horstretch>0</horstretch> |
||||
|
<verstretch>0</verstretch> |
||||
|
</sizepolicy> |
||||
|
</property> |
||||
|
<property name="maximumSize"> |
||||
|
<size> |
||||
|
<width>200</width> |
||||
|
<height>200</height> |
||||
|
</size> |
||||
|
</property> |
||||
|
<property name="text"> |
||||
|
<string/> |
||||
|
</property> |
||||
|
<property name="pixmap"> |
||||
|
<pixmap resource="../../dist/qt_themes/default/default.qrc">:/icons/default/256x256/eden.png</pixmap> |
||||
|
</property> |
||||
|
<property name="scaledContents"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<spacer name="verticalSpacer"> |
||||
|
<property name="orientation"> |
||||
|
<enum>Qt::Orientation::Vertical</enum> |
||||
|
</property> |
||||
|
<property name="sizeHint" stdset="0"> |
||||
|
<size> |
||||
|
<width>20</width> |
||||
|
<height>40</height> |
||||
|
</size> |
||||
|
</property> |
||||
|
</spacer> |
||||
|
</item> |
||||
|
</layout> |
||||
|
</item> |
||||
|
<item> |
||||
|
<layout class="QVBoxLayout" name="verticalLayout"> |
||||
|
<item> |
||||
|
<widget class="QLabel" name="labelEden"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> |
||||
|
<horstretch>0</horstretch> |
||||
|
<verstretch>0</verstretch> |
||||
|
</sizepolicy> |
||||
|
</property> |
||||
|
<property name="text"> |
||||
|
<string><html><head/><body><p><span style=" font-size:28pt;">Eden Dependencies</span></p></body></html></string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QLabel" name="labelInfo"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> |
||||
|
<horstretch>0</horstretch> |
||||
|
<verstretch>0</verstretch> |
||||
|
</sizepolicy> |
||||
|
</property> |
||||
|
<property name="text"> |
||||
|
<string><html><head/><body><p>The projects that make Eden possible</p></body></html></string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QTableWidget" name="tableDeps"> |
||||
|
<property name="editTriggers"> |
||||
|
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set> |
||||
|
</property> |
||||
|
<property name="alternatingRowColors"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
<property name="selectionMode"> |
||||
|
<enum>QAbstractItemView::SelectionMode::NoSelection</enum> |
||||
|
</property> |
||||
|
<property name="columnCount"> |
||||
|
<number>2</number> |
||||
|
</property> |
||||
|
<attribute name="horizontalHeaderShowSortIndicator" stdset="0"> |
||||
|
<bool>false</bool> |
||||
|
</attribute> |
||||
|
<attribute name="verticalHeaderVisible"> |
||||
|
<bool>false</bool> |
||||
|
</attribute> |
||||
|
<column/> |
||||
|
<column/> |
||||
|
</widget> |
||||
|
</item> |
||||
|
</layout> |
||||
|
</item> |
||||
|
</layout> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QDialogButtonBox" name="buttonBox"> |
||||
|
<property name="orientation"> |
||||
|
<enum>Qt::Orientation::Horizontal</enum> |
||||
|
</property> |
||||
|
<property name="standardButtons"> |
||||
|
<set>QDialogButtonBox::StandardButton::Ok</set> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
</layout> |
||||
|
</widget> |
||||
|
<resources> |
||||
|
<include location="../../dist/qt_themes/default/default.qrc"/> |
||||
|
</resources> |
||||
|
<connections> |
||||
|
<connection> |
||||
|
<sender>buttonBox</sender> |
||||
|
<signal>accepted()</signal> |
||||
|
<receiver>DepsDialog</receiver> |
||||
|
<slot>accept()</slot> |
||||
|
<hints> |
||||
|
<hint type="sourcelabel"> |
||||
|
<x>20</x> |
||||
|
<y>20</y> |
||||
|
</hint> |
||||
|
<hint type="destinationlabel"> |
||||
|
<x>20</x> |
||||
|
<y>20</y> |
||||
|
</hint> |
||||
|
</hints> |
||||
|
</connection> |
||||
|
<connection> |
||||
|
<sender>buttonBox</sender> |
||||
|
<signal>rejected()</signal> |
||||
|
<receiver>DepsDialog</receiver> |
||||
|
<slot>reject()</slot> |
||||
|
<hints> |
||||
|
<hint type="sourcelabel"> |
||||
|
<x>20</x> |
||||
|
<y>20</y> |
||||
|
</hint> |
||||
|
<hint type="destinationlabel"> |
||||
|
<x>20</x> |
||||
|
<y>20</y> |
||||
|
</hint> |
||||
|
</hints> |
||||
|
</connection> |
||||
|
</connections> |
||||
|
</ui> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue