--- /dev/null
+#include "preferences.h"
+#include "hexview.h"
+
+#include <QApplication>
+#include <QClipboard>
+#include <QDebug>
+#include <QPainter>
+#include <QPaintEvent>
+#include <QScrollArea>
+
+const int HEXCHARS_IN_LINE = 3 * 16;
+const int BYTES_PER_LINE = 16;
+const int GAP_ADR_HEX = 1;
+const int GAP_HEX_ASCII = 3;
+
+HexView::HexView(QScrollArea *parent) :
+ QWidget(parent)
+{
+ m_scrollArea = parent;
+ this->setObjectName("hexView");
+ m_scrollArea->setWidget(this);
+
+ resetSelection(0);
+}
+
+void HexView::setData(const QByteArray &data)
+{
+ m_data = data;
+ adjust();
+}
+
+int HexView::addressChars() const
+{
+ return QString("%1").arg(m_data.size(), 0, 16).length();
+}
+
+void HexView::adjust()
+{
+ int lines = (m_data.size() / BYTES_PER_LINE) + 1;
+ setMinimumHeight((lines + 1) * m_charHeight);
+
+ int addressArea = (addressChars() + GAP_ADR_HEX) * m_charWidth;
+ int hexArea = HEXCHARS_IN_LINE * m_charWidth;
+ int asciiArea = (GAP_HEX_ASCII + BYTES_PER_LINE) * m_charWidth;
+ setMinimumWidth(addressArea + hexArea + asciiArea);
+}
+
+int HexView::cursorPos(const QPoint &pos)
+{
+ int result = -1;
+ if (xPosHex() <= pos.x() && pos.x() < xPosAscii()) {
+ int x = (pos.x() - xPosHex()) / m_charWidth;
+ if (x % 3 == 0) {
+ x /= 3;
+ }
+ else {
+ x = (x / 3) + 1;
+ }
+ int y = pos.y() / m_charHeight;
+
+ result = x + y * BYTES_PER_LINE;
+
+ qDebug() << x << y << result;
+ }
+
+ return result;
+}
+
+void HexView::resetSelection(int index)
+{
+ m_selectionBegin = index;
+ m_selectionEnd = index;
+ m_selectionInit = index;
+
+ emit copyAvailable(false);
+}
+
+void HexView::setSelection(int index)
+{
+ if (index > m_selectionInit) {
+ m_selectionBegin = m_selectionInit;
+ m_selectionEnd = index;
+ }
+ else {
+ m_selectionBegin = index;
+ m_selectionEnd = m_selectionInit;
+ }
+
+ emit copyAvailable(m_selectionBegin != m_selectionEnd);
+}
+
+int HexView::xPosHex() const
+{
+ return m_charWidth * (addressChars() + GAP_ADR_HEX);
+}
+
+int HexView::xPosAscii() const
+{
+ return xPosHex() + m_charWidth * (HEXCHARS_IN_LINE + GAP_HEX_ASCII);
+}
+
+void HexView::onCopy()
+{
+ QString selected;
+ for (int idx = m_selectionBegin; idx < m_selectionEnd; ++idx) {
+ quint8 c = static_cast<quint8>(m_data[idx]);
+ selected.append(QString("%1 ").arg(c, 2, 16, QChar('0')));
+ }
+
+ QClipboard *clipboard = qApp->clipboard();
+ clipboard->setText(selected.trimmed());
+}
+
+void HexView::onScaleDown()
+{
+ Preferences prefs(this);
+ QFont font = prefs.getHexViewFont();
+ font.setPointSize(font.pointSize() - 1);
+ prefs.setHexViewFont(font);
+
+ setVisible(true);
+ adjust();
+ update();
+}
+
+void HexView::onScaleUp()
+{
+ Preferences prefs(this);
+ QFont font = prefs.getHexViewFont();
+ font.setPointSize(font.pointSize() + 1);
+ prefs.setHexViewFont(font);
+
+ setVisible(true);
+ adjust();
+ update();
+}
+
+void HexView::onSelectAll()
+{
+ resetSelection(0);
+ setSelection(m_data.size());
+
+ update();
+}
+
+void HexView::setVisible(bool visible)
+{
+ if (visible) {
+ Preferences prefs(this);
+ QPalette pal = this->palette();
+ pal.setColor(this->backgroundRole(), prefs.getHexViewBgColor());
+ pal.setColor(this->foregroundRole(), prefs.getHexViewFgColor());
+ this->setPalette(pal);
+ this->setAutoFillBackground(true);
+ this->setFont(prefs.getHexViewFont());
+
+ m_charHeight = fontMetrics().height();
+ m_charWidth = fontMetrics().width('9');
+ }
+
+ QWidget::setVisible(visible);
+}
+
+void HexView::mousePressEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton) {
+ int cPos = cursorPos(e->pos());
+ resetSelection(cPos);
+
+ update();
+ }
+}
+
+void HexView::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton) {
+ int cPos = cursorPos(e->pos());
+ int lineHead = (cPos / BYTES_PER_LINE) * BYTES_PER_LINE;
+ resetSelection(lineHead);
+ setSelection(lineHead + BYTES_PER_LINE);
+
+ update();
+ }
+}
+
+void HexView::mouseMoveEvent(QMouseEvent *e)
+{
+ m_scrollArea->ensureVisible(e->x(), e->y());
+
+ int cPos = cursorPos(e->pos());
+ if (cPos != -1) {
+ setSelection(cPos);
+ update();
+ }
+}
+
+void HexView::keyPressEvent(QKeyEvent *)
+{
+}
+
+void HexView::paintEvent(QPaintEvent *e)
+{
+ QPainter painter(this);
+
+ // 描画対象となるデータの範囲
+ int firstLineIdx = ((e->rect().top() / m_charHeight) - m_charHeight) * BYTES_PER_LINE;
+ if (firstLineIdx < 0)
+ firstLineIdx = 0;
+ int lastLineIdx = ((e->rect().bottom() / m_charHeight) + m_charHeight) * BYTES_PER_LINE;
+ if (lastLineIdx > m_data.size())
+ lastLineIdx = m_data.size();
+ // 描画開始位置
+ int yPosStart = (firstLineIdx / BYTES_PER_LINE) * m_charHeight + m_charHeight;
+
+ // アドレスエリア
+ QRect addressRect(e->rect());
+ addressRect.setLeft(0);
+ addressRect.setWidth(m_charWidth * addressChars());
+ painter.fillRect(addressRect, Qt::gray);
+ painter.setPen(Qt::black);
+ for (int lineIdx = firstLineIdx, yPos = yPosStart;
+ lineIdx < lastLineIdx;
+ lineIdx += BYTES_PER_LINE, yPos += m_charHeight)
+ {
+ QString address = QString("%1")
+ .arg(lineIdx, addressChars(), 16, QChar('0'));
+ painter.drawText(addressRect.left(), yPos, address);
+ }
+
+ // バイナリエリア
+ for (int lineIdx = firstLineIdx, yPos = yPosStart;
+ lineIdx < lastLineIdx;
+ lineIdx += BYTES_PER_LINE, yPos += m_charHeight)
+ {
+ int xPos = xPosHex();
+ for (int colIdx = 0;
+ lineIdx + colIdx < m_data.size() && colIdx < BYTES_PER_LINE;
+ colIdx++, xPos += m_charWidth * 3)
+ {
+ int Idx = lineIdx + colIdx;
+ if (m_selectionBegin <= Idx && Idx < m_selectionEnd) {
+ painter.setBackground(this->palette().highlight());
+ painter.setBackgroundMode(Qt::OpaqueMode);
+ painter.setPen(this->palette().highlightedText().color());
+ }
+ else {
+ painter.setPen(this->palette().color(this->foregroundRole()));
+ painter.setBackgroundMode(Qt::TransparentMode);
+ }
+
+ quint8 ch = static_cast<quint8>(m_data[Idx]);
+ QString s = QString("%1").arg(ch, 2, 16, QChar('0'));
+ if (colIdx < 8) {
+ s.append(" ");
+ painter.drawText(xPos, yPos, s);
+ }
+ else {
+ s.prepend(" ");
+ painter.drawText(xPos, yPos, s);
+ }
+ }
+ }
+
+ // アスキーエリア
+ painter.setPen(this->palette().color(this->foregroundRole()));
+ painter.setBackgroundMode(Qt::TransparentMode);
+ for (int lineIdx = firstLineIdx, yPos = yPosStart;
+ lineIdx < lastLineIdx;
+ lineIdx += BYTES_PER_LINE, yPos += m_charHeight)
+ {
+ int xPos = xPosAscii();
+
+ for (int colIdx = 0;
+ lineIdx + colIdx < m_data.size() && colIdx < BYTES_PER_LINE;
+ colIdx++, xPos += m_charWidth)
+ {
+ quint8 ch = static_cast<quint8>(m_data[lineIdx + colIdx]);
+ if (!::isprint(ch) && ch != ' ') {
+ ch = '.';
+ }
+ QString s = QString(ch).toLatin1();
+ painter.drawText(xPos, yPos, s);
+ }
+ }
+}