comparison python/hexedit.py @ 133:a816c683c1c0

Fixes in hexedit
author Windel Bouwman
date Sun, 20 Jan 2013 21:48:41 +0100
parents 205578c96a79
children 1a50d6db24ed
comparison
equal deleted inserted replaced
132:205578c96a79 133:a816c683c1c0
1 1 import sys
2 from PyQt4.QtCore import * 2 from PyQt4.QtCore import *
3 from PyQt4.QtGui import * 3 from PyQt4.QtGui import *
4
5 BYTES_PER_LINE = 8
6 GAP = 16
7
8 class BinViewer(QWidget):
9 """ The view has an address, hex byte and ascii column """
10 def __init__(self):
11 super().__init__()
12 self.setFont(QFont('Courier', 10))
13 self.setFocusPolicy(Qt.StrongFocus)
14 self.blinkcursor = False
15 self.Data = bytearray()
16 t = QTimer(self)
17 t.timeout.connect(self.updateCursor)
18 t.setInterval(500)
19 t.start()
20 self.cursorX = 0
21 self.cursorY = 0
22 def updateCursor(self):
23 self.blinkcursor = not self.blinkcursor
24 self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight)
25 def setCursorPosition(self, position):
26 if position > len(self.Data) * 2 - 1:
27 position = len(self.Data) * 2 - 1
28 if position < 0:
29 position = 0
30 self.cursorPosition = position
31 x = position % (2 * BYTES_PER_LINE)
32 self.cursorX = self.xposHex + x * self.charWidth
33 self.cursorY = int(position / (2 * BYTES_PER_LINE)) * self.charHeight + 4
34 self.blinkcursor = True
35 self.update()
36 def paintEvent(self, event):
37 painter = QPainter(self)
38 # Background:
39 painter.fillRect(event.rect(), self.palette().color(QPalette.Base))
40 painter.fillRect(QRect(self.xposAddr, event.rect().top(), self.xposHex, self.height()), Qt.yellow)
41
42 painter.setPen(Qt.black)
43 # first and last index
44 firstIndex = (int(event.rect().top() / self.charHeight) - self.charHeight) * BYTES_PER_LINE
45 if firstIndex < 0:
46 firstIndex = 0
47 lastIndex = (int(event.rect().bottom() / self.charHeight) + self.charHeight) * BYTES_PER_LINE
48 if lastIndex < 0:
49 lastIndex = 0
50 yposStart = int(firstIndex / BYTES_PER_LINE) * self.charHeight + self.charHeight
51
52 ypos = yposStart
53 for index in range(firstIndex, lastIndex, BYTES_PER_LINE):
54 xpos = self.xposHex
55 for colIndex in range(BYTES_PER_LINE):
56 if index + colIndex < len(self.Data):
57 b = '{0:02X}'.format(self.Data[index + colIndex])
58 painter.drawText(xpos, ypos, b)
59 xpos += 2 * self.charWidth
60 ypos += self.charHeight
61
62 # cursor
63 if self.blinkcursor:
64 painter.fillRect(self.cursorX, self.cursorY + self.charHeight - 2, self.charWidth, 2, Qt.blue)
65 def keyPressEvent(self, event):
66 if event.matches(QKeySequence.MoveToNextChar):
67 self.setCursorPosition(self.cursorPosition + 1)
68 if event.matches(QKeySequence.MoveToPreviousChar):
69 self.setCursorPosition(self.cursorPosition - 1)
70 if event.matches(QKeySequence.MoveToNextLine):
71 self.setCursorPosition(self.cursorPosition + 2 * BYTES_PER_LINE)
72 if event.matches(QKeySequence.MoveToPreviousLine):
73 self.setCursorPosition(self.cursorPosition - 2 * BYTES_PER_LINE)
74
75 def adjust(self):
76 self.charHeight = self.fontMetrics().height()
77 self.charWidth = self.fontMetrics().width('x')
78 self.xposAddr = 2
79 self.xposHex = self.xposAddr + 8 * self.charWidth + GAP
80 self.xposAscii = self.xposHex + (BYTES_PER_LINE * 3 - 1) * self.charWidth + GAP
81 self.setMinimumWidth(self.xposAscii + self.charWidth * BYTES_PER_LINE)
82 self.setMinimumHeight((int(len(self.Data) / BYTES_PER_LINE) + 1) * self.charHeight)
83 self.update()
84 def getBytes(self, offset):
85 return bytes()
86 def setHexFile(self, hf):
87 self.hexfile = hf
88 self.update()
89 def getData(self):
90 return self.data
91 def setData(self, d):
92 self.data = d
93 self.adjust()
94 self.setCursorPosition(0)
95 Data = property(getData, setData)
4 96
5 class HexEdit(QScrollArea): 97 class HexEdit(QScrollArea):
6 def __init__(self): 98 def __init__(self):
7 super().__init__() 99 super().__init__()
100 self.setWidgetResizable(True)
101 self.bv = BinViewer()
102 self.setWidget(self.bv)
103 self.setFocusPolicy(Qt.NoFocus)
8 104
9 class BinViewer(QWidget): 105 if __name__ == '__main__':
10 """ 106 app = QApplication(sys.argv)
11 The binviewer consists of a hex view, a ascii view 107 he = HexEdit()
12 and perhaps others.. 108 he.show()
13 """ 109 he.bv.Data = bytearray(range(100)) * 8
14 def __init__(self): 110 app.exec()
15 super().__init__() 111
16 self.setFont(QFont('Courier'))
17 self.fontHeight = self.fontMetrics().height()
18 self.fontWidth = self.fontMetrics().width('x')
19 self.hexfile = hexfile.HexFile()
20 def paintEvent(self, event):
21 painter = QPainter(self)
22 br = QBrush(Qt.lightGray)
23 painter.setBrush(br)
24 h = self.height()
25 addressWidth = self.fontWidth * 8
26 painter.drawRect(2, 2, addressWidth, h)
27 br2 = QBrush(Qt.yellow)
28 painter.setBrush(br2)
29 w = self.width()
30 byteWidth = self.fontWidth * (16 * 3 - 1)
31 painter.drawRect(addressWidth + 4, 2, byteWidth, h)
32 asciiWidth = self.fontWidth * 16
33 br2 = QBrush(Qt.gray)
34 painter.setBrush(br2)
35 painter.drawRect(addressWidth + byteWidth + 4, 2, asciiWidth, h)
36 rows = int(h / self.fontHeight) + 1
37 offset = 0
38 for r in range(1, rows):
39 bts = self.getBytes(offset + r - 1)
40 addr = '{0:08X}'.format(r << 16)
41 painter.drawText(2, 2 + self.fontHeight * r, addr)
42 x = addressWidth + 4
43 for b in bts:
44 b = '{0:02X}'.format(b)
45 painter.drawText(x, 2 + self.fontHeight * r, b)
46 x += 3 * self.fontWidth
47 x = addressWidth + byteWidth + 4
48 for b in bts:
49 b = '{0}'.format(chr(b))
50 painter.drawText(x, 2 + self.fontHeight * r, b)
51 x += 1 * self.fontWidth
52 def getBytes(self, offset):
53 if self.hexfile.regions:
54 r = self.hexfile.regions[0]
55 chunks = [r.data[p:p+16] for p in range(0, len(r.data), 16)]
56 if len(chunks) > offset:
57 return chunks[offset]
58 return bytes()
59 def setHexFile(self, hf):
60 self.hexfile = hf
61 self.update()