Mercurial > lcfOS
view python/hexedit.py @ 135:01d88140dc03
Improve hexedit
author | Windel Bouwman |
---|---|
date | Mon, 21 Jan 2013 21:12:36 +0100 |
parents | 1a50d6db24ed |
children | 9af544be5d2a |
line wrap: on
line source
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, scrollArea): super().__init__(scrollArea) self.scrollArea = scrollArea self.setFont(QFont('Courier', 18)) self.setFocusPolicy(Qt.StrongFocus) self.blinkcursor = False self.cursorX = 0 self.cursorY = 0 self.scrollArea = scrollArea self.Data = bytearray() t = QTimer(self) t.timeout.connect(self.updateCursor) t.setInterval(500) t.start() def updateCursor(self): self.blinkcursor = not self.blinkcursor self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight) def setCursorPosition(self, position): position = int(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 getCursorPosition(self): return self.cursorPosition CursorPosition = property(getCursorPosition, setCursorPosition) 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.gray) painter.setPen(Qt.gray) x = self.xposAscii - (GAP / 2) painter.drawLine(x, event.rect().top(), x, self.height()) 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): painter.drawText(self.xposAddr, ypos, '{0:08X}'.format(index)) xpos = self.xposHex xposA = self.xposAscii for colIndex in range(BYTES_PER_LINE): if index + colIndex < len(self.Data): b = self.Data[index + colIndex] bhex = '{0:02X}'.format(b) ba = chr(b) painter.drawText(xpos, ypos, bhex) painter.drawText(xposA, ypos, ba) xpos += 2 * self.charWidth xposA += self.charWidth ypos += self.charHeight # cursor if self.blinkcursor: painter.fillRect(self.cursorX, self.cursorY + self.charHeight - 2, self.charWidth, 2, Qt.black) def keyPressEvent(self, event): if event.matches(QKeySequence.MoveToNextChar): self.CursorPosition += 1 if event.matches(QKeySequence.MoveToPreviousChar): self.CursorPosition -= 1 if event.matches(QKeySequence.MoveToNextLine): self.CursorPosition += 2 * BYTES_PER_LINE if event.matches(QKeySequence.MoveToPreviousLine): self.CursorPosition -= 2 * BYTES_PER_LINE char = event.text().lower() if char and char in '0123456789abcdef': i = int(self.CursorPosition / 2) hb = self.CursorPosition % 2 v = int(char, 16) if hb == 0: # high half byte self.data[i] = (self.data[i] & 0xF) | (v << 4) else: self.data[i] = (self.data[i] & 0xF0) | v self.CursorPosition += 1 self.scrollArea.ensureVisible(self.cursorX, self.cursorY, self.charWidth, self.charHeight + 2) self.update() def cursorPositionAt(self, pos): """ Calculate cursor position at a certain point """ if pos.x() > self.xposHex and pos.x() < self.xposAscii: x = (pos.x() - self.xposHex) / self.charWidth y = int(pos.y() / self.charHeight) * 2 * BYTES_PER_LINE return x + y return 0 def mousePressEvent(self, event): cpos = self.cursorPositionAt(event.pos()) self.setCursorPosition(cpos) 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 * 2) * self.charWidth + GAP self.setMinimumWidth(self.xposAscii + self.charWidth * BYTES_PER_LINE) self.scrollArea.setMinimumWidth(self.xposAscii + self.charWidth * BYTES_PER_LINE) self.setMinimumHeight((int(len(self.Data) / BYTES_PER_LINE) + 1) * self.charHeight) 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.bv = BinViewer(self) self.setWidget(self.bv) self.setWidgetResizable(True) self.setFocusPolicy(Qt.NoFocus) if __name__ == '__main__': app = QApplication(sys.argv) he = HexEdit() he.show() he.bv.Data = bytearray(range(100)) * 8 + b'hjkfd' app.exec()