Closed prjemian closed 2 years ago
Is there a visibility rule missing?
That comes from ADSetup.adl. There is a rectangle that spans the background. Second widget in the ADL file (means it is stacked in the back, later widgets are stacked on top). Look at the rule for "Connected".
Could be related to #61.
Can show this with ADSimDetector instance: pydm -m "P=ad:,R=cam1:" ADSetup.ui
Here's a side-by-side view with caQtDM (left) & PyDM (right):
Does not work yet (#61 included).
section from .adl
file:
text {
object {
x=197
y=259
width=90
height=20
}
"basic attribute" {
clr=63
}
"dynamic attribute" {
vis="if not zero"
calc="0"
chan="$(P)$(R)AsynIO.CNCT"
}
textix="Connected"
align="horiz. centered"
}
Corresponding section from converted PyDM file:
<widget class="PyDMLabel" name="text_3">
<property name="geometry">
<rect>
<x>197</x>
<y>259</y>
<width>90</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Connected</string>
</property>
<property name="font" stdset="0">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="brush" stdset="0">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>40</red>
<green>147</green>
<blue>21</blue>
</color>
</brush>
</property>
<property name="rules" stdset="0">
<string>[{"name": "visibility", "property": "Visible", "channels": [{"channel": "ca://${P}${R}AsynIO.CNCT", "trigger": true}], "expression": "0"}]</string>
</property>
<property name="toolTip">
<string>text_3</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="styleSheet">
<string notr="true">PyDMLabel#text_3 {
color: rgb(40, 147, 21);
}</string>
</property>
</widget>
Here's the PyDM screen in QT's designer, showing the rules for the Disconnected
widget.
Now, rules for the Connected
widget.
The Expression
should be similar but it is not.
The Expression
must compare with the string value?
(pydm) prjemian@zap:~/.../BCDA-APS/adl2pydm$ caget ad:cam1:AsynIO.CNCT
ad:cam1:AsynIO.CNCT Connect
Correct. Confirmed by replacing the PV in the calc (${P}${R}AsynIO.CNCT
) with a bo PV (gp:gp:bit1
) that can be controlled independent of area detector. Then, change the Expression to compare =="Connect"
or !="Connect"
.
Question: How to force Expression to use a number?
Also, for the text
widget with textix="Connected"
in ADSetup.adl
, there is an additional calc=0
setting under dynamic attribute
that is not present in ther Disconnected
case. How can adl2pydm
resolve this?
Compare with with the same widget (also Qt .ui
file) rendered for caQtDM:
<widget class="caLabel" name="caLabel_3">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="foreground">
<color alpha="255">
<red>40</red>
<green>147</green>
<blue>21</blue>
</color>
</property>
<property name="background">
<color alpha="0">
<red>40</red>
<green>147</green>
<blue>21</blue>
</color>
</property>
<property name="visibility">
<enum>caLabel::IfNotZero</enum>
</property>
<property name="visibilityCalc">
<string>0</string>
</property>
<property name="channel">
<string>$(P)$(R)AsynIO.CNCT</string>
</property>
<property name="text">
<string>Connected</string>
</property>
<property name="fontScaleMode">
<enum>ESimpleLabel::WidthAndHeight</enum>
</property>
<property name="alignment">
<set>Qt::AlignAbsolute|Qt::AlignHCenter|Qt::AlignVCenter</set>
</property>
<property name="geometry">
<rect>
<x>197</x>
<y>259</y>
<width>90</width>
<height>20</height>
</rect>
</property>
</widget>
This is a tough one to solve. The PV in question is returning a string value and there is no easy way from PyDM to request a numerical value. If it were a bo
record, could use the .RVAL
field but that is not the case here. Here is a demo using a bo
record (gp:gp:bit1
). with Expressions in several ways. The first column is what the current rendering uses with ADSetup.adl, then second is using string comparisons (the string values are not available to the converter), and the third is using a numerical value from the .RVAL
field.
.dbd
file shows: field(CNCT, DBF_MENU) {
promptgroup("40 - Input")
prompt("Connect/Disconnect")
interest(1)
menu(asynCONNECT)
special(SPC_MOD)
}
It would help if PyDM had a mode to use numerical values instead of strings in these calcs. But there can be uses for string values, too. An option switch.
Propose some resolution in a PR to PyDM.
How does caQtDM handle the comparison here? Always request numerical DBF type? Sounds like a non-default option for PyDM to gain compatibility.
The caQtDM code looks like it is a complicated decision:
if((caFieldType == caSTRING || caFieldType == caENUM || caFieldType == caCHAR) && ptr->edata.dataB != (void*) 0) {
if(ptr->edata.dataSize < STRING_EXCHANGE_SIZE) {
memcpy(dataString, (char*) ptr->edata.dataB, (size_t) ptr->edata.dataSize);
dataString[ptr->edata.dataSize] = '\0';
// in case of enum we have to get the right string from the value
if(caFieldType == caENUM) {
QString String(dataString);
QStringList list;
//list = String.split(";");
list = String.split((QChar)27);
if((ptr->edata.fieldtype == caENUM) && ((int) ptr->edata.ivalue < list.count() ) && (list.count() > 0)) {
if(list.at((int) ptr->edata.ivalue).trimmed().size() != 0) { // string seems to empty, give value
QString strng = list.at((int) ptr->edata.ivalue);
QByteArray ba = strng.toLatin1();
strcpy(dataString, ba.data());
}
}
}
} else {
char asc[MAX_STRING_LENGTH];
snprintf(asc, MAX_STRING_LENGTH, "Invalid channel data type %s", qasc(w->objectName()));
postMessage(QtDebugMsg, asc);
valid = false;
return true;
}
}
This type of decision must be handled in pydm with access to the actual PV used in the calc. Only with a connected channel can the field type and list of enumerations be determined.
The PyDM code to evaluate rules is much shorter:
def calculate_expression(self, widget_ref, idx, rule):
"""
Evaluate the expression defined by the rule and emit the `rule_signal`
with the new value.
.. warning
This method mutates the input rule in-place
Returns
-------
None
"""
rule['calculate'] = False
vals = rule['values']
enums = rule['enums']
calc_vals = []
for en, val in zip(enums, vals):
try:
calc_vals.append(en[val])
continue
except:
calc_vals.append(val)
eval_env = {'np': np,
'ch': calc_vals}
eval_env.update({k: v
for k, v in math.__dict__.items()
if k[0] != '_'})
try:
expression = rule['rule']['expression']
name = rule['rule']['name']
prop = rule['rule']['property']
val = eval(expression, eval_env)
self.emit_value(widget_ref, name, prop, val)
except Exception as e:
logger.exception("Error while evaluating Rule.")
But this is the line that substitutes an enumerated text value from an integer value:
calc_vals.append(en[val])
We want to make this conversion the default but can switch it off for converted MEDM screens.
Need:
As an alternative to a command-line option, this converter could set a property on each widget that would be used to prevent the default conversion. ONLY those widgets with the property set to True would bypass the conversion. This is easier and more automatic than passing the new command-line option from the application down to each widget.
When using the new PyDM screens with an AVT Mako camera, the green "Connected" text does not show on the PyDM screen although it shows in the caQtDM screen (shown to the left).