#include "stdafx.h" #include "game_list_base.h" #include "localized.h" #include #include #include LOG_CHANNEL(game_list_log, "GameList"); game_list_base::game_list_base() { } void game_list_base::repaint_icons(QList& game_data, const QColor& icon_color, const QSize& icon_size, qreal device_pixel_ratio) { m_icon_size = icon_size; m_icon_color = icon_color; QPixmap placeholder(icon_size * device_pixel_ratio); placeholder.setDevicePixelRatio(device_pixel_ratio); placeholder.fill(Qt::transparent); for (game_info& game : game_data) { game->pxmap = placeholder; if (movie_item_base* item = game->item) { item->set_icon_load_func([this, game, device_pixel_ratio, cancel = item->icon_loading_aborted()](int) { IconLoadFunction(game, device_pixel_ratio, cancel); }); item->call_icon_func(); } } } void game_list_base::IconLoadFunction(game_info game, qreal device_pixel_ratio, std::shared_ptr> cancel) { if (cancel && cancel->load()) { return; } static std::unordered_set warn_once_list; static shared_mutex s_mtx; if (game->icon.isNull() && (game->info.icon_path.empty() || !game->icon.load(QString::fromStdString(game->info.icon_path)))) { if (game_list_log.warning) { bool logged = false; { std::lock_guard lock(s_mtx); logged = !warn_once_list.emplace(game->info.icon_path).second; } if (!logged) { game_list_log.warning("Could not load image from path %s", QDir(QString::fromStdString(game->info.icon_path)).absolutePath()); } } } if (!game->item || (cancel && cancel->load())) { return; } const QColor color = GetGridCompatibilityColor(game->compat.color); { std::lock_guard lock(game->item->pixmap_mutex); game->pxmap = PaintedPixmap(game->icon, device_pixel_ratio, game->hasCustomConfig, game->hasCustomPadConfig, color); } if (!cancel || !cancel->load()) { if (m_icon_ready_callback) m_icon_ready_callback(game); } } QPixmap game_list_base::PaintedPixmap(const QPixmap& icon, qreal device_pixel_ratio, bool paint_config_icon, bool paint_pad_config_icon, const QColor& compatibility_color) const { QSize canvas_size(320, 176); QSize icon_size(icon.size()); QPoint target_pos; if (!icon.isNull()) { // Let's upscale the original icon to at least fit into the outer rect of the size of PS3's ICON0.PNG if (icon_size.width() < 320 || icon_size.height() < 176) { icon_size.scale(320, 176, Qt::KeepAspectRatio); } canvas_size = icon_size; // Calculate the centered size and position of the icon on our canvas. if (icon_size.width() != 320 || icon_size.height() != 176) { ensure(icon_size.height() > 0); constexpr double target_ratio = 320.0 / 176.0; // aspect ratio 20:11 if ((icon_size.width() / static_cast(icon_size.height())) > target_ratio) { canvas_size.setHeight(std::ceil(icon_size.width() / target_ratio)); } else { canvas_size.setWidth(std::ceil(icon_size.height() * target_ratio)); } target_pos.setX(std::max(0, (canvas_size.width() - icon_size.width()) / 2.0)); target_pos.setY(std::max(0, (canvas_size.height() - icon_size.height()) / 2.0)); } } // Create a canvas large enough to fit our entire scaled icon QPixmap canvas(canvas_size * device_pixel_ratio); canvas.setDevicePixelRatio(device_pixel_ratio); canvas.fill(m_icon_color); // Create a painter for our canvas QPainter painter(&canvas); painter.setRenderHint(QPainter::SmoothPixmapTransform); // Draw the icon onto our canvas if (!icon.isNull()) { painter.drawPixmap(target_pos.x(), target_pos.y(), icon_size.width(), icon_size.height(), icon); } // Draw config icons if necessary if (!m_is_list_layout && (paint_config_icon || paint_pad_config_icon)) { const int width = canvas_size.width() * 0.2; const QPoint origin = QPoint(canvas_size.width() - width, 0); QString icon_path; if (paint_config_icon && paint_pad_config_icon) { icon_path = ":/Icons/combo_config_bordered.png"; } else if (paint_config_icon) { icon_path = ":/Icons/custom_config.png"; } else if (paint_pad_config_icon) { icon_path = ":/Icons/controllers.png"; } QPixmap custom_config_icon(icon_path); custom_config_icon.setDevicePixelRatio(device_pixel_ratio); painter.drawPixmap(origin, custom_config_icon.scaled(QSize(width, width) * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation)); } // Draw game compatibility icons if necessary if (compatibility_color.isValid()) { const int size = canvas_size.height() * 0.2; const int spacing = canvas_size.height() * 0.05; QColor copyColor = QColor(compatibility_color); copyColor.setAlpha(215); // ~85% opacity painter.setRenderHint(QPainter::Antialiasing); painter.setBrush(QBrush(copyColor)); painter.setPen(QPen(Qt::black, std::max(canvas_size.width() / 320, canvas_size.height() / 176))); painter.drawEllipse(spacing, spacing, size, size); } // Finish the painting painter.end(); // Scale and return our final image return canvas.scaled(m_icon_size * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation); } QColor game_list_base::GetGridCompatibilityColor(const QString& string) const { if (m_draw_compat_status_to_grid && !m_is_list_layout) { return QColor(string); } return QColor(); } std::string game_list_base::GetGameVersion(const game_info& game) { if (game->info.app_ver == Localized().category.unknown.toStdString()) { // Fall back to Disc/Pkg Revision return game->info.version; } return game->info.app_ver; } QIcon game_list_base::GetCustomConfigIcon(const game_info& game) { if (!game) return {}; static const QIcon icon_combo_config_bordered(":/Icons/combo_config_bordered.png"); static const QIcon icon_custom_config(":/Icons/custom_config.png"); static const QIcon icon_controllers(":/Icons/controllers.png"); if (game->hasCustomConfig && game->hasCustomPadConfig) { return icon_combo_config_bordered; } if (game->hasCustomConfig) { return icon_custom_config; } if (game->hasCustomPadConfig) { return icon_controllers; } return {}; }