Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Highlighting memory changes in memory editor #306

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,12 @@
*.rar
*/out
*/bin

# No QTCreator project metadata files.
*.cflags
*.config
*.creator
*.cxxflags
*.files
*.includes

4 changes: 4 additions & 0 deletions bsnes/ui-qt/debugger/tools/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ MemoryEditor::MemoryEditor() {
autoUpdateBox = new QCheckBox("Auto update");
controlLayout->addWidget(autoUpdateBox);

trackMemoryBox = new QCheckBox("Highlight changes");
controlLayout->addWidget(trackMemoryBox);

refreshButton = new QPushButton("Refresh");
controlLayout->addWidget(refreshButton);

Expand Down Expand Up @@ -107,6 +110,7 @@ MemoryEditor::MemoryEditor() {
connect(refreshButton, SIGNAL(released()), this, SLOT(refresh()));
connect(exportButton, SIGNAL(released()), this, SLOT(exportMemory()));
connect(importButton, SIGNAL(released()), this, SLOT(importMemory()));
connect(trackMemoryBox, SIGNAL(toggled(bool)), editor, SLOT(setMemoryTracking(bool)));

searchPos = -1;
breakpointPos = -1;
Expand Down
1 change: 1 addition & 0 deletions bsnes/ui-qt/debugger/tools/memory.moc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class MemoryEditor : public Window {
QComboBox *source;
QLineEdit *addr;
QCheckBox *autoUpdateBox;
QCheckBox *trackMemoryBox;
QPushButton *refreshButton;

QHBoxLayout *toolLayout;
Expand Down
99 changes: 92 additions & 7 deletions bsnes/ui-qt/debugger/tools/qhexedit2/qhexedit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

const int HEXCHARS_IN_LINE = 47;
const int BYTES_PER_LINE = 16;
const quint16 FRAMES_TO_FADE_HEXBG = 30;


// ********************************************************************** Constructor, destructor
Expand All @@ -24,6 +25,9 @@ QHexEdit::QHexEdit(QWidget *parent) : QAbstractScrollArea(parent)
_cursorTimer.setInterval(500);
_cursorTimer.start();

_animatedHexChangeTimer.setInterval(64);
_animatedHexChangeTimer.start();

_editorSize = 0;
_lastEventSize = 0;
_asciiArea = true;
Expand All @@ -32,8 +36,10 @@ QHexEdit::QHexEdit(QWidget *parent) : QAbstractScrollArea(parent)
_highlighting = true;
_readOnly = false;
_cursorPosition = 0;
_trackMemoryChanges = false;

connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor()));
connect(&_animatedHexChangeTimer, SIGNAL(timeout()), this, SLOT(updateAnimatedHexValues()));
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust()));
connect(_undoStack, SIGNAL(indexChanged(int)), this, SLOT(dataChangedPrivate(int)));

Expand Down Expand Up @@ -73,8 +79,12 @@ QColor QHexEdit::addressAreaColor()

void QHexEdit::setAddressOffset(qint64 addressOffset)
{
_addressOffset = addressOffset;
adjust();
{
ScopedMemoryTracker tracker(this);
_addressOffset = addressOffset;
adjust();
}

setCursorPosition(_cursorPosition);
viewport()->update();
}
Expand All @@ -86,8 +96,11 @@ qint64 QHexEdit::addressOffset()

void QHexEdit::setEditorSize(qint64 size)
{
_editorSize = size;
adjust();
{
ScopedMemoryTracker tracker(this);
_editorSize = size;
adjust();
}
setCursorPosition(_cursorPosition);
viewport()->update();
}
Expand Down Expand Up @@ -183,6 +196,12 @@ void QHexEdit::setHighlighting(bool highlighting)
viewport()->update();
}

void QHexEdit::setMemoryTracking(bool mode)
{
_trackMemoryChanges = mode;
refresh();
}

bool QHexEdit::highlighting()
{
return _highlighting;
Expand Down Expand Up @@ -738,6 +757,7 @@ void QHexEdit::paintEvent(QPaintEvent *event)
for (int colIdx = 0; ((bPosLine + colIdx) < _dataShown.size() and (colIdx < BYTES_PER_LINE)); colIdx++)
{
QColor c = viewport()->palette().color(QPalette::Base);
QColor accent = viewport()->palette().color(QPalette::Link);
painter.setPen(colStandard);

qint64 posBa = _bPosFirst + bPosLine + colIdx;
Expand Down Expand Up @@ -777,6 +797,11 @@ void QHexEdit::paintEvent(QPaintEvent *event)
r.setRect(pxPosX - _pxCharWidth, pxPosY - _pxCharHeight + _pxSelectionSub, 3*_pxCharWidth, _pxCharHeight);
painter.fillRect(r, c);
hex = _hexDataShown.mid((bPosLine + colIdx) * 2, 2);
if (_trackMemoryChanges && _hexChangesMap.contains(_bPosFirst + colIdx + row * BYTES_PER_LINE + _addressOffset)) {
const qreal value = _hexChangesMap[_bPosFirst + colIdx + row * BYTES_PER_LINE + _addressOffset];
accent.setAlphaF(value / qreal(FRAMES_TO_FADE_HEXBG));
painter.fillRect(r, accent);
}
painter.drawText(pxPosX, pxPosY, hex);
pxPosX += 3*_pxCharWidth;

Expand Down Expand Up @@ -918,16 +943,22 @@ void QHexEdit::refresh(bool showCursor)
{
if (showCursor)
ensureVisible();
readBuffers();

{
ScopedMemoryTracker tracker(this);
readBuffers();
}

viewport()->update();
}

void QHexEdit::readBuffers()
{
_dataShown.clear();
for (qint64 i = _bPosFirst; i < qMin(_editorSize, _bPosLast + BYTES_PER_LINE + 1); i++)
for (qint64 i = _bPosFirst; i < qMin(_editorSize, _bPosLast + BYTES_PER_LINE + 1); i++) {
_dataShown.append(reader ? reader(i) : 0);

}

_hexDataShown = QByteArray(_dataShown.toHex());
}

Expand Down Expand Up @@ -965,3 +996,57 @@ void QHexEdit::updateCursor()
viewport()->update(_cursorRect);
}

void QHexEdit::updateAnimatedHexValues()
{
if (_trackMemoryChanges && !_hexChangesMap.keys().empty()) {
QHash<qint64, quint16>::iterator it = _hexChangesMap.begin();
while (it != _hexChangesMap.end()) {
it.value()--;
if (it.value() == 0) {
it = _hexChangesMap.erase(it);
} else {
++it;
}
}

viewport()->update();
}
}

QHexEdit::ScopedMemoryTracker::ScopedMemoryTracker(QHexEdit *editor)
: _editor(editor){
Q_ASSERT(_editor);
const QByteArray currentData = _editor->_dataShown;
const qint64 first = _editor->_bPosFirst;
const qint64 last = _editor->_bPosLast;
const qint64 editorSize = _editor->_editorSize;

for (qint64 i = first; i < qMin(editorSize, last + BYTES_PER_LINE + 1); i++) {
const qint64 addr = i + _editor->_addressOffset;
char value = currentData.at(i-first);
_dataHash.insert(addr, value);
}
}

QHexEdit::ScopedMemoryTracker::~ScopedMemoryTracker() {
const QByteArray currentData = _editor->_dataShown;
const qint64 first = _editor->_bPosFirst;
const qint64 last = _editor->_bPosLast;
const qint64 editorSize = _editor->_editorSize;

for (qint64 i = first; i < qMin(editorSize, last + BYTES_PER_LINE + 1); i++) {
const qint64 addr = i + _editor->_addressOffset;
// Track any changes to memory we saw when the object was created, and
// register those changes with the memory tracker...
char value = currentData.at(i-first);
if (_dataHash.contains(addr) && _dataHash[addr] != value) {
if (_editor->_hexChangesMap.contains(addr)) {
_editor->_hexChangesMap[addr] = FRAMES_TO_FADE_HEXBG;
} else {
_editor->_hexChangesMap.insert(addr, FRAMES_TO_FADE_HEXBG);
}
}
}
}


25 changes: 23 additions & 2 deletions bsnes/ui-qt/debugger/tools/qhexedit2/qhexedit.moc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,26 @@ class QHexEdit : public QAbstractScrollArea
/*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/
Q_PROPERTY(QFont font READ font WRITE setFont)

private:
/* Tracks values associated with certain memory addresses,
* and registers any changes in those values to _hexChangesMap */
struct ScopedMemoryTracker {
ScopedMemoryTracker(QHexEdit* editor);

~ScopedMemoryTracker();

private:
QHexEdit* _editor;
QHash<qint64, quint16> _dataHash;
};

public:
/*! Creates an instance of QHexEdit.
\param parent Parent widget of QHexEdit.
*/
QHexEdit(QWidget *parent=0);

// Access to data of qhexedit

function<uint8_t (unsigned)> reader;
function<void (unsigned, uint8_t)> writer;
function<uint8_t (unsigned)> usage;
Expand Down Expand Up @@ -246,11 +258,16 @@ public slots:
*/
void setAsciiArea(bool asciiArea);

/*! Switch the highlighting feature on or of.
/*! Switch the highlighting feature on or off.
\param mode true (show it), false (hide it).
*/
void setHighlighting(bool mode);

/*! Switch memory change tracking feature on or off.
\param state true (enabled), false (disabled).
*/
void setMemoryTracking(bool mode);

/*! Undoes the last operation. If there is no operation to undo, i.e.
there is no undo step in the undo/redo history, nothing happens.
*/
Expand Down Expand Up @@ -321,6 +338,7 @@ private slots:
void adjust(); // recalc pixel positions
void dataChangedPrivate(int idx=0); // emit dataChanged() signal
void updateCursor(); // update blinking cursor
void updateAnimatedHexValues(); // update animated hex value change effect.

private:
// Name convention: pixel positions start with _px
Expand Down Expand Up @@ -368,6 +386,9 @@ private slots:
qint64 _editorSize;
QByteArray _dataShown; // data in the current View
QByteArray _hexDataShown; // data in view, transformed to hex
bool _trackMemoryChanges; // Whether we should be rendering hex value changes.
QTimer _animatedHexChangeTimer; // timer used for animating hax value change background color.
QHash<qint64, quint16> _hexChangesMap; // Map of changed indices to number of frames left for fade transition.
qint64 _lastEventSize; // size, which was emitted last time
QByteArray _markedShown; // marked data in view
bool _modified; // Is any data in editor modified?
Expand Down