def __init__(self, recoil_element: RecoilElement, colormap, element_simulation: ElementSimulation): """Inits a recoil info dialog. Args: recoil_element: A RecoilElement object. colormap: Colormap for elements. element_simulation: Element simulation that has the recoil element. """ super().__init__() self.recoil_element = recoil_element self.element_simulation = element_simulation self.tmp_color = QColor(self.recoil_element.color) self.colormap = colormap value = self.recoil_element.reference_density self.scientific_spinbox = ScientificSpinBox(value=value, minimum=0.01, maximum=9.99e23) uic.loadUi(gutils.get_ui_dir() / "ui_recoil_info_dialog.ui", self) self.okPushButton.clicked.connect(self.__accept_settings) self.cancelPushButton.clicked.connect(self.close) self.colorPushButton.clicked.connect(self.__change_color) self.fields_are_valid = True iv.set_input_field_red(self.nameLineEdit) self.nameLineEdit.textChanged.connect( lambda: iv.check_text(self.nameLineEdit, qwidget=self)) self.nameLineEdit.textEdited.connect(self.__validate) self.name = recoil_element.name self.description = recoil_element.description self.formLayout.insertRow( 4, QtWidgets.QLabel(r"Reference density [at./cm<sup>3</sup>]:"), self.scientific_spinbox) self.formLayout.removeRow(self.widget) self.description = recoil_element.description self.isOk = False self.dateLabel.setText( time.strftime( "%c %z %Z", time.localtime(self.recoil_element.modification_time))) title = f"Recoil element: " \ f"{self.recoil_element.element.get_prefix()}" self.infoGroupBox.setTitle(title) self.__set_color_button_color(self.recoil_element.element.symbol) self.exec_()
def setUp(self): self.minimum = 1.0e20 self.maximum = 9.9e23 self.sbox = ScientificSpinBox(1.123e+22, minimum=self.minimum, maximum=self.maximum) down_btn = self.sbox.downButton up_btn = self.sbox.upButton self.click_down = lambda: QTest.mouseClick(down_btn, Qt.LeftButton) self.click_up = lambda: QTest.mouseClick(up_btn, Qt.LeftButton)
def __init__(self): super().__init__() self.spinbox = QtWidgets.QSpinBox() self.doubleSpinbox = QtWidgets.QDoubleSpinBox() self.textBox = QtWidgets.QTextEdit() self.timeEdit = QtWidgets.QTimeEdit() self.checkBox = QtWidgets.QCheckBox() self.label = QtWidgets.QLabel() self.plaintext = QtWidgets.QPlainTextEdit() self.not2waySpinBox = QtWidgets.QSpinBox() self.scibox = ScientificSpinBox() self.listWidget = QtWidgets.QListWidget() self.group_box = QtWidgets.QGroupBox() self.radio_group = QtWidgets.QButtonGroup() for i in range(3): btn = QtWidgets.QRadioButton(f"rb{i}", self) self.radio_group.addButton(btn) gutils.set_btn_group_data(self.radio_group, ["fizz", "buzz", "fizzbuzz"]) self.comboBox = QtWidgets.QComboBox() for i in range(3): self.comboBox.addItem(f"x-{i + 42}", i) self.tree = QtWidgets.QTreeWidget() gutils.fill_tree(self.tree.invisibleRootItem(), ["foo", "bar", "baz"])
def __init__(self, **kwargs): """Initialize the widget. Args: kwargs: property values to be shown in the widget. """ ui_file = gutils.get_ui_dir() / "ui_optimization_fluence_params.ui" self.fluenceDoubleSpinBox = ScientificSpinBox(10e12) super().__init__(ui_file, **kwargs) self.fluence_form_layout.addRow("Upper limit", self.fluenceDoubleSpinBox)
class RecoilInfoDialog(QtWidgets.QDialog, bnd.PropertyBindingWidget, metaclass=gutils.QtABCMeta): """Dialog for editing the name, description and reference density of a recoil element. """ # TODO possibly track name changes name = bnd.bind("nameLineEdit") description = bnd.bind("descriptionLineEdit") reference_density = bnd.bind("scientific_spinbox") @property def color(self): return self.tmp_color.name() def __init__(self, recoil_element: RecoilElement, colormap, element_simulation: ElementSimulation): """Inits a recoil info dialog. Args: recoil_element: A RecoilElement object. colormap: Colormap for elements. element_simulation: Element simulation that has the recoil element. """ super().__init__() self.recoil_element = recoil_element self.element_simulation = element_simulation self.tmp_color = QColor(self.recoil_element.color) self.colormap = colormap value = self.recoil_element.reference_density self.scientific_spinbox = ScientificSpinBox(value=value, minimum=0.01, maximum=9.99e23) uic.loadUi(gutils.get_ui_dir() / "ui_recoil_info_dialog.ui", self) self.okPushButton.clicked.connect(self.__accept_settings) self.cancelPushButton.clicked.connect(self.close) self.colorPushButton.clicked.connect(self.__change_color) self.fields_are_valid = True iv.set_input_field_red(self.nameLineEdit) self.nameLineEdit.textChanged.connect( lambda: iv.check_text(self.nameLineEdit, qwidget=self)) self.nameLineEdit.textEdited.connect(self.__validate) self.name = recoil_element.name self.description = recoil_element.description self.formLayout.insertRow( 4, QtWidgets.QLabel(r"Reference density [at./cm<sup>3</sup>]:"), self.scientific_spinbox) self.formLayout.removeRow(self.widget) self.description = recoil_element.description self.isOk = False self.dateLabel.setText( time.strftime( "%c %z %Z", time.localtime(self.recoil_element.modification_time))) title = f"Recoil element: " \ f"{self.recoil_element.element.get_prefix()}" self.infoGroupBox.setTitle(title) self.__set_color_button_color(self.recoil_element.element.symbol) self.exec_() def __density_valid(self): """ Check if density value is valid and in limits. Return: True or False. """ try: self.scientific_spinbox.get_value() return True except TypeError: return False def __accept_settings(self): """Function for accepting the current settings and closing the dialog window. """ if not self.fields_are_valid or not self.__density_valid(): QtWidgets.QMessageBox.critical( self, "Warning", "Some of the setting values are invalid.\n" "Please input values in fields indicated in red.", QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) return if self.name != self.recoil_element.name: # Check that the new name is not already in use if self.name in ( r.name for r in # has_recoil self.element_simulation.recoil_elements): QtWidgets.QMessageBox.critical( self, "Warning", "Name of the recoil element is already in use. Please use " "a different name", QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok) return # If current recoil is used in a running simulation if self.recoil_element is \ self.element_simulation.get_main_recoil(): if (self.element_simulation.is_simulation_running() or self.element_simulation.is_optimization_running()) and \ self.name != self.recoil_element.name: reply = QtWidgets.QMessageBox.question( self, "Recoil used in simulation", "This recoil is used in a simulation that is " "currently running.\nIf you change the name of " "the recoil, the running simulation will be " "stopped.\n\n" "Do you want to save changes anyway?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel) if reply == QtWidgets.QMessageBox.No or reply == \ QtWidgets.QMessageBox.Cancel: return else: self.element_simulation.stop() self.isOk = True self.close() def __change_color(self): """ Change the color of the recoil element. """ dialog = QtWidgets.QColorDialog(self) color = dialog.getColor(self.tmp_color) if color.isValid(): self.tmp_color = color self.__change_color_button_color( self.recoil_element.element.symbol) def __change_color_button_color(self, element: str): """ Change color button's color. Args: element: String representing element name. """ df.set_btn_color(self.colorPushButton, self.tmp_color, self.colormap, element) def __set_color_button_color(self, element): """Set default color of element to color button. Args: element: String representing element. """ self.colorPushButton.setEnabled(True) self.tmp_color = QColor(self.recoil_element.color) self.__change_color_button_color(element) def __validate(self): """ Validate the recoil name. """ text = self.name regex = "^[A-Za-z0-9-ÖöÄäÅå]*" valid_text = iv.validate_text_input(text, regex) self.name = valid_text
def __init__(self, obj: Union[Measurement, Simulation], preset_folder=None): """Initializes the widget. Args: obj: object that uses these settings, either a Measurement or a Simulation. """ super().__init__() uic.loadUi(gutils.get_ui_dir() / "ui_measurement_settings_tab.ui", self) self.fluenceDoubleSpinBox = ScientificSpinBox() image = gf.get_root_dir() / "images" / "measurement_setup_angles.png" pixmap = QtGui.QPixmap(str(image)) self.picture.setScaledContents(True) self.picture.setPixmap(pixmap) self.obj = obj self.__original_property_values = {} locale = QLocale.c() self.energyDoubleSpinBox.setLocale(locale) self.energyDistDoubleSpinBox.setLocale(locale) self.spotSizeXdoubleSpinBox.setLocale(locale) self.spotSizeYdoubleSpinBox.setLocale(locale) self.divergenceDoubleSpinBox.setLocale(locale) self.currentDoubleSpinBox.setLocale(locale) self.timeDoubleSpinBox.setLocale(locale) self.runChargeDoubleSpinBox.setLocale(locale) self.targetThetaDoubleSpinBox.setLocale(locale) self.detectorThetaDoubleSpinBox.setLocale(locale) self.detectorFiiDoubleSpinBox.setLocale(locale) self.targetFiiDoubleSpinBox.setLocale(locale) # Fii angles are currently not used so disable their spin boxes self.detectorFiiDoubleSpinBox.setEnabled(False) self.targetFiiDoubleSpinBox.setEnabled(False) gutils.fill_combobox(self.profileComboBox, Profile) # Copy of measurement's/simulation's run or default run # TODO should default run also be copied? if not self.obj.run: self.tmp_run = self.obj.request.default_run else: self.tmp_run = copy.deepcopy(self.obj.run) self.isotopeInfoLabel.setVisible(False) self.beamIonButton.clicked.connect(self.change_element) self.fields_are_valid = False iv.set_input_field_red(self.nameLineEdit) self.nameLineEdit.textChanged.connect( lambda: iv.check_text(self.nameLineEdit, qwidget=self)) self.nameLineEdit.textEdited.connect(self.__validate) self.nameLineEdit.setEnabled(False) self.run_form_layout: QtWidgets.QFormLayout self.run_form_layout.insertRow(3, "Fluence", self.fluenceDoubleSpinBox) self.fluenceDoubleSpinBox.scientificLineEdit.setContextMenuPolicy( Qt.ActionsContextMenu) self.actionMultiply = QtWidgets.QAction( self.fluenceDoubleSpinBox.scientificLineEdit) self.actionMultiply.triggered.connect(self.__multiply_fluence) self.fluenceDoubleSpinBox.scientificLineEdit.addAction( self.actionMultiply) self.actionUndo = QtWidgets.QAction( self.fluenceDoubleSpinBox.scientificLineEdit) self.actionUndo.setText("Undo multiply") self.actionUndo.triggered.connect(self.__undo_fluence) self.actionUndo.setEnabled(bool(self.tmp_run.previous_fluence)) self.fluenceDoubleSpinBox.scientificLineEdit.addAction(self.actionUndo) self.clipboard = QGuiApplication.clipboard() self._ratio = None self.clipboard.changed.connect(self.__update_multiply_action) self.__update_multiply_action() self.energyDoubleSpinBox.setToolTip("Energy set in MeV with.") if preset_folder is not None: self.preset_widget = PresetWidget.add_preset_widget( preset_folder / "measurement", "mea", lambda w: self.layout().insertWidget(0, w), save_callback=self.save_properties_to_file, load_callback=self.load_properties_from_file ) else: self.preset_widget = None self.show_settings()
def __init__(self, obj: Detector, request: Request, icon_manager, run=None): """Initializes a DetectorSettingsWidget object. Args: obj: a Detector object. request: Which request it belongs to. icon_manager: IconManager object. run: Run object. None if detector is default detector. """ super().__init__() uic.loadUi(gutils.get_ui_dir() / "ui_request_detector_settings.ui", self) self.obj = obj self.request = request self.icon_manager = icon_manager self.run = run self.__original_properties = {} # Temporary foils list which holds all the information given in the # foil dialog # If user presses ok or apply, these values will be saved into # request's default detector self.tmp_foil_info = [] # List of foil indexes that are timing foils self.tof_foils = [] # Add foil widgets and foil objects self.detector_structure_widgets = [] self.foils_layout = self._add_default_foils(self.obj) self.detectorScrollAreaContents.layout().addLayout(self.foils_layout) self.newFoilButton.clicked.connect( lambda: self._add_new_foil(self.foils_layout)) self.addEfficiencyButton.clicked.connect(self.__add_efficiency) self.removeEfficiencyButton.clicked.connect(self.__remove_efficiency) self.plotEfficiencyButton.clicked.connect(self.__plot_efficiency) self.efficiencyListWidget.itemSelectionChanged.connect( self._enable_remove_btn) self._enable_remove_btn() # Calibration settings # TODO: Require saving affected cuts if beam setting has been changed self.executeCalibrationButton.clicked.connect( self.__open_calibration_dialog) self.executeCalibrationButton.setEnabled( not self.request.samples.measurements.is_empty()) gutils.fill_combobox(self.typeComboBox, DetectorType) self.fields_are_valid = False iv.set_input_field_red(self.nameLineEdit) self.nameLineEdit.textChanged.connect( lambda: iv.check_text(self.nameLineEdit, qwidget=self)) self.nameLineEdit.textEdited.connect( lambda: iv.sanitize_file_name(self.nameLineEdit)) self.nameLineEdit.setEnabled(False) locale = QLocale.c() self.timeResSpinBox.setLocale(locale) self.virtualSizeXSpinBox.setLocale(locale) self.virtualSizeYSpinBox.setLocale(locale) self.angleSlopeLineEdit.setLocale(locale) self.angleOffsetLineEdit.setLocale(locale) # Create scientific spinboxes for tof slope and tof offset self.formLayout_2.removeRow(self.slopeLineEdit) self.formLayout_2.removeRow(self.offsetLineEdit) self.scientific_tof_slope = ScientificSpinBox(minimum=-math.inf, maximum=math.inf) self.scientific_tof_offset = ScientificSpinBox(minimum=-math.inf, maximum=math.inf) self.formLayout_2.insertRow(0, "ToF slope [s/channel]:", self.scientific_tof_slope) self.formLayout_2.insertRow(1, "ToF offset[s]:", self.scientific_tof_offset) if platform.system() == "Darwin": self.scientific_tof_offset.scientificLineEdit.setFixedWidth(170) self.scientific_tof_slope.scientificLineEdit.setFixedWidth(170) # Save as and load self.saveButton.clicked.connect(self.__save_file) self.loadButton.clicked.connect(self.__load_file) self.show_settings()
class TestSciSpinbox(unittest.TestCase): def setUp(self): self.minimum = 1.0e20 self.maximum = 9.9e23 self.sbox = ScientificSpinBox(1.123e+22, minimum=self.minimum, maximum=self.maximum) down_btn = self.sbox.downButton up_btn = self.sbox.upButton self.click_down = lambda: QTest.mouseClick(down_btn, Qt.LeftButton) self.click_up = lambda: QTest.mouseClick(up_btn, Qt.LeftButton) def test_display(self): self.sbox.minimum = -math.inf self.sbox.set_value(5.5e+22) self.assertEqual("5.5e+22", self.sbox.scientificLineEdit.text()) self.sbox.set_value(math.pi * 1e20) self.assertEqual("3.1415926535897e+20", self.sbox.scientificLineEdit.text()) self.sbox.set_value(1.00000e21) self.assertEqual("1.0e+21", self.sbox.scientificLineEdit.text()) self.sbox.set_value(1.00000e-21) self.assertEqual("1.0e-21", self.sbox.scientificLineEdit.text()) self.sbox.set_value(-1.00000e-21) self.assertEqual("-1.0e-21", self.sbox.scientificLineEdit.text()) self.sbox.set_value(0.1) self.assertEqual("1.0e-1", self.sbox.scientificLineEdit.text()) self.sbox.set_value(0) self.assertEqual("0.0e+0", self.sbox.scientificLineEdit.text()) def test_typed_values(self): self.sbox.scientificLineEdit.setText("1.321e20") self.assertEqual(1.321e20, self.sbox.get_value()) self.sbox.scientificLineEdit.setText("0") self.assertEqual(0, self.sbox.get_value()) self.sbox.scientificLineEdit.setText("foo") self.assertRaises(TypeError, lambda: self.sbox.get_value()) def test_decrease(self): self.sbox.minimum = -math.inf self.sbox.set_value(5.5e+22) self.click_down() self.assertEqual(5.4e+22, self.sbox.get_value()) self.sbox.set_value(1.0001e+22) self.click_down() self.assertEqual(9.9001e+21, self.sbox.get_value()) self.sbox.set_value(0.0e0) self.click_down() self.assertEqual(-1.0e-2, self.sbox.get_value()) self.sbox.set_value(1.05e-3) self.click_down() self.assertEqual(9.95e-4, self.sbox.get_value()) self.sbox.set_value(-9.95e-4) self.click_down() self.assertEqual(-1.05e-3, self.sbox.get_value()) self.sbox.scientificLineEdit.setText("foo") self.click_down() self.assertEqual("foo", self.sbox.scientificLineEdit.text()) def test_increase(self): self.sbox.minimum = -math.inf self.sbox.set_value(9.81e+22) self.click_up() self.assertEqual(9.91e+22, self.sbox.get_value()) self.click_up() self.assertEqual(1.01e+23, self.sbox.get_value()) self.sbox.set_value(0.0e0) self.click_up() self.assertEqual(1.0e-2, self.sbox.get_value()) self.sbox.set_value(9.9e0) self.click_up() self.assertEqual(1.0e1, self.sbox.get_value()) self.sbox.set_value(-1.05e-10) self.click_up() self.assertEqual(-9.95e-11, self.sbox.get_value()) def test_set_value(self): self.sbox.set_value(5e22) self.assertEqual(5e22, self.sbox.get_value()) # Value below min self.sbox.set_value(10) self.assertEqual(self.minimum, self.sbox.get_value()) # Value over max self.sbox.set_value(5e25) self.assertEqual(self.maximum, self.sbox.get_value()) # Try setting a string self.sbox.set_value("5e21") self.assertEqual(5e21, self.sbox.get_value()) def test_value_properties(self): # After n up clicks and n down clicks, value of the spinbox should # be the same as it was when started self.sbox.minimum = -math.inf self.sbox.maximum = math.inf value_min = -10.0e-10 value_max = 10.0e-10 max_clicks = 25 n = 15 for i in range(n): value = random.uniform(value_min, value_max) self.sbox.set_value(value) x0 = self.sbox.get_value() clicks = random.randint(1, max_clicks) click_order = [ *[self.click_down] * clicks, *[self.click_up] * clicks ] random.shuffle(click_order) for cl in click_order: x1 = self.sbox.get_value() cl() x2 = self.sbox.get_value() if cl is self.click_down: self.assertLess(x2, x1) else: self.assertLess(x1, x2) self.assertEqual(x0, self.sbox.get_value())