Mercurial > lcfOS
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() |