7 Module implementing an editor for binary data. |
7 Module implementing an editor for binary data. |
8 """ |
8 """ |
9 |
9 |
10 import math |
10 import math |
11 |
11 |
12 from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QByteArray, QTimer, QRect, \ |
12 from PyQt5.QtCore import ( |
13 QBuffer, QIODevice |
13 pyqtSignal, pyqtSlot, Qt, QByteArray, QTimer, QRect, QBuffer, QIODevice |
14 from PyQt5.QtGui import QBrush, QPen, QColor, QFont, QPalette, QKeySequence, \ |
14 ) |
15 QPainter |
15 from PyQt5.QtGui import ( |
|
16 QBrush, QPen, QColor, QFont, QPalette, QKeySequence, QPainter |
|
17 ) |
16 from PyQt5.QtWidgets import QAbstractScrollArea, QApplication |
18 from PyQt5.QtWidgets import QAbstractScrollArea, QApplication |
17 |
19 |
18 from .HexEditChunks import HexEditChunks |
20 from .HexEditChunks import HexEditChunks |
19 from .HexEditUndoStack import HexEditUndoStack |
21 from .HexEditUndoStack import HexEditUndoStack |
20 |
22 |
725 """ |
727 """ |
726 result = -1 |
728 result = -1 |
727 if (point.x() >= self.__pxPosHexX) and ( |
729 if (point.x() >= self.__pxPosHexX) and ( |
728 point.x() < (self.__pxPosHexX + (1 + self.HEXCHARS_PER_LINE) * |
730 point.x() < (self.__pxPosHexX + (1 + self.HEXCHARS_PER_LINE) * |
729 self.__pxCharWidth)): |
731 self.__pxCharWidth)): |
730 x = (point.x() - self.__pxPosHexX - self.__pxCharWidth // 2) // \ |
732 x = ( |
|
733 (point.x() - self.__pxPosHexX - self.__pxCharWidth // 2) // |
731 self.__pxCharWidth |
734 self.__pxCharWidth |
|
735 ) |
732 x = (x // 3) * 2 + x % 3 |
736 x = (x // 3) * 2 + x % 3 |
733 y = ((point.y() - 3) // self.__pxCharHeight) * 2 * \ |
737 y = ( |
|
738 ((point.y() - 3) // self.__pxCharHeight) * 2 * |
734 self.BYTES_PER_LINE |
739 self.BYTES_PER_LINE |
|
740 ) |
735 result = self.__bPosFirst * 2 + x + y |
741 result = self.__bPosFirst * 2 + x + y |
736 return result |
742 return result |
737 |
743 |
738 def ensureVisible(self): |
744 def ensureVisible(self): |
739 """ |
745 """ |
995 |
1001 |
996 def selectToEndOfLine(self): |
1002 def selectToEndOfLine(self): |
997 """ |
1003 """ |
998 Public method to extend the selection to the end of line. |
1004 Public method to extend the selection to the end of line. |
999 """ |
1005 """ |
1000 pos = self.__cursorPosition - \ |
1006 pos = ( |
1001 (self.__cursorPosition % (2 * self.BYTES_PER_LINE)) + \ |
1007 self.__cursorPosition - |
|
1008 (self.__cursorPosition % (2 * self.BYTES_PER_LINE)) + |
1002 2 * self.BYTES_PER_LINE |
1009 2 * self.BYTES_PER_LINE |
|
1010 ) |
1003 self.setCursorPosition(pos) |
1011 self.setCursorPosition(pos) |
1004 self.__setSelection(pos) |
1012 self.__setSelection(pos) |
1005 |
1013 |
1006 def selectToStartOfLine(self): |
1014 def selectToStartOfLine(self): |
1007 """ |
1015 """ |
1008 Public method to extend the selection to the start of line. |
1016 Public method to extend the selection to the start of line. |
1009 """ |
1017 """ |
1010 pos = self.__cursorPosition - \ |
1018 pos = ( |
|
1019 self.__cursorPosition - |
1011 (self.__cursorPosition % (2 * self.BYTES_PER_LINE)) |
1020 (self.__cursorPosition % (2 * self.BYTES_PER_LINE)) |
|
1021 ) |
1012 self.setCursorPosition(pos) |
1022 self.setCursorPosition(pos) |
1013 self.__setSelection(pos) |
1023 self.__setSelection(pos) |
1014 |
1024 |
1015 def selectPreviousLine(self): |
1025 def selectPreviousLine(self): |
1016 """ |
1026 """ |
1030 |
1040 |
1031 def selectNextPage(self): |
1041 def selectNextPage(self): |
1032 """ |
1042 """ |
1033 Public method to extend the selection one page down. |
1043 Public method to extend the selection one page down. |
1034 """ |
1044 """ |
1035 pos = self.__cursorPosition + \ |
1045 pos = ( |
1036 ((self.viewport().height() // self.__pxCharHeight) - 1) * \ |
1046 self.__cursorPosition + |
|
1047 ((self.viewport().height() // self.__pxCharHeight) - 1) * |
1037 2 * self.BYTES_PER_LINE |
1048 2 * self.BYTES_PER_LINE |
|
1049 ) |
1038 self.setCursorPosition(pos) |
1050 self.setCursorPosition(pos) |
1039 self.__setSelection(pos) |
1051 self.__setSelection(pos) |
1040 |
1052 |
1041 def selectPreviousPage(self): |
1053 def selectPreviousPage(self): |
1042 """ |
1054 """ |
1043 Public method to extend the selection one page up. |
1055 Public method to extend the selection one page up. |
1044 """ |
1056 """ |
1045 pos = self.__cursorPosition - \ |
1057 pos = ( |
1046 ((self.viewport().height() // self.__pxCharHeight) - 1) * \ |
1058 self.__cursorPosition - |
|
1059 ((self.viewport().height() // self.__pxCharHeight) - 1) * |
1047 2 * self.BYTES_PER_LINE |
1060 2 * self.BYTES_PER_LINE |
|
1061 ) |
1048 self.setCursorPosition(pos) |
1062 self.setCursorPosition(pos) |
1049 self.__setSelection(pos) |
1063 self.__setSelection(pos) |
1050 |
1064 |
1051 def selectEndOfDocument(self): |
1065 def selectEndOfDocument(self): |
1052 """ |
1066 """ |
1224 self.selectStartOfDocument() |
1238 self.selectStartOfDocument() |
1225 |
1239 |
1226 # Edit commands |
1240 # Edit commands |
1227 elif evt.matches(QKeySequence.Copy): |
1241 elif evt.matches(QKeySequence.Copy): |
1228 self.copy() |
1242 self.copy() |
1229 elif evt.key() == Qt.Key_Insert and \ |
1243 elif ( |
1230 evt.modifiers() == Qt.NoModifier: |
1244 evt.key() == Qt.Key_Insert and |
|
1245 evt.modifiers() == Qt.NoModifier |
|
1246 ): |
1231 self.setOverwriteMode(not self.overwriteMode()) |
1247 self.setOverwriteMode(not self.overwriteMode()) |
1232 self.setCursorPosition(self.__cursorPosition) |
1248 self.setCursorPosition(self.__cursorPosition) |
1233 |
1249 |
1234 elif not self.__readOnly: |
1250 elif not self.__readOnly: |
1235 if evt.matches(QKeySequence.Cut): |
1251 if evt.matches(QKeySequence.Cut): |
1236 self.cut() |
1252 self.cut() |
1237 elif evt.matches(QKeySequence.Paste): |
1253 elif evt.matches(QKeySequence.Paste): |
1238 self.paste() |
1254 self.paste() |
1239 elif evt.matches(QKeySequence.Delete): |
1255 elif evt.matches(QKeySequence.Delete): |
1240 self.deleteByte() |
1256 self.deleteByte() |
1241 elif evt.key() == Qt.Key_Backspace and \ |
1257 elif ( |
1242 evt.modifiers() == Qt.NoModifier: |
1258 evt.key() == Qt.Key_Backspace and |
|
1259 evt.modifiers() == Qt.NoModifier |
|
1260 ): |
1243 self.deleteByteBack() |
1261 self.deleteByteBack() |
1244 elif evt.matches(QKeySequence.Undo): |
1262 elif evt.matches(QKeySequence.Undo): |
1245 self.undo() |
1263 self.undo() |
1246 elif evt.matches(QKeySequence.Redo): |
1264 elif evt.matches(QKeySequence.Redo): |
1247 self.redo() |
1265 self.redo() |
1331 @param evt reference to the paint event |
1349 @param evt reference to the paint event |
1332 @type QPaintEvent |
1350 @type QPaintEvent |
1333 """ |
1351 """ |
1334 painter = QPainter(self.viewport()) |
1352 painter = QPainter(self.viewport()) |
1335 |
1353 |
1336 if evt.rect() != self.__cursorRect and \ |
1354 if ( |
1337 evt.rect() != self.__cursorRectAscii: |
1355 evt.rect() != self.__cursorRect and |
|
1356 evt.rect() != self.__cursorRectAscii |
|
1357 ): |
1338 pxOfsX = self.horizontalScrollBar().value() |
1358 pxOfsX = self.horizontalScrollBar().value() |
1339 pxPosStartY = self.__pxCharHeight |
1359 pxPosStartY = self.__pxCharHeight |
1340 |
1360 |
1341 # draw some patterns if needed |
1361 # draw some patterns if needed |
1342 painter.fillRect( |
1362 painter.fillRect( |
1385 pxPosX = self.__pxPosHexX - pxOfsX |
1405 pxPosX = self.__pxPosHexX - pxOfsX |
1386 pxPosAsciiX2 = self.__pxPosAsciiX - pxOfsX |
1406 pxPosAsciiX2 = self.__pxPosAsciiX - pxOfsX |
1387 bPosLine = row * self.BYTES_PER_LINE |
1407 bPosLine = row * self.BYTES_PER_LINE |
1388 |
1408 |
1389 colIdx = 0 |
1409 colIdx = 0 |
1390 while bPosLine + colIdx < len(self.__dataShown) and \ |
1410 while ( |
1391 colIdx < self.BYTES_PER_LINE: |
1411 bPosLine + colIdx < len(self.__dataShown) and |
|
1412 colIdx < self.BYTES_PER_LINE |
|
1413 ): |
1392 c = self.viewport().palette().color(QPalette.Base) |
1414 c = self.viewport().palette().color(QPalette.Base) |
1393 painter.setPen(colStandard) |
1415 painter.setPen(colStandard) |
1394 |
1416 |
1395 posBa = self.__bPosFirst + bPosLine + colIdx |
1417 posBa = self.__bPosFirst + bPosLine + colIdx |
1396 if self.getSelectionBegin() <= posBa and \ |
1418 if ( |
1397 self.getSelectionEnd() > posBa: |
1419 self.getSelectionBegin() <= posBa and |
|
1420 self.getSelectionEnd() > posBa |
|
1421 ): |
1398 c = self.__selectionBrush.color() |
1422 c = self.__selectionBrush.color() |
1399 painter.setPen(self.__selectionPen) |
1423 painter.setPen(self.__selectionPen) |
1400 elif self.__highlighting: |
1424 elif self.__highlighting: |
1401 if self.__markedShown and self.__markedShown[ |
1425 if self.__markedShown and self.__markedShown[ |
1402 posBa - self.__bPosFirst]: |
1426 posBa - self.__bPosFirst]: |
1418 pxPosY - self.__pxCharHeight + |
1442 pxPosY - self.__pxCharHeight + |
1419 self.__pxSelectionSub, |
1443 self.__pxSelectionSub, |
1420 3 * self.__pxCharWidth, |
1444 3 * self.__pxCharWidth, |
1421 self.__pxCharHeight) |
1445 self.__pxCharHeight) |
1422 painter.fillRect(r, c) |
1446 painter.fillRect(r, c) |
1423 hexStr = \ |
1447 hexStr = ( |
1424 chr(self.__hexDataShown[(bPosLine + colIdx) * 2]) + \ |
1448 chr(self.__hexDataShown[(bPosLine + colIdx) * 2]) + |
1425 chr(self.__hexDataShown[(bPosLine + colIdx) * 2 + 1]) |
1449 chr(self.__hexDataShown[(bPosLine + colIdx) * 2 + 1]) |
|
1450 ) |
1426 painter.drawText(pxPosX, pxPosY, hexStr) |
1451 painter.drawText(pxPosX, pxPosY, hexStr) |
1427 pxPosX += 3 * self.__pxCharWidth |
1452 pxPosX += 3 * self.__pxCharWidth |
1428 |
1453 |
1429 # render ascii value |
1454 # render ascii value |
1430 if self.__asciiArea: |
1455 if self.__asciiArea: |
1648 (self.__addrDigits + self.__addrSeparators) * |
1673 (self.__addrDigits + self.__addrSeparators) * |
1649 self.__pxCharWidth + self.__pxGapAdrHex) |
1674 self.__pxCharWidth + self.__pxGapAdrHex) |
1650 else: |
1675 else: |
1651 self.__pxPosHexX = self.__pxGapAdrHex |
1676 self.__pxPosHexX = self.__pxGapAdrHex |
1652 self.__pxPosAdrX = self.__pxGapAdr |
1677 self.__pxPosAdrX = self.__pxGapAdr |
1653 self.__pxPosAsciiX = self.__pxPosHexX + \ |
1678 self.__pxPosAsciiX = ( |
1654 self.HEXCHARS_PER_LINE * self.__pxCharWidth + self.__pxGapHexAscii |
1679 self.__pxPosHexX + |
|
1680 self.HEXCHARS_PER_LINE * self.__pxCharWidth + |
|
1681 self.__pxGapHexAscii |
|
1682 ) |
1655 |
1683 |
1656 # set horizontal scrollbar |
1684 # set horizontal scrollbar |
1657 pxWidth = self.__pxPosAsciiX |
1685 pxWidth = self.__pxPosAsciiX |
1658 if self.__asciiArea: |
1686 if self.__asciiArea: |
1659 pxWidth += self.BYTES_PER_LINE * self.__pxCharWidth |
1687 pxWidth += self.BYTES_PER_LINE * self.__pxCharWidth |
1660 self.horizontalScrollBar().setRange( |
1688 self.horizontalScrollBar().setRange( |
1661 0, pxWidth - self.viewport().width()) |
1689 0, pxWidth - self.viewport().width()) |
1662 self.horizontalScrollBar().setPageStep(self.viewport().width()) |
1690 self.horizontalScrollBar().setPageStep(self.viewport().width()) |
1663 |
1691 |
1664 # set vertical scrollbar |
1692 # set vertical scrollbar |
1665 self.__rowsShown = \ |
1693 self.__rowsShown = ( |
1666 (self.viewport().height() - 4) // self.__pxCharHeight |
1694 (self.viewport().height() - 4) // self.__pxCharHeight |
|
1695 ) |
1667 lineCount = (self.__chunks.size() // self.BYTES_PER_LINE) + 1 |
1696 lineCount = (self.__chunks.size() // self.BYTES_PER_LINE) + 1 |
1668 self.verticalScrollBar().setRange(0, lineCount - self.__rowsShown) |
1697 self.verticalScrollBar().setRange(0, lineCount - self.__rowsShown) |
1669 self.verticalScrollBar().setPageStep(self.__rowsShown) |
1698 self.verticalScrollBar().setPageStep(self.__rowsShown) |
1670 |
1699 |
1671 # do the rest |
1700 # do the rest |
1672 value = self.verticalScrollBar().value() |
1701 value = self.verticalScrollBar().value() |
1673 self.__bPosFirst = value * self.BYTES_PER_LINE |
1702 self.__bPosFirst = value * self.BYTES_PER_LINE |
1674 self.__bPosLast = \ |
1703 self.__bPosLast = ( |
1675 self.__bPosFirst + self.__rowsShown * self.BYTES_PER_LINE - 1 |
1704 self.__bPosFirst + self.__rowsShown * self.BYTES_PER_LINE - 1 |
|
1705 ) |
1676 if self.__bPosLast >= self.__chunks.size(): |
1706 if self.__bPosLast >= self.__chunks.size(): |
1677 self.__bPosLast = self.__chunks.size() - 1 |
1707 self.__bPosLast = self.__chunks.size() - 1 |
1678 self.__readBuffers() |
1708 self.__readBuffers() |
1679 self.setCursorPosition(self.__cursorPosition) |
1709 self.setCursorPosition(self.__cursorPosition) |
1680 |
1710 |