mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-19 03:55:46 -04:00
Qt: Add new cheat manager
This commit is contained in:
@ -18,6 +18,12 @@ set(SRCS
|
||||
biossettingswidget.cpp
|
||||
biossettingswidget.h
|
||||
biossettingswidget.ui
|
||||
cheatmanagerdialog.cpp
|
||||
cheatmanagerdialog.h
|
||||
cheatmanagerdialog.ui
|
||||
cheatcodeeditordialog.cpp
|
||||
cheatcodeeditordialog.h
|
||||
cheatcodeeditordialog.ui
|
||||
consolesettingswidget.cpp
|
||||
consolesettingswidget.h
|
||||
consolesettingswidget.ui
|
||||
|
88
src/duckstation-qt/cheatcodeeditordialog.cpp
Normal file
88
src/duckstation-qt/cheatcodeeditordialog.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include "cheatcodeeditordialog.h"
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
CheatCodeEditorDialog::CheatCodeEditorDialog(CheatList* list, CheatCode* code, QWidget* parent)
|
||||
: m_code(code), QDialog(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
setupAdditionalUi(list);
|
||||
fillUi();
|
||||
connectUi();
|
||||
}
|
||||
|
||||
CheatCodeEditorDialog::~CheatCodeEditorDialog() = default;
|
||||
|
||||
void CheatCodeEditorDialog::saveClicked()
|
||||
{
|
||||
std::string new_description = m_ui.description->text().toStdString();
|
||||
if (new_description.empty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Description cannot be empty."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_code->SetInstructionsFromString(m_ui.instructions->toPlainText().toStdString()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Instructions are invalid."));
|
||||
return;
|
||||
}
|
||||
|
||||
m_code->description = std::move(new_description);
|
||||
m_code->type = static_cast<CheatCode::Type>(m_ui.type->currentIndex());
|
||||
m_code->activation = static_cast<CheatCode::Activation>(m_ui.activation->currentIndex());
|
||||
m_code->group = m_ui.group->currentText().toStdString();
|
||||
|
||||
done(1);
|
||||
}
|
||||
|
||||
void CheatCodeEditorDialog::cancelClicked()
|
||||
{
|
||||
done(0);
|
||||
}
|
||||
|
||||
void CheatCodeEditorDialog::setupAdditionalUi(CheatList* list)
|
||||
{
|
||||
for (u32 i = 0; i < static_cast<u32>(CheatCode::Type::Count); i++)
|
||||
{
|
||||
m_ui.type->addItem(qApp->translate("Cheats", CheatCode::GetTypeDisplayName(static_cast<CheatCode::Type>(i))));
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < static_cast<u32>(CheatCode::Activation::Count); i++)
|
||||
{
|
||||
m_ui.activation->addItem(
|
||||
qApp->translate("Cheats", CheatCode::GetActivationDisplayName(static_cast<CheatCode::Activation>(i))));
|
||||
}
|
||||
|
||||
const auto groups = list->GetCodeGroups();
|
||||
if (!groups.empty())
|
||||
{
|
||||
for (const std::string& group_name : groups)
|
||||
m_ui.group->addItem(QString::fromStdString(group_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.group->addItem(QStringLiteral("Ungrouped"));
|
||||
}
|
||||
}
|
||||
|
||||
void CheatCodeEditorDialog::fillUi()
|
||||
{
|
||||
m_ui.description->setText(QString::fromStdString(m_code->description));
|
||||
|
||||
int index = m_ui.group->findText(QString::fromStdString(m_code->group));
|
||||
if (index >= 0)
|
||||
m_ui.group->setCurrentIndex(index);
|
||||
else
|
||||
m_ui.group->setCurrentIndex(0);
|
||||
|
||||
m_ui.type->setCurrentIndex(static_cast<int>(m_code->type));
|
||||
m_ui.activation->setCurrentIndex(static_cast<int>(m_code->activation));
|
||||
|
||||
m_ui.instructions->setPlainText(QString::fromStdString(m_code->GetInstructionsAsString()));
|
||||
}
|
||||
|
||||
void CheatCodeEditorDialog::connectUi()
|
||||
{
|
||||
connect(m_ui.save, &QPushButton::clicked, this, &CheatCodeEditorDialog::saveClicked);
|
||||
connect(m_ui.cancel, &QPushButton::clicked, this, &CheatCodeEditorDialog::cancelClicked);
|
||||
}
|
25
src/duckstation-qt/cheatcodeeditordialog.h
Normal file
25
src/duckstation-qt/cheatcodeeditordialog.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "core/cheats.h"
|
||||
#include "ui_cheatcodeeditordialog.h"
|
||||
|
||||
class CheatCodeEditorDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheatCodeEditorDialog(CheatList* list, CheatCode* code, QWidget* parent);
|
||||
~CheatCodeEditorDialog();
|
||||
|
||||
private Q_SLOTS:
|
||||
void saveClicked();
|
||||
void cancelClicked();
|
||||
|
||||
private:
|
||||
void setupAdditionalUi(CheatList* list);
|
||||
void fillUi();
|
||||
void connectUi();
|
||||
|
||||
CheatCode* m_code;
|
||||
|
||||
Ui::CheatCodeEditorDialog m_ui;
|
||||
};
|
101
src/duckstation-qt/cheatcodeeditordialog.ui
Normal file
101
src/duckstation-qt/cheatcodeeditordialog.ui
Normal file
@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CheatCodeEditorDialog</class>
|
||||
<widget class="QDialog" name="CheatCodeEditorDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>491</width>
|
||||
<height>284</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Cheat Code Editor</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Description:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="description"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Group:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="group"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="type"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Activation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="activation"/>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QPlainTextEdit" name="instructions"/>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="save">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancel">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
689
src/duckstation-qt/cheatmanagerdialog.cpp
Normal file
689
src/duckstation-qt/cheatmanagerdialog.cpp
Normal file
@ -0,0 +1,689 @@
|
||||
#include "cheatmanagerdialog.h"
|
||||
#include "cheatcodeeditordialog.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/system.h"
|
||||
#include "qthostinterface.h"
|
||||
#include "qtutils.h"
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtGui/QColor>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QTreeWidgetItemIterator>
|
||||
#include <array>
|
||||
|
||||
static QString formatHexValue(u32 value)
|
||||
{
|
||||
return QStringLiteral("0x%1").arg(static_cast<uint>(value), 8, 16, QChar('0'));
|
||||
}
|
||||
|
||||
static QString formatValue(u32 value, bool is_signed)
|
||||
{
|
||||
if (is_signed)
|
||||
return QStringLiteral("%1").arg(static_cast<int>(value));
|
||||
else
|
||||
return QStringLiteral("%1").arg(static_cast<uint>(value));
|
||||
}
|
||||
|
||||
CheatManagerDialog::CheatManagerDialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
setupAdditionalUi();
|
||||
connectUi();
|
||||
|
||||
updateCheatList();
|
||||
}
|
||||
|
||||
CheatManagerDialog::~CheatManagerDialog() = default;
|
||||
|
||||
void CheatManagerDialog::setupAdditionalUi()
|
||||
{
|
||||
m_ui.scanStartAddress->setText(formatHexValue(m_scanner.GetStartAddress()));
|
||||
m_ui.scanEndAddress->setText(formatHexValue(m_scanner.GetEndAddress()));
|
||||
}
|
||||
|
||||
void CheatManagerDialog::connectUi()
|
||||
{
|
||||
connect(m_ui.tabWidget, &QTabWidget::currentChanged, [this](int index) {
|
||||
resizeColumns();
|
||||
setUpdateTimerEnabled(index == 1);
|
||||
});
|
||||
connect(m_ui.cheatList, &QTreeWidget::currentItemChanged, this, &CheatManagerDialog::cheatListCurrentItemChanged);
|
||||
connect(m_ui.cheatList, &QTreeWidget::itemActivated, this, &CheatManagerDialog::cheatListItemActivated);
|
||||
connect(m_ui.cheatList, &QTreeWidget::itemChanged, this, &CheatManagerDialog::cheatListItemChanged);
|
||||
connect(m_ui.cheatListNewCategory, &QPushButton::clicked, this, &CheatManagerDialog::newCategoryClicked);
|
||||
connect(m_ui.cheatListAdd, &QPushButton::clicked, this, &CheatManagerDialog::addCodeClicked);
|
||||
connect(m_ui.cheatListEdit, &QPushButton::clicked, this, &CheatManagerDialog::editCodeClicked);
|
||||
connect(m_ui.cheatListRemove, &QPushButton::clicked, this, &CheatManagerDialog::deleteCodeClicked);
|
||||
connect(m_ui.cheatListActivate, &QPushButton::clicked, this, &CheatManagerDialog::activateCodeClicked);
|
||||
connect(m_ui.cheatListImport, &QPushButton::clicked, this, &CheatManagerDialog::importClicked);
|
||||
connect(m_ui.cheatListExport, &QPushButton::clicked, this, &CheatManagerDialog::exportClicked);
|
||||
|
||||
connect(m_ui.scanValue, &QLineEdit::textChanged, this, &CheatManagerDialog::updateScanValue);
|
||||
connect(m_ui.scanValueBase, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
[this](int index) { updateScanValue(); });
|
||||
connect(m_ui.scanSize, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
m_scanner.SetSize(static_cast<MemoryAccessSize>(index));
|
||||
m_scanner.ResetSearch();
|
||||
updateResults();
|
||||
});
|
||||
connect(m_ui.scanValueSigned, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
m_scanner.SetValueSigned(index == 0);
|
||||
m_scanner.ResetSearch();
|
||||
updateResults();
|
||||
});
|
||||
connect(m_ui.scanOperator, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
[this](int index) { m_scanner.SetOperator(static_cast<MemoryScan::Operator>(index)); });
|
||||
connect(m_ui.scanNewSearch, &QPushButton::clicked, [this]() {
|
||||
m_scanner.Search();
|
||||
updateResults();
|
||||
});
|
||||
connect(m_ui.scanSearchAgain, &QPushButton::clicked, [this]() {
|
||||
m_scanner.SearchAgain();
|
||||
updateResults();
|
||||
});
|
||||
connect(m_ui.scanResetSearch, &QPushButton::clicked, [this]() {
|
||||
m_scanner.ResetSearch();
|
||||
updateResults();
|
||||
});
|
||||
connect(m_ui.scanAddWatch, &QPushButton::clicked, this, &CheatManagerDialog::addToWatchClicked);
|
||||
connect(m_ui.scanRemoveWatch, &QPushButton::clicked, this, &CheatManagerDialog::removeWatchClicked);
|
||||
connect(m_ui.scanTable, &QTableWidget::currentItemChanged, this, &CheatManagerDialog::scanCurrentItemChanged);
|
||||
connect(m_ui.watchTable, &QTableWidget::currentItemChanged, this, &CheatManagerDialog::watchCurrentItemChanged);
|
||||
connect(m_ui.scanTable, &QTableWidget::itemChanged, this, &CheatManagerDialog::scanItemChanged);
|
||||
connect(m_ui.watchTable, &QTableWidget::itemChanged, this, &CheatManagerDialog::watchItemChanged);
|
||||
}
|
||||
|
||||
void CheatManagerDialog::showEvent(QShowEvent* event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
resizeColumns();
|
||||
}
|
||||
|
||||
void CheatManagerDialog::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QDialog::resizeEvent(event);
|
||||
resizeColumns();
|
||||
}
|
||||
|
||||
void CheatManagerDialog::resizeColumns()
|
||||
{
|
||||
QtUtils::ResizeColumnsForTableView(m_ui.scanTable, {-1, 100, 100});
|
||||
QtUtils::ResizeColumnsForTableView(m_ui.watchTable, {50, -1, 100, 150, 100});
|
||||
QtUtils::ResizeColumnsForTreeView(m_ui.cheatList, {-1, 100, 150, 100});
|
||||
}
|
||||
|
||||
void CheatManagerDialog::setUpdateTimerEnabled(bool enabled)
|
||||
{
|
||||
if ((!m_update_timer && !enabled) && m_update_timer->isActive() == enabled)
|
||||
return;
|
||||
|
||||
if (!m_update_timer)
|
||||
{
|
||||
m_update_timer = new QTimer(this);
|
||||
connect(m_update_timer, &QTimer::timeout, this, &CheatManagerDialog::updateScanUi);
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
m_update_timer->start(100);
|
||||
else
|
||||
m_update_timer->stop();
|
||||
}
|
||||
|
||||
int CheatManagerDialog::getSelectedResultIndex() const
|
||||
{
|
||||
QList<QTableWidgetSelectionRange> sel = m_ui.scanTable->selectedRanges();
|
||||
if (sel.isEmpty())
|
||||
return -1;
|
||||
|
||||
return sel.front().topRow();
|
||||
}
|
||||
|
||||
int CheatManagerDialog::getSelectedWatchIndex() const
|
||||
{
|
||||
QList<QTableWidgetSelectionRange> sel = m_ui.watchTable->selectedRanges();
|
||||
if (sel.isEmpty())
|
||||
return -1;
|
||||
|
||||
return sel.front().topRow();
|
||||
}
|
||||
|
||||
QTreeWidgetItem* CheatManagerDialog::getItemForCheatIndex(u32 index) const
|
||||
{
|
||||
QTreeWidgetItemIterator iter(m_ui.cheatList);
|
||||
while (*iter)
|
||||
{
|
||||
QTreeWidgetItem* item = *iter;
|
||||
const QVariant item_data(item->data(0, Qt::UserRole));
|
||||
if (item_data.isValid() && item_data.toUInt() == index)
|
||||
return item;
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static u32 getCheatIndexFromItem(QTreeWidgetItem* item)
|
||||
{
|
||||
return item->data(0, Qt::UserRole).toUInt();
|
||||
}
|
||||
|
||||
int CheatManagerDialog::getSelectedCheatIndex() const
|
||||
{
|
||||
QList<QTreeWidgetItem*> sel = m_ui.cheatList->selectedItems();
|
||||
if (sel.isEmpty())
|
||||
return -1;
|
||||
|
||||
return static_cast<int>(getCheatIndexFromItem(sel.first()));
|
||||
}
|
||||
|
||||
CheatList* CheatManagerDialog::getCheatList() const
|
||||
{
|
||||
Assert(System::IsValid());
|
||||
|
||||
CheatList* list = System::GetCheatList();
|
||||
if (!list)
|
||||
QtHostInterface::GetInstance()->LoadCheatListFromGameTitle();
|
||||
if (!list)
|
||||
{
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread(
|
||||
[]() { System::SetCheatList(std::make_unique<CheatList>()); }, true);
|
||||
list = System::GetCheatList();
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void CheatManagerDialog::updateCheatList()
|
||||
{
|
||||
QSignalBlocker sb(m_ui.cheatList);
|
||||
|
||||
CheatList* list = getCheatList();
|
||||
while (m_ui.cheatList->topLevelItemCount() > 0)
|
||||
delete m_ui.cheatList->takeTopLevelItem(0);
|
||||
|
||||
const std::vector<std::string> groups = list->GetCodeGroups();
|
||||
for (const std::string& group_name : groups)
|
||||
{
|
||||
QTreeWidgetItem* group = new QTreeWidgetItem();
|
||||
group->setFlags(group->flags() | Qt::ItemIsUserCheckable);
|
||||
group->setText(0, QString::fromStdString(group_name));
|
||||
m_ui.cheatList->addTopLevelItem(group);
|
||||
|
||||
const u32 count = list->GetCodeCount();
|
||||
bool all_enabled = true;
|
||||
for (u32 i = 0; i < count; i++)
|
||||
{
|
||||
const CheatCode& code = list->GetCode(i);
|
||||
if (code.group != group_name)
|
||||
continue;
|
||||
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem(group);
|
||||
item->setData(0, Qt::UserRole, QVariant(static_cast<uint>(i)));
|
||||
if (code.IsManuallyActivated())
|
||||
{
|
||||
item->setFlags(item->flags() & ~(Qt::ItemIsUserCheckable));
|
||||
}
|
||||
else
|
||||
{
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(0, code.enabled ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
item->setText(0, QString::fromStdString(code.description));
|
||||
item->setText(1, qApp->translate("Cheats", CheatCode::GetTypeDisplayName(code.type)));
|
||||
item->setText(2, qApp->translate("Cheats", CheatCode::GetActivationDisplayName(code.activation)));
|
||||
item->setText(3, QString::number(static_cast<uint>(code.instructions.size())));
|
||||
|
||||
all_enabled &= code.enabled;
|
||||
}
|
||||
|
||||
group->setCheckState(0, all_enabled ? Qt::Checked : Qt::Unchecked);
|
||||
group->setExpanded(true);
|
||||
}
|
||||
|
||||
m_ui.cheatListEdit->setEnabled(false);
|
||||
m_ui.cheatListRemove->setEnabled(false);
|
||||
m_ui.cheatListActivate->setText(tr("Activate"));
|
||||
m_ui.cheatListActivate->setEnabled(false);
|
||||
m_ui.cheatListExport->setEnabled(list->GetCodeCount() > 0);
|
||||
}
|
||||
|
||||
void CheatManagerDialog::saveCheatList()
|
||||
{
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread([]() { QtHostInterface::GetInstance()->SaveCheatList(); });
|
||||
}
|
||||
|
||||
void CheatManagerDialog::cheatListCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
|
||||
{
|
||||
const bool has_current = (current != nullptr);
|
||||
m_ui.cheatListEdit->setEnabled(has_current);
|
||||
m_ui.cheatListRemove->setEnabled(has_current);
|
||||
m_ui.cheatListActivate->setEnabled(has_current);
|
||||
|
||||
if (!current)
|
||||
{
|
||||
m_ui.cheatListActivate->setText(tr("Activate"));
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool manual_activation = getCheatList()->GetCode(getCheatIndexFromItem(current)).IsManuallyActivated();
|
||||
m_ui.cheatListActivate->setText(manual_activation ? tr("Activate") : tr("Toggle"));
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManagerDialog::cheatListItemActivated(QTreeWidgetItem* item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
const u32 index = getCheatIndexFromItem(item);
|
||||
activateCheat(index);
|
||||
}
|
||||
|
||||
void CheatManagerDialog::cheatListItemChanged(QTreeWidgetItem* item, int column)
|
||||
{
|
||||
if (!item || column != 0)
|
||||
return;
|
||||
|
||||
const u32 index = getCheatIndexFromItem(item);
|
||||
CheatList* list = getCheatList();
|
||||
if (index >= list->GetCodeCount())
|
||||
return;
|
||||
|
||||
CheatCode& cc = list->GetCode(index);
|
||||
if (cc.IsManuallyActivated())
|
||||
return;
|
||||
|
||||
const bool new_enabled = (item->checkState(0) == Qt::Checked);
|
||||
if (cc.enabled == new_enabled)
|
||||
return;
|
||||
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread([index, new_enabled]() {
|
||||
System::GetCheatList()->SetCodeEnabled(index, new_enabled);
|
||||
QtHostInterface::GetInstance()->SaveCheatList();
|
||||
});
|
||||
}
|
||||
|
||||
void CheatManagerDialog::activateCheat(u32 index)
|
||||
{
|
||||
CheatList* list = getCheatList();
|
||||
if (index >= list->GetCodeCount())
|
||||
return;
|
||||
|
||||
CheatCode& cc = list->GetCode(index);
|
||||
if (cc.IsManuallyActivated())
|
||||
{
|
||||
QtHostInterface::GetInstance()->applyCheat(index);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool new_enabled = !cc.enabled;
|
||||
QTreeWidgetItem* item = getItemForCheatIndex(index);
|
||||
if (item)
|
||||
{
|
||||
QSignalBlocker sb(m_ui.cheatList);
|
||||
item->setCheckState(0, new_enabled ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread([index, new_enabled]() {
|
||||
System::GetCheatList()->SetCodeEnabled(index, new_enabled);
|
||||
QtHostInterface::GetInstance()->SaveCheatList();
|
||||
});
|
||||
}
|
||||
|
||||
void CheatManagerDialog::newCategoryClicked()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
void CheatManagerDialog::addCodeClicked()
|
||||
{
|
||||
CheatList* list = getCheatList();
|
||||
|
||||
CheatCode new_code;
|
||||
CheatCodeEditorDialog editor(list, &new_code, this);
|
||||
if (editor.exec() > 0)
|
||||
{
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread(
|
||||
[this, &new_code]() {
|
||||
System::GetCheatList()->AddCode(std::move(new_code));
|
||||
QtHostInterface::GetInstance()->SaveCheatList();
|
||||
},
|
||||
true);
|
||||
updateCheatList();
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManagerDialog::editCodeClicked()
|
||||
{
|
||||
int index = getSelectedCheatIndex();
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
CheatList* list = getCheatList();
|
||||
if (static_cast<u32>(index) >= list->GetCodeCount())
|
||||
return;
|
||||
|
||||
CheatCode new_code = list->GetCode(static_cast<u32>(index));
|
||||
CheatCodeEditorDialog editor(list, &new_code, this);
|
||||
if (editor.exec() > 0)
|
||||
{
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread(
|
||||
[index, &new_code]() {
|
||||
System::GetCheatList()->SetCode(static_cast<u32>(index), std::move(new_code));
|
||||
QtHostInterface::GetInstance()->SaveCheatList();
|
||||
},
|
||||
true);
|
||||
updateCheatList();
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManagerDialog::deleteCodeClicked()
|
||||
{
|
||||
int index = getSelectedCheatIndex();
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
CheatList* list = getCheatList();
|
||||
if (static_cast<u32>(index) >= list->GetCodeCount())
|
||||
return;
|
||||
|
||||
if (QMessageBox::question(this, tr("Delete Code"),
|
||||
tr("Are you sure you wish to delete the selected code? This action is not reversible."),
|
||||
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread(
|
||||
[index]() {
|
||||
System::GetCheatList()->RemoveCode(static_cast<u32>(index));
|
||||
QtHostInterface::GetInstance()->SaveCheatList();
|
||||
},
|
||||
true);
|
||||
updateCheatList();
|
||||
}
|
||||
|
||||
void CheatManagerDialog::activateCodeClicked()
|
||||
{
|
||||
int index = getSelectedCheatIndex();
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
activateCheat(static_cast<u32>(index));
|
||||
}
|
||||
|
||||
void CheatManagerDialog::importClicked()
|
||||
{
|
||||
const QString filter(tr("PCSXR/Libretro Cheat Files (*.cht *.txt);;All Files (*.*)"));
|
||||
const QString filename(QFileDialog::getOpenFileName(this, tr("Import Cheats"), QString(), filter));
|
||||
if (filename.isEmpty())
|
||||
return;
|
||||
|
||||
CheatList new_cheats;
|
||||
if (!new_cheats.LoadFromFile(filename.toUtf8().constData(), CheatList::Format::Autodetect))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to parse cheat file. The log may contain more information."));
|
||||
return;
|
||||
}
|
||||
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread(
|
||||
[&new_cheats]() {
|
||||
DebugAssert(System::HasCheatList());
|
||||
CheatList* list = System::GetCheatList();
|
||||
for (u32 i = 0; i < new_cheats.GetCodeCount(); i++)
|
||||
list->AddCode(new_cheats.GetCode(i));
|
||||
|
||||
QtHostInterface::GetInstance()->SaveCheatList();
|
||||
},
|
||||
true);
|
||||
updateCheatList();
|
||||
}
|
||||
|
||||
void CheatManagerDialog::exportClicked()
|
||||
{
|
||||
const QString filter(tr("PCSXR Cheat Files (*.cht);;All Files (*.*)"));
|
||||
const QString filename(QFileDialog::getSaveFileName(this, tr("Export Cheats"), QString(), filter));
|
||||
if (filename.isEmpty())
|
||||
return;
|
||||
|
||||
if (!getCheatList()->SaveToPCSXRFile(filename.toUtf8().constData()))
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to save cheat file. The log may contain more information."));
|
||||
}
|
||||
|
||||
void CheatManagerDialog::addToWatchClicked()
|
||||
{
|
||||
const int index = getSelectedResultIndex();
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
const MemoryScan::Result& res = m_scanner.GetResults()[static_cast<u32>(index)];
|
||||
m_watch.AddEntry(StringUtil::StdStringFromFormat("0x%08x", res.address), res.address, m_scanner.GetSize(),
|
||||
m_scanner.GetValueSigned(), false);
|
||||
updateWatch();
|
||||
}
|
||||
|
||||
void CheatManagerDialog::removeWatchClicked()
|
||||
{
|
||||
const int index = getSelectedWatchIndex();
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
m_watch.RemoveEntry(static_cast<u32>(index));
|
||||
updateWatch();
|
||||
}
|
||||
|
||||
void CheatManagerDialog::scanCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous)
|
||||
{
|
||||
m_ui.scanAddWatch->setEnabled((current != nullptr));
|
||||
}
|
||||
|
||||
void CheatManagerDialog::watchCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous)
|
||||
{
|
||||
m_ui.scanRemoveWatch->setEnabled((current != nullptr));
|
||||
}
|
||||
|
||||
void CheatManagerDialog::scanItemChanged(QTableWidgetItem* item)
|
||||
{
|
||||
const u32 index = static_cast<u32>(item->row());
|
||||
switch (item->column())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
bool value_ok = false;
|
||||
if (m_scanner.GetValueSigned())
|
||||
{
|
||||
int value = item->text().toInt(&value_ok);
|
||||
if (value_ok)
|
||||
m_scanner.SetResultValue(index, static_cast<u32>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint value = item->text().toUInt(&value_ok);
|
||||
if (value_ok)
|
||||
m_scanner.SetResultValue(index, static_cast<u32>(value));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManagerDialog::watchItemChanged(QTableWidgetItem* item)
|
||||
{
|
||||
const u32 index = static_cast<u32>(item->row());
|
||||
if (index >= m_watch.GetEntryCount())
|
||||
return;
|
||||
|
||||
switch (item->column())
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_watch.SetEntryFreeze(index, (item->checkState() == Qt::Checked));
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
m_watch.SetEntryDescription(index, item->text().toStdString());
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
const MemoryWatchList::Entry& entry = m_watch.GetEntry(index);
|
||||
bool value_ok = false;
|
||||
if (entry.is_signed)
|
||||
{
|
||||
int value = item->text().toInt(&value_ok);
|
||||
if (value_ok)
|
||||
m_watch.SetEntryValue(index, static_cast<u32>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint value = item->text().toUInt(&value_ok);
|
||||
if (value_ok)
|
||||
m_watch.SetEntryValue(index, static_cast<u32>(value));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManagerDialog::updateScanValue()
|
||||
{
|
||||
QString value = m_ui.scanValue->text();
|
||||
if (value.startsWith(QStringLiteral("0x")))
|
||||
value.remove(0, 2);
|
||||
|
||||
bool ok = false;
|
||||
uint uint_value = value.toUInt(&ok, (m_ui.scanValueBase->currentIndex() > 0) ? 16 : 10);
|
||||
if (ok)
|
||||
m_scanner.SetValue(uint_value);
|
||||
}
|
||||
|
||||
void CheatManagerDialog::updateResults()
|
||||
{
|
||||
QSignalBlocker sb(m_ui.scanTable);
|
||||
m_ui.scanTable->setRowCount(0);
|
||||
|
||||
const MemoryScan::ResultVector& results = m_scanner.GetResults();
|
||||
if (!results.empty())
|
||||
{
|
||||
int row = 0;
|
||||
for (const MemoryScan::Result& res : m_scanner.GetResults())
|
||||
{
|
||||
m_ui.scanTable->insertRow(row);
|
||||
|
||||
QTableWidgetItem* address_item = new QTableWidgetItem(formatHexValue(res.address));
|
||||
address_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable));
|
||||
m_ui.scanTable->setItem(row, 0, address_item);
|
||||
|
||||
QTableWidgetItem* value_item = new QTableWidgetItem(formatValue(res.value, m_scanner.GetValueSigned()));
|
||||
m_ui.scanTable->setItem(row, 1, value_item);
|
||||
|
||||
QTableWidgetItem* previous_item = new QTableWidgetItem(formatValue(res.last_value, m_scanner.GetValueSigned()));
|
||||
previous_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable));
|
||||
m_ui.scanTable->setItem(row, 2, previous_item);
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
m_ui.scanResetSearch->setEnabled(!results.empty());
|
||||
m_ui.scanSearchAgain->setEnabled(!results.empty());
|
||||
m_ui.scanAddWatch->setEnabled(false);
|
||||
}
|
||||
|
||||
void CheatManagerDialog::updateResultsValues()
|
||||
{
|
||||
QSignalBlocker sb(m_ui.scanTable);
|
||||
|
||||
int row = 0;
|
||||
for (const MemoryScan::Result& res : m_scanner.GetResults())
|
||||
{
|
||||
if (res.value_changed)
|
||||
{
|
||||
QTableWidgetItem* item = m_ui.scanTable->item(row, 1);
|
||||
item->setText(formatValue(res.value, m_scanner.GetValueSigned()));
|
||||
item->setForeground(Qt::red);
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManagerDialog::updateWatch()
|
||||
{
|
||||
static constexpr std::array<const char*, 6> size_strings = {
|
||||
{QT_TR_NOOP("Byte"), QT_TR_NOOP("Halfword"), QT_TR_NOOP("Word"), QT_TR_NOOP("Signed Byte"),
|
||||
QT_TR_NOOP("Signed Halfword"), QT_TR_NOOP("Signed Word")}};
|
||||
|
||||
m_watch.UpdateValues();
|
||||
|
||||
QSignalBlocker sb(m_ui.watchTable);
|
||||
m_ui.watchTable->setRowCount(0);
|
||||
|
||||
const MemoryWatchList::EntryVector& entries = m_watch.GetEntries();
|
||||
if (!entries.empty())
|
||||
{
|
||||
int row = 0;
|
||||
for (const MemoryWatchList::Entry& res : entries)
|
||||
{
|
||||
m_ui.watchTable->insertRow(row);
|
||||
|
||||
QTableWidgetItem* freeze_item = new QTableWidgetItem();
|
||||
freeze_item->setFlags(freeze_item->flags() | (Qt::ItemIsEditable | Qt::ItemIsUserCheckable));
|
||||
freeze_item->setCheckState(res.freeze ? Qt::Checked : Qt::Unchecked);
|
||||
m_ui.watchTable->setItem(row, 0, freeze_item);
|
||||
|
||||
QTableWidgetItem* description_item = new QTableWidgetItem(QString::fromStdString(res.description));
|
||||
m_ui.watchTable->setItem(row, 1, description_item);
|
||||
|
||||
QTableWidgetItem* address_item = new QTableWidgetItem(formatHexValue(res.address));
|
||||
address_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable));
|
||||
m_ui.watchTable->setItem(row, 2, address_item);
|
||||
|
||||
QTableWidgetItem* size_item =
|
||||
new QTableWidgetItem(tr(size_strings[static_cast<u32>(res.size) + (res.is_signed ? 3 : 0)]));
|
||||
size_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable));
|
||||
m_ui.watchTable->setItem(row, 3, size_item);
|
||||
|
||||
QTableWidgetItem* value_item = new QTableWidgetItem(formatValue(res.value, res.is_signed));
|
||||
m_ui.watchTable->setItem(row, 4, value_item);
|
||||
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
m_ui.scanSaveWatch->setEnabled(!entries.empty());
|
||||
m_ui.scanRemoveWatch->setEnabled(false);
|
||||
}
|
||||
|
||||
void CheatManagerDialog::updateWatchValues()
|
||||
{
|
||||
QSignalBlocker sb(m_ui.watchTable);
|
||||
int row = 0;
|
||||
for (const MemoryWatchList::Entry& res : m_watch.GetEntries())
|
||||
{
|
||||
if (res.changed)
|
||||
m_ui.watchTable->item(row, 4)->setText(formatValue(res.value, res.is_signed));
|
||||
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManagerDialog::updateScanUi()
|
||||
{
|
||||
m_scanner.UpdateResultsValues();
|
||||
m_watch.UpdateValues();
|
||||
|
||||
updateResultsValues();
|
||||
updateWatchValues();
|
||||
}
|
71
src/duckstation-qt/cheatmanagerdialog.h
Normal file
71
src/duckstation-qt/cheatmanagerdialog.h
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include "core/cheats.h"
|
||||
#include "ui_cheatmanagerdialog.h"
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QTableWidget>
|
||||
#include <optional>
|
||||
|
||||
class CheatManagerDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheatManagerDialog(QWidget* parent);
|
||||
~CheatManagerDialog();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event);
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
|
||||
private Q_SLOTS:
|
||||
void resizeColumns();
|
||||
|
||||
CheatList* getCheatList() const;
|
||||
void updateCheatList();
|
||||
void saveCheatList();
|
||||
void cheatListCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
|
||||
void cheatListItemActivated(QTreeWidgetItem* item);
|
||||
void cheatListItemChanged(QTreeWidgetItem* item, int column);
|
||||
void activateCheat(u32 index);
|
||||
void newCategoryClicked();
|
||||
void addCodeClicked();
|
||||
void editCodeClicked();
|
||||
void deleteCodeClicked();
|
||||
void activateCodeClicked();
|
||||
void importClicked();
|
||||
void exportClicked();
|
||||
|
||||
void addToWatchClicked();
|
||||
void removeWatchClicked();
|
||||
void scanCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);
|
||||
void watchCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);
|
||||
void scanItemChanged(QTableWidgetItem* item);
|
||||
void watchItemChanged(QTableWidgetItem* item);
|
||||
void updateScanValue();
|
||||
void updateScanUi();
|
||||
|
||||
private:
|
||||
void setupAdditionalUi();
|
||||
void connectUi();
|
||||
void setUpdateTimerEnabled(bool enabled);
|
||||
void updateResults();
|
||||
void updateResultsValues();
|
||||
void updateWatch();
|
||||
void updateWatchValues();
|
||||
|
||||
QTreeWidgetItem* getItemForCheatIndex(u32 index) const;
|
||||
int getSelectedCheatIndex() const;
|
||||
int getSelectedResultIndex() const;
|
||||
int getSelectedWatchIndex() const;
|
||||
|
||||
Ui::CheatManagerDialog m_ui;
|
||||
|
||||
MemoryScan m_scanner;
|
||||
MemoryWatchList m_watch;
|
||||
|
||||
QTimer* m_update_timer = nullptr;
|
||||
};
|
550
src/duckstation-qt/cheatmanagerdialog.ui
Normal file
550
src/duckstation-qt/cheatmanagerdialog.ui
Normal file
@ -0,0 +1,550 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CheatManagerDialog</class>
|
||||
<widget class="QDialog" name="CheatManagerDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>864</width>
|
||||
<height>599</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Cheat Manager</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Cheat List</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="cheatListNewCategory">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&New Category...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cheatListAdd">
|
||||
<property name="text">
|
||||
<string>&Add Code...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cheatListEdit">
|
||||
<property name="text">
|
||||
<string>&Edit Code...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cheatListRemove">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Delete Code</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cheatListActivate">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Activate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cheatListImport">
|
||||
<property name="text">
|
||||
<string>Import...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cheatListExport">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Export...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTreeWidget" name="cheatList">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Activation</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Instructions</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Memory Scanner</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="scanTable">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Previous Value</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Search Parameters</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="scanValue"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="scanValueSigned">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Signed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Unsigned</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="scanValueBase">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Decimal</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Hex</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Data Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="scanSize">
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Byte (1 byte)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Halfword (2 bytes)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Word (4 bytes)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Operator:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="scanOperator">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Equal to...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Not Equal to...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Greater Than...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Greater or Equal...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Less Than...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Less or Equal...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Increased By...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Decreased By...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Changed By...</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Equal to Previous</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Not Equal to Previous</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Greater Than Previous</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Greater or Equal to Previous</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Less Than Previous</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Less or Equal to Previous</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Start Address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="scanStartAddress"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>End Address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="scanEndAddress"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanNewSearch">
|
||||
<property name="text">
|
||||
<string>New Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanSearchAgain">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search Again</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanResetSearch">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear Results</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="watchTable">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderHighlightSections">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Freeze</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Description</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanAddWatch">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add To Watch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanAddManualAddress">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add Manual Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanRemoveWatch">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove Watch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanLoadWatch">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load Watch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="scanSaveWatch">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save Watch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -56,6 +56,8 @@
|
||||
<ClCompile Include="audiosettingswidget.cpp" />
|
||||
<ClCompile Include="autoupdaterdialog.cpp" />
|
||||
<ClCompile Include="biossettingswidget.cpp" />
|
||||
<ClCompile Include="cheatmanagerdialog.cpp" />
|
||||
<ClCompile Include="cheatcodeeditordialog.cpp" />
|
||||
<ClCompile Include="consolesettingswidget.cpp" />
|
||||
<ClCompile Include="enhancementsettingswidget.cpp" />
|
||||
<ClCompile Include="gamelistmodel.cpp" />
|
||||
@ -86,6 +88,8 @@
|
||||
<QtMoc Include="aboutdialog.h" />
|
||||
<QtMoc Include="audiosettingswidget.h" />
|
||||
<QtMoc Include="biossettingswidget.h" />
|
||||
<QtMoc Include="cheatmanagerdialog.h" />
|
||||
<QtMoc Include="cheatcodeeditordialog.h" />
|
||||
<QtMoc Include="controllersettingswidget.h" />
|
||||
<QtMoc Include="enhancementsettingswidget.h" />
|
||||
<QtMoc Include="memorycardsettingswidget.h" />
|
||||
@ -181,6 +185,12 @@
|
||||
<QtUi Include="memorycardeditordialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="cheatmanagerdialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="cheatcodeeditordialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtResource Include="resources\resources.qrc">
|
||||
@ -193,6 +203,8 @@
|
||||
<ClCompile Include="$(IntDir)moc_autoupdaterdialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_advancedsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_biossettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_cheatmanagerdialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_cheatcodeeditordialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_consolesettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_controllersettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_enhancementsettingswidget.cpp" />
|
||||
|
@ -11,6 +11,7 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
// Register any standard types we need elsewhere
|
||||
qRegisterMetaType<std::optional<bool>>();
|
||||
qRegisterMetaType<std::function<void()>>();
|
||||
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "mainwindow.h"
|
||||
#include "aboutdialog.h"
|
||||
#include "autoupdaterdialog.h"
|
||||
#include "cheatmanagerdialog.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/host_display.h"
|
||||
#include "core/settings.h"
|
||||
@ -233,6 +234,12 @@ void MainWindow::onEmulationStopped()
|
||||
m_emulation_running = false;
|
||||
updateEmulationActions(false, false);
|
||||
switchToGameListView();
|
||||
|
||||
if (m_cheat_manager_dialog)
|
||||
{
|
||||
delete m_cheat_manager_dialog;
|
||||
m_cheat_manager_dialog = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onEmulationPaused(bool paused)
|
||||
@ -316,6 +323,8 @@ void MainWindow::onChangeDiscFromPlaylistMenuAboutToHide()
|
||||
void MainWindow::onCheatsMenuAboutToShow()
|
||||
{
|
||||
m_ui.menuCheats->clear();
|
||||
connect(m_ui.menuCheats->addAction(tr("Cheat Manager")), &QAction::triggered, this, &MainWindow::onToolsCheatManagerTriggered);
|
||||
m_ui.menuCheats->addSeparator();
|
||||
m_host_interface->populateCheatsMenu(m_ui.menuCheats);
|
||||
}
|
||||
|
||||
@ -645,6 +654,7 @@ void MainWindow::updateEmulationActions(bool starting, bool running)
|
||||
m_ui.actionViewSystemDisplay->setEnabled(starting || running);
|
||||
m_ui.menuChangeDisc->setDisabled(starting || !running);
|
||||
m_ui.menuCheats->setDisabled(starting || !running);
|
||||
m_ui.actionCheatManager->setDisabled(starting || !running);
|
||||
|
||||
m_ui.actionSaveState->setDisabled(starting || !running);
|
||||
m_ui.menuSaveState->setDisabled(starting || !running);
|
||||
@ -779,6 +789,7 @@ void MainWindow::connectSignals()
|
||||
connect(m_ui.actionAbout, &QAction::triggered, this, &MainWindow::onAboutActionTriggered);
|
||||
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, &MainWindow::onCheckForUpdatesActionTriggered);
|
||||
connect(m_ui.actionMemory_Card_Editor, &QAction::triggered, this, &MainWindow::onToolsMemoryCardEditorTriggered);
|
||||
connect(m_ui.actionCheatManager, &QAction::triggered, this, &MainWindow::onToolsCheatManagerTriggered);
|
||||
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
|
||||
connect(m_ui.actionGridViewShowTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowCoverTitles);
|
||||
connect(m_ui.actionGridViewZoomIn, &QAction::triggered, m_game_list_widget, [this]() {
|
||||
@ -1167,6 +1178,15 @@ void MainWindow::onToolsMemoryCardEditorTriggered()
|
||||
m_memory_card_editor_dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::onToolsCheatManagerTriggered()
|
||||
{
|
||||
if (!m_cheat_manager_dialog)
|
||||
m_cheat_manager_dialog = new CheatManagerDialog(this);
|
||||
|
||||
m_cheat_manager_dialog->setModal(false);
|
||||
m_cheat_manager_dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::onToolsOpenDataDirectoryTriggered()
|
||||
{
|
||||
QtUtils::OpenURL(this, QUrl::fromLocalFile(m_host_interface->getUserDirectoryRelativePath(QString())));
|
||||
|
@ -15,6 +15,7 @@ class QtHostInterface;
|
||||
class QtDisplayWidget;
|
||||
class AutoUpdaterDialog;
|
||||
class MemoryCardEditorDialog;
|
||||
class CheatManagerDialog;
|
||||
|
||||
class HostDisplay;
|
||||
struct GameListEntry;
|
||||
@ -76,6 +77,7 @@ private Q_SLOTS:
|
||||
void onAboutActionTriggered();
|
||||
void onCheckForUpdatesActionTriggered();
|
||||
void onToolsMemoryCardEditorTriggered();
|
||||
void onToolsCheatManagerTriggered();
|
||||
void onToolsOpenDataDirectoryTriggered();
|
||||
|
||||
void onGameListEntrySelected(const GameListEntry* entry);
|
||||
@ -127,6 +129,7 @@ private:
|
||||
SettingsDialog* m_settings_dialog = nullptr;
|
||||
AutoUpdaterDialog* m_auto_updater_dialog = nullptr;
|
||||
MemoryCardEditorDialog* m_memory_card_editor_dialog = nullptr;
|
||||
CheatManagerDialog* m_cheat_manager_dialog = nullptr;
|
||||
|
||||
bool m_emulation_running = false;
|
||||
};
|
||||
|
@ -205,6 +205,7 @@
|
||||
<string>&Tools</string>
|
||||
</property>
|
||||
<addaction name="actionMemory_Card_Editor"/>
|
||||
<addaction name="actionCheatManager"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionOpenDataDirectory"/>
|
||||
</widget>
|
||||
@ -712,6 +713,11 @@
|
||||
<string>Memory &Card Editor</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCheatManager">
|
||||
<property name="text">
|
||||
<string>C&heat Manager</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewGameGrid">
|
||||
<property name="text">
|
||||
<string>Game &Grid</string>
|
||||
|
@ -971,7 +971,7 @@ void QtHostInterface::populateCheatsMenu(QMenu* menu)
|
||||
QAction* action = menu->addAction(tr("&Load Cheats..."));
|
||||
connect(action, &QAction::triggered, [this]() {
|
||||
QString filename = QFileDialog::getOpenFileName(m_main_window, tr("Select Cheat File"), QString(),
|
||||
tr("PCSXR/Libretro Cheat Files (*.cht);;All Files (*.*)"));
|
||||
tr("PCSXR/Libretro Cheat Files (*.cht *.txt);;All Files (*.*)"));
|
||||
if (!filename.isEmpty())
|
||||
loadCheatList(filename);
|
||||
});
|
||||
@ -980,7 +980,7 @@ void QtHostInterface::populateCheatsMenu(QMenu* menu)
|
||||
action->setEnabled(has_cheat_list);
|
||||
connect(action, &QAction::triggered, [this]() {
|
||||
QString filename = QFileDialog::getSaveFileName(m_main_window, tr("Select Cheat File"), QString(),
|
||||
tr("PCSXR/Libretro Cheat Files (*.cht);;All Files (*.*)"));
|
||||
tr("PCSXR Cheat Files (*.cht);;All Files (*.*)"));
|
||||
if (!filename.isEmpty())
|
||||
SaveCheatList(filename.toUtf8().constData());
|
||||
});
|
||||
@ -1052,6 +1052,28 @@ void QtHostInterface::reloadPostProcessingShaders()
|
||||
ReloadPostProcessingShaders();
|
||||
}
|
||||
|
||||
void QtHostInterface::executeOnEmulationThread(std::function<void()> callback, bool wait)
|
||||
{
|
||||
if (isOnWorkerThread())
|
||||
{
|
||||
callback();
|
||||
if (wait)
|
||||
m_worker_thread_sync_execute_done.Signal();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(this, "executeOnEmulationThread", Qt::QueuedConnection,
|
||||
Q_ARG(std::function<void()>, callback), Q_ARG(bool, wait));
|
||||
if (wait)
|
||||
{
|
||||
// don't deadlock
|
||||
while (!m_worker_thread_sync_execute_done.TryWait(10))
|
||||
qApp->processEvents(QEventLoop::ExcludeSocketNotifiers);
|
||||
m_worker_thread_sync_execute_done.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void QtHostInterface::loadState(const QString& filename)
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
|
@ -167,6 +167,7 @@ public Q_SLOTS:
|
||||
void setCheatEnabled(quint32 index, bool enabled);
|
||||
void applyCheat(quint32 index);
|
||||
void reloadPostProcessingShaders();
|
||||
void executeOnEmulationThread(std::function<void()> callback, bool wait = false);
|
||||
|
||||
private Q_SLOTS:
|
||||
void doStopThread();
|
||||
@ -254,6 +255,7 @@ private:
|
||||
QThread* m_original_thread = nullptr;
|
||||
Thread* m_worker_thread = nullptr;
|
||||
QEventLoop* m_worker_thread_event_loop = nullptr;
|
||||
Common::Event m_worker_thread_sync_execute_done;
|
||||
|
||||
std::atomic_bool m_shutdown_flag{false};
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <QtWidgets/QScrollBar>
|
||||
#include <QtWidgets/QStyle>
|
||||
#include <QtWidgets/QTableView>
|
||||
#include <QtWidgets/QTreeView>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <map>
|
||||
@ -44,10 +45,17 @@ QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog)
|
||||
return widget;
|
||||
}
|
||||
|
||||
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths)
|
||||
template<typename T>
|
||||
ALWAYS_INLINE_RELEASE static void ResizeColumnsForView(T* view, const std::initializer_list<int>& widths)
|
||||
{
|
||||
const int min_column_width = view->horizontalHeader()->minimumSectionSize();
|
||||
const int max_column_width = view->horizontalHeader()->maximumSectionSize();
|
||||
QHeaderView* header;
|
||||
if constexpr (std::is_same_v<T, QTableView>)
|
||||
header = view->horizontalHeader();
|
||||
else
|
||||
header = view->header();
|
||||
|
||||
const int min_column_width = header->minimumSectionSize();
|
||||
const int max_column_width = header->maximumSectionSize();
|
||||
const int total_width =
|
||||
std::accumulate(widths.begin(), widths.end(), 0, [&min_column_width, &max_column_width](int a, int b) {
|
||||
return a + ((b < 0) ? 0 : std::clamp(b, min_column_width, max_column_width));
|
||||
@ -74,6 +82,16 @@ void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int
|
||||
}
|
||||
}
|
||||
|
||||
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths)
|
||||
{
|
||||
ResizeColumnsForView(view, widths);
|
||||
}
|
||||
|
||||
void ResizeColumnsForTreeView(QTreeView* view, const std::initializer_list<int>& widths)
|
||||
{
|
||||
ResizeColumnsForView(view, widths);
|
||||
}
|
||||
|
||||
static const std::map<int, QString> s_qt_key_names = {
|
||||
{Qt::Key_Escape, QStringLiteral("Escape")},
|
||||
{Qt::Key_Tab, QStringLiteral("Tab")},
|
||||
|
@ -2,10 +2,12 @@
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QMetaType>
|
||||
#include <QtCore/QString>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <optional>
|
||||
|
||||
Q_DECLARE_METATYPE(std::optional<bool>);
|
||||
Q_DECLARE_METATYPE(std::function<void()>);
|
||||
|
||||
class ByteStream;
|
||||
|
||||
@ -13,6 +15,7 @@ class QComboBox;
|
||||
class QFrame;
|
||||
class QKeyEvent;
|
||||
class QTableView;
|
||||
class QTreeView;
|
||||
class QWidget;
|
||||
class QUrl;
|
||||
|
||||
@ -27,6 +30,7 @@ QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog = true);
|
||||
/// Resizes columns of the table view to at the specified widths. A negative width will stretch the column to use the
|
||||
/// remaining space.
|
||||
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths);
|
||||
void ResizeColumnsForTreeView(QTreeView* view, const std::initializer_list<int>& widths);
|
||||
|
||||
/// Returns a string identifier for a Qt key ID.
|
||||
QString GetKeyIdentifier(int key);
|
||||
|
Reference in New Issue
Block a user