frappy/frappy/gui/modulewidget.py
Alexander Zaft b0b85a2711 Make input field more distinct
* different color for value fields
* placeholder text in input fields

Change-Id: Ibb94eb09ab7bfd7c2807f27226b7e2825ac3ea5d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30579
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-21 16:15:20 +02:00

271 lines
9.0 KiB
Python

from frappy.gui.qt import QDialog, QIcon, QLabel, QLineEdit, QMessageBox, \
QPushButton, QToolButton, QWidget, pyqtSignal
import frappy.gui.resources # pylint: disable=unused-import
from frappy.gui.util import Colors, loadUi
from frappy.gui.valuewidgets import get_widget
class CommandDialog(QDialog):
def __init__(self, cmdname, argument, parent=None):
super().__init__(parent)
loadUi(self, 'cmddialog.ui')
self.setWindowTitle('Arguments for %s' % cmdname)
# row = 0
self._labels = []
self.widgets = []
# improve! recursive?
dtype = argument
label = QLabel(repr(dtype))
label.setWordWrap(True)
widget = get_widget(dtype, readonly=False)
self.gridLayout.addWidget(label, 0, 0)
self.gridLayout.addWidget(widget, 0, 1)
self._labels.append(label)
self.widgets.append(widget)
self.gridLayout.setRowStretch(1, 1)
self.setModal(True)
self.resize(self.sizeHint())
def get_value(self):
return True, self.widgets[0].get_value()
def exec_(self):
if super().exec_():
return self.get_value()
return None
def showCommandResultDialog(command, args, result, extras=''):
m = QMessageBox()
args = '' if args is None else repr(args)
m.setText('calling: %s(%s)\nyielded: %r\nqualifiers: %s' %
(command, args, result, extras))
m.exec_()
def showErrorDialog(command, args, error):
m = QMessageBox()
args = '' if args is None else repr(args)
m.setText('calling: %s(%s)\nraised %r' % (command, args, error))
m.exec_()
class CommandButton(QPushButton):
def __init__(self, cmdname, cmdinfo, cb, parent=None):
super().__init__(parent)
self._cmdname = cmdname
self._argintype = cmdinfo['datatype'].argument # single datatype
self.result = cmdinfo['datatype'].result
self._cb = cb # callback function for exection
self.setText(cmdname)
if cmdinfo['description']:
self.setToolTip(cmdinfo['description'])
self.pressed.connect(self.on_pushButton_pressed)
def on_pushButton_pressed(self):
#self.setEnabled(False)
if self._argintype:
dlg = CommandDialog(self._cmdname, self._argintype)
args = dlg.exec_()
if args: # not 'Cancel' clicked
self._cb(self._cmdname, args[1])
else:
# no need for arguments
self._cb(self._cmdname, None)
#self.setEnabled(True)
class ModuleWidget(QWidget):
plot = pyqtSignal(str)
plotAdd = pyqtSignal(str)
def __init__(self, node, name, parent=None):
super().__init__()
loadUi(self, 'modulewidget.ui')
self._node = node
self._name = name
self._paramDisplays = {}
self._paramInputs = {}
self._addbtns = []
self._paramWidgets = {}
self.moduleName.setText(name)
props = self._node.getModuleProperties(self._name)
description = props.get('description', '')
self.moduleDescription.setText(description)
row = 0
params = dict(self._node.getParameters(self._name))
if 'status' in params:
params.pop('status')
self._addRParam('status', row)
row += 1
if 'value' in params:
params.pop('value')
self._addRParam('value', row)
row += 1
if 'target' in params:
params.pop('target')
self._addRWParam('target', row)
row += 1
for param in params:
paramProps = self._node.getProperties(self._name, param)
if paramProps['readonly']:
self._addRParam(param, row)
else:
self._addRWParam(param, row)
row += 1
self._setParamHidden(param, True)
self._addCommands(row)
cache = self._node.queryCache(self._name)
for param, val in cache.items():
self._updateValue(self._name, param, val)
node.newData.connect(self._updateValue)
def _updateValue(self, mod, param, val):
if mod != self._name:
return
if param in self._paramDisplays:
# TODO: stopgap
if val.readerror:
strvalue = str(val)
else:
strvalue = ('%g' if isinstance(val.value, float)
else '%s') % (val.value,)
self._paramDisplays[param].setText(strvalue)
def _addRParam(self, param, row):
props = self._node.getProperties(self._name, param)
nameLabel = QLabel(param)
unitLabel = QLabel(props.get('unit', ''))
display = QLineEdit()
p = display.palette()
p.setColor(display.backgroundRole(), Colors.palette.window().color())
display.setPalette(p)
self._paramDisplays[param] = display
self._paramWidgets[param] = [nameLabel, unitLabel, display]
l = self.moduleDisplay.layout()
l.addWidget(nameLabel, row,0,1,1)
l.addWidget(display, row,1,1,5)
l.addWidget(unitLabel, row,6)
self._addPlotButtons(param, row)
def _addRWParam(self, param, row):
props = self._node.getProperties(self._name, param)
nameLabel = QLabel(param)
unitLabel = QLabel(props.get('unit', ''))
unitLabel2 = QLabel(props.get('unit', ''))
display = QLineEdit()
inputEdit = QLineEdit()
submitButton = QPushButton('Go')
submitButton.setIcon(QIcon(':/icons/submit'))
inputEdit.setPlaceholderText('new value')
p = display.palette()
p.setColor(display.backgroundRole(), Colors.palette.window().color())
display.setPalette(p)
submitButton.pressed.connect(lambda: self._button_pressed(param))
inputEdit.returnPressed.connect(lambda: self._button_pressed(param))
self._paramDisplays[param] = display
self._paramInputs[param] = inputEdit
self._paramWidgets[param] = [nameLabel, unitLabel, unitLabel2,
display, inputEdit, submitButton]
l = self.moduleDisplay.layout()
l.addWidget(nameLabel, row,0,1,1)
l.addWidget(display, row,1,1,2)
l.addWidget(unitLabel, row,3,1,1)
l.addWidget(inputEdit, row,4,1,2)
l.addWidget(unitLabel2, row,6,1,1)
l.addWidget(submitButton, row, 7)
self._addPlotButtons(param, row)
def _addPlotButtons(self, param, row):
if param == 'status':
return
plotButton = QToolButton()
plotButton.setIcon(QIcon(':/icons/plot'))
plotButton.setToolTip('Plot %s' % param)
plotAddButton = QToolButton()
plotAddButton.setIcon(QIcon(':/icons/plot-add'))
plotAddButton.setToolTip('Plot With...')
plotButton.clicked.connect(lambda: self.plot.emit(param))
plotAddButton.clicked.connect(lambda: self.plotAdd.emit(param))
self._addbtns.append(plotAddButton)
plotAddButton.setDisabled(True)
self._paramWidgets[param].append(plotButton)
self._paramWidgets[param].append(plotAddButton)
l = self.moduleDisplay.layout()
l.addWidget(plotButton, row, 8)
l.addWidget(plotAddButton, row, 9)
def _addCommands(self, startrow):
cmdicons = {
'stop': QIcon(':/icons/stop'),
}
cmds = self._node.getCommands(self._name)
if not cmds:
return
l = self.moduleDisplay.layout()
# max cols in GridLayout, find out programmatically?
maxcols = 7
l.addWidget(QLabel('Commands:'))
for (i, cmd) in enumerate(cmds):
cmdb = CommandButton(cmd, cmds[cmd], self._execCommand)
if cmd in cmdicons:
cmdb.setIcon(cmdicons[cmd])
row = startrow + i // maxcols
col = (i % maxcols) + 1
l.addWidget(cmdb, row, col)
def _execCommand(self, command, args=None):
try:
result, qualifiers = self._node.execCommand(
self._name, command, args)
except Exception as e:
showErrorDialog(command, args, e)
return
if result is not None:
showCommandResultDialog(command, args, result, qualifiers)
def _setParamHidden(self, param, hidden):
for w in self._paramWidgets[param]:
w.setHidden(hidden)
def _setGroupHidden(self, group):
pass
def rebuildAdvanced(self, advanced):
for param in self._paramWidgets:
if param in ['value', 'status', 'target']:
continue
self._setParamHidden(param, not advanced)
def _button_pressed(self, param):
target = self._paramInputs[param].text()
try:
self._node.setParameter(self._name, param, target)
except Exception as e:
QMessageBox.warning(self.parent(), 'Operation failed', str(e))
def plotsPresent(self, present):
for btn in self._addbtns:
btn.setDisabled(present)