reindent and some image tweeks
This commit is contained in:
@@ -20,32 +20,32 @@ simulated = appsconf.get("simulate", False)
|
|||||||
logger.info(f"configuring for endstation: {endstation.upper()}")
|
logger.info(f"configuring for endstation: {endstation.upper()}")
|
||||||
|
|
||||||
if simulated:
|
if simulated:
|
||||||
logger.warning("SIMULATION is ACTIVE")
|
logger.warning("SIMULATION is ACTIVE")
|
||||||
css_file = inst_folder / "swissmx.css"
|
css_file = inst_folder / "swissmx.css"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def font(name: str) -> str:
|
def font(name: str) -> str:
|
||||||
p = Path(__file__).absolute().parent / "fonts" / name
|
p = Path(__file__).absolute().parent / "fonts" / name
|
||||||
return str(p)
|
return str(p)
|
||||||
|
|
||||||
|
|
||||||
def logo(size: int = 0) -> str:
|
def logo(size: int = 0) -> str:
|
||||||
p = Path(__file__).absolute().parent / "logos" / "logo.png"
|
p = Path(__file__).absolute().parent / "logos" / "logo.png"
|
||||||
if size:
|
if size:
|
||||||
p = Path(__file__).absolute().parent / "logos" / f"tell_logo_{size}x{size}.png"
|
p = Path(__file__).absolute().parent / "logos" / f"tell_logo_{size}x{size}.png"
|
||||||
return str(p)
|
return str(p)
|
||||||
|
|
||||||
|
|
||||||
def option(key: str) -> bool:
|
def option(key: str) -> bool:
|
||||||
try:
|
try:
|
||||||
return settings.value(key, type=bool)
|
return settings.value(key, type=bool)
|
||||||
except:
|
except:
|
||||||
logger.error(f"option {key} not known")
|
logger.error(f"option {key} not known")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def toggle_option(key: str):
|
def toggle_option(key: str):
|
||||||
v = settings.value(key, type=bool)
|
v = settings.value(key, type=bool)
|
||||||
settings.setValue(key, not v)
|
settings.setValue(key, not v)
|
||||||
settings.sync()
|
settings.sync()
|
||||||
|
|||||||
147
camera.py
147
camera.py
@@ -24,6 +24,20 @@ Best regards
|
|||||||
Helge
|
Helge
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# In [2]: np.array(range(20))
|
||||||
|
# Out[2]:
|
||||||
|
# array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||||
|
# 17, 18, 19])
|
||||||
|
|
||||||
|
# In [3]: np.array(range(20)).reshape(4,5)
|
||||||
|
# Out[3]:
|
||||||
|
# array([[ 0, 1, 2, 3, 4],
|
||||||
|
# [ 5, 6, 7, 8, 9],
|
||||||
|
# [10, 11, 12, 13, 14],
|
||||||
|
# [15, 16, 17, 18, 19]])
|
||||||
|
|
||||||
|
# shape is (imgidx,h,w) w is the fast counting index
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
_log = logging.getLogger(__name__)
|
_log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -99,7 +113,7 @@ class epics_cam(object):
|
|||||||
imgSeq=self._sim['imgSeq']
|
imgSeq=self._sim['imgSeq']
|
||||||
idx=self._sim['imgIdx']
|
idx=self._sim['imgIdx']
|
||||||
self._sim['imgIdx']=(idx + 1) % imgSeq.shape[0]
|
self._sim['imgIdx']=(idx + 1) % imgSeq.shape[0]
|
||||||
_log.info('simulated idx:{}'.format(idx))
|
#_log.debug('simulated idx:{}'.format(idx))
|
||||||
self.pic=pic=imgSeq[idx]
|
self.pic=pic=imgSeq[idx]
|
||||||
return pic
|
return pic
|
||||||
try:
|
try:
|
||||||
@@ -200,30 +214,54 @@ class epics_cam(object):
|
|||||||
|
|
||||||
def sim_gen(self,sz=(1500,1000),t=100,mode=0):
|
def sim_gen(self,sz=(1500,1000),t=100,mode=0):
|
||||||
'generate simulation data'
|
'generate simulation data'
|
||||||
_log.info('generate simulation images, mode:{}...'.format(mode))
|
if mode==0:
|
||||||
w,h=sz
|
_log.info('generate {} pulsing wases simulation images, mode:{}...'.format(t,mode))
|
||||||
self._imgSeq=imgSeq=np.ndarray(shape=(t,h,w),dtype=np.uint16)
|
w,h=sz
|
||||||
x = np.linspace(-5, 5, w)
|
imgSeq=np.ndarray(shape=(t,h,w),dtype=np.uint16)
|
||||||
y = np.linspace(-5, 5, h)
|
x = np.linspace(-5, 5, w)
|
||||||
# full coordinate arrays
|
y = np.linspace(-5, 5, h)
|
||||||
xx, yy = np.meshgrid(x, y)
|
# full coordinate arrays
|
||||||
|
xx, yy = np.meshgrid(x, y)
|
||||||
|
|
||||||
|
for i in range(t):
|
||||||
|
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+.1*i)**2 + np.sin(yy+.01*i)**2)#+xx*t+yy*t)
|
||||||
|
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+.1*i)**2 + np.sin((1+.1*np.sin(.2*i))*yy+.001*i**2)**2)#+xx*t+yy*t)
|
||||||
|
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+2*np.sin(i/t*2*np.pi))**2 + np.sin(yy)**2)
|
||||||
|
px=2*np.sin(i/t*2*np.pi)
|
||||||
|
fx=1
|
||||||
|
py=2*np.sin(i/t*2*np.pi)
|
||||||
|
fy=1+.3*np.sin(i/t*2*np.pi*2)
|
||||||
|
imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx*fx+px)**2 + np.sin(yy*fy+py)**2)
|
||||||
|
#np.random.bytes(100)
|
||||||
|
wr=w//4
|
||||||
|
hr=h//4
|
||||||
|
imgSeq[:,0:hr,0:wr]+=np.random.randint(0,100,(t,hr,wr),dtype=np.uint16)
|
||||||
|
elif mode==1:
|
||||||
|
import glob,PIL.Image
|
||||||
|
path='/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX/simCamImg/*.png'
|
||||||
|
_log.info('generate simulation images:{}...'.format(path))
|
||||||
|
glb=glob.glob(path)
|
||||||
|
img = PIL.Image.open(glb[0])
|
||||||
|
sz=img.size # (w,h)
|
||||||
|
imgSeq=np.ndarray(shape=(len(glb),sz[1],sz[0]),dtype=np.uint8) # shape is (n,h,w)
|
||||||
|
for i,fn in enumerate(glb):
|
||||||
|
img=PIL.Image.open(fn)
|
||||||
|
assert(img.mode=='L') # 8 bit grayscale
|
||||||
|
assert(sz==img.size)
|
||||||
|
imgSeq[i,:,:]=np.array(img.getdata()).reshape(sz[::-1])
|
||||||
|
f=np.array(((0,0,0,0,0),
|
||||||
|
(0,1,1,1,0),
|
||||||
|
(0,1,0,0,0),
|
||||||
|
(0,1,1,0,0),
|
||||||
|
(0,1,0,0,0),
|
||||||
|
(0,0,0,0,0),),imgSeq.dtype)
|
||||||
|
imgSeq[i,0:6,0:5]=f*255
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for i in range(t):
|
|
||||||
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+.1*i)**2 + np.sin(yy+.01*i)**2)#+xx*t+yy*t)
|
|
||||||
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+.1*i)**2 + np.sin((1+.1*np.sin(.2*i))*yy+.001*i**2)**2)#+xx*t+yy*t)
|
|
||||||
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+2*np.sin(i/t*2*np.pi))**2 + np.sin(yy)**2)
|
|
||||||
px=2*np.sin(i/t*2*np.pi)
|
|
||||||
fx=1
|
|
||||||
py=2*np.sin(i/t*2*np.pi)
|
|
||||||
fy=1+.3*np.sin(i/t*2*np.pi*2)
|
|
||||||
imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx*fx+px)**2 + np.sin(yy*fy+py)**2)
|
|
||||||
#np.random.bytes(100)
|
|
||||||
wr=w//4
|
|
||||||
hr=h//4
|
|
||||||
imgSeq[:,0:hr,0:wr]+=np.random.randint(0,100,(t,hr,wr),dtype=np.uint16)
|
|
||||||
self._sim['imgSeq']=imgSeq
|
self._sim['imgSeq']=imgSeq
|
||||||
self._sim['imgIdx']=0
|
self._sim['imgIdx']=0
|
||||||
_log.info('dome')
|
_log.info('done-> shape:{} dtype:{}'.format(imgSeq.shape,imgSeq.dtype))
|
||||||
|
|
||||||
def set_transformations(self,*args):
|
def set_transformations(self,*args):
|
||||||
_log.error('OLD FUNCTION NOT IMPLEMENTED {}'.format(args))
|
_log.error('OLD FUNCTION NOT IMPLEMENTED {}'.format(args))
|
||||||
@@ -232,7 +270,9 @@ class epics_cam(object):
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import time, os, PIL.Image, platform, subprocess
|
import time, os, PIL.Image, platform, subprocess
|
||||||
import argparse
|
import argparse
|
||||||
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
logging.basicConfig(level=logging.DEBUG,format='%(name)s:%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
||||||
|
logging.getLogger('PIL').setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def default_app_open(file):
|
def default_app_open(file):
|
||||||
if platform.system() == 'Darwin': # macOS
|
if platform.system() == 'Darwin': # macOS
|
||||||
@@ -248,6 +288,7 @@ if __name__ == "__main__":
|
|||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--ui", "-u", help="qt test", type=int, default=0)
|
parser.add_argument("--ui", "-u", help="qt test", type=int, default=0)
|
||||||
parser.add_argument("--sim", "-s", help="simulation mode", type=int, default=None)
|
parser.add_argument("--sim", "-s", help="simulation mode", type=int, default=None)
|
||||||
|
parser.add_argument("--delay", "-d", help="delay in simulation mode", type=float, default=None)
|
||||||
parser.add_argument("--prefix","-p",help="PV prefix for images: default=%(default)s",type=str,default="SARES30-CAMS156-SMX-OAV",)
|
parser.add_argument("--prefix","-p",help="PV prefix for images: default=%(default)s",type=str,default="SARES30-CAMS156-SMX-OAV",)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@@ -328,7 +369,11 @@ if __name__ == "__main__":
|
|||||||
(0,1,0,0,0),
|
(0,1,0,0,0),
|
||||||
(0,0,0,0,0),),pic.dtype)
|
(0,0,0,0,0),),pic.dtype)
|
||||||
pic[0:6,0:5]=f*pic.max()
|
pic[0:6,0:5]=f*pic.max()
|
||||||
imv.setImage(pic, autoRange=False, autoLevels=False)
|
if args.ui==1:
|
||||||
|
img.setImage(pic)
|
||||||
|
else:
|
||||||
|
imv.setImage(pic, autoRange=False, autoLevels=False)
|
||||||
|
|
||||||
|
|
||||||
def new_frame_sim_cb(self,arl=False):
|
def new_frame_sim_cb(self,arl=False):
|
||||||
imgSeq =self._sim['imgSeq']
|
imgSeq =self._sim['imgSeq']
|
||||||
@@ -338,9 +383,15 @@ if __name__ == "__main__":
|
|||||||
self._sim['imgIdx']=(idx+1) % imgSeq.shape[0]
|
self._sim['imgIdx']=(idx+1) % imgSeq.shape[0]
|
||||||
#_log.info('simulated idx:{}'.format(idx))
|
#_log.info('simulated idx:{}'.format(idx))
|
||||||
pic = imgSeq[idx]
|
pic = imgSeq[idx]
|
||||||
imv.setImage(pic, autoRange=arl, autoLevels=arl)
|
if args.ui==1:
|
||||||
|
img.setImage(pic)
|
||||||
|
else:
|
||||||
|
imv.setImage(pic, autoRange=arl, autoLevels=arl)
|
||||||
|
|
||||||
QtCore.QTimer.singleShot(1, self.new_frame_sim_cb)
|
if args.delay:
|
||||||
|
QtCore.QTimer.singleShot(int(1000*args.delay), self.new_frame_sim_cb)
|
||||||
|
else:
|
||||||
|
QtCore.QTimer.singleShot(0, self.new_frame_sim_cb)
|
||||||
now = ptime.time()
|
now = ptime.time()
|
||||||
fps2 = 1.0 / (now - udt)
|
fps2 = 1.0 / (now - udt)
|
||||||
self._sim['updateTime'] = now
|
self._sim['updateTime'] = now
|
||||||
@@ -358,13 +409,34 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
|
|
||||||
## Create window with ImageView widget
|
if args.ui==1:
|
||||||
win = QtGui.QMainWindow()
|
win = pg.GraphicsLayoutWidget()
|
||||||
win.resize(800,800)
|
win.show() ## show widget alone in its own window
|
||||||
imv = pg.ImageView()
|
win.setWindowTitle('pyqtgraph example: ImageItem')
|
||||||
win.setCentralWidget(imv)
|
view = win.addViewBox(invertY=True)
|
||||||
win.show()
|
|
||||||
win.setWindowTitle('pyqtgraph example: ImageView')
|
## lock the aspect ratio so pixels are always square
|
||||||
|
view.setAspectLocked(True)
|
||||||
|
|
||||||
|
## Create image item https://pyqtgraph.readthedocs.io/en/latest/graphicsItems/imageitem.html
|
||||||
|
img = pg.ImageItem(border='g')
|
||||||
|
#tr = QtGui.QTransform() # prepare ImageItem transformation:
|
||||||
|
#tr.scale(6.0, 3.0) # scale horizontal and vertical axes
|
||||||
|
#tr.translate(-1.5, -1.5) # move 3x3 image to locate center at axis origin
|
||||||
|
#img.setTransform(tr) # assign transform
|
||||||
|
view.addItem(img)
|
||||||
|
|
||||||
|
## Set initial view bounds
|
||||||
|
view.setRange(QtCore.QRectF(0, 0, 600, 600))
|
||||||
|
else:
|
||||||
|
## Create window with ImageView widget
|
||||||
|
win = QtGui.QMainWindow()
|
||||||
|
win.resize(800,800)
|
||||||
|
imv = pg.ImageView()
|
||||||
|
win.setCentralWidget(imv)
|
||||||
|
win.show()
|
||||||
|
win.setWindowTitle('pyqtgraph example: ImageView')
|
||||||
|
|
||||||
|
|
||||||
## Display the data and assign each frame a time value from 1.0 to 3.0
|
## Display the data and assign each frame a time value from 1.0 to 3.0
|
||||||
cam = UIcamera(prefix=args.prefix)
|
cam = UIcamera(prefix=args.prefix)
|
||||||
@@ -383,10 +455,11 @@ if __name__ == "__main__":
|
|||||||
cam._sim['updateTime'] = ptime.time()
|
cam._sim['updateTime'] = ptime.time()
|
||||||
cam.new_frame_sim_cb(arl=True)
|
cam.new_frame_sim_cb(arl=True)
|
||||||
|
|
||||||
## Set a custom color map
|
if args.ui==2:
|
||||||
colors = [(0, 0, 0),(45, 5, 61),(84, 42, 55),(150, 87, 60),(208, 171, 141),(255, 255, 255)]
|
## Set a custom color map
|
||||||
cmap = pg.ColorMap(pos=np.linspace(0.0, 1.0, 6), color=colors)
|
colors = [(0, 0, 0),(45, 5, 61),(84, 42, 55),(150, 87, 60),(208, 171, 141),(255, 255, 255)]
|
||||||
imv.setColorMap(cmap)
|
cmap = pg.ColorMap(pos=np.linspace(0.0, 1.0, 6), color=colors)
|
||||||
|
imv.setColorMap(cmap)
|
||||||
|
|
||||||
## Start Qt event loop unless running in interactive mode.
|
## Start Qt event loop unless running in interactive mode.
|
||||||
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import math
|
|
||||||
import logging
|
import logging
|
||||||
|
_log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
import math
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal
|
from PyQt5.QtCore import Qt, pyqtSignal
|
||||||
from PyQt5.QtGui import QPainter, QBrush, QColor, QPainterPath, QPen, QDoubleValidator
|
from PyQt5.QtGui import QPainter, QBrush, QColor, QPainterPath, QPen, QDoubleValidator
|
||||||
@@ -11,8 +13,6 @@ from epics.ca import pend_event
|
|||||||
from app_utils import DeltatauMotorStatus, assert_motor_positions
|
from app_utils import DeltatauMotorStatus, assert_motor_positions
|
||||||
|
|
||||||
Ui_MotorTweak, QWidget = loadUiType('epics_widgets/MotorTweak.ui')
|
Ui_MotorTweak, QWidget = loadUiType('epics_widgets/MotorTweak.ui')
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
SPMG_STOP = 0
|
SPMG_STOP = 0
|
||||||
SPMG_PAUSE = 1
|
SPMG_PAUSE = 1
|
||||||
SPMG_MOVE = 2
|
SPMG_MOVE = 2
|
||||||
@@ -20,336 +20,340 @@ SPMG_GO = 3
|
|||||||
|
|
||||||
|
|
||||||
class MotorTweak(QWidget, Ui_MotorTweak):
|
class MotorTweak(QWidget, Ui_MotorTweak):
|
||||||
event_val = pyqtSignal(str, dict)
|
event_val = pyqtSignal(str, dict)
|
||||||
event_readback = pyqtSignal(str, float, dict)
|
event_readback = pyqtSignal(str, float, dict)
|
||||||
event_soft_limit = pyqtSignal(str, dict)
|
event_soft_limit = pyqtSignal(str, dict)
|
||||||
event_high_hard_limit = pyqtSignal(str, dict)
|
event_high_hard_limit = pyqtSignal(str, dict)
|
||||||
event_low_hard_limit = pyqtSignal(str, dict)
|
event_low_hard_limit = pyqtSignal(str, dict)
|
||||||
event_axis_fault = pyqtSignal(str, dict)
|
event_axis_fault = pyqtSignal(str, dict)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(MotorTweak, self).__init__(parent=parent)
|
super(MotorTweak, self).__init__(parent=parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self._wheel_tweaks = True
|
self._wheel_tweaks = True
|
||||||
self._auto_labels = True
|
self._auto_labels = True
|
||||||
self._locked = False
|
self._locked = False
|
||||||
self._label_style = 'basic'
|
self._label_style = 'basic'
|
||||||
self._templates_source = {
|
self._templates_source = {
|
||||||
'basic': '<b>{short_name}</b> <font color="#080">{{rbv:.{precision}f}} {units}</font>',
|
'basic': '<b>{short_name}</b> <font color="#080">{{rbv:.{precision}f}} {units}</font>',
|
||||||
'small': '<small>{short_name} <font size="small" color="#080">{{rbv:.{precision}f}} {units}</font><small>',
|
'small': '<small>{short_name} <font size="small" color="#080">{{rbv:.{precision}f}} {units}</font><small>',
|
||||||
'2 lines': '<b>{short_name}</b><br><font size="small" color="#080">{{rbv:.{precision}f}} {units}</font>',
|
'2 lines': '<b>{short_name}</b><br><font size="small" color="#080">{{rbv:.{precision}f}} {units}</font>',
|
||||||
'busy': '<b>{short_name}</b> <font color="#080">{{rbv:.{precision}f}} {units}</font>'
|
'busy': '<b>{short_name}</b> <font color="#080">{{rbv:.{precision}f}} {units}</font>'
|
||||||
}
|
}
|
||||||
self._templates = {}
|
self._templates = {}
|
||||||
|
|
||||||
|
|
||||||
def connect_motor(self, motor_base, short_name=None, **kwargs):
|
def connect_motor(self, motor_base, short_name=None, **kwargs):
|
||||||
m = Motor(motor_base)
|
m = Motor(motor_base)
|
||||||
m.get_position()
|
m.get_position()
|
||||||
self._ignore_limits = m.HLM == m.LLM # if both high/low limits are equal they are meaningless
|
self._ignore_limits = m.HLM == m.LLM # if both high/low limits are equal they are meaningless
|
||||||
self.motor = m
|
self.motor = m
|
||||||
if not short_name:
|
if not short_name:
|
||||||
short_name = m.description
|
short_name = m.description
|
||||||
self.short_name = short_name
|
self.short_name = short_name
|
||||||
self._pvname = motor_base
|
self._pvname = motor_base
|
||||||
|
|
||||||
for attr in ['RTYP', 'JVEL', 'HLS', 'LLS', 'TWV', 'RBV', 'VAL', 'LVIO', 'HLM', 'LLM']:
|
for attr in ['RTYP', 'JVEL', 'HLS', 'LLS', 'TWV', 'RBV', 'VAL', 'LVIO', 'HLM', 'LLM']:
|
||||||
# logger.debug('connecting to field {}'.format(attr))
|
# _log.debug('connecting to field {}'.format(attr))
|
||||||
m.PV(attr, connect=True)
|
m.PV(attr, connect=True)
|
||||||
|
|
||||||
self.set_motor_validator()
|
self.set_motor_validator()
|
||||||
self._drive_val.setText(m.get('VAL', as_string=True))
|
self._drive_val.setText(m.get('VAL', as_string=True))
|
||||||
self._drive_val.returnPressed.connect(self.move_motor_to_position)
|
self._drive_val.returnPressed.connect(self.move_motor_to_position)
|
||||||
|
|
||||||
tweak_min = kwargs.get("tweak_min", 0.0001)
|
tweak_min = kwargs.get("tweak_min", 0.0001)
|
||||||
tweak_max = kwargs.get("tweak_max", 10.0)
|
tweak_max = kwargs.get("tweak_max", 10.0)
|
||||||
self._tweak_val.setText(m.get('TWV', as_string=True))
|
self._tweak_val.setText(m.get('TWV', as_string=True))
|
||||||
self._tweak_val.setValidator(QDoubleValidator(tweak_min, tweak_max, 4, self._tweak_val))
|
self._tweak_val.setValidator(QDoubleValidator(tweak_min, tweak_max, 4, self._tweak_val))
|
||||||
self._tweak_val.editingFinished.connect(lambda m=m: m.PV('TWV').put(self._tweak_val.text()))
|
self._tweak_val.editingFinished.connect(lambda m=m: m.PV('TWV').put(self._tweak_val.text()))
|
||||||
|
|
||||||
self.jog_reverse.hide()
|
self.jog_reverse.hide()
|
||||||
self.jog_forward.hide()
|
self.jog_forward.hide()
|
||||||
# self.jog_forward.pressed.connect(lambda: self.jog('forward', True))
|
# self.jog_forward.pressed.connect(lambda: self.jog('forward', True))
|
||||||
# self.jog_reverse.pressed.connect(lambda: self.jog('reverse', True))
|
# self.jog_reverse.pressed.connect(lambda: self.jog('reverse', True))
|
||||||
# self.jog_forward.released.connect(lambda: self.jog('forward', False))
|
# self.jog_forward.released.connect(lambda: self.jog('forward', False))
|
||||||
# self.jog_reverse.released.connect(lambda: self.jog('reverse', False))
|
# self.jog_reverse.released.connect(lambda: self.jog('reverse', False))
|
||||||
|
|
||||||
self.tweak_forward.clicked.connect(lambda m: self.motor.tweak('forward'))
|
self.tweak_forward.clicked.connect(lambda m: self.motor.tweak('forward'))
|
||||||
self.tweak_reverse.clicked.connect(lambda m: self.motor.tweak('reverse'))
|
self.tweak_reverse.clicked.connect(lambda m: self.motor.tweak('reverse'))
|
||||||
|
|
||||||
self.bind_wheel()
|
self.bind_wheel()
|
||||||
|
|
||||||
self.update_label_template()
|
self.update_label_template()
|
||||||
m.add_callback('VAL', self.set_val)
|
m.add_callback('VAL', self.set_val)
|
||||||
m.add_callback('RBV', self.update_label)
|
m.add_callback('RBV', self.update_label)
|
||||||
m.set_callback('HLS', self.update_label)
|
m.set_callback('HLS', self.update_label)
|
||||||
m.set_callback('LLS', self.update_label)
|
m.set_callback('LLS', self.update_label)
|
||||||
|
|
||||||
m.set_callback('VAL', self.emit_signals, {'source_field': 'VAL'})
|
m.set_callback('VAL', self.emit_signals, {'source_field': 'VAL'})
|
||||||
m.set_callback('RBV', self.emit_signals, {'source_field': 'RBV'})
|
m.set_callback('RBV', self.emit_signals, {'source_field': 'RBV'})
|
||||||
m.set_callback('HLS', self.emit_signals, {'source_field': 'HLS'})
|
m.set_callback('HLS', self.emit_signals, {'source_field': 'HLS'})
|
||||||
m.set_callback('LLS', self.emit_signals, {'source_field': 'LLS'})
|
m.set_callback('LLS', self.emit_signals, {'source_field': 'LLS'})
|
||||||
m.set_callback('LVIO', self.emit_signals, {'source_field': 'LVIO'})
|
m.set_callback('LVIO', self.emit_signals, {'source_field': 'LVIO'})
|
||||||
m.set_callback('STAT', self.emit_signals, {'source_field': 'STAT'})
|
m.set_callback('STAT', self.emit_signals, {'source_field': 'STAT'})
|
||||||
|
|
||||||
m.set_callback('HLM', self.set_motor_validator)
|
m.set_callback('HLM', self.set_motor_validator)
|
||||||
|
|
||||||
|
|
||||||
def set_val(self, **kw):
|
def set_val(self, **kw):
|
||||||
v = kw['char_value']
|
v = kw['char_value']
|
||||||
logger.debug('updating VAL = {}'.format(v))
|
_log.debug('updating VAL = {}'.format(v))
|
||||||
self._drive_val.setText(v)
|
self._drive_val.setText(v)
|
||||||
|
|
||||||
|
|
||||||
def set_motor_validator(self, **kwargs):
|
def set_motor_validator(self, **kwargs):
|
||||||
m = self.motor
|
m = self.motor
|
||||||
lineedit = self._drive_val
|
lineedit = self._drive_val
|
||||||
min, max = m.PV('LLM').get(), m.PV('HLM').get()
|
min, max = m.PV('LLM').get(), m.PV('HLM').get()
|
||||||
if min == max:
|
if min == max:
|
||||||
min = -1e6
|
min = -1e6
|
||||||
max = 1e6
|
max = 1e6
|
||||||
lineedit.setValidator(QDoubleValidator(min, max, m.PV('PREC').get(), lineedit))
|
lineedit.setValidator(QDoubleValidator(min, max, m.PV('PREC').get(), lineedit))
|
||||||
|
|
||||||
|
|
||||||
def move_relative(self, dist):
|
def move_relative(self, dist):
|
||||||
self.motor.move(dist, ignore_limits=True, relative=True)
|
self.motor.move(dist, ignore_limits=True, relative=True)
|
||||||
|
|
||||||
def is_done(self):
|
def is_done(self):
|
||||||
self.motor.refresh()
|
self.motor.refresh()
|
||||||
return 1 == self.motor.done_moving
|
return 1 == self.motor.done_moving
|
||||||
|
|
||||||
def get_position(self):
|
def get_position(self):
|
||||||
return self.motor.get_position(readback=True)
|
return self.motor.get_position(readback=True)
|
||||||
|
|
||||||
def is_homed(self):
|
def is_homed(self):
|
||||||
self.motor.refresh()
|
self.motor.refresh()
|
||||||
status = DeltatauMotorStatus(self.motor.motor_status)
|
status = DeltatauMotorStatus(self.motor.motor_status)
|
||||||
return bool(DeltatauMotorStatus.MOTOR_HAS_BEEN_HOMED & status)
|
return bool(DeltatauMotorStatus.MOTOR_HAS_BEEN_HOMED & status)
|
||||||
|
|
||||||
def move_motor_to_position(self, drive=None, wait=False, assert_position=False):
|
def move_motor_to_position(self, drive=None, wait=False, assert_position=False):
|
||||||
if drive is None:
|
if drive is None:
|
||||||
drive = float(self._drive_val.text())
|
drive = float(self._drive_val.text())
|
||||||
if assert_position:
|
if assert_position:
|
||||||
wait=True
|
wait=True
|
||||||
self.motor.move(drive, wait=wait, ignore_limits=True, relative=False)
|
self.motor.move(drive, wait=wait, ignore_limits=True, relative=False)
|
||||||
if assert_position:
|
if assert_position:
|
||||||
assert_motor_positions([(self.motor, drive, 0.1)], timeout=1)
|
assert_motor_positions([(self.motor, drive, 0.1)], timeout=1)
|
||||||
|
|
||||||
def emit_signals(self, **kw):
|
def emit_signals(self, **kw):
|
||||||
'''
|
'''
|
||||||
:param kw: info about the channel {
|
:param kw: info about the channel {
|
||||||
'access': 'read-only',
|
'access': 'read-only',
|
||||||
'char_value': '-0.105',
|
'char_value': '-0.105',
|
||||||
'chid': 36984304,
|
'chid': 36984304,
|
||||||
'count': 1,
|
'count': 1,
|
||||||
'enum_strs': None,
|
'enum_strs': None,
|
||||||
'ftype': 20,
|
'ftype': 20,
|
||||||
'host': 'SAR-CPPM-EXPMX1.psi.ch:5064',
|
'host': 'SAR-CPPM-EXPMX1.psi.ch:5064',
|
||||||
'lower_alarm_limit': None,
|
'lower_alarm_limit': None,
|
||||||
'lower_ctrl_limit': 0.0,
|
'lower_ctrl_limit': 0.0,
|
||||||
'lower_disp_limit': 0.0,
|
'lower_disp_limit': 0.0,
|
||||||
'lower_warning_limit': None,
|
'lower_warning_limit': None,
|
||||||
'motor_field': 'RBV',
|
'motor_field': 'RBV',
|
||||||
'nelm': 1,
|
'nelm': 1,
|
||||||
'precision': 3,
|
'precision': 3,
|
||||||
'pvname': 'SAR-EXPMX:MOT_ROT_Y.RBV',
|
'pvname': 'SAR-EXPMX:MOT_ROT_Y.RBV',
|
||||||
'read_access': True,
|
'read_access': True,
|
||||||
'severity': 0,
|
'severity': 0,
|
||||||
'source_field': 'RBV',
|
'source_field': 'RBV',
|
||||||
'status': 0,
|
'status': 0,
|
||||||
'timestamp': 1522314072.878331,
|
'timestamp': 1522314072.878331,
|
||||||
'type': 'time_double',
|
'type': 'time_double',
|
||||||
'typefull': 'time_double',
|
'typefull': 'time_double',
|
||||||
'units': b'deg',
|
'units': b'deg',
|
||||||
'upper_alarm_limit': None,
|
'upper_alarm_limit': None,
|
||||||
'upper_ctrl_limit': 0.0,
|
'upper_ctrl_limit': 0.0,
|
||||||
'upper_disp_limit': 0.0,
|
'upper_disp_limit': 0.0,
|
||||||
'upper_warning_limit': None,
|
'upper_warning_limit': None,
|
||||||
'value': -0.105,
|
'value': -0.105,
|
||||||
'write_access': False}
|
'write_access': False}
|
||||||
|
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
field = kw['motor_field']
|
field = kw['motor_field']
|
||||||
src = kw['source_field']
|
src = kw['source_field']
|
||||||
kw['alias'] = self.short_name
|
kw['alias'] = self.short_name
|
||||||
if field != src:
|
if field != src:
|
||||||
return
|
return
|
||||||
if field == 'VAL':
|
if field == 'VAL':
|
||||||
self.event_val.emit(self._pvname, kw)
|
self.event_val.emit(self._pvname, kw)
|
||||||
elif field == 'RBV':
|
elif field == 'RBV':
|
||||||
self.event_readback.emit(kw['alias'], kw['value'], kw)
|
self.event_readback.emit(kw['alias'], kw['value'], kw)
|
||||||
elif field == 'LVIO':
|
elif field == 'LVIO':
|
||||||
self.event_soft_limit.emit(self._pvname, kw)
|
self.event_soft_limit.emit(self._pvname, kw)
|
||||||
elif field == 'HLS':
|
elif field == 'HLS':
|
||||||
self.event_high_hard_limit.emit(self._pvname, kw)
|
self.event_high_hard_limit.emit(self._pvname, kw)
|
||||||
self.event_axis_fault.emit(self._pvname, kw)
|
self.event_axis_fault.emit(self._pvname, kw)
|
||||||
elif field == 'LVIO':
|
elif field == 'LVIO':
|
||||||
self.event_low_hard_limit.emit(self._pvname, kw)
|
self.event_low_hard_limit.emit(self._pvname, kw)
|
||||||
self.event_axis_fault.emit(self._pvname, kw)
|
self.event_axis_fault.emit(self._pvname, kw)
|
||||||
elif field == 'STAT':
|
elif field == 'STAT':
|
||||||
self.event_axis_fault.emit(self._pvname, kw)
|
self.event_axis_fault.emit(self._pvname, kw)
|
||||||
|
|
||||||
def update_label(self, **kwargs):
|
def update_label(self, **kwargs):
|
||||||
m = self.motor
|
m = self.motor
|
||||||
self.label.setText(self._templates[self._label_style].format(rbv=m.readback))
|
self.label.setText(self._templates[self._label_style].format(rbv=m.readback))
|
||||||
self.jog_forward.setToolTip('jog forward at {:.3f} {}/s'.format(m.jog_speed, m.units))
|
self.jog_forward.setToolTip('jog forward at {:.3f} {}/s'.format(m.jog_speed, m.units))
|
||||||
self.jog_reverse.setToolTip('jog reverse at {:.3f} {}/s'.format(m.jog_speed, m.units))
|
self.jog_reverse.setToolTip('jog reverse at {:.3f} {}/s'.format(m.jog_speed, m.units))
|
||||||
self.tweak_forward.setToolTip('tweak forward by {:.3f} {}'.format(m.tweak_val, m.units))
|
self.tweak_forward.setToolTip('tweak forward by {:.3f} {}'.format(m.tweak_val, m.units))
|
||||||
self.tweak_reverse.setToolTip('tweak reverse by {:.3f} {}'.format(m.tweak_val, m.units))
|
self.tweak_reverse.setToolTip('tweak reverse by {:.3f} {}'.format(m.tweak_val, m.units))
|
||||||
|
|
||||||
def update_jog_speed(self, event):
|
def update_jog_speed(self, event):
|
||||||
m = self.motor
|
m = self.motor
|
||||||
speed = m.jog_speed
|
speed = m.jog_speed
|
||||||
sign = math.copysign(1, event.angleDelta().y())
|
sign = math.copysign(1, event.angleDelta().y())
|
||||||
m.jog_speed = speed + (sign * 0.1 * speed)
|
m.jog_speed = speed + (sign * 0.1 * speed)
|
||||||
self.jog_forward.setToolTip('jog forward at {:.3f} {}/s'.format(m.jog_speed, m.units))
|
self.jog_forward.setToolTip('jog forward at {:.3f} {}/s'.format(m.jog_speed, m.units))
|
||||||
self.jog_reverse.setToolTip('jog reverse at {:.3f} {}/s'.format(m.jog_speed, m.units))
|
self.jog_reverse.setToolTip('jog reverse at {:.3f} {}/s'.format(m.jog_speed, m.units))
|
||||||
|
|
||||||
def tweak_event(self, event):
|
def tweak_event(self, event):
|
||||||
m = self.motor
|
m = self.motor
|
||||||
sign = event.angleDelta().y()
|
sign = event.angleDelta().y()
|
||||||
if sign < 0:
|
if sign < 0:
|
||||||
m.tweak_reverse = 1
|
m.tweak_reverse = 1
|
||||||
else:
|
else:
|
||||||
m.tweak_forward = 1
|
m.tweak_forward = 1
|
||||||
|
|
||||||
def bind_wheel(self):
|
def bind_wheel(self):
|
||||||
self.tweak_forward.wheelEvent = self.tweak_event
|
self.tweak_forward.wheelEvent = self.tweak_event
|
||||||
self.tweak_reverse.wheelEvent = self.tweak_event
|
self.tweak_reverse.wheelEvent = self.tweak_event
|
||||||
|
|
||||||
def jog(self, direction, enable):
|
def jog(self, direction, enable):
|
||||||
m = self.motor
|
m = self.motor
|
||||||
if 'forw' in direction:
|
if 'forw' in direction:
|
||||||
m.jog_forward = int(enable)
|
m.jog_forward = int(enable)
|
||||||
else:
|
else:
|
||||||
m.jog_reverse = int(enable)
|
m.jog_reverse = int(enable)
|
||||||
|
|
||||||
def contextMenuEvent(self, event):
|
def contextMenuEvent(self, event):
|
||||||
m = self.motor
|
m = self.motor
|
||||||
menu = QMenu(self)
|
menu = QMenu(self)
|
||||||
menu.setTitle(self.short_name)
|
menu.setTitle(self.short_name)
|
||||||
|
|
||||||
lockmotor = QAction('lock motor', menu, checkable=True)
|
lockmotor = QAction('lock motor', menu, checkable=True)
|
||||||
lockmotor.setChecked(self._locked)
|
lockmotor.setChecked(self._locked)
|
||||||
menu.addAction(lockmotor)
|
menu.addAction(lockmotor)
|
||||||
|
|
||||||
autolabelsAction = QAction('auto', menu, checkable=True)
|
autolabelsAction = QAction('auto', menu, checkable=True)
|
||||||
autolabelsAction.setChecked(self._auto_labels)
|
autolabelsAction.setChecked(self._auto_labels)
|
||||||
menu.addAction(autolabelsAction)
|
menu.addAction(autolabelsAction)
|
||||||
|
|
||||||
wheel_tweaks = QAction('Mouse wheel tweaks motor', menu, checkable=True)
|
wheel_tweaks = QAction('Mouse wheel tweaks motor', menu, checkable=True)
|
||||||
wheel_tweaks.setChecked(self._wheel_tweaks)
|
wheel_tweaks.setChecked(self._wheel_tweaks)
|
||||||
menu.addAction(wheel_tweaks)
|
menu.addAction(wheel_tweaks)
|
||||||
|
|
||||||
stopmotorAction = QAction('Stopped', menu, checkable=True)
|
stopmotorAction = QAction('Stopped', menu, checkable=True)
|
||||||
stopmotorAction.setChecked(SPMG_STOP == m.stop_go)
|
stopmotorAction.setChecked(SPMG_STOP == m.stop_go)
|
||||||
menu.addAction(stopmotorAction)
|
menu.addAction(stopmotorAction)
|
||||||
changeprecAction = menu.addAction("Change Precision")
|
changeprecAction = menu.addAction("Change Precision")
|
||||||
changejogspeedAction = menu.addAction("Jog speed {:.3f} {}/s".format(m.jog_speed, m.units))
|
changejogspeedAction = menu.addAction("Jog speed {:.3f} {}/s".format(m.jog_speed, m.units))
|
||||||
changetweakstepAction = menu.addAction("Tweak step {:.3f} {}".format(m.tweak_val, m.units))
|
changetweakstepAction = menu.addAction("Tweak step {:.3f} {}".format(m.tweak_val, m.units))
|
||||||
|
|
||||||
tozeroAction = menu.addAction("move to Zero")
|
tozeroAction = menu.addAction("move to Zero")
|
||||||
|
|
||||||
|
|
||||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||||
if action == lockmotor:
|
if action == lockmotor:
|
||||||
self._locked = not self._locked
|
self._locked = not self._locked
|
||||||
if self._locked:
|
if self._locked:
|
||||||
self._controlbox.setDisabled(True)
|
self._controlbox.setDisabled(True)
|
||||||
else:
|
else:
|
||||||
self._controlbox.setDisabled(False)
|
self._controlbox.setDisabled(False)
|
||||||
elif action == changeprecAction:
|
elif action == changeprecAction:
|
||||||
name = m.NAME
|
name = m.NAME
|
||||||
prec = m.PREC
|
prec = m.PREC
|
||||||
msg = 'Precision for motor {}'.format(name)
|
msg = 'Precision for motor {}'.format(name)
|
||||||
logger.debug('prec before %d', prec)
|
_log.debug('prec before %d', prec)
|
||||||
prec, ok = QInputDialog.getInt(self, msg, msg, prec, 0, 10)
|
prec, ok = QInputDialog.getInt(self, msg, msg, prec, 0, 10)
|
||||||
logger.debug('prec after (%d) %d', ok, prec)
|
_log.debug('prec after (%d) %d', ok, prec)
|
||||||
if ok:
|
if ok:
|
||||||
self.motor.put('PREC', prec, wait=True)
|
self.motor.put('PREC', prec, wait=True)
|
||||||
|
|
||||||
elif action == changejogspeedAction:
|
elif action == changejogspeedAction:
|
||||||
name = m.NAME
|
name = m.NAME
|
||||||
speed = m.jog_speed
|
speed = m.jog_speed
|
||||||
msg = 'Jog speed for motor {}'.format(name)
|
msg = 'Jog speed for motor {}'.format(name)
|
||||||
speed, ok = QInputDialog.getDouble(self, msg, msg, speed, 0.01, m.slew_speed, m.precision)
|
speed, ok = QInputDialog.getDouble(self, msg, msg, speed, 0.01, m.slew_speed, m.precision)
|
||||||
if ok:
|
if ok:
|
||||||
self.motor.put('JVEL', speed, wait=True)
|
self.motor.put('JVEL', speed, wait=True)
|
||||||
|
|
||||||
elif action == changetweakstepAction:
|
elif action == changetweakstepAction:
|
||||||
name = m.NAME
|
name = m.NAME
|
||||||
tv = m.tweak_val
|
tv = m.tweak_val
|
||||||
msg = 'Tweak step for motor {} at {} {}'.format(name, tv, m.units)
|
msg = 'Tweak step for motor {} at {} {}'.format(name, tv, m.units)
|
||||||
tv, ok = QInputDialog.getDouble(self, msg, msg, tv, pow(10, -m.precision), m.slew_speed, m.precision)
|
tv, ok = QInputDialog.getDouble(self, msg, msg, tv, pow(10, -m.precision), m.slew_speed, m.precision)
|
||||||
if ok:
|
if ok:
|
||||||
self.motor.put('TWV', tv, wait=True)
|
self.motor.put('TWV', tv, wait=True)
|
||||||
|
|
||||||
elif action == tozeroAction:
|
elif action == tozeroAction:
|
||||||
m.move(0.0, ignore_limits=True)
|
m.move(0.0, ignore_limits=True)
|
||||||
|
|
||||||
elif action == stopmotorAction:
|
elif action == stopmotorAction:
|
||||||
self.motor.stop_go = SPMG_STOP if m.stop_go == SPMG_GO else SPMG_GO
|
self.motor.stop_go = SPMG_STOP if m.stop_go == SPMG_GO else SPMG_GO
|
||||||
|
|
||||||
elif action == autolabelsAction:
|
elif action == autolabelsAction:
|
||||||
self._auto_labels = not self._auto_labels
|
self._auto_labels = not self._auto_labels
|
||||||
|
|
||||||
elif action == wheel_tweaks:
|
elif action == wheel_tweaks:
|
||||||
self._wheel_tweaks = not self._wheel_tweaks
|
self._wheel_tweaks = not self._wheel_tweaks
|
||||||
self.bind_wheel()
|
self.bind_wheel()
|
||||||
|
|
||||||
self.update_label_template()
|
self.update_label_template()
|
||||||
|
|
||||||
def resizeEvent(self, event):
|
def resizeEvent(self, event):
|
||||||
return # FIXME disable for the time being
|
return # FIXME disable for the time being
|
||||||
if not self._auto_labels:
|
if not self._auto_labels:
|
||||||
return
|
return
|
||||||
|
|
||||||
w, h = event.size().width(), event.size().height()
|
w, h = event.size().width(), event.size().height()
|
||||||
if w < 400:
|
if w < 400:
|
||||||
self.jog_reverse.hide()
|
self.jog_reverse.hide()
|
||||||
self.jog_forward.hide()
|
self.jog_forward.hide()
|
||||||
else:
|
else:
|
||||||
self.jog_reverse.show()
|
self.jog_reverse.show()
|
||||||
self.jog_forward.show()
|
self.jog_forward.show()
|
||||||
self.update_label()
|
self.update_label()
|
||||||
|
|
||||||
def update_label_template(self):
|
def update_label_template(self):
|
||||||
m = self.motor
|
m = self.motor
|
||||||
source = self._templates_source
|
source = self._templates_source
|
||||||
target = self._templates
|
target = self._templates
|
||||||
|
|
||||||
for k in source:
|
for k in source:
|
||||||
target[k] = source[k].format(
|
target[k] = source[k].format(
|
||||||
short_name=self.short_name,
|
short_name=self.short_name,
|
||||||
precision=m.PREC,
|
precision=m.PREC,
|
||||||
units=m.units)
|
units=m.units)
|
||||||
self.label.setText(target[self._label_style].format(rbv=m.readback))
|
self.label.setText(target[self._label_style].format(rbv=m.readback))
|
||||||
|
|
||||||
def paintEvent(self, e):
|
def paintEvent(self, e):
|
||||||
qp = QPainter()
|
qp = QPainter()
|
||||||
qp.begin(self)
|
qp.begin(self)
|
||||||
qp.setRenderHint(QPainter.Antialiasing)
|
qp.setRenderHint(QPainter.Antialiasing)
|
||||||
self._draw_limits(qp)
|
self._draw_limits(qp)
|
||||||
qp.end()
|
qp.end()
|
||||||
|
|
||||||
def _draw_limits(self, qp):
|
def _draw_limits(self, qp):
|
||||||
m = self.motor
|
try:
|
||||||
width, height = self.size().width(), self.size().height()
|
m = self.motor
|
||||||
pad = 5
|
except AttributeError:
|
||||||
rounding = 2
|
_log.warning('Motor not connected')
|
||||||
size = 10
|
return
|
||||||
if m.HLS:
|
width, height = self.size().width(), self.size().height()
|
||||||
x, y, w, h = width - size, pad, size, height - 2 * pad
|
pad = 5
|
||||||
elif m.LLS:
|
rounding = 2
|
||||||
x, y, w, h = 0, pad, size, height - 2 * pad
|
size = 10
|
||||||
else:
|
if m.HLS:
|
||||||
return
|
x, y, w, h = width - size, pad, size, height - 2 * pad
|
||||||
color = QColor('indianred')
|
elif m.LLS:
|
||||||
qp.setBrush(QBrush(color, Qt.SolidPattern))
|
x, y, w, h = 0, pad, size, height - 2 * pad
|
||||||
qp.setPen(QPen(color))
|
else:
|
||||||
path = QPainterPath()
|
return
|
||||||
path.setFillRule(Qt.WindingFill)
|
color = QColor('indianred')
|
||||||
path.addRoundedRect(x, y, w, h, rounding, rounding)
|
qp.setBrush(QBrush(color, Qt.SolidPattern))
|
||||||
qp.drawPath(path)
|
qp.setPen(QPen(color))
|
||||||
|
path = QPainterPath()
|
||||||
|
path.setFillRule(Qt.WindingFill)
|
||||||
|
path.addRoundedRect(x, y, w, h, rounding, rounding)
|
||||||
|
qp.drawPath(path)
|
||||||
|
|||||||
5960
swissmx.py
5960
swissmx.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user