changeset 133:a816c683c1c0

Fixes in hexedit
author Windel Bouwman
date Sun, 20 Jan 2013 21:48:41 +0100
parents 205578c96a79
children 1a50d6db24ed
files python/hexedit.py
diffstat 1 files changed, 104 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- 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()
+