Browse Source

help menu

Signed-off-by: crueter <crueter@eden-emu.dev>
pull/3016/head
crueter 1 week ago
parent
commit
57df8f24f0
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 26
      CMakeLists.txt
  2. 173
      src/CMakeLists.txt
  3. 2
      src/Eden/Interface/GraphicsDeviceInterface.cpp
  4. 33
      src/Eden/Interface/MainWindowInterface.cpp
  5. 8
      src/Eden/Interface/MainWindowInterface.h
  6. 2
      src/Eden/Interface/MetaObjectHelper.h
  7. 27
      src/Eden/Interface/QMLSetting.cpp
  8. 4
      src/Eden/Interface/SettingsInterface.cpp
  9. 84
      src/Eden/Main/AboutDialog.qml
  10. 3
      src/Eden/Main/CMakeLists.txt
  11. 142
      src/Eden/Main/DepsDialog.qml
  12. 9
      src/Eden/Main/GameCarousel.qml
  13. 83
      src/Eden/Main/Main.qml
  14. 1
      src/Eden/Models/CMakeLists.txt
  15. 50
      src/Eden/Models/DependencyModel.cpp
  16. 29
      src/Eden/Models/DependencyModel.h
  17. 57
      src/Eden/Native/CMakeLists.txt
  18. 5
      src/Eden/Native/EdenApplication.cpp
  19. 10
      src/Eden/Native/main.cpp
  20. 1
      src/qt_common/CMakeLists.txt
  21. 4
      src/qt_common/externals/cpmfile.json
  22. 7
      src/qt_common/qt_constants.h
  23. 137
      src/yuzu/CMakeLists.txt
  24. 8
      src/yuzu/main_window.cpp

26
CMakeLists.txt

@ -17,6 +17,7 @@ include(DownloadExternals)
include(CMakeDependentOption)
include(CTest)
include(CPMUtil)
include(UseCcache)
DetectArchitecture()
@ -200,30 +201,6 @@ if(YUZU_ENABLE_LTO)
include(UseLTO)
endif()
option(USE_CCACHE "Use ccache for compilation" OFF)
set(CCACHE_PATH "ccache" CACHE STRING "Path to ccache binary")
if(USE_CCACHE)
find_program(CCACHE_BINARY ${CCACHE_PATH})
if(CCACHE_BINARY)
message(STATUS "Found ccache at: ${CCACHE_BINARY}")
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_BINARY})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_BINARY})
else()
message(FATAL_ERROR "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}")
endif()
# Follow SCCache recommendations:
# <https://github.com/mozilla/sccache/blob/main/README.md?plain=1#L144>
if(WIN32)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
endif()
endif()
endif()
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
option(YUZU_LEGACY "Apply patches that improve compatibility with older GPUs (e.g. Snapdragon 865) at the cost of performance" OFF)
@ -268,7 +245,6 @@ if (ENABLE_OPENSSL)
option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" ${DEFAULT_YUZU_USE_BUNDLED_OPENSSL})
endif()
# TODO(crueter): CPM this
if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
AddJsonPackage(vulkan-validation-layers)

173
src/CMakeLists.txt

@ -240,21 +240,174 @@ if (ENABLE_SDL2 AND YUZU_CMD)
set_target_properties(yuzu-cmd PROPERTIES OUTPUT_NAME "eden-cli")
endif()
if (ENABLE_WEB_SERVICE)
add_subdirectory(web_service)
endif()
if (ENABLE_QT)
add_subdirectory(qt_common)
endif()
if (ENABLE_QT_QML)
set(QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "")
add_subdirectory(Eden)
endif()
function(yuzu_qt_target target)
target_compile_definitions(${target} PRIVATE
# Use QStringBuilder for string concatenation to reduce
# the overall number of temporary strings created.
-DQT_USE_QSTRINGBUILDER
if(ENABLE_QT_WIDGETS)
add_subdirectory(yuzu)
endif()
# Disable implicit type narrowing in signal/slot connect() calls.
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
if (ENABLE_WEB_SERVICE)
add_subdirectory(web_service)
# Disable unsafe overloads of QProcess' start() function.
-DQT_NO_PROCESS_COMBINED_ARGUMENT_START
# Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
-DQT_NO_URL_CAST_FROM_STRING
)
file(GLOB COMPAT_LIST
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*)
file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
if (ENABLE_UPDATE_CHECKER)
target_compile_definitions(${target} PUBLIC ENABLE_UPDATE_CHECKER)
endif()
if (ENABLE_QT_TRANSLATION)
set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
option(WORKAROUND_BROKEN_LUPDATE "Run lupdate directly through CMake if Qt's convenience wrappers don't work" OFF)
# Update source TS file if enabled
if (GENERATE_QT_TRANSLATION)
get_target_property(SRCS yuzu SOURCES)
# these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals
# so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm
set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
if (WORKAROUND_BROKEN_LUPDATE)
add_custom_command(OUTPUT ${YUZU_QT_LANGUAGES}/en.ts
COMMAND lupdate
-source-language en_US
-target-language en_US
${SRCS}
${UIS}
-ts ${YUZU_QT_LANGUAGES}/en.ts
DEPENDS
${SRCS}
${UIS}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
)
else()
qt_create_translation(QM_FILES
${SRCS}
${UIS}
${YUZU_QT_LANGUAGES}/en.ts
OPTIONS
-source-language en_US
-target-language en_US
)
endif()
# Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts
set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts)
set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals")
if (WORKAROUND_BROKEN_LUPDATE)
add_custom_command(OUTPUT ${GENERATED_PLURALS_FILE}
COMMAND lupdate
-source-language en_US
-target-language en_US
${SRCS}
${UIS}
-ts ${GENERATED_PLURALS_FILE}
DEPENDS
${SRCS}
${UIS}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
)
else()
qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
endif()
add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE})
endif()
# Find all TS files except en.ts
file(GLOB_RECURSE LANGUAGES_TS ${YUZU_QT_LANGUAGES}/*.ts)
list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts)
# Compile TS files to QM files
qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS})
# Compile english plurals TS file to en.qm
qt_add_translation(LANGUAGES_QM ${PROJECT_SOURCE_DIR}/dist/english_plurals/en.ts)
# Build a QRC file from the QM file list
set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc)
file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n")
foreach (QM ${LANGUAGES_QM})
get_filename_component(QM_FILE ${QM} NAME)
file(APPEND ${LANGUAGES_QRC} "<file>${QM_FILE}</file>\n")
endforeach (QM)
file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>")
# Add the QRC file to package in all QM files
qt_add_resources(LANGUAGES ${LANGUAGES_QRC})
else()
set(LANGUAGES)
endif()
target_sources(${target}
PRIVATE
${COMPAT_LIST}
${ICONS}
${LANGUAGES}
${THEMES})
if (APPLE)
# Normal icns
set(MACOSX_ICON "${PROJECT_SOURCE_DIR}/dist/eden.icns")
set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
target_sources(${target} PRIVATE ${MACOSX_ICON})
# Liquid glass
set(MACOSX_LIQUID_GLASS_ICON "${PROJECT_SOURCE_DIR}/dist/Assets.car")
set_source_files_properties(${MACOSX_LIQUID_GLASS_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
target_sources(${target} PRIVATE ${MACOSX_LIQUID_GLASS_ICON})
set_target_properties(${target} PROPERTIES MACOSX_BUNDLE TRUE)
set_target_properties(${target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib")
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES
MACOSX_PACKAGE_LOCATION Frameworks
XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
target_sources(${target} PRIVATE ${MOLTENVK_LIBRARY})
elseif(WIN32)
# compile as a win32 gui application instead of a console application
target_link_libraries(${target} PRIVATE Qt6::EntryPointPrivate)
if(MSVC)
target_link_libraries(${target} PRIVATE version.lib)
set_target_properties(${target} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
elseif(MINGW)
set_target_properties(${target} PROPERTIES LINK_FLAGS_RELEASE "-Wl,--subsystem,windows")
target_link_libraries(${target} PRIVATE dwmapi)
endif()
endif()
endfunction()
if (ENABLE_QT_QML)
set(QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "")
add_subdirectory(Eden)
endif()
if(ENABLE_QT_WIDGETS)
add_subdirectory(yuzu)
endif()
endif()
if (ANDROID)

2
src/Eden/Interface/GraphicsDeviceInterface.cpp

@ -68,7 +68,7 @@ void GraphicsDeviceInterface::populateVsync()
}
const auto &present_modes = //< relevant vector of present modes for the selected device or API
m_isVulkan && m_device > -1 && https://gofile.io/d/920ShN ? device_present_modes[m_device] : default_present_modes;
m_isVulkan && m_device > -1 && !device_present_modes.empty() ? device_present_modes[m_device] : default_present_modes;
m_vsyncModes.clear();
m_vsyncModes.reserve(present_modes.size());

33
src/Eden/Interface/MainWindowInterface.cpp

@ -9,6 +9,9 @@
#include "qt_common/util/game.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/qt_constants.h"
#include <QDesktopServices>
MainWindowInterface::MainWindowInterface(GameListModel* model, QObject* parent)
: QObject{parent}, m_gameList(model) {
@ -67,6 +70,8 @@ void MainWindowInterface::setFirmwareVersion() {
setFirmwareTooltip(QString::fromStdString(display_title));
}
// TODO(qml): The following are basically all identical to main_window.cpp
// Is there any way we can combine these?
void MainWindowInterface::openRootDataFolder() {
QtCommon::Game::OpenRootDataFolder();
}
@ -91,7 +96,35 @@ void MainWindowInterface::openLogFolder()
QtCommon::Game::OpenLogFolder();
}
void MainWindowInterface::createHomeMenuDesktopShortcut() {
QtCommon::Game::CreateHomeMenuShortcut(QtCommon::Game::ShortcutTarget::Desktop);
}
void MainWindowInterface::createHomeMenuApplicationMenuShortcut() {
QtCommon::Game::CreateHomeMenuShortcut(QtCommon::Game::ShortcutTarget::Applications);
}
void MainWindowInterface::openURL(const QUrl& url) {
const bool open = QDesktopServices::openUrl(url);
if (!open) {
QtCommon::Frontend::Warning(tr("Error opening URL"),
tr("Unable to open the URL \"%1\".").arg(url.toString()));
}
}
void MainWindowInterface::openModsPage() {
openURL(QUrl(QString::fromLocal8Bit(QtCommon::Constants::modPage)));
}
void MainWindowInterface::openQuickstartGuide() {
openURL(QUrl(QString::fromLocal8Bit(QtCommon::Constants::quickstartPage)));
}
void MainWindowInterface::openFAQ() {
openURL(QUrl(QString::fromLocal8Bit(QtCommon::Constants::helpPage)));
}
/// PROPERTIES ///
QString MainWindowInterface::firmwareDisplay() const {
return m_firmwareDisplay;
}

8
src/Eden/Interface/MainWindowInterface.h

@ -24,6 +24,14 @@ public:
Q_INVOKABLE void installDecryptionKeys();
Q_INVOKABLE void createHomeMenuApplicationMenuShortcut();
Q_INVOKABLE void createHomeMenuDesktopShortcut();
Q_INVOKABLE void openURL(const QUrl& url);
Q_INVOKABLE void openModsPage();
Q_INVOKABLE void openQuickstartGuide();
Q_INVOKABLE void openFAQ();
bool firmwareGood() const;
void setFirmwareGood(bool newFirmwareGood);

2
src/Eden/Interface/MetaObjectHelper.h

@ -18,7 +18,7 @@ public:
{
QQmlProperty qmlProperty(object, property);
QMetaProperty metaProperty = qmlProperty.property();
return metaProperty.typeName();
return QString::fromLocal8Bit(metaProperty.typeName());
}
};

27
src/Eden/Interface/QMLSetting.cpp

@ -3,7 +3,6 @@
#include "QMLSetting.h"
#include "common/settings.h"
#include "qt_common/config/uisettings.h"
#include <QVariant>
@ -56,17 +55,17 @@ QMLSetting::QMLSetting(Settings::BasicSetting *setting, QObject *parent, Request
}();
if (type == typeid(bool)) {
m_type = "bool";
m_type = QStringLiteral("bool");
m_metaType = QMetaType::Bool;
} else if (setting->IsEnum()) {
m_metaType = QMetaType::UInt;
if (request == RequestType::RadioGroup) {
m_type = "radio";
m_type = QStringLiteral("radio");
// TODO: Add the options and whatnot
// see CreateRadioGroup
} else {
m_type = "enumCombo";
m_type = QStringLiteral("enumCombo");
}
} else if (setting->IsIntegral()) {
m_metaType = QMetaType::UInt;
@ -75,27 +74,27 @@ QMLSetting::QMLSetting(Settings::BasicSetting *setting, QObject *parent, Request
case RequestType::Slider:
case RequestType::ReverseSlider:
// TODO: Reversal and multiplier
m_type = "intSlider";
m_type = QStringLiteral("intSlider");
break;
case RequestType::Default:
case RequestType::LineEdit:
m_type = "intSpin";
m_type = QStringLiteral("intSpin");
break;
case RequestType::DateTimeEdit:
// TODO: disabled/restrict
m_type = "time";
m_type = QStringLiteral("time");
break;
case RequestType::SpinBox:
// TODO: suffix
m_type = "intSpin";
m_type = QStringLiteral("intSpin");
break;
case RequestType::HexEdit:
m_type = "hex";
m_type = QStringLiteral("hex");
break;
case RequestType::ComboBox:
// TODO: Add the options and whatnot
// see CreateComboBox
m_type = "intCombo";
m_type = QStringLiteral("intCombo");
break;
default:
// UNIMPLEMENTED();
@ -108,12 +107,12 @@ QMLSetting::QMLSetting(Settings::BasicSetting *setting, QObject *parent, Request
case RequestType::Default:
case RequestType::SpinBox:
// TODO: suffix
m_type = "doubleSpin";
m_type = QStringLiteral("doubleSpin");
break;
case RequestType::Slider:
case RequestType::ReverseSlider:
// TODO: multiplier, suffix, reversal
m_type = "doubleSlider";
m_type = QStringLiteral("doubleSlider");
break;
default:
// UNIMPLEMENTED assert
@ -126,10 +125,10 @@ QMLSetting::QMLSetting(Settings::BasicSetting *setting, QObject *parent, Request
switch (request) {
case RequestType::Default:
case RequestType::LineEdit:
m_type = "stringLine";
m_type = QStringLiteral("stringLine");
break;
case RequestType::ComboBox:
m_type = "stringCombo";
m_type = QStringLiteral("stringCombo");
break;
default:
// UNIMPLEMENTED();

4
src/Eden/Interface/SettingsInterface.cpp

@ -93,11 +93,11 @@ QMLSetting *SettingsInterface::getSetting(Settings::BasicSetting *setting)
}
// TODO: Suffix (fr)
QString suffix = "";
QString suffix = QString();
if ((setting->Specialization() & Settings::SpecializationAttributeMask) ==
Settings::Specialization::Percentage) {
suffix = "%";
suffix = QStringLiteral("%");
}
// paired setting (I/A)

84
src/Eden/Main/AboutDialog.qml

@ -0,0 +1,84 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Carboxyl.Contour
NativeDialog {
title: qsTr("About Eden")
width: 700
height: 400
standardButtons: Dialog.Ok
Image {
id: img
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
margins: 10
}
source: "qrc:/icons/default/256x256/eden.png"
width: 200
height: 200
}
ColumnLayout {
anchors {
left: img.right
top: parent.top
bottom: parent.bottom
right: parent.right
margins: 10
}
Label {
font.pixelSize: 28
text: qsTr("Eden")
}
Label {
font.pixelSize: 14
text: TitleManager.title
}
Label {
text: qsTr("Eden is an experimental open-source emulator for the Nintendo Switch licensed under the \
GPLv3.0+, based on the Yuzu emulator project, which ended development back in March 2024.\n\n\
This software should not be used to play games you have not legally obtained.")
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.fillHeight: true
font.pointSize: 12
}
Label {
text: '<a href="https://eden-emulator.github.io/" style="text-decoration: underline; color:#039be5;">Website</a> | '
+ '<a href="https://git.eden-emu.dev" style="text-decoration: underline; color:#039be5;">Source Code</a> | '
+ '<a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors" style="text-decoration: underline; color:#039be5;">Contributors</a> | '
+ '<a href="https://discord.gg/HstXbPch7X" style="text-decoration: underline; color:#039be5;">Discord</a> | '
+ '<a href="https://rvlt.gg/qKgFEAbH" style="text-decoration: underline; color:#039be5;">Revolt</a> | '
+ '<a href="https://nitter.poast.org/edenemuofficial" style="text-decoration: underline; color:#039be5;">Twitter</a> | '
+ '<a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt" style="text-decoration: underline; color:#039be5;">License</a>'
textFormat: Text.RichText
wrapMode: Text.WordWrap
Layout.fillWidth: true
onLinkActivated: link => Qt.openUrlExternally(link)
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
Label {
text: '"Nintendo Switch" is a trademark of Nintendo. Eden is not affiliated with Nintendo in any way.'
font.pixelSize: 9
}
}
}

3
src/Eden/Main/CMakeLists.txt

@ -18,6 +18,9 @@ EdenModule(
GameCarouselCard.qml
GameCarousel.qml
AboutDialog.qml
DepsDialog.qml
LIBRARIES
Eden::Interface
)

142
src/Eden/Main/DepsDialog.qml

@ -0,0 +1,142 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Carboxyl.Contour
NativeDialog {
title: qsTr("Eden Dependencies")
width: 700
height: 600
standardButtons: Dialog.Ok
Image {
id: img
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
margins: 10
}
source: "qrc:/icons/default/256x256/eden.png"
width: 200
height: 200
}
ColumnLayout {
anchors {
left: img.right
top: parent.top
bottom: parent.bottom
right: parent.right
margins: 10
}
Label {
font.pixelSize: 28
text: qsTr("Eden Dependencies")
}
Label {
font.pixelSize: 14
text: qsTr("The projects that make Eden possible")
}
HorizontalHeaderView {
syncView: tableView
clip: true
delegate: Rectangle {
required property string display
implicitWidth: scroll.width / 2 - 5
implicitHeight: 30
color: palette.alternateBase
border {
color: palette.mid
width: 1
}
Component.onCompleted: console.log(display, row)
Label {
text: display
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
}
ScrollView {
id: scroll
Layout.fillHeight: true
Layout.fillWidth: true
TableView {
id: tableView
alternatingRows: true
model: DependencyModel
boundsBehavior: Flickable.StopAtBounds
clip: true
Component.onCompleted: console.log(itemAtCell(Qt.point(1, 1)))
delegate: Rectangle {
required property string display
required property int row
implicitWidth: scroll.width / 2 - 5
implicitHeight: 30
color: row % 2 == 0 ? palette.base : palette.alternateBase
border {
color: palette.mid
width: 1
}
Component.onCompleted: console.log(display, row)
Label {
text: display
anchors.fill: parent
anchors.leftMargin: 10
verticalAlignment: Text.AlignVCenter
textFormat: Text.RichText
onLinkActivated: link => Qt.openUrlExternally(link)
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
}
}
WheelHandler {
target: scroll
onWheel: event => {
const sensitivity = 1 / 1500
scroll.ScrollBar.vertical.position -= event.angleDelta.y * sensitivity
scroll.ScrollBar.vertical.position = Math.max(
Math.min(
scroll.ScrollBar.vertical.position,
1.0 - scroll.ScrollBar.vertical.size), 0.0)
}
}
}
}
}

9
src/Eden/Main/GameCarousel.qml

@ -1,6 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
import Qt.labs.platform
@ -15,7 +14,6 @@ ListView {
focus: true
// focusPolicy: Qt.StrongFocus
model: EdenGameList
orientation: ListView.Horizontal
clip: false
@ -38,7 +36,6 @@ ListView {
currentIndex = count - 1
}
// TODO(crueter): handle move/displace/add (requires thread worker on game list and a bunch of other shit)
Rectangle {
id: hg
clip: false
@ -79,10 +76,12 @@ ListView {
}
highlightRangeMode: ListView.StrictlyEnforceRange
preferredHighlightBegin: currentItem === null ? 0 : x + width / 2 - currentItem.width / 2
preferredHighlightEnd: currentItem === null ? 0 : x + width / 2 + currentItem.width / 2
// TODO: Configurable Card size
preferredHighlightBegin: x + width / 2 - 150
preferredHighlightEnd: x + width / 2 + 150
highlightMoveDuration: 300
delegate: GameCarouselCard {
id: game
width: 300

83
src/Eden/Main/Main.qml

@ -40,6 +40,14 @@ ApplicationWindow {
id: globalConfig
}
AboutDialog {
id: aboutDialog
}
DepsDialog {
id: depDialog
}
menuBar: MenuBar {
Menu {
title: qsTr("&File")
@ -206,34 +214,91 @@ ApplicationWindow {
MenuSeparator {}
Menu {
title: qsTr("&Amiibo")
title: qsTr("Am&iibo")
}
Menu {
title: qsTr("&Applets")
Action {
text: qsTr("Open &Album")
}
Action {
text: qsTr("Open &Mii Editor")
}
Action {
text: qsTr("Open &Controller Menu")
}
Action {
text: qsTr("Open &Home Menu")
}
Action {
text: qsTr("Open &Setup")
}
}
Menu {
title: qsTr("&Create Home Menu Shortcut")
Action {
text: qsTr("&Desktop")
onTriggered: MainWindowInterface.createHomeMenuDesktopShortcut()
}
Action {
text: qsTr("&Application Menu")
onTriggered: MainWindowInterface.createHomeMenuApplicationMenuShortcut()
}
}
MenuSeparator {}
Action {
text: qsTr("Open A&lbum")
text: qsTr("&Capture Screenshot")
shortcut: "Ctrl+P"
}
Menu {
title: "&TAS"
}
}
Menu {
title: qsTr("&Multiplayer")
}
Menu {
title: qsTr("&Help")
Action {
text: qsTr("Open &Mii Editor")
text: qsTr("Open &Mods Page")
onTriggered: MainWindowInterface.openModsPage()
}
Action {
text: qsTr("Open Co&ntroller Menu")
text: qsTr("Open &Quickstart Guide")
onTriggered: MainWindowInterface.openQuickstartGuide()
}
Action {
text: qsTr("Open &Home Menu")
text: qsTr("&FAQ")
onTriggered: MainWindowInterface.openFAQ()
}
MenuSeparator {}
Action {
text: qsTr("&Capture Screenshot")
shortcut: "Ctrl+P"
text: qsTr("&About Eden")
onTriggered: aboutDialog.show()
}
Menu {
title: "&TAS"
Action {
text: qsTr("&Eden Dependencies")
onTriggered: depDialog.show()
}
}
}

1
src/Eden/Models/CMakeLists.txt

@ -11,6 +11,7 @@ qt_add_library(EdenModels STATIC
SettingsModel.h SettingsModel.cpp
GameListWorker.h GameListWorker.cpp
GameIconProvider.h GameIconProvider.cpp
DependencyModel.h DependencyModel.cpp
)
target_link_libraries(EdenModels PRIVATE Qt6::Core Qt6::Quick Qt6::Gui)

50
src/Eden/Models/DependencyModel.cpp

@ -0,0 +1,50 @@
#include <qnamespace.h>
#include "DependencyModel.h"
#include "dep_hashes.h"
DependencyModel::DependencyModel(QObject* parent) : QAbstractTableModel(parent) {
for (size_t i = 0; i < Common::dep_hashes.size(); ++i) {
QString name = QString::fromLocal8Bit(Common::dep_names.at(i));
QString version = QString::fromLocal8Bit(Common::dep_hashes.at(i));
QString url = QString::fromLocal8Bit(Common::dep_urls.at(i));
m_data.append(Dependency{name, version, url});
}
}
QVariant DependencyModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (orientation == Qt::Vertical)
return QString();
switch (section) {
case 0:
return tr("Dependency");
case 1:
default:
return tr("Version");
}
}
int DependencyModel::rowCount(const QModelIndex& parent) const {
return m_data.size();
}
int DependencyModel::columnCount(const QModelIndex& parent) const {
return 2;
}
QVariant DependencyModel::data(const QModelIndex& index, int role) const {
if (!index.isValid() || role != Qt::DisplayRole)
return QVariant();
Dependency d = m_data[index.row()];
switch (index.column()) {
case 0:
return QStringLiteral("<a href=%1>%2</a>").arg(d.url, d.name);
case 1:
default:
return d.version;
}
}

29
src/Eden/Models/DependencyModel.h

@ -0,0 +1,29 @@
#pragma once
#include <QAbstractTableModel>
struct Dependency {
QString name;
QString version;
QString url;
};
class DependencyModel : public QAbstractTableModel {
Q_OBJECT
public:
explicit DependencyModel(QObject* parent = nullptr);
// Header:
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
// Basic functionality:
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
private:
QList<Dependency> m_data;
};

57
src/Eden/Native/CMakeLists.txt

@ -10,8 +10,7 @@ qt_add_executable(eden
EdenApplication.h EdenApplication.cpp
LibQtCommon.cpp
LibQtCommon.h
)
LibQtCommon.h)
set(MODULES
Eden::Util
@ -20,8 +19,7 @@ set(MODULES
Eden::Interface
Eden::Constants
Eden::Main
Eden::Models
)
Eden::Models)
# if (ENABLE_SDL2)
# add_subdirectory(Gamepad)
@ -38,60 +36,13 @@ target_link_libraries(eden
Carboxyl::Carboxyl
${MODULES}
)
${MODULES})
target_link_libraries(eden PRIVATE common core input_common frontend_common qt_common network video_core)
target_link_libraries(eden PRIVATE Boost::headers glad fmt)
target_link_libraries(eden PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
target_compile_definitions(eden PRIVATE
# Use QStringBuilder for string concatenation to reduce
# the overall number of temporary strings created.
-DQT_USE_QSTRINGBUILDER
# Disable implicit type narrowing in signal/slot connect() calls.
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
# Disable unsafe overloads of QProcess' start() function.
-DQT_NO_PROCESS_COMBINED_ARGUMENT_START
# Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
-DQT_NO_URL_CAST_FROM_STRING
)
if (APPLE)
set(MACOSX_ICON "../../dist/eden.icns")
set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
target_sources(eden PRIVATE ${MACOSX_ICON})
set_target_properties(eden PROPERTIES MACOSX_BUNDLE TRUE)
set_target_properties(eden PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
if (YUZU_USE_BUNDLED_MOLTENVK)
set(MOLTENVK_PLATFORM "macOS")
set(MOLTENVK_VERSION "v1.4.0")
download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
endif()
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib")
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES
MACOSX_PACKAGE_LOCATION Frameworks
XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
target_sources(eden PRIVATE ${MOLTENVK_LIBRARY})
elseif(WIN32)
# compile as a win32 gui application instead of a console application
target_link_libraries(eden PRIVATE Qt6::EntryPointPrivate)
if(MSVC)
target_link_libraries(eden PRIVATE version.lib)
set_target_properties(eden PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
elseif(MINGW)
set_target_properties(eden PROPERTIES LINK_FLAGS_RELEASE "-Wl,--subsystem,windows")
target_link_libraries(eden PRIVATE dwmapi)
endif()
endif()
yuzu_qt_target(eden)
if (ENABLE_QT_WIDGETS)
set_target_properties(eden PROPERTIES OUTPUT_NAME "eden-qml")

5
src/Eden/Native/EdenApplication.cpp

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "Eden/Interface/MainWindowInterface.h"
#include "Eden/Models/DependencyModel.h"
#include "EdenApplication.h"
#include <QQmlApplicationEngine>
@ -94,6 +95,10 @@ int EdenApplication::run() {
GameListModel *gameListModel = new GameListModel(this, &engine);
ctx->setContextProperty(QStringLiteral("EdenGameList"), gameListModel);
// Dependency Model
DependencyModel* depModel = new DependencyModel(this);
ctx->setContextProperty(QStringLiteral("DependencyModel"), depModel);
// Settings Interface
SettingsInterface *interface = new SettingsInterface(&engine);
ctx->setContextProperty(QStringLiteral("SettingsInterface"), interface);

10
src/Eden/Native/main.cpp

@ -6,12 +6,22 @@
#undef VMA_IMPLEMENTATION
#endif
#include <QDirIterator>
#include "EdenApplication.h"
int main(int argc, char *argv[])
{
EdenApplication app(argc, argv);
QDirIterator iter(QDir(QStringLiteral(":/")), QDirIterator::Subdirectories);
while (iter.hasNext()) {
QString next = iter.next();
if (!next.contains(QStringLiteral("k")) && !next.contains(QStringLiteral("breeze"))) {
qDebug() << next;
}
}
return app.run();
}

1
src/qt_common/CMakeLists.txt

@ -38,6 +38,7 @@ add_library(qt_common STATIC
util/fs.h util/fs.cpp
util/vk_device_info.cpp
util/vk_device_info.h
qt_constants.h
)
if (UNIX)

4
src/qt_common/externals/cpmfile.json

@ -19,8 +19,8 @@
"package": "Carboxyl",
"repo": "crueter/Carboxyl",
"git_host": "git.crueter.xyz",
"sha": "6c37572331",
"hash": "e2a7f14d6b6bc9285e1b525fee653a47bc0f971343addb1223873c11f683f0c9e360dedfa496c5074895f0788092ea401d42e7e61e98a244c38373de49a0f638",
"sha": "ff49f168b0",
"hash": "a4a46be3aea6bb666c274c1ae323abb4b26746a4976e0595b9893cfba5297b78c267526ba99e02e6ce8d48da605f9ea448d8cf6bbd01e81953754a2131c65d2b",
"bundled": "true",
"options": [
"CARBOXYL_DEMO OFF"

7
src/qt_common/qt_constants.h

@ -0,0 +1,7 @@
#pragma once
namespace QtCommon::Constants {
static constexpr const char* modPage = "https://github.com/eden-emulator/yuzu-mod-archive";
static constexpr const char* quickstartPage = "https://yuzu-mirror.github.io/help/quickstart/";
static constexpr const char* helpPage = "https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user";
}

137
src/yuzu/CMakeLists.txt

@ -255,142 +255,7 @@ if (CXX_CLANG)
)
endif()
file(GLOB COMPAT_LIST
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*)
file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
if (ENABLE_UPDATE_CHECKER)
target_compile_definitions(yuzu PUBLIC ENABLE_UPDATE_CHECKER)
endif()
if (ENABLE_QT_TRANSLATION)
set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
option(WORKAROUND_BROKEN_LUPDATE "Run lupdate directly through CMake if Qt's convenience wrappers don't work" OFF)
# Update source TS file if enabled
if (GENERATE_QT_TRANSLATION)
get_target_property(SRCS yuzu SOURCES)
# these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals
# so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm
set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
if (WORKAROUND_BROKEN_LUPDATE)
add_custom_command(OUTPUT ${YUZU_QT_LANGUAGES}/en.ts
COMMAND lupdate
-source-language en_US
-target-language en_US
${SRCS}
${UIS}
-ts ${YUZU_QT_LANGUAGES}/en.ts
DEPENDS
${SRCS}
${UIS}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
)
else()
qt_create_translation(QM_FILES
${SRCS}
${UIS}
${YUZU_QT_LANGUAGES}/en.ts
OPTIONS
-source-language en_US
-target-language en_US
)
endif()
# Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts
set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts)
set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals")
if (WORKAROUND_BROKEN_LUPDATE)
add_custom_command(OUTPUT ${GENERATED_PLURALS_FILE}
COMMAND lupdate
-source-language en_US
-target-language en_US
${SRCS}
${UIS}
-ts ${GENERATED_PLURALS_FILE}
DEPENDS
${SRCS}
${UIS}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
)
else()
qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
endif()
add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE})
endif()
# Find all TS files except en.ts
file(GLOB_RECURSE LANGUAGES_TS ${YUZU_QT_LANGUAGES}/*.ts)
list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts)
# Compile TS files to QM files
qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS})
# Compile english plurals TS file to en.qm
qt_add_translation(LANGUAGES_QM ${PROJECT_SOURCE_DIR}/dist/english_plurals/en.ts)
# Build a QRC file from the QM file list
set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc)
file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n")
foreach (QM ${LANGUAGES_QM})
get_filename_component(QM_FILE ${QM} NAME)
file(APPEND ${LANGUAGES_QRC} "<file>${QM_FILE}</file>\n")
endforeach (QM)
file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>")
# Add the QRC file to package in all QM files
qt_add_resources(LANGUAGES ${LANGUAGES_QRC})
else()
set(LANGUAGES)
endif()
target_sources(yuzu
PRIVATE
${COMPAT_LIST}
${ICONS}
${LANGUAGES}
${THEMES}
)
if (APPLE)
# Normal icns
set(MACOSX_ICON "../../dist/eden.icns")
set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
target_sources(yuzu PRIVATE ${MACOSX_ICON})
# Liquid glass
set(MACOSX_LIQUID_GLASS_ICON "../../dist/Assets.car")
set_source_files_properties(${MACOSX_LIQUID_GLASS_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
target_sources(yuzu PRIVATE ${MACOSX_LIQUID_GLASS_ICON})
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib")
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES
MACOSX_PACKAGE_LOCATION Frameworks
XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
target_sources(yuzu PRIVATE ${MOLTENVK_LIBRARY})
elseif(WIN32)
# compile as a win32 gui application instead of a console application
target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate)
if(MSVC)
target_link_libraries(yuzu PRIVATE version.lib)
set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
elseif(MINGW)
set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "-Wl,--subsystem,windows")
target_link_libraries(yuzu PRIVATE dwmapi)
endif()
endif()
yuzu_qt_target(yuzu)
target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common)

8
src/yuzu/main_window.cpp

@ -78,6 +78,7 @@
#include "qt_common/abstract/frontend.h"
#include "qt_common/qt_common.h"
#include "qt_common/qt_constants.h"
#include "qt_common/util/path.h"
#include "qt_common/util/content.h"
@ -2732,6 +2733,7 @@ void MainWindow::IncrementInstallProgress() {
install_progress->setValue(install_progress->value() + 1);
}
// TODO(qml): Implement InstallDialog + Interface in QML
void MainWindow::OnMenuInstallToNAND() {
const QString file_filter =
tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
@ -3095,15 +3097,15 @@ void MainWindow::OpenURL(const QUrl& url) {
}
void MainWindow::OnOpenModsPage() {
OpenURL(QUrl(QStringLiteral("https://github.com/eden-emulator/yuzu-mod-archive")));
OpenURL(QUrl(QString::fromLocal8Bit(QtCommon::Constants::modPage)));
}
void MainWindow::OnOpenQuickstartGuide() {
OpenURL(QUrl(QStringLiteral("https://yuzu-mirror.github.io/help/quickstart/")));
OpenURL(QUrl(QString::fromLocal8Bit(QtCommon::Constants::quickstartPage)));
}
void MainWindow::OnOpenFAQ() {
OpenURL(QUrl(QStringLiteral("https://yuzu-mirror.github.io/help")));
OpenURL(QUrl(QString::fromLocal8Bit(QtCommon::Constants::helpPage)));
}
void MainWindow::ToggleFullscreen() {

Loading…
Cancel
Save