forked from eden-emu/eden
		
	
		
			
				
	
	
		
			857 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			857 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "qhexedit_p.h"
 | |
| #include "commands.h"
 | |
| 
 | |
| const int HEXCHARS_IN_LINE = 47;
 | |
| const int GAP_ADR_HEX = 10;
 | |
| const int GAP_HEX_ASCII = 16;
 | |
| const int BYTES_PER_LINE = 16;
 | |
| 
 | |
| QHexEditPrivate::QHexEditPrivate(QScrollArea *parent) : QWidget(parent)
 | |
| {
 | |
|     _undoStack = new QUndoStack(this);
 | |
| 
 | |
|     _scrollArea = parent;
 | |
|     setAddressWidth(4);
 | |
|     setAddressOffset(0);
 | |
|     setAddressArea(true);
 | |
|     setAsciiArea(true);
 | |
|     setHighlighting(true);
 | |
|     setOverwriteMode(true);
 | |
|     setReadOnly(false);
 | |
|     setAddressAreaColor(QColor(0xd4, 0xd4, 0xd4, 0xff));
 | |
|     setHighlightingColor(QColor(0xff, 0xff, 0x99, 0xff));
 | |
|     setSelectionColor(QColor(0x6d, 0x9e, 0xff, 0xff));
 | |
|     setFont(QFont("Courier", 10));
 | |
| 
 | |
|     _size = 0;
 | |
|     resetSelection(0);
 | |
| 
 | |
|     setFocusPolicy(Qt::StrongFocus);
 | |
| 
 | |
|     connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor()));
 | |
|     _cursorTimer.setInterval(500);
 | |
|     _cursorTimer.start();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setAddressOffset(int offset)
 | |
| {
 | |
|     _xData.setAddressOffset(offset);
 | |
|     adjust();
 | |
| }
 | |
| 
 | |
| int QHexEditPrivate::addressOffset()
 | |
| {
 | |
|     return _xData.addressOffset();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setData(const QByteArray &data)
 | |
| {
 | |
|     _xData.setData(data);
 | |
|     _undoStack->clear();
 | |
|     adjust();
 | |
|     setCursorPos(0);
 | |
| }
 | |
| 
 | |
| QByteArray QHexEditPrivate::data()
 | |
| {
 | |
|     return _xData.data();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setAddressAreaColor(const QColor &color)
 | |
| {
 | |
|     _addressAreaColor = color;
 | |
|     update();
 | |
| }
 | |
| 
 | |
| QColor QHexEditPrivate::addressAreaColor()
 | |
| {
 | |
|     return _addressAreaColor;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setHighlightingColor(const QColor &color)
 | |
| {
 | |
|     _highlightingColor = color;
 | |
|     update();
 | |
| }
 | |
| 
 | |
| QColor QHexEditPrivate::highlightingColor()
 | |
| {
 | |
|     return _highlightingColor;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setSelectionColor(const QColor &color)
 | |
| {
 | |
|     _selectionColor = color;
 | |
|     update();
 | |
| }
 | |
| 
 | |
| QColor QHexEditPrivate::selectionColor()
 | |
| {
 | |
|     return _selectionColor;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setReadOnly(bool readOnly)
 | |
| {
 | |
|     _readOnly = readOnly;
 | |
| }
 | |
| 
 | |
| bool QHexEditPrivate::isReadOnly()
 | |
| {
 | |
|     return _readOnly;
 | |
| }
 | |
| 
 | |
| XByteArray & QHexEditPrivate::xData()
 | |
| {
 | |
|     return _xData;
 | |
| }
 | |
| 
 | |
| int QHexEditPrivate::indexOf(const QByteArray & ba, int from)
 | |
| {
 | |
|     if (from > (_xData.data().length() - 1))
 | |
|         from = _xData.data().length() - 1;
 | |
|     int idx = _xData.data().indexOf(ba, from);
 | |
|     if (idx > -1)
 | |
|     {
 | |
|         int curPos = idx*2;
 | |
|         setCursorPos(curPos + ba.length()*2);
 | |
|         resetSelection(curPos);
 | |
|         setSelection(curPos + ba.length()*2);
 | |
|         ensureVisible();
 | |
|     }
 | |
|     return idx;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::insert(int index, const QByteArray & ba)
 | |
| {
 | |
|     if (ba.length() > 0)
 | |
|     {
 | |
|         if (_overwriteMode)
 | |
|         {
 | |
|             QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length());
 | |
|             _undoStack->push(arrayCommand);
 | |
|             emit dataChanged();
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::insert, index, ba, ba.length());
 | |
|             _undoStack->push(arrayCommand);
 | |
|             emit dataChanged();
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::insert(int index, char ch)
 | |
| {
 | |
|     QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::insert, index, ch);
 | |
|     _undoStack->push(charCommand);
 | |
|     emit dataChanged();
 | |
| }
 | |
| 
 | |
| int QHexEditPrivate::lastIndexOf(const QByteArray & ba, int from)
 | |
| {
 | |
|     from -= ba.length();
 | |
|     if (from < 0)
 | |
|         from = 0;
 | |
|     int idx = _xData.data().lastIndexOf(ba, from);
 | |
|     if (idx > -1)
 | |
|     {
 | |
|         int curPos = idx*2;
 | |
|         setCursorPos(curPos);
 | |
|         resetSelection(curPos);
 | |
|         setSelection(curPos + ba.length()*2);
 | |
|         ensureVisible();
 | |
|     }
 | |
|     return idx;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::remove(int index, int len)
 | |
| {
 | |
|     if (len > 0)
 | |
|     {
 | |
|         if (len == 1)
 | |
|         {
 | |
|             if (_overwriteMode)
 | |
|             {
 | |
|                 QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::replace, index, char(0));
 | |
|                 _undoStack->push(charCommand);
 | |
|                 emit dataChanged();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::remove, index, char(0));
 | |
|                 _undoStack->push(charCommand);
 | |
|                 emit dataChanged();
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             QByteArray ba = QByteArray(len, char(0));
 | |
|             if (_overwriteMode)
 | |
|             {
 | |
|                 QUndoCommand *arrayCommand = new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length());
 | |
|                 _undoStack->push(arrayCommand);
 | |
|                 emit dataChanged();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::remove, index, ba, len);
 | |
|                 _undoStack->push(arrayCommand);
 | |
|                 emit dataChanged();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::replace(int index, char ch)
 | |
| {
 | |
|     QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::replace, index, ch);
 | |
|     _undoStack->push(charCommand);
 | |
|     resetSelection();
 | |
|     emit dataChanged();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::replace(int index, const QByteArray & ba)
 | |
| {
 | |
|     QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length());
 | |
|     _undoStack->push(arrayCommand);
 | |
|     resetSelection();
 | |
|     emit dataChanged();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::replace(int pos, int len, const QByteArray &after)
 | |
| {
 | |
|     QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::replace, pos, after, len);
 | |
|     _undoStack->push(arrayCommand);
 | |
|     resetSelection();
 | |
|     emit dataChanged();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setAddressArea(bool addressArea)
 | |
| {
 | |
|     _addressArea = addressArea;
 | |
|     adjust();
 | |
| 
 | |
|     setCursorPos(_cursorPosition);
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setAddressWidth(int addressWidth)
 | |
| {
 | |
|     _xData.setAddressWidth(addressWidth);
 | |
| 
 | |
|     setCursorPos(_cursorPosition);
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setAsciiArea(bool asciiArea)
 | |
| {
 | |
|     _asciiArea = asciiArea;
 | |
|     adjust();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setFont(const QFont &font)
 | |
| {
 | |
|     QWidget::setFont(font);
 | |
|     adjust();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setHighlighting(bool mode)
 | |
| {
 | |
|     _highlighting = mode;
 | |
|     update();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setOverwriteMode(bool overwriteMode)
 | |
| {
 | |
|     _overwriteMode = overwriteMode;
 | |
| }
 | |
| 
 | |
| bool QHexEditPrivate::overwriteMode()
 | |
| {
 | |
|     return _overwriteMode;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::redo()
 | |
| {
 | |
|     _undoStack->redo();
 | |
|     emit dataChanged();
 | |
|     setCursorPos(_cursorPosition);
 | |
|     update();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::undo()
 | |
| {
 | |
|     _undoStack->undo();
 | |
|     emit dataChanged();
 | |
|     setCursorPos(_cursorPosition);
 | |
|     update();
 | |
| }
 | |
| 
 | |
| QString QHexEditPrivate::toRedableString()
 | |
| {
 | |
|     return _xData.toRedableString();
 | |
| }
 | |
| 
 | |
| 
 | |
| QString QHexEditPrivate::selectionToReadableString()
 | |
| {
 | |
|     return _xData.toRedableString(getSelectionBegin(), getSelectionEnd());
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::keyPressEvent(QKeyEvent *event)
 | |
| {
 | |
|     int charX = (_cursorX - _xPosHex) / _charWidth;
 | |
|     int posX = (charX / 3) * 2 + (charX % 3);
 | |
|     int posBa = (_cursorY / _charHeight) * BYTES_PER_LINE + posX / 2;
 | |
| 
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /* Cursor movements */
 | |
| /*****************************************************************************/
 | |
| 
 | |
|     if (event->matches(QKeySequence::MoveToNextChar))
 | |
|     {
 | |
|         setCursorPos(_cursorPosition + 1);
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::MoveToPreviousChar))
 | |
|     {
 | |
|         setCursorPos(_cursorPosition - 1);
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::MoveToEndOfLine))
 | |
|     {
 | |
|         setCursorPos(_cursorPosition | (2 * BYTES_PER_LINE -1));
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::MoveToStartOfLine))
 | |
|     {
 | |
|         setCursorPos(_cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)));
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::MoveToPreviousLine))
 | |
|     {
 | |
|         setCursorPos(_cursorPosition - (2 * BYTES_PER_LINE));
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::MoveToNextLine))
 | |
|     {
 | |
|         setCursorPos(_cursorPosition + (2 * BYTES_PER_LINE));
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
| 
 | |
|     if (event->matches(QKeySequence::MoveToNextPage))
 | |
|     {
 | |
|         setCursorPos(_cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE));
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::MoveToPreviousPage))
 | |
|     {
 | |
|         setCursorPos(_cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE));
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::MoveToEndOfDocument))
 | |
|     {
 | |
|         setCursorPos(_xData.size() * 2);
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::MoveToStartOfDocument))
 | |
|     {
 | |
|         setCursorPos(0);
 | |
|         resetSelection(_cursorPosition);
 | |
|     }
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /* Select commands */
 | |
| /*****************************************************************************/
 | |
|     if (event->matches(QKeySequence::SelectAll))
 | |
|     {
 | |
|         resetSelection(0);
 | |
|         setSelection(2*_xData.size() + 1);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectNextChar))
 | |
|     {
 | |
|         int pos = _cursorPosition + 1;
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectPreviousChar))
 | |
|     {
 | |
|         int pos = _cursorPosition - 1;
 | |
|         setSelection(pos);
 | |
|         setCursorPos(pos);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectEndOfLine))
 | |
|     {
 | |
|         int pos = _cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)) + (2 * BYTES_PER_LINE);
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectStartOfLine))
 | |
|     {
 | |
|         int pos = _cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE));
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectPreviousLine))
 | |
|     {
 | |
|         int pos = _cursorPosition - (2 * BYTES_PER_LINE);
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectNextLine))
 | |
|     {
 | |
|         int pos = _cursorPosition + (2 * BYTES_PER_LINE);
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
| 
 | |
|     if (event->matches(QKeySequence::SelectNextPage))
 | |
|     {
 | |
|         int pos = _cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE);
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectPreviousPage))
 | |
|     {
 | |
|         int pos = _cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE);
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectEndOfDocument))
 | |
|     {
 | |
|         int pos = _xData.size() * 2;
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
|     if (event->matches(QKeySequence::SelectStartOfDocument))
 | |
|     {
 | |
|         int pos = 0;
 | |
|         setCursorPos(pos);
 | |
|         setSelection(pos);
 | |
|     }
 | |
| 
 | |
| /*****************************************************************************/
 | |
| /* Edit Commands */
 | |
| /*****************************************************************************/
 | |
| if (!_readOnly)
 | |
| {
 | |
|     /* Hex input */
 | |
|         int key = int(event->text()[0].toLatin1());
 | |
|         if ((key>='0' && key<='9') || (key>='a' && key <= 'f'))
 | |
|         {
 | |
|             if (getSelectionBegin() != getSelectionEnd())
 | |
|             {
 | |
|                 posBa = getSelectionBegin();
 | |
|                 remove(posBa, getSelectionEnd() - posBa);
 | |
|                 setCursorPos(2*posBa);
 | |
|                 resetSelection(2*posBa);
 | |
|             }
 | |
| 
 | |
|             // If insert mode, then insert a byte
 | |
|             if (_overwriteMode == false)
 | |
|                 if ((charX % 3) == 0)
 | |
|                 {
 | |
|                     insert(posBa, char(0));
 | |
|                 }
 | |
| 
 | |
|             // Change content
 | |
|             if (_xData.size() > 0)
 | |
|             {
 | |
|                 QByteArray hexValue = _xData.data().mid(posBa, 1).toHex();
 | |
|                 if ((charX % 3) == 0)
 | |
|                     hexValue[0] = key;
 | |
|                 else
 | |
|                     hexValue[1] = key;
 | |
| 
 | |
|                 replace(posBa, QByteArray().fromHex(hexValue)[0]);
 | |
| 
 | |
|                 setCursorPos(_cursorPosition + 1);
 | |
|                 resetSelection(_cursorPosition);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /* Cut & Paste */
 | |
|         if (event->matches(QKeySequence::Cut))
 | |
|         {
 | |
|             QString result = QString();
 | |
|             for (int idx = getSelectionBegin(); idx < getSelectionEnd(); idx++)
 | |
|             {
 | |
|                 result += _xData.data().mid(idx, 1).toHex() + " ";
 | |
|                 if ((idx % 16) == 15)
 | |
|                     result.append("\n");
 | |
|             }
 | |
|             remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin());
 | |
|             QClipboard *clipboard = QApplication::clipboard();
 | |
|             clipboard->setText(result);
 | |
|             setCursorPos(getSelectionBegin());
 | |
|             resetSelection(getSelectionBegin());
 | |
|         }
 | |
| 
 | |
|         if (event->matches(QKeySequence::Paste))
 | |
|         {
 | |
|             QClipboard *clipboard = QApplication::clipboard();
 | |
|             QByteArray ba = QByteArray().fromHex(clipboard->text().toLatin1());
 | |
|             insert(_cursorPosition / 2, ba);
 | |
|             setCursorPos(_cursorPosition + 2 * ba.length());
 | |
|             resetSelection(getSelectionBegin());
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /* Delete char */
 | |
|         if (event->matches(QKeySequence::Delete))
 | |
|         {
 | |
|             if (getSelectionBegin() != getSelectionEnd())
 | |
|             {
 | |
|                 posBa = getSelectionBegin();
 | |
|                 remove(posBa, getSelectionEnd() - posBa);
 | |
|                 setCursorPos(2*posBa);
 | |
|                 resetSelection(2*posBa);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (_overwriteMode)
 | |
|                     replace(posBa, char(0));
 | |
|                 else
 | |
|                     remove(posBa, 1);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /* Backspace */
 | |
|         if ((event->key() == Qt::Key_Backspace) && (event->modifiers() == Qt::NoModifier))
 | |
|             {
 | |
|                 if (getSelectionBegin() != getSelectionEnd())
 | |
|                 {
 | |
|                     posBa = getSelectionBegin();
 | |
|                     remove(posBa, getSelectionEnd() - posBa);
 | |
|                     setCursorPos(2*posBa);
 | |
|                     resetSelection(2*posBa);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if (posBa > 0)
 | |
|                     {
 | |
|                         if (_overwriteMode)
 | |
|                             replace(posBa - 1, char(0));
 | |
|                         else
 | |
|                             remove(posBa - 1, 1);
 | |
|                         setCursorPos(_cursorPosition - 2);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|         /* undo */
 | |
|         if (event->matches(QKeySequence::Undo))
 | |
|         {
 | |
|             undo();
 | |
|         }
 | |
| 
 | |
|         /* redo */
 | |
|         if (event->matches(QKeySequence::Redo))
 | |
|         {
 | |
|             redo();
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     if (event->matches(QKeySequence::Copy))
 | |
|     {
 | |
|         QString result = QString();
 | |
|         for (int idx = getSelectionBegin(); idx < getSelectionEnd(); idx++)
 | |
|         {
 | |
|             result += _xData.data().mid(idx, 1).toHex() + " ";
 | |
|             if ((idx % 16) == 15)
 | |
|                 result.append('\n');
 | |
|         }
 | |
|         QClipboard *clipboard = QApplication::clipboard();
 | |
|         clipboard->setText(result);
 | |
|     }
 | |
| 
 | |
|     // Switch between insert/overwrite mode
 | |
|     if ((event->key() == Qt::Key_Insert) && (event->modifiers() == Qt::NoModifier))
 | |
|     {
 | |
|         _overwriteMode = !_overwriteMode;
 | |
|         setCursorPos(_cursorPosition);
 | |
|         overwriteModeChanged(_overwriteMode);
 | |
|     }
 | |
| 
 | |
|     ensureVisible();
 | |
|     update();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::mouseMoveEvent(QMouseEvent * event)
 | |
| {
 | |
|     _blink = false;
 | |
|     update();
 | |
|     int actPos = cursorPos(event->pos());
 | |
|     setCursorPos(actPos);
 | |
|     setSelection(actPos);
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::mousePressEvent(QMouseEvent * event)
 | |
| {
 | |
|     _blink = false;
 | |
|     update();
 | |
|     int cPos = cursorPos(event->pos());
 | |
|     resetSelection(cPos);
 | |
|     setCursorPos(cPos);
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::paintEvent(QPaintEvent *event)
 | |
| {
 | |
|     QPainter painter(this);
 | |
| 
 | |
|     // draw some patterns if needed
 | |
|     painter.fillRect(event->rect(), this->palette().color(QPalette::Base));
 | |
|     if (_addressArea)
 | |
|         painter.fillRect(QRect(_xPosAdr, event->rect().top(), _xPosHex - GAP_ADR_HEX + 2, height()), _addressAreaColor);
 | |
|     if (_asciiArea)
 | |
|     {
 | |
|         int linePos = _xPosAscii - (GAP_HEX_ASCII / 2);
 | |
|         painter.setPen(Qt::gray);
 | |
|         painter.drawLine(linePos, event->rect().top(), linePos, height());
 | |
|     }
 | |
| 
 | |
|     painter.setPen(this->palette().color(QPalette::WindowText));
 | |
| 
 | |
|     // calc position
 | |
|     int firstLineIdx = ((event->rect().top()/ _charHeight) - _charHeight) * BYTES_PER_LINE;
 | |
|     if (firstLineIdx < 0)
 | |
|         firstLineIdx = 0;
 | |
|     int lastLineIdx = ((event->rect().bottom() / _charHeight) + _charHeight) * BYTES_PER_LINE;
 | |
|     if (lastLineIdx > _xData.size())
 | |
|         lastLineIdx = _xData.size();
 | |
|     int yPosStart = ((firstLineIdx) / BYTES_PER_LINE) * _charHeight + _charHeight;
 | |
| 
 | |
|     // paint address area
 | |
|     if (_addressArea)
 | |
|     {
 | |
|         for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight)
 | |
|         {
 | |
|             QString address = QString("%1")
 | |
|                               .arg(lineIdx + _xData.addressOffset(), _xData.realAddressNumbers(), 16, QChar('0'));
 | |
|             painter.drawText(_xPosAdr, yPos, address);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // paint hex area
 | |
|     QByteArray hexBa(_xData.data().mid(firstLineIdx, lastLineIdx - firstLineIdx + 1).toHex());
 | |
|     QBrush highLighted = QBrush(_highlightingColor);
 | |
|     QPen colHighlighted = QPen(this->palette().color(QPalette::WindowText));
 | |
|     QBrush selected = QBrush(_selectionColor);
 | |
|     QPen colSelected = QPen(Qt::white);
 | |
|     QPen colStandard = QPen(this->palette().color(QPalette::WindowText));
 | |
| 
 | |
|     painter.setBackgroundMode(Qt::TransparentMode);
 | |
| 
 | |
|     for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight)
 | |
|     {
 | |
|         QByteArray hex;
 | |
|         int xPos = _xPosHex;
 | |
|         for (int colIdx = 0; ((lineIdx + colIdx) < _xData.size() && (colIdx < BYTES_PER_LINE)); colIdx++)
 | |
|         {
 | |
|             int posBa = lineIdx + colIdx;
 | |
|             if ((getSelectionBegin() <= posBa) && (getSelectionEnd() > posBa))
 | |
|             {
 | |
|                 painter.setBackground(selected);
 | |
|                 painter.setBackgroundMode(Qt::OpaqueMode);
 | |
|                 painter.setPen(colSelected);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (_highlighting)
 | |
|                 {
 | |
|                     // hilight diff bytes
 | |
|                     painter.setBackground(highLighted);
 | |
|                     if (_xData.dataChanged(posBa))
 | |
|                     {
 | |
|                         painter.setPen(colHighlighted);
 | |
|                         painter.setBackgroundMode(Qt::OpaqueMode);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         painter.setPen(colStandard);
 | |
|                         painter.setBackgroundMode(Qt::TransparentMode);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // render hex value
 | |
|             if (colIdx == 0)
 | |
|             {
 | |
|                 hex = hexBa.mid((lineIdx - firstLineIdx) * 2, 2);
 | |
|                 painter.drawText(xPos, yPos, hex);
 | |
|                 xPos += 2 * _charWidth;
 | |
|             } else {
 | |
|                 hex = hexBa.mid((lineIdx + colIdx - firstLineIdx) * 2, 2).prepend(" ");
 | |
|                 painter.drawText(xPos, yPos, hex);
 | |
|                 xPos += 3 * _charWidth;
 | |
|             }
 | |
| 
 | |
|         }
 | |
|     }
 | |
|     painter.setBackgroundMode(Qt::TransparentMode);
 | |
|     painter.setPen(this->palette().color(QPalette::WindowText));
 | |
| 
 | |
|     // paint ascii area
 | |
|     if (_asciiArea)
 | |
|     {
 | |
|         for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight)
 | |
|         {
 | |
|             int xPosAscii = _xPosAscii;
 | |
|             for (int colIdx = 0; ((lineIdx + colIdx) < _xData.size() && (colIdx < BYTES_PER_LINE)); colIdx++)
 | |
|             {
 | |
|                 painter.drawText(xPosAscii, yPos, _xData.asciiChar(lineIdx + colIdx));
 | |
|                 xPosAscii += _charWidth;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // paint cursor
 | |
|     if (_blink && !_readOnly && hasFocus())
 | |
|     {
 | |
|         if (_overwriteMode)
 | |
|             painter.fillRect(_cursorX, _cursorY + _charHeight - 2, _charWidth, 2, this->palette().color(QPalette::WindowText));
 | |
|         else
 | |
|             painter.fillRect(_cursorX, _cursorY, 2, _charHeight, this->palette().color(QPalette::WindowText));
 | |
|     }
 | |
| 
 | |
|     if (_size != _xData.size())
 | |
|     {
 | |
|         _size = _xData.size();
 | |
|         emit currentSizeChanged(_size);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setCursorPos(int position)
 | |
| {
 | |
|     // delete cursor
 | |
|     _blink = false;
 | |
|     update();
 | |
| 
 | |
|     // cursor in range?
 | |
|     if (_overwriteMode)
 | |
|     {
 | |
|         if (position > (_xData.size() * 2 - 1))
 | |
|             position = _xData.size() * 2 - 1;
 | |
|     } else {
 | |
|         if (position > (_xData.size() * 2))
 | |
|             position = _xData.size() * 2;
 | |
|     }
 | |
| 
 | |
|     if (position < 0)
 | |
|         position = 0;
 | |
| 
 | |
|     // calc position
 | |
|     _cursorPosition = position;
 | |
|     _cursorY = (position / (2 * BYTES_PER_LINE)) * _charHeight + 4;
 | |
|     int x = (position % (2 * BYTES_PER_LINE));
 | |
|     _cursorX = (((x / 2) * 3) + (x % 2)) * _charWidth + _xPosHex;
 | |
| 
 | |
|     // immiadately draw cursor
 | |
|     _blink = true;
 | |
|     update();
 | |
|     emit currentAddressChanged(_cursorPosition/2);
 | |
| }
 | |
| 
 | |
| int QHexEditPrivate::cursorPos(QPoint pos)
 | |
| {
 | |
|     int result = -1;
 | |
|     // find char under cursor
 | |
|     if ((pos.x() >= _xPosHex) && (pos.x() < (_xPosHex + HEXCHARS_IN_LINE * _charWidth)))
 | |
|     {
 | |
|         int x = (pos.x() - _xPosHex) / _charWidth;
 | |
|         if ((x % 3) == 0)
 | |
|             x = (x / 3) * 2;
 | |
|         else
 | |
|             x = ((x / 3) * 2) + 1;
 | |
|         int y = ((pos.y() - 3) / _charHeight) * 2 * BYTES_PER_LINE;
 | |
|         result = x + y;
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| int QHexEditPrivate::cursorPos()
 | |
| {
 | |
|     return _cursorPosition;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::resetSelection()
 | |
| {
 | |
|     _selectionBegin = _selectionInit;
 | |
|     _selectionEnd = _selectionInit;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::resetSelection(int pos)
 | |
| {
 | |
|     if (pos < 0)
 | |
|         pos = 0;
 | |
|     pos = pos / 2;
 | |
|     _selectionInit = pos;
 | |
|     _selectionBegin = pos;
 | |
|     _selectionEnd = pos;
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::setSelection(int pos)
 | |
| {
 | |
|     if (pos < 0)
 | |
|         pos = 0;
 | |
|     pos = pos / 2;
 | |
|     if (pos >= _selectionInit)
 | |
|     {
 | |
|         _selectionEnd = pos;
 | |
|         _selectionBegin = _selectionInit;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         _selectionBegin = pos;
 | |
|         _selectionEnd = _selectionInit;
 | |
|     }
 | |
| }
 | |
| 
 | |
| int QHexEditPrivate::getSelectionBegin()
 | |
| {
 | |
|     return _selectionBegin;
 | |
| }
 | |
| 
 | |
| int QHexEditPrivate::getSelectionEnd()
 | |
| {
 | |
|     return _selectionEnd;
 | |
| }
 | |
| 
 | |
| 
 | |
| void QHexEditPrivate::updateCursor()
 | |
| {
 | |
|     if (_blink)
 | |
|         _blink = false;
 | |
|     else
 | |
|         _blink = true;
 | |
|     update(_cursorX, _cursorY, _charWidth, _charHeight);
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::adjust()
 | |
| {
 | |
|     _charWidth = fontMetrics().width(QLatin1Char('9'));
 | |
|     _charHeight = fontMetrics().height();
 | |
| 
 | |
|     _xPosAdr = 0;
 | |
|     if (_addressArea)
 | |
|         _xPosHex = _xData.realAddressNumbers()*_charWidth + GAP_ADR_HEX;
 | |
|     else
 | |
|         _xPosHex = 0;
 | |
|     _xPosAscii = _xPosHex + HEXCHARS_IN_LINE * _charWidth + GAP_HEX_ASCII;
 | |
| 
 | |
|     // tell QAbstractScollbar, how big we are
 | |
|     setMinimumHeight(((_xData.size()/16 + 1) * _charHeight) + 5);
 | |
|     if(_asciiArea)
 | |
|         setMinimumWidth(_xPosAscii + (BYTES_PER_LINE * _charWidth));
 | |
|     else
 | |
|         setMinimumWidth(_xPosHex + HEXCHARS_IN_LINE * _charWidth);
 | |
| 
 | |
|     update();
 | |
| }
 | |
| 
 | |
| void QHexEditPrivate::ensureVisible()
 | |
| {
 | |
|     // scrolls to cursorx, cusory (which are set by setCursorPos)
 | |
|     // x-margin is 3 pixels, y-margin is half of charHeight
 | |
|     _scrollArea->ensureVisible(_cursorX, _cursorY + _charHeight/2, 3, _charHeight/2 + 2);
 | |
| }
 | 
