Compare commits

...

3 commits

Author SHA1 Message Date
1dec879ec8
data dialog rewrite
Signed-off-by: crueter <crueter@eden-emu.dev>
2025-10-08 22:45:33 -04:00
e8149b77ae
headers
Signed-off-by: crueter <crueter@eden-emu.dev>
2025-10-08 16:12:11 -04:00
221d9c71ac
[desktop] Initial data manager prototype
Right now, all this adds is a small dialog to the Widgets frontend
showing the user how much space is taken up by their saves, shaders,
NAND, and mods. It also gives them the choice to clear these directories
(with 2x confirmation), OR open the directory in their system file
manager.

In the future, a lot more can be done with this concept. Notably, a
common import/export (a la android) could be added, the UI can obviously
be polished, etc. We could also add this to Android, but I don't think
common import/export is needed *for* Android, and should probably be
left in qt_common.

Signed-off-by: crueter <crueter@eden-emu.dev>
2025-10-08 16:07:02 -04:00
24 changed files with 636 additions and 13 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

View file

@ -18,6 +18,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file> <file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file> <file alias="48x48/folder.png">icons/48x48/folder.png</file>
<file alias="48x48/trash.png">icons/48x48/trash.png</file>
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file> <file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file> <file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>

View file

@ -11,6 +11,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file> <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file> <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file> <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
<file alias="48x48/trash.png">../colorful/icons/48x48/trash.png</file>
<file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file> <file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file> <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
<file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file> <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>

View file

@ -14,6 +14,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file> <file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file> <file alias="48x48/folder.png">icons/48x48/folder.png</file>
<file alias="48x48/trash.png">icons/48x48/trash.png</file>
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file> <file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
<file alias="48x48/star.png">icons/48x48/star.png</file> <file alias="48x48/star.png">icons/48x48/star.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

View file

@ -13,6 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file> <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file> <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file> <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
<file alias="48x48/trash.png">../colorful/icons/48x48/trash.png</file>
<file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file> <file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
<file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file> <file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file> <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

View file

@ -9,6 +9,7 @@
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file> <file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file> <file alias="48x48/folder.png">icons/48x48/folder.png</file>
<file alias="48x48/trash.png">icons/48x48/trash.png</file>
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file> <file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file> <file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>

View file

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
@ -7,6 +10,7 @@ add_library(frontend_common STATIC
content_manager.h content_manager.h
firmware_manager.h firmware_manager.h
firmware_manager.cpp firmware_manager.cpp
data_manager.h data_manager.cpp
) )
create_target_directory_groups(frontend_common) create_target_directory_groups(frontend_common)

View file

@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "data_manager.h"
#include "common/assert.h"
#include "common/fs/path_util.h"
#include <filesystem>
#include <fmt/format.h>
namespace FrontendCommon::DataManager {
namespace fs = std::filesystem;
const std::string GetDataDir(DataDir dir)
{
const fs::path nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir);
switch (dir) {
case DataDir::Saves:
return (nand_dir / "user" / "save" / "0000000000000000").string();
case DataDir::UserNand:
return (nand_dir / "user" / "Contents" / "registered").string();
case DataDir::SysNand:
return (nand_dir / "system").string();
case DataDir::Mods:
return Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir);
case DataDir::Shaders:
return Common::FS::GetEdenPathString(Common::FS::EdenPath::ShaderDir);
default:
UNIMPLEMENTED();
}
return "";
}
u64 ClearDir(DataDir dir)
{
fs::path data_dir = GetDataDir(dir);
u64 result = fs::remove_all(data_dir);
// mkpath at the end just so it actually exists
fs::create_directories(data_dir);
return result;
}
const std::string ReadableBytesSize(u64 size)
{
static constexpr std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
if (size == 0) {
return "0 B";
}
const int digit_groups = (std::min) (static_cast<int>(std::log10(size) / std::log10(1024)),
static_cast<int>(units.size()));
return fmt::format("{:.1f} {}", size / std::pow(1024, digit_groups), units[digit_groups]);
}
u64 DataDirSize(DataDir dir)
{
fs::path data_dir = GetDataDir(dir);
u64 size = 0;
if (!fs::exists(data_dir))
return 0;
for (const auto& entry : fs::recursive_directory_iterator(data_dir)) {
if (!entry.is_directory()) {
size += entry.file_size();
}
}
return size;
}
}

View file

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef DATA_MANAGER_H
#define DATA_MANAGER_H
#include "common/common_types.h"
#include <string>
namespace FrontendCommon::DataManager {
enum class DataDir { Saves, UserNand, SysNand, Mods, Shaders };
const std::string GetDataDir(DataDir dir);
u64 ClearDir(DataDir dir);
const std::string ReadableBytesSize(u64 size);
u64 DataDirSize(DataDir dir);
}; // namespace FrontendCommon::DataManager
#endif // DATA_MANAGER_H

View file

@ -4,9 +4,6 @@
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
find_package(Qt6 REQUIRED COMPONENTS Core)
find_package(Qt6 REQUIRED COMPONENTS Core)
add_library(qt_common STATIC add_library(qt_common STATIC
qt_common.h qt_common.h
qt_common.cpp qt_common.cpp
@ -27,6 +24,7 @@ add_library(qt_common STATIC
qt_rom_util.h qt_rom_util.cpp qt_rom_util.h qt_rom_util.cpp
qt_applet_util.h qt_applet_util.cpp qt_applet_util.h qt_applet_util.cpp
qt_progress_dialog.h qt_progress_dialog.cpp qt_progress_dialog.h qt_progress_dialog.cpp
qt_string_lookup.h
) )
@ -40,6 +38,7 @@ endif()
add_subdirectory(externals) add_subdirectory(externals)
target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip)
target_link_libraries(qt_common PUBLIC frozen::frozen)
if (NOT APPLE AND ENABLE_OPENGL) if (NOT APPLE AND ENABLE_OPENGL)
target_compile_definitions(qt_common PUBLIC HAS_OPENGL) target_compile_definitions(qt_common PUBLIC HAS_OPENGL)

View file

@ -17,4 +17,4 @@ AddJsonPackage(quazip)
# frozen # frozen
# TODO(crueter): Qt String Lookup # TODO(crueter): Qt String Lookup
# AddJsonPackage(frozen) AddJsonPackage(frozen)

View file

@ -348,4 +348,29 @@ void FixProfiles()
QtCommon::Game::OpenSaveFolder(); QtCommon::Game::OpenSaveFolder();
} }
void ClearDataDir(FrontendCommon::DataManager::DataDir dir) {
auto result = QtCommon::Frontend::Warning("Really clear data?",
"Important data may be lost!",
QMessageBox::Yes | QMessageBox::No);
if (result != QMessageBox::Yes)
return;
result = QtCommon::Frontend::Warning(
"Are you REALLY sure?",
"Once deleted, your data will NOT come back!\n"
"Only do this if you're 100% sure you want to delete this data.",
QMessageBox::Yes | QMessageBox::No);
if (result != QMessageBox::Yes)
return;
QtCommon::Frontend::QtProgressDialog dialog(tr("Clearing..."), QString(), 0, 0);
dialog.show();
FrontendCommon::DataManager::ClearDir(dir);
dialog.close();
}
} // namespace QtCommon::Content } // namespace QtCommon::Content

View file

@ -6,6 +6,7 @@
#include <QObject> #include <QObject>
#include "common/common_types.h" #include "common/common_types.h"
#include "frontend_common/data_manager.h"
namespace QtCommon::Content { namespace QtCommon::Content {
@ -46,6 +47,8 @@ void InstallKeys();
void VerifyGameContents(const std::string &game_path); void VerifyGameContents(const std::string &game_path);
void VerifyInstalledContents(); void VerifyInstalledContents();
void ClearDataDir(FrontendCommon::DataManager::DataDir dir);
// Profiles // // Profiles //
void FixProfiles(); void FixProfiles();
} }

View file

@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QString>
#include <frozen/string.h>
#include <frozen/unordered_map.h>
#include <qobjectdefs.h>
#include <qtmetamacros.h>
namespace QtCommon::StringLookup {
Q_NAMESPACE
// TODO(crueter): QML interface
enum StringKey {
SavesTooltip,
ShadersTooltip,
UserNandTooltip,
SysNandTooltip,
ModsTooltip,
};
static constexpr const frozen::unordered_map<StringKey, frozen::string, 5> strings = {
{SavesTooltip, "Contains game save data. DO NOT REMOVE UNLESS YOU KNOW WHAT YOU'RE DOING!"},
{ShadersTooltip, "Contains Vulkan and OpenGL pipeline caches. Generally safe to remove."},
{UserNandTooltip, "Contains updates and DLC for games."},
{SysNandTooltip, "Contains firmware and applet data."},
{ModsTooltip, "Contains game mods, patches, and cheats."},
};
static inline const QString Lookup(StringKey key)
{
return QString::fromStdString(strings.at(key).data());
}
}

View file

@ -234,6 +234,9 @@ add_executable(yuzu
deps_dialog.cpp deps_dialog.cpp
deps_dialog.h deps_dialog.h
deps_dialog.ui deps_dialog.ui
data_dialog.h data_dialog.cpp data_dialog.ui
data_widget.ui
) )
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden") set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")

85
src/yuzu/data_dialog.cpp Normal file
View file

@ -0,0 +1,85 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "data_dialog.h"
#include "frontend_common/data_manager.h"
#include "qt_common/qt_content_util.h"
#include "qt_common/qt_string_lookup.h"
#include "ui_data_dialog.h"
#include <QDesktopServices>
#include <QFutureWatcher>
#include <QtConcurrent/QtConcurrentRun>
DataDialog::DataDialog(QWidget *parent)
: QDialog(parent)
, ui(std::make_unique<Ui::DataDialog>())
{
ui->setupUi(this);
// TODO: Should we make this a single widget that pulls data from a model?
#define WIDGET(name) \
ui->page->addWidget(new DataWidget(FrontendCommon::DataManager::DataDir::name, \
QtCommon::StringLookup::name##Tooltip, \
this));
WIDGET(Saves)
WIDGET(Shaders)
WIDGET(UserNand)
WIDGET(SysNand)
WIDGET(Mods)
#undef WIDGET
connect(ui->labels, &QListWidget::itemSelectionChanged, this, [this]() {
ui->page->setCurrentIndex(ui->labels->currentRow());
});
}
DataDialog::~DataDialog() = default;
DataWidget::DataWidget(FrontendCommon::DataManager::DataDir data_dir,
QtCommon::StringLookup::StringKey tooltip,
QWidget *parent)
: QWidget(parent)
, ui(std::make_unique<Ui::DataWidget>())
, m_dir(data_dir)
{
ui->setupUi(this);
ui->tooltip->setText(QtCommon::StringLookup::Lookup(tooltip));
ui->clear->setIcon(QIcon::fromTheme(QStringLiteral("trash")));
ui->open->setIcon(QIcon::fromTheme(QStringLiteral("folder")));
connect(ui->clear, &QPushButton::clicked, this, &DataWidget::clear);
connect(ui->open, &QPushButton::clicked, this, &DataWidget::open);
scan();
}
void DataWidget::clear() {
QtCommon::Content::ClearDataDir(m_dir);
scan();
}
void DataWidget::open() {
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(FrontendCommon::DataManager::GetDataDir(m_dir))));
}
void DataWidget::scan() {
ui->size->setText(tr("Calculating..."));
QFutureWatcher<u64> *watcher = new QFutureWatcher<u64>(this);
connect(watcher, &QFutureWatcher<u64>::finished, this, [=, this]() {
u64 size = watcher->result();
ui->size->setText(
QString::fromStdString(FrontendCommon::DataManager::ReadableBytesSize(size)));
watcher->deleteLater();
});
watcher->setFuture(
QtConcurrent::run([this]() { return FrontendCommon::DataManager::DataDirSize(m_dir); }));
}

47
src/yuzu/data_dialog.h Normal file
View file

@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef DATA_DIALOG_H
#define DATA_DIALOG_H
#include <QDialog>
#include "frontend_common/data_manager.h"
#include "qt_common/qt_string_lookup.h"
#include "ui_data_widget.h"
namespace Ui {
class DataDialog;
}
class DataDialog : public QDialog
{
Q_OBJECT
public:
explicit DataDialog(QWidget *parent = nullptr);
~DataDialog();
private:
std::unique_ptr<Ui::DataDialog> ui;
};
class DataWidget : public QWidget
{
Q_OBJECT
public:
explicit DataWidget(FrontendCommon::DataManager::DataDir data_dir,
QtCommon::StringLookup::StringKey tooltip,
QWidget *parent = nullptr);
public slots:
void clear();
void open();
void scan();
private:
std::unique_ptr<Ui::DataWidget> ui;
FrontendCommon::DataManager::DataDir m_dir;
};
#endif // DATA_DIALOG_H

148
src/yuzu/data_dialog.ui Normal file
View file

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DataDialog</class>
<widget class="QDialog" name="DataDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>480</width>
<height>320</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>320</height>
</size>
</property>
<property name="windowTitle">
<string>Data Manager</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
<item>
<widget class="QListWidget" name="labels">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Saves</string>
</property>
</item>
<item>
<property name="text">
<string>Shaders</string>
</property>
</item>
<item>
<property name="text">
<string>UserNAND</string>
</property>
</item>
<item>
<property name="text">
<string>SysNAND</string>
</property>
</item>
<item>
<property name="text">
<string>Mods</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="page">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>275</width>
<height>200</height>
</size>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Deleting ANY data is IRREVERSABLE!</string>
</property>
</widget>
</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>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DataDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DataDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

147
src/yuzu/data_widget.ui Normal file
View file

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DataWidget</class>
<widget class="QWidget" name="DataWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>275</width>
<height>200</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,2">
<item>
<widget class="QLabel" name="tooltip">
<property name="text">
<string>Tooltip</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="size">
<property name="font">
<font>
<pointsize>10</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">Size</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,1">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetFixedSize</enum>
</property>
<property name="bottomMargin">
<number>25</number>
</property>
<item>
<widget class="QPushButton" name="open">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>52</width>
<height>42</height>
</size>
</property>
<property name="toolTip">
<string>Open with your system file manager</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
border-style: solid;
border-width:1px;
border-radius:25px;
border-color: transparent;
max-width:50px;
max-height:40px;
min-width:50px;
min-height:40px;
}</string>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clear">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>52</width>
<height>42</height>
</size>
</property>
<property name="toolTip">
<string>Delete all data in this directory. THIS IS 100% IRREVERSABLE!</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
border-style: solid;
border-width:1px;
border-radius:25px;
border-color: transparent;
max-width:50px;
max-height:40px;
min-width:50px;
min-height:40px;
}</string>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -156,6 +156,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/debugger/console.h" #include "yuzu/debugger/console.h"
#include "yuzu/debugger/controller.h" #include "yuzu/debugger/controller.h"
#include "yuzu/debugger/wait_tree.h" #include "yuzu/debugger/wait_tree.h"
#include "yuzu/data_dialog.h"
#include "yuzu/deps_dialog.h" #include "yuzu/deps_dialog.h"
#include "yuzu/discord.h" #include "yuzu/discord.h"
#include "yuzu/game_list.h" #include "yuzu/game_list.h"
@ -1705,6 +1706,7 @@ void GMainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys); connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
connect_menu(ui->action_About, &GMainWindow::OnAbout); connect_menu(ui->action_About, &GMainWindow::OnAbout);
connect_menu(ui->action_Eden_Dependencies, &GMainWindow::OnEdenDependencies); connect_menu(ui->action_Eden_Dependencies, &GMainWindow::OnEdenDependencies);
connect_menu(ui->action_Data_Manager, &GMainWindow::OnDataDialog);
} }
void GMainWindow::UpdateMenuState() { void GMainWindow::UpdateMenuState() {
@ -3934,6 +3936,11 @@ void GMainWindow::OnEdenDependencies() {
depsDialog.exec(); depsDialog.exec();
} }
void GMainWindow::OnDataDialog() {
DataDialog dataDialog(this);
dataDialog.exec();
}
void GMainWindow::OnToggleFilterBar() { void GMainWindow::OnToggleFilterBar() {
game_list->SetFilterVisible(ui->action_Show_Filter_Bar->isChecked()); game_list->SetFilterVisible(ui->action_Show_Filter_Bar->isChecked());
if (ui->action_Show_Filter_Bar->isChecked()) { if (ui->action_Show_Filter_Bar->isChecked()) {

View file

@ -387,6 +387,7 @@ private slots:
void OnInstallDecryptionKeys(); void OnInstallDecryptionKeys();
void OnAbout(); void OnAbout();
void OnEdenDependencies(); void OnEdenDependencies();
void OnDataDialog();
void OnToggleFilterBar(); void OnToggleFilterBar();
void OnToggleStatusBar(); void OnToggleStatusBar();
void OnGameListRefresh(); void OnGameListRefresh();

View file

@ -158,13 +158,23 @@
</property> </property>
<widget class="QMenu" name="menu_cabinet_applet"> <widget class="QMenu" name="menu_cabinet_applet">
<property name="title"> <property name="title">
<string>&amp;Amiibo</string> <string>Am&amp;iibo</string>
</property> </property>
<addaction name="action_Load_Cabinet_Nickname_Owner"/> <addaction name="action_Load_Cabinet_Nickname_Owner"/>
<addaction name="action_Load_Cabinet_Eraser"/> <addaction name="action_Load_Cabinet_Eraser"/>
<addaction name="action_Load_Cabinet_Restorer"/> <addaction name="action_Load_Cabinet_Restorer"/>
<addaction name="action_Load_Cabinet_Formatter"/> <addaction name="action_Load_Cabinet_Formatter"/>
</widget> </widget>
<widget class="QMenu" name="menu_Applets">
<property name="title">
<string>&amp;Applets</string>
</property>
<addaction name="action_Load_Home_Menu"/>
<addaction name="action_Load_Album"/>
<addaction name="action_Load_Mii_Edit"/>
<addaction name="action_Open_Controller_Menu"/>
<addaction name="action_Open_Setup"/>
</widget>
<widget class="QMenu" name="menuTAS"> <widget class="QMenu" name="menuTAS">
<property name="title"> <property name="title">
<string>&amp;TAS</string> <string>&amp;TAS</string>
@ -184,7 +194,7 @@
</widget> </widget>
<widget class="QMenu" name="menuInstall_Firmware"> <widget class="QMenu" name="menuInstall_Firmware">
<property name="title"> <property name="title">
<string>Install Firmware</string> <string>Install &amp;Firmware</string>
</property> </property>
<addaction name="action_Firmware_From_Folder"/> <addaction name="action_Firmware_From_Folder"/>
<addaction name="action_Firmware_From_ZIP"/> <addaction name="action_Firmware_From_ZIP"/>
@ -192,13 +202,10 @@
<addaction name="action_Install_Keys"/> <addaction name="action_Install_Keys"/>
<addaction name="menuInstall_Firmware"/> <addaction name="menuInstall_Firmware"/>
<addaction name="action_Verify_installed_contents"/> <addaction name="action_Verify_installed_contents"/>
<addaction name="action_Data_Manager"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="menu_cabinet_applet"/> <addaction name="menu_cabinet_applet"/>
<addaction name="action_Load_Album"/> <addaction name="menu_Applets"/>
<addaction name="action_Load_Mii_Edit"/>
<addaction name="action_Open_Controller_Menu"/>
<addaction name="action_Load_Home_Menu"/>
<addaction name="action_Open_Setup"/>
<addaction name="menu_Create_Shortcuts"/> <addaction name="menu_Create_Shortcuts"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="action_Capture_Screenshot"/> <addaction name="action_Capture_Screenshot"/>
@ -497,12 +504,12 @@
</action> </action>
<action name="action_Install_Keys"> <action name="action_Install_Keys">
<property name="text"> <property name="text">
<string>Install Decryption Keys</string> <string>Install Decryption &amp;Keys</string>
</property> </property>
</action> </action>
<action name="action_Load_Home_Menu"> <action name="action_Load_Home_Menu">
<property name="text"> <property name="text">
<string>Open Home Menu</string> <string>Open &amp;Home Menu</string>
</property> </property>
</action> </action>
<action name="action_Discord"> <action name="action_Discord">
@ -593,6 +600,11 @@
<string>&amp;Eden Dependencies</string> <string>&amp;Eden Dependencies</string>
</property> </property>
</action> </action>
<action name="action_Data_Manager">
<property name="text">
<string>&amp;Data Manager</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="yuzu.qrc"/> <include location="yuzu.qrc"/>