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();