Skip to content

Instantly share code, notes, and snippets.

@zxmarcos
Created February 17, 2018 17:05
Show Gist options
  • Save zxmarcos/c7e2b31ebd890e8fee3b373881851853 to your computer and use it in GitHub Desktop.
Save zxmarcos/c7e2b31ebd890e8fee3b373881851853 to your computer and use it in GitHub Desktop.
DasmView Widget
#include <QtWidgets>
#include <limits>
#include <cstdint>
#include <algorithm>
#include "DasmView.h"
static inline qint64 map_value(qint64 input, qint64 is, qint64 ie, qint64 os, qint64 oe)
{
double slope = 1.0 * (oe - os) / (ie - is);
return os + floor(slope * (input - is) + 0.5);
}
DasmView::DasmView(QWidget *parent) :
QAbstractScrollArea(parent)
{
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_lowerAddress = 0;
m_higherAddress = 0x100000000;
m_firstMask = ~0;
m_sbMinValue = 0;
m_sbMaxValue = 0x100000000ULL >> 4;
verticalScrollBar()->setRange(m_sbMinValue, m_sbMaxValue - 1);
m_font = QFont("Andale Mono", 12);
setFont(m_font);
QFontMetrics metrics(m_font);
m_lineHeight = metrics.height();
m_descent = metrics.descent();
m_viewFirstAddr = 0;
m_currentAddr = 0;
m_selectedAddr = 0;
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(verticalScroll(int)));
viewport()->setFixedWidth(metrics.width('X') * 60);
m_addressWidth = metrics.width('0') * 10;
m_currentAddrColor = QColor(120, 200, 255);
m_selectedAddrColor = QColor(255, 200, 200, 200);
m_dasmBgColor = QColor(255, 255, 220);
m_addressBgColor = QColor(220, 255, 220);
m_dasmDisplace = 8;
}
DasmView::~DasmView()
{
}
void DasmView::paintEvent(QPaintEvent *event)
{
QPainter p(viewport());
p.setClipRect(event->rect());
p.fillRect(event->rect(), m_dasmBgColor);
int linesPerView = viewport()->rect().height() / m_lineHeight + 2;
Address address = m_viewFirstAddr;
if (linesPerView >= m_displayList.size())
m_displayList.resize(linesPerView * 2);
else if (linesPerView < m_displayList.size())
m_displayList.resize(linesPerView);
int dasmPosX = m_addressWidth + m_dasmDisplace;
p.fillRect(QRect(0, 0, m_addressWidth, viewport()->height()), m_addressBgColor);
for (int i = 0; i < linesPerView; i++) {
Result result;
if (m_dasmCallback) {
result = m_dasmCallback(address);
} else {
result = qMakePair(QString(), 1);
}
m_displayList[i] = address;
if (address >= std::numeric_limits<Address>::max())
break;
if (address == m_currentAddr)
p.fillRect(0, i * m_lineHeight, viewport()->width(), m_lineHeight, m_currentAddrColor);
if (address == m_selectedAddr)
p.fillRect(0, i * m_lineHeight, viewport()->width(), m_lineHeight, m_selectedAddrColor);
const int ypos = (i + 1) * m_lineHeight - m_descent;
// Draw address
p.drawText(4, ypos, QString("%0").arg(address, 8, 16, QChar('0')).toUpper());
// Draw dasm
p.drawText(dasmPosX, ypos, result.first);
// Check for address overflow
quint64 adr = static_cast<quint64>(address) + static_cast<quint64>(result.second);
if (adr >= 0x100000000)
break;
address += result.second;
}
p.drawLine(QLine(m_addressWidth, 0, m_addressWidth, viewport()->height()));
}
void DasmView::mousePressEvent(QMouseEvent *event)
{
int line = event->y() / m_lineHeight;
m_selectedAddr = m_displayList[line];
viewport()->update();
}
void DasmView::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Space) {
emit nextLine();
} else {
QAbstractScrollArea::keyPressEvent(event);
}
}
void DasmView::gotoAddress(Address addr)
{
int linesPerView = viewport()->rect().height() / m_lineHeight + 2;
m_currentAddr = addr;
auto iter = std::find(std::begin(m_displayList), std::end(m_displayList), addr);
if (iter == m_displayList.end()) {
int displace = (linesPerView / 2 - 1) * 16;
verticalScrollBar()->setValue(addr / 16);//(addr - displace) / 16);
} else if (std::distance(std::begin(m_displayList), iter) > linesPerView-3) {
verticalScrollBar()->setValue(addr / 16);
}
viewport()->update();
}
DasmView::Address DasmView::selectedAddress()
{
return m_selectedAddr;
}
void DasmView::verticalScroll(int value)
{
unsigned val = map_value(value, m_sbMinValue, m_sbMaxValue, m_lowerAddress, m_higherAddress);
m_viewFirstAddr = val & m_firstMask;
update();
}
void DasmView::setDasm(std::function<Result(Address)> dasm)
{
m_dasmCallback = dasm;
}
void DasmView::setAddressLimits(quint64 low, quint64 hi, Address mask)
{
m_lowerAddress = low;
m_higherAddress = hi;
m_firstMask = mask;
m_sbMinValue = 0;
m_sbMaxValue = hi / 16;
verticalScrollBar()->setRange(m_sbMinValue, m_sbMaxValue - 1);
}
DasmView::Address DasmView::cursorAddress()
{
return m_selectedAddr;
}
#ifndef DASMVIEW_H
#define DASMVIEW_H
#include <QFont>
#include <QAbstractScrollArea>
#include <QVector>
#include <QPair>
#include <cstdint>
#include <functional>
class DasmView : public QAbstractScrollArea
{
Q_OBJECT
public:
typedef QPair<QString,size_t> Result;
typedef uint32_t Address;
DasmView(QWidget *parent=0);
~DasmView();
Address selectedAddress();
void setDasm(std::function<Result(Address)> dasm);
void setAddressLimits(quint64 low, quint64 hi, Address mask);
Address cursorAddress();
public slots:
void gotoAddress(Address addr);
private slots:
void verticalScroll(int units);
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void mousePressEvent(QMouseEvent *event);
virtual void keyPressEvent(QKeyEvent *event);
signals:
void nextLine();
private:
quint64 m_lowerAddress;
quint64 m_higherAddress;
quint64 m_sbMinValue;
quint64 m_sbMaxValue;
Address m_firstMask;
std::function<Result(Address)> m_dasmCallback;
QVector<Address> m_displayList;
int m_addressWidth;
int m_dasmDisplace;
Address m_viewFirstAddr;
Address m_currentAddr;
Address m_selectedAddr;
QFont m_font;
QColor m_currentAddrColor;
QColor m_selectedAddrColor;
QColor m_dasmBgColor;
QColor m_addressBgColor;
int m_lineHeight;
int m_descent;
};
#endif // DASMVIEWEX_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment