10 import math |
10 import math |
11 |
11 |
12 from PyQt6.QtCore import ( |
12 from PyQt6.QtCore import ( |
13 pyqtSignal, pyqtSlot, Qt, QByteArray, QTimer, QRect, QBuffer, QIODevice |
13 pyqtSignal, pyqtSlot, Qt, QByteArray, QTimer, QRect, QBuffer, QIODevice |
14 ) |
14 ) |
15 from PyQt6.QtGui import ( |
15 from PyQt6.QtGui import QFont, QPalette, QKeySequence, QPainter |
16 QBrush, QPen, QColor, QFont, QPalette, QKeySequence, QPainter |
|
17 ) |
|
18 from PyQt6.QtWidgets import QAbstractScrollArea, QApplication |
16 from PyQt6.QtWidgets import QAbstractScrollArea, QApplication |
|
17 |
|
18 from EricWidgets.EricApplication import ericApp |
19 |
19 |
20 from .HexEditChunks import HexEditChunks |
20 from .HexEditChunks import HexEditChunks |
21 from .HexEditUndoStack import HexEditUndoStack |
21 from .HexEditUndoStack import HexEditUndoStack |
22 |
22 |
23 import Globals |
23 import Globals |
63 super().__init__(parent) |
63 super().__init__(parent) |
64 |
64 |
65 # Properties |
65 # Properties |
66 self.__addressArea = True |
66 self.__addressArea = True |
67 # switch the address area on/off |
67 # switch the address area on/off |
68 self.__addressAreaBrush = QBrush() |
|
69 self.__addressAreaPen = QPen() |
|
70 # background and pen of the address area |
|
71 self.__addressOffset = 0 |
68 self.__addressOffset = 0 |
72 # offset into the shown address range |
69 # offset into the shown address range |
73 self.__addressWidth = 4 |
70 self.__addressWidth = 4 |
74 # address area width in characters |
71 # address area width in characters |
75 self.__asciiArea = True |
72 self.__asciiArea = True |
76 # switch the ASCII area on/off |
73 # switch the ASCII area on/off |
77 self.__data = bytearray() |
74 self.__data = bytearray() |
78 # contents of the hex editor |
75 # contents of the hex editor |
79 self.__highlighting = True |
76 self.__highlighting = True |
80 # switch the highlighting feature on/off |
77 # switch the highlighting feature on/off |
81 self.__highlightingBrush = QBrush() |
|
82 self.__highlightingPen = QPen() |
|
83 # background and pen of highlighted text |
|
84 self.__overwriteMode = True |
78 self.__overwriteMode = True |
85 # set overwrite mode on/off |
79 # set overwrite mode on/off |
86 self.__selectionBrush = QBrush() |
|
87 self.__selectionPen = QPen() |
|
88 # background and pen of selected text |
|
89 self.__readOnly = False |
80 self.__readOnly = False |
90 # set read only mode on/off |
81 # set read only mode on/off |
91 self.__cursorPosition = 0 |
82 self.__cursorPosition = 0 |
92 # absolute position of cursor, 1 Byte == 2 tics |
83 # absolute position of cursor, 1 Byte == 2 tics |
93 |
84 |
131 if Globals.isWindowsPlatform(): |
122 if Globals.isWindowsPlatform(): |
132 self.setFont(QFont(["Courier"], 10)) |
123 self.setFont(QFont(["Courier"], 10)) |
133 else: |
124 else: |
134 self.setFont(QFont(["Monospace"], 10)) |
125 self.setFont(QFont(["Monospace"], 10)) |
135 |
126 |
136 # TODO: make some colors custimizable |
|
137 self.setAddressAreaColors( |
|
138 self.palette().color(QPalette.ColorRole.WindowText), |
|
139 self.palette().alternateBase().color()) |
|
140 self.setHighlightColors( |
|
141 self.palette().color(QPalette.ColorRole.WindowText), |
|
142 QColor(0xff, 0xff, 0x99, 0xff)) |
|
143 self.setSelectionColors( |
|
144 self.palette().highlightedText().color(), |
|
145 self.palette().highlight().color()) |
|
146 |
|
147 self.__cursorTimer = QTimer() |
127 self.__cursorTimer = QTimer() |
148 self.__cursorTimer.timeout.connect(self.__updateCursor) |
128 self.__cursorTimer.timeout.connect(self.__updateCursor) |
149 |
129 |
150 self.verticalScrollBar().valueChanged.connect(self.__adjust) |
130 self.verticalScrollBar().valueChanged.connect(self.__adjust) |
151 |
131 |
210 @type bool |
190 @type bool |
211 """ |
191 """ |
212 self.__addressArea = on |
192 self.__addressArea = on |
213 self.__adjust() |
193 self.__adjust() |
214 self.setCursorPosition(self.__cursorPosition) |
194 self.setCursorPosition(self.__cursorPosition) |
215 self.viewport().update() |
|
216 |
|
217 def addressAreaColors(self): |
|
218 """ |
|
219 Public method to get the address area colors. |
|
220 |
|
221 @return address area foreground and background colors |
|
222 @rtype tuple of 2 QColor |
|
223 """ |
|
224 return self.__addressAreaPen.color(), self.__addressAreaBrush.color() |
|
225 |
|
226 def setAddressAreaColors(self, foreground, background): |
|
227 """ |
|
228 Public method to set the address area colors. |
|
229 |
|
230 @param foreground address area foreground color |
|
231 @type QColor |
|
232 @param background address area background color |
|
233 @type QColor |
|
234 """ |
|
235 self.__addressAreaPen = QPen(foreground) |
|
236 self.__addressAreaBrush = QBrush(background) |
|
237 self.viewport().update() |
195 self.viewport().update() |
238 |
196 |
239 def addressOffset(self): |
197 def addressOffset(self): |
240 """ |
198 """ |
241 Public method to get the address offset. |
199 Public method to get the address offset. |
504 @type bool |
462 @type bool |
505 """ |
463 """ |
506 self.__highlighting = on |
464 self.__highlighting = on |
507 self.viewport().update() |
465 self.viewport().update() |
508 |
466 |
509 def highlightColors(self): |
|
510 """ |
|
511 Public method to get the highlight colors. |
|
512 |
|
513 @return highlight foreground and background colors |
|
514 @rtype tuple of 2 QColor |
|
515 """ |
|
516 return self.__highlightingPen.color(), self.__highlightingBrush.color() |
|
517 |
|
518 def setHighlightColors(self, foreground, background): |
|
519 """ |
|
520 Public method to set the highlight colors. |
|
521 |
|
522 @param foreground highlight foreground color |
|
523 @type QColor |
|
524 @param background highlight background color |
|
525 @type QColor |
|
526 """ |
|
527 self.__highlightingPen = QPen(foreground) |
|
528 self.__highlightingBrush = QBrush(background) |
|
529 self.viewport().update() |
|
530 |
|
531 def overwriteMode(self): |
467 def overwriteMode(self): |
532 """ |
468 """ |
533 Public method to get the overwrite mode. |
469 Public method to get the overwrite mode. |
534 |
470 |
535 @return overwrite mode |
471 @return overwrite mode |
553 # step 2: change the cursor rectangle |
489 # step 2: change the cursor rectangle |
554 self.__setHexCursorRect() |
490 self.__setHexCursorRect() |
555 # step 3: draw new cursors |
491 # step 3: draw new cursors |
556 self.__blink = True |
492 self.__blink = True |
557 self.viewport().update(self.__cursorRect) |
493 self.viewport().update(self.__cursorRect) |
558 |
|
559 def selectionColors(self): |
|
560 """ |
|
561 Public method to get the selection colors. |
|
562 |
|
563 @return selection foreground and background colors |
|
564 @rtype tuple of 2 QColor |
|
565 """ |
|
566 return self.__selectionPen.color(), self.__selectionBrush.color() |
|
567 |
|
568 def setSelectionColors(self, foreground, background): |
|
569 """ |
|
570 Public method to set the selection colors. |
|
571 |
|
572 @param foreground selection foreground color |
|
573 @type QColor |
|
574 @param background selection background color |
|
575 @type QColor |
|
576 """ |
|
577 self.__selectionPen = QPen(foreground) |
|
578 self.__selectionBrush = QBrush(background) |
|
579 self.viewport().update() |
|
580 |
494 |
581 def isReadOnly(self): |
495 def isReadOnly(self): |
582 """ |
496 """ |
583 Public method to test the read only state. |
497 Public method to test the read only state. |
584 |
498 |
1356 @param evt reference to the paint event |
1270 @param evt reference to the paint event |
1357 @type QPaintEvent |
1271 @type QPaintEvent |
1358 """ |
1272 """ |
1359 painter = QPainter(self.viewport()) |
1273 painter = QPainter(self.viewport()) |
1360 |
1274 |
|
1275 # initialize colors |
|
1276 if ericApp().usesDarkPalette(): |
|
1277 addressAreaForeground = self.palette().color( |
|
1278 QPalette.ColorRole.Text) |
|
1279 addressAreaBackground = self.palette().color( |
|
1280 QPalette.ColorRole.Base).lighter(200) |
|
1281 highlightingForeground = self.palette().color( |
|
1282 QPalette.ColorRole.HighlightedText).darker(200) |
|
1283 highlightingBackground = self.palette().color( |
|
1284 QPalette.ColorRole.Highlight).lighter() |
|
1285 else: |
|
1286 addressAreaForeground = self.palette().color( |
|
1287 QPalette.ColorRole.Text) |
|
1288 addressAreaBackground = self.palette().color( |
|
1289 QPalette.ColorRole.Base).darker() |
|
1290 highlightingForeground = self.palette().color( |
|
1291 QPalette.ColorRole.HighlightedText).lighter() |
|
1292 highlightingBackground = self.palette().color( |
|
1293 QPalette.ColorRole.Highlight).darker() |
|
1294 selectionForeground = self.palette().color( |
|
1295 QPalette.ColorRole.HighlightedText) |
|
1296 selectionBackground = self.palette().color( |
|
1297 QPalette.ColorRole.Highlight) |
|
1298 standardBackground = self.viewport().palette().color( |
|
1299 QPalette.ColorRole.Base) |
|
1300 standardForeground = self.viewport().palette().color( |
|
1301 QPalette.ColorRole.Text) |
|
1302 |
1361 if ( |
1303 if ( |
1362 evt.rect() != self.__cursorRect and |
1304 evt.rect() != self.__cursorRect and |
1363 evt.rect() != self.__cursorRectAscii |
1305 evt.rect() != self.__cursorRectAscii |
1364 ): |
1306 ): |
1365 pxOfsX = self.horizontalScrollBar().value() |
1307 pxOfsX = self.horizontalScrollBar().value() |
1366 pxPosStartY = self.__pxCharHeight |
1308 pxPosStartY = self.__pxCharHeight |
1367 |
1309 |
1368 # draw some patterns if needed |
1310 # draw some patterns if needed |
1369 painter.fillRect( |
1311 painter.fillRect(evt.rect(), standardBackground) |
1370 evt.rect(), |
|
1371 self.viewport().palette().color(QPalette.ColorRole.Base)) |
|
1372 if self.__addressArea: |
1312 if self.__addressArea: |
1373 painter.fillRect( |
1313 painter.fillRect( |
1374 QRect(-pxOfsX, evt.rect().top(), |
1314 QRect(-pxOfsX, evt.rect().top(), |
1375 self.__pxPosHexX - self.__pxGapAdrHex // 2 - pxOfsX, |
1315 self.__pxPosHexX - self.__pxGapAdrHex // 2 - pxOfsX, |
1376 self.height()), |
1316 self.height()), |
1377 self.__addressAreaBrush) |
1317 addressAreaBackground) |
1378 if self.__asciiArea: |
1318 if self.__asciiArea: |
1379 linePos = self.__pxPosAsciiX - (self.__pxGapHexAscii // 2) |
1319 linePos = self.__pxPosAsciiX - (self.__pxGapHexAscii // 2) |
1380 painter.setPen(Qt.GlobalColor.gray) |
1320 painter.setPen(Qt.GlobalColor.gray) |
1381 painter.drawLine(linePos - pxOfsX, evt.rect().top(), |
1321 painter.drawLine(linePos - pxOfsX, evt.rect().top(), |
1382 linePos - pxOfsX, self.height()) |
1322 linePos - pxOfsX, self.height()) |
1383 |
1323 |
1384 painter.setPen( |
|
1385 self.viewport().palette().color(QPalette.ColorRole.WindowText)) |
|
1386 |
|
1387 # paint the address area |
1324 # paint the address area |
1388 if self.__addressArea: |
1325 if self.__addressArea: |
1389 painter.setPen(self.__addressAreaPen) |
1326 painter.setPen(addressAreaForeground) |
1390 address = "" |
1327 address = "" |
1391 row = 0 |
1328 row = 0 |
1392 pxPosY = self.__pxCharHeight |
1329 pxPosY = self.__pxCharHeight |
1393 while row <= len(self.__dataShown) // self.BYTES_PER_LINE: |
1330 while row <= len(self.__dataShown) // self.BYTES_PER_LINE: |
1394 address = "{0:0{1}x}".format( |
1331 address = "{0:0{1}x}".format( |
1417 colIdx = 0 |
1351 colIdx = 0 |
1418 while ( |
1352 while ( |
1419 bPosLine + colIdx < len(self.__dataShown) and |
1353 bPosLine + colIdx < len(self.__dataShown) and |
1420 colIdx < self.BYTES_PER_LINE |
1354 colIdx < self.BYTES_PER_LINE |
1421 ): |
1355 ): |
1422 c = self.viewport().palette().color( |
1356 background = standardBackground |
1423 QPalette.ColorRole.Base) |
1357 painter.setPen(standardForeground) |
1424 painter.setPen(colStandard) |
|
1425 |
1358 |
1426 posBa = self.__bPosFirst + bPosLine + colIdx |
1359 posBa = self.__bPosFirst + bPosLine + colIdx |
1427 if ( |
1360 if ( |
1428 self.getSelectionBegin() <= posBa and |
1361 self.getSelectionBegin() <= posBa and |
1429 self.getSelectionEnd() > posBa |
1362 self.getSelectionEnd() > posBa |
1430 ): |
1363 ): |
1431 c = self.__selectionBrush.color() |
1364 background = selectionBackground |
1432 painter.setPen(self.__selectionPen) |
1365 painter.setPen(selectionForeground) |
1433 elif ( |
1366 elif ( |
1434 self.__highlighting and |
1367 self.__highlighting and |
1435 self.__markedShown and |
1368 self.__markedShown and |
1436 self.__markedShown[posBa - self.__bPosFirst] |
1369 self.__markedShown[posBa - self.__bPosFirst] |
1437 ): |
1370 ): |
1438 c = self.__highlightingBrush.color() |
1371 background = highlightingBackground |
1439 painter.setPen(self.__highlightingPen) |
1372 painter.setPen(highlightingForeground) |
1440 |
1373 |
1441 # render hex value |
1374 # render hex value |
1442 r = QRect() |
1375 rect = QRect() |
1443 if colIdx == 0: |
1376 if colIdx == 0: |
1444 r.setRect( |
1377 rect.setRect( |
1445 pxPosX, |
1378 pxPosX, |
1446 pxPosY - self.__pxCharHeight + |
1379 pxPosY - self.__pxCharHeight + |
1447 self.__pxSelectionSub, |
1380 self.__pxSelectionSub, |
1448 2 * self.__pxCharWidth, |
1381 2 * self.__pxCharWidth, |
1449 self.__pxCharHeight) |
1382 self.__pxCharHeight) |
1450 else: |
1383 else: |
1451 r.setRect( |
1384 rect.setRect( |
1452 pxPosX - self.__pxCharWidth, |
1385 pxPosX - self.__pxCharWidth, |
1453 pxPosY - self.__pxCharHeight + |
1386 pxPosY - self.__pxCharHeight + |
1454 self.__pxSelectionSub, |
1387 self.__pxSelectionSub, |
1455 3 * self.__pxCharWidth, |
1388 3 * self.__pxCharWidth, |
1456 self.__pxCharHeight) |
1389 self.__pxCharHeight) |
1457 painter.fillRect(r, c) |
1390 painter.fillRect(rect, background) |
1458 hexStr = ( |
1391 hexStr = ( |
1459 chr(self.__hexDataShown[(bPosLine + colIdx) * 2]) + |
1392 chr(self.__hexDataShown[(bPosLine + colIdx) * 2]) + |
1460 chr(self.__hexDataShown[(bPosLine + colIdx) * 2 + 1]) |
1393 chr(self.__hexDataShown[(bPosLine + colIdx) * 2 + 1]) |
1461 ) |
1394 ) |
1462 painter.drawText(pxPosX, pxPosY, hexStr) |
1395 painter.drawText(pxPosX, pxPosY, hexStr) |
1467 by = self.__dataShown[bPosLine + colIdx] |
1400 by = self.__dataShown[bPosLine + colIdx] |
1468 if by < 0x20 or (by > 0x7e and by < 0xa0): |
1401 if by < 0x20 or (by > 0x7e and by < 0xa0): |
1469 ch = "." |
1402 ch = "." |
1470 else: |
1403 else: |
1471 ch = chr(by) |
1404 ch = chr(by) |
1472 r.setRect( |
1405 rect.setRect( |
1473 pxPosAsciiX2, |
1406 pxPosAsciiX2, |
1474 pxPosY - self.__pxCharHeight + |
1407 pxPosY - self.__pxCharHeight + |
1475 self.__pxSelectionSub, |
1408 self.__pxSelectionSub, |
1476 self.__pxCharWidth, |
1409 self.__pxCharWidth, |
1477 self.__pxCharHeight) |
1410 self.__pxCharHeight) |
1478 painter.fillRect(r, c) |
1411 painter.fillRect(rect, background) |
1479 painter.drawText(pxPosAsciiX2, pxPosY, ch) |
1412 painter.drawText(pxPosAsciiX2, pxPosY, ch) |
1480 pxPosAsciiX2 += self.__pxCharWidth |
1413 pxPosAsciiX2 += self.__pxCharWidth |
1481 |
1414 |
1482 # increment loop variable |
1415 # increment loop variable |
1483 colIdx += 1 |
1416 colIdx += 1 |
1485 # increment loop variables |
1418 # increment loop variables |
1486 row += 1 |
1419 row += 1 |
1487 pxPosY += self.__pxCharHeight |
1420 pxPosY += self.__pxCharHeight |
1488 |
1421 |
1489 painter.setBackgroundMode(Qt.BGMode.TransparentMode) |
1422 painter.setBackgroundMode(Qt.BGMode.TransparentMode) |
1490 painter.setPen( |
1423 painter.setPen(standardForeground) |
1491 self.viewport().palette().color(QPalette.ColorRole.WindowText)) |
1424 |
1492 |
|
1493 # paint cursor |
1425 # paint cursor |
1494 if self.__blink and not self.__readOnly and self.isActiveWindow(): |
1426 if self.__blink and not self.__readOnly and self.isActiveWindow(): |
1495 painter.fillRect( |
1427 painter.fillRect(self.__cursorRect, standardForeground) |
1496 self.__cursorRect, |
|
1497 self.palette().color(QPalette.ColorRole.WindowText)) |
|
1498 else: |
1428 else: |
1499 if self.__hexDataShown: |
1429 if self.__hexDataShown: |
1500 try: |
1430 try: |
1501 c = chr(self.__hexDataShown[ |
1431 c = chr(self.__hexDataShown[ |
1502 self.__cursorPosition - self.__bPosFirst * 2]) |
1432 self.__cursorPosition - self.__bPosFirst * 2]) |