eric7/HexEdit/HexEditWidget.py

branch
eric7
changeset 8875
67c3ea933787
parent 8857
8191d15b8974
child 8881
54e42bc2437a
equal deleted inserted replaced
8874:ccd99849803e 8875:67c3ea933787
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(
1400 # increment loop variables 1337 # increment loop variables
1401 row += 1 1338 row += 1
1402 pxPosY += self.__pxCharHeight 1339 pxPosY += self.__pxCharHeight
1403 1340
1404 # paint hex and ascii area 1341 # paint hex and ascii area
1405 colStandard = QPen(
1406 self.viewport().palette().color(QPalette.ColorRole.WindowText))
1407
1408 painter.setBackgroundMode(Qt.BGMode.TransparentMode) 1342 painter.setBackgroundMode(Qt.BGMode.TransparentMode)
1409 1343
1410 row = 0 1344 row = 0
1411 pxPosY = pxPosStartY 1345 pxPosY = pxPosStartY
1412 while row <= self.__rowsShown: 1346 while row <= self.__rowsShown:
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])

eric ide

mercurial