diff 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 diff
--- a/python/hexedit.py	Mon Jan 21 20:24:40 2013 +0100
+++ b/python/hexedit.py	Mon Jan 21 21:12:36 2013 +0100
@@ -8,8 +8,9 @@
 class BinViewer(QWidget):
    """ The view has an address, hex byte and ascii column """
    def __init__(self, scrollArea):
-      super().__init__()
-      self.setFont(QFont('Courier', 10))
+      super().__init__(scrollArea)
+      self.scrollArea = scrollArea
+      self.setFont(QFont('Courier', 18))
       self.setFocusPolicy(Qt.StrongFocus)
       self.blinkcursor = False
       self.cursorX = 0
@@ -24,6 +25,7 @@
       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:
@@ -34,11 +36,17 @@
       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.yellow)
+      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
@@ -55,43 +63,63 @@
          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 = '{0:02X}'.format(self.Data[index + colIndex])
-               painter.drawText(xpos, ypos, b)
+               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.blue)
+         painter.fillRect(self.cursorX, self.cursorY + self.charHeight - 2, self.charWidth, 2, Qt.black)
    def keyPressEvent(self, event):
       if event.matches(QKeySequence.MoveToNextChar):
-         self.setCursorPosition(self.cursorPosition + 1)
+         self.CursorPosition += 1
       if event.matches(QKeySequence.MoveToPreviousChar):
-         self.setCursorPosition(self.cursorPosition - 1)
+         self.CursorPosition -= 1
       if event.matches(QKeySequence.MoveToNextLine):
-         self.setCursorPosition(self.cursorPosition + 2 * BYTES_PER_LINE)
+         self.CursorPosition += 2 * BYTES_PER_LINE
       if event.matches(QKeySequence.MoveToPreviousLine):
-         self.setCursorPosition(self.cursorPosition - 2 * BYTES_PER_LINE)
-      self.ensureVisible()
+         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 ensureVisible(self):
-      self.scrollArea.ensureVisible(self.cursorX, self.cursorY + self.charHeight, 3, self.charHeight / 2 + 2)
+   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 * 3 - 1) * 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 getBytes(self, offset):
-      return bytes()
-   def setHexFile(self, hf):
-      self.hexfile = hf
-      self.update()
    def getData(self):
       return self.data
    def setData(self, d):
@@ -103,15 +131,15 @@
 class HexEdit(QScrollArea):
    def __init__(self):
       super().__init__()
-      self.setWidgetResizable(True)
       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
+   he.bv.Data = bytearray(range(100)) * 8 + b'hjkfd'
    app.exec()