summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Buesch <m@bues.ch>2020-07-09 21:43:38 +0200
committerMichael Buesch <m@bues.ch>2020-07-11 15:13:54 +0200
commitd5ccb02c25dd1bd98342d789564a84c34c0f4dd3 (patch)
tree2ccb8db8475e35da9e8b3a101100d21e07d9effb
parent3e47dbffa1a76a51c9649e586f40a916f197079c (diff)
downloadtoprammer-py3.tar.xz
toprammer-py3.zip
gui: Switch to PyQt5 and Python3py3
Signed-off-by: Michael Buesch <m@bues.ch>
-rw-r--r--libtoprammer/util.py42
-rwxr-xr-xtoprammer-gui78
2 files changed, 66 insertions, 54 deletions
diff --git a/libtoprammer/util.py b/libtoprammer/util.py
index 5156077..2bd6bd5 100644
--- a/libtoprammer/util.py
+++ b/libtoprammer/util.py
@@ -105,7 +105,9 @@ hexdump_re = re.compile(r"0x[0-9a-fA-F]+:\s+([0-9a-fA-F\s]+)\s*.*")
def parseHexdump(dump):
try:
- bin = []
+ if isinstance(dump, (bytes, bytearray)):
+ dump = dump.decode("ASCII")
+ binData = []
for line in dump.splitlines():
line = line.strip()
if not line:
@@ -113,14 +115,18 @@ def parseHexdump(dump):
m = hexdump_re.match(line)
if not m:
raise TOPException("Invalid hexdump format (regex failure)")
- bytes = m.group(1).replace(" ", "")
- if len(bytes) % 2 != 0:
+ data = m.group(1)
+ idx = data.find(" ")
+ if idx >= 0:
+ data = data[:idx] # Strip ascii section
+ data = data.replace(" ", "")
+ if len(data) % 2 != 0:
raise TOPException("Invalid hexdump format (odd bytestring len)")
- for i in range(0, len(bytes), 2):
- byte = int(bytes[i:i+2], 16)
- bin.append(int2byte(byte))
- return b"".join(bin)
- except (ValueError) as e:
+ for i in range(0, len(data), 2):
+ byte = int(data[i:i+2], 16)
+ binData.append(int2byte(byte))
+ return b"".join(binData)
+ except (ValueError, UnicodeError) as e:
raise TOPException("Invalid hexdump format (Integer error)")
def generateHexdump(mem):
@@ -159,11 +165,13 @@ class IO_ihex(object):
return True
def toBinary(self, ihexData, addressRange=None, defaultBytes=b"\xFF"):
- bin = []
+ binData = []
checksumWarned = False
doublewriteWarned = False
addrBias = addressRange.startAddress if addressRange else 0
try:
+ if isinstance(ihexData, (bytes, bytearray)):
+ ihexData = ihexData.decode("ASCII")
lines = ihexData.splitlines()
hiAddr = 0
segment = 0
@@ -210,24 +218,24 @@ class IO_ihex(object):
if addressRange and addr > addressRange.endAddress:
continue
if type == self.TYPE_DATA:
- if len(bin) < addr - addrBias + count: # Reallocate
- bytesToAdd = addr - addrBias + count - len(bin)
+ if len(binData) < addr - addrBias + count: # Reallocate
+ bytesToAdd = addr - addrBias + count - len(binData)
for i in range(bytesToAdd):
- defOffs = len(bin) % len(defaultBytes)
- bin += [ defaultBytes[defOffs], ]
+ defOffs = len(binData) % len(defaultBytes)
+ binData += [ defaultBytes[defOffs], ]
for i in range(9, 9 + count * 2, 2):
byte = int2byte(int(line[i:i+2], 16))
offset = (i - 9) // 2 + addr - addrBias
- if bin[offset] != defaultBytes[offset % len(defaultBytes)] and \
+ if binData[offset] != defaultBytes[offset % len(defaultBytes)] and \
not doublewriteWarned:
doublewriteWarned = True
print("Invalid IHEX format (Wrote twice to same location)")
- bin[offset] = byte
+ binData[offset] = byte
continue
raise TOPException("Invalid IHEX format (unsup type %d)" % type)
- except ValueError:
+ except (ValueError, UnicodeError) as e:
raise TOPException("Invalid IHEX format (digit format)")
- return b"".join(bin)
+ return b"".join(binData)
def fromBinary(self, binData):
ihex = []
diff --git a/toprammer-gui b/toprammer-gui
index bfe70dc..bca3a4e 100755
--- a/toprammer-gui
+++ b/toprammer-gui
@@ -25,14 +25,16 @@ from libtoprammer.main import *
from libtoprammer.util import *
import sys
import time
-import cgi
+import html
import configparser
try:
- from PySide.QtCore import *
- from PySide.QtGui import *
+ from PyQt5.QtCore import *
+ from PyQt5.QtGui import *
+ from PyQt5.QtWidgets import *
+ Signal = pyqtSignal
except (ImportError) as e:
- print("Failed to import PySide modules: %s" % str(e))
- print("Please install PySide. On Debian Linux run: aptitude install python-pyside")
+ print("Failed to import PyQt5 modules: %s" % str(e))
+ print("Please install PyQt5. On Debian Linux run: apt install python3-pyqt5")
sys.exit(1)
@@ -47,7 +49,7 @@ def stringRemoveChars(string, chars):
return "".join(ret)
def htmlEscape(plaintext):
- return cgi.escape(plaintext)
+ return html.escape(plaintext, True)
def getIconPath(name):
return pkg_resources.resource_filename("libtoprammer",
@@ -582,7 +584,7 @@ class UnitestDialog(QDialog):
def __saveFile(self, filename):
try:
- fd = open(filename, "w+b")
+ fd = open(filename, "w", encoding="UTF-8")
fd.write("[TOPRAMMER-UNITEST-SETTINGS]\r\n")
fd.write("fileVersion=%d\r\n" % 1)
@@ -616,7 +618,7 @@ class UnitestDialog(QDialog):
fd.write("oscillatorDiv=%d\r\n" % self.oscDiv.value())
fd.write("zifOutEnMask=%X\r\n" % self.zifWidget.getOutEnMask())
fd.write("zifOutMask=%X\r\n" % self.zifWidget.getOutMask())
- except (IOError) as e:
+ except (IOError, UnicodeError) as e:
QMessageBox.critical(self, "Failed to save settings",
"Failed to write settings to file: %s" % str(e))
@@ -1223,11 +1225,14 @@ class HexEditWidget(QWidget):
self.cursor1Color = QColor("#D0D0AF")
font = self.font()
- font.setFamily("monospace")
- font.setFixedPitch(True)
+ font.setFamily("Courier")
+ font.setStyleHint(QFont.Courier)
+ font.setWeight(QFont.Normal)
font.setPointSize(10)
+ font.setBold(False)
+ font.setFixedPitch(True)
self.setFont(font)
- self.charWidth = self.fontMetrics().width("x")
+ self.charWidth = self.fontMetrics().width("X" * 100) / 100
self.charHeight = self.fontMetrics().height()
self.bytesPerLine = 16
@@ -1259,15 +1264,14 @@ class HexEditWidget(QWidget):
nrLeft = self.bytesPerLine - (len(data) % self.bytesPerLine)
text.append(" " * nrLeft)
text.append(" |")
- for byte in data:
- text.append(bytes2ascii(byte))
+ text.append(bytes2ascii(data))
text.append("|")
lines.append("".join(text))
else:
lines = [ "<The buffer is empty>", ]
self.textLines = lines
self.nrLines = len(lines)
- self.previousData = self.data
+ self.previousData = self.getData()
width = self.fontMetrics().width(self.textLines[0])
height = self.nrLines * self.charHeight
@@ -1275,25 +1279,25 @@ class HexEditWidget(QWidget):
self.repaint()
def getData(self):
- return self.data
+ return bytes(self.data)
def setData(self, data):
if not data:
- data = ""
- self.data = data
+ data = b""
+ assert isinstance(data, (bytes, bytearray))
+ self.data = bytearray(data)
self.updateText()
self.__setCursor(0, False)
def charInput(self, char):
if not self.data:
return
- data = list(self.data)
- assert(self.cursorByte < len(data))
+ assert(self.cursorByte < len(self.data))
if self.cursorOnAscii:
- data[self.cursorByte] = char
+ self.data[self.cursorByte] = ord(char)
self.__setCursor(self.cursorByte + 1, True)
else:
- dataByte = byte2int(data[self.cursorByte])
+ dataByte = self.data[self.cursorByte]
char = ord(char.upper())
if char >= ord("0") and char <= ord("9"):
nibble = char - ord("0")
@@ -1305,12 +1309,11 @@ class HexEditWidget(QWidget):
dataByte = (dataByte & 0xF0) | nibble
else:
dataByte = (dataByte & 0x0F) | (nibble << 4)
- data[self.cursorByte] = chr(dataByte)
+ self.data[self.cursorByte] = dataByte
if self.cursorNibble == 1:
self.cursorNibble = 0
else:
self.__setCursor(self.cursorByte + 1, False)
- self.data = "".join(data)
self.updateText()
def keyPressEvent(self, e):
@@ -1381,31 +1384,31 @@ class HexEditWidget(QWidget):
def mousePressEvent(self, e):
x = e.pos().x()
y = e.pos().y()
- byteAreaX = self.charWidth * 13
+ byteAreaX = round(self.charWidth * 13)
byteAreaY = 3
- asciiAreaX = self.charWidth * (13 + 3 * self.bytesPerLine + 3 - 1)
+ asciiAreaX = round(self.charWidth * (13 + 3 * self.bytesPerLine + 3 - 1))
asciiAreaY = 3
if x >= byteAreaX and\
y >= byteAreaY and\
- x <= byteAreaX + self.charWidth * 3 * self.bytesPerLine and\
+ x <= round(byteAreaX + self.charWidth * 3 * self.bytesPerLine) and\
y <= byteAreaY + self.charHeight * self.nrLines:
# Click in byte area.
x -= byteAreaX
y -= byteAreaY
line = y // self.charHeight
- column = x // (self.charWidth * 3)
+ column = round(x // (self.charWidth * 3))
self.__setCursor(line * self.bytesPerLine + column,
False)
return
if x >= asciiAreaX and\
y >= asciiAreaY and\
- x <= asciiAreaX + self.charWidth * self.bytesPerLine and\
+ x <= round(asciiAreaX + self.charWidth * self.bytesPerLine) and\
y <= asciiAreaY + self.charHeight * self.nrLines:
# Click on ascii area.
x -= asciiAreaX
y -= asciiAreaY
line = y // self.charHeight
- column = x // self.charWidth
+ column = round(x // self.charWidth)
self.__setCursor(line * self.bytesPerLine + column,
True)
return
@@ -1417,11 +1420,10 @@ class HexEditWidget(QWidget):
y = self.charHeight * (self.cursorByte // self.bytesPerLine)
y += 3
else:
- x = self.charWidth * 13
- x += self.charWidth * 3 * (self.cursorByte % self.bytesPerLine)
+ x = self.charWidth * (13 + 3 * (self.cursorByte % self.bytesPerLine))
y = self.charHeight * (self.cursorByte // self.bytesPerLine)
y += 3
- return (x, y)
+ return (round(x), round(y))
def paintEvent(self, e):
p = QPainter(self)
@@ -1433,14 +1435,14 @@ class HexEditWidget(QWidget):
if self.data and self.hasFocus():
(x, y) = self.__cursorUpperLeftEdge()
if self.cursorOnAscii:
- p.fillRect(x, y, self.charWidth, self.charHeight,
+ p.fillRect(x, y, round(self.charWidth), self.charHeight,
self.cursor0Color)
else:
- p.fillRect(x, y, self.charWidth * 2, self.charHeight,
+ p.fillRect(x, y, round(self.charWidth * 2), self.charHeight,
self.cursor1Color)
if self.cursorNibble == 0:
- x += self.charWidth
- p.fillRect(x, y, self.charWidth, self.charHeight,
+ x = round(x + self.charWidth)
+ p.fillRect(x, y, round(self.charWidth), self.charHeight,
self.cursor0Color)
# Text
@@ -2601,8 +2603,10 @@ class MainWindow(QMainWindow):
else:
assert(0)
try:
+ if isinstance(data, str):
+ data = data.encode("UTF-8")
open(fn, "wb").write(data)
- except (IOError) as e:
+ except (IOError, UnicodeError) as e:
QMessageBox.critical(self, "Failed to write file",
"Failed to write %s:\n%s" %\
(str(fn), str(e.strerror)))
bues.ch cgit interface