mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-29 09:05:41 +00:00
Qt: PCSX2 UI fix backports
This commit is contained in:
parent
546f73e36a
commit
dd1a00674d
|
@ -32,7 +32,8 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||||
m_ui.enableXInputSource->setEnabled(false);
|
m_ui.enableXInputSource->setEnabled(false);
|
||||||
m_ui.enableRawInput->setEnabled(false);
|
m_ui.enableRawInput->setEnabled(false);
|
||||||
#endif
|
#endif
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableMouseMapping, "UI", "EnableMouseMapping", false);
|
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableMouseMapping, "UI", "EnableMouseMapping",
|
||||||
|
false);
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.multitapMode, "ControllerPorts", "MultitapMode",
|
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.multitapMode, "ControllerPorts", "MultitapMode",
|
||||||
&Settings::ParseMultitapModeName, &Settings::GetMultitapModeName,
|
&Settings::ParseMultitapModeName, &Settings::GetMultitapModeName,
|
||||||
Settings::DEFAULT_MULTITAP_MODE);
|
Settings::DEFAULT_MULTITAP_MODE);
|
||||||
|
|
|
@ -114,11 +114,11 @@ const char* GameListModel::getColumnName(Column col)
|
||||||
return s_column_names[static_cast<int>(col)];
|
return s_column_names[static_cast<int>(col)];
|
||||||
}
|
}
|
||||||
|
|
||||||
GameListModel::GameListModel(QObject* parent /* = nullptr */)
|
GameListModel::GameListModel(float cover_scale, bool show_cover_titles, QObject* parent /* = nullptr */)
|
||||||
: QAbstractTableModel(parent), m_cover_pixmap_cache(MIN_COVER_CACHE_SIZE)
|
: QAbstractTableModel(parent), m_show_titles_for_covers(show_cover_titles)
|
||||||
{
|
{
|
||||||
loadCommonImages();
|
loadCommonImages();
|
||||||
setCoverScale(1.0f);
|
setCoverScale(cover_scale);
|
||||||
setColumnDisplayNames();
|
setColumnDisplayNames();
|
||||||
}
|
}
|
||||||
GameListModel::~GameListModel() = default;
|
GameListModel::~GameListModel() = default;
|
||||||
|
@ -132,6 +132,8 @@ void GameListModel::setCoverScale(float scale)
|
||||||
m_cover_scale = scale;
|
m_cover_scale = scale;
|
||||||
m_loading_pixmap = QPixmap(getCoverArtWidth(), getCoverArtHeight());
|
m_loading_pixmap = QPixmap(getCoverArtWidth(), getCoverArtHeight());
|
||||||
m_loading_pixmap.fill(QColor(0, 0, 0, 0));
|
m_loading_pixmap.fill(QColor(0, 0, 0, 0));
|
||||||
|
|
||||||
|
emit coverScaleChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListModel::refreshCovers()
|
void GameListModel::refreshCovers()
|
||||||
|
@ -150,9 +152,9 @@ void GameListModel::updateCacheSize(int width, int height)
|
||||||
m_cover_pixmap_cache.SetMaxCapacity(static_cast<int>(std::max(num_columns * num_rows, MIN_COVER_CACHE_SIZE)));
|
m_cover_pixmap_cache.SetMaxCapacity(static_cast<int>(std::max(num_columns * num_rows, MIN_COVER_CACHE_SIZE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListModel::reloadCommonImages()
|
void GameListModel::reloadThemeSpecificImages()
|
||||||
{
|
{
|
||||||
loadCommonImages();
|
loadThemeSpecificImages();
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,17 +587,24 @@ bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListModel::loadCommonImages()
|
void GameListModel::loadThemeSpecificImages()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < static_cast<u32>(GameList::EntryType::Count); i++)
|
for (u32 i = 0; i < static_cast<u32>(GameList::EntryType::Count); i++)
|
||||||
m_type_pixmaps[i] = QtUtils::GetIconForEntryType(static_cast<GameList::EntryType>(i)).pixmap(QSize(24, 24));
|
m_type_pixmaps[i] = QtUtils::GetIconForEntryType(static_cast<GameList::EntryType>(i)).pixmap(QSize(24, 24));
|
||||||
|
|
||||||
for (u32 i = 0; i < static_cast<u32>(DiscRegion::Count); i++)
|
for (u32 i = 0; i < static_cast<u32>(DiscRegion::Count); i++)
|
||||||
m_region_pixmaps[i] = QtUtils::GetIconForRegion(static_cast<DiscRegion>(i)).pixmap(42, 30);
|
m_region_pixmaps[i] = QtUtils::GetIconForRegion(static_cast<DiscRegion>(i)).pixmap(42, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameListModel::loadCommonImages()
|
||||||
|
{
|
||||||
|
loadThemeSpecificImages();
|
||||||
|
|
||||||
for (int i = 0; i < static_cast<int>(GameDatabase::CompatibilityRating::Count); i++)
|
for (int i = 0; i < static_cast<int>(GameDatabase::CompatibilityRating::Count); i++)
|
||||||
|
{
|
||||||
m_compatibility_pixmaps[i] =
|
m_compatibility_pixmaps[i] =
|
||||||
QtUtils::GetIconForCompatibility(static_cast<GameDatabase::CompatibilityRating>(i)).pixmap(96, 24);
|
QtUtils::GetIconForCompatibility(static_cast<GameDatabase::CompatibilityRating>(i)).pixmap(96, 24);
|
||||||
|
}
|
||||||
|
|
||||||
m_placeholder_pixmap.load(QStringLiteral("%1/images/cover-placeholder.png").arg(QtHost::GetResourcesBasePath()));
|
m_placeholder_pixmap.load(QStringLiteral("%1/images/cover-placeholder.png").arg(QtHost::GetResourcesBasePath()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
static std::optional<Column> getColumnIdForName(std::string_view name);
|
static std::optional<Column> getColumnIdForName(std::string_view name);
|
||||||
static const char* getColumnName(Column col);
|
static const char* getColumnName(Column col);
|
||||||
|
|
||||||
GameListModel(QObject* parent = nullptr);
|
GameListModel(float cover_scale, bool show_cover_titles, QObject* parent = nullptr);
|
||||||
~GameListModel();
|
~GameListModel();
|
||||||
|
|
||||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
@ -56,6 +56,7 @@ public:
|
||||||
ALWAYS_INLINE const QString& getColumnDisplayName(int column) { return m_column_display_names[column]; }
|
ALWAYS_INLINE const QString& getColumnDisplayName(int column) { return m_column_display_names[column]; }
|
||||||
|
|
||||||
void refresh();
|
void refresh();
|
||||||
|
void reloadThemeSpecificImages();
|
||||||
|
|
||||||
bool titlesLessThan(int left_row, int right_row) const;
|
bool titlesLessThan(int left_row, int right_row) const;
|
||||||
|
|
||||||
|
@ -71,10 +72,13 @@ public:
|
||||||
int getCoverArtSpacing() const;
|
int getCoverArtSpacing() const;
|
||||||
void refreshCovers();
|
void refreshCovers();
|
||||||
void updateCacheSize(int width, int height);
|
void updateCacheSize(int width, int height);
|
||||||
void reloadCommonImages();
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void coverScaleChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadCommonImages();
|
void loadCommonImages();
|
||||||
|
void loadThemeSpecificImages();
|
||||||
void setColumnDisplayNames();
|
void setColumnDisplayNames();
|
||||||
void loadOrGenerateCover(const GameList::Entry* ge);
|
void loadOrGenerateCover(const GameList::Entry* ge);
|
||||||
void invalidateCoverForPath(const std::string& path);
|
void invalidateCoverForPath(const std::string& path);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#include "gamelistwidget.h"
|
#include "gamelistwidget.h"
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
#include <QtGui/QWheelEvent>
|
#include <QtGui/QWheelEvent>
|
||||||
#include <QtWidgets/QHeaderView>
|
#include <QtWidgets/QHeaderView>
|
||||||
#include <QtWidgets/QMenu>
|
#include <QtWidgets/QMenu>
|
||||||
|
#include <QtWidgets/QScrollBar>
|
||||||
|
|
||||||
static constexpr float MIN_SCALE = 0.1f;
|
static constexpr float MIN_SCALE = 0.1f;
|
||||||
static constexpr float MAX_SCALE = 2.0f;
|
static constexpr float MAX_SCALE = 2.0f;
|
||||||
|
@ -91,9 +92,9 @@ GameListWidget::~GameListWidget() = default;
|
||||||
|
|
||||||
void GameListWidget::initialize()
|
void GameListWidget::initialize()
|
||||||
{
|
{
|
||||||
m_model = new GameListModel(this);
|
const float cover_scale = Host::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", 0.45f);
|
||||||
m_model->setCoverScale(Host::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", 0.45f));
|
const bool show_cover_titles = Host::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true);
|
||||||
m_model->setShowCoverTitles(Host::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true));
|
m_model = new GameListModel(cover_scale, show_cover_titles, this);
|
||||||
m_model->updateCacheSize(width(), height());
|
m_model->updateCacheSize(width(), height());
|
||||||
|
|
||||||
m_sort_model = new GameListSortModel(m_model);
|
m_sort_model = new GameListSortModel(m_model);
|
||||||
|
@ -162,17 +163,16 @@ void GameListWidget::initialize()
|
||||||
m_list_view = new GameListGridListView(m_ui.stack);
|
m_list_view = new GameListGridListView(m_ui.stack);
|
||||||
m_list_view->setModel(m_sort_model);
|
m_list_view->setModel(m_sort_model);
|
||||||
m_list_view->setModelColumn(GameListModel::Column_Cover);
|
m_list_view->setModelColumn(GameListModel::Column_Cover);
|
||||||
m_list_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
m_list_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
m_list_view->setViewMode(QListView::IconMode);
|
m_list_view->setViewMode(QListView::IconMode);
|
||||||
m_list_view->setResizeMode(QListView::Adjust);
|
m_list_view->setResizeMode(QListView::Adjust);
|
||||||
m_list_view->setUniformItemSizes(true);
|
m_list_view->setUniformItemSizes(true);
|
||||||
m_list_view->setItemAlignment(Qt::AlignHCenter);
|
m_list_view->setItemAlignment(Qt::AlignHCenter);
|
||||||
m_list_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
m_list_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
m_list_view->setFrameStyle(QFrame::NoFrame);
|
m_list_view->setFrameStyle(QFrame::NoFrame);
|
||||||
m_list_view->setSpacing(m_model->getCoverArtSpacing());
|
|
||||||
m_list_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
|
m_list_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
|
||||||
|
m_list_view->verticalScrollBar()->setSingleStep(15);
|
||||||
updateListFont();
|
onCoverScaleChanged();
|
||||||
|
|
||||||
connect(m_list_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
connect(m_list_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||||
&GameListWidget::onSelectionModelCurrentChanged);
|
&GameListWidget::onSelectionModelCurrentChanged);
|
||||||
|
@ -180,6 +180,7 @@ void GameListWidget::initialize()
|
||||||
connect(m_list_view, &GameListGridListView::zoomOut, this, &GameListWidget::gridZoomOut);
|
connect(m_list_view, &GameListGridListView::zoomOut, this, &GameListWidget::gridZoomOut);
|
||||||
connect(m_list_view, &QListView::activated, this, &GameListWidget::onListViewItemActivated);
|
connect(m_list_view, &QListView::activated, this, &GameListWidget::onListViewItemActivated);
|
||||||
connect(m_list_view, &QListView::customContextMenuRequested, this, &GameListWidget::onListViewContextMenuRequested);
|
connect(m_list_view, &QListView::customContextMenuRequested, this, &GameListWidget::onListViewContextMenuRequested);
|
||||||
|
connect(m_model, &GameListModel::coverScaleChanged, this, &GameListWidget::onCoverScaleChanged);
|
||||||
|
|
||||||
m_ui.stack->insertWidget(1, m_list_view);
|
m_ui.stack->insertWidget(1, m_list_view);
|
||||||
|
|
||||||
|
@ -237,6 +238,11 @@ void GameListWidget::cancelRefresh()
|
||||||
AssertMsg(!m_refresh_thread, "Game list thread should be unreferenced by now");
|
AssertMsg(!m_refresh_thread, "Game list thread should be unreferenced by now");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameListWidget::reloadThemeSpecificImages()
|
||||||
|
{
|
||||||
|
m_model->reloadThemeSpecificImages();
|
||||||
|
}
|
||||||
|
|
||||||
void GameListWidget::onRefreshProgress(const QString& status, int current, int total)
|
void GameListWidget::onRefreshProgress(const QString& status, int current, int total)
|
||||||
{
|
{
|
||||||
// switch away from the placeholder while we scan, in case we find anything
|
// switch away from the placeholder while we scan, in case we find anything
|
||||||
|
@ -326,14 +332,23 @@ void GameListWidget::onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder)
|
||||||
saveTableViewColumnSortSettings();
|
saveTableViewColumnSortSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameListWidget::onCoverScaleChanged()
|
||||||
|
{
|
||||||
|
m_model->updateCacheSize(width(), height());
|
||||||
|
|
||||||
|
m_list_view->setSpacing(m_model->getCoverArtSpacing());
|
||||||
|
|
||||||
|
QFont font;
|
||||||
|
font.setPointSizeF(16.0f * m_model->getCoverScale());
|
||||||
|
m_list_view->setFont(font);
|
||||||
|
}
|
||||||
|
|
||||||
void GameListWidget::listZoom(float delta)
|
void GameListWidget::listZoom(float delta)
|
||||||
{
|
{
|
||||||
const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_SCALE, MAX_SCALE);
|
const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_SCALE, MAX_SCALE);
|
||||||
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
|
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
|
||||||
Host::CommitBaseSettingChanges();
|
Host::CommitBaseSettingChanges();
|
||||||
m_model->setCoverScale(new_scale);
|
m_model->setCoverScale(new_scale);
|
||||||
m_model->updateCacheSize(width(), height());
|
|
||||||
updateListFont();
|
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
|
|
||||||
m_model->refresh();
|
m_model->refresh();
|
||||||
|
@ -356,8 +371,6 @@ void GameListWidget::gridIntScale(int int_scale)
|
||||||
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
|
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
|
||||||
Host::CommitBaseSettingChanges();
|
Host::CommitBaseSettingChanges();
|
||||||
m_model->setCoverScale(new_scale);
|
m_model->setCoverScale(new_scale);
|
||||||
m_model->updateCacheSize(width(), height());
|
|
||||||
updateListFont();
|
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
|
|
||||||
m_model->refresh();
|
m_model->refresh();
|
||||||
|
@ -416,13 +429,6 @@ void GameListWidget::setShowCoverTitles(bool enabled)
|
||||||
emit layoutChange();
|
emit layoutChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListWidget::updateListFont()
|
|
||||||
{
|
|
||||||
QFont font;
|
|
||||||
font.setPointSizeF(16.0f * m_model->getCoverScale());
|
|
||||||
m_list_view->setFont(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameListWidget::updateToolbar()
|
void GameListWidget::updateToolbar()
|
||||||
{
|
{
|
||||||
const bool grid_view = isShowingGameGrid();
|
const bool grid_view = isShowingGameGrid();
|
||||||
|
@ -473,11 +479,6 @@ void GameListWidget::resizeTableViewColumnsToFit()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListWidget::reloadCommonImages()
|
|
||||||
{
|
|
||||||
m_model->reloadCommonImages();
|
|
||||||
}
|
|
||||||
|
|
||||||
static TinyString getColumnVisibilitySettingsKeyName(int column)
|
static TinyString getColumnVisibilitySettingsKeyName(int column)
|
||||||
{
|
{
|
||||||
return TinyString::FromFormat("Show%s", GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
|
return TinyString::FromFormat("Show%s", GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -43,10 +43,10 @@ public:
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
void resizeTableViewColumnsToFit();
|
void resizeTableViewColumnsToFit();
|
||||||
void reloadCommonImages();
|
|
||||||
|
|
||||||
void refresh(bool invalidate_cache);
|
void refresh(bool invalidate_cache);
|
||||||
void cancelRefresh();
|
void cancelRefresh();
|
||||||
|
void reloadThemeSpecificImages();
|
||||||
|
|
||||||
bool isShowingGameList() const;
|
bool isShowingGameList() const;
|
||||||
bool isShowingGameGrid() const;
|
bool isShowingGameGrid() const;
|
||||||
|
@ -76,6 +76,7 @@ private Q_SLOTS:
|
||||||
void onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder);
|
void onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder);
|
||||||
void onListViewItemActivated(const QModelIndex& index);
|
void onListViewItemActivated(const QModelIndex& index);
|
||||||
void onListViewContextMenuRequested(const QPoint& point);
|
void onListViewContextMenuRequested(const QPoint& point);
|
||||||
|
void onCoverScaleChanged();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void showGameList();
|
void showGameList();
|
||||||
|
@ -96,7 +97,6 @@ private:
|
||||||
void loadTableViewColumnSortSettings();
|
void loadTableViewColumnSortSettings();
|
||||||
void saveTableViewColumnSortSettings();
|
void saveTableViewColumnSortSettings();
|
||||||
void listZoom(float delta);
|
void listZoom(float delta);
|
||||||
void updateListFont();
|
|
||||||
void updateToolbar();
|
void updateToolbar();
|
||||||
|
|
||||||
Ui::GameListWidget m_ui;
|
Ui::GameListWidget m_ui;
|
||||||
|
|
|
@ -135,7 +135,7 @@ void InputBindingDialog::startListeningForInput(u32 timeout_in_seconds)
|
||||||
{
|
{
|
||||||
m_value_ranges.clear();
|
m_value_ranges.clear();
|
||||||
m_new_bindings.clear();
|
m_new_bindings.clear();
|
||||||
m_mouse_mapping_enabled = InputBindingWidget::isMouseMappingEnabled();
|
m_mouse_mapping_enabled = InputBindingWidget::isMouseMappingEnabled(m_sif);
|
||||||
m_input_listen_start_position = QCursor::pos();
|
m_input_listen_start_position = QCursor::pos();
|
||||||
m_input_listen_timer = new QTimer(this);
|
m_input_listen_timer = new QTimer(this);
|
||||||
m_input_listen_timer->setSingleShot(false);
|
m_input_listen_timer->setSingleShot(false);
|
||||||
|
|
|
@ -42,9 +42,10 @@ InputBindingWidget::~InputBindingWidget()
|
||||||
Q_ASSERT(!isListeningForInput());
|
Q_ASSERT(!isListeningForInput());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputBindingWidget::isMouseMappingEnabled()
|
bool InputBindingWidget::isMouseMappingEnabled(SettingsInterface* sif)
|
||||||
{
|
{
|
||||||
return Host::GetBaseBoolSettingValue("UI", "EnableMouseMapping", false);
|
return sif ? sif->GetBoolValue("UI", "EnableMouseMapping", false) :
|
||||||
|
Host::GetBaseBoolSettingValue("UI", "EnableMouseMapping", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputBindingWidget::initialize(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name,
|
void InputBindingWidget::initialize(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name,
|
||||||
|
@ -287,7 +288,7 @@ void InputBindingWidget::startListeningForInput(u32 timeout_in_seconds)
|
||||||
{
|
{
|
||||||
m_value_ranges.clear();
|
m_value_ranges.clear();
|
||||||
m_new_bindings.clear();
|
m_new_bindings.clear();
|
||||||
m_mouse_mapping_enabled = isMouseMappingEnabled();
|
m_mouse_mapping_enabled = isMouseMappingEnabled(m_sif);
|
||||||
m_input_listen_start_position = QCursor::pos();
|
m_input_listen_start_position = QCursor::pos();
|
||||||
m_input_listen_timer = new QTimer(this);
|
m_input_listen_timer = new QTimer(this);
|
||||||
m_input_listen_timer->setSingleShot(false);
|
m_input_listen_timer->setSingleShot(false);
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
std::string section_name, std::string key_name);
|
std::string section_name, std::string key_name);
|
||||||
~InputBindingWidget();
|
~InputBindingWidget();
|
||||||
|
|
||||||
static bool isMouseMappingEnabled();
|
static bool isMouseMappingEnabled(SettingsInterface* sif);
|
||||||
|
|
||||||
void initialize(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name,
|
void initialize(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name,
|
||||||
std::string key_name);
|
std::string key_name);
|
||||||
|
|
|
@ -1417,13 +1417,25 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||||
|
|
||||||
void MainWindow::setGameListEntryCoverImage(const GameList::Entry* entry)
|
void MainWindow::setGameListEntryCoverImage(const GameList::Entry* entry)
|
||||||
{
|
{
|
||||||
QString filename = QFileDialog::getOpenFileName(this, tr("Select Cover Image"), QString(),
|
const QString filename = QDir::toNativeSeparators(QFileDialog::getOpenFileName(
|
||||||
tr("All Cover Image Types (*.jpg *.jpeg *.png)"));
|
this, tr("Select Cover Image"), QString(), tr("All Cover Image Types (*.jpg *.jpeg *.png *.webp)")));
|
||||||
if (filename.isEmpty())
|
if (filename.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!GameList::GetCoverImagePathForEntry(entry).empty())
|
const QString old_filename = QString::fromStdString(GameList::GetCoverImagePathForEntry(entry));
|
||||||
|
const QString new_filename =
|
||||||
|
QString::fromStdString(GameList::GetNewCoverImagePathForEntry(entry, filename.toUtf8().constData(), false));
|
||||||
|
if (new_filename.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!old_filename.isEmpty())
|
||||||
{
|
{
|
||||||
|
if (QFileInfo(old_filename) == QFileInfo(filename))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Copy Error"), tr("You must select a different file to the current cover image."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (QMessageBox::question(this, tr("Cover Already Exists"),
|
if (QMessageBox::question(this, tr("Cover Already Exists"),
|
||||||
tr("A cover image for this game already exists, do you wish to replace it?"),
|
tr("A cover image for this game already exists, do you wish to replace it?"),
|
||||||
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
|
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
|
||||||
|
@ -1432,23 +1444,21 @@ void MainWindow::setGameListEntryCoverImage(const GameList::Entry* entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString new_filename =
|
|
||||||
QString::fromStdString(GameList::GetNewCoverImagePathForEntry(entry, filename.toStdString().c_str(), false));
|
|
||||||
if (new_filename.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (QFile::exists(new_filename) && !QFile::remove(new_filename))
|
if (QFile::exists(new_filename) && !QFile::remove(new_filename))
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Copy Error"), tr("Failed to remove existing cover '%1'").arg(new_filename));
|
QMessageBox::critical(this, tr("Copy Error"), tr("Failed to remove existing cover '%1'").arg(new_filename));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QFile::copy(filename, new_filename))
|
if (!QFile::copy(filename, new_filename))
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Copy Error"), tr("Failed to copy '%1' to '%2'").arg(filename).arg(new_filename));
|
QMessageBox::critical(this, tr("Copy Error"), tr("Failed to copy '%1' to '%2'").arg(filename).arg(new_filename));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!old_filename.isEmpty() && old_filename != new_filename && !QFile::remove(old_filename))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Copy Error"), tr("Failed to remove '%1'").arg(old_filename));
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_game_list_widget->refreshGridCovers();
|
m_game_list_widget->refreshGridCovers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2068,7 +2078,12 @@ void MainWindow::updateTheme()
|
||||||
{
|
{
|
||||||
updateApplicationTheme();
|
updateApplicationTheme();
|
||||||
updateMenuSelectedTheme();
|
updateMenuSelectedTheme();
|
||||||
m_game_list_widget->reloadCommonImages();
|
reloadThemeSpecificImages();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::reloadThemeSpecificImages()
|
||||||
|
{
|
||||||
|
m_game_list_widget->reloadThemeSpecificImages();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setStyleFromSettings()
|
void MainWindow::setStyleFromSettings()
|
||||||
|
@ -2405,6 +2420,12 @@ void MainWindow::changeEvent(QEvent* event)
|
||||||
g_emu_thread->redrawDisplayWindow();
|
g_emu_thread->redrawDisplayWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event->type() == QEvent::StyleChange)
|
||||||
|
{
|
||||||
|
setIconThemeFromSettings();
|
||||||
|
reloadThemeSpecificImages();
|
||||||
|
}
|
||||||
|
|
||||||
QMainWindow::changeEvent(event);
|
QMainWindow::changeEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,7 @@ private:
|
||||||
void clearGameListEntryPlayTime(const GameList::Entry* entry);
|
void clearGameListEntryPlayTime(const GameList::Entry* entry);
|
||||||
void setTheme(const QString& theme);
|
void setTheme(const QString& theme);
|
||||||
void updateTheme();
|
void updateTheme();
|
||||||
|
void reloadThemeSpecificImages();
|
||||||
void recreate();
|
void recreate();
|
||||||
|
|
||||||
void registerForDeviceNotifications();
|
void registerForDeviceNotifications();
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/file_system.h"
|
||||||
#include "common/path.h"
|
#include "common/path.h"
|
||||||
|
|
||||||
#include <QtCore/QtCore>
|
#include <QtCore/QtCore>
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include <QtWidgets/QFileDialog>
|
#include <QtWidgets/QFileDialog>
|
||||||
#include <QtWidgets/QLineEdit>
|
#include <QtWidgets/QLineEdit>
|
||||||
#include <QtWidgets/QMenu>
|
#include <QtWidgets/QMenu>
|
||||||
|
#include <QtWidgets/QMessageBox>
|
||||||
#include <QtWidgets/QSlider>
|
#include <QtWidgets/QSlider>
|
||||||
#include <QtWidgets/QSpinBox>
|
#include <QtWidgets/QSpinBox>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -1030,22 +1032,20 @@ static void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename WidgetType>
|
static inline void BindWidgetToFolderSetting(SettingsInterface* sif, QLineEdit* widget, QAbstractButton* browse_button,
|
||||||
static void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget, QAbstractButton* browse_button,
|
QAbstractButton* open_button, QAbstractButton* reset_button,
|
||||||
QAbstractButton* open_button, QAbstractButton* reset_button, std::string section,
|
std::string section, std::string key, std::string default_value,
|
||||||
std::string key, std::string default_value)
|
bool use_relative = true)
|
||||||
{
|
{
|
||||||
using Accessor = SettingAccessor<WidgetType>;
|
using Accessor = SettingAccessor<QLineEdit>;
|
||||||
|
|
||||||
std::string current_path(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str()));
|
std::string current_path(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str()));
|
||||||
if (current_path.empty())
|
if (current_path.empty())
|
||||||
current_path = default_value;
|
current_path = default_value;
|
||||||
else if (!Path::IsAbsolute(current_path))
|
else if (use_relative && !Path::IsAbsolute(current_path))
|
||||||
current_path = Path::Combine(EmuFolders::DataRoot, current_path);
|
current_path = Path::Canonicalize(Path::Combine(EmuFolders::DataRoot, current_path));
|
||||||
|
|
||||||
const QString value(QString::fromStdString(current_path));
|
const QString value(QString::fromStdString(current_path));
|
||||||
Accessor::setStringValue(widget, value);
|
Accessor::setStringValue(widget, value);
|
||||||
|
|
||||||
// if we're doing per-game settings, disable the widget, we only allow folder changes in the base config
|
// if we're doing per-game settings, disable the widget, we only allow folder changes in the base config
|
||||||
if (sif)
|
if (sif)
|
||||||
{
|
{
|
||||||
|
@ -1057,32 +1057,65 @@ static void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
|
auto value_changed = [widget, section = std::move(section), key = std::move(key), default_value, use_relative]() {
|
||||||
const std::string new_value(Accessor::getStringValue(widget).toStdString());
|
const std::string new_value(widget->text().toStdString());
|
||||||
if (!new_value.empty())
|
if (!new_value.empty())
|
||||||
{
|
{
|
||||||
std::string relative_path(Path::MakeRelative(new_value, EmuFolders::DataRoot));
|
if (FileSystem::DirectoryExists(new_value.c_str()) ||
|
||||||
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), relative_path.c_str());
|
QMessageBox::question(
|
||||||
|
QtUtils::GetRootWidget(widget), qApp->translate("SettingWidgetBinder", "Confirm Folder"),
|
||||||
|
qApp
|
||||||
|
->translate(
|
||||||
|
"SettingWidgetBinder",
|
||||||
|
"The chosen directory does not currently exist:\n\n%1\n\nDo you want to create this directory?")
|
||||||
|
.arg(QString::fromStdString(new_value)),
|
||||||
|
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
if (use_relative)
|
||||||
|
{
|
||||||
|
const std::string relative_path(Path::MakeRelative(new_value, EmuFolders::DataRoot));
|
||||||
|
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), relative_path.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), new_value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Host::CommitBaseSettingChanges();
|
||||||
|
g_emu_thread->updateEmuFolders();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Host::DeleteBaseSettingValue(section.c_str(), key.c_str());
|
QMessageBox::critical(QtUtils::GetRootWidget(widget), qApp->translate("SettingWidgetBinder", "Error"),
|
||||||
|
qApp->translate("SettingWidgetBinder", "Folder path cannot be empty."));
|
||||||
}
|
}
|
||||||
|
|
||||||
Host::CommitBaseSettingChanges();
|
// reset to old value
|
||||||
g_emu_thread->updateEmuFolders();
|
std::string current_path(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str()));
|
||||||
});
|
if (current_path.empty())
|
||||||
|
current_path = default_value;
|
||||||
|
else if (use_relative && !Path::IsAbsolute(current_path))
|
||||||
|
current_path = Path::Canonicalize(Path::Combine(EmuFolders::DataRoot, current_path));
|
||||||
|
|
||||||
|
widget->setText(QString::fromStdString(current_path));
|
||||||
|
};
|
||||||
|
|
||||||
if (browse_button)
|
if (browse_button)
|
||||||
{
|
{
|
||||||
QObject::connect(browse_button, &QAbstractButton::clicked, browse_button, [widget, key]() {
|
QObject::connect(browse_button, &QAbstractButton::clicked, browse_button, [widget, key, value_changed]() {
|
||||||
const QString path(QDir::toNativeSeparators(QFileDialog::getExistingDirectory(
|
const QString path(QDir::toNativeSeparators(QFileDialog::getExistingDirectory(
|
||||||
QtUtils::GetRootWidget(widget),
|
QtUtils::GetRootWidget(widget),
|
||||||
|
// It seems that the latter half should show the types of folders that can be selected within Settings ->
|
||||||
|
// Folders, but right now it's broken. It would be best for localization purposes to duplicate this into
|
||||||
|
// multiple lines, each per type of folder.
|
||||||
qApp->translate("SettingWidgetBinder", "Select folder for %1").arg(QString::fromStdString(key)))));
|
qApp->translate("SettingWidgetBinder", "Select folder for %1").arg(QString::fromStdString(key)))));
|
||||||
if (path.isEmpty())
|
if (path.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Accessor::setStringValue(widget, path);
|
widget->setText(path);
|
||||||
|
value_changed();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (open_button)
|
if (open_button)
|
||||||
|
@ -1096,9 +1129,12 @@ static void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget
|
||||||
if (reset_button)
|
if (reset_button)
|
||||||
{
|
{
|
||||||
QObject::connect(reset_button, &QAbstractButton::clicked, reset_button,
|
QObject::connect(reset_button, &QAbstractButton::clicked, reset_button,
|
||||||
[widget, default_value = std::move(default_value)]() {
|
[widget, default_value = std::move(default_value), value_changed]() {
|
||||||
Accessor::setStringValue(widget, QString::fromStdString(default_value));
|
widget->setText(QString::fromStdString(default_value));
|
||||||
|
value_changed();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
widget->connect(widget, &QLineEdit::editingFinished, widget, std::move(value_changed));
|
||||||
}
|
}
|
||||||
} // namespace SettingWidgetBinder
|
} // namespace SettingWidgetBinder
|
||||||
|
|
Loading…
Reference in a new issue