comparison python/hexedit.py @ 136:9af544be5d2a

Added hexfile edit
author Windel Bouwman
date Wed, 23 Jan 2013 21:54:14 +0100
parents 01d88140dc03
children 0a540ce31cd5
comparison
equal deleted inserted replaced
135:01d88140dc03 136:9af544be5d2a
1 import sys 1 import sys
2 from PyQt4.QtCore import * 2 from PyQt4.QtCore import *
3 from PyQt4.QtGui import * 3 from PyQt4.QtGui import *
4 4
5 BYTES_PER_LINE = 8 5 BYTES_PER_LINE = 8
6 GAP = 16 6 GAP = 12
7
8 def clamp(minimum, x, maximum):
9 return max(minimum, min(x, maximum))
10
11 def asciiChar(v):
12 if v < 0x20 or v > 0x7e:
13 return '.'
14 else:
15 return chr(v)
7 16
8 class BinViewer(QWidget): 17 class BinViewer(QWidget):
9 """ The view has an address, hex byte and ascii column """ 18 """ The view has an address, hex byte and ascii column """
10 def __init__(self, scrollArea): 19 def __init__(self, scrollArea):
11 super().__init__(scrollArea) 20 super().__init__(scrollArea)
12 self.scrollArea = scrollArea 21 self.scrollArea = scrollArea
13 self.setFont(QFont('Courier', 18)) 22 self.setFont(QFont('Courier', 18))
14 self.setFocusPolicy(Qt.StrongFocus) 23 self.setFocusPolicy(Qt.StrongFocus)
15 self.blinkcursor = False 24 self.blinkcursor = False
16 self.cursorX = 0 25 self.cursorX = self.cursorY = 0
17 self.cursorY = 0
18 self.scrollArea = scrollArea 26 self.scrollArea = scrollArea
19 self.Data = bytearray() 27 self.Data = bytearray()
28 self.Offset = 0
20 t = QTimer(self) 29 t = QTimer(self)
21 t.timeout.connect(self.updateCursor) 30 t.timeout.connect(self.updateCursor)
22 t.setInterval(500) 31 t.setInterval(500)
23 t.start() 32 t.start()
24 def updateCursor(self): 33 def updateCursor(self):
25 self.blinkcursor = not self.blinkcursor 34 self.blinkcursor = not self.blinkcursor
26 self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight) 35 self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight)
27 def setCursorPosition(self, position): 36 def setCursorPosition(self, position):
28 position = int(position) 37 position = clamp(0, int(position), len(self.Data) * 2 - 1)
29 if position > len(self.Data) * 2 - 1:
30 position = len(self.Data) * 2 - 1
31 if position < 0:
32 position = 0
33 self.cursorPosition = position 38 self.cursorPosition = position
34 x = position % (2 * BYTES_PER_LINE) 39 x = position % (2 * BYTES_PER_LINE)
35 self.cursorX = self.xposHex + x * self.charWidth 40 self.cursorX = self.xposHex + x * self.charWidth
36 self.cursorY = int(position / (2 * BYTES_PER_LINE)) * self.charHeight + 4 41 self.cursorY = int(position / (2 * BYTES_PER_LINE)) * self.charHeight + 2
37 self.blinkcursor = True 42 self.blinkcursor = True
38 self.update() 43 self.update()
39 def getCursorPosition(self): 44 def getCursorPosition(self):
40 return self.cursorPosition 45 return self.cursorPosition
41 CursorPosition = property(getCursorPosition, setCursorPosition) 46 CursorPosition = property(getCursorPosition, setCursorPosition)
47 def getOffset(self):
48 return self.offset
49 def setOffset(self, off):
50 self.offset = off
51 self.update()
52 Offset = property(getOffset, setOffset)
42 def paintEvent(self, event): 53 def paintEvent(self, event):
54 # Helper variables:
55 er = event.rect()
56 chw, chh = self.charWidth, self.charHeight
43 painter = QPainter(self) 57 painter = QPainter(self)
44 # Background: 58 # Background:
45 painter.fillRect(event.rect(), self.palette().color(QPalette.Base)) 59 painter.fillRect(er, self.palette().color(QPalette.Base))
46 painter.fillRect(QRect(self.xposAddr, event.rect().top(), self.xposHex, self.height()), Qt.gray) 60 painter.fillRect(QRect(self.xposAddr, er.top(), 8 * chw, er.bottom() + 1), Qt.gray)
47 painter.setPen(Qt.gray) 61 painter.setPen(Qt.gray)
48 x = self.xposAscii - (GAP / 2) 62 x = self.xposAscii - (GAP / 2)
49 painter.drawLine(x, event.rect().top(), x, self.height()) 63 painter.drawLine(x, er.top(), x, er.bottom())
50 64 x = self.xposEnd - (GAP / 2)
65 painter.drawLine(x, er.top(), x, er.bottom())
66 # first and last index
67 firstIndex = max((int(er.top() / chh) - chh) * BYTES_PER_LINE, 0)
68 lastIndex = max((int(er.bottom() / chh) + chh) * BYTES_PER_LINE, 0)
69 yposStart = int(firstIndex / BYTES_PER_LINE) * chh + chh
70 # Draw contents:
51 painter.setPen(Qt.black) 71 painter.setPen(Qt.black)
52 # first and last index
53 firstIndex = (int(event.rect().top() / self.charHeight) - self.charHeight) * BYTES_PER_LINE
54 if firstIndex < 0:
55 firstIndex = 0
56 lastIndex = (int(event.rect().bottom() / self.charHeight) + self.charHeight) * BYTES_PER_LINE
57 if lastIndex < 0:
58 lastIndex = 0
59 yposStart = int(firstIndex / BYTES_PER_LINE) * self.charHeight + self.charHeight
60
61 ypos = yposStart 72 ypos = yposStart
62 for index in range(firstIndex, lastIndex, BYTES_PER_LINE): 73 for index in range(firstIndex, lastIndex, BYTES_PER_LINE):
63 painter.drawText(self.xposAddr, ypos, '{0:08X}'.format(index)) 74 painter.drawText(self.xposAddr, ypos, '{0:08X}'.format(index + self.Offset))
64
65 xpos = self.xposHex 75 xpos = self.xposHex
66 xposA = self.xposAscii 76 xposAscii = self.xposAscii
67 for colIndex in range(BYTES_PER_LINE): 77 for colIndex in range(BYTES_PER_LINE):
68 if index + colIndex < len(self.Data): 78 if index + colIndex < len(self.Data):
69 b = self.Data[index + colIndex] 79 b = self.Data[index + colIndex]
70 bhex = '{0:02X}'.format(b) 80 painter.drawText(xpos, ypos, '{0:02X}'.format(b))
71 ba = chr(b) 81 painter.drawText(xposAscii, ypos, asciiChar(b))
72 painter.drawText(xpos, ypos, bhex) 82 xpos += 2 * chw
73 painter.drawText(xposA, ypos, ba) 83 xposAscii += chw
74 xpos += 2 * self.charWidth 84 ypos += chh
75 xposA += self.charWidth
76 ypos += self.charHeight
77
78 # cursor 85 # cursor
79 if self.blinkcursor: 86 if self.blinkcursor:
80 painter.fillRect(self.cursorX, self.cursorY + self.charHeight - 2, self.charWidth, 2, Qt.black) 87 painter.fillRect(self.cursorX, self.cursorY + chh - 2, chw, 2, Qt.black)
81 def keyPressEvent(self, event): 88 def keyPressEvent(self, event):
82 if event.matches(QKeySequence.MoveToNextChar): 89 if event.matches(QKeySequence.MoveToNextChar):
83 self.CursorPosition += 1 90 self.CursorPosition += 1
84 if event.matches(QKeySequence.MoveToPreviousChar): 91 if event.matches(QKeySequence.MoveToPreviousChar):
85 self.CursorPosition -= 1 92 self.CursorPosition -= 1
86 if event.matches(QKeySequence.MoveToNextLine): 93 if event.matches(QKeySequence.MoveToNextLine):
87 self.CursorPosition += 2 * BYTES_PER_LINE 94 self.CursorPosition += 2 * BYTES_PER_LINE
88 if event.matches(QKeySequence.MoveToPreviousLine): 95 if event.matches(QKeySequence.MoveToPreviousLine):
89 self.CursorPosition -= 2 * BYTES_PER_LINE 96 self.CursorPosition -= 2 * BYTES_PER_LINE
97 if event.matches(QKeySequence.MoveToNextPage):
98 rows = int(self.scrollArea.viewport().height() / self.charHeight)
99 self.CursorPosition += (rows - 1) * 2 * BYTES_PER_LINE
100 if event.matches(QKeySequence.MoveToPreviousPage):
101 rows = int(self.scrollArea.viewport().height() / self.charHeight)
102 self.CursorPosition -= (rows - 1) * 2 * BYTES_PER_LINE
90 char = event.text().lower() 103 char = event.text().lower()
91 if char and char in '0123456789abcdef': 104 if char and char in '0123456789abcdef':
92 i = int(self.CursorPosition / 2) 105 i = int(self.CursorPosition / 2)
93 hb = self.CursorPosition % 2 106 hb = self.CursorPosition % 2
94 v = int(char, 16) 107 v = int(char, 16)
111 cpos = self.cursorPositionAt(event.pos()) 124 cpos = self.cursorPositionAt(event.pos())
112 self.setCursorPosition(cpos) 125 self.setCursorPosition(cpos)
113 def adjust(self): 126 def adjust(self):
114 self.charHeight = self.fontMetrics().height() 127 self.charHeight = self.fontMetrics().height()
115 self.charWidth = self.fontMetrics().width('x') 128 self.charWidth = self.fontMetrics().width('x')
116 self.xposAddr = 2 129 self.xposAddr = GAP
117 self.xposHex = self.xposAddr + 8 * self.charWidth + GAP 130 self.xposHex = self.xposAddr + 8 * self.charWidth + GAP
118 self.xposAscii = self.xposHex + (BYTES_PER_LINE * 2) * self.charWidth + GAP 131 self.xposAscii = self.xposHex + BYTES_PER_LINE * 2 * self.charWidth + GAP
119 self.setMinimumWidth(self.xposAscii + self.charWidth * BYTES_PER_LINE) 132 self.xposEnd = self.xposAscii + self.charWidth * BYTES_PER_LINE + GAP
120 self.scrollArea.setMinimumWidth(self.xposAscii + self.charWidth * BYTES_PER_LINE) 133 self.setMinimumWidth(self.xposEnd)
134 sbw = self.scrollArea.verticalScrollBar().width()
135 self.scrollArea.setMinimumWidth(self.xposEnd + sbw + 5)
121 self.setMinimumHeight((int(len(self.Data) / BYTES_PER_LINE) + 1) * self.charHeight) 136 self.setMinimumHeight((int(len(self.Data) / BYTES_PER_LINE) + 1) * self.charHeight)
137 self.scrollArea.setMinimumHeight(self.charHeight * 8)
122 self.update() 138 self.update()
123 def getData(self): 139 def getData(self):
124 return self.data 140 return self.data
125 def setData(self, d): 141 def setData(self, d):
126 self.data = d 142 self.data = d
132 def __init__(self): 148 def __init__(self):
133 super().__init__() 149 super().__init__()
134 self.bv = BinViewer(self) 150 self.bv = BinViewer(self)
135 self.setWidget(self.bv) 151 self.setWidget(self.bv)
136 self.setWidgetResizable(True) 152 self.setWidgetResizable(True)
153 self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
137 self.setFocusPolicy(Qt.NoFocus) 154 self.setFocusPolicy(Qt.NoFocus)
138 155
139 if __name__ == '__main__': 156 if __name__ == '__main__':
140 app = QApplication(sys.argv) 157 app = QApplication(sys.argv)
141 he = HexEdit() 158 he = HexEdit()