#!/usr/bin/env python # *-----------------------------------------------------------------------* # | | # | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) | # | | # | Author Thierry Zamofing (thierry.zamofing@psi.ch) | # *-----------------------------------------------------------------------* from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QApplication from PyQt5.QtGui import QPainter, QColor, QBrush from pyqtgraph.Qt import QtCore, QtGui import numpy as np import PyQt5.QtGui as QtGui import PyQt5.QtCore as QtCore import PyQt5.QtWidgets as QtW from PyQt5.uic import loadUiType import numpy as np import geometry import sys import logging import epics _log=logging.getLogger(__name__) def obj_info(obj,p=''): print(f"{p}obj_info:{obj}") try: pos=obj.pos() print(f"{p}pos:({pos.x():.6g},{pos.y():.6g})") # in coordinate value on the scene (no change by zooming) except AttributeError: pass try: sz=obj.size() print(f"{p}size:({sz.x():.6g},{sz.y():.6g})") # in coordinate value on the scene (no change by zooming) except AttributeError: pass try: for k, v in (('Viewport', obj.viewport()), ('Window', obj.window())): print( f"{p}{k} (x,y)(w,h):({v.x():.6g},{v.y():.6g})({v.width():.6g},{v.height():.6g})") # in coordinate value on the scene (no change by zooming) except AttributeError: pass try: scnPos=obj.scenePos() print(f"{p}scenePos:({scnPos.x():.6g},{scnPos.y():.6g})") # in pixel on the scene (changes by zooming) except AttributeError: pass try: if type(obj)==QtGui.QTransform: t=obj else: t=obj.transform() print(f"{p}QTransform:{t.m11():8.5g} {t.m12():8.5g} {t.m13():8.5g}") print(f"{p} {t.m21():8.5g} {t.m22():8.5g} {t.m23():8.5g}") print(f"{p} {t.m31():8.5g} {t.m32():8.5g} {t.m33():8.5g}") except AttributeError: pass class RIXSgirder(QWidget): _lutColor={0:(255,0,0),1:(0,255,0),2:(255,255,0)} def __init__(self): super().__init__() self._param={'ctr':(200, 300), # location of big chamber 'rCmb':80, # radius of chamber 'rTrg':10, # radius of target 'szSeal': (20,50), 'szArm': (80,350), 'aaSeal':70, # RIXS sliding angle 'aaArm':70, # RIXS arm angle 'airPads':0, # air pads (off=0 on=1 undef=2) 'defComp':0, # deformation compensation (off=0 on=1 undef=2) } self.initUI() def initUI(self): self.setGeometry(300, 300, 850, 800) self.setWindowTitle('RIXS girder') #label = QLabel('Python', self) #label.move(50,50) #b1 = QPushButton("Button1",self) #b1.move(400,150) self._wdGrpDraw=w=QtGui.QGroupBox("Drawing",self) w.move(10,10) l=QtGui.QVBoxLayout(w) sld={} for key,rng,tk in (('aaSeal',(0,180),5),('aaArm',(0,180),5),('airPads',(0,2),1),('defComp',(0,2),1),): sl=QtGui.QSlider(QtCore.Qt.Horizontal,objectName=key) sl.setFixedWidth(200);sl.setMinimum(rng[0]);sl.setMaximum(rng[1]) sl.setValue(self._param[key]) sl.setTickPosition(QtGui.QSlider.TicksBelow);sl.setTickInterval(tk) l.addWidget(sl) sl.valueChanged.connect(lambda val,key=key: self.sldChanged(key,val)) sld[key]=sl self.show() def sldChanged(self,key,val,*args,**kwargs): p=self._param #print(key,val) if key=='aaArm': p['aaSeal']=v=p['aaSeal']-p['aaArm']+val wSl=self._wdGrpDraw.findChild(QtGui.QSlider, 'aaSeal') wSl.blockSignals(True) wSl.setValue(int(v)) wSl.blockSignals(False) sl=QtGui.QSlider(QtCore.Qt.Horizontal,objectName=key) p[key]=val self.update() def paintEvent(self, e): p=self._param ctr=p['ctr'] aaSeal=p['aaSeal'] aaArm=p['aaArm'] rCmb=p['rCmb'] rTrg=p['rTrg'] xa,ya=p['szArm'] xs,ys=p['szSeal'] ap=p['airPads'] dc=p['defComp'] qp = QPainter() qp.begin(self) qp.translate(ctr[0],ctr[1]) tf0=qp.transform() qp.setPen(QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine)) qp.setBrush(QColor(155, 155, 155, 128)) br1=qp.brush() qp.drawEllipse(-rCmb, -rCmb, 2*rCmb, 2*rCmb) # big chamber qp.drawEllipse(-rTrg, -rTrg, 2*rTrg, 2*rTrg) # target qp.drawLine(0,-rCmb-50,0,-rTrg) #beam qp.rotate(-aaSeal) qp.translate(0,rCmb) tf1=qp.transform() xs2=xs//2 xa2=xa//2 ya2=ya//2 d=int(abs(aaSeal-aaArm)*20) r=min(155+d,255) gb=max(155-d,0) qp.setBrush(QColor(r, gb, gb, 255)) qp.drawRect(-xs2, 0, xs, ys) # seal bellow qp.setBrush(br1) qp.setTransform(tf0) qp.rotate(-aaArm) qp.translate(0,rCmb+ys) tf2=qp.transform() qp.drawRect(-xa2, 0, xa, ya) # girder #qp.drawEllipse(-ya2, 100+150, 20, 20) #pusher left #qp.drawEllipse( ya2-r, 100+150, 20, 20) #pusher right #air pad r,g,b=RIXSgirder._lutColor[ap] rd=13 r3=int(rd*np.sqrt(3)) qp.setBrush(QColor(r, g, b, 255)) qp.drawEllipse(-xa2-rd, ya-4*rd, 2*rd, 2*rd) #left qp.drawEllipse(-xa2-rd+r3,ya-3*rd, 2*rd, 2*rd) #left qp.drawEllipse(-xa2-rd+r3,ya-5*rd, 2*rd, 2*rd) #left qp.drawEllipse( xa2-rd, ya-4*rd, 2*rd, 2*rd) #right qp.drawEllipse( xa2-rd-r3,ya-3*rd, 2*rd, 2*rd) #right qp.drawEllipse( xa2-rd-r3,ya-5*rd, 2*rd, 2*rd) #right qp.drawEllipse( -rd, 3*rd, 2*rd, 2*rd) #grating qp.drawEllipse( 0, 3*rd-r3, 2*rd, 2*rd) #grating qp.drawEllipse( -2*rd, 3*rd-r3, 2*rd, 2*rd) #grating qp.setBrush(br1) #deformation compensation r,g,b=RIXSgirder._lutColor[dc] rd=14 qp.setBrush(QColor(r, g, b, 255)) qp.drawEllipse(-xa2, ya2, 2*rd, 2*rd) #air pad left qp.drawEllipse( xa2-2*rd, ya2, 2*rd, 2*rd) #air pad right #qp.drawEllipse( -rd, rd, 2*rd, 2*rd) #air pad grating qp.setBrush(br1) qp.end() #Ui_MainWindow, QMainWindow = loadUiType("graphEx1.ui") #class RIXSgrating(QMainWindow, Ui_MainWindow): # def __init__(self, ): # super(RIXSgrating, self).__init__() # self.setupUi(self) class RIXSgrating(QWidget): def __init__(self): super().__init__() self._param={'ctr':(500,500), # location of vlsg 'r1':314,#distance probe grating 'r2':447,#distance grating detector 'aa':18, #grating angle 'bb':18, #reflection angle 'cc':58, #detector angle 'szG':(200,5), #size VLS grating 'szD':(150,5), #size detector 'difrBeamPaint':4, # mode to plot the difracted beam } self._lutDifrBeamPaint=(# (number of difr beam,draw mode,alpha,width) ( 4, 2, 190, 0), ( 4, 1, 200, 0), (32, 1, 120, 0), ( 8, 1, 196, 0), (32, 0, 120, 3), (32, 2, 255, 0), ) # n=4;mode=2;alpha=190 # n=4;mode=1;alpha=200 # n=32;mode=1;alpha=120 # n=8;mode=1;alpha=196 n=32; mode=0; alpha=120; width=3 # n=32;mode=2;alpha=255 self.initUI() def initUI(self): #p=self.palette() #p.setColor(self.backgroundRole(), QtCore.Qt.black) #self.setPalette(p) self.setGeometry(300, 300, 1050, 700) self.setWindowTitle('RIXS grating') #w.move(400,100) #w.setFixedSize(200,200) self._wdGrpEnergy=w=QtGui.QGroupBox("Energy",self) w.move(10,10) #w.setFixedSize(200,42+32*2) lv=QtGui.QVBoxLayout(w) w=QtGui.QWidget() #QGroupBox("E2",self) lv.addWidget(w) lg=QtGui.QGridLayout(w) i=0;t='Energy' w=QLabel(t); lg.addWidget(w, i,0) w=QtGui.QLineEdit(t,objectName=t); lg.addWidget(w, i,1) w.returnPressed.connect(lambda w=w:self.OnEnergyChanged(w)) i+=1;t='Grating' w=QLabel(t); lg.addWidget(w, i,0) w=QtGui.QComboBox(objectName=t); lg.addWidget(w, i,1) for i,t in enumerate(geometry.VLSgrating.vlsgTypes): w.insertItem(i,t) w.currentIndexChanged.connect(lambda val,w=w:self.OnEnergyChanged(w,val)) key,rng,tk,pos=('energy',(200,1500),50,60) w=QtGui.QSlider(QtCore.Qt.Horizontal,objectName=key) w.setFixedWidth(200);w.setMinimum(rng[0]);w.setMaximum(rng[1]) #w.setValue(self._param[key]) w.setTickPosition(QtGui.QSlider.TicksBelow);w.setTickInterval(tk) lv.addWidget(w) #sl.valueChanged.connect(lambda val,key=key: self.sldChanged(key,val)) w.valueChanged.connect(lambda val,w=w:self.OnEnergyChanged(w,val)) self._wdGrpGeometry=w=QtGui.QGroupBox("Geometry",self) w.move(10,160) #w.setFixedSize(200,42+32*4) l=QtGui.QGridLayout(w) lut={'aa':'\u03B1', 'bb':'\u03B2', 'cc':'\u03B3'} for i,t in enumerate(('r1','r2','aa','bb','cc',)): tl=lut.get(t,t) w=QLabel(tl) l.addWidget(w, i,0) w=QtGui.QLineEdit(t,objectName=t) l.addWidget(w, i,1) self._wdGrpRaw=w=QtGui.QGroupBox("Motors",self) w.move(250,10) #w.setFixedSize(200,42+32*4) l=QtGui.QGridLayout(w) motors=( ('MT', 'Mask translation'), ('GTZ', 'Grating translation along Z-axis (along beam)'), ('GTY1', 'Grating translation along Y-axis (height) Wedge leveller 1'), ('GTY2', 'Grating translation along Y-axis (height) Wedge leveller 2'), ('GRX', 'Grating rotation around X-axis'), ('GTX', 'Grating translation along X-axis'), ('DTZ', 'Detector Translation along Z-axis'), ('DTY1', 'Detector Translation along Y-axis'), ('DTY2', 'Detector Translation along Y-axis'), ('DRX', 'Detector Rotation around X-axis (ɣ) '), ) for i,m in enumerate(motors): tl,inf=m t=tl.lower() w=QLabel(tl) l.addWidget(w, i,0) w=QtGui.QLineEdit(t,objectName=t) w.setToolTip(inf) l.addWidget(w, i,1) w=QtGui.QPushButton('move all motors') w.clicked.connect(self.btnMoveAllMotors) l.addWidget(w, i+1, 1) self._wdGrpDraw=w=QtGui.QGroupBox("Drawing",self) w.move(470,10) l=QtGui.QVBoxLayout(w) sld={} for key,rng,tk in (('r1',(50,800),50),('r2',(50,800),50),('aa',(0,90),5),('bb',(0,90),5),('cc',(0,180),5), ('difrBeamPaint',(0,len(self._lutDifrBeamPaint)-1),1),): sl=QtGui.QSlider(QtCore.Qt.Horizontal,objectName=key) sl.setFixedWidth(200);sl.setMinimum(rng[0]);sl.setMaximum(rng[1]) sl.setValue(self._param[key]) sl.setTickPosition(QtGui.QSlider.TicksBelow);sl.setTickInterval(tk) l.addWidget(sl) sl.valueChanged.connect(lambda val,key=key: self.sldChanged(key,val)) sld[key]=sl self.show() def OnEnergyChanged(self,w,*args): #_log.debug(f'OnEnergyChanged: {w} {args}') app=QApplication.instance() #wCb=self._wdGrpEnergy.findChild(QtGui.QComboBox, 'Grating') wLe=self._wdGrpEnergy.findChild(QtGui.QLineEdit, 'Energy') wSl=self._wdGrpEnergy.findChild(QtGui.QSlider, 'energy') t=type(w) if t==QtGui.QLineEdit: try: e=float(w.text()) except ValueError as e: return wSl.blockSignals(True) wSl.setValue(int(e)) wSl.blockSignals(False) elif t==QtGui.QComboBox: app=QApplication.instance() vlsg=app._vlsg vlsg.setup(w.currentText()) try: e=float(wLe.text()) except ValueError as e: return elif t==QtGui.QSlider: e=args[0] wLe.setText(f'{e:.4g}') else: raise(TypeError(f'wrong type: {t}')) self.setEnergy(e) def OnEvent(self,*args,**kwargs): #test event print(f'OnEvent: {args} ,{kwargs}') def setEnergy(self,val): app=QApplication.instance() p=self._param wGrating=self._wdGrpEnergy.findChild(QtGui.QComboBox, 'Grating') wEnergy=self._wdGrpEnergy.findChild(QtGui.QLineEdit, 'Energy') wEnergy.setText(f'{val:.4g}') vlsg=app._vlsg vlsg.setup(wGrating.currentText()) self._vlsg_geo=geo=vlsg.energy2geometry(val) p['r1']=geo['r1']/8 p['r2']=geo['r2']/8 p['aa']=(90-geo['aa'])*5 p['bb']=(90-geo['bb'])*5 p['cc']=geo['cc'] grp=self._wdGrpDraw for k,v in p.items(): w=grp.findChild(QtGui.QSlider, k) if w is not None: w.blockSignals(True) w.setValue(int(v)) w.blockSignals(False) grp=self._wdGrpGeometry for k,v in geo.items(): w=grp.findChild(QtGui.QLineEdit, k) w.setText(f'{v:.6g}') self._vlsg_raw=raw,err=vlsg.geometry2raw(**geo) if err is not None: _log.error(str(err)) self._vlsg_raw=raw grp=self._wdGrpRaw for k,v in raw.items(): w=grp.findChild(QtGui.QLineEdit, k) if v is None: w.setText('(null)') else: w.setText(f'{v:.6g}') self.update() def sldChanged(self,key,val,*args,**kwargs): #print(key,val) try: self._vlsg_geo except AttributeError: pass p=self._param p[key]=val self.update() def btnMoveAllMotors(self): p=self._param wGr=self._wdGrpEnergy.findChild(QtGui.QComboBox, 'Grating') wEn=self._wdGrpEnergy.findChild(QtGui.QLineEdit, 'Energy') try: mot=self._vlsg_raw except AttributeError: _log.error('no current energy set') return dlg=DlgMoveMotors() dlg.initUI('prefix',mot) #dlg.initUI('prefix',self._vlsg_raw) if dlg.exec(): print("Success!") else: print("Cancel!") #print(f'grating:{wGr.currentText()} energy:{wEn.text()}') #print(f'geometry:{self._vlsg_geo}') #print(f'raw motors:{self._vlsg_raw}') def paintEvent(self, e): p=self._param r1=int(p['r1']) r2=int(p['r2']) aa=p['aa'] bb=p['bb'] cc=p['cc'] szG=p['szG'] szD=p['szD'] ctr=p['ctr'] qp = QPainter() qp.begin(self) qp.setRenderHints(QPainter.HighQualityAntialiasing) #plot black background w=int(max(szG[0],szD[0])/2) ctr=(max(ctr[0],w+r1),max(w+r2*np.sin((aa+bb)*np.pi/180),ctr[1])) qp.translate(ctr[0],ctr[1]) qp.setBrush(QColor(0, 0, 0)) qp.drawRect(-r1-w, -w, r1+w, 2*w) #qp.drawEllipse(-r1-w, -w, 2*w, 2*w) qp.drawEllipse(-w, -w, 2*w, 2*w) qp.rotate(180-aa-bb) qp.drawRect(-r2-w, -w, r2+w, 2*w) #qp.drawEllipse(-r2-w, -w, 2*w, 2*w) #plot beam path qp.setTransform(QtGui.QTransform()) qp.translate(ctr[0],ctr[1]) qp.setCompositionMode(QtGui.QPainter.CompositionMode_Lighten) tf0=qp.transform() qp.setPen(QtGui.QPen(QtCore.Qt.white, 1, QtCore.Qt.SolidLine)) qp.setBrush(QColor(255, 80, 0, 128)) qp.drawEllipse(-r1-20, -10, 20, 20) # target qp.drawLine(-r1,0,0,0) #central beam1 qp.rotate(-aa) tf1=qp.transform() qp.drawRect(int(-szG[0]/2), 0, szG[0], szG[1]) # grating qp.rotate(-bb) tf2=qp.transform() qp.drawLine(0,0,int(r2+szD[0]/2),0) #central beam2 qp.translate(r2,0) qp.rotate(-cc) tf3=qp.transform() qp.drawRect(int(-szD[0]/2),0 , szD[0], szD[1]) # detector #beam target to vlsg qp.setTransform(QtGui.QTransform()) p0=QtCore.QPointF(*tf0.map(-r1-10, 10)) p1=QtCore.QPointF(*tf1.map(-szG[0]/2, 0)) qp.drawLine(p0,p1) p0=QtCore.QPointF(*tf0.map(-r1-10, -10)) p1=QtCore.QPointF(*tf1.map(szG[0]/2, 0)) qp.drawLine(p0,p1) # beam vlsg to detector #n=32;mode=0;alpha=120;width=3 n,mode,alpha,width=self._lutDifrBeamPaint[p['difrBeamPaint']] scl=256/n p0=QtCore.QPointF(*tf1.map(-szG[0]/2, 0)) p1=QtCore.QPointF(*tf1.map(szG[0]/2, 0)) if mode==0: pen=QtGui.QPen(QtCore.Qt.black, width, QtCore.Qt.SolidLine) col=QtGui.QColor() for i in range(n): p2=QtCore.QPointF(*tf3.map(szD[0]/2-szD[0]*i/(n-1),0)) col.setHsv(int(i*scl),255,255,alpha) pen.setColor(col) qp.setPen(pen) qp.drawLine(p0,p2) qp.drawLine(p1,p2) if mode==1: col=QtGui.QColor() qp.setPen(QtGui.QPen(QtCore.Qt.black, 0, QtCore.Qt.SolidLine)) for i in range(n): p2=QtCore.QPointF(*tf3.map(szD[0]/2-szD[0]*i/(n-1), 0)) col.setHsv(int(i*scl), 255, 255, alpha) qp.setBrush(col) qp.drawPolygon(p0, p1, p2) if mode==2: col=QtGui.QColor() qp.setPen(QtGui.QPen(QtCore.Qt.black, 0, QtCore.Qt.SolidLine)) for i in range(n): p2=QtCore.QPointF(*tf3.map(szD[0]/2-szD[0]*(i+1)/n, 0)) p3=QtCore.QPointF(*tf3.map(szD[0]/2-szD[0]*i/n, 0)) col.setHsv(int(i*scl), 255, 255, alpha) qp.setBrush(col) qp.drawPolygon(p0, p1, p2, p3) qp.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver) #draw central beam (if needed) if mode!=0: qp.setTransform(tf0) qp.setPen(QtGui.QPen(QtGui.QColor(0x757780), 2, QtCore.Qt.SolidLine)) qp.drawLine(-r1,0,0,0) #central beam1 qp.setTransform(tf2) qp.drawLine(0,0,int(r2+szD[0]/2),0) #central beam2 #draw dimensions try: d=self._vlsg_geo except AttributeError: vr1=r1; vr2=r2; vaa=aa; vbb=bb; vcc=cc else: vr1=d['r1'] vr2=d['r2'] vaa=90-d['aa'] vbb=90-d['bb'] vcc=d['cc'] qp.setTransform(QtGui.QTransform()) pen=QtGui.QPen(QtCore.Qt.red, 1, QtCore.Qt.SolidLine) penTxt=QtGui.QPen(QtCore.Qt.yellow, 1, QtCore.Qt.SolidLine) qp.setPen(pen) p0=QtCore.QPointF(*tf0.map(-r1-10, +10)) p1=QtCore.QPointF(*tf0.map(-r1-10, 0+w)) qp.drawLine(p0,p1) p2=QtCore.QPointF(*tf0.map(0, 0)) p3=QtCore.QPointF(*tf0.map(0, 0+w)) qp.drawLine(p2,p3) p4=(p1+p3)/2 #text pos p5=QtCore.QPointF(*tf2.map(0, 0+w)) qp.drawLine(p2,p5) p6=QtCore.QPointF(*tf2.map(r2, 0)) p7=QtCore.QPointF(*tf2.map(r2, 0+w)) qp.drawLine(p6,p7) p8=(p5+p7)/2 #text pos p9=QtCore.QPointF(*tf1.map(0, -w)) qp.drawLine(p2,p9) s=50 qp.drawArc(int(p2.x())-s, int(p2.y())-s, 2*s, 2*s, 180*16, int(aa*16)) s1=s*np.cos(aa*np.pi/180); s2=s*np.sin(aa*np.pi/180) qp.drawArc(int(p2.x())-s, int(p2.y())-s, 2*s, 2*s, int(aa*16), int(bb*16)) qp.drawArc(int(p6.x())-s, int(p6.y())-s, 2*s, 2*s, int((aa+bb)*16), int(cc*16)) p10=QtCore.QPointF(*tf2.map(r2+20, 0)) #text pos qp.setPen(penTxt) qp.drawText(p4+QtCore.QPointF(-40,-10),f'R1={vr1:.5g}mm') #qp.setTransform(QtGui.QTransform()) qp.translate(p8); qp.rotate(-aa-bb) qp.drawText(-40,-10,f'R2={vr2:.5g}mm') qp.setTransform(QtGui.QTransform()) qp.translate(p2); qp.rotate(-aa) qp.drawText(20-int(szG[0]/2),20,f'aa={vaa:.5g}°') qp.drawText(20,20,f'bb={vbb:.5g}°') qp.setTransform(QtGui.QTransform()) qp.translate(p10); qp.rotate(-aa-bb) qp.drawText(0,20,f'cc={vcc:.5g}°') #for i,p in enumerate((p0,p1,p2,p3,p4,p5,p6,p7,p8,p9)): # qp.drawText(p,f'P{i}') #p5=QtCore.QPointF(*tf1.map(-r2-10, 50+w)) qp.end() #https://www.pythonguis.com/tutorials/pyqt-dialogs/ class DlgMoveMotors(QtGui.QDialog): def __init__(self): super().__init__() #self.initUI() def initUI(self,prefix,motDst): self._motDst=motDst self.setWindowTitle("Move Motors:") #QBtn=QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel #self.buttonBox=QtGui.QDialogButtonBox(QBtn) #self.buttonBox.accepted.connect(self.accept) #self.buttonBox.rejected.connect(self.reject) self.buttonBox=QtGui.QDialogButtonBox() btn=self.buttonBox.addButton('move all',QtGui.QDialogButtonBox.ActionRole) btn.clicked.connect(self.OnMove) self.buttonBox.addButton('stop all',QtGui.QDialogButtonBox.ActionRole) self.layout=QtGui.QVBoxLayout() message=QLabel("Something happened, is that OK?") self.layout.addWidget(message) self._wdGrpRaw=w=QtGui.QGroupBox("Motors", self) self.layout.addWidget(w) self._layoutGrid=lg=QtGui.QGridLayout(w) # dev=epics.Device('SATES30-RIXS:MOT_ABL.', attrs=('VAL', 'RBV', 'DESC')) app=QApplication.instance() devs=app._devs prefix='SATES30-RIXS:' for i,(k,v) in enumerate(motDst.items()): m='MOT_'+k.upper() #devs[k]=dev=epics.Device(prefix+m+'.', attrs=('RBV', 'DESC'), timeout=.5) # for safty: removed 'VAL', try: dev=devs[k] except KeyError: devs[k]=dev=SimDevice(prefix+m+'.', attrs=('VAL', 'RBV', 'DESC')) w=QtGui.QCheckBox(m,objectName=k) lg.addWidget(w, i, 0) if v is None: #v="
(null)"
v="(null)"
else:
rbv=dev.RBV
d=v-rbv
if d>0:
c='ff8080'
else:
c='60a060'
v=f"{v:.5g} (old:{rbv:.5g} {d:.5g})"
w.setChecked(True)
w=QLabel(v)
lg.addWidget(w, i, 1)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
def OnMove(self):
app=QApplication.instance()
devs=app._devs
motDst=self._motDst
lg=self._layoutGrid
col=lg.columnCount()
for i,(k,v) in enumerate(motDst.items()):
cb=lg.itemAt(i*col).widget()
if cb.isChecked():
if v is not None:
dev=devs[k]
#print(dev)
dev.VAL=v # move motor
print(f'{cb.objectName()} {dev}')
# ->>>> https://pyepics.github.io/pyepics/devices.html >>> USE THIS
#[satesf-cons-03 ~]$ /opt/gfa/python-3.8/latest/bin/ipython3
#import CaChannel
#import epics
#capv=CaChannel.CaChannel('SATES30-RIXS:MOT_ABL.VAL') -> THIS IS REALLY BASIC...
#capv.state()
#m=epics.Motor('SATES30-RIXS:MOT_ABL')
#pv=pvm.PV('RBV')
#dev=epics.Device('SATES30-RIXS:MOT_ABL.', attrs=('VAL', 'RBV', 'DESC'))
#dev.RBV
class SimDevice():
def __init__(self, prefix='', attrs=None,
nonpvs=None, delim='', timeout=None,
mutable=True, aliases=None, with_poll=True):
self._prefix=prefix
self._pvs={}
for k in attrs:
self._pvs[k]=0
def __getattr__(self, attr):
#if self._pvs:
if '_pvs' in self.__dict__:
return self._pvs[attr]
else:
_log.debug(attr)
raise AttributeError
def __setattr__(self, attr, val):
if attr in ('_pvs','_prefix'):
self.__dict__[attr]=val
elif attr in self._pvs:
self._pvs[attr]= val
if attr=='VAL' and 'RBV' in self._pvs:
self._pvs['RBV']=val
else:
self.__dict__[attr]=val
def __repr__(self):
"string representation"
attr=[]
for k,v in self._pvs.items():
attr.append(f'{k}: {v}')
s=f"