diff --git a/dist/themes/default/default.qrc b/dist/themes/default/default.qrc
new file mode 100644
index 0000000..6c5952d
--- /dev/null
+++ b/dist/themes/default/default.qrc
@@ -0,0 +1,19 @@
+
+
+ icons/index.theme
+
+ icons/24x24/app.png
+
+ icons/24x24/dlc.png
+
+ icons/24x24/save_data.png
+
+ icons/24x24/system_archive.png
+
+ icons/24x24/system_data.png
+
+ icons/24x24/unknown.png
+
+ icons/24x24/update.png
+
+
diff --git a/dist/themes/default/icons/24x24/app.png b/dist/themes/default/icons/24x24/app.png
new file mode 100644
index 0000000..0176791
Binary files /dev/null and b/dist/themes/default/icons/24x24/app.png differ
diff --git a/dist/themes/default/icons/24x24/dlc.png b/dist/themes/default/icons/24x24/dlc.png
new file mode 100644
index 0000000..61c6fa3
Binary files /dev/null and b/dist/themes/default/icons/24x24/dlc.png differ
diff --git a/dist/themes/default/icons/24x24/save_data.png b/dist/themes/default/icons/24x24/save_data.png
new file mode 100644
index 0000000..d35c8b1
Binary files /dev/null and b/dist/themes/default/icons/24x24/save_data.png differ
diff --git a/dist/themes/default/icons/24x24/system_archive.png b/dist/themes/default/icons/24x24/system_archive.png
new file mode 100644
index 0000000..75c7e2b
Binary files /dev/null and b/dist/themes/default/icons/24x24/system_archive.png differ
diff --git a/dist/themes/default/icons/24x24/system_data.png b/dist/themes/default/icons/24x24/system_data.png
new file mode 100644
index 0000000..e816083
Binary files /dev/null and b/dist/themes/default/icons/24x24/system_data.png differ
diff --git a/dist/themes/default/icons/24x24/unknown.png b/dist/themes/default/icons/24x24/unknown.png
new file mode 100644
index 0000000..1991c1e
Binary files /dev/null and b/dist/themes/default/icons/24x24/unknown.png differ
diff --git a/dist/themes/default/icons/24x24/update.png b/dist/themes/default/icons/24x24/update.png
new file mode 100644
index 0000000..90da7a2
Binary files /dev/null and b/dist/themes/default/icons/24x24/update.png differ
diff --git a/dist/themes/default/icons/index.theme b/dist/themes/default/icons/index.theme
new file mode 100644
index 0000000..b5525bb
--- /dev/null
+++ b/dist/themes/default/icons/index.theme
@@ -0,0 +1,7 @@
+[Icon Theme]
+Name=default
+Comment=default theme
+Directories=24x24
+
+[24x24]
+Size=24
diff --git a/license.txt b/license.txt
index d511905..040eb5b 100644
--- a/license.txt
+++ b/license.txt
@@ -337,3 +337,8 @@ proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
+
+---
+
+The icons used in this project are from https://github.com/google/material-design-icons,
+licensed under Apache License 2.0.
diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt
index 06d0af6..851a735 100644
--- a/src/frontend/CMakeLists.txt
+++ b/src/frontend/CMakeLists.txt
@@ -6,6 +6,8 @@ if (POLICY CMP0071)
cmake_policy(SET CMP0071 NEW)
endif()
+file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/themes/*)
+
add_executable(threeSD
import_dialog.cpp
import_dialog.h
@@ -15,6 +17,7 @@ add_executable(threeSD
main.cpp
main.h
main.ui
+ ${THEMES}
)
target_link_libraries(threeSD PRIVATE common core)
diff --git a/src/frontend/import_dialog.cpp b/src/frontend/import_dialog.cpp
index 0283b2b..4415692 100644
--- a/src/frontend/import_dialog.cpp
+++ b/src/frontend/import_dialog.cpp
@@ -31,15 +31,17 @@ QString ReadableByteSize(qulonglong size) {
.arg(QObject::tr(units[digit_groups], "ImportDialog"));
}
-static constexpr std::array, 7> ContentTypeMap{{
- {Core::ContentType::Application, QT_TR_NOOP("Application")},
- {Core::ContentType::Update, QT_TR_NOOP("Update")},
- {Core::ContentType::DLC, QT_TR_NOOP("DLC")},
- {Core::ContentType::Savegame, QT_TR_NOOP("Save Data")},
- {Core::ContentType::Extdata, QT_TR_NOOP("Extra Data")},
- {Core::ContentType::SystemArchive, QT_TR_NOOP("System Archive")},
- {Core::ContentType::Sysdata, QT_TR_NOOP("System Data")},
-}};
+// content type, name, icon name
+static constexpr std::array, 7>
+ ContentTypeMap{{
+ {Core::ContentType::Application, QT_TR_NOOP("Application"), "app"},
+ {Core::ContentType::Update, QT_TR_NOOP("Update"), "update"},
+ {Core::ContentType::DLC, QT_TR_NOOP("DLC"), "dlc"},
+ {Core::ContentType::Savegame, QT_TR_NOOP("Save Data"), "save_data"},
+ {Core::ContentType::Extdata, QT_TR_NOOP("Extra Data"), "save_data"},
+ {Core::ContentType::SystemArchive, QT_TR_NOOP("System Archive"), "system_archive"},
+ {Core::ContentType::Sysdata, QT_TR_NOOP("System Data"), "system_data"},
+ }};
static const std::unordered_map EncryptionTypeMap{{
{Core::EncryptionType::None, QT_TR_NOOP("None")},
@@ -57,10 +59,22 @@ QString GetContentName(const Core::ContentSpecifier& specifier) {
}
QString GetContentTypeName(Core::ContentType type) {
- return QObject::tr(ContentTypeMap.at(static_cast(type)).second, "ImportDialog");
+ return QObject::tr(std::get<1>(ContentTypeMap.at(static_cast(type))),
+ "ImportDialog");
}
-QPixmap GetContentIcon(const Core::ContentSpecifier& specifier) {
+QPixmap GetContentTypeIcon(Core::ContentType type) {
+ return QIcon::fromTheme(
+ QString::fromUtf8(std::get<2>(ContentTypeMap.at(static_cast(type)))))
+ .pixmap(24);
+}
+
+QPixmap GetContentIcon(const Core::ContentSpecifier& specifier, bool use_category_icon = false) {
+ if (specifier.icon.empty()) {
+ // Return a category icon, or a null icon
+ return use_category_icon ? GetContentTypeIcon(specifier.type)
+ : QIcon::fromTheme(QStringLiteral("unknown")).pixmap(24);
+ }
return QPixmap::fromImage(QImage(reinterpret_cast(specifier.icon.data()), 24, 24,
QImage::Format::Format_RGB16));
}
@@ -179,8 +193,10 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe
// HACK: The checkbox is used to record ID. Is there a better way?
checkBox->setProperty("id", id);
+ const bool use_title_view = ui->title_view_button->isChecked();
+
QString name;
- if (ui->title_view_button->isChecked()) {
+ if (use_title_view) {
if (row == 0) {
name = QStringLiteral("%1 (%2)")
.arg(GetContentName(content))
@@ -214,11 +230,17 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe
{QString{}, name, ReadableByteSize(content.maximum_size), encryption,
content.already_exists ? QStringLiteral("Yes") : QStringLiteral("No")}};
- if (!ui->title_view_button->isChecked()) {
- // Display icon when present
- item->setData(1, Qt::DecorationRole,
- replace_icon.isNull() ? GetContentIcon(content) : replace_icon);
+ QPixmap icon;
+ if (replace_icon.isNull()) {
+ // When not in title view, only System Data and System Archive groups use category icons.
+ const bool use_category_icon = content.type == Core::ContentType::Sysdata ||
+ content.type == Core::ContentType::SystemArchive;
+ icon = use_title_view ? GetContentTypeIcon(content.type)
+ : GetContentIcon(content, use_category_icon);
+ } else {
+ icon = replace_icon;
}
+ item->setData(1, Qt::DecorationRole, icon);
ui->main->invisibleRootItem()->child(row)->addChild(item);
ui->main->setItemWidget(item, 0, checkBox);
@@ -276,6 +298,10 @@ void ImportDialog::RepopulateContent() {
title_name_map.insert_or_assign(1, tr("System Archive"));
title_name_map.insert_or_assign(2, tr("System Data"));
+ title_icon_map.insert_or_assign(0, QIcon::fromTheme(QStringLiteral("unknown")).pixmap(24));
+ title_icon_map.insert_or_assign(1, GetContentTypeIcon(Core::ContentType::SystemArchive));
+ title_icon_map.insert_or_assign(2, GetContentTypeIcon(Core::ContentType::Sysdata));
+
std::unordered_map title_row_map;
for (const auto& [id, name] : title_name_map) {
InsertTopLevelItem(name, title_icon_map.count(id) ? title_icon_map.at(id) : QPixmap{});
@@ -316,8 +342,8 @@ void ImportDialog::RepopulateContent() {
InsertSecondLevelItem(row, content, i);
}
} else {
- for (const auto& [type, name] : ContentTypeMap) {
- InsertTopLevelItem(tr(name));
+ for (const auto& [type, name, _] : ContentTypeMap) {
+ InsertTopLevelItem(tr(name), GetContentTypeIcon(type));
}
for (std::size_t i = 0; i < contents.size(); ++i) {
diff --git a/src/frontend/main.cpp b/src/frontend/main.cpp
index a76fe1a..55849dd 100644
--- a/src/frontend/main.cpp
+++ b/src/frontend/main.cpp
@@ -219,6 +219,9 @@ int main(int argc, char* argv[]) {
QApplication app(argc, argv);
+ QIcon::setThemeSearchPaths(QStringList(QStringLiteral(":/icons/default")));
+ QIcon::setThemeName(QStringLiteral(":/icons/default"));
+
MainDialog main_dialog;
main_dialog.show();