data dialog rewrite

Signed-off-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
crueter 2025-10-08 22:45:33 -04:00
parent c302c1b1a3
commit 1c186d9280
15 changed files with 304 additions and 170 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/chip.png">icons/48x48/chip.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/no_avatar.png">icons/48x48/no_avatar.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/chip.png">../colorful/icons/48x48/chip.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/sd_card.png">../colorful/icons/48x48/sd_card.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/chip.png">icons/48x48/chip.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/sd_card.png">icons/48x48/sd_card.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/chip.png">../colorful/icons/48x48/chip.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/list-add.png">../colorful/icons/48x48/list-add.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/chip.png">icons/48x48/chip.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/list-add.png">icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>

View file

@ -23,11 +23,11 @@ enum StringKey {
};
static constexpr const frozen::unordered_map<StringKey, frozen::string, 5> strings = {
{SavesTooltip, "DO NOT REMOVE UNLESS YOU KNOW WHAT YOU'RE DOING!"},
{ShadersTooltip, "Shader pipeline caches. Generally safe to remove."},
{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 all of your mod data."},
{ModsTooltip, "Contains game mods, patches, and cheats."},
};
static inline const QString Lookup(StringKey key)

View file

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

View file

@ -4,17 +4,12 @@
#include "data_dialog.h"
#include "frontend_common/data_manager.h"
#include "qt_common/qt_content_util.h"
#include "qt_common/qt_frontend_util.h"
#include "qt_common/qt_progress_dialog.h"
#include "qt_common/qt_string_lookup.h"
#include "ui_data_dialog.h"
#include <QDesktopServices>
#include <QFutureWatcher>
#include <QMenu>
#include <QProgressDialog>
#include <QtConcurrent/qtconcurrentrun.h>
#include <qnamespace.h>
#include <QtConcurrent/QtConcurrentRun>
DataDialog::DataDialog(QWidget *parent)
: QDialog(parent)
@ -22,86 +17,69 @@ DataDialog::DataDialog(QWidget *parent)
{
ui->setupUi(this);
std::size_t row = 0;
#define TABLE_ITEM(label, name, data_dir) \
QTableWidgetItem *name##Label = new QTableWidgetItem(tr(label)); \
name##Label->setToolTip( \
QtCommon::StringLookup::Lookup(QtCommon::StringLookup::data_dir##Tooltip)); \
ui->sizes->setItem(row, 0, name##Label); \
DataItem *name##Item = new DataItem(FrontendCommon::DataManager::DataDir::data_dir, this); \
ui->sizes->setItem(row, 1, name##Item); \
++row;
// 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));
TABLE_ITEM("Saves", save, Saves)
TABLE_ITEM("Shaders", shaders, Shaders)
TABLE_ITEM("UserNAND", user, UserNand)
TABLE_ITEM("SysNAND", sys, SysNand)
TABLE_ITEM("Mods", mods, Mods)
WIDGET(Saves)
WIDGET(Shaders)
WIDGET(UserNand)
WIDGET(SysNand)
WIDGET(Mods)
#undef TABLE_ITEM
#undef WIDGET
QObject::connect(ui->sizes, &QTableWidget::customContextMenuRequested, this, [this]() {
auto items = ui->sizes->selectedItems();
if (items.empty())
return;
QTableWidgetItem *selected = items.at(0);
DataItem *item = (DataItem *) ui->sizes->item(selected->row(), 1);
QMenu *menu = new QMenu(this);
QAction *open = menu->addAction(tr("Open"));
QObject::connect(open, &QAction::triggered, this, [item]() {
auto data_dir
= item->data(DataItem::DATA_DIR).value<FrontendCommon::DataManager::DataDir>();
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(FrontendCommon::DataManager::GetDataDir(data_dir))));
});
QAction *clear = menu->addAction(tr("Clear"));
QObject::connect(clear, &QAction::triggered, this, [item]() {
auto data_dir
= item->data(DataItem::DATA_DIR).value<FrontendCommon::DataManager::DataDir>();
QtCommon::Content::ClearDataDir(data_dir);
item->scan();
});
menu->exec(QCursor::pos());
connect(ui->labels, &QListWidget::itemSelectionChanged, this, [this]() {
ui->page->setCurrentIndex(ui->labels->currentRow());
});
}
DataDialog::~DataDialog() = default;
DataItem::DataItem(FrontendCommon::DataManager::DataDir data_dir, QWidget *parent)
: QTableWidgetItem(QObject::tr("Calculating"))
, m_parent(parent)
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)
{
setData(DataItem::DATA_DIR, QVariant::fromValue(m_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();
}
bool DataItem::operator<(const QTableWidgetItem &other) const
{
return this->data(DataRole::SIZE).toULongLong() < other.data(DataRole::SIZE).toULongLong();
void DataWidget::clear() {
QtCommon::Content::ClearDataDir(m_dir);
scan();
}
void DataItem::reset() {
setText(QStringLiteral("0 B"));
setData(DataItem::SIZE, QVariant::fromValue(0ULL));
void DataWidget::open() {
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(FrontendCommon::DataManager::GetDataDir(m_dir))));
}
void DataItem::scan() {
m_watcher = new QFutureWatcher<u64>(m_parent);
void DataWidget::scan() {
ui->size->setText(tr("Calculating..."));
m_parent->connect(m_watcher, &QFutureWatcher<u64>::finished, m_parent, [=, this]() {
u64 size = m_watcher->result();
setText(QString::fromStdString(FrontendCommon::DataManager::ReadableBytesSize(size)));
setData(DataItem::SIZE, QVariant::fromValue(size));
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();
});
m_watcher->setFuture(
watcher->setFuture(
QtConcurrent::run([this]() { return FrontendCommon::DataManager::DataDirSize(m_dir); }));
}

View file

@ -5,11 +5,10 @@
#define DATA_DIALOG_H
#include <QDialog>
#include <QFutureWatcher>
#include <QSortFilterProxyModel>
#include <QTableWidgetItem>
#include "frontend_common/data_manager.h"
#include <qnamespace.h>
#include "qt_common/qt_string_lookup.h"
#include "ui_data_widget.h"
namespace Ui {
class DataDialog;
@ -27,19 +26,21 @@ private:
std::unique_ptr<Ui::DataDialog> ui;
};
class DataItem : public QTableWidgetItem
class DataWidget : public QWidget
{
Q_OBJECT
public:
DataItem(FrontendCommon::DataManager::DataDir data_dir, QWidget *parent);
enum DataRole { SIZE = Qt::UserRole + 1, DATA_DIR };
explicit DataWidget(FrontendCommon::DataManager::DataDir data_dir,
QtCommon::StringLookup::StringKey tooltip,
QWidget *parent = nullptr);
bool operator<(const QTableWidgetItem &other) const;
void reset();
public slots:
void clear();
void open();
void scan();
private:
QWidget *m_parent;
QFutureWatcher<u64> *m_watcher = nullptr;
std::unique_ptr<Ui::DataWidget> ui;
FrontendCommon::DataManager::DataDir m_dir;
};

View file

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>350</height>
<width>480</width>
<height>320</height>
</rect>
</property>
<property name="sizePolicy">
@ -27,90 +27,86 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Right-click on an item to either open it or clear it. Hold your mouse over an item to see more information about it.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
<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>
<widget class="QTableWidget" name="sizes">
<property name="contextMenuPolicy">
<enum>Qt::ContextMenuPolicy::CustomContextMenu</enum>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>10</number>
</property>
<property name="editTriggers">
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>80</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<row>
<property name="text">
<string>New Row</string>
</property>
</row>
<row>
<property name="text">
<string>0</string>
</property>
</row>
<row>
<property name="text">
<string>1</string>
</property>
</row>
<row>
<property name="text">
<string>2</string>
</property>
</row>
<row>
<property name="text">
<string>4</string>
</property>
</row>
<column>
<property name="text">
<string>Directory</string>
</property>
</column>
<column>
<property name="text">
<string>Size</string>
</property>
</column>
</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>
<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>

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

@ -165,6 +165,16 @@
<addaction name="action_Load_Cabinet_Restorer"/>
<addaction name="action_Load_Cabinet_Formatter"/>
</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">
<property name="title">
<string>&amp;TAS</string>
@ -195,11 +205,7 @@
<addaction name="action_Data_Manager"/>
<addaction name="separator"/>
<addaction name="menu_cabinet_applet"/>
<addaction name="action_Load_Album"/>
<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_Applets"/>
<addaction name="menu_Create_Shortcuts"/>
<addaction name="separator"/>
<addaction name="action_Capture_Screenshot"/>
@ -503,7 +509,7 @@
</action>
<action name="action_Load_Home_Menu">
<property name="text">
<string>Open Home Menu</string>
<string>Open &amp;Home Menu</string>
</property>
</action>
<action name="action_Discord">