code import
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
#!/bin/env python3
|
||||
|
||||
import gex
|
||||
|
||||
import sys
|
||||
from PyQt4 import QtGui, QtCore
|
||||
import ini_syntax
|
||||
|
||||
class GexIniEditor(QtGui.QMainWindow):
|
||||
"""
|
||||
Gexync is a GEX ini file editor.
|
||||
The editor loads the INI file through the communication interface
|
||||
without having to mount the virtual filesystem, which is unreliable
|
||||
on some systems.
|
||||
|
||||
This utility allows live editing of the UNITS.INI file.
|
||||
|
||||
On save, a new version is loaded with formatting and error messages
|
||||
generated by GEX, as if the virtual config filesystem was re-mounted.
|
||||
|
||||
The editor does not keep GEX claimed, instead does so only when needed.
|
||||
This allows testing of the current configuration without having to close
|
||||
and reopen the editor.
|
||||
"""
|
||||
|
||||
def __init__(self, xferLambda):
|
||||
self.xferLambda = xferLambda
|
||||
|
||||
self.filenum = int(sys.argv[1]) if len(sys.argv)>1 else 0
|
||||
|
||||
super().__init__()
|
||||
self.initUI()
|
||||
# TODO let user pick GEX device if multiple
|
||||
|
||||
def initToolbar(self):
|
||||
icon = self.style().standardIcon(QtGui.QStyle.SP_BrowserReload)
|
||||
loadAction = QtGui.QAction(icon, 'Reload', self)
|
||||
loadAction.setShortcut('Ctrl+O')
|
||||
loadAction.triggered.connect(self.gexLoad)
|
||||
|
||||
icon = self.style().standardIcon(QtGui.QStyle.SP_DialogSaveButton)
|
||||
syncAction = QtGui.QAction(icon, 'Write Changes', self)
|
||||
syncAction.setShortcut('Ctrl+S')
|
||||
syncAction.triggered.connect(self.gexSync)
|
||||
|
||||
icon = self.style().standardIcon(QtGui.QStyle.SP_DialogOkButton)
|
||||
persAction = QtGui.QAction(icon, 'Persist', self)
|
||||
persAction.setShortcut('Ctrl+P')
|
||||
persAction.triggered.connect(self.gexPersist)
|
||||
|
||||
self.toolbar = self.addToolBar('Toolbar')
|
||||
self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
|
||||
self.toolbar.addAction(loadAction)
|
||||
self.toolbar.addAction(syncAction)
|
||||
self.toolbar.addSeparator()
|
||||
self.toolbar.addAction(persAction)
|
||||
|
||||
def initEditor(self):
|
||||
self.editor = QtGui.QPlainTextEdit()
|
||||
|
||||
# Editor background and text color
|
||||
pal = QtGui.QPalette()
|
||||
bgc = QtGui.QColor(0xFFFFF6)
|
||||
pal.setColor(QtGui.QPalette.Base, bgc)
|
||||
textc = QtGui.QColor(0x000000)
|
||||
pal.setColor(QtGui.QPalette.Text, textc)
|
||||
self.editor.setPalette(pal)
|
||||
# Font
|
||||
font = QtGui.QFont('Liberation Mono', 12)
|
||||
font.setStyleHint(QtGui.QFont.TypeWriter)
|
||||
self.editor.setFont(font)
|
||||
# Initial size
|
||||
self.highlight = ini_syntax.IniHighlighter(self.editor.document())
|
||||
|
||||
def initUI(self):
|
||||
self.setWindowTitle('GEX config file editor')
|
||||
self.initToolbar()
|
||||
self.initEditor()
|
||||
self.setCentralWidget(self.editor)
|
||||
self.show()
|
||||
|
||||
self.gexLoad()
|
||||
|
||||
def gexLoad(self):
|
||||
self.editor.setPlainText("")
|
||||
self.editor.repaint()
|
||||
|
||||
client = gex.Client(self.xferLambda(), load_units=False)
|
||||
read_ini = client.ini_read(self.filenum)
|
||||
client.close()
|
||||
|
||||
self.editor.setPlainText(read_ini)
|
||||
self.highlight.rehighlight()
|
||||
self.setWindowTitle('GEX config file editor')
|
||||
|
||||
def gexSync(self):
|
||||
new_txt = self.editor.toPlainText()
|
||||
self.editor.setPlainText("")
|
||||
self.editor.repaint()
|
||||
|
||||
client = gex.Client(self.xferLambda(), load_units=False)
|
||||
client.ini_write(new_txt)
|
||||
read_ini = client.ini_read(self.filenum)
|
||||
client.close()
|
||||
|
||||
self.editor.setPlainText(read_ini)
|
||||
self.highlight.rehighlight()
|
||||
self.setWindowTitle('*GEX config file editor')
|
||||
|
||||
def gexPersist(self):
|
||||
client = gex.Client(self.xferLambda(), load_units=False)
|
||||
client.ini_persist()
|
||||
client.close()
|
||||
self.setWindowTitle('GEX config file editor')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
editor = GexIniEditor(lambda: gex.TrxRawUSB())
|
||||
# editor = GexIniEditor(lambda: gex.TrxSerialThread(port='/dev/ttyUSB1',
|
||||
# baud=57600))
|
||||
|
||||
# centered resize
|
||||
w = 800
|
||||
h = 900
|
||||
ss = app.desktop().availableGeometry().size()
|
||||
editor.setGeometry(int(ss.width() / 2 - w / 2), int(ss.height() / 2 - h / 2), w, h)
|
||||
|
||||
sys.exit(app.exec_())
|
||||
@@ -0,0 +1,81 @@
|
||||
# syntax.py
|
||||
|
||||
# This is a companion file to gexync.py
|
||||
|
||||
# based on https://wiki.python.org/moin/PyQt/Python%20syntax%20highlighting
|
||||
|
||||
from PyQt4.QtCore import QRegExp
|
||||
from PyQt4.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter
|
||||
|
||||
def format(color, style=''):
|
||||
"""Return a QTextCharFormat with the given attributes.
|
||||
"""
|
||||
_color = QColor()
|
||||
_color.setNamedColor(color)
|
||||
|
||||
_format = QTextCharFormat()
|
||||
_format.setForeground(_color)
|
||||
if 'bold' in style:
|
||||
_format.setFontWeight(QFont.Bold)
|
||||
if 'italic' in style:
|
||||
_format.setFontItalic(True)
|
||||
|
||||
return _format
|
||||
|
||||
|
||||
# Syntax styles that can be shared by all languages
|
||||
STYLES = {
|
||||
'operator': format('red'),
|
||||
'string': format('magenta'),
|
||||
'comment': format('#6C8A70', 'italic'),
|
||||
'key': format('#008AFF'),
|
||||
'numbers': format('brown'),
|
||||
'section': format('black', 'bold'),
|
||||
}
|
||||
|
||||
class IniHighlighter (QSyntaxHighlighter):
|
||||
# Python braces
|
||||
def __init__(self, document):
|
||||
QSyntaxHighlighter.__init__(self, document)
|
||||
|
||||
rules = [
|
||||
(r'=', 0, STYLES['operator']),
|
||||
(r'\b[YN]\b', 0, STYLES['numbers']),
|
||||
|
||||
# Double-quoted string, possibly containing escape sequences
|
||||
(r'"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),
|
||||
# Single-quoted string, possibly containing escape sequences
|
||||
(r"'[^'\\]*(\\.[^'\\]*)*'", 0, STYLES['string']),
|
||||
|
||||
# Numeric literals
|
||||
(r'\b[+-]?[0-9]+\b', 0, STYLES['numbers']),
|
||||
(r'\b[+-]?0[xX][0-9A-Fa-f]+\b', 0, STYLES['numbers']),
|
||||
(r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b', 0, STYLES['numbers']),
|
||||
|
||||
# From '#' until a newline
|
||||
(r'#[^\n]*', 0, STYLES['comment']),
|
||||
|
||||
(r'^\[.+\]', 0, STYLES['section']),
|
||||
|
||||
(r'^[a-zA-Z0-9_-]+\s?=', 0, STYLES['key']),
|
||||
]
|
||||
|
||||
# Build a QRegExp for each pattern
|
||||
self.rules = [(QRegExp(pat), index, fmt)
|
||||
for (pat, index, fmt) in rules]
|
||||
|
||||
def highlightBlock(self, text):
|
||||
"""Apply syntax highlighting to the given block of text.
|
||||
"""
|
||||
# Do other syntax formatting
|
||||
for expression, nth, format in self.rules:
|
||||
index = expression.indexIn(text, 0)
|
||||
|
||||
while index >= 0:
|
||||
# We actually want the index of the nth match
|
||||
index = expression.pos(nth)
|
||||
length = len(expression.cap(nth))
|
||||
self.setFormat(index, length, format)
|
||||
index = expression.indexIn(text, index + length)
|
||||
|
||||
self.setCurrentBlockState(0)
|
||||
Reference in New Issue
Block a user