# HG changeset patch # User Windel Bouwman # Date 1358714921 -3600 # Node ID a816c683c1c03b731282ec344ad64c7d4689ceab # Parent 205578c96a79608936712c091e219cecdeffc2b5 Fixes in hexedit diff -r 205578c96a79 -r a816c683c1c0 python/hexedit.py --- a/python/hexedit.py Sun Jan 20 17:45:45 2013 +0100 +++ b/python/hexedit.py Sun Jan 20 21:48:41 2013 +0100 @@ -1,61 +1,111 @@ - +import sys from PyQt4.QtCore import * from PyQt4.QtGui import * +BYTES_PER_LINE = 8 +GAP = 16 + +class BinViewer(QWidget): + """ The view has an address, hex byte and ascii column """ + def __init__(self): + super().__init__() + self.setFont(QFont('Courier', 10)) + self.setFocusPolicy(Qt.StrongFocus) + self.blinkcursor = False + self.Data = bytearray() + t = QTimer(self) + t.timeout.connect(self.updateCursor) + t.setInterval(500) + t.start() + self.cursorX = 0 + self.cursorY = 0 + def updateCursor(self): + self.blinkcursor = not self.blinkcursor + self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight) + def setCursorPosition(self, position): + if position > len(self.Data) * 2 - 1: + position = len(self.Data) * 2 - 1 + if position < 0: + position = 0 + self.cursorPosition = position + x = position % (2 * BYTES_PER_LINE) + self.cursorX = self.xposHex + x * self.charWidth + self.cursorY = int(position / (2 * BYTES_PER_LINE)) * self.charHeight + 4 + self.blinkcursor = True + self.update() + def paintEvent(self, event): + painter = QPainter(self) + # Background: + painter.fillRect(event.rect(), self.palette().color(QPalette.Base)) + painter.fillRect(QRect(self.xposAddr, event.rect().top(), self.xposHex, self.height()), Qt.yellow) + + painter.setPen(Qt.black) + # first and last index + firstIndex = (int(event.rect().top() / self.charHeight) - self.charHeight) * BYTES_PER_LINE + if firstIndex < 0: + firstIndex = 0 + lastIndex = (int(event.rect().bottom() / self.charHeight) + self.charHeight) * BYTES_PER_LINE + if lastIndex < 0: + lastIndex = 0 + yposStart = int(firstIndex / BYTES_PER_LINE) * self.charHeight + self.charHeight + + ypos = yposStart + for index in range(firstIndex, lastIndex, BYTES_PER_LINE): + xpos = self.xposHex + for colIndex in range(BYTES_PER_LINE): + if index + colIndex < len(self.Data): + b = '{0:02X}'.format(self.Data[index + colIndex]) + painter.drawText(xpos, ypos, b) + xpos += 2 * self.charWidth + ypos += self.charHeight + + # cursor + if self.blinkcursor: + painter.fillRect(self.cursorX, self.cursorY + self.charHeight - 2, self.charWidth, 2, Qt.blue) + def keyPressEvent(self, event): + if event.matches(QKeySequence.MoveToNextChar): + self.setCursorPosition(self.cursorPosition + 1) + if event.matches(QKeySequence.MoveToPreviousChar): + self.setCursorPosition(self.cursorPosition - 1) + if event.matches(QKeySequence.MoveToNextLine): + self.setCursorPosition(self.cursorPosition + 2 * BYTES_PER_LINE) + if event.matches(QKeySequence.MoveToPreviousLine): + self.setCursorPosition(self.cursorPosition - 2 * BYTES_PER_LINE) + + def adjust(self): + self.charHeight = self.fontMetrics().height() + self.charWidth = self.fontMetrics().width('x') + self.xposAddr = 2 + self.xposHex = self.xposAddr + 8 * self.charWidth + GAP + self.xposAscii = self.xposHex + (BYTES_PER_LINE * 3 - 1) * self.charWidth + GAP + self.setMinimumWidth(self.xposAscii + self.charWidth * BYTES_PER_LINE) + self.setMinimumHeight((int(len(self.Data) / BYTES_PER_LINE) + 1) * self.charHeight) + self.update() + def getBytes(self, offset): + return bytes() + def setHexFile(self, hf): + self.hexfile = hf + self.update() + def getData(self): + return self.data + def setData(self, d): + self.data = d + self.adjust() + self.setCursorPosition(0) + Data = property(getData, setData) + class HexEdit(QScrollArea): def __init__(self): super().__init__() + self.setWidgetResizable(True) + self.bv = BinViewer() + self.setWidget(self.bv) + self.setFocusPolicy(Qt.NoFocus) -class BinViewer(QWidget): - """ - The binviewer consists of a hex view, a ascii view - and perhaps others.. - """ - def __init__(self): - super().__init__() - self.setFont(QFont('Courier')) - self.fontHeight = self.fontMetrics().height() - self.fontWidth = self.fontMetrics().width('x') - self.hexfile = hexfile.HexFile() - def paintEvent(self, event): - painter = QPainter(self) - br = QBrush(Qt.lightGray) - painter.setBrush(br) - h = self.height() - addressWidth = self.fontWidth * 8 - painter.drawRect(2, 2, addressWidth, h) - br2 = QBrush(Qt.yellow) - painter.setBrush(br2) - w = self.width() - byteWidth = self.fontWidth * (16 * 3 - 1) - painter.drawRect(addressWidth + 4, 2, byteWidth, h) - asciiWidth = self.fontWidth * 16 - br2 = QBrush(Qt.gray) - painter.setBrush(br2) - painter.drawRect(addressWidth + byteWidth + 4, 2, asciiWidth, h) - rows = int(h / self.fontHeight) + 1 - offset = 0 - for r in range(1, rows): - bts = self.getBytes(offset + r - 1) - addr = '{0:08X}'.format(r << 16) - painter.drawText(2, 2 + self.fontHeight * r, addr) - x = addressWidth + 4 - for b in bts: - b = '{0:02X}'.format(b) - painter.drawText(x, 2 + self.fontHeight * r, b) - x += 3 * self.fontWidth - x = addressWidth + byteWidth + 4 - for b in bts: - b = '{0}'.format(chr(b)) - painter.drawText(x, 2 + self.fontHeight * r, b) - x += 1 * self.fontWidth - def getBytes(self, offset): - if self.hexfile.regions: - r = self.hexfile.regions[0] - chunks = [r.data[p:p+16] for p in range(0, len(r.data), 16)] - if len(chunks) > offset: - return chunks[offset] - return bytes() - def setHexFile(self, hf): - self.hexfile = hf - self.update() +if __name__ == '__main__': + app = QApplication(sys.argv) + he = HexEdit() + he.show() + he.bv.Data = bytearray(range(100)) * 8 + app.exec() +