|
12 | 12 |
|
13 | 13 | #include "common/Assertions.h"
|
14 | 14 | #include "common/Console.h"
|
| 15 | +#include "common/Path.h" |
15 | 16 | #include "common/StringUtil.h"
|
16 | 17 |
|
17 | 18 | #include "fmt/format.h"
|
18 | 19 |
|
19 | 20 | #include <QtCore/QSortFilterProxyModel>
|
| 21 | +#include <QtCore/QDir> |
| 22 | +#include <QtCore/QString> |
20 | 23 | #include <QtGui/QPainter>
|
21 | 24 | #include <QtGui/QPixmap>
|
22 | 25 | #include <QtGui/QPixmapCache>
|
23 | 26 | #include <QtGui/QWheelEvent>
|
24 | 27 | #include <QtWidgets/QApplication>
|
| 28 | +#include <QtWidgets/QFileDialog> |
25 | 29 | #include <QtWidgets/QHeaderView>
|
26 | 30 | #include <QtWidgets/QMenu>
|
27 | 31 | #include <QtWidgets/QScrollBar>
|
@@ -280,6 +284,92 @@ void GameListWidget::initialize()
|
280 | 284 |
|
281 | 285 | updateToolbar();
|
282 | 286 | resizeTableViewColumnsToFit();
|
| 287 | + setCustomBackground(false); |
| 288 | +} |
| 289 | + |
| 290 | +static void resizeAndPadImage(QImage* image, int expected_width, int expected_height, bool fill_with_top_left) |
| 291 | +{ |
| 292 | + const qreal dpr = image->devicePixelRatio(); |
| 293 | + const int dpr_expected_width = static_cast<int>(static_cast<qreal>(expected_width) * dpr); |
| 294 | + const int dpr_expected_height = static_cast<int>(static_cast<qreal>(expected_height) * dpr); |
| 295 | + if (image->width() == dpr_expected_width && image->height() == dpr_expected_height) |
| 296 | + return; |
| 297 | + |
| 298 | + if ((static_cast<float>(image->width()) / static_cast<float>(image->height())) >= |
| 299 | + (static_cast<float>(dpr_expected_width) / static_cast<float>(dpr_expected_height))) |
| 300 | + { |
| 301 | + *image = image->scaledToWidth(dpr_expected_width, Qt::SmoothTransformation); |
| 302 | + } |
| 303 | + else |
| 304 | + { |
| 305 | + *image = image->scaledToHeight(dpr_expected_height, Qt::SmoothTransformation); |
| 306 | + } |
| 307 | + |
| 308 | + if (image->width() == dpr_expected_width && image->height() == dpr_expected_height) |
| 309 | + return; |
| 310 | + |
| 311 | + int xoffs = 0; |
| 312 | + int yoffs = 0; |
| 313 | + const int image_width = image->width(); |
| 314 | + const int image_height = image->height(); |
| 315 | + if (image_width < dpr_expected_width) |
| 316 | + xoffs = static_cast<int>(static_cast<qreal>((dpr_expected_width - image_width) / 2) / dpr); |
| 317 | + if (image_height < dpr_expected_height) |
| 318 | + yoffs = static_cast<int>(static_cast<qreal>((dpr_expected_height - image_height) / 2) / dpr); |
| 319 | + |
| 320 | + QImage padded_image(dpr_expected_width, dpr_expected_height, QImage::Format_ARGB32); |
| 321 | + padded_image.setDevicePixelRatio(dpr); |
| 322 | + if (fill_with_top_left) |
| 323 | + padded_image.fill(image->pixel(0, 0)); |
| 324 | + else |
| 325 | + padded_image.fill(Qt::transparent); |
| 326 | + |
| 327 | + QPainter painter; |
| 328 | + if (painter.begin(&padded_image)) |
| 329 | + { |
| 330 | + painter.setCompositionMode(QPainter::CompositionMode_Source); |
| 331 | + painter.drawImage(xoffs, yoffs, *image); |
| 332 | + painter.end(); |
| 333 | + } |
| 334 | + |
| 335 | + *image = std::move(padded_image); |
| 336 | +} |
| 337 | + |
| 338 | +void GameListWidget::setCustomBackground(bool reload) |
| 339 | +{ |
| 340 | + std::string path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath"); |
| 341 | + if (path.empty()) |
| 342 | + return; |
| 343 | + |
| 344 | + if (!Path::IsAbsolute(path)) |
| 345 | + path = Path::Combine(EmuFolders::DataRoot, path); |
| 346 | + |
| 347 | + if (reload) |
| 348 | + { |
| 349 | + m_background_image = QImage(); |
| 350 | + if (!path.empty() && m_background_image.load(path.c_str())) |
| 351 | + m_background_image.setDevicePixelRatio(devicePixelRatio()); |
| 352 | + } |
| 353 | + |
| 354 | + if (m_background_image.isNull() || path.empty()) |
| 355 | + { |
| 356 | + m_ui.stack->setPalette(QApplication::palette()); |
| 357 | + m_table_view->setAlternatingRowColors(true); |
| 358 | + return; |
| 359 | + } |
| 360 | + |
| 361 | + int widget_width = m_ui.stack->width(); |
| 362 | + int widget_height = m_ui.stack->height(); |
| 363 | + |
| 364 | + resizeAndPadImage(&m_background_image, widget_width, widget_height, false); |
| 365 | + |
| 366 | + if (widget_width != m_ui.stack->width() || widget_height != m_ui.stack->height()) |
| 367 | + return; |
| 368 | + |
| 369 | + m_table_view->setAlternatingRowColors(false); |
| 370 | + QPalette new_palette(m_ui.stack->palette()); |
| 371 | + new_palette.setBrush(QPalette::Base, QPixmap::fromImage(m_background_image)); |
| 372 | + m_ui.stack->setPalette(new_palette); |
283 | 373 | }
|
284 | 374 |
|
285 | 375 | bool GameListWidget::isShowingGameList() const
|
@@ -467,6 +557,28 @@ void GameListWidget::refreshGridCovers()
|
467 | 557 | m_model->refreshCovers();
|
468 | 558 | }
|
469 | 559 |
|
| 560 | +void GameListWidget::onViewSetGameListBackgroundTriggered() |
| 561 | +{ |
| 562 | + const QString path = QDir::toNativeSeparators( |
| 563 | + QFileDialog::getOpenFileName(this, tr("Select Background Image"), QString(), tr("Supported Image Types (*.jpg *.jpeg *.png *.webp)"))); |
| 564 | + if (path.isEmpty()) |
| 565 | + return; |
| 566 | + |
| 567 | + std::string relative_path = Path::MakeRelative(QDir::toNativeSeparators(path).toStdString(), EmuFolders::DataRoot); |
| 568 | + Host::SetBaseStringSettingValue("UI", "GameListBackgroundPath", relative_path.c_str()); |
| 569 | + Host::CommitBaseSettingChanges(); |
| 570 | + setCustomBackground(true); |
| 571 | +} |
| 572 | + |
| 573 | +void GameListWidget::onViewClearGameListBackgroundTriggered() |
| 574 | +{ |
| 575 | + Host::RemoveBaseSettingValue("UI", "GameListBackgroundPath"); |
| 576 | + Host::CommitBaseSettingChanges(); |
| 577 | + updateToolbar(); |
| 578 | + resizeTableViewColumnsToFit(); |
| 579 | + setCustomBackground(true); |
| 580 | +} |
| 581 | + |
470 | 582 | void GameListWidget::showGameList()
|
471 | 583 | {
|
472 | 584 | if (m_ui.stack->currentIndex() == 0 || m_model->rowCount() == 0)
|
@@ -545,6 +657,7 @@ void GameListWidget::resizeEvent(QResizeEvent* event)
|
545 | 657 | QWidget::resizeEvent(event);
|
546 | 658 | resizeTableViewColumnsToFit();
|
547 | 659 | m_model->updateCacheSize(width(), height());
|
| 660 | + setCustomBackground(true); |
548 | 661 | }
|
549 | 662 |
|
550 | 663 | void GameListWidget::resizeTableViewColumnsToFit()
|
|
0 commit comments