Files
bdbase/guiframe.py
2022-01-10 13:15:41 +01:00

1212 lines
49 KiB
Python

""" Base frame
"""
from datetime import datetime
import inspect
import os
import random
import re
from matplotlib.backends.backend_qt5agg import (
FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar)
from qtpy.QtCore import QSize, Qt
from qtpy.QtGui import QColor, QFont, QFontMetricsF, QIcon, QIntValidator, QPainter, QPixmap
from qtpy.QtWidgets import (QApplication, QCheckBox, QComboBox, QFrame, QGridLayout, QGroupBox,
QHBoxLayout, QLabel, QLineEdit, QMessageBox,
QPushButton, QRadioButton, QSpacerItem, QSpinBox, QStackedWidget, QStatusBar,
QTabWidget, QToolButton, QVBoxLayout, QWidget)
from caqtwidgets.pvwidgets import (CAQDoubleSpinBox, CAQLabel, CAQLineEdit,
CAQMenu, CAQMessageButton, CAQSpinBox,
CAQTableWidget, CAQTextEntry, QMessageWidget,
QHLine, QVLine, QResultsWidget)
from pyqtacc.bdbase.enumkind import Facility, MsgSeverity, UserMode
_pymodule = os.path.basename(__file__)
_appversion = "1.0.0"
INPUT_PARAMETERS_HEIGHT = 600
EXPERT_PARAMETERS_HEIGHT = 240
def _line():
"""Macro to return the current line number.
The current line number within the file is used when
reporting messages to the message logging window.
Returns:
int: Current line number.
"""
return inspect.currentframe().f_back.f_lineno
class GUIFrame(QWidget):
""" GUI Class
"""
def __init__(self, parent, appname):
super(GUIFrame, self).__init__()
self.parent = parent
self.appname = parent.appname
self.facility = parent.facility
self.settings = parent.settings
self.cafe = parent.cafe
self.cyca = parent.cyca
self.input_parameters = parent.input_parameters
self.input_labels = parent.input_labels
self.expert_parameters = parent.expert_parameters
self.expert_labels = parent.expert_labels
try:
self.widget_height = self.settings.data["StyleGuide"]["widgetHeight"]
except KeyError as error:
print("KeyError in guiframe.py, init:", error)
self.widget_height = 25
self.autopost_elog = True
try:
self.autopost_epics = self.settings.data["menuFlags"]["hasEpics"]
except KeyError as error:
print("KeyError in guiframe.py, init:", error)
self.autopost_epics = True
try:
self.autopost_hdf = self.settings.data["menuFlags"]["hasH5"]
except KeyError as error:
print("KeyError in guiframe.py, init:", error)
self.autopost_hdf = True
self.expert_parameters_group = None
self.operator_parameters_group = None
self.energy_stacked_widget = None
self.phase_stacked_widget = None
self.multiple_figure_dict = None
self.line_sender_dict = {}
self.msg_severity_qcolor = parent.msg_severity_qcolor
self.msg_severity = MsgSeverity
self.font_gui = QFont("sans serif")
self.font_gui.setPointSize(11)
self.font_pts10 = QFont("sans serif")
self.font_pts10.setPointSize(10)
self.central_tab_widget = QTabWidget()
self.measurement_wgt = QWidget()
self.measurement_layout = QHBoxLayout(self.measurement_wgt)
self.measurement_tab_wgt = QTabWidget(self.measurement_wgt)
self.operator_wgt = QWidget(self.measurement_tab_wgt)
self.expert_wgt = QWidget(self.measurement_tab_wgt)
self.results_wgt = QWidget()
self.results_layout = QHBoxLayout(self.results_wgt)
self.results_tab_wgt = QTabWidget(self.results_wgt)
self.results_tab_wgt_titles = self.settings.data[
"GUI"]["subResultsTabTitle"]
self.sub_results_wgt = [None] * len(self.results_tab_wgt_titles)
self.sub_results_layout = [None] * len(self.results_tab_wgt_titles)
for i in range(0, len(self.results_tab_wgt_titles)):
self.sub_results_wgt[i] = QWidget(self.results_tab_wgt)
#self.plots_wgt = QWidget(self.results_tab_wgt)
#self.table_wgt = QWidget(self.results_tab_wgt)
self.canvas = [None] * len(self.results_tab_wgt_titles)
self.nav = [None] * len(self.results_tab_wgt_titles)
self.arrow_button_widget = [None] * len(self.results_tab_wgt_titles)
self.canvas_current_idx = [0] * len(self.results_tab_wgt_titles)
self.canvas_fig_dict = {}
self.left_arrow_dict = {}
self.right_arrow_dict = {}
self.analysis_wgt = QWidget()
self.abort_wgt = QWidget()
self.start_wgt = QWidget()
self.start_wgt_text = "Start"
self.save_all_wgt = QWidget()
self.init_measurement_tab_wgt()
self.init_results_tab_wgt()
#self.results_wgt = QWidget()
#self.results_layout = QVBoxLayout()
#self.results_layout.addWidget(self.results_wgt)
self.log_wgt = QMessageWidget()
self.log_layout = QVBoxLayout(self.log_wgt)
self.show_log_message(MsgSeverity.INFO, _pymodule, _line(),
"Application started")
self.input_wgt_grid = QGridLayout()
self.input_wgt_grid.setHorizontalSpacing(0)
self.input_wgt_grid.setVerticalSpacing(2)
self.expert_wgt_grid = QGridLayout()
self.expert_wgt_grid.setHorizontalSpacing(0)
self.expert_wgt_grid.setVerticalSpacing(2)
self.init_central_tab_widget()
self.enter_input_parameters()
def init_central_tab_widget(self):
self.central_tab_widget.setFont(self.font_gui)
self.central_tab_widget.addTab(self.measurement_wgt, "Measurement")
self.central_tab_widget.addTab(
self.results_wgt, self.settings.data["GUI"]["resultsTabTitle"])
self.central_tab_widget.addTab(self.log_wgt, "Log")
def init_measurement_tab_wgt(self):
self.measurement_tab_wgt.setFont(self.font_gui)
self.measurement_tab_wgt.addTab(self.operator_wgt, "Operator")
self.measurement_tab_wgt.addTab(self.expert_wgt, "Expert")
self.measurement_layout.addWidget(self.measurement_tab_wgt)
'''
def init_results_tab_wgt_(self):
self.results_tab_wgt.setFont(self.font_gui)
#self.results_tab_wgt.addTab(self.plots_wgt, "Plots")
#self.results_tab_wgt.addTab(self.table_wgt, "Tables")
for wgt, subtitle in zip(self.sub_results_wgt,
self.results_tab_wgt_titles):
self.results_tab_wgt.addTab (wgt, subtitle)
self.results_layout.addWidget(self.results_tab_wgt)
'''
def init_results_tab_wgt(self):
self.results_tab_wgt.setFont(self.font_gui)
#self.results_tab_wgt.addTab(self.plots_wgt, "Plots")
#self.results_tab_wgt.addTab(self.table_wgt, "Tables")
for i, (wgt, subtitle) in enumerate(zip(self.sub_results_wgt,
self.results_tab_wgt_titles)):
top_widget = QWidget(self.results_tab_wgt)
top_layout = QVBoxLayout()
self.sub_results_layout[i] = QVBoxLayout()
if self.settings.data["GUI"]["resultsSeq"][i] > 1:
top_layout.addWidget(self.get_arrow_button_widget(i))
#else:
# top_layout.addWidget(QFrame())
wgt.setLayout(self.sub_results_layout[i])
top_layout.addWidget(wgt)
#self.sub_results_layout[i].setAlignment(Qt.AlignTop)
top_widget.setLayout(top_layout) #self.sub_results_layout[i])
self.results_tab_wgt.addTab (top_widget, subtitle)
self.results_layout.addWidget(self.results_tab_wgt)
def show_log_message(self, severity=None, pymodule="", lineno=0,
message="", options={}):
source = "{0}:{1:d} ".format(pymodule, lineno)
message_to_send = datetime.utcnow().strftime(
'%Y-%m-%d %H:%M:%S.%f')[:-5]
message_to_send += " "
if (isinstance(severity, self.msg_severity)):
message_to_send += severity.name
elif (severity in self.msg_severity_qcolor.keys()):
message_to_send += str(severity)
elif (str(severity) == "WARNING"):
message_to_send += "WARN"
message_to_send += (" {" + source + message + "} ")
if options:
message_to_send += "\n"
for k, v in options.items():
message_to_send += (" [" + str(k) + ": " + str(v) + "]")
self.log_wgt.insertItem(0, message_to_send)
self.log_wgt.item(0).setFlags(
Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled |
Qt.NoItemFlags)
self.log_wgt.item(0).setForeground(
self.msg_severity_qcolor.get(severity, QColor(8, 8, 8)))
#Top level groups
def analysis_procedure_group(
self, start_title="Start", start_action=None,
start_tooltip="Start measurement and analysis procedure",
abort_title="Abort", abort_action=None,
abort_tooltip="Abort procedure at next break point"):
group_box = QGroupBox("Procedure")
group_box.setObjectName("OUTER")
hbox = QVBoxLayout()
hbox.addWidget(self.create_analysis_wgt())
hbox.setContentsMargins(9, 9, 9, 9)
hbox.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
group_box.setContentsMargins(0, 0, 0, 0)
group_box.setMaximumWidth(208)
#group_box.setMaximumHeight(130)
group_box.setFont(self.font_gui)
group_box.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
group_box.setLayout(hbox)
return group_box
def input_parameters_group(self, title="Input Parameters"):
group_box = QGroupBox(title)
group_box.setObjectName("OUTER")
hbox = QVBoxLayout()
hbox.setContentsMargins(9, 19, 9, 9)
hbox.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
group_box.setContentsMargins(0, 0, 0, 0)
group_box.setFixedWidth(250)
group_box.setMaximumHeight(400)
group_box.setFont(self.font_gui)
group_box.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
group_box.setLayout(hbox)
return group_box
def operator_parameters_groupbox(self, title="Input Parameters"):
self.operator_parameters_group = self.input_parameters_group(title)
return self.operator_parameters_group
def expert_parameters_groupbox(self, title="Expert Parameters"):
self.expert_parameters_group = self.input_parameters_group(title)
return self.expert_parameters_group
def create_analysis_wgt(
self, start_title="Start", start_action=None,
start_tooltip="Start measurement and analysis procedure",
abort_title="Abort", abort_action=None,
abort_tooltip="Abort procedure at next break point"):
self.start_wgt = self.create_start_wgt(start_title,
self.parent.start_analysis_thread,
start_tooltip)
self.abort_wgt = self.create_abort_wgt(abort_title,
self.parent.receive_abort_analysis,
abort_tooltip)
self_start_wgt_text = self.start_wgt.text()
self.save_all_wgt = self.save_all_group()
grid = QVBoxLayout()
grid.addWidget(self.start_wgt)
grid.addWidget(self.abort_wgt)
grid.addWidget(self.save_all_wgt)
grid.setAlignment(Qt.AlignLeft | Qt.AlignTop)
self.analysis_wgt.setLayout(grid)
self.analysis_wgt.setMaximumHeight(180)
self.analysis_wgt.setMaximumWidth(360)
return self.analysis_wgt
def in_measurement_procedure(self):
self.abort_wgt.setVisible(True)
self.abort_wgt.setEnabled(True)
self.start_wgt.setEnabled(False)
self.start_wgt.setText("in progress...")
self.save_all_group_box.setEnabled(False)
self.operator_parameters_group.setEnabled(False)
self.expert_parameters_group.setEnabled(False)
def in_abort_procedure(self):
self.abort_wgt.setEnabled(False)
self.start_wgt.setEnabled(False)
self.start_wgt.setText("Aborting...")
def reset_procedure(self):
self.abort_wgt.setVisible(False)
self.abort_wgt.setEnabled(True)
self.start_wgt.setEnabled(True)
self.start_wgt.setText(self.start_wgt_text)
self.save_all_group_box.setEnabled(True)
self.operator_parameters_group.setEnabled(True)
self.expert_parameters_group.setEnabled(True)
def create_abort_wgt(self, title, action, tooltip):
abort_wgt = QPushButton(title)
abort_wgt.setObjectName("Abort")
abort_wgt.setFixedWidth(150)
abort_wgt.setFixedHeight(40)
abort_wgt.setToolTip(tooltip)
if action:
abort_wgt.clicked.connect(action)
abort_wgt.setVisible(False)
sp_retain = abort_wgt.sizePolicy()
sp_retain.setRetainSizeWhenHidden(True)
abort_wgt.setSizePolicy(sp_retain)
return abort_wgt
def create_start_wgt(self, title, action, tooltip):
start_wgt = QPushButton(title)
start_wgt.setObjectName("Controller")
start_wgt.setProperty("actOnBeam", True)
start_wgt.setFixedWidth(150)
start_wgt.setFixedHeight(40)
start_wgt.setToolTip(tooltip)
if action:
start_wgt.clicked.connect(action)
start_wgt.setVisible(True)
return start_wgt
def combine_save_icons(self): #epics=False, hdf=False, elog=False):
epics = self.autopost_epics
hdf = self.autopost_hdf
elog = self.autopost_elog
combinedIcon = QIcon()
startx1 = 0
startx2 = 0
startx3 = 0
true_list = [epics, hdf, elog]
if true_list.count(True) == 1:
startx1 = 150
startx2 = 150
startx3 = 150
elif true_list.count(True) == 3:
startx1 = 0
startx2 = 150
startx3 = 300
else:
if epics:
startx1 = 75
startx2 = 225
startx3 = 225
elif hdf:
startx2 = 75
startx3 = 225
comboPixmap = QPixmap(420, 100) #420, 100
comboPixmap.fill(Qt.transparent)
epicsImage = QPixmap(":/epics.png")
hdfImage = QPixmap(":/hdfS.png")
elogImage = QPixmap(":/elog.png")
painter = QPainter(comboPixmap)
if epics:
painter.drawPixmap(startx1, 0, epicsImage, 0, -20, 100, 160)
if hdf:
painter.drawPixmap(startx2, 0, hdfImage, 0, -20, 100, 160)
if elog:
painter.drawPixmap(startx3, 0, elogImage)
combinedIcon.addPixmap(comboPixmap)
painter.end()
return combinedIcon
def post_measurement_save_button(self): # epics=True, hdf=True, elog=True):
epics = self.autopost_epics #= epics
hdf = self.autopost_hdf #= hdf
elog = self.autopost_elog #= elog
widget_height = 40
true_list = [epics, hdf, elog]
widget_width = max(75, 45 * true_list.count(True))
save_data_btn = QPushButton("")
save_data_btn.setIconSize(QSize(100, 38))
save_data_btn.setIcon(self.combine_save_icons())
#epics=epics, hdf=hdf, elog=elog))
save_data_btn.setFixedHeight(widget_height)
save_data_btn.setObjectName("WriteData")
save_data_btn.clicked.connect(self.write_to_destinations)
save_data_btn.setFixedHeight(widget_height)
save_data_btn.setFixedWidth(widget_width) #80 for one
if epics and hdf and elog:
choices = "epics/hdf5/elog"
elif epics and hdf:
choices = "epics/hdf5"
elif hdf and elog:
choices = "hdf/elog"
elif epics:
choices = "epics"
elif hdf:
choices = "hdf"
elif elog:
choices = "elog"
_tip = "Saves data to {0}".format(choices)
save_data_btn.setToolTip(_tip)
return save_data_btn
def post_measurement_group(self): #epics=True, hdf=True, elog=True):
#self.autopost_epics = epics
#self.autopost_hdf = hdf
#self.autopost_elog = elog
group_box = QGroupBox("Post-measurement")
group_box.setObjectName("OUTER")
hbox = QVBoxLayout()
hbox.addWidget(self.post_measurement_save_button())
#epics=epics, hdf=hdf, elog=elog))
hbox.setContentsMargins(9, 19, 9, 9)
hbox.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
group_box.setContentsMargins(0, 0, 0, 0)
group_box.setFixedWidth(208)
group_box.setMaximumHeight(130)
group_box.setFont(self.font_gui)
group_box.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
group_box.setLayout(hbox)
return group_box
def save_all_group(self): # epics=True, hdf=True, elog=True):
#self.autopost_epics = epics
#self.autopost_hdf = hdf
#self.autopost_elog = elog
self.save_all_group_box = QGroupBox("Save All")
self.save_all_group_box.setObjectName("INNERCENTER")
hbox = QVBoxLayout()
hbox.addWidget(self.post_measurement_save_button())
#epics=epics, hdf=hdf, elog=elog))
hbox.setContentsMargins(1, 4, 1, 2)
hbox.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
self.save_all_group_box.setContentsMargins(0, 0, 0, 0)
self.save_all_group_box.setMaximumWidth(160)
self.save_all_group_box.setFixedHeight(60)
self.save_all_group_box.setFont(self.font_gui)
self.save_all_group_box.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
self.save_all_group_box.setLayout(hbox)
return self.save_all_group_box
def write_to_destinations(self):
if self.autopost_epics:
ready = self.parent.write_to_epics()
#if not ready:
# return
if self.autopost_hdf:
self.parent.save_to_hdf()
if self.autopost_elog:
self.parent.send_to_elog()
def checkbox_simulation(self):
widget = QWidget ()
layout=QGridLayout()
layout.addWidget(QHLine(), 0, 0, 1, 3)
try:
text = self.settings.data["Expert"]["simulation"]["data"]["text"]
except KeyError as error:
print("KeyError in guiframe.py; def checkbox_simulation:", error)
text = "Simulation"
checkbox = QCheckBox(text)
checkbox.setObjectName("Simulation")
checkbox.setToolTip(
"Dry-run only; does not write to EPICS Process Variables")
checkbox.setFont(self.font_gui)
#checkbox.setStyleSheet("QCheckBox::indicator::checked {width=85px; height: 85px;};")
#self.parent.simulation = True if self.parent.input_parameters["simulation"] else False
checkbox.stateChanged.connect(self.on_simulation_change)
checkbox.setCheckState(Qt.Checked if self.parent.input_parameters[
"simulation"] else Qt.Unchecked)
layout.addWidget(checkbox, 1, 0)
widget.setLayout(layout)
return widget
def on_simulation_change(self):
checkbox = self.sender()
if checkbox.isChecked():
print("Checkbox is checked")
self.parent.simulation = True
self.parent.gui_header.change_operation_mode(
user_mode=UserMode.SIMULATION)
else:
self.parent.simulation = False
self.parent.gui_header.reset_operation_mode()
self.input_parameters["simulation"] = self.parent.simulation
def get_arrow_button_widget(self, parent_idx=0):
#Back/Forward Buttons START####
arrow_button_widget = QWidget() #self.plot_widget[i])
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setAlignment(Qt.AlignLeft|Qt.AlignTop)
button_left = QToolButton(arrow_button_widget)
button_left.setArrowType(Qt.LeftArrow)
button_left.clicked.connect(self.on_toggle_left)
layout.addWidget(button_left)
button_right = QToolButton(arrow_button_widget)
button_right.setArrowType(Qt.RightArrow)
button_right.clicked.connect(self.on_toggle_right)
layout.addWidget(button_right)
arrow_button_widget.setLayout(layout)
self.left_arrow_dict[button_left] = parent_idx
self.right_arrow_dict[button_right] = parent_idx
layout.setAlignment(Qt.AlignTop)
arrow_button_widget.setMaximumHeight(25)
return arrow_button_widget
#Back/Forward Buttons Actions
def on_toggle_left(self, is_checked):
print(self.sender())
print(self.left_arrow_dict[self.sender()])
self.next_figure(self.left_arrow_dict[self.sender()], -1)
def on_toggle_right(self, is_checked):
print(self.sender())
print(self.right_arrow_dict[self.sender()])
self.next_figure(self.right_arrow_dict[self.sender()], 1)
def next_figure(self, det=0, idx=0):
if det not in self.canvas_fig_dict:
return
fig = self.canvas_fig_dict[det]
no_plots_seq = len(self.multiple_figure_dict[fig])
self.canvas_current_idx[det] = (self.canvas_current_idx[det] + idx) % no_plots_seq
if self.canvas[det] is not None:
self.sub_results_layout[det].removeWidget(self.canvas[det])
self.canvas[det].deleteLater()
if self.nav[det] is not None:
self.sub_results_layout[det].removeWidget(self.nav[det])
self.nav[det].deleteLater()
if fig in self.multiple_figure_dict:
if self.multiple_figure_dict[fig]:
self.canvas[det] = FigureCanvasQTAgg(self.multiple_figure_dict[fig][self.canvas_current_idx[det]])
self.sub_results_layout[det].addWidget(self.canvas[det])
self.sub_results_wgt[det].setLayout(self.sub_results_layout[det])
self.nav[det] = NavigationToolbar(
self.canvas[det], self.sub_results_wgt[det], coordinates=False)
self.nav[det].setMinimumWidth(400)
self.nav[det].setMinimumHeight(50)
#nav.setContentsMargins(0, 0, 0, 0)
self.nav[det].setVisible(True)
self.nav[det].setStyleSheet("QToolBar { border: 0px }")
#else:
# self.canvas[det] = None
# self.nav[det] = None
def canvas_update(self, fig_data, idx=0):
self.multiple_figure_dict = fig_data
for i, key in enumerate(self.multiple_figure_dict.keys()):
self.canvas_fig_dict[i] = key
for i, (canvas, nav, wgt, layout, key) in enumerate(
zip(self.canvas, self.nav,
self.sub_results_wgt,
self.sub_results_layout,
self.multiple_figure_dict.keys())):
if canvas is not None:
layout.removeWidget(canvas)
canvas.deleteLater()
if nav is not None:
nav.deleteLater()
if self.multiple_figure_dict[key]: #'Figure 1']:
if not isinstance(self.multiple_figure_dict[key], list):
temp_list = []
temp_list.append(self.multiple_figure_dict[key])
self.multiple_figure_dict[key] = temp_list
self.canvas[i] = FigureCanvasQTAgg(
self.multiple_figure_dict[key][idx])
self.sub_results_layout[i].addWidget(
self.canvas[i])
self.nav[i] = NavigationToolbar(self.canvas[i],
self.sub_results_wgt[i],
coordinates=False)
self.nav[i].setMinimumWidth(400)
self.nav[i].setMinimumHeight(50)
#self.nav[i].setContentsMargins(0, 0, 0, 0)
self.nav[i].setVisible(True)
self.nav[i].setStyleSheet("QToolBar { border: 0px }")
else:
self.canvas[i] = None
self.nav[i] = None
##### GUI Input Widget
def pv_phase_stacked_wgt(self):
self.phase_stacked_widget = QStackedWidget()
stack1 = self.pv_selector_wgt(title="Inj. Phase Selector",
key="zeroPhase",
pv="SINDI01-RSYS:SET-BEAM-PHASE",
manual_value=35)
stack2 = self.pv_selector_wgt(title="Aramis Phase Selector",
key="zeroPhase",
pv="S30CB14-RSYS:SET-BEAM-PHASE",
manual_value=58.53)
stack3 = self.pv_selector_wgt(title="Athos Phase Selector",
key="zeroPhase",
pv="SATMA02-RSYS:SET-BEAM-PHASE",
manual_value=90)
self.phase_stacked_widget.addWidget(stack1)
self.phase_stacked_widget.addWidget(stack2)
self.phase_stacked_widget.addWidget(stack3)
self.phase_stacked_widget.setMaximumHeight(220)
return self.phase_stacked_widget
def pv_energy_stacked_wgt(self):
self.energy_stacked_widget = QStackedWidget()
pvlist = ["SINDI01-RTDS100:ENERGY-OP",
"S30CB14-RTDS100:ENERGY-OP",
"SATMA02-RTDS100:ENERGY-OP"]
self.cafe.openPrepare()
self.cafe.open(pvlist)
self.cafe.openNowAndWait(0.4)
for pv in pvlist:
self.cafe.setGetActionWhenMonitorPolicy(
pv, self.cyca.GET_FROM_CACHE)
stack1 = self.pv_selector_wgt(
title="Inj. Energy Selector", key="beamEnergy",
pv=pvlist[0], manual_value=298)
stack2 = self.pv_selector_wgt(
title="Aramis Energy Selector", key="beamEnergy",
pv=pvlist[1], manual_value=3487)
stack3 = self.pv_selector_wgt(
title="Athos Energy Selector", key="beamEnergy",
pv=pvlist[2], manual_value=3167)
self.energy_stacked_widget.addWidget(stack1)
self.energy_stacked_widget.addWidget(stack2)
self.energy_stacked_widget.addWidget(stack3)
self.energy_stacked_widget.setMaximumHeight(220)
return self.energy_stacked_widget
def pv_selector_wgt(self, title="Select", key="beamEnergy", pv=None,
manual_value="", monitor=True, read=True, manual=True):
group_box = QGroupBox(title)
group_box.setObjectName("INNERCENTER")
grid = QGridLayout()
radio_buddy_text_dict = {}
radiobutton_title = ["Monitor", "Update", "Manual"]
radiobutton_flag = [monitor, read, manual]
radiobutton_list = [None] * len(radiobutton_title)
def cb_pv_selector(value):
value_str = radio_buddy_text_dict[ self.sender()].text()
if not value_str:
print("Fired on Initialization when not connected", value)
print("sender", self.sender())
print("radio_buddy_text", radio_buddy_text_dict)
print("value", radio_buddy_text_dict[self.sender()].text())
return
value_input = re.findall(r'-?\d+\.?\d*', value_str)
self.input_parameters[key] = value_input[0]
for irow, (radio, flag) in enumerate(zip(radiobutton_list,
radiobutton_flag)):
radio = QRadioButton("")
radio.toggled.connect(cb_pv_selector)
radio.setFont(self.font_pts10)
radio.setFixedWidth(15)
radiobutton_list[irow] = radio
if flag:
grid.addWidget(radio, irow, 0)
if monitor:
ql = QLabel(radiobutton_title[0])
ql.setFont(self.font_pts10)
ql.setFixedHeight(self.widget_height)
ql.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
grid.addWidget(ql, 0, 1)
if manual:
ql = QLabel(radiobutton_title[2])
ql.setFont(self.font_pts10)
ql.setFixedHeight(self.widget_height)
ql.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
grid.addWidget(ql, 2, 1)
if monitor:
monitor_pv = CAQLabel(self, pv_name=pv, show_units=True)
monitor_pv.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
monitor_pv.setFont(self.font_pts10)
monitor_pv.setFixedHeight(self.widget_height)
monitor_pv.setFixedWidth(122)
grid.addWidget(monitor_pv, 0, 2, 1, 2)
if read:
read_pv = CAQLabel(self, pv_name=pv, pv_within_daq_group=True,
color_mode="static", show_units=True)
read_pv.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
#read_pv.setObjectName("Readback")
#read_pv.setProperty("static", True)
#read_pv.setStyleSheet('background-color: rgb(255, 255,223)')
read_pv.setFont(self.font_pts10)
init_value = self.cafe.getCache(pv)
if init_value is None:
# init_value = self.cafe.get(pv)
print("init value for pv", init_value, pv)
if init_value is not None:
val = read_pv.format_display_value(init_value)
read_pv.setText(str(val))
read_pv.setFixedHeight(self.widget_height)
read_pv.setFixedWidth(122)
grid.addWidget(read_pv, 1, 2, 1,2)
def update_read_value():
print("sender = ", self.sender())
pvdata = self.cafe.getPV(pv)
init_value = pvdata.value[0]
print(read_pv.text())
if init_value is not None:
#value_str = read_pv.format_display_value(init_value)
#read_pv.setText(str(value_str))
#print(len(read_pv.text()))
#val = re.findall(r'-?\d+\.?\d*', value_str)
#print (val)
#val[0] = val[0] #add space that we stripped off
read_pv.receive_monitor_update(init_value, pvdata.status, pvdata.alarmSeverity)
print(read_pv.text())
if read:
qpb = QPushButton(radiobutton_title[1])
qpb.setObjectName("Update")
#qpb.setStyleSheet('QPushButton {background-color: rgb(225, 225, 225);}')
qpb.pressed.connect(update_read_value)
qpb.setFixedHeight(self.widget_height)
qpb.setFixedWidth(60)
grid.addWidget(qpb, 1, 1)
qpb.pressed.emit()
if manual:
manual_wgt = QLineEdit(str(manual_value))
manual_wgt.setObjectName("WriteCenter")
manual_wgt.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
manual_wgt.setFixedHeight(self.widget_height)
manual_wgt.setFixedWidth(74)
grid.addWidget(manual_wgt, 2, 2)
ql = QLabel(self.cafe.getUnits(pv))
ql.setFont(self.font_pts10)
ql.setFixedHeight(self.widget_height)
ql.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
grid.addWidget(ql, 2, 3)
grid.setContentsMargins(9, 6, 9, 0)
grid.setAlignment(Qt.AlignLeft | Qt.AlignTop)
grid.setVerticalSpacing(2)
grid.setHorizontalSpacing(4)
group_box.setContentsMargins(0, 0, 0, 0)
group_box.setMaximumWidth(280)
group_box.setMaximumHeight(260)
group_box.setFont(self.font_pts10)
group_box.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
group_box.setLayout(grid)
if monitor:
radio_buddy_text_dict[radiobutton_list[0]] = monitor_pv
if read:
radio_buddy_text_dict[radiobutton_list[1]] = read_pv
if manual:
radio_buddy_text_dict[radiobutton_list[2]] = manual_wgt
idx = 1 if read else 0
#print("idx", idx)
#print(radio_buddy_text_dict)
radiobutton_list[idx].setChecked(True)
radiobutton_list[idx].toggled.emit(True)
return group_box
def input_wgt(self, buddy, label, key, value, irow=0,
destination=0):
suggested = "WW"
label_text = label
label = QLabel(label_text if buddy != "QCheckBox".upper() else "")
label.setFixedHeight(24)
label.setFont(self.font_pts10)
label.setContentsMargins(5, 0, 0, 0)
if buddy == "QComboBox".upper():
#if isinstance(value, list):
def combo_cb(new_text):
value = new_text
#print("value=", new_text, self.sender())
#_key = self.line_sender_dict[self.sender()]
print("key and _key", key, self.sender(), new_text)
#sender = self.sender()
self.input_parameters[key] = new_text
print (self.parent.input_parameters[key])
print (self.input_parameters[key])
if 'forwardLink' in self.settings.data['Parameters'][key]['data']:
link = self.settings.data['Parameters'][key]['data']['forwardLink'][0]
if self.energy_stacked_widget:
link_list = self.settings.data[link].keys()
print(link_list)
idx = list(link_list).index(self.input_parameters[key])
print(idx)
self.energy_stacked_widget.setCurrentIndex(idx)
if self.phase_stacked_widget:
link_list = self.settings.data[link].keys()
print(link_list)
idx = list(link_list).index(self.input_parameters[key])
print(idx)
self.phase_stacked_widget.setCurrentIndex(idx)
print("link is ", link)
print("value", value)
for item in self.settings.data[link][value]:
value_list = self.settings.data[link][value][item]
print ("item", item, "valuelist", value_list)
print ( self.settings.data['Parameters'][item]['data']['widget'])
if item in self.line_sender_dict:
if self.settings.data['Parameters'][item]['data']['widget'] in 'QComboBox':
self.line_sender_dict[item].clear()
self.line_sender_dict[item].addItems(value_list)
self.line_sender_dict[item].setCurrentIndex(0)
self.line_sender_dict[item].currentTextChanged.emit(value_list[0])
#self.line_sender_dict[item].setStyleSheet(
# "QComboBox QAbstractItemView {selection-background-color: blue;}")
elif self.settings.data['Parameters'][item]['data']['widget'] in 'QLineEdit':
self.line_sender_dict[item].setText(str(value_list))
line = QComboBox()
line.clear()
'''
start_idx = self.parent.settings.data["Parameters"][key]["data"]["startIdx"]
link = self.settings.data["Parameters"][key]["data"]["link"]
link_values = self.settings.data["Parameters"][link]["data"]["value"]
link_startIdx = self.settings.data["Parameters"][link]["data"]["startIdx"]
link_seq = link_values[link_startIdx]
items = self.settings.data["Parameters"][key]["data"]["value"][link_seq]
'''
line.addItems(value)
line.setFixedHeight(26)
line.currentTextChanged.connect(combo_cb)
line.setCurrentIndex(0)
line.currentTextChanged.emit(value[0])
value_for_width = max(value, key=len)
#line.currentTextChanged.emit(value["SINDI01"][0])
fm = QFontMetricsF(line.font())
param_width = max(fm.width(str(value_for_width)), fm.width(suggested))
line.setFixedWidth(param_width + 56)
line.setObjectName("Write")
elif buddy == "QRadioButton".upper():
def on_radiobutton_change(new_value):
radio_button = self.sender()
self.parent.input_parameters[key] = radio_button.target
print(key, radio_button.target)
color_list = ["#894961", "teal", "darkblue"]
if 'forwardLink' in self.settings.data['Parameters'][key]['data']:
link = self.settings.data['Parameters'][key]['data']['forwardLink'][0]
print("forwardLink is ====> ", link)
for item in self.settings.data[link][radio_button.target]:
value_list = self.settings.data[link][radio_button.target][item]
print ("item", item, "valuelist", value_list)
print ( self.settings.data['Parameters'][item]['data']['widget'])
if item in self.line_sender_dict:
if self.settings.data['Parameters'][item]['data']['widget'] in 'QComboBox':
self.line_sender_dict[item].clear()
self.line_sender_dict[item].addItems(value_list)
self.line_sender_dict[item].setCurrentIndex(0)
self.line_sender_dict[item].currentTextChanged.emit(value_list[0])
#self.line_sender_dict[item].setStyleSheet(
# "QComboBox QAbstractItemView {selection-background-color: blue;}")
elif self.settings.data['Parameters'][item]['data']['widget'] in 'QLineEdit':
self.line_sender_dict[item].setText(str(value_list))
#line = QTabWidget()
#for tab in value:
# wgt = QWidget()
# line.addTab(wgt, tab)
line = self.radio_buttons(value)
rblist = line.findChildren(QRadioButton)
#values = self.settings.data["Parameters"][key]["data"]["name"].keys()
for rb in rblist:
rb.toggled.connect(on_radiobutton_change)
rblist[0].setChecked(True)
rblist[0].toggled.emit(True)
#if rb.target == item:
# rb.setChecked(True)
#rb.toggled.emit(True)
# print("Item checked")
elif buddy == "QCheckBox".upper():
def check_cb(new_value):
print("value=", new_value, self.sender())
#_key = self.line_sender_dict[self.sender()]
self.parent.input_parameters[key] = new_value
print (self.parent.input_parameters[key])
line = QCheckBox(label_text)
#line.setObjectName("Write")
line.setChecked(Qt.Checked if value else Qt.Unchecked)
line.stateChanged.connect(check_cb)
elif buddy == "QLabel".upper():
#Read only has no callback
line = QLabel()
line.setText(str(value)) #"{0: 3.1f}".format(value))
line.setFixedHeight(24)
line.setAlignment(Qt.AlignRight | Qt.AlignBottom)
line.setStyleSheet("QLabel{text-align: right}")
fm = QFontMetricsF(line.font())
param_width = max(fm.width(str(value)), fm.width(suggested))
line.setMaximumWidth(param_width + 40)
elif buddy == "QLineRead".upper():
#Read only has no callback
line = QLineEdit()
line.setObjectName("Read")
line.setText(str(value)) #"{0: 3.1f}".format(value))
line.setFixedHeight(24)
line.setAlignment(Qt.AlignRight | Qt.AlignBottom)
line.setStyleSheet("QLabel{text-align: right}")
fm = QFontMetricsF(line.font())
param_width = max(fm.width(str(value)), fm.width(suggested))
line.setMaximumWidth(param_width + 20)
else:
def line_cb(new_value):
print("value=", new_value, self.sender())
#_key = self.line_sender_dict[self.sender()]
#self.parent.input_value_dict[_key] = new_value
self.parent.input_parameters[key] = new_value
print (self.parent.input_parameters[key])
line = QLineEdit()
line.setObjectName("Write")
line.setFixedHeight(24)
line.textEdited.connect(line_cb)
fm = QFontMetricsF(line.font())
line.setText(str(value))
param_width = max(fm.width(str(value)), fm.width(suggested))
line.setMaximumWidth(param_width + 20)
self.line_sender_dict[key] = line
#print("row count", self.input_wgt_grid.rowCount())
#print("col count", self.input_wgt_grid.columnCount())
#print(buddy)
if destination == 0:
if buddy == "QComboBox".upper():
#qw = QWidget()
vbox = QVBoxLayout()
#label.setContentsMargins(5, 0, 0, 0)
#line.setContentsMargins(0, 0, 0, 0)
label.setAlignment(Qt.AlignBottom)
vbox.addWidget(label)
vbox.addWidget(line)
#qw.setLayout(vbox)
#qw.setFixedHeight(56)
self.input_wgt_grid.addLayout(
vbox, irow, 0, 1, 3, Qt.AlignLeft | Qt.AlignVCenter)
elif buddy == "QCheckBox".upper():
self.input_wgt_grid.addWidget(
line, irow, 0, 1, 4, Qt.AlignLeft | Qt.AlignVCenter)
elif buddy == "QRadioButton".upper():
self.input_wgt_grid.addWidget(
line, irow, 0, 1, 4)
else:
self.input_wgt_grid.addWidget(
label, irow, 0, 1, 2, Qt.AlignLeft | Qt.AlignVCenter)
self.input_wgt_grid.addWidget(
line, irow, 2, 1, 2, Qt.AlignLeft | Qt.AlignVCenter)
#self.input_wgt_grid.addWidget(QFrame(), irow, 3, 1, 2, Qt.AlignLeft | Qt.AlignVCenter)
#print(self.input_wgt_grid.itemAtPosition(irow, 1).widget().text())
if irow==4:
qFrame = QFrame()
qFrame.setFixedHeight(10)
self.input_wgt_grid.addWidget(
qFrame, irow+1, 0, 1, 4)
if irow == 4:
self.input_wgt_grid.addWidget(
self.pv_phase_stacked_wgt(), irow+2, 0, 1, 4)
if irow==4:
qFrame = QFrame()
qFrame.setFixedHeight(10)
self.input_wgt_grid.addWidget(
qFrame, irow+3, 0, 1, 4)
if irow == 4:
self.input_wgt_grid.addWidget(
self.pv_energy_stacked_wgt(), irow+4, 0, 1, 4)
if irow==4:
qFrame = QHLine()
qFrame.setFixedHeight(10)
self.input_wgt_grid.addWidget(
qFrame, irow+5, 0, 1, 4)
return self.input_wgt_grid
else:
if buddy == "QComboBox".upper():
vbox = QVBoxLayout()
label.setAlignment(Qt.AlignBottom)
vbox.addWidget(label)
vbox.addWidget(line)
self.expert_wgt_grid.addLayout(
vbox, irow, 0, 1, 3, Qt.AlignLeft | Qt.AlignVCenter)
if buddy == "QCheckBox".upper():
self.expert_wgt_grid.addWidget(
line, irow, 0, 1, 3, Qt.AlignLeft | Qt.AlignVCenter)
else:
self.expert_wgt_grid.addWidget(
label, irow, 0, 1, 1, Qt.AlignLeft | Qt.AlignVCenter)
self.expert_wgt_grid.addWidget(
line, irow, 1, 1, 1, Qt.AlignCenter | Qt.AlignVCenter)
return self.expert_wgt_grid
def enter_input_parameters(self):
#operator
self.operator_parameters_group \
= self.operator_parameters_groupbox()
if self.facility == Facility.SwissFEL:
try:
if self.settings.data["Parameters"]["undulator"]["flag"]:
self.operator_parameters_group.layout().addWidget(
self.parent.gui_header.operator_group_header())
except KeyError:
pass
for i, ( (key, val), label) in enumerate(zip(
self.input_parameters.items(), self.input_labels.values())):
buddy = self.settings.data[
"Parameters"][key]["data"]["widget"].upper()
j=self.input_wgt_grid.rowCount()
print("row count is ", j)
if buddy != "NONE":
layout = self.input_wgt(buddy=buddy, label=label, key=key,
value=val, irow=j )
self.operator_parameters_group.layout().addLayout(layout)
# QTaggedLineEdit(label_text="Input DD:", value=19, position="LEFT"))
# self.operator_parameters_group.layout().addWidget(QFrame(), stretch=1)
self.operator_parameters_group.setFixedHeight(INPUT_PARAMETERS_HEIGHT)
lo = QGridLayout()
lo.setContentsMargins(9, 19, 9, 9)
lo.addWidget(self.operator_parameters_group, 0, 0, 2, 1)
if random.randint(1, 10) > 5:
lo.addWidget(self.create_analysis_wgt(), 0, 1)
else: #self.operator_parameters_group.layout().addWidget(self.gui_frame.checkbox_simulation())
lo.addWidget(self.analysis_procedure_group(), 0, 1)
lo.setAlignment(Qt.AlignLeft | Qt.AlignTop)
lo.setHorizontalSpacing(20)
self.operator_wgt.setLayout(lo)
#expert
expert_layout = None
self.expert_parameters_group = self.expert_parameters_groupbox()
for i, ((key, val), label) in enumerate(zip(
self.expert_parameters.items(), self.expert_labels.values())):
buddy = self.settings.data[
"Expert"][key]["data"]["widget"].upper()
if buddy != "NONE":
expert_layout = self.input_wgt(buddy=buddy, label=label,
key=key, value=val, irow=i,
destination=1)
self.input_parameters.update(self.expert_parameters)
#self.expert_parameters_group.layout().setContentsMargins(9, 19, 9, 9)
if expert_layout:
self.expert_parameters_group.layout().addLayout(expert_layout)
self.expert_parameters_group.layout().addWidget(
self.checkbox_simulation())
self.expert_parameters_group.setFixedHeight(EXPERT_PARAMETERS_HEIGHT)
lo = QGridLayout()
lo.setContentsMargins(9, 19, 9, 9)
lo.addWidget(self.expert_parameters_group, 0, 0, 2, 1)
lo.setAlignment(Qt.AlignLeft | Qt.AlignTop)
lo.setHorizontalSpacing(20)
self.expert_wgt.setLayout(lo)
def radio_buttons(self, options=[], start_idx=0):
widget = QWidget()
layout = QGridLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
target_list = options
color_list = ["#894961", "teal", "darkblue"]
self.radiobutton = [None] * len(options)
for i, title in enumerate(options):
self.radiobutton[i] = QRadioButton(title)
width_list = [70, 70, 70]
layout.addWidget(QHLine(), 0, 0, 1, 3)
layout.addWidget(QLabel("RF Tranverse Deflector"), 1, 0, 1, 3, Qt.AlignCenter)
for i, (radio, target, color, width) in enumerate(
zip(self.radiobutton, target_list, color_list, width_list)):
#radio = QRadioButton(target)
radio.setFont(self.font_pts10)
radio.setStyleSheet("color : {0};".format(color))
radio.target = target
#radio.toggled.connect(self.on_target_clicked)
layout.addWidget(radio, 2, i)
#radio.setFixedWidth(width)
self.radiobutton[start_idx].setChecked(True)
self.radiobutton[start_idx].toggled.emit(True)
layout.addWidget(QHLine(), 3, 0, 1, 3)
widget.setLayout(layout)
return widget