big rework to comply to current spec
- adapt to release(v2018-11-07) - remove duplicate errors.py - adapt tests Change-Id: I383bb571f9808c72b37c12fbe55042011c4c0084 Reviewed-on: https://forge.frm2.tum.de/review/19397 Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
This commit is contained in:
430
secop/gui/miniplot.py
Normal file
430
secop/gui/miniplot.py
Normal file
@ -0,0 +1,430 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# *****************************************************************************
|
||||
# Copyright (c) 2015-2016 by the authors, see LICENSE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
|
||||
from os import path
|
||||
|
||||
from secop.gui.qt import Qt, QColor, QWidget, QSize, \
|
||||
QBrush, QPainter, QPolygonF, QPointF, QPen, QRectF
|
||||
|
||||
|
||||
|
||||
_magenta = QBrush(QColor('#A12F86'))
|
||||
_yellow = QBrush(QColor('yellow'))
|
||||
_white = QBrush(QColor('white'))
|
||||
_lightgrey = QBrush(QColor('lightgrey'))
|
||||
_grey = QBrush(QColor('grey'))
|
||||
_darkgrey = QBrush(QColor('#404040'))
|
||||
_black = QBrush(QColor('black'))
|
||||
_blue = QBrush(QColor('blue'))
|
||||
_green = QBrush(QColor('green'))
|
||||
_red = QBrush(QColor('red'))
|
||||
_olive = QBrush(QColor('olive'))
|
||||
_orange = QBrush(QColor('#ffa500'))
|
||||
|
||||
|
||||
my_uipath = path.dirname(__file__)
|
||||
|
||||
class MiniPlotCurve(object):
|
||||
# placeholder for data
|
||||
linecolor = _black
|
||||
linewidth = 0 # set to 0 to disable lines
|
||||
symbolcolors = (_black, _white) # line, fill
|
||||
symbolsize = 3 # both symbol linewidth and symbolsize, set to 0 to disable
|
||||
errorbarcolor = _darkgrey
|
||||
errorbarwidth = 3 # set to 0 to disable errorbar
|
||||
|
||||
def __init__(self):
|
||||
self.data = [] # tripels of x, y, err (err may be None)
|
||||
|
||||
@property
|
||||
def xvalues(self):
|
||||
return [p[0] for p in self.data] if self.data else [0]
|
||||
|
||||
@property
|
||||
def yvalues(self):
|
||||
return [p[1] for p in self.data] if self.data else [0]
|
||||
|
||||
@property
|
||||
def errvalues(self):
|
||||
return [p[2] or 0.0 for p in self.data] if self.data else [0]
|
||||
|
||||
@property
|
||||
def xmin(self):
|
||||
return min(self.xvalues)
|
||||
|
||||
@property
|
||||
def xmax(self):
|
||||
return max(self.xvalues)
|
||||
|
||||
@property
|
||||
def ymin(self):
|
||||
return min(self.yvalues)
|
||||
|
||||
@property
|
||||
def ymax(self):
|
||||
return max(self.yvalues)
|
||||
|
||||
@property
|
||||
def yemin(self):
|
||||
return min(y-(e or 0) for _, y, e in self.data) if self.data else 0
|
||||
|
||||
@property
|
||||
def yemax(self):
|
||||
return max(y+(e or 0) for _, y, e in self.data) if self.data else 0
|
||||
|
||||
|
||||
def paint(self, scale, painter):
|
||||
# note: scale returns a screen-XY tuple for data XY
|
||||
# draw errorbars, lines and symbols in that order
|
||||
if self.errorbarwidth > 0:
|
||||
pen = QPen()
|
||||
pen.setBrush(self.errorbarcolor)
|
||||
pen.setWidth(self.errorbarwidth)
|
||||
painter.setPen(pen)
|
||||
for _x,_y,_e in self.data:
|
||||
if _e is None:
|
||||
continue
|
||||
x, y = scale(_x,_y)
|
||||
e = scale(_x,_y + _e)[1] - y
|
||||
painter.drawLine(x, y-e, x, y+e)
|
||||
painter.fillRect(x - self.errorbarwidth / 2., y - e,
|
||||
self.errorbarwidth, 2 * e, self.errorbarcolor)
|
||||
|
||||
points = [QPointF(*scale(p[0], p[1])) for p in self.data]
|
||||
if self.linewidth > 0:
|
||||
pen = QPen()
|
||||
pen.setBrush(self.linecolor)
|
||||
pen.setWidth(self.linewidth)
|
||||
painter.setPen(pen)
|
||||
painter.drawPolyline(QPolygonF(points))
|
||||
|
||||
if self.symbolsize > 0:
|
||||
pen = QPen()
|
||||
pen.setBrush(self.symbolcolors[0]) # linecolor
|
||||
pen.setWidth(self.symbolsize) # linewidth
|
||||
painter.setPen(pen)
|
||||
painter.setBrush(self.symbolcolors[1]) # fill color
|
||||
if self.symbolsize > 0:
|
||||
for p in points:
|
||||
painter.drawEllipse(p, 2*self.symbolsize, 2*self.symbolsize)
|
||||
|
||||
def preparepainting(self, scale, xmin, xmax):
|
||||
pass # nothing to do
|
||||
|
||||
|
||||
class MiniPlotFitCurve(MiniPlotCurve):
|
||||
|
||||
# do not influence scaling of plotting window
|
||||
@property
|
||||
def xmin(self):
|
||||
return float('inf')
|
||||
|
||||
@property
|
||||
def xmax(self):
|
||||
return float('-inf')
|
||||
|
||||
@property
|
||||
def ymin(self):
|
||||
return float('inf')
|
||||
|
||||
@property
|
||||
def ymax(self):
|
||||
return float('-inf')
|
||||
|
||||
@property
|
||||
def yemin(self):
|
||||
return float('inf')
|
||||
|
||||
@property
|
||||
def yemax(self):
|
||||
return float('-inf')
|
||||
|
||||
def __init__(self, formula, params):
|
||||
super(MiniPlotFitCurve, self).__init__()
|
||||
self.formula = formula
|
||||
self.params = params
|
||||
|
||||
linecolor = _blue
|
||||
linewidth = 5 # set to 0 to disable lines
|
||||
symbolsize = 0 # both symbol linewidth and symbolsize, set to 0 to disable
|
||||
errorbarwidth = 0 # set to 0 to disable errorbar
|
||||
|
||||
def preparepainting(self, scale, xmin, xmax):
|
||||
# recalculate data
|
||||
points = int(scale(xmax) - scale(xmin))
|
||||
self.data = []
|
||||
for idx in range(points+1):
|
||||
x = xmin + idx * (xmax-xmin) / points
|
||||
y = self.formula(x, *self.params)
|
||||
self.data.append((x,y,None))
|
||||
|
||||
|
||||
class MiniPlot(QWidget):
|
||||
ticklinecolors = (_grey, _lightgrey) # ticks, subticks
|
||||
ticklinewidth = 1
|
||||
bordercolor = _black
|
||||
borderwidth = 1
|
||||
labelcolor = _black
|
||||
xlabel = 'x'
|
||||
ylabel = 'y'
|
||||
xfmt = '%.1f'
|
||||
yfmt = '%g'
|
||||
autotickx = True
|
||||
autoticky = True
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.xmin = self.xmax = None
|
||||
self.ymin = self.ymax = None
|
||||
self.curves = []
|
||||
self.plotx = 0 # left of this are labels
|
||||
self.ploty = self.height() # below this are labels
|
||||
|
||||
def scaleX(self, x):
|
||||
if not self.curves:
|
||||
return x # XXX: !!!!
|
||||
x = self.plotx + (self.width() - self.plotx) * (x - self.xmin) / (self.xmax - self.xmin)
|
||||
# x = max(min(x, self.width()), self.plotx)
|
||||
return x
|
||||
|
||||
def scaleY(self, y):
|
||||
if not self.curves:
|
||||
return y # XXX: !!!!
|
||||
y = self.ploty * (self.ymax - y) / (self.ymax - self.ymin)
|
||||
# y = max(min(y, self.ploty), 0)
|
||||
return y
|
||||
|
||||
def scale(self, x, y):
|
||||
# scales a plotting xx/y to a screen x/y to be used for painting...
|
||||
return self.scaleX(x), self.scaleY(y)
|
||||
|
||||
def removeCurve(self, curve):
|
||||
if curve in self.curves:
|
||||
self.curves.remove(curve)
|
||||
self.updatePlot()
|
||||
|
||||
def addCurve(self, curve):
|
||||
if curve is not None and curve not in self.curves:
|
||||
# new curve, recalculate all
|
||||
self.curves.append(curve)
|
||||
self.updatePlot()
|
||||
|
||||
def updatePlot(self):
|
||||
xmin,xmax = -1,1
|
||||
ymin,ymax = -1,1
|
||||
# find limits of known curves
|
||||
if self.curves:
|
||||
xmin = min(c.xmin for c in self.curves)
|
||||
xmax = max(c.xmax for c in self.curves)
|
||||
ymin = min(c.yemin for c in self.curves)
|
||||
ymax = max(c.yemax for c in self.curves)
|
||||
# fallback values for no curve
|
||||
while xmin >= xmax:
|
||||
xmin, xmax = xmin - 1, xmax + 1
|
||||
while ymin >= ymax:
|
||||
ymin, ymax = ymin - 1, ymax + 1
|
||||
# adjust limits a little
|
||||
self.xmin = xmin - 0.05 * (xmax - xmin)
|
||||
self.xmax = xmax + 0.05 * (xmax - xmin)
|
||||
self.ymin = ymin - 0.05 * (ymax - ymin)
|
||||
self.ymax = ymax + 0.05 * (ymax - ymin)
|
||||
|
||||
# (re-)generate x/yticks
|
||||
if self.autotickx:
|
||||
self.calc_xticks(xmin, xmax)
|
||||
if self. autoticky:
|
||||
self.calc_yticks(ymin, ymax)
|
||||
# redraw
|
||||
self.update()
|
||||
|
||||
def calc_xticks(self, xmin, xmax):
|
||||
self.xticks = self.calc_ticks(xmin, xmax, self.xfmt)
|
||||
|
||||
def calc_yticks(self, ymin, ymax):
|
||||
self.yticks = self.calc_ticks(ymin, ymax, self.yfmt)
|
||||
|
||||
def calc_ticks(self, _min, _max, fmt):
|
||||
min_intervals = 2
|
||||
diff = _max - _min
|
||||
if diff <= 0:
|
||||
return [0]
|
||||
# find a 'good' step size
|
||||
step = abs(diff / min_intervals)
|
||||
# split into mantissa and exp.
|
||||
expo = 0
|
||||
while step >= 10:
|
||||
step /= 10.
|
||||
expo += 1
|
||||
while step < 1:
|
||||
step *= 10.
|
||||
expo -= 1
|
||||
# make step 'latch' into smalle bigger magic number
|
||||
subs = 1
|
||||
for n, subs in reversed([(1,5.), (1.5,3.), (2,4.), (3,3.), (5,5.), (10,2.)]):
|
||||
if step >= n:
|
||||
step = n
|
||||
break
|
||||
# convert back to normal number
|
||||
while expo > 0:
|
||||
step *= 10.
|
||||
expo -= 1
|
||||
while expo < 0:
|
||||
step /= 10.
|
||||
expo += 1
|
||||
substep = step / subs
|
||||
# round lower
|
||||
rounded_min = step * int(_min / step)
|
||||
|
||||
# generate ticks list
|
||||
ticks = []
|
||||
x = rounded_min
|
||||
while x + substep < _min:
|
||||
x += substep
|
||||
for _ in range(100):
|
||||
if x < _max + substep:
|
||||
break
|
||||
|
||||
# check if x is a tick or a subtick
|
||||
x = substep * int(x / substep)
|
||||
if abs(x - step * int(x / step)) <= substep / 2:
|
||||
# tick
|
||||
ticks.append((x, fmt % x))
|
||||
else:
|
||||
# subtick
|
||||
ticks.append((x, ''))
|
||||
x += substep
|
||||
return ticks
|
||||
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
# obtain a few properties we need for proper drawing
|
||||
|
||||
painter.setFont(self.font())
|
||||
fm = painter.fontMetrics()
|
||||
label_height = fm.height()
|
||||
|
||||
self.plotx = 3 + 2 * label_height
|
||||
self.ploty = self.height() - 3 - 2 * label_height
|
||||
|
||||
# fill bg of plotting area
|
||||
painter.fillRect(self.plotx ,0,self.width()-self.plotx, self.ploty,_white)
|
||||
|
||||
# paint ticklines
|
||||
if self.curves and self.ticklinewidth > 0:
|
||||
for e in self.xticks:
|
||||
try:
|
||||
_x = e[0] # pylint: disable=unsubscriptable-object
|
||||
_l = e[1] # pylint: disable=unsubscriptable-object
|
||||
except TypeError:
|
||||
_x = e
|
||||
_l = self.xfmt % _x
|
||||
x = self.scaleX(_x)
|
||||
pen = QPen()
|
||||
pen.setBrush(self.ticklinecolors[0 if _l else 1])
|
||||
pen.setWidth(self.ticklinewidth)
|
||||
painter.setPen(pen)
|
||||
painter.drawLine(x, 0, x, self.ploty)
|
||||
for e in self.yticks:
|
||||
try:
|
||||
_y = e[0] # pylint: disable=unsubscriptable-object
|
||||
_l = e[1] # pylint: disable=unsubscriptable-object
|
||||
except TypeError:
|
||||
_y = e
|
||||
_l = self.xfmt % _x
|
||||
y = self.scaleY(_y)
|
||||
pen = QPen()
|
||||
pen.setBrush(self.ticklinecolors[0 if _l else 1])
|
||||
pen.setWidth(self.ticklinewidth)
|
||||
painter.setPen(pen)
|
||||
painter.drawLine(self.plotx, y, self.width(), y)
|
||||
|
||||
# paint curves
|
||||
painter.setClipRect(QRectF(self.plotx, 0, self.width()-self.plotx, self.ploty))
|
||||
for c in self.curves:
|
||||
c.preparepainting(self.scaleX, self.xmin, self.xmax)
|
||||
c.paint(self.scale, painter)
|
||||
painter.setClipping(False)
|
||||
|
||||
# paint frame
|
||||
pen = QPen()
|
||||
pen.setBrush(self.bordercolor)
|
||||
pen.setWidth(self.borderwidth)
|
||||
painter.setPen(pen)
|
||||
painter.drawPolyline(QPolygonF([
|
||||
QPointF(self.plotx, 0),
|
||||
QPointF(self.width()-1, 0),
|
||||
QPointF(self.width()-1, self.ploty),
|
||||
QPointF(self.plotx, self.ploty),
|
||||
QPointF(self.plotx, 0),
|
||||
]))
|
||||
|
||||
# draw labels
|
||||
painter.setBrush(self.labelcolor)
|
||||
h2 = (self.height()-self.ploty)/2.
|
||||
# XXX: offset axis labels from axis a little
|
||||
painter.drawText(self.plotx, self.ploty + h2,
|
||||
self.width() - self.plotx, h2,
|
||||
Qt.AlignCenter | Qt.AlignVCenter, self.xlabel)
|
||||
# rotate ylabel?
|
||||
painter.resetTransform()
|
||||
painter.translate(0, self.ploty / 2.)
|
||||
painter.rotate(-90)
|
||||
w = fm.width(self.ylabel)
|
||||
painter.drawText(-w, -fm.height() / 2., w * 2, self.plotx,
|
||||
Qt.AlignCenter | Qt.AlignTop, self.ylabel)
|
||||
painter.resetTransform()
|
||||
|
||||
if self.curves:
|
||||
for e in self.xticks:
|
||||
try:
|
||||
_x = e[0] # pylint: disable=unsubscriptable-object
|
||||
l = e[1] # pylint: disable=unsubscriptable-object
|
||||
except TypeError:
|
||||
_x = e
|
||||
l = self.xfmt % _x
|
||||
x = self.scaleX(_x)
|
||||
w = fm.width(l)
|
||||
painter.drawText(x - w, self.ploty + 2, 2 * w, h2,
|
||||
Qt.AlignCenter | Qt.AlignVCenter, l)
|
||||
for e in self.yticks:
|
||||
try:
|
||||
_y = e[0] # pylint: disable=unsubscriptable-object
|
||||
l = e[1] # pylint: disable=unsubscriptable-object
|
||||
except TypeError:
|
||||
_y = e
|
||||
l = self.yfmt % _y
|
||||
y = self.scaleY(_y)
|
||||
w = fm.width(l)
|
||||
painter.resetTransform()
|
||||
painter.translate(self.plotx - fm.height(), y + w)
|
||||
painter.rotate(-90)
|
||||
painter.drawText(0, -1,
|
||||
2 * w, fm.height(),
|
||||
Qt.AlignCenter | Qt.AlignBottom, l)
|
||||
painter.resetTransform()
|
||||
|
||||
def sizeHint(self):
|
||||
return QSize(320, 240)
|
@ -43,30 +43,31 @@ from secop.gui.valuewidgets import get_widget
|
||||
|
||||
|
||||
class CommandDialog(QDialog):
|
||||
def __init__(self, cmdname, arglist, parent=None):
|
||||
def __init__(self, cmdname, argument, parent=None):
|
||||
super(CommandDialog, self).__init__(parent)
|
||||
loadUi(self, 'cmddialog.ui')
|
||||
|
||||
self.setWindowTitle('Arguments for %s' % cmdname)
|
||||
row = 0
|
||||
#row = 0
|
||||
|
||||
self._labels = []
|
||||
self.widgets = []
|
||||
for row, dtype in enumerate(arglist):
|
||||
l = QLabel(repr(dtype))
|
||||
l.setWordWrap(True)
|
||||
w = get_widget(dtype, readonly=False)
|
||||
self.gridLayout.addWidget(l, row, 0)
|
||||
self.gridLayout.addWidget(w, row, 1)
|
||||
self._labels.append(l)
|
||||
self.widgets.append(w)
|
||||
# improve! recursive?
|
||||
dtype = argument
|
||||
l = QLabel(repr(dtype))
|
||||
l.setWordWrap(True)
|
||||
w = get_widget(dtype, readonly=False)
|
||||
self.gridLayout.addWidget(l, 0, 0)
|
||||
self.gridLayout.addWidget(w, 0, 1)
|
||||
self._labels.append(l)
|
||||
self.widgets.append(w)
|
||||
|
||||
self.gridLayout.setRowStretch(len(arglist), 1)
|
||||
self.gridLayout.setRowStretch(1, 1)
|
||||
self.setModal(True)
|
||||
self.resize(self.sizeHint())
|
||||
|
||||
def get_value(self):
|
||||
return [w.get_value() for w in self.widgets]
|
||||
return True, self.widgets[0].get_value()
|
||||
|
||||
def exec_(self):
|
||||
if super(CommandDialog, self).exec_():
|
||||
@ -127,7 +128,7 @@ class CommandButton(QPushButton):
|
||||
super(CommandButton, self).__init__(parent)
|
||||
|
||||
self._cmdname = cmdname
|
||||
self._argintypes = cmdinfo['datatype'].argtypes # list of datatypes
|
||||
self._argintype = cmdinfo['datatype'].argtype # single datatype
|
||||
self.resulttype = cmdinfo['datatype'].resulttype
|
||||
self._cb = cb # callback function for exection
|
||||
|
||||
@ -138,11 +139,11 @@ class CommandButton(QPushButton):
|
||||
|
||||
def on_pushButton_pressed(self):
|
||||
self.setEnabled(False)
|
||||
if self._argintypes:
|
||||
dlg = CommandDialog(self._cmdname, self._argintypes)
|
||||
if self._argintype:
|
||||
dlg = CommandDialog(self._cmdname, self._argintype)
|
||||
args = dlg.exec_()
|
||||
if args: # not 'Cancel' clicked
|
||||
self._cb(self._cmdname, args)
|
||||
self._cb(self._cmdname, args[1])
|
||||
else:
|
||||
# no need for arguments
|
||||
self._cb(self._cmdname, None)
|
||||
@ -172,8 +173,13 @@ class ModuleCtrl(QWidget):
|
||||
def _execCommand(self, command, args=None):
|
||||
if not args:
|
||||
args = tuple()
|
||||
result, qualifiers = self._node.execCommand(
|
||||
self._module, command, args)
|
||||
try:
|
||||
result, qualifiers = self._node.execCommand(
|
||||
self._module, command, args)
|
||||
except TypeError:
|
||||
result = None
|
||||
qualifiers = {}
|
||||
# XXX: flag missing data report as error
|
||||
showCommandResultDialog(command, args, result, qualifiers)
|
||||
|
||||
def _initModuleWidgets(self):
|
||||
@ -182,7 +188,7 @@ class ModuleCtrl(QWidget):
|
||||
|
||||
# ignore groupings for commands (for now)
|
||||
commands = self._node.getCommands(self._module)
|
||||
# keep a reference or the widgets are detroyed to soon.
|
||||
# keep a reference or the widgets are destroyed to soon.
|
||||
self.cmdWidgets = cmdWidgets = {}
|
||||
# create and insert widgets into our QGridLayout
|
||||
for command in sorted(commands):
|
||||
@ -191,6 +197,7 @@ class ModuleCtrl(QWidget):
|
||||
cmdWidgets[command] = w
|
||||
self.commandGroupBox.layout().addWidget(w, 0, row)
|
||||
row += 1
|
||||
|
||||
row = 0
|
||||
# collect grouping information
|
||||
paramsByGroup = {} # groupname -> [paramnames]
|
||||
@ -198,8 +205,8 @@ class ModuleCtrl(QWidget):
|
||||
params = self._node.getParameters(self._module)
|
||||
for param in params:
|
||||
props = self._node.getProperties(self._module, param)
|
||||
group = props.get('group', None)
|
||||
if group is not None:
|
||||
group = props.get('group', '')
|
||||
if group:
|
||||
allGroups.add(group)
|
||||
paramsByGroup.setdefault(group, []).append(param)
|
||||
# enforce reading initial value if not already in cache
|
||||
@ -210,6 +217,7 @@ class ModuleCtrl(QWidget):
|
||||
self._groupWidgets = groupWidgets = {}
|
||||
|
||||
# create and insert widgets into our QGridLayout
|
||||
# iterate over a union of all groups and all params
|
||||
for param in sorted(allGroups.union(set(params))):
|
||||
labelstr = param + ':'
|
||||
if param in paramsByGroup:
|
||||
@ -226,7 +234,7 @@ class ModuleCtrl(QWidget):
|
||||
'datatype', None)
|
||||
# yes: create a widget for this as well
|
||||
labelstr, buttons = self._makeEntry(
|
||||
param, initValues[param].value, datatype=datatype, nolabel=True, checkbox=checkbox, invert=True)
|
||||
group, initValues[param].value, datatype=datatype, nolabel=True, checkbox=checkbox, invert=True)
|
||||
checkbox.setText(labelstr)
|
||||
|
||||
# add to Layout (yes: ignore the label!)
|
||||
@ -249,7 +257,7 @@ class ModuleCtrl(QWidget):
|
||||
self._module, param_).get(
|
||||
'datatype', None)
|
||||
label, buttons = self._makeEntry(
|
||||
param_, initval, checkbox=checkbox, invert=False)
|
||||
param_, initval, datatype=datatype, checkbox=checkbox, invert=False)
|
||||
|
||||
# add to Layout
|
||||
self.paramGroupBox.layout().addWidget(label, row, 0)
|
||||
@ -260,7 +268,7 @@ class ModuleCtrl(QWidget):
|
||||
# param is a 'normal' param: create a widget if it has no group
|
||||
# or is named after a group (otherwise its created above)
|
||||
props = self._node.getProperties(self._module, param)
|
||||
if props.get('group', param) == param:
|
||||
if (props.get('group', '') or param) == param:
|
||||
datatype = self._node.getProperties(
|
||||
self._module, param).get(
|
||||
'datatype', None)
|
||||
|
@ -37,7 +37,7 @@ from secop.gui.qt import QWidget, QTextCursor, QFont, QFontMetrics, QLabel, \
|
||||
QMessageBox, pyqtSlot, toHtmlEscaped
|
||||
|
||||
from secop.gui.util import loadUi
|
||||
from secop.protocol.errors import SECOPError
|
||||
from secop.errors import SECoPError
|
||||
from secop.datatypes import StringType, EnumType
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ class NodeCtrl(QWidget):
|
||||
self._addLogEntry(reply, newline=True, pretty=False)
|
||||
else:
|
||||
self._addLogEntry(reply, newline=True, pretty=True)
|
||||
except SECOPError as e:
|
||||
except SECoPError as e:
|
||||
self._addLogEntry(
|
||||
'error %s %s' % (e.name, json.dumps(e.args)),
|
||||
newline=True,
|
||||
@ -145,8 +145,8 @@ class NodeCtrl(QWidget):
|
||||
if 'interface_class' in modprops:
|
||||
interfaces = modprops['interface_class']
|
||||
else:
|
||||
interfaces = modprops['interfaces']
|
||||
description = modprops['description']
|
||||
interfaces = modprops.get('interfaces', '')
|
||||
description = modprops.get('description', '!!! missing description !!!')
|
||||
|
||||
# fallback: allow (now) invalid 'Driveable'
|
||||
unit = ''
|
||||
|
@ -134,7 +134,7 @@ class GenericCmdWidget(ParameterWidget):
|
||||
loadUi(self, 'cmdbuttons.ui')
|
||||
|
||||
self.cmdLineEdit.setText('')
|
||||
self.cmdLineEdit.setEnabled(self.datatype.argtypes is not None)
|
||||
self.cmdLineEdit.setEnabled(self.datatype.argtype is not None)
|
||||
self.cmdLineEdit.returnPressed.connect(
|
||||
self.on_cmdPushButton_clicked)
|
||||
|
||||
@ -164,7 +164,6 @@ def ParameterView(module,
|
||||
parent=None):
|
||||
# depending on datatype returns an initialized widget fit for display and
|
||||
# interaction
|
||||
|
||||
if datatype is not None:
|
||||
if datatype.IS_COMMAND:
|
||||
return GenericCmdWidget(
|
||||
|
@ -24,25 +24,34 @@
|
||||
# pylint: disable=unused-import
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
try:
|
||||
# Do not abort on exceptions in signal handlers.
|
||||
# pylint: disable=unnecessary-lambda
|
||||
sys.excepthook = lambda *args: sys.__excepthook__(*args)
|
||||
|
||||
from PyQt5 import uic
|
||||
from PyQt5.QtCore import Qt, QObject, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QFont, QTextCursor, QFontMetrics
|
||||
from PyQt5.QtWidgets import QLabel, QWidget, QDialog, QLineEdit, QCheckBox, QPushButton, \
|
||||
QSizePolicy, QMainWindow, QMessageBox, QInputDialog, QTreeWidgetItem, QApplication, \
|
||||
QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, \
|
||||
QGridLayout, QScrollArea, QFrame
|
||||
from PyQt5.QtCore import Qt, QObject, pyqtSignal, pyqtSlot, QSize, QPointF, \
|
||||
QRectF
|
||||
from PyQt5.QtGui import QFont, QTextCursor, QFontMetrics, QColor, QBrush, \
|
||||
QPainter, QPolygonF, QPen
|
||||
from PyQt5.QtWidgets import QLabel, QWidget, QDialog, QLineEdit, QCheckBox, \
|
||||
QPushButton, QSizePolicy, QMainWindow, QMessageBox, QInputDialog, \
|
||||
QTreeWidgetItem, QApplication, QGroupBox, QSpinBox, QDoubleSpinBox, \
|
||||
QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, QGridLayout, \
|
||||
QScrollArea, QFrame
|
||||
|
||||
from xml.sax.saxutils import escape as toHtmlEscaped
|
||||
|
||||
except ImportError:
|
||||
from PyQt4 import uic
|
||||
from PyQt4.QtCore import Qt, QObject, pyqtSignal, pyqtSlot
|
||||
from PyQt4.QtCore import Qt, QObject, pyqtSignal, pyqtSlot, QSize, QPointF, QRectF
|
||||
from PyQt4.QtGui import QFont, QTextCursor, QFontMetrics, \
|
||||
QLabel, QWidget, QDialog, QLineEdit, QCheckBox, QPushButton, \
|
||||
QSizePolicy, QMainWindow, QMessageBox, QInputDialog, QTreeWidgetItem, QApplication, \
|
||||
QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, \
|
||||
QGridLayout, QScrollArea, QFrame
|
||||
QGridLayout, QScrollArea, QFrame, QColor, QBrush, QPainter, QPolygonF, QPen
|
||||
|
||||
def toHtmlEscaped(s):
|
||||
return Qt.escape(s)
|
||||
|
@ -6,10 +6,16 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>730</width>
|
||||
<width>464</width>
|
||||
<height>33</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>33</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
@ -37,7 +43,7 @@
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>256</width>
|
||||
<width>128</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -57,7 +63,7 @@
|
||||
<widget class="QLineEdit" name="setLineEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>256</width>
|
||||
<width>128</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>238</width>
|
||||
<height>121</height>
|
||||
<width>100</width>
|
||||
<height>100</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
Reference in New Issue
Block a user