Skip to content

Commit 0e477c6

Browse files
committed
Add history to goto dialogues
1 parent bb7d72f commit 0e477c6

File tree

10 files changed

+236
-26
lines changed

10 files changed

+236
-26
lines changed

gui/qt/CEmu.pro

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ SOURCES += \
292292
../../core/bus.c \
293293
keyhistorywidget.cpp \
294294
tablewidget.cpp \
295+
gotodialog.cpp \
295296
basicdebugger.cpp
296297

297298
linux|macx: SOURCES += ../../core/os/os-linux.c
@@ -390,7 +391,8 @@ HEADERS += \
390391
archive/extractor.h \
391392
../../core/bus.h \
392393
keyhistorywidget.h \
393-
tablewidget.h
394+
tablewidget.h \
395+
gotodialog.h
394396

395397
FORMS += \
396398
mainwindow.ui \

gui/qt/debugger.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,24 @@
2222
#include "../../core/realclock.h"
2323
#include "../../core/sha256.h"
2424
#include "../../core/schedule.h"
25+
#include "gotodialog.h"
2526

2627
#include <QtWidgets/QToolTip>
2728
#include <QtCore/QFileInfo>
2829
#include <QtCore/QRegularExpression>
2930
#include <QtWidgets/QMessageBox>
3031
#include <QtWidgets/QInputDialog>
32+
#include <QtWidgets/QComboBox>
33+
#include <QtWidgets/QDialogButtonBox>
34+
#include <QtWidgets/QVBoxLayout>
35+
#include <QtWidgets/QLabel>
36+
#include <QtWidgets/QLineEdit>
3137
#include <QtWidgets/QScrollBar>
3238
#include <QtNetwork/QNetworkReply>
3339
#include <QtGui/QClipboard>
3440
#include <QtGui/QWindow>
3541
#include <QtGui/QScreen>
42+
#include <algorithm>
3643

3744
#ifdef _MSC_VER
3845
#include <direct.h>
@@ -1968,16 +1975,26 @@ void MainWindow::disasmUpdateAddr(int base, bool pane) {
19681975
// ------------------------------------------------
19691976

19701977
void MainWindow::gotoPressed() {
1971-
bool accept;
1972-
19731978
if (m_gotoAddr.isEmpty()) {
19741979
m_gotoAddr = m_disasm->getSelectedAddr();
19751980
}
19761981

1977-
QString address = getAddressString(m_gotoAddr, &accept);
1982+
GotoDialog dlg(m_gotoAddr, m_disasmGotoHistory, this);
1983+
if (dlg.exec() == QDialog::Accepted) {
1984+
QString typed = dlg.text().toUpper().trimmed();
1985+
bool ok = false;
1986+
QString resolved = resolveAddressOrEquate(typed, &ok);
1987+
if (ok) {
1988+
m_gotoAddr = typed;
1989+
disasmUpdateAddr(static_cast<int>(hex2int(resolved)), false);
19781990

1979-
if (accept) {
1980-
disasmUpdateAddr(hex2int(m_gotoAddr = address), false);
1991+
auto &hist = m_disasmGotoHistory;
1992+
hist.erase(std::remove_if(hist.begin(), hist.end(), [&](const QString &s){ return s.compare(typed, Qt::CaseInsensitive) == 0; }), hist.end());
1993+
hist.insert(hist.begin(), typed);
1994+
if (hist.size() > 50) { hist.resize(50); }
1995+
} else {
1996+
QMessageBox::warning(this, MSG_WARNING, tr("Error when reading input string"));
1997+
}
19811998
}
19821999
}
19832000

gui/qt/gotodialog.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include "gotodialog.h"
2+
3+
#include <QtWidgets/QComboBox>
4+
#include <QtWidgets/QDialogButtonBox>
5+
#include <QtWidgets/QLabel>
6+
#include <QtWidgets/QVBoxLayout>
7+
#include <QtWidgets/QSizePolicy>
8+
9+
GotoDialog::GotoDialog(const QString &seed,
10+
const std::vector<QString> &history,
11+
QWidget *parent)
12+
: QDialog(parent) {
13+
setWindowTitle(tr("Goto"));
14+
auto *layout = new QVBoxLayout(this); // NOLINT: Qt parent-ownership handles deletion
15+
16+
auto *label = new QLabel(tr("Input Address (Or Equate):"), this); // NOLINT: Qt parent-ownership handles deletion
17+
layout->addWidget(label);
18+
19+
m_combo = new QComboBox(this); // NOLINT: Qt parent-ownership handles deletion
20+
m_combo->setEditable(true);
21+
22+
for (const QString &h : history) {
23+
m_combo->addItem(h);
24+
}
25+
if (!seed.isEmpty()) {
26+
m_combo->setEditText(seed.toUpper());
27+
}
28+
layout->addWidget(m_combo);
29+
30+
auto *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); // NOLINT: Qt parent-ownership handles deletion
31+
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
32+
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
33+
layout->addWidget(buttons);
34+
35+
layout->setSizeConstraint(QLayout::SetFixedSize);
36+
setMinimumWidth(360);
37+
38+
setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, true);
39+
40+
m_combo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
41+
m_combo->setFixedHeight(m_combo->sizeHint().height());
42+
adjustSize();
43+
}
44+
45+
QString GotoDialog::text() const {
46+
return m_combo ? m_combo->currentText() : QString();
47+
}

gui/qt/gotodialog.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifndef GOTODIALOG_H
2+
#define GOTODIALOG_H
3+
4+
#include <QtWidgets/QDialog>
5+
#include <QtCore/QString>
6+
#include <vector>
7+
8+
QT_BEGIN_NAMESPACE
9+
class QComboBox;
10+
QT_END_NAMESPACE
11+
12+
class GotoDialog : public QDialog {
13+
Q_OBJECT
14+
public:
15+
explicit GotoDialog(const QString &seed,
16+
const std::vector<QString> &history,
17+
QWidget *parent = nullptr);
18+
19+
[[nodiscard]] QString text() const;
20+
21+
private:
22+
QComboBox *m_combo = nullptr;
23+
};
24+
25+
#endif // GOTODIALOG_H

gui/qt/mainwindow.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,35 @@ MainWindow::MainWindow(CEmuOpts &cliOpts, QWidget *p) : QMainWindow(p), ui(new U
638638
setDebugIgnoreBreakpoints(m_config->value(SETTING_DEBUGGER_BREAK_IGNORE, false).toBool());
639639
setDebugSoftCommands(m_config->value(SETTING_DEBUGGER_ENABLE_SOFT, true).toBool());
640640
setAllowAnyRev(m_config->value(SETTING_DEBUGGER_ALLOW_ANY_REV, false).toBool());
641+
642+
// disassembly goto history
643+
{
644+
const QStringList list = m_config->value(SETTING_DEBUGGER_DISASM_GOTO_HISTORY).toStringList();
645+
m_disasmGotoHistory.clear();
646+
m_disasmGotoHistory.reserve(list.size());
647+
for (const QString &s : list) {
648+
QString t = s.toUpper().trimmed();
649+
if (!t.isEmpty()) {
650+
m_disasmGotoHistory.push_back(t);
651+
if (m_disasmGotoHistory.size() >= 50) { break; }
652+
}
653+
}
654+
}
655+
656+
// memory editors goto history
657+
{
658+
const QStringList list = m_config->value(SETTING_DEBUGGER_MEM_GOTO_HISTORY).toStringList();
659+
m_memGotoHistory.clear();
660+
m_memGotoHistory.reserve(list.size());
661+
for (const QString &s : list) {
662+
QString t = s.toUpper().trimmed();
663+
if (!t.isEmpty()) {
664+
m_memGotoHistory.push_back(t);
665+
if (m_memGotoHistory.size() >= 50) { break; }
666+
}
667+
}
668+
}
669+
641670
setPythonEdition(qvariant_cast<Qt::CheckState>(m_config->value(SETTING_PYTHON_EDITION, Qt::PartiallyChecked)));
642671
setNormalOs(m_config->value(SETTING_DEBUGGER_NORM_OS, true).toBool());
643672
setDebugLcdDma(!m_config->value(SETTING_DEBUGGER_IGNORE_DMA, true).toBool());

gui/qt/mainwindow.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <QtCore/QStandardPaths>
3434

3535
#include <functional>
36+
#include <vector>
3637

3738
QT_BEGIN_NAMESPACE
3839
class QButtonGroup;
@@ -727,6 +728,10 @@ private slots:
727728
QString m_RamGotoAddr;
728729
QString m_memGotoAddr;
729730

731+
std::vector<QString> m_disasmGotoHistory;
732+
733+
std::vector<QString> m_memGotoHistory;
734+
730735
QString m_pathConfig;
731736
QMenu *m_menuDocks;
732737
QMenu *m_menuDebug;
@@ -781,6 +786,8 @@ private slots:
781786

782787
// Settings definitions
783788
static const QString SETTING_DEBUGGER_TEXT_SIZE;
789+
static const QString SETTING_DEBUGGER_DISASM_GOTO_HISTORY;
790+
static const QString SETTING_DEBUGGER_MEM_GOTO_HISTORY;
784791
static const QString SETTING_DEBUGGER_DISASM_SPACE;
785792
static const QString SETTING_DEBUGGER_DISASM_TAB;
786793
static const QString SETTING_DEBUGGER_RESTORE_ON_OPEN;

gui/qt/memorywidget.cpp

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "mainwindow.h"
22
#include "ui_mainwindow.h"
33
#include "searchwidget.h"
4+
#include "gotodialog.h"
45
#include "dockwidget.h"
56
#include "utils.h"
67
#include "../../core/schedule.h"
@@ -12,6 +13,7 @@
1213
#include <QtCore/QRegularExpression>
1314
#include <QtWidgets/QMessageBox>
1415
#include <QtWidgets/QInputDialog>
16+
#include <algorithm>
1517
#include <QtWidgets/QScrollBar>
1618

1719
#ifdef _MSC_VER
@@ -105,24 +107,43 @@ void MainWindow::memUpdateEdit(HexWidget *edit, bool force) {
105107
}
106108

107109
void MainWindow::flashGotoPressed() {
108-
bool accept = false;
109-
QString addrStr = getAddressString(m_flashGotoAddr, &accept);
110-
111-
if (accept) {
112-
m_flashGotoAddr = addrStr;
113-
ui->flashEdit->setFocus();
114-
ui->flashEdit->setOffset(hex2int(addrStr));
110+
if (GotoDialog dlg(m_flashGotoAddr, m_memGotoHistory, this); dlg.exec() == QDialog::Accepted) {
111+
const QString typed = dlg.text().toUpper().trimmed();
112+
bool ok = false;
113+
const QString resolved = resolveAddressOrEquate(typed, &ok);
114+
if (ok) {
115+
m_flashGotoAddr = typed;
116+
ui->flashEdit->setFocus();
117+
ui->flashEdit->setOffset(hex2int(resolved));
118+
119+
auto &hist = m_memGotoHistory;
120+
std::erase_if(hist, [&](const QString &s){ return s.compare(typed, Qt::CaseInsensitive) == 0; });
121+
hist.insert(hist.begin(), typed);
122+
if (hist.size() > 50) { hist.resize(50); }
123+
} else {
124+
QMessageBox::warning(this, MSG_WARNING, tr("Error when reading input string"));
125+
}
115126
}
116127
}
117128

118129
void MainWindow::ramGotoPressed() {
119-
bool accept = false;
120-
QString addrStr = getAddressString(m_RamGotoAddr, &accept);
121-
122-
if (accept) {
123-
m_RamGotoAddr = addrStr;
124-
ui->ramEdit->setFocus();
125-
ui->ramEdit->setOffset(hex2int(addrStr) - 0xD00000);
130+
GotoDialog dlg(m_RamGotoAddr, m_memGotoHistory, this);
131+
if (dlg.exec() == QDialog::Accepted) {
132+
const QString typed = dlg.text().toUpper().trimmed();
133+
bool ok = false;
134+
const QString resolved = resolveAddressOrEquate(typed, &ok);
135+
if (ok) {
136+
m_RamGotoAddr = typed;
137+
ui->ramEdit->setFocus();
138+
ui->ramEdit->setOffset(hex2int(resolved) - 0xD00000);
139+
140+
auto &hist = m_memGotoHistory;
141+
std::erase_if(hist, [&](const QString &s){ return s.compare(typed, Qt::CaseInsensitive) == 0; });
142+
hist.insert(hist.begin(), typed);
143+
if (hist.size() > 50) { hist.resize(50); }
144+
} else {
145+
QMessageBox::warning(this, MSG_WARNING, tr("Error when reading input string"));
146+
}
126147
}
127148
}
128149

@@ -194,11 +215,22 @@ void MainWindow::memGotoEdit(HexWidget *edit) {
194215
return;
195216
}
196217

197-
bool accept = false;
198-
QString address = getAddressString(m_memGotoAddr, &accept);
199-
200-
if (accept) {
201-
memGoto(edit, static_cast<uint32_t>(hex2int(m_memGotoAddr = address)));
218+
GotoDialog dlg(m_memGotoAddr, m_memGotoHistory, this);
219+
if (dlg.exec() == QDialog::Accepted) {
220+
QString typed = dlg.text().toUpper().trimmed();
221+
bool ok = false;
222+
QString resolved = resolveAddressOrEquate(typed, &ok);
223+
if (ok) {
224+
m_memGotoAddr = typed;
225+
memGoto(edit, static_cast<uint32_t>(hex2int(resolved)));
226+
// MRU update
227+
auto &hist = m_memGotoHistory;
228+
hist.erase(std::remove_if(hist.begin(), hist.end(), [&](const QString &s){ return s.compare(typed, Qt::CaseInsensitive) == 0; }), hist.end());
229+
hist.insert(hist.begin(), typed);
230+
if (hist.size() > 50) { hist.resize(50); }
231+
} else {
232+
QMessageBox::warning(this, MSG_WARNING, tr("Error when reading input string"));
233+
}
202234
}
203235
}
204236

gui/qt/settings.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#endif
3434

3535
const QString MainWindow::SETTING_DEBUGGER_TEXT_SIZE = QStringLiteral("Debugger/text_size");
36+
const QString MainWindow::SETTING_DEBUGGER_DISASM_GOTO_HISTORY = QStringLiteral("Debugger/disasm_goto_history");
37+
const QString MainWindow::SETTING_DEBUGGER_MEM_GOTO_HISTORY = QStringLiteral("Debugger/mem_goto_history");
3638
const QString MainWindow::SETTING_DEBUGGER_RESTORE_ON_OPEN = QStringLiteral("Debugger/restore_on_open");
3739
const QString MainWindow::SETTING_DEBUGGER_SAVE_ON_CLOSE = QStringLiteral("Debugger/save_on_close");
3840
const QString MainWindow::SETTING_DEBUGGER_RESET_OPENS = QStringLiteral("Debugger/open_on_reset");
@@ -1280,6 +1282,22 @@ void MainWindow::saveSettings() {
12801282
m_config->setValue(SETTING_WINDOW_KEYHISTORY_DOCKS, m_docksKeyHistory);
12811283
m_config->setValue(SETTING_WINDOW_KEYHISTORY_CONFIG, QVariant::fromValue(m_docksKeyHistorySize));
12821284

1285+
// Disassembly Goto history
1286+
{
1287+
QStringList list;
1288+
list.reserve(static_cast<int>(m_disasmGotoHistory.size()));
1289+
for (const QString &s : m_disasmGotoHistory) { list.append(s); }
1290+
m_config->setValue(SETTING_DEBUGGER_DISASM_GOTO_HISTORY, list);
1291+
}
1292+
1293+
// Memory editors Goto history
1294+
{
1295+
QStringList list;
1296+
list.reserve(static_cast<int>(m_memGotoHistory.size()));
1297+
for (const QString &s : m_memGotoHistory) { list.append(s); }
1298+
m_config->setValue(SETTING_DEBUGGER_MEM_GOTO_HISTORY, list);
1299+
}
1300+
12831301
saveDebug();
12841302
stateSaveInfo();
12851303
recentSaveInfo();
@@ -1368,4 +1386,3 @@ void MainWindow::keymapExport() {
13681386
bool MainWindow::isFirstRun() {
13691387
return !m_config->value(SETTING_FIRST_RUN, false).toBool();
13701388
}
1371-

gui/qt/utils.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,37 @@ QString int2hex(uint32_t a, uint8_t l) {
5959
return QString::number(a, 16).rightJustified(l, '0', true).toUpper();
6060
}
6161

62+
QString resolveAddressOrEquate(const QString &input, bool *ok) {
63+
if (ok) {
64+
*ok = false;
65+
}
66+
QString in = input.toUpper().trimmed();
67+
if (in.isEmpty()) {
68+
return {};
69+
}
70+
71+
if (QString equ = getAddressOfEquate(in.toStdString()); !equ.isEmpty()) {
72+
if (ok) { *ok = true; }
73+
return equ;
74+
}
75+
76+
QString s = in;
77+
if (s.startsWith(QStringLiteral("0X"))) {
78+
s = s.mid(2);
79+
}
80+
if (s.isEmpty() || s.length() > 6) {
81+
return {};
82+
}
83+
std::string ss = s.toStdString();
84+
if (ss.find_first_not_of("0123456789ABCDEF") != std::string::npos) {
85+
return {};
86+
}
87+
88+
const auto value = static_cast<uint32_t>(hex2int(in));
89+
if (ok) { *ok = true; }
90+
return int2hex(value, 6);
91+
}
92+
6293
std::string calc_var_content_string(const calc_var_t &var) {
6394
decltype(&tivars::TypeHandlers::TH_TempEqu::makeStringFromData) func;
6495
// We need to special case some specific temp-equ variables...

gui/qt/utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ QString sendingROM(QDragEnterEvent *e, bool *value);
4242
// integer to hex strings and vice versa
4343
int hex2int(const QString &str);
4444
QString int2hex(uint32_t a, uint8_t l);
45+
46+
QString resolveAddressOrEquate(const QString &input, bool *ok);
47+
4548
void guiDelay(int ms);
4649

4750
bool isProcRunning(pid_t procID);

0 commit comments

Comments
 (0)