def addSpinBox( self, attribute_name, title, tool_tip=None, min_value=1, max_value=10, single_step=1, ): sb = QSpinBox() self[attribute_name] = sb sb.setMaximumHeight(25) sb_layout = QHBoxLayout() sb_layout.addWidget(sb) sb_layout.addStretch() self.addRow(title, sb_layout) if tool_tip is not None: sb.setToolTip(tool_tip) sb.setMinimum(min_value) sb.setMaximum(max_value) sb.setSingleStep(single_step) def getter(self): return self[attribute_name].value() def setter(self, value): self[attribute_name].setValue(value) self.updateProperty(attribute_name, getter, setter) return sb
def _create(self, initial_value: int, spin_range: range) -> QSpinBox: """Return the configured QSpinBox. Parameters ---------- initial_value : int The initial value of the QSpinBox. spin_range : range The start/stop/step of the QSpinBox. Return ------ QSpinBox The configured QSpinBox. """ spin = QSpinBox() spin.setMinimum(spin_range.start) spin.setMaximum(spin_range.stop) spin.setSingleStep(spin_range.step) spin.setValue(initial_value) spin.setKeyboardTracking(False) # correct? spin.setAlignment(Qt.AlignCenter) spin.valueChanged.connect(self._on_change) return spin
def createTimeStepRow(self): history_length_spinner = QSpinBox() addHelpToWidget(history_length_spinner, "config/init/history_length") history_length_spinner.setMinimum(0) history_length_spinner.setMaximum(getHistoryLength()) initial = QToolButton() initial.setText("Initial") addHelpToWidget(initial, "config/init/history_length") def setToMin(): history_length_spinner.setValue(0) initial.clicked.connect(setToMin) end_of_time = QToolButton() end_of_time.setText("End of time") addHelpToWidget(end_of_time, "config/init/history_length") def setToMax(): history_length_spinner.setValue(getHistoryLength()) end_of_time.clicked.connect(setToMax) row = createRow(QLabel("Timestep:"), history_length_spinner, initial, end_of_time) return row, history_length_spinner
def __init__(self): SimulationConfigPanel.__init__(self, IteratedEnsembleSmoother) layout = QFormLayout() case_selector = CaseSelector() layout.addRow("Current case:", case_selector) run_path_label = QLabel("<b>%s</b>" % getRunPath()) addHelpToWidget(run_path_label, "config/simulation/runpath") layout.addRow("Runpath:", run_path_label) number_of_realizations_label = QLabel("<b>%d</b>" % getRealizationCount()) addHelpToWidget(number_of_realizations_label, "config/ensemble/num_realizations") layout.addRow(QLabel("Number of realizations:"), number_of_realizations_label) # The num_iterations_spinner does not track any external changes (will that ever happen?) num_iterations_spinner = QSpinBox() num_iterations_spinner.setMinimum(1) num_iterations_spinner.setMaximum(100) num_iterations_spinner.setValue(getNumberOfIterations()) addHelpToWidget(num_iterations_spinner, "config/simulation/number_of_iterations") num_iterations_spinner.valueChanged[int].connect(setNumberOfIterations) layout.addRow("Number of iterations:", num_iterations_spinner) self._iterated_target_case_format_model = TargetCaseModel( format_mode=True) self._iterated_target_case_format_field = StringBox( self._iterated_target_case_format_model, "config/simulation/iterated_target_case_format", ) self._iterated_target_case_format_field.setValidator( ProperNameFormatArgument()) layout.addRow("Target case format:", self._iterated_target_case_format_field) self._analysis_module_selector = AnalysisModuleSelector( iterable=True, help_link="config/analysis/analysis_module") layout.addRow("Analysis Module:", self._analysis_module_selector) self._active_realizations_model = ActiveRealizationsModel() self._active_realizations_field = StringBox( self._active_realizations_model, "config/simulation/active_realizations") self._active_realizations_field.setValidator( RangeStringArgument(getRealizationCount())) layout.addRow("Active realizations", self._active_realizations_field) self._iterated_target_case_format_field.getValidationSupport( ).validationChanged.connect(self.simulationConfigurationChanged) self._active_realizations_field.getValidationSupport( ).validationChanged.connect(self.simulationConfigurationChanged) self.setLayout(layout)
def add_int_box(layout, default, minimum, maximum, label, row, column=0): box = QSpinBox() box.setMinimum(minimum) box.setMaximum(maximum) # Not always set if not after min & max box.setValue(default) layout.addWidget(QLabel(label), row, column) layout.addWidget(box, row, column + 1) return box
def createSpinBox(self, variable_name, variable_value, variable_type, analysis_module_variables_model): spinner = QSpinBox() spinner.setMinimumWidth(75) spinner.setMaximum(analysis_module_variables_model.getVariableMaximumValue(variable_name)) spinner.setMinimum(analysis_module_variables_model.getVariableMinimumValue(variable_name)) spinner.setSingleStep(analysis_module_variables_model.getVariableStepValue(variable_name)) if variable_value is not None: spinner.setValue(variable_value) spinner.valueChanged.connect(partial(self.valueChanged, variable_name, variable_type, spinner)) return spinner
def createEditor(self, parent): if isinstance(self._value, int): sb = QSpinBox(parent) elif isinstance(self._value, float): sb = QDoubleSpinBox(parent) sb.setDecimals(self.decimals) sb.setMinimum(self.min) sb.setMaximum(self.max) sb.setValue(self._value) sb.setFrame(False) return sb
class QtRender(QWidget): """Dockable widget for render controls. Attributes ---------- """ def __init__(self, layer): """Create our windgets. """ super().__init__() self.layer = layer self.layer.events.octree_level.connect(self._on_octree_level) layout = QVBoxLayout() spin_layout = QHBoxLayout() self.spin_level = QSpinBox() self.spin_level.setKeyboardTracking(False) self.spin_level.setSingleStep(1) self.spin_level.setMinimum(0) self.spin_level.setMaximum(10) self.spin_level.valueChanged.connect(self._on_spin) self.spin_level.setAlignment(Qt.AlignCenter) label = QLabel("Quadtree Level:") spin_layout.addWidget(label) spin_layout.addWidget(self.spin_level) layout.addLayout(spin_layout) self.setLayout(layout) # Get initial value. self._on_octree_level() def _on_spin(self, value): """Level spinbox changed. Parameters ---------- value : int New value of the spinbox """ self.layer.octree_level = value def _on_octree_level(self, event=None): value = self.layer.octree_level self.spin_level.setValue(value)
def create_spinbox(self, prefix, suffix, option, default=NoDefault, min_=None, max_=None, step=None, tip=None, section=None): if section is not None and section != self.CONF_SECTION: self.cross_section_options[option] = section widget = QWidget(self) if prefix: plabel = QLabel(prefix) widget.plabel = plabel else: plabel = None if suffix: slabel = QLabel(suffix) widget.slabel = slabel else: slabel = None if step is not None: if type(step) is int: spinbox = QSpinBox() else: spinbox = QDoubleSpinBox() spinbox.setDecimals(1) spinbox.setSingleStep(step) else: spinbox = QSpinBox() if min_ is not None: spinbox.setMinimum(min_) if max_ is not None: spinbox.setMaximum(max_) if tip is not None: spinbox.setToolTip(tip) self.spinboxes[spinbox] = (section, option, default) layout = QHBoxLayout() for subwidget in (plabel, spinbox, slabel): if subwidget is not None: layout.addWidget(subwidget) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) widget.spinbox = spinbox widget.setLayout(layout) return widget
def createSpinBox( self, variable_name, variable_value, analysis_module_variables_model, ): spinner = QSpinBox() spinner.setMinimumWidth(75) spinner.setMaximum( analysis_module_variables_model.getVariableMaximumValue( variable_name)) spinner.setMinimum( analysis_module_variables_model.getVariableMinimumValue( variable_name)) spinner.setSingleStep( analysis_module_variables_model.getVariableStepValue( variable_name)) spinner.setObjectName(variable_name) if variable_value is not None: spinner.setValue(variable_value) return spinner
def createEditor(self, parent): w = QWidget(parent) l = QHBoxLayout() l.setSpacing(0) l.setContentsMargins(0, 0, 0, 0) for v in self._value: if isinstance(v, int): sb = QSpinBox() elif isinstance(v, float): sb = QDoubleSpinBox() sb.setDecimals(self.decimals) sb.setMinimum(self.min) sb.setMaximum(self.max) sb.setValue(v) sb.setFrame(False) l.addWidget(sb) w.setLayout(l) return w
def create_spinbox(self, prefix, suffix, option, default=NoDefault, min_=None, max_=None, step=None, tip=None): widget = QWidget(self) if prefix: plabel = QLabel(prefix) widget.plabel = plabel else: plabel = None if suffix: slabel = QLabel(suffix) widget.slabel = slabel else: slabel = None if step is not None: if type(step) is int: spinbox = QSpinBox() else: spinbox = QDoubleSpinBox() spinbox.setDecimals(1) spinbox.setSingleStep(step) else: spinbox = QSpinBox() if min_ is not None: spinbox.setMinimum(min_) if max_ is not None: spinbox.setMaximum(max_) if tip is not None: spinbox.setToolTip(tip) self.spinboxes[spinbox] = (option, default) layout = QHBoxLayout() for subwidget in (plabel, spinbox, slabel): if subwidget is not None: layout.addWidget(subwidget) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) widget.spinbox = spinbox widget.setLayout(layout) return widget
class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('JSON valid') JSON_INVALID = _('JSON invalid') def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) self.parent = parent self.external = external bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = bbox.button(QDialogButtonBox.Ok) self.button_cancel = bbox.button(QDialogButtonBox.Cancel) self.button_ok.setEnabled(False) description = _('To create a new configuration, ' 'you need to select a programming ' 'language, along with a executable ' 'name for the server to execute ' '(If the instance is local), ' 'and the host and port. Finally, ' 'you need to provide the ' 'arguments that the server accepts. ' 'The placeholders <tt>%(host)s</tt> and ' '<tt>%(port)s</tt> refer to the host ' 'and the port, respectively.') server_settings_description = QLabel(description) server_settings_description.setWordWrap(True) lang_label = QLabel(_('Language:')) self.lang_cb = QComboBox(self) self.lang_cb.setToolTip(_('Programming language provided ' 'by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.host_input.setToolTip(_('Name of the host that will provide ' 'access to the server')) self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) cmd_label = QLabel(_('Command to execute:')) self.cmd_input = QLineEdit(self) self.cmd_input.setToolTip(_('Command used to start the ' 'LSP server locally')) self.cmd_input.setText(cmd) if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) args_label = QLabel(_('Server arguments:')) self.args_input = QLineEdit(self) self.args_input.setToolTip(_('Additional arguments required to ' 'start the server')) self.args_input.setText(args) conf_label = QLabel(_('LSP Server Configurations:')) self.conf_input = CodeEditor(None) self.conf_input.textChanged.connect(self.validate) color_scheme = CONF.get('color_schemes', 'selected') self.conf_input.setup_editor( language='JSON', color_scheme=color_scheme, wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json') self.conf_input.setToolTip(_('Additional LSP server configurations ' 'set at runtime. JSON required')) conf_text = '{}' try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: pass self.conf_input.set_text(conf_text) self.json_label = QLabel(self.JSON_VALID, self) self.external_cb = QCheckBox(_('External server'), self) self.external_cb.setToolTip(_('Check if the server runs ' 'on a remote location')) self.external_cb.setChecked(external) self.external_cb.stateChanged.connect(self.set_local_options) hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(server_settings_description) vlayout = QVBoxLayout() lang_layout = QVBoxLayout() lang_layout.addWidget(lang_label) lang_layout.addWidget(self.lang_cb) # layout2 = QHBoxLayout() # layout2.addLayout(lang_layout) lang_layout.addWidget(self.external_cb) vlayout.addLayout(lang_layout) host_layout = QVBoxLayout() host_layout.addWidget(host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) vlayout.addLayout(conn_info_layout) cmd_layout = QVBoxLayout() cmd_layout.addWidget(cmd_label) cmd_layout.addWidget(self.cmd_input) vlayout.addLayout(cmd_layout) args_layout = QVBoxLayout() args_layout.addWidget(args_label) args_layout.addWidget(self.args_input) vlayout.addLayout(args_layout) conf_layout = QVBoxLayout() conf_layout.addWidget(conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) hlayout.addLayout(vlayout) hlayout.addLayout(conf_layout) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(bbox) self.setLayout(general_vlayout) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.lang_cb.currentIndexChanged.connect( self.lang_selection_changed) self.form_status(False) if language is not None: self.form_status(True) self.validate() @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet("QLineEdit{border: 1px solid red;}") self.host_input.setToolTip('Hostname must be valid') return else: self.host_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.host_input.setToolTip('Hostname is valid') self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Command must be non empty') return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Program was not found ' 'on your system') return else: self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.cmd_input.setToolTip('Program was found on your system') self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except: pass except (ValueError, json.decoder.JSONDecodeError): try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) try: self.validate() except: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, configurations=configurations) return server
class QtLabelsControls(QtLayerControls): def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect(self._on_selection_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contig_change) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.layer.events.editable.connect(self._on_editable_change) # shuffle colormap button self.colormapUpdate = QPushButton('shuffle colors') self.colormapUpdate.setObjectName('shuffle') self.colormapUpdate.clicked.connect(self.changeColor) self.colormapUpdate.setFixedHeight(28) # selection spinbox self.selectionSpinBox = QSpinBox() self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.setSingleStep(1) self.selectionSpinBox.setMinimum(0) self.selectionSpinBox.setMaximum(2147483647) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self._on_selection_change(None) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged[int].connect(lambda value=sld: self.changeSize(value)) self.brushSizeSlider = sld self._on_brush_size_change(None) contig_cb = QCheckBox() contig_cb.setToolTip('contiguous editing') contig_cb.stateChanged.connect( lambda state=contig_cb: self.change_contig(state)) self.contigCheckBox = contig_cb self._on_contig_change(None) ndim_cb = QCheckBox() ndim_cb.setToolTip('n-dimensional editing') ndim_cb.stateChanged.connect( lambda state=ndim_cb: self.change_ndim(state)) self.ndimCheckBox = ndim_cb self._on_n_dim_change(None) self.panzoom_button = QtModeButton(layer, 'zoom', Mode.PAN_ZOOM, 'Pan/zoom mode') self.pick_button = QtModeButton(layer, 'picker', Mode.PICKER, 'Pick mode') self.paint_button = QtModeButton(layer, 'paint', Mode.PAINT, 'Paint mode') self.fill_button = QtModeButton(layer, 'fill', Mode.FILL, 'Fill mode') self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.panzoom_button.setChecked(True) self._on_editable_change(None) button_row = QHBoxLayout() button_row.addWidget(self.pick_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.panzoom_button) button_row.addStretch(1) button_row.setSpacing(4) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 1, 1, 2) self.grid_layout.addWidget(self.colormapUpdate, 0, 0) self.grid_layout.addWidget(QLabel('label:'), 1, 0) self.grid_layout.addWidget(self.selectionSpinBox, 1, 2) self.grid_layout.addWidget(QtColorBox(layer), 1, 1) self.grid_layout.addWidget(QLabel('opacity:'), 2, 0) self.grid_layout.addWidget(self.opacitySilder, 2, 1, 1, 2) self.grid_layout.addWidget(QLabel('brush size:'), 3, 0) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 2) self.grid_layout.addWidget(QLabel('blending:'), 4, 0) self.grid_layout.addWidget(self.blendComboBox, 4, 1, 1, 2) self.grid_layout.addWidget(QLabel('contiguous:'), 5, 0) self.grid_layout.addWidget(self.contigCheckBox, 5, 1) self.grid_layout.addWidget(QLabel('n-dim:'), 6, 0) self.grid_layout.addWidget(self.ndimCheckBox, 6, 1) self.grid_layout.setRowStretch(7, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def mouseMoveEvent(self, event): self.layer.status = str(self.layer.mode) def _on_mode_change(self, event): mode = event.mode if mode == Mode.PAN_ZOOM: self.panzoom_button.setChecked(True) elif mode == Mode.PICKER: self.pick_button.setChecked(True) elif mode == Mode.PAINT: self.paint_button.setChecked(True) elif mode == Mode.FILL: self.fill_button.setChecked(True) else: raise ValueError("Mode not recongnized") def changeColor(self): self.layer.new_colormap() def changeSelection(self, value): self.layer.selected_label = value self.selectionSpinBox.clearFocus() self.setFocus() def changeSize(self, value): self.layer.brush_size = value def change_contig(self, state): if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def _on_selection_change(self, event): with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selectionSpinBox.setValue(int(value)) def _on_brush_size_change(self, event): with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brushSizeSlider.setValue(value) def _on_n_dim_change(self, event): with self.layer.events.n_dimensional.blocker(): self.ndimCheckBox.setChecked(self.layer.n_dimensional) def _on_contig_change(self, event): with self.layer.events.contiguous.blocker(): self.contigCheckBox.setChecked(self.layer.contiguous) def _on_editable_change(self, event): self.pick_button.setEnabled(self.layer.editable) self.paint_button.setEnabled(self.layer.editable) self.fill_button.setEnabled(self.layer.editable)
class ImageRotationDialog(ExToolWindow): def __init__(self, signal, axes, parent, plugin): super(ImageRotationDialog, self).__init__(parent) self.ui = parent self.create_controls() self.accepted.connect(self.ok) self.rejected.connect(self.close_new) self.signal = signal self.plugin = plugin self.new_out = None self._connected_updates = False if isinstance(axes, str): axm = signal.signal.axes_manager if axes.startswith("nav"): axes = (axm._axes.index(axm.navigation_axes[0]), axm._axes.index(axm.navigation_axes[1])) elif axes.startswith("sig"): axes = (axm._axes.index(axm.signal_axes[0]), axm._axes.index(axm.signal_axes[1])) self.axes = axes self.setWindowTitle(tr("Rotate")) # TODO: TAG: Functionality check if not hasattr(signal.signal, 'events'): self.gbo_preview.setVisible(False) # TODO: Add dynamic rotation, e.g. one that rotates when source # signal's data_changed event triggers def connect(self): # TODO: Don't have to con/dis those in gbo self.opt_new.toggled.connect(self.close_new) self.num_angle.valueChanged.connect(self.update) self.chk_grid.toggled.connect(self.update) self.num_grid.valueChanged.connect(self.update) self.chk_reshape.toggled.connect(self.update) self.opt_new.toggled.connect(self.update) self.opt_replace.toggled.connect(self.update) def disconnect(self): self.num_angle.valueChanged.disconnect(self.update) self.chk_grid.toggled.disconnect(self.update) self.num_grid.valueChanged.disconnect(self.update) self.chk_reshape.toggled.disconnect(self.update) self.opt_new.toggled.disconnect(self.update) self.opt_replace.toggled.disconnect(self.update) def ok(self): # Draw figure if not already done # TODO: TAG: Functionality check if not hasattr(self.signal.signal, 'events') or \ not self.gbo_preview.isChecked(): self.update() angle = self.num_angle.value() reshape = self.chk_reshape.isChecked() self.plugin.record_code( r"<p>.rotate_signal({0}, reshape={1}, axes={2})".format( angle, reshape, self.axes)) # Clean up event connections if self.new_out is not None: self.connect_update_plot(self.new_out.signal, disconnect=True) def close_new(self, value=False): if self.new_out is not None and not value: self.new_out.close() self.new_out = None self._connected_updates = False def set_preview(self, value): if not hasattr(self.signal.signal, 'events'): return if value: self.connect() self.update() else: self.disconnect() self.close_new() def _axes_in_nav(self): axm = self.signal.signal.axes_manager navidx = [axm._axes.index(ax) for ax in axm.navigation_axes] if self.axes[0] in navidx: return True return False def connect_update_plot(self, signal, disconnect=False): if self._connected_updates != disconnect: return # Nothing to do, prevent double connections if self._axes_in_nav(): f = signal._plot.navigator_plot.update else: f = signal._plot.signal_plot.update # TODO: TAG: Functionality check if hasattr(signal, 'events') and hasattr(signal.events, 'data_changed'): if disconnect: signal.events.data_changed.disconnect(f) else: signal.events.data_changed.connect(f, []) self._connected_updates = not disconnect def update(self): angle = self.num_angle.value() reshape = self.chk_reshape.isChecked() if self.opt_new.isChecked(): if self.new_out is None: out = None else: out = self.new_out.signal elif self.opt_replace.isChecked(): out = self.signal.signal else: return # Indeterminate state, do nothing s = self.plugin.rotate_signal(angle, self.signal.signal, record=False, reshape=reshape, out=out, axes=self.axes) if out is None: s.metadata.General.title = self.signal.name + "[Rotated]" s.plot() self.connect_update_plot(s) if (self.gbo_preview.isChecked() and self.opt_new.isChecked() and self.new_out is None): self.new_out = self.ui.lut_signalwrapper[s] else: s = out if self.chk_grid.isChecked() is True: pass # TODO: Draw grid def create_controls(self): """ Create UI controls. """ vbox = QVBoxLayout() form = QFormLayout() self.num_angle = QDoubleSpinBox() self.num_angle.setValue(0.0) self.num_angle.setMinimum(-360) self.num_angle.setMaximum(360) form.addRow(tr("Angle:"), self.num_angle) vbox.addLayout(form) self.gbo_preview = QGroupBox(tr("Preview")) self.gbo_preview.setCheckable(True) self.gbo_preview.setChecked(False) gbo_vbox = QVBoxLayout() self.chk_grid = QCheckBox(tr("Grid")) self.chk_grid.setChecked(False) self.num_grid = QSpinBox() self.num_grid.setValue(4) self.num_grid.setMinimum(1) self.num_grid.setEnabled(False) self.chk_grid.toggled[bool].connect(self.num_grid.setEnabled) gbo_vbox.addWidget(self.chk_grid) gbo_vbox.addWidget(self.num_grid) self.gbo_preview.setLayout(gbo_vbox) vbox.addWidget(self.gbo_preview) self.gbo_preview.toggled[bool].connect(self.set_preview) self.gbo_output = QGroupBox(tr("Output")) self.opt_new = QRadioButton(tr("New signal")) self.opt_replace = QRadioButton(tr("In place")) self.opt_new.setChecked(True) gbo_vbox2 = QVBoxLayout() gbo_vbox2.addWidget(self.opt_new) gbo_vbox2.addWidget(self.opt_replace) self.gbo_output.setLayout(gbo_vbox2) vbox.addWidget(self.gbo_output) self.chk_reshape = QCheckBox(tr("Resize to fit")) self.chk_reshape.setChecked(False) vbox.addWidget(self.chk_reshape) self.btn_ok = QPushButton(tr("&OK")) self.btn_ok.setDefault(True) self.btn_ok.clicked.connect(self.accept) self.btn_cancel = QPushButton(tr("&Cancel")) self.btn_cancel.clicked.connect(self.reject) hbox = QHBoxLayout() hbox.addWidget(self.btn_ok) hbox.addWidget(self.btn_cancel) vbox.addLayout(hbox) vbox.addStretch(1) self.setLayout(vbox)
class NewConfigurationDialog(QDialog): """A dialog for selecting defaults for a new configuration.""" def __init__(self, configuration_path, parent=None): QDialog.__init__(self, parent) self.setModal(True) self.setWindowTitle("New configuration file") self.setMinimumWidth(250) self.setMinimumHeight(150) layout = QFormLayout() directory, filename = os.path.split(configuration_path) if directory.strip() == "": directory = os.path.abspath(os.curdir) self.configuration_path = "%s/%s" % (directory, filename) else: self.configuration_path = configuration_path configuration_location = QLabel() configuration_location.setText(directory) configuration_name = QLabel() configuration_name.setText(filename) self.num_realizations = QSpinBox() self.num_realizations.setMinimum(1) self.num_realizations.setMaximum(1000) self.num_realizations.setValue(10) self.storage_path = QLineEdit() self.storage_path.setText("Storage") self.storage_path.textChanged.connect(self._validateName) layout.addRow(createSpace(10)) layout.addRow("Configuration name:", configuration_name) layout.addRow("Configuration location:", configuration_location) layout.addRow("Path to store DBase:", self.storage_path) layout.addRow("Number of realizations", self.num_realizations) layout.addRow(createSpace(10)) buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.ok_button = buttons.button(QDialogButtonBox.Ok) layout.addRow(buttons) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) self.setLayout(layout) def getNumberOfRealizations(self): return self.num_realizations.value() def getConfigurationPath(self): return self.configuration_path def getStoragePath(self): """Return the DBase storage path""" return str(self.storage_path.text()).strip() def _validateName(self, name): name = str(name) enabled = len(name) > 0 and name.find(" ") == -1 self.ok_button.setEnabled(enabled)
def _setupUi(self): title = QLabel(self.title, self, alignment=Qt.AlignCenter) title.setStyleSheet("font-weight: bold;") title.setSizePolicy(QSzPlcy.Preferred, QSzPlcy.Maximum) # limit setpoints self._wid_lims = QGroupBox('Select Thresholds: ') lay_lims = QGridLayout(self._wid_lims) lay_lims.setAlignment(Qt.AlignTop) row = 0 if 'sum' in self.metric: text = '\nThresholds must be set in Monit1 rate\n'\ 'counts. Here we make available you \n'\ 'to read Sum-Mon values, in Monit rate\n'\ 'counts, and convert them to Monit1\n'\ 'rate counts using calibration curves.\n'\ 'You can also apply a scale factor to\n'\ 'the values read.\n\n' self._label_help = QLabel(text, self) lay_lims.addWidget(self._label_help, row, 0, 1, 2) row += 1 self._pb_get = QPushButton('Get current Sum-Mon', self) self._pb_get.released.connect(self._get_new_sum) lay_lims.addWidget(self._pb_get, row, 0, 1, 2) row += 1 self._label_getsts = QLabel('\n', self) lay_lims.addWidget(self._label_getsts, row, 0, 1, 2) row += 1 self._label_scl = QLabel('Scale: ', self) lay_lims.addWidget(self._label_scl, row, 0) self._spin_scl = QDoubleSpinBox(self) self._spin_scl.setDecimals(2) self._spin_scl.setValue(1.00) self._spin_scl.setMinimum(-100.00) self._spin_scl.setMaximum(+100.00) lay_lims.addWidget(self._spin_scl, row, 1) else: self._head_value = QLabel('Value', self, alignment=Qt.AlignCenter) lay_lims.addWidget(self._head_value, 0, 1) self._head_send = QLabel('Apply', self, alignment=Qt.AlignCenter) lay_lims.addWidget(self._head_send, 0, 2) self._spins, self._checks = dict(), dict() for lsp in self.lim_sp: row += 1 text = lsp.split('-')[0].split('Lmt')[1] + ' [nm]: ' label = QLabel(text, self, alignment=Qt.AlignRight) lay_lims.addWidget(label, row, 0) spin = QSpinBox(self) self._spins[lsp] = spin spin.setValue(0) spin.setMinimum(-1e9) spin.setMaximum(1e9) lay_lims.addWidget(spin, row, 1) check = QCheckBox(self) self._checks[lsp] = check lay_lims.addWidget(check, row, 2, alignment=Qt.AlignCenter) row += 1 self._label_reforb = QLabel( '\nChoose Ref.Orb. to calculate reference\n' + self.title.lower() + ' around which we\napply the values above:') lay_lims.addWidget(self._label_reforb, row, 0, 1, 3) row += 1 self._cb_reforb = RefOrbComboBox(self) self._cb_reforb.refOrbChanged.connect(self._set_ref_orb) lay_lims.addWidget(self._cb_reforb, row, 0, 1, 3) if 'trans' in self.metric: text = '\n\nBPM calculation consider the translation\n' \ 'estimative:' \ '\n\n(pos@downstream+pos@upstream)/2\n\n' \ 'where the pairs upstream/downstream\nfolow:\n' \ ' - M1/M2\n' \ ' - C1-1/C1-2\n' \ ' - C2/C3-1\n' \ ' - C3-2/C4\n' elif 'ang' in self.metric: text = '\n\nBPM calculation consider the angulation\n' \ 'estimative:' \ '\n\n(pos@downstream - pos@upstream)\n\n' \ 'where the pairs upstream/downstream\nfolow:\n' \ ' - M1/M2\n' \ ' - C1-1/C1-2\n' \ ' - C2/C3-1\n' \ ' - C3-2/C4\n' row += 1 self._label_help = QLabel(text, self) lay_lims.addWidget(self._label_help, row, 0, 1, 3) # BPM selection groupsel = QGroupBox('Select BPMs:') groupsel.setObjectName('groupsel') groupsel.setStyleSheet('#groupsel{min-width: 27em; max-width: 27em;}') self._bpm_sel = _BPMSelectionWidget(self, show_toggle_all_false=False, toggle_all_true_text='Select All', prefix=self.prefix) lay_groupsel = QGridLayout(groupsel) lay_groupsel.addWidget(self._bpm_sel) # connect signals and slots self._bpm_sel.applyChangesClicked.connect(self.send_value) lay = QGridLayout(self) lay.addWidget(title, 0, 0, 1, 2) lay.addWidget(self._wid_lims, 1, 0) lay.addWidget(groupsel, 1, 1)
class IteratedEnsembleSmootherPanel(SimulationConfigPanel): analysis_module_name = "IES_ENKF" def __init__(self, facade: LibresFacade, notifier: ErtNotifier): self.facade = facade self.notifier = notifier SimulationConfigPanel.__init__(self, IteratedEnsembleSmoother) layout = QFormLayout() case_selector = CaseSelector(self.facade, notifier) layout.addRow("Current case:", case_selector) run_path_label = QLabel(f"<b>{self.facade.run_path}</b>") addHelpToWidget(run_path_label, "config/simulation/runpath") layout.addRow("Runpath:", run_path_label) number_of_realizations_label = QLabel( f"<b>{self.facade.get_ensemble_size()}</b>") addHelpToWidget(number_of_realizations_label, "config/ensemble/num_realizations") layout.addRow(QLabel("Number of realizations:"), number_of_realizations_label) # The num_iterations_spinner does not track any external changes (will # that ever happen?) self._num_iterations_spinner = QSpinBox() self._num_iterations_spinner.setMinimum(1) self._num_iterations_spinner.setMaximum(100) self._num_iterations_spinner.setValue( self.facade.get_number_of_iterations()) addHelpToWidget(self._num_iterations_spinner, "config/simulation/number_of_iterations") self._num_iterations_spinner.valueChanged[int].connect( self.setNumberIterations) layout.addRow("Number of iterations:", self._num_iterations_spinner) self._iterated_target_case_format_model = TargetCaseModel( self.facade, notifier, format_mode=True) self._iterated_target_case_format_field = StringBox( self._iterated_target_case_format_model, "config/simulation/iterated_target_case_format", ) self._iterated_target_case_format_field.setValidator( ProperNameFormatArgument()) layout.addRow("Target case format:", self._iterated_target_case_format_field) self._analysis_module_edit = AnalysisModuleEdit( self.facade, module_name=IteratedEnsembleSmootherPanel.analysis_module_name, help_link="config/analysis/analysis_module", ) layout.addRow("Analysis module:", self._analysis_module_edit) self._active_realizations_model = ActiveRealizationsModel(self.facade) self._active_realizations_field = StringBox( self._active_realizations_model, "config/simulation/active_realizations") self._active_realizations_field.setValidator( RangeStringArgument(self.facade.get_ensemble_size())) layout.addRow("Active realizations", self._active_realizations_field) self._iterated_target_case_format_field.getValidationSupport( ).validationChanged.connect( # noqa self.simulationConfigurationChanged) self._active_realizations_field.getValidationSupport( ).validationChanged.connect( # noqa self.simulationConfigurationChanged) self.setLayout(layout) def setNumberIterations(self, iteration_count): if iteration_count != self.facade.get_number_of_iterations(): self.facade.get_analysis_config().getAnalysisIterConfig( ).setNumIterations(iteration_count) self.notifier.emitErtChange() def isConfigurationValid(self): return (self._iterated_target_case_format_field.isValid() and self._active_realizations_field.isValid()) def getSimulationArguments(self): return Arguments( mode="iterative_ensemble_smoother", target_case=self._iterated_target_case_format_model.getValue(), realizations=self._active_realizations_field.text(), num_iterations=self._num_iterations_spinner.value(), )
class PreferencesWindow(PyDialog): """ +-------------+ | Preferences | +---------------------------------+ | Text Size ______ Default | | Annotation Color ______ | | Annotation Size ______ | | Picker Size ______ | | Back Color ______ | | Text Color ______ | | | | Apply OK Cancel | +---------------------------------+ """ def __init__(self, data, win_parent=None): """ Saves the data members from data and performs type checks """ PyDialog.__init__(self, data, win_parent) self._updated_preference = False self._default_font_size = data['font_size'] self._default_text_size = 14 self._default_annotation_size = 18 self._default_coord_scale = 0.05 * 100. self._default_coord_text_scale = 0.5 * 100. self._default_clipping_min = data['min_clip'] self._default_clipping_max = data['max_clip'] #self._default_annotation_size = data['annotation_size'] # int #self.default_magnify = data['magnify'] self.dim_max = data['dim_max'] self._use_gradient_background = data['use_gradient_background'] # bool self._show_corner_coord = data['show_corner_coord'] self._annotation_size = data['annotation_size'] # int #self.out_data = data self._picker_size = data['picker_size'] * 100. self._coord_scale = data['coord_scale'] * 100. self._coord_text_scale = data['coord_text_scale'] * 100. self._magnify = data['magnify'] self._text_size = data['text_size'] self._highlight_opacity = data['highlight_opacity'] self.annotation_color_float, self.annotation_color_int = _check_color( data['annotation_color']) self.background_color_float, self.background_color_int = _check_color( data['background_color']) self.background_color2_float, self.background_color2_int = _check_color( data['background_color2']) self.text_color_float, self.text_color_int = _check_color( data['text_color']) self.highlight_color_float, self.highlight_color_int = _check_color( data['highlight_color']) self._nastran_is_element_quality = data['nastran_is_element_quality'] self._nastran_is_properties = data['nastran_is_properties'] self._nastran_is_3d_bars = data['nastran_is_3d_bars'] self._nastran_is_3d_bars_update = data['nastran_is_3d_bars_update'] self._nastran_is_bar_axes = data['nastran_is_bar_axes'] self._nastran_create_coords = data['nastran_create_coords'] self.setWindowTitle('Preferences') self.create_widgets() self.create_layout() self.set_connections() self.on_font(self._default_font_size) self.on_gradient_scale() #self.show() def create_widgets(self): """creates the display window""" # Text Size self.font_size_label = QLabel("Font Size:") self.font_size_edit = QSpinBox(self) self.font_size_edit.setValue(self._default_font_size) self.font_size_edit.setRange(7, 20) self.font_size_button = QPushButton("Default") #----------------------------------------------------------------------- # Annotation Color self.annotation_color_label = QLabel("Annotation Color:") self.annotation_color_edit = QPushButtonColor( self.annotation_color_int) self.annotation_color_label.hide() self.annotation_color_edit.hide() #----------------------------------------------------------------------- # Text Color self.text_size_label = QLabel("Text Size:") self.text_size_edit = QSpinBox(self) self.text_size_edit.setValue(self._default_text_size) self.text_size_edit.setRange(7, 30) self.text_size_button = QPushButton("Default") # Text Color self.text_color_label = QLabel("Text Color:") self.text_color_edit = QPushButtonColor(self.text_color_int) #----------------------------------------------------------------------- # Highlight Color self.highlight_opacity_label = QLabel("Highlight Opacity:") self.highlight_opacity_edit = QDoubleSpinBox(self) self.highlight_opacity_edit.setValue(self._highlight_opacity) self.highlight_opacity_edit.setRange(0.1, 1.0) self.highlight_opacity_edit.setDecimals(1) self.highlight_opacity_edit.setSingleStep(0.1) self.highlight_opacity_button = QPushButton("Default") # Text Color self.highlight_color_label = QLabel("Highlight Color:") self.highlight_color_edit = QPushButtonColor(self.highlight_color_int) #----------------------------------------------------------------------- # Background Color self.background_color_label = QLabel("Btm Background Color:") self.background_color_edit = QPushButtonColor( self.background_color_int) # Background Color2 self.gradient_scale_label = QLabel("Gradient Background:") self.gradient_scale_checkbox = QCheckBox() self.gradient_scale_checkbox.setChecked(self._use_gradient_background) self.background_color2_label = QLabel("Top Background Color:") self.background_color2_edit = QPushButtonColor( self.background_color2_int) #----------------------------------------------------------------------- # Annotation Size self.annotation_size_label = QLabel("Annotation Size:") self.annotation_size_edit = QSpinBox(self) self.annotation_size_edit.setRange(1, 500) self.annotation_size_edit.setValue(self._annotation_size) self.annotation_size_button = QPushButton("Default") #----------------------------------------------------------------------- # Picker Size self.picker_size_label = QLabel("Picker Size (% of Screen):") self.picker_size_edit = QDoubleSpinBox(self) self.picker_size_edit.setRange(0., 10.) log_dim = log10(self.dim_max) decimals = int(ceil(abs(log_dim))) decimals = max(6, decimals) self.picker_size_edit.setDecimals(decimals) self.picker_size_edit.setSingleStep(10. / 5000.) self.picker_size_edit.setValue(self._picker_size) #----------------------------------------------------------------------- # Clipping Min self.clipping_min_label = QLabel("Clipping Min:") self.clipping_min_edit = QLineEdit(str(self._default_clipping_min)) self.clipping_min_button = QPushButton("Default") # Clipping Max self.clipping_max_label = QLabel("Clipping Max:") self.clipping_max_edit = QLineEdit(str(self._default_clipping_max)) self.clipping_max_button = QPushButton("Default") #----------------------------------------------------------------------- self.coord_scale_label = QLabel('Coordinate System Scale:') self.coord_scale_button = QPushButton("Default") self.coord_scale_edit = QDoubleSpinBox(self) self.coord_scale_edit.setRange(0.1, 1000.) self.coord_scale_edit.setDecimals(3) self.coord_scale_edit.setSingleStep(2.5) self.coord_scale_edit.setValue(self._coord_scale) self.coord_text_scale_label = QLabel('Coordinate System Text Scale:') self.coord_text_scale_button = QPushButton("Default") self.coord_text_scale_edit = QDoubleSpinBox(self) self.coord_text_scale_edit.setRange(0.1, 2000.) self.coord_text_scale_edit.setDecimals(3) self.coord_text_scale_edit.setSingleStep(2.5) self.coord_text_scale_edit.setValue(self._coord_text_scale) # Show corner coord self.corner_coord_label = QLabel("Show Corner Coordinate System:") self.corner_coord_checkbox = QCheckBox() self.corner_coord_checkbox.setChecked(self._show_corner_coord) #----------------------------------------------------------------------- self.magnify_label = QLabel('Screenshot Magnify:') self.magnify_edit = QSpinBox(self) self.magnify_edit.setMinimum(1) self.magnify_edit.setMaximum(10) self.magnify_edit.setValue(self._magnify) #----------------------------------------------------------------------- self.nastran_is_element_quality_checkbox = QCheckBox('Element Quality') self.nastran_is_properties_checkbox = QCheckBox('Properties') self.nastran_is_3d_bars_checkbox = QCheckBox('3D Bars') self.nastran_is_3d_bars_update_checkbox = QCheckBox('Update 3D Bars') self.nastran_create_coords_checkbox = QCheckBox('Coords') self.nastran_is_bar_axes_checkbox = QCheckBox('Bar Axes') self.nastran_is_3d_bars_checkbox.setDisabled(True) self.nastran_is_3d_bars_update_checkbox.setDisabled(True) #self.nastran_is_bar_axes_checkbox.setDisabled(True) self.nastran_is_element_quality_checkbox.setChecked( self._nastran_is_element_quality) self.nastran_is_properties_checkbox.setChecked( self._nastran_is_properties) self.nastran_is_3d_bars_checkbox.setChecked(self._nastran_is_3d_bars) #self.nastran_is_3d_bars_update_checkbox.setChecked(self._nastran_is_3d_bars_update) self.nastran_is_3d_bars_update_checkbox.setChecked(False) self.nastran_is_bar_axes_checkbox.setChecked(self._nastran_is_bar_axes) self.nastran_create_coords_checkbox.setChecked( self._nastran_create_coords) #----------------------------------------------------------------------- # closing self.apply_button = QPushButton("Apply") self.ok_button = QPushButton("OK") self.cancel_button = QPushButton("Cancel") #def create_legend_widgets(self): #""" #Creates the widgets for the legend control #Name Itailic Bold Font #==== ======= ===== ======== #Title check check pulldown #Label check check pulldown #""" #self.name_label = QLabel("Name:") #self.italic_label = QLabel("Italic:") #self.bold_label = QLabel("Bold:") #self.font_label = QLabel("Font:") #self.legend_label = QLabel("Legend:") #self.legend_title_name = QLabel("Title") #self.legend_title_italic_check = QCheckBox() #self.legend_title_bold_check = QCheckBox() #self.legend_title_font_edit = QComboBox() #self.legend_title_font_edit.addItems(['cat', 'dog', 'frog']) #self.legend_label_italic_name = QLabel("Label") #self.legend_label_italic_check = QCheckBox() #self.legend_label_bold_check = QCheckBox() #self.legend_label_font_edit = QComboBox() #self.legend_label_font_edit.addItems(['cat2', 'dog2', 'frog2']) #def create_legend_layout(self): #""" #Creates the layout for the legend control #Name Itailic Bold Font #==== ======= ===== ======== #Title check check pulldown #Label check check pulldown #""" #grid2 = QGridLayout() #grid2.addWidget(self.legend_label, 0, 0) #grid2.addWidget(self.name_label, 1, 0) #grid2.addWidget(self.italic_label, 1, 1) #grid2.addWidget(self.bold_label, 1, 2) #grid2.addWidget(self.font_label, 1, 3) #grid2.addWidget(self.legend_title_name, 2, 0) #grid2.addWidget(self.legend_title_italic_check, 2, 1) #grid2.addWidget(self.legend_title_bold_check, 2, 2) #grid2.addWidget(self.legend_title_font_edit, 2, 3) #grid2.addWidget(self.legend_label_italic_name, 3, 0) #grid2.addWidget(self.legend_label_italic_check, 3, 1) #grid2.addWidget(self.legend_label_bold_check, 3, 2) #grid2.addWidget(self.legend_label_font_edit, 3, 3) #return grid2 def create_layout(self): grid = QGridLayout() irow = 0 grid.addWidget(self.font_size_label, irow, 0) grid.addWidget(self.font_size_edit, irow, 1) grid.addWidget(self.font_size_button, irow, 2) irow += 1 grid.addWidget(self.gradient_scale_label, irow, 0) grid.addWidget(self.gradient_scale_checkbox, irow, 1) irow += 1 grid.addWidget(self.background_color2_label, irow, 0) grid.addWidget(self.background_color2_edit, irow, 1) irow += 1 grid.addWidget(self.background_color_label, irow, 0) grid.addWidget(self.background_color_edit, irow, 1) irow += 1 grid.addWidget(self.highlight_color_label, irow, 0) grid.addWidget(self.highlight_color_edit, irow, 1) irow += 1 grid.addWidget(self.highlight_opacity_label, irow, 0) grid.addWidget(self.highlight_opacity_edit, irow, 1) irow += 1 grid.addWidget(self.text_color_label, irow, 0) grid.addWidget(self.text_color_edit, irow, 1) irow += 1 grid.addWidget(self.text_size_label, irow, 0) grid.addWidget(self.text_size_edit, irow, 1) grid.addWidget(self.text_size_button, irow, 2) irow += 1 grid.addWidget(self.annotation_color_label, irow, 0) grid.addWidget(self.annotation_color_edit, irow, 1) irow += 1 grid.addWidget(self.annotation_size_label, irow, 0) grid.addWidget(self.annotation_size_edit, irow, 1) grid.addWidget(self.annotation_size_button, irow, 2) irow += 1 #grid.addWidget(self.clipping_min_label, irow, 0) #grid.addWidget(self.clipping_min_edit, irow, 1) #grid.addWidget(self.clipping_min_button, irow, 2) #irow += 1 #grid.addWidget(self.clipping_max_label, irow, 0) #grid.addWidget(self.clipping_max_edit, irow, 1) #grid.addWidget(self.clipping_max_button, irow, 2) #irow += 1 grid.addWidget(self.corner_coord_label, irow, 0) grid.addWidget(self.corner_coord_checkbox, irow, 1) irow += 1 grid.addWidget(self.coord_scale_label, irow, 0) grid.addWidget(self.coord_scale_edit, irow, 1) grid.addWidget(self.coord_scale_button, irow, 2) irow += 1 grid.addWidget(self.coord_text_scale_label, irow, 0) grid.addWidget(self.coord_text_scale_edit, irow, 1) grid.addWidget(self.coord_text_scale_button, irow, 2) irow += 1 #----------------------------------------------- grid.addWidget(self.magnify_label, irow, 0) grid.addWidget(self.magnify_edit, irow, 1) irow += 1 grid.addWidget(self.picker_size_label, irow, 0) grid.addWidget(self.picker_size_edit, irow, 1) irow += 1 #-------------------------------------------------- grid_nastran = QGridLayout() irow = 0 grid_nastran.addWidget(self.nastran_create_coords_checkbox, irow, 0) irow += 1 grid_nastran.addWidget(self.nastran_is_element_quality_checkbox, irow, 0) grid_nastran.addWidget(self.nastran_is_properties_checkbox, irow, 1) irow += 1 grid_nastran.addWidget(self.nastran_is_bar_axes_checkbox, irow, 0) irow += 1 grid_nastran.addWidget(self.nastran_is_3d_bars_checkbox, irow, 0) grid_nastran.addWidget(self.nastran_is_3d_bars_update_checkbox, irow, 1) irow += 1 #bold_font = make_font(self._default_font_size, is_bold=True) vbox_nastran = QVBoxLayout() self.nastran_label = QLabel('Nastran:') vbox_nastran.addWidget(self.nastran_label) vbox_nastran.addLayout(grid_nastran) #self.create_legend_widgets() #grid2 = self.create_legend_layout() ok_cancel_box = QHBoxLayout() ok_cancel_box.addWidget(self.apply_button) ok_cancel_box.addWidget(self.ok_button) ok_cancel_box.addWidget(self.cancel_button) vbox = QVBoxLayout() vbox.addLayout(grid) vbox.addLayout(vbox_nastran) #vbox.addStretch() #vbox.addLayout(grid2) vbox.addStretch() vbox.addLayout(ok_cancel_box) self.setLayout(vbox) def set_connections(self): """creates the actions for the menu""" self.font_size_button.clicked.connect(self.on_default_font_size) self.font_size_edit.valueChanged.connect(self.on_font) self.annotation_size_edit.editingFinished.connect( self.on_annotation_size) self.annotation_size_edit.valueChanged.connect(self.on_annotation_size) self.annotation_color_edit.clicked.connect(self.on_annotation_color) self.annotation_size_button.clicked.connect( self.on_default_annotation_size) self.background_color_edit.clicked.connect(self.on_background_color) self.background_color2_edit.clicked.connect(self.on_background_color2) self.gradient_scale_checkbox.clicked.connect(self.on_gradient_scale) self.highlight_color_edit.clicked.connect(self.on_highlight_color) self.highlight_opacity_edit.valueChanged.connect( self.on_highlight_opacity) self.text_color_edit.clicked.connect(self.on_text_color) self.text_size_edit.valueChanged.connect(self.on_text_size) self.text_size_button.clicked.connect(self.on_default_text_size) self.picker_size_edit.valueChanged.connect(self.on_picker_size) self.picker_size_edit.editingFinished.connect(self.on_picker_size) self.coord_scale_edit.valueChanged.connect(self.on_coord_scale) self.coord_scale_edit.editingFinished.connect(self.on_coord_scale) self.coord_scale_button.clicked.connect(self.on_default_coord_scale) self.corner_coord_checkbox.clicked.connect(self.on_corner_coord) self.coord_text_scale_edit.valueChanged.connect( self.on_coord_text_scale) self.coord_text_scale_edit.editingFinished.connect( self.on_coord_text_scale) self.coord_text_scale_button.clicked.connect( self.on_default_coord_text_scale) self.magnify_edit.valueChanged.connect(self.on_magnify) self.magnify_edit.editingFinished.connect(self.on_magnify) self.clipping_min_button.clicked.connect(self.on_default_clipping_min) self.clipping_max_button.clicked.connect(self.on_default_clipping_max) #------------------------------------ # format-specific self.nastran_is_element_quality_checkbox.clicked.connect( self.on_nastran_is_element_quality) self.nastran_is_properties_checkbox.clicked.connect( self.on_nastran_is_properties) self.nastran_is_3d_bars_checkbox.clicked.connect( self.on_nastran_is_3d_bars) self.nastran_is_3d_bars_update_checkbox.clicked.connect( self.on_nastran_is_3d_bars) self.nastran_is_bar_axes_checkbox.clicked.connect( self.on_nastran_is_bar_axes) self.nastran_create_coords_checkbox.clicked.connect( self.on_nastran_create_coords) #------------------------------------ self.apply_button.clicked.connect(self.on_apply) self.ok_button.clicked.connect(self.on_ok) self.cancel_button.clicked.connect(self.on_cancel) # closeEvent def on_nastran_is_element_quality(self): """set the nastran element quality preferences""" is_checked = self.nastran_is_element_quality_checkbox.isChecked() if self.win_parent is not None: self.win_parent.settings.nastran_is_element_quality = is_checked def on_nastran_is_properties(self): """set the nastran properties preferences""" is_checked = self.nastran_is_properties_checkbox.isChecked() if self.win_parent is not None: self.win_parent.settings.nastran_is_properties = is_checked def on_nastran_is_3d_bars(self): """set the nastran properties preferences""" is_checked = self.nastran_is_3d_bars_checkbox.isChecked() if self.win_parent is not None: self.win_parent.settings.nastran_is_3d_bars = is_checked def on_nastran_is_3d_bars_update(self): """set the nastran properties preferences""" is_checked = self.nastran_is_3d_bars_update_checkbox.isChecked() if self.win_parent is not None: self.win_parent.settings.nastran_is_3d_bars_update = is_checked def on_nastran_is_bar_axes(self): """set the nastran properties preferences""" is_checked = self.nastran_is_bar_axes_checkbox.isChecked() if self.win_parent is not None: self.win_parent.settings.nastran_is_bar_axes = is_checked def on_nastran_create_coords(self): """set the nastran properties preferences""" is_checked = self.nastran_create_coords_checkbox.isChecked() if self.win_parent is not None: self.win_parent.settings.nastran_create_coords = is_checked def on_font(self, value=None): """update the font for the current window""" if value is None: value = self.font_size_edit.value() font = QtGui.QFont() font.setPointSize(value) self.setFont(font) bold_font = make_font(value, is_bold=True) self.nastran_label.setFont(bold_font) def on_annotation_size(self, value=None): """update the annotation size""" if value is None: value = int(self.annotation_size_edit.text()) self._annotation_size = value #self.on_apply(force=True) #self.min_edit.setText(str(self._default_min)) #self.min_edit.setStyleSheet("QLineEdit{background: white;}") self.update_annotation_size_color() def update_annotation_size_color(self): if self.win_parent is not None: self.win_parent.settings.set_annotation_size_color( size=self._annotation_size) def on_gradient_scale(self): is_checked = self.gradient_scale_checkbox.isChecked() self.background_color2_label.setEnabled(is_checked) self.background_color2_edit.setEnabled(is_checked) if self.win_parent is not None: self.win_parent.settings.set_gradient_background( use_gradient_background=is_checked) def on_corner_coord(self): is_checked = self.corner_coord_checkbox.isChecked() if self.win_parent is not None: self.win_parent.set_corner_axis_visiblity(is_checked, render=True) def on_annotation_color(self): rgb_color_ints = self.annotation_color_int title = "Choose an annotation color" passed, rgb_color_ints, rgb_color_floats = self.on_color( self.annotation_color_edit, rgb_color_ints, title) if passed: self.annotation_color_int = rgb_color_ints self.annotation_color_float = rgb_color_floats self.update_annotation_size_color() def on_background_color(self): """ Choose a background color""" title = "Choose a primary background color" rgb_color_ints = self.background_color_int color_edit = self.background_color_edit func_name = 'set_background_color' passed, rgb_color_ints, rgb_color_floats = self._background_color( title, color_edit, rgb_color_ints, func_name) if passed: self.background_color_int = rgb_color_ints self.background_color_float = rgb_color_floats def on_background_color2(self): """ Choose a background color""" title = "Choose a secondary background color" rgb_color_ints = self.background_color2_int color_edit = self.background_color2_edit func_name = 'set_background_color2' passed, rgb_color_ints, rgb_color_floats = self._background_color( title, color_edit, rgb_color_ints, func_name) if passed: self.background_color2_int = rgb_color_ints self.background_color2_float = rgb_color_floats def on_highlight_color(self): """ Choose a highlight color""" title = "Choose a highlight color" rgb_color_ints = self.highlight_color_int color_edit = self.highlight_color_edit func_name = 'set_highlight_color' passed, rgb_color_ints, rgb_color_floats = self._background_color( title, color_edit, rgb_color_ints, func_name) if passed: self.highlight_color_int = rgb_color_ints self.highlight_color_float = rgb_color_floats def on_highlight_opacity(self, value=None): if value is None: value = self.highlight_opacity_edit.value() self._highlight_opacity = value if self.win_parent is not None: self.win_parent.settings.set_highlight_opacity(value) def _background_color(self, title, color_edit, rgb_color_ints, func_name): """helper method for ``on_background_color`` and ``on_background_color2``""" passed, rgb_color_ints, rgb_color_floats = self.on_color( color_edit, rgb_color_ints, title) if passed: if self.win_parent is not None: settings = self.win_parent.settings func_background_color = getattr(settings, func_name) func_background_color(rgb_color_floats) return passed, rgb_color_ints, rgb_color_floats def on_text_color(self): """ Choose a text color """ rgb_color_ints = self.text_color_int title = "Choose a text color" passed, rgb_color_ints, rgb_color_floats = self.on_color( self.text_color_edit, rgb_color_ints, title) if passed: self.text_color_int = rgb_color_ints self.text_color_float = rgb_color_floats if self.win_parent is not None: self.win_parent.settings.set_text_color(rgb_color_floats) def on_default_text_size(self): self.text_size_edit.setValue(self._default_text_size) self.on_text_size(self._default_text_size) def on_text_size(self, value=None): if value is None: value = self.text_size_edit.value() self._text_size = value if self.win_parent is not None: self.win_parent.settings.set_text_size(value) def on_color(self, color_edit, rgb_color_ints, title): """pops a color dialog""" col = QColorDialog.getColor(QtGui.QColor(*rgb_color_ints), self, title) if not col.isValid(): return False, rgb_color_ints, None color_float = col.getRgbF()[:3] # floats color_int = [int(colori * 255) for colori in color_float] assert isinstance(color_float[0], float), color_float assert isinstance(color_int[0], int), color_int color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(color_int) + #"border:1px solid rgb(255, 170, 255); " "}") return True, color_int, color_float def on_picker_size(self): self._picker_size = float(self.picker_size_edit.text()) if self.win_parent is not None: self.win_parent.element_picker_size = self._picker_size / 100. #self.on_apply(force=True) def on_magnify(self, value=None): if value is None: value = self.magnify_edit.value() self._magnify = value if self.win_parent is not None: self.win_parent.settings.set_magnify(value) #--------------------------------------------------------------------------- def on_coord_scale(self, value=None): if value is None: value = self.coord_scale_edit.value() self._coord_scale = value if self.win_parent is not None: self.win_parent.settings.set_coord_scale(value / 100.) def on_default_coord_scale(self): self.coord_scale_edit.setValue(self._default_coord_scale) self.on_coord_scale(self._default_coord_scale) def on_coord_text_scale(self, value=None): if value is None: value = self.coord_text_scale_edit.value() self._coord_text_scale = value if self.win_parent is not None: self.win_parent.settings.set_coord_text_scale(value / 100.) def on_default_coord_text_scale(self): self.coord_text_scale_edit.setValue(self._default_coord_text_scale) self.on_coord_text_scale(self._default_coord_text_scale) #--------------------------------------------------------------------------- def on_default_font_size(self): self.font_size_edit.setValue(self._default_font_size) self.on_font(self._default_font_size) def on_default_annotation_size(self): self.annotation_size_edit.setValue(self._default_annotation_size) self.on_annotation_size(self._default_annotation_size) def on_default_clipping_min(self): self.clipping_min_edit.setText(str(self._default_clipping_min)) self.clipping_min_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_clipping_max(self): self.clipping_max_edit.setText(str(self._default_clipping_max)) self.clipping_max_edit.setStyleSheet("QLineEdit{background: white;}") def on_validate(self): font_size_value, flag0 = check_float(self.font_size_edit) annotation_size_value, flag1 = check_float(self.annotation_size_edit) assert isinstance(self.annotation_color_float[0], float), self.annotation_color_float assert isinstance(self.annotation_color_int[0], int), self.annotation_color_int picker_size_value, flag2 = check_float(self.picker_size_edit) clipping_min_value, flag3 = check_label_float(self.clipping_min_edit) clipping_max_value, flag4 = check_label_float(self.clipping_max_edit) if all([flag0, flag1, flag2, flag3, flag4]): self._annotation_size = annotation_size_value self._picker_size = picker_size_value self.out_data['font_size'] = int(font_size_value) self.out_data['min_clip'] = min(clipping_min_value, clipping_max_value) self.out_data['max_clip'] = max(clipping_min_value, clipping_max_value) self.out_data['clicked_ok'] = True return True return False def on_apply(self, force=False): passed = self.on_validate() if (passed or force) and self.win_parent is not None: self.win_parent.settings.on_set_font_size( self.out_data['font_size']) #self.win_parent.settings.set_annotation_size_color(self._annotation_size) #self.win_parent.element_picker_size = self._picker_size / 100. if passed and self.win_parent is not None: self.win_parent.clipping_obj.apply_clipping(self.out_data) return passed def on_ok(self): passed = self.on_apply() if passed: self.close() #self.destroy() def on_cancel(self): self.out_data['close'] = True self.close()
class ImageRotationDialog(ExToolWindow): def __init__(self, signal, axes, parent, plugin): super(ImageRotationDialog, self).__init__(parent) self.ui = parent self.create_controls() self.accepted.connect(self.ok) self.rejected.connect(self.close_new) self.signal = signal self.plugin = plugin self.new_out = None self._connected_updates = False if isinstance(axes, str): axm = signal.signal.axes_manager if axes.startswith("nav"): axes = (axm._axes.index(axm.navigation_axes[0]), axm._axes.index(axm.navigation_axes[1])) elif axes.startswith("sig"): axes = (axm._axes.index(axm.signal_axes[0]), axm._axes.index(axm.signal_axes[1])) self.axes = axes self.setWindowTitle(tr("Rotate")) # TODO: TAG: Functionality check if not hasattr(signal.signal, 'events'): self.gbo_preview.setVisible(False) # TODO: Add dynamic rotation, e.g. one that rotates when source # signal's data_changed event triggers def connect(self): # TODO: Don't have to con/dis those in gbo self.opt_new.toggled.connect(self.close_new) self.num_angle.valueChanged.connect(self.update) self.chk_grid.toggled.connect(self.update) self.num_grid.valueChanged.connect(self.update) self.chk_reshape.toggled.connect(self.update) self.opt_new.toggled.connect(self.update) self.opt_replace.toggled.connect(self.update) def disconnect(self): self.num_angle.valueChanged.disconnect(self.update) self.chk_grid.toggled.disconnect(self.update) self.num_grid.valueChanged.disconnect(self.update) self.chk_reshape.toggled.disconnect(self.update) self.opt_new.toggled.disconnect(self.update) self.opt_replace.toggled.disconnect(self.update) def ok(self): # Draw figure if not already done # TODO: TAG: Functionality check if not hasattr(self.signal.signal, 'events') or \ not self.gbo_preview.isChecked(): self.update() angle = self.num_angle.value() reshape = self.chk_reshape.isChecked() self.plugin.record_code( r"<p>.rotate_signal({0}, reshape={1}, axes={2})".format( angle, reshape, self.axes)) # Clean up event connections if self.new_out is not None: self.connect_update_plot(self.new_out.signal, disconnect=True) def close_new(self, value=False): if self.new_out is not None and not value: self.new_out.close() self.new_out = None self._connected_updates = False def set_preview(self, value): if not hasattr(self.signal.signal, 'events'): return if value: self.connect() self.update() else: self.disconnect() self.close_new() def _axes_in_nav(self): axm = self.signal.signal.axes_manager navidx = [axm._axes.index(ax) for ax in axm.navigation_axes] if self.axes[0] in navidx: return True return False def connect_update_plot(self, signal, disconnect=False): if self._connected_updates != disconnect: return # Nothing to do, prevent double connections if self._axes_in_nav(): f = signal._plot.navigator_plot.update else: f = signal._plot.signal_plot.update # TODO: TAG: Functionality check if hasattr(signal, 'events') and hasattr( signal.events, 'data_changed'): if disconnect: signal.events.data_changed.disconnect(f) else: signal.events.data_changed.connect(f, []) self._connected_updates = not disconnect def update(self): angle = self.num_angle.value() reshape = self.chk_reshape.isChecked() if self.opt_new.isChecked(): if self.new_out is None: out = None else: out = self.new_out.signal elif self.opt_replace.isChecked(): out = self.signal.signal else: return # Indeterminate state, do nothing s = self.plugin.rotate_signal(angle, self.signal.signal, record=False, reshape=reshape, out=out, axes=self.axes) if out is None: s.metadata.General.title = self.signal.name + "[Rotated]" s.plot() self.connect_update_plot(s) if (self.gbo_preview.isChecked() and self.opt_new.isChecked() and self.new_out is None): self.new_out = self.ui.lut_signalwrapper[s] else: s = out if self.chk_grid.isChecked() is True: pass # TODO: Draw grid def create_controls(self): """ Create UI controls. """ vbox = QVBoxLayout() form = QFormLayout() self.num_angle = QDoubleSpinBox() self.num_angle.setValue(0.0) self.num_angle.setMinimum(-360) self.num_angle.setMaximum(360) form.addRow(tr("Angle:"), self.num_angle) vbox.addLayout(form) self.gbo_preview = QGroupBox(tr("Preview")) self.gbo_preview.setCheckable(True) self.gbo_preview.setChecked(False) gbo_vbox = QVBoxLayout() self.chk_grid = QCheckBox(tr("Grid")) self.chk_grid.setChecked(False) self.num_grid = QSpinBox() self.num_grid.setValue(4) self.num_grid.setMinimum(1) self.num_grid.setEnabled(False) self.chk_grid.toggled[bool].connect(self.num_grid.setEnabled) gbo_vbox.addWidget(self.chk_grid) gbo_vbox.addWidget(self.num_grid) self.gbo_preview.setLayout(gbo_vbox) vbox.addWidget(self.gbo_preview) self.gbo_preview.toggled[bool].connect(self.set_preview) self.gbo_output = QGroupBox(tr("Output")) self.opt_new = QRadioButton(tr("New signal")) self.opt_replace = QRadioButton(tr("In place")) self.opt_new.setChecked(True) gbo_vbox2 = QVBoxLayout() gbo_vbox2.addWidget(self.opt_new) gbo_vbox2.addWidget(self.opt_replace) self.gbo_output.setLayout(gbo_vbox2) vbox.addWidget(self.gbo_output) self.chk_reshape = QCheckBox(tr("Resize to fit")) self.chk_reshape.setChecked(False) vbox.addWidget(self.chk_reshape) self.btn_ok = QPushButton(tr("&OK")) self.btn_ok.setDefault(True) self.btn_ok.clicked.connect(self.accept) self.btn_cancel = QPushButton(tr("&Cancel")) self.btn_cancel.clicked.connect(self.reject) hbox = QHBoxLayout() hbox.addWidget(self.btn_ok) hbox.addWidget(self.btn_cancel) vbox.addLayout(hbox) vbox.addStretch(1) self.setLayout(vbox)
class QtLabelsControls(QtLayerControls): """Qt view and controls for the napari Labels layer. Parameters ---------- layer : napari.layers.Labels An instance of a napari Labels layer. Attributes ---------- button_group : qtpy.QtWidgets.QButtonGroup Button group of labels layer modes: PAN_ZOOM, PICKER, PAINT, ERASE, or FILL. colormapUpdate : qtpy.QtWidgets.QPushButton Button to update colormap of label layer. contigCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is contiguous. fill_button : qtpy.QtWidgets.QtModeRadioButton Button to select FILL mode on Labels layer. grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Labels An instance of a napari Labels layer. ndimCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is n-dimensional. paint_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAINT mode on Labels layer. panzoom_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAN_ZOOM mode on Labels layer. pick_button : qtpy.QtWidgets.QtModeRadioButton Button to select PICKER mode on Labels layer. erase_button : qtpy.QtWidgets.QtModeRadioButton Button to select ERASE mode on Labels layer. selectionSpinBox : qtpy.QtWidgets.QSpinBox Widget to select a specific label by its index. Raises ------ ValueError Raise error if label mode is not PAN_ZOOM, PICKER, PAINT, ERASE, or FILL. """ def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect( self._on_selected_label_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contiguous_change) self.layer.events.n_dimensional.connect(self._on_n_dimensional_change) self.layer.events.contour.connect(self._on_contour_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.events.preserve_labels.connect( self._on_preserve_labels_change) self.layer.events.color_mode.connect(self._on_color_mode_change) # selection spinbox self.selectionSpinBox = QSpinBox() self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.setSingleStep(1) self.selectionSpinBox.setMinimum(0) self.selectionSpinBox.setMaximum(1024) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self.selectionSpinBox.setAlignment(Qt.AlignCenter) self._on_selected_label_change() sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged.connect(self.changeSize) self.brushSizeSlider = sld self._on_brush_size_change() contig_cb = QCheckBox() contig_cb.setToolTip(trans._('contiguous editing')) contig_cb.stateChanged.connect(self.change_contig) self.contigCheckBox = contig_cb self._on_contiguous_change() ndim_cb = QCheckBox() ndim_cb.setToolTip(trans._('edit all dimensions')) ndim_cb.stateChanged.connect(self.change_ndim) self.ndimCheckBox = ndim_cb self._on_n_dimensional_change() contour_sb = QSpinBox() contour_sb.setToolTip(trans._('display contours of labels')) contour_sb.valueChanged.connect(self.change_contour) self.contourSpinBox = contour_sb self.contourSpinBox.setKeyboardTracking(False) self.contourSpinBox.setSingleStep(1) self.contourSpinBox.setMinimum(0) self.contourSpinBox.setMaximum(2147483647) self.contourSpinBox.setAlignment(Qt.AlignCenter) self._on_contour_change() preserve_labels_cb = QCheckBox() preserve_labels_cb.setToolTip( trans._('preserve existing labels while painting')) preserve_labels_cb.stateChanged.connect(self.change_preserve_labels) self.preserveLabelsCheckBox = preserve_labels_cb self._on_preserve_labels_change() selectedColorCheckbox = QCheckBox() selectedColorCheckbox.setToolTip( trans._("Display only selected label")) selectedColorCheckbox.stateChanged.connect(self.toggle_selected_mode) self.selectedColorCheckbox = selectedColorCheckbox # shuffle colormap button self.colormapUpdate = QtModePushButton( None, 'shuffle', slot=self.changeColor, tooltip=trans._('shuffle colors'), ) self.panzoom_button = QtModeRadioButton( layer, 'zoom', Mode.PAN_ZOOM, tooltip=trans._('Pan/zoom mode (Space)'), checked=True, ) self.pick_button = QtModeRadioButton(layer, 'picker', Mode.PICK, tooltip=trans._('Pick mode (L)')) self.paint_button = QtModeRadioButton( layer, 'paint', Mode.PAINT, tooltip=trans._('Paint mode (P)')) self.fill_button = QtModeRadioButton( layer, 'fill', Mode.FILL, tooltip=trans._("Fill mode (F) \nToggle with {key}".format( key=KEY_SYMBOLS['Control'])), ) self.erase_button = QtModeRadioButton( layer, 'erase', Mode.ERASE, tooltip=trans._("Erase mode (E) \nToggle with {key}".format( key=KEY_SYMBOLS['Alt'])), ) self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.button_group.addButton(self.erase_button) self._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.colormapUpdate) button_row.addWidget(self.erase_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.pick_button) button_row.addWidget(self.panzoom_button) button_row.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) brush_shape_comboBox = QComboBox(self) for index, (data, text) in enumerate(LABEL_BRUSH_SHAPE_TRANSLATIONS.items()): data = data.value brush_shape_comboBox.addItem(text, data) if self.layer.brush_shape == data: brush_shape_comboBox.setCurrentIndex(index) brush_shape_comboBox.activated[str].connect(self.change_brush_shape) self.brushShapeComboBox = brush_shape_comboBox self._on_brush_shape_change() color_mode_comboBox = QComboBox(self) for index, (data, text) in enumerate(LABEL_COLOR_MODE_TRANSLATIONS.items()): data = data.value color_mode_comboBox.addItem(text, data) if self.layer.color_mode == data: color_mode_comboBox.setCurrentIndex(index) color_mode_comboBox.activated[str].connect(self.change_color_mode) self.colorModeComboBox = color_mode_comboBox self._on_color_mode_change() color_layout = QHBoxLayout() self.colorBox = QtColorBox(layer) color_layout.addWidget(self.colorBox) color_layout.addWidget(self.selectionSpinBox) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 0, 1, 4) self.grid_layout.addWidget(QLabel(trans._('label:')), 1, 0, 1, 1) self.grid_layout.addLayout(color_layout, 1, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 2, 0, 1, 1) self.grid_layout.addWidget(self.opacitySlider, 2, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('brush size:')), 3, 0, 1, 1) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('brush shape:')), 4, 0, 1, 1) self.grid_layout.addWidget(self.brushShapeComboBox, 4, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('blending:')), 5, 0, 1, 1) self.grid_layout.addWidget(self.blendComboBox, 5, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('color mode:')), 6, 0, 1, 1) self.grid_layout.addWidget(self.colorModeComboBox, 6, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('contour:')), 7, 0, 1, 1) self.grid_layout.addWidget(self.contourSpinBox, 7, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('contiguous:')), 8, 0, 1, 1) self.grid_layout.addWidget(self.contigCheckBox, 8, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('n-dim:')), 8, 2, 1, 1) self.grid_layout.addWidget(self.ndimCheckBox, 8, 3, 1, 1) self.grid_layout.addWidget(QLabel(trans._('preserve labels:')), 9, 0, 1, 2) self.grid_layout.addWidget(self.preserveLabelsCheckBox, 9, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('show selected:')), 9, 2, 1, 1) self.grid_layout.addWidget(self.selectedColorCheckbox, 9, 3, 1, 1) self.grid_layout.setRowStretch(9, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def _on_mode_change(self, event): """Receive layer model mode change event and update checkbox ticks. Parameters ---------- event : napari.utils.event.Event The napari event that triggered this method. Raises ------ ValueError Raise error if event.mode is not PAN_ZOOM, PICK, PAINT, ERASE, or FILL """ mode = event.mode if mode == Mode.PAN_ZOOM: self.panzoom_button.setChecked(True) elif mode == Mode.PICK: self.pick_button.setChecked(True) elif mode == Mode.PAINT: self.paint_button.setChecked(True) elif mode == Mode.FILL: self.fill_button.setChecked(True) elif mode == Mode.ERASE: self.erase_button.setChecked(True) else: raise ValueError(trans._("Mode not recognized")) def changeColor(self): """Change colormap of the label layer.""" self.layer.new_colormap() def changeSelection(self, value): """Change currently selected label. Parameters ---------- value : int Index of label to select. """ self.layer.selected_label = value self.selectionSpinBox.clearFocus() self.setFocus() def toggle_selected_mode(self, state): if state == Qt.Checked: self.layer.show_selected_label = True else: self.layer.show_selected_label = False def changeSize(self, value): """Change paint brush size. Parameters ---------- value : float Size of the paint brush. """ self.layer.brush_size = value def change_contig(self, state): """Toggle contiguous state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if labels are contiguous. """ if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): """Toggle n-dimensional state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if label layer is n-dimensional. """ if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def change_contour(self, value): """Change contour thickness. Parameters ---------- value : int Thickness of contour. """ self.layer.contour = value self.contourSpinBox.clearFocus() self.setFocus() def change_preserve_labels(self, state): """Toggle preserve_labels state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if overwriting label is enabled. """ if state == Qt.Checked: self.layer.preserve_labels = True else: self.layer.preserve_labels = False def change_color_mode(self, new_mode): """Change color mode of label layer. Parameters ---------- new_mode : str AUTO (default) allows color to be set via a hash function with a seed. DIRECT allows color of each label to be set directly by a color dictionary. """ self.layer.color_mode = self.colorModeComboBox.currentData() def change_brush_shape(self, brush_shape): """Change paintbrush shape of label layer. Parameters ---------- brush_shape : str CIRCLE (default) uses circle paintbrush (case insensitive). SQUARE uses square paintbrush (case insensitive). """ self.layer.brush_shape = self.brushShapeComboBox.currentData() def _on_contour_change(self, event=None): """Receive layer model contour value change event and update spinbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.contour.blocker(): value = self.layer.contour self.contourSpinBox.setValue(int(value)) def _on_selected_label_change(self, event=None): """Receive layer model label selection change event and update spinbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selectionSpinBox.setValue(int(value)) def _on_brush_size_change(self, event=None): """Receive layer model brush size change event and update the slider. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brushSizeSlider.setValue(value) def _on_n_dimensional_change(self, event=None): """Receive layer model n-dim mode change event and update the checkbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.n_dimensional.blocker(): self.ndimCheckBox.setChecked(self.layer.n_dimensional) def _on_contiguous_change(self, event=None): """Receive layer model contiguous change event and update the checkbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.contiguous.blocker(): self.contigCheckBox.setChecked(self.layer.contiguous) def _on_preserve_labels_change(self, event=None): """Receive layer model preserve_labels event and update the checkbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.preserve_labels.blocker(): self.preserveLabelsCheckBox.setChecked(self.layer.preserve_labels) def _on_color_mode_change(self, event=None): """Receive layer model color. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.color_mode.blocker(): # `self.colorModeComboBox.findData` is not returning the correct index. for index in range(self.colorModeComboBox.count()): if self.layer.color_mode == self.colorModeComboBox.itemData( index): self.colorModeComboBox.setCurrentIndex(index) break def _on_brush_shape_change(self, event=None): """Receive brush shape change event and update dropdown menu. Parameters ---------- event : napari.utils.event.Event The napari event that triggered this method. """ with self.layer.events.brush_shape.blocker(): # `self.brushShapeComboBox.findData` is not returning the correct index. for index in range(self.brushShapeComboBox.count()): if self.layer.brush_shape == self.brushShapeComboBox.itemData( index): self.brushShapeComboBox.setCurrentIndex(index) break def _on_editable_change(self, event=None): """Receive layer model editable change event & enable/disable buttons. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ disable_with_opacity( self, ['pick_button', 'paint_button', 'fill_button'], self.layer.editable, )
class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('JSON valid') JSON_INVALID = _('JSON invalid') def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) self.parent = parent self.external = external bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = bbox.button(QDialogButtonBox.Ok) self.button_cancel = bbox.button(QDialogButtonBox.Cancel) self.button_ok.setEnabled(False) description = _('To create a new configuration, ' 'you need to select a programming ' 'language, along with a executable ' 'name for the server to execute ' '(If the instance is local), ' 'and the host and port. Finally, ' 'you need to provide the ' 'arguments that the server accepts. ' 'The placeholders <tt>%(host)s</tt> and ' '<tt>%(port)s</tt> refer to the host ' 'and the port, respectively.') server_settings_description = QLabel(description) server_settings_description.setWordWrap(True) lang_label = QLabel(_('Language:')) self.lang_cb = QComboBox(self) self.lang_cb.setToolTip(_('Programming language provided ' 'by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.host_input.setToolTip(_('Name of the host that will provide ' 'access to the server')) self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) cmd_label = QLabel(_('Command to execute:')) self.cmd_input = QLineEdit(self) self.cmd_input.setToolTip(_('Command used to start the ' 'LSP server locally')) self.cmd_input.setText(cmd) if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) args_label = QLabel(_('Server arguments:')) self.args_input = QLineEdit(self) self.args_input.setToolTip(_('Additional arguments required to ' 'start the server')) self.args_input.setText(args) conf_label = QLabel(_('LSP Server Configurations:')) self.conf_input = CodeEditor(None) self.conf_input.textChanged.connect(self.validate) color_scheme = CONF.get('appearance', 'selected') self.conf_input.setup_editor( language='JSON', color_scheme=color_scheme, wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json') self.conf_input.setToolTip(_('Additional LSP server configurations ' 'set at runtime. JSON required')) conf_text = '{}' try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: pass self.conf_input.set_text(conf_text) self.json_label = QLabel(self.JSON_VALID, self) self.external_cb = QCheckBox(_('External server'), self) self.external_cb.setToolTip(_('Check if the server runs ' 'on a remote location')) self.external_cb.setChecked(external) self.external_cb.stateChanged.connect(self.set_local_options) hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(server_settings_description) vlayout = QVBoxLayout() lang_layout = QVBoxLayout() lang_layout.addWidget(lang_label) lang_layout.addWidget(self.lang_cb) # layout2 = QHBoxLayout() # layout2.addLayout(lang_layout) lang_layout.addWidget(self.external_cb) vlayout.addLayout(lang_layout) host_layout = QVBoxLayout() host_layout.addWidget(host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) vlayout.addLayout(conn_info_layout) cmd_layout = QVBoxLayout() cmd_layout.addWidget(cmd_label) cmd_layout.addWidget(self.cmd_input) vlayout.addLayout(cmd_layout) args_layout = QVBoxLayout() args_layout.addWidget(args_label) args_layout.addWidget(self.args_input) vlayout.addLayout(args_layout) conf_layout = QVBoxLayout() conf_layout.addWidget(conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) hlayout.addLayout(vlayout) hlayout.addLayout(conf_layout) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(bbox) self.setLayout(general_vlayout) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.lang_cb.currentIndexChanged.connect( self.lang_selection_changed) self.form_status(False) if language is not None: self.form_status(True) self.validate() @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet("QLineEdit{border: 1px solid red;}") self.host_input.setToolTip('Hostname must be valid') return else: self.host_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.host_input.setToolTip('Hostname is valid') self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Command must be non empty') return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Program was not found ' 'on your system') return else: self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.cmd_input.setToolTip('Program was found on your system') self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except: pass except (ValueError, json.decoder.JSONDecodeError): try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) try: self.validate() except: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, configurations=configurations) return server
class Settings(QDialog): roiClicked = Signal(int, int) def __init__(self, parent=None): super(Settings, self).__init__(parent) # Create a form with some controls self.selector = QComboBox() self.selector.setEditable(True) self.cameraCols = QSpinBox() self.cameraCols.setMinimum(1) self.cameraCols.setMaximum(6) self.cameraCols.setValue(1) self.cameraRows = QSpinBox() self.cameraRows.setMinimum(1) self.cameraRows.setMaximum(6) self.cameraRows.setValue(1) self.scale = QSpinBox() self.scale.setRange(0, 5000) self.scale.setSingleStep(10) self.scale.setValue(0) self.fps = QSpinBox() self.fps.setRange(1, 30) self.fps.setValue(5) self.xDivs = QSpinBox() self.xDivs.setRange(1, 50) self.xDivs.setValue(5) self.yDivs = QSpinBox() self.yDivs.setRange(1, 50) self.yDivs.setValue(5) self.color = QCheckBox() self.container = None self.microscope = None self.url = QLineEdit('http://localhost:9998/jpg/image.jpg') self.okButton = QPushButton('OK') self.applyButton = QPushButton('Apply') self.cancelButton = QPushButton('Cancel') # Lay it out formLayout = QFormLayout() formLayout.addRow('Camera:', self.selector) rowsCols = QHBoxLayout() rowsCols.addWidget(self.cameraCols) rowsCols.addWidget(self.cameraRows) formLayout.addRow('Cameras:', rowsCols) formLayout.addRow('Camera URL:', self.url) formLayout.addRow('Image Scale:', self.scale) formLayout.addRow('Frame Rate:', self.fps) formLayout.addRow('X Divisions:', self.xDivs) formLayout.addRow('Y Divisions:', self.yDivs) formLayout.addRow('Color boxes:', self.color) # Create layout and add widgets layout = QVBoxLayout() hbox = QHBoxLayout() hbox.addStretch() hbox.addWidget(self.okButton) hbox.addWidget(self.applyButton) hbox.addWidget(self.cancelButton) hbox.addStretch() layout.addLayout(formLayout) layout.addLayout(hbox) self.setLayout(layout) self.okButton.clicked.connect(self.okClicked) self.applyButton.clicked.connect(self.applyClicked) self.cancelButton.clicked.connect(self.cancelClicked) # Connect up some signals and slots... self.selector.currentIndexChanged.connect(self.selectionChanged) self.cameraCols.valueChanged.connect(self.cameraColsChanged) self.cameraRows.valueChanged.connect(self.cameraRowsChanged) def setMicroscope(self, microscope): self.microscope = microscope self.updateForm() def setContainer(self, container): # Store a reference to the container, default to widget 0. self.container = container self.setMicroscope(container.microscope(0)) self.updateCameraSelect() def okClicked(self): self.updateMicroscope() self.accept() def applyClicked(self): self.updateMicroscope() def cancelClicked(self): self.reject() def updateCameraSelect(self): # Iterate over the microscopes and create entries in the select. self.selector.clear() for i in range(self.container.count): print(f'doing element {i}') self.selector.addItem(f'Camera {i + 1}', i) self.cameraCols.setValue(self.container.size[0]) self.cameraRows.setValue(self.container.size[1]) def selectionChanged(self, index): self.updateMicroscope() self.microscope = self.container.microscope(index) self.updateForm() def cameraColsChanged(self, value): if self.container is None: print('Error, no active container.') return self.container.size = [value, self.container.size[1]] self.updateCameraSelect() self.container.update() def cameraRowsChanged(self, value): if self.container is None: print('Error, no active container.') return self.container.size = [self.container.size[0], value] self.updateCameraSelect() self.container.update() def updateMicroscope(self): self.microscope.url = self.url.text() self.microscope.fps = self.fps.value() self.microscope.xDivs = self.xDivs.value() self.microscope.yDivs = self.yDivs.value() self.microscope.color = self.color.isChecked() self.microscope.scale = [self.scale.value(), 0] self.microscope.update() def updateForm(self): self.url.setText(self.microscope.url) self.fps.setValue(self.microscope.fps) self.xDivs.setValue(self.microscope.xDivs) self.yDivs.setValue(self.microscope.yDivs) self.color.setChecked(self.microscope.color) if len(self.microscope.scale) > 0: self.scale.setValue(self.microscope.scale[0])
class ShearMomentTorqueWindow(PyDialog): """ +-------------------------+ | ShearMomentTorqueWindow | +-------------------------+ | Origin cid x y z | | P2 cid x y z | | z-axis cid x y z | | tol cid x y z | | | | Apply OK Cancel | +-------------------------+ """ def __init__(self, data, win_parent=None): """ Saves the data members from data and performs type checks """ PyDialog.__init__(self, data, win_parent) self._updated_preference = False self._default_font_size = data['font_size'] #self.dim_max = data['dim_max'] self.model_name = data['model_name'] self.cids = data['cids'] self.gpforce = data['gpforce'] #self._origin = data['origin'] #self._p1 = data['origin'] #self._p2 = data['origin'] #self.out_data = data self.plane_color_float, self.plane_color_int = check_color( data['plane_color']) self.plane_opacity = data['plane_opacity'] self.methods = ['Z-Axis Projection', 'CORD2R'] self.zaxis_methods = ['Global Z', 'Camera Normal', 'Manual'] self._zaxis_method = 0 # Global Z self.setWindowTitle('Shear, Moment, Torque') self.create_widgets() self.create_layout() self.set_connections() self.on_font(self._default_font_size) #self.on_gradient_scale() #self.show() def on_font(self, value=None): """update the font for the current window""" if value is None: value = self.font_size_edit.value() font = QtGui.QFont() font.setPointSize(value) self.setFont(font) def set_font_size(self, font_size): """ Updates the font size of all objects in the PyDialog Parameters ---------- font_size : int the font size """ if self.font_size == font_size: return self.font_size = font_size font = make_font(font_size, is_bold=False) self.setFont(font) self.set_bold_font(font_size) def set_bold_font(self, font_size): """ Updates the font size of all bolded objects in the dialog Parameters ---------- font_size : int the font size """ bold_font = make_font(font_size, is_bold=True) self.additional_params_label.setFont(bold_font) self.case_info_label.setFont(bold_font) self.plane_label.setFont(bold_font) self.location_label.setFont(bold_font) self.cid_label.setFont(bold_font) self.x_label.setFont(bold_font) self.y_label.setFont(bold_font) self.z_label.setFont(bold_font) def create_widgets(self): """creates the display window""" # CORD2R #self.origin_label = QLabel("Origin:") #self.zaxis_label = QLabel("Z Axis:") #self.xz_plane_label = QLabel("XZ Plane:") # Z-Axis Projection self.p1_label = QLabel("Origin:") self.p3_label = QLabel("End:") self.p2_label = QLabel("XZ Plane:") self.p1_label.setToolTip( 'Defines the starting point for the shear, moment, torque plot') self.p3_label.setToolTip( 'Defines the end point for the shear, moment, torque plot') self.p2_label.setToolTip('Defines the XZ plane for the shears/moments') self.zaxis_label = QLabel("Z Axis:") self.method_pulldown = QComboBox() for method in self.methods: self.method_pulldown.addItem(method) self.zaxis_method_pulldown = QComboBox() for method in self.zaxis_methods: self.zaxis_method_pulldown.addItem(method) self.cid_label = QLabel("Coordinate System:") self.p1_cid_pulldown = QComboBox() self.p2_cid_pulldown = QComboBox() self.p3_cid_pulldown = QComboBox() self.zaxis_cid_pulldown = QComboBox() cid_global_str = '0/Global' for cid in sorted(self.cids): if cid == 0: cid_str = cid_global_str else: cid_str = str(cid) #print('cid_str = %r' % cid_str) self.p1_cid_pulldown.addItem(cid_str) self.p2_cid_pulldown.addItem(cid_str) self.p3_cid_pulldown.addItem(cid_str) self.zaxis_cid_pulldown.addItem(cid_str) self.p1_cid_pulldown.setCurrentIndex(0) self.p2_cid_pulldown.setCurrentIndex(0) self.p3_cid_pulldown.setCurrentIndex(0) self.zaxis_cid_pulldown.setCurrentIndex(0) if len(self.cids) == 1: self.p1_cid_pulldown.setEnabled(False) self.p2_cid_pulldown.setEnabled(False) self.p3_cid_pulldown.setEnabled(False) self.zaxis_cid_pulldown.setEnabled(False) #self.p1_cid_pulldown.setItemText(0, cid_str) #self.p2_cid_pulldown.setItemText(0, cid_str) #self.zaxis_cid_pulldown.setItemText(0, cid_str) self.p1_cid_pulldown.setToolTip( 'Defines the coordinate system for Point P1') self.p2_cid_pulldown.setToolTip( 'Defines the coordinate system for Point P2') self.p3_cid_pulldown.setToolTip( 'Defines the coordinate system for Point P3') self.zaxis_cid_pulldown.setToolTip( 'Defines the coordinate system for the Z Axis') self.p1_x_edit = QFloatEdit('') self.p1_y_edit = QFloatEdit('') self.p1_z_edit = QFloatEdit('') self.p2_x_edit = QFloatEdit('') self.p2_y_edit = QFloatEdit('') self.p2_z_edit = QFloatEdit('') self.p3_x_edit = QFloatEdit('') self.p3_y_edit = QFloatEdit('') self.p3_z_edit = QFloatEdit('') self.zaxis_x_edit = QFloatEdit('') self.zaxis_y_edit = QFloatEdit('') self.zaxis_z_edit = QFloatEdit('') self.additional_params_label = QLabel('Plane Parameters:') self.case_info_label = QLabel('Case Info:') self.p2_label = QLabel("XZ Plane:") # Plane Color self.plane_color_label = QLabel("Plane Color:") self.plane_color_edit = QPushButtonColor(self.plane_color_int) self.plane_opacity_label = QLabel("Plane Opacity:") self.plane_opacity_edit = QDoubleSpinBox() self.plane_opacity_edit.setRange(0.1, 1.0) self.plane_opacity_edit.setDecimals(1) self.plane_opacity_edit.setSingleStep(0.1) self.plane_opacity_edit.setValue(self.plane_opacity) self.flip_coord_label = QLabel("Flip Coordinate System:") self.flip_coord_checkbox = QCheckBox() #----------------------------------------------------------------------- self.time_label = QLabel('Time:') if self.gpforce is None: times = ['0.', '0.5', '1.', '1.5', '2.'] time = '0.' else: times = [func_str(time) for time in self.gpforce._times] time = times[0] self.times_pulldown = make_combo_box(times, time) self.time_label.setEnabled(False) self.times_pulldown.setEnabled(False) #self.node_label = QLabel('Nodes:') #self.node_edit = QNodeEdit(self.win_parent, self.model_name, parent=self.gui, #pick_style='area', tab_to_next=False) #self.element_label = QLabel('Elements:') #self.element_edit = QElementEdit(self.win_parent, self.model_name, parent=self.gui, #pick_style='area', tab_to_next=False) #self.node_element_label = QLabel('Nodes/Elements:') #self.node_element_edit = QLineEdit() #self.node_element_edit.setReadOnly(True) self.nplanes_label = QLabel('Num Planes:') self.nplanes_spinner = QSpinBox() self.nplanes_spinner.setMinimum(2) self.nplanes_spinner.setMaximum(500) self.nplanes_spinner.setValue(20) #----------------------------------------------------------------------- self.method_label = QLabel('Method:') self.plane_label = QLabel('Plane:') self.location_label = QLabel('Location:') self.zaxis_method_label = QLabel('Z-Axis Method:') self.cid_label = QLabel('Coordinate System:') self.x_label = QLabel('X') self.y_label = QLabel('Y') self.z_label = QLabel('Z') #self.location_label.setAlignment(Qt.AlignCenter) self.cid_label.setAlignment(Qt.AlignCenter) self.x_label.setAlignment(Qt.AlignCenter) self.y_label.setAlignment(Qt.AlignCenter) self.z_label.setAlignment(Qt.AlignCenter) self.export_checkbox = QCheckBox() self.csv_label = QLabel('CSV Filename:') self.csv_edit = QLineEdit() self.csv_button = QPushButton('Browse...') self.csv_label.setEnabled(False) self.csv_edit.setEnabled(False) self.csv_button.setEnabled(False) #----------------------------------------------------------------------- # nodes self.add_button = QPushButton('Add') self.remove_button = QPushButton('Remove') # elements self.add2_button = QPushButton('Add') self.remove2_button = QPushButton('Remove') #----------------------------------------------------------------------- # closing self.apply_button = QPushButton('Apply') self.cancel_button = QPushButton('Cancel') self.set_bold_font(self._default_font_size) @property def gui(self): if self.win_parent is None: return None return self.win_parent.parent.gui def create_layout(self): """sets up the window""" grid = self._make_grid_layout() #hbox_csv = QHBoxLayout() grid2 = QGridLayout() #irow = 0 #grid2.addWidget(self.node_label, irow, 0) #grid2.addWidget(self.node_edit, irow, 1) #grid2.addWidget(self.add_button, irow, 2) #grid2.addWidget(self.remove_button, irow, 3) #irow += 1 #grid2.addWidget(self.element_label, irow, 0) #grid2.addWidget(self.element_edit, irow, 1) #grid2.addWidget(self.add2_button, irow, 2) #grid2.addWidget(self.remove2_button, irow, 3) #irow += 1 #grid2.addWidget(self.node_element_label, irow, 0) #grid2.addWidget(self.node_element_edit, irow, 1) #irow += 1 hbox_csv = QHBoxLayout() hbox_csv.addWidget(self.export_checkbox) hbox_csv.addWidget(self.csv_label) hbox_csv.addWidget(self.csv_edit) hbox_csv.addWidget(self.csv_button) #---------------------------------------------- ok_cancel_box = QHBoxLayout() ok_cancel_box.addWidget(self.apply_button) ok_cancel_box.addWidget(self.cancel_button) vbox = QVBoxLayout() vbox.addLayout(grid) vbox.addLayout(grid2) #vbox.addStretch() vbox.addLayout(hbox_csv) vbox.addStretch() #----------------------- #vbox.addLayout(add_remove_box) vbox.addLayout(ok_cancel_box) self.on_method(0) self.on_zaxis_method(0) self.setLayout(vbox) def on_export_checkbox(self): """this is called when the checkbox is clicked""" is_checked = self.export_checkbox.isChecked() self.csv_label.setEnabled(is_checked) self.csv_edit.setEnabled(is_checked) self.csv_button.setEnabled(is_checked) def on_browse_csv(self): """opens a file dialog""" default_dirname = os.getcwd() csv_filename, wildcard = save_file_dialog( self, 'Select the file name for export', default_dirname, wildcard_csv) if not csv_filename: return self.csv_edit.setText(csv_filename) def _make_grid_layout(self): """builds the QGridLayout""" grid = QGridLayout() irow = 0 #------------------------- grid.addWidget(self.location_label, irow, 0) grid.addWidget(self.cid_label, irow, 1) grid.addWidget(self.x_label, irow, 2) grid.addWidget(self.y_label, irow, 3) grid.addWidget(self.z_label, irow, 4) irow += 1 add_row(irow, grid, self.p1_label, self.p1_cid_pulldown, self.p1_x_edit, self.p1_y_edit, self.p1_z_edit) irow += 1 add_row(irow, grid, self.p3_label, self.p3_cid_pulldown, self.p3_x_edit, self.p3_y_edit, self.p3_z_edit) irow += 1 grid.addWidget(self.plane_label, irow, 0) irow += 1 grid.addWidget(self.method_label, irow, 0) grid.addWidget(self.method_pulldown, irow, 1) irow += 1 grid.addWidget(self.zaxis_method_label, irow, 0) grid.addWidget(self.zaxis_method_pulldown, irow, 1) irow += 1 add_row(irow, grid, self.zaxis_label, self.zaxis_cid_pulldown, self.zaxis_x_edit, self.zaxis_y_edit, self.zaxis_z_edit) irow += 1 add_row(irow, grid, self.p2_label, self.p2_cid_pulldown, self.p2_x_edit, self.p2_y_edit, self.p2_z_edit) irow += 1 #----------------------------------------- grid.addWidget(self.case_info_label, irow, 0) irow += 1 grid.addWidget(self.time_label, irow, 0) grid.addWidget(self.times_pulldown, irow, 1) irow += 1 grid.addWidget(self.nplanes_label, irow, 0) grid.addWidget(self.nplanes_spinner, irow, 1) irow += 1 #----------------------------------------- grid.addWidget(self.additional_params_label, irow, 0) irow += 1 grid.addWidget(self.plane_color_label, irow, 0) grid.addWidget(self.plane_color_edit, irow, 1) irow += 1 grid.addWidget(self.plane_opacity_label, irow, 0) grid.addWidget(self.plane_opacity_edit, irow, 1) irow += 1 #---------------------------------------------- return grid def set_connections(self): """creates the actions for the menu""" self.method_pulldown.currentIndexChanged.connect(self.on_method) self.zaxis_method_pulldown.currentIndexChanged.connect( self.on_zaxis_method) self.plane_color_edit.clicked.connect(self.on_plane_color) self.export_checkbox.clicked.connect(self.on_export_checkbox) self.csv_button.clicked.connect(self.on_browse_csv) self.apply_button.clicked.connect(self.on_apply) self.cancel_button.clicked.connect(self.on_cancel) def on_method(self, method_int=None): method = get_pulldown_text(method_int, self.methods, self.method_pulldown) if method == 'Z-Axis Projection': is_cord2r = False elif method == 'CORD2R': is_cord2r = True else: raise NotImplementedError(method) if is_cord2r: self._zaxis_method = self.zaxis_method_pulldown.currentIndex() # set to manual #self.on_zaxis_method(method_int=2) # manual self.zaxis_method_pulldown.setCurrentIndex(2) self.on_zaxis_method() # update else: self.zaxis_method_pulldown.setCurrentIndex(self._zaxis_method) self.on_zaxis_method() # update # works self.zaxis_method_pulldown.setEnabled(not is_cord2r) self.zaxis_method_pulldown.setVisible(not is_cord2r) self.zaxis_method_label.setEnabled(not is_cord2r) def on_zaxis_method(self, method_int=None): method = get_pulldown_text(method_int, self.zaxis_methods, self.zaxis_method_pulldown) if method == 'Global Z': is_visible = False elif method == 'Camera Normal': is_visible = False elif method == 'Manual': is_visible = True else: raise NotImplementedError(method) self.zaxis_cid_pulldown.setVisible(is_visible) self.zaxis_x_edit.setVisible(is_visible) self.zaxis_y_edit.setVisible(is_visible) self.zaxis_z_edit.setVisible(is_visible) def on_plane_color(self): """ Choose a plane color""" title = "Choose a cutting plane color" rgb_color_ints = self.plane_color_int color_edit = self.plane_color_edit func_name = 'set_plane_color' passed, rgb_color_ints, rgb_color_floats = self._background_color( title, color_edit, rgb_color_ints, func_name) if passed: self.plane_color_int = rgb_color_ints self.plane_color_float = rgb_color_floats def _background_color(self, title, color_edit, rgb_color_ints, func_name): """helper method for ``on_background_color`` and ``on_background_color2``""" passed, rgb_color_ints, rgb_color_floats = self.on_color( color_edit, rgb_color_ints, title) if passed and 0: if self.win_parent is not None: settings = self.win_parent.settings func_background_color = getattr(settings, func_name) func_background_color(rgb_color_floats) return passed, rgb_color_ints, rgb_color_floats def on_color(self, color_edit, rgb_color_ints, title): """pops a color dialog""" col = QColorDialog.getColor(QtGui.QColor(*rgb_color_ints), self, title) if not col.isValid(): return False, rgb_color_ints, None color_float = col.getRgbF()[:3] # floats color_int = [int(colori * 255) for colori in color_float] assert isinstance(color_float[0], float), color_float assert isinstance(color_int[0], int), color_int color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(color_int) + #"border:1px solid rgb(255, 170, 255); " "}") return True, color_int, color_float #--------------------------------------------------------------------------- def on_validate(self): p1_cidi = self.p1_cid_pulldown.currentText() p2_cidi = self.p2_cid_pulldown.currentText() p3_cidi = self.p3_cid_pulldown.currentText() zaxis_cidi = self.zaxis_cid_pulldown.currentText() p1_cid = int(p1_cidi) if 'Global' not in p1_cidi else 0 p2_cid = int(p2_cidi) if 'Global' not in p2_cidi else 0 p3_cid = int(p3_cidi) if 'Global' not in p3_cidi else 0 zaxis_cid = int(zaxis_cidi) if 'Global' not in zaxis_cidi else 0 #print('p1_cidi=%r p2_cidi=%r p3_cidi=%r' % (p1_cidi, p2_cidi, zaxis_cidi)) #print('p2_cid=%r p2_cid=%r p3_cidi=%r' % (p2_cid, p2_cid, zaxis_cid)) p1_x, flag1 = check_float(self.p1_x_edit) p1_y, flag2 = check_float(self.p1_y_edit) p1_z, flag3 = check_float(self.p1_z_edit) p2_x, flag4 = check_float(self.p2_x_edit) p2_y, flag5 = check_float(self.p2_y_edit) p2_z, flag6 = check_float(self.p2_z_edit) p3_x, flag7 = check_float(self.p3_x_edit) p3_y, flag8 = check_float(self.p3_y_edit) p3_z, flag9 = check_float(self.p3_z_edit) p1 = [p1_x, p1_y, p1_z] p2 = [p2_x, p2_y, p2_z] p3 = [p3_x, p3_y, p3_z] flag10, flag11, flag12, zaxis_cid, zaxis = get_zaxis( self.win_parent, # for camera self.zaxis_method_pulldown, self.zaxis_x_edit, self.zaxis_y_edit, self.zaxis_z_edit) method = self.method_pulldown.currentText() assert method in self.methods, 'method=%r' % method flag13 = True plane_opacity = self.plane_opacity_edit.value() nplanes = self.nplanes_spinner.value() csv_filename = None flag14 = True if self.export_checkbox.isChecked(): csv_filename, flag14 = check_save_path(self.csv_edit) flags = [ flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8, flag9, flag10, flag11, flag12, flag13, flag14 ] if all(flags): self.out_data['method'] = method self.out_data['p1'] = [p1_cid, p1] self.out_data['p2'] = [p2_cid, p2] self.out_data['p3'] = [p3_cid, p3] self.out_data['zaxis'] = [zaxis_cid, zaxis] self.out_data['plane_color'] = self.plane_color_float self.out_data['plane_opacity'] = plane_opacity self.out_data['nplanes'] = nplanes self.out_data['csv_filename'] = csv_filename self.out_data['clicked_ok'] = True return True return False def on_apply(self): passed = self.on_validate() if passed and self.win_parent is not None: self.win_parent.shear_moment_torque_obj.make_smt_from_data( self.out_data, show=True) #self.win_parent.make_smt_from_data(self.out_data) return passed def on_cancel(self): self.out_data['close'] = True self.close()
class ConnectDialog(QDialog): """ A modal dialog window with widgets for modifying connection parameters. Changes + OK will change the parameters in the CbSdkConnection singleton, but will not actually connect. """ def __init__(self, parent=None): super(ConnectDialog, self).__init__(parent) # Get access to the CbSdkConnection instance, but don't connect yet. self.cbsdkConn = CbSdkConnection() # Widgets to show/edit connection parameters. layout = QVBoxLayout(self) # client-addr ip client_addr_layout = QHBoxLayout() client_addr_layout.addWidget(QLabel("client-addr")) self.clientIpEdit = QLineEdit(self.cbsdkConn.con_params['client-addr']) self.clientIpEdit.setInputMask("000.000.000.000;_") client_addr_layout.addWidget(self.clientIpEdit) layout.addLayout(client_addr_layout) # client-port int client_port_layout = QHBoxLayout() client_port_layout.addWidget(QLabel("client-port")) self.clientPortSpin = QSpinBox() self.clientPortSpin.setMinimum(0) self.clientPortSpin.setMaximum(99999) self.clientPortSpin.setSingleStep(1) self.clientPortSpin.setValue(self.cbsdkConn.con_params['client-port']) client_port_layout.addWidget(self.clientPortSpin) layout.addLayout(client_port_layout) # inst-addr ip inst_addr_layout = QHBoxLayout() inst_addr_layout.addWidget(QLabel("inst-addr")) self.instIpEdit = QLineEdit(self.cbsdkConn.con_params['inst-addr']) self.instIpEdit.setInputMask("000.000.000.000;_") inst_addr_layout.addWidget(self.instIpEdit) layout.addLayout(inst_addr_layout) # inst-port int inst_port_layout = QHBoxLayout() inst_port_layout.addWidget(QLabel("inst-port")) self.instPortSpin = QSpinBox() self.instPortSpin.setMinimum(0) self.instPortSpin.setMaximum(99999) self.instPortSpin.setSingleStep(1) self.instPortSpin.setValue(self.cbsdkConn.con_params['inst-port']) inst_port_layout.addWidget(self.instPortSpin) layout.addLayout(inst_port_layout) # receive-buffer-size int rec_buff_layout = QHBoxLayout() rec_buff_layout.addWidget(QLabel("receive-buffer-size")) self.recBuffSpin = QSpinBox() self.recBuffSpin.setMinimum(6 * 1024 * 1024) self.recBuffSpin.setMaximum(8 * 1024 * 1024) self.recBuffSpin.setSingleStep(1024 * 1024) self.recBuffSpin.setValue( self.cbsdkConn.con_params['receive-buffer-size']) rec_buff_layout.addWidget(self.recBuffSpin) layout.addLayout(rec_buff_layout) # OK and Cancel buttons buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) layout.addWidget(buttons) @staticmethod def do_connect_dialog(parent=None): dialog = ConnectDialog(parent) result = dialog.exec_() if result == QDialog.Accepted: dialog.cbsdkConn.disconnect() # Collect values from widgets and set them on dialog.cbsdkConn new_params = { 'client-addr': dialog.clientIpEdit.text(), 'client-port': dialog.clientPortSpin.value(), 'inst-addr': dialog.instIpEdit.text(), 'inst-port': dialog.instPortSpin.value(), 'receive-buffer-size': dialog.recBuffSpin.value() } dialog.cbsdkConn.con_params = new_params return dialog.cbsdkConn.connect() return -1
class QtVectorsLayer(QtLayer): def __init__(self, layer): super().__init__(layer) self.layer.events.averaging.connect(self._on_avg_change) self.layer.events.width.connect(self._on_width_change) self.layer.events.length.connect(self._on_len_change) # vector color adjustment and widget face_comboBox = QComboBox() colors = self.layer._colors for c in colors: face_comboBox.addItem(c) index = face_comboBox.findText(self.layer.color, Qt.MatchFixedString) if index >= 0: face_comboBox.setCurrentIndex(index) face_comboBox.activated[str].connect( lambda text=face_comboBox: self.change_face_color(text)) self.grid_layout.addWidget(QLabel('color:'), 3, 0) self.grid_layout.addWidget(face_comboBox, 3, 1) # line width in pixels self.width_field = QDoubleSpinBox() self.width_field.setSingleStep(0.1) self.width_field.setMinimum(0.1) value = self.layer.width self.width_field.setValue(value) self.width_field.valueChanged.connect(self.change_width) self.grid_layout.addWidget(QLabel('width:'), 4, 0) self.grid_layout.addWidget(self.width_field, 4, 1) # averaging spinbox self.averaging_spinbox = QSpinBox() self.averaging_spinbox.setSingleStep(1) self.averaging_spinbox.setValue(1) self.averaging_spinbox.setMinimum(1) self.averaging_spinbox.valueChanged.connect(self.change_average_type) self.grid_layout.addWidget(QLabel('avg kernel'), 5, 0) self.grid_layout.addWidget(self.averaging_spinbox, 5, 1) # line length self.length_field = QDoubleSpinBox() self.length_field.setSingleStep(0.1) value = self.layer.length self.length_field.setValue(value) self.length_field.setMinimum(0.1) self.length_field.valueChanged.connect(self.change_length) self.grid_layout.addWidget(QLabel('length:'), 6, 0) self.grid_layout.addWidget(self.length_field, 6, 1) self.setExpanded(False) def change_face_color(self, text): self.layer.color = text def change_connector_type(self, text): self.layer.connector = text def change_average_type(self, value): self.layer.averaging = value def change_width(self, value): self.layer.width = value def change_length(self, value): self.layer.length = value def _on_avg_change(self, event): with self.layer.events.averaging.blocker(): self.averaging_spinbox.setValue(self.layer.averaging) def _on_len_change(self, event): with self.layer.events.length.blocker(): self.length_field.setValue(self.layer.length) def _on_width_change(self, event): with self.layer.events.width.blocker(): self.width_field.setValue(self.layer.width)
class QtLabelsProperties(QtLayerProperties): def __init__(self, layer): super().__init__(layer) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.selected_label.connect(self._on_selection_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contig_change) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.colormap_update = QPushButton('click') self.colormap_update.setObjectName('shuffle') self.colormap_update.clicked.connect(self.changeColor) self.colormap_update.setFixedWidth(112) self.colormap_update.setFixedHeight(25) shuffle_label = QLabel('shuffle colors:') shuffle_label.setObjectName('shuffle-label') row = self.grid_layout.rowCount() self.grid_layout.addWidget(shuffle_label, row, self.name_column) self.grid_layout.addWidget( self.colormap_update, row, self.property_column ) # selection spinbox self.selection_spinbox = QSpinBox() self.selection_spinbox.setSingleStep(1) self.selection_spinbox.setMinimum(0) self.selection_spinbox.setMaximum(2147483647) self.selection_spinbox.setValue(self.layer.selected_label) self.selection_spinbox.setFixedWidth(75) self.selection_spinbox.valueChanged.connect(self.changeSelection) row = self.grid_layout.rowCount() self.grid_layout.addWidget(QLabel('label:'), row, self.name_column) self.grid_layout.addWidget( self.selection_spinbox, row, self.property_column ) sld = QSlider(Qt.Horizontal, self) sld.setFocusPolicy(Qt.NoFocus) sld.setFixedWidth(110) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) value = self.layer.brush_size if isinstance(value, Iterable): if isinstance(value, list): value = np.asarray(value) value = value[:2].mean() sld.setValue(int(value)) sld.valueChanged[int].connect(lambda value=sld: self.changeSize(value)) self.brush_size_slider = sld row = self.grid_layout.rowCount() self.grid_layout.addWidget( QLabel('brush size:'), row, self.name_column ) self.grid_layout.addWidget(sld, row, self.property_column) contig_cb = QCheckBox() contig_cb.setToolTip('contiguous editing') contig_cb.setChecked(self.layer.contiguous) contig_cb.stateChanged.connect( lambda state=contig_cb: self.change_contig(state) ) self.contig_checkbox = contig_cb row = self.grid_layout.rowCount() self.grid_layout.addWidget( QLabel('contiguous:'), row, self.name_column ) self.grid_layout.addWidget(contig_cb, row, self.property_column) ndim_cb = QCheckBox() ndim_cb.setToolTip('n-dimensional editing') ndim_cb.setChecked(self.layer.n_dimensional) ndim_cb.stateChanged.connect( lambda state=ndim_cb: self.change_ndim(state) ) self.ndim_checkbox = ndim_cb row = self.grid_layout.rowCount() self.grid_layout.addWidget(QLabel('n-dim:'), row, self.name_column) self.grid_layout.addWidget(ndim_cb, row, self.property_column) self.setExpanded(False) def changeColor(self): self.layer.new_colormap() def changeSelection(self, value): self.layer.selected_label = value def changeSize(self, value): self.layer.brush_size = value def change_contig(self, state): if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def _on_colormap_change(self, event): self.layer._node.cmap = self.layer.colormap def _on_selection_change(self, event): with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selection_spinbox.setValue(int(value)) def _on_brush_size_change(self, event): with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brush_size_slider.setValue(value) def _on_n_dim_change(self, event): with self.layer.events.n_dimensional.blocker(): self.ndim_checkbox.setChecked(self.layer.n_dimensional) def _on_contig_change(self, event): with self.layer.events.contiguous.blocker(): self.contig_checkbox.setChecked(self.layer.contiguous)
class DataPreferences(QWidget): def __init__(self, mainWindow): super().__init__() self.mainWindow = mainWindow bestMonthGroup = GroupWidget("Best month", layout="grid") self.bestMonthCriteria = QComboBox() self.bestMonthCriteria.addItems( ["Time", "Distance", "Avg. speed", "Calories", "Gear"]) bestMonthLabel = QLabel("Criterion:") bestMonthGroup.addWidget(bestMonthLabel, 0, 0) bestMonthGroup.addWidget(self.bestMonthCriteria, 0, 1) topSessionsGroup = GroupWidget("Top sessions", layout="grid") self.numSessionsBox = QSpinBox() self.numSessionsBox.setMinimum(1) numSessionsLabel = QLabel("Number of top sessions:") topSessionsGroup.addWidget(numSessionsLabel, 0, 0) topSessionsGroup.addWidget(self.numSessionsBox, 0, 1) summaryCriteriaGroup = GroupWidget("Summary criteria", layout="grid") names = ["Time", "Distance", "Calories", "Speed", "Gear"] self.summaryComboBoxes = {} for row, name in enumerate(names): summaryCriteriaGroup.addWidget(QLabel(name), row, 0) box = FuncComboBox() self.summaryComboBoxes[name.lower()] = box summaryCriteriaGroup.addWidget(box, row, 1) mainLayout = QVBoxLayout() mainLayout.addWidget(summaryCriteriaGroup) mainLayout.addWidget(bestMonthGroup) mainLayout.addWidget(topSessionsGroup) mainLayout.addStretch(1) self.setLayout(mainLayout) self.setCurrentValues() # apply initial state self.apply() def setCurrentValues(self): self.settings = Settings() self.settings.beginGroup("pb") bestMonthCriterion = self.settings.value("bestMonthCriterion", "distance").capitalize() self.bestMonthCriteria.setCurrentText(bestMonthCriterion) numSessions = self.settings.value("numSessions", 5, int) self.numSessionsBox.setValue(numSessions) for name, widget in self.summaryComboBoxes.items(): funcName = self.settings.value(f"summary/{name}", None) if funcName is None: funcName = self.mainWindow.summary.getFunc(name) widget.setCurrentText(funcName) self.settings.endGroup() def apply(self): bestMonthCriterion = self.bestMonthCriteria.currentText().lower() self.mainWindow.pb.bestMonth.setColumn(bestMonthCriterion) numSessions = self.numSessionsBox.value() self.mainWindow.pb.bestSessions.setNumRows(numSessions) self.settings.beginGroup("pb") self.settings.setValue("bestMonthCriterion", bestMonthCriterion) self.settings.setValue("numSessions", numSessions) # make dict to pass to `setFunc` so it doesn't remake the viewer five times summaryFuncs = {} for name, widget in self.summaryComboBoxes.items(): funcName = widget.currentText() self.settings.setValue(f"summary/{name}", funcName) summaryFuncs[name] = funcName self.mainWindow.summary.setFunc(summaryFuncs) self.settings.endGroup()
class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False DEFAULT_STDIO = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('Valid JSON') JSON_INVALID = _('Invalid JSON') MIN_SIZE = QSize(850, 600) INVALID_CSS = "QLineEdit {border: 1px solid red;}" VALID_CSS = "QLineEdit {border: 1px solid green;}" def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, stdio=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) description = _( "To create a new server configuration, you need to select a " "programming language, set the command to start its associated " "server and enter any arguments that should be passed to it on " "startup. Additionally, you can set the server's hostname and " "port if connecting to an external server, " "or to a local one using TCP instead of stdio pipes." "<br><br>" "<i>Note</i>: You can use the placeholders <tt>{host}</tt> and " "<tt>{port}</tt> in the server arguments field to automatically " "fill in the respective values.<br>" ) self.parent = parent self.external = external # Widgets self.server_settings_description = QLabel(description) self.lang_cb = QComboBox(self) self.external_cb = QCheckBox(_('External server'), self) self.host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.cmd_label = QLabel(_('Command:')) self.cmd_input = QLineEdit(self) self.args_label = QLabel(_('Arguments:')) self.args_input = QLineEdit(self) self.json_label = QLabel(self.JSON_VALID, self) self.conf_label = QLabel(_('<b>Server Configuration:</b>')) self.conf_input = CodeEditor(None) self.bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = self.bbox.button(QDialogButtonBox.Ok) self.button_cancel = self.bbox.button(QDialogButtonBox.Cancel) # Widget setup self.setMinimumSize(self.MIN_SIZE) self.setWindowTitle(_('LSP server editor')) self.server_settings_description.setWordWrap(True) self.lang_cb.setToolTip( _('Programming language provided by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) self.button_ok.setEnabled(False) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) self.host_input.setPlaceholderText('127.0.0.1') self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) self.cmd_input.setText(cmd) self.cmd_input.setPlaceholderText('/absolute/path/to/command') self.args_input.setToolTip( _('Additional arguments required to start the server')) self.args_input.setText(args) self.args_input.setPlaceholderText(r'--host {host} --port {port}') self.conf_input.setup_editor( language='json', color_scheme=CONF.get('appearance', 'selected'), wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json', folding=False ) self.conf_input.set_language('json', 'config.json') self.conf_input.setToolTip(_('Additional LSP server configuration ' 'set at runtime. JSON required')) try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: conf_text = '{}' self.conf_input.set_text(conf_text) self.external_cb.setToolTip( _('Check if the server runs on a remote location')) self.external_cb.setChecked(external) self.stdio_cb = QCheckBox(_('Use stdio pipes for communication'), self) self.stdio_cb.setToolTip(_('Check if the server communicates ' 'using stdin/out pipes')) self.stdio_cb.setChecked(stdio) # Layout setup hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(self.server_settings_description) vlayout = QVBoxLayout() lang_group = QGroupBox(_('Language')) lang_layout = QVBoxLayout() lang_layout.addWidget(self.lang_cb) lang_group.setLayout(lang_layout) vlayout.addWidget(lang_group) server_group = QGroupBox(_('Language server')) server_layout = QGridLayout() server_layout.addWidget(self.cmd_label, 0, 0) server_layout.addWidget(self.cmd_input, 0, 1) server_layout.addWidget(self.args_label, 1, 0) server_layout.addWidget(self.args_input, 1, 1) server_group.setLayout(server_layout) vlayout.addWidget(server_group) address_group = QGroupBox(_('Server address')) host_layout = QVBoxLayout() host_layout.addWidget(self.host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(self.port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) address_group.setLayout(conn_info_layout) vlayout.addWidget(address_group) advanced_group = QGroupBox(_('Advanced')) advanced_layout = QVBoxLayout() advanced_layout.addWidget(self.external_cb) advanced_layout.addWidget(self.stdio_cb) advanced_group.setLayout(advanced_layout) vlayout.addWidget(advanced_group) conf_layout = QVBoxLayout() conf_layout.addWidget(self.conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) vlayout.addStretch() hlayout.addLayout(vlayout, 2) hlayout.addLayout(conf_layout, 3) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(self.bbox) self.setLayout(general_vlayout) self.form_status(False) # Signals if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) self.external_cb.stateChanged.connect(self.set_local_options) self.stdio_cb.stateChanged.connect(self.set_stdio_options) self.lang_cb.currentIndexChanged.connect(self.lang_selection_changed) self.conf_input.textChanged.connect(self.validate) self.bbox.accepted.connect(self.accept) self.bbox.rejected.connect(self.reject) # Final setup if language is not None: self.form_status(True) self.validate() if stdio: self.set_stdio_options(True) if external: self.set_local_options(True) @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet(self.INVALID_CSS) if bool(host_text): self.host_input.setToolTip(_('Hostname must be valid')) else: self.host_input.setToolTip( _('Hostname or IP address of the host on which the server ' 'is running. Must be non empty.')) else: self.host_input.setStyleSheet(self.VALID_CSS) self.host_input.setToolTip(_('Hostname is valid')) self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet(self.INVALID_CSS) self.cmd_input.setToolTip( _('Command used to start the LSP server locally. Must be ' 'non empty')) return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet(self.INVALID_CSS) self.cmd_input.setToolTip(_('Program was not found ' 'on your system')) else: self.cmd_input.setStyleSheet(self.VALID_CSS) self.cmd_input.setToolTip(_('Program was found on your ' 'system')) self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except Exception: pass except ValueError: try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except Exception: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.stdio_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.stdio_cb.setChecked(server.stdio) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.stdio_cb.setChecked(self.DEFAULT_STDIO) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) self.stdio_cb.stateChanged.disconnect() self.stdio_cb.setChecked(False) self.stdio_cb.setEnabled(False) else: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.stdio_cb.setEnabled(True) self.stdio_cb.setChecked(False) self.stdio_cb.stateChanged.connect(self.set_stdio_options) try: self.validate() except Exception: pass @Slot(bool) @Slot(int) def set_stdio_options(self, enabled): self.stdio = enabled if enabled: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.external_cb.stateChanged.disconnect() self.external_cb.setChecked(False) self.external_cb.setEnabled(False) self.host_input.setStyleSheet('') self.host_input.setEnabled(False) self.port_spinner.setEnabled(False) else: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.external_cb.setChecked(False) self.external_cb.setEnabled(True) self.external_cb.stateChanged.connect(self.set_local_options) self.host_input.setEnabled(True) self.port_spinner.setEnabled(True) try: self.validate() except Exception: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() stdio = self.stdio_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, stdio=stdio, configurations=configurations) return server
def createEditor(self, parent, option, index): if index.isValid(): role = index.data(PropertiesTreeModel.TYPE_ROLE) if role == 'class_combo': node_types = list(presets.nodes.keys()) cbox = QComboBox(parent) current_item = index.data(Qt.DisplayRole) for idx, node_type in enumerate(node_types): cbox.addItem(node_type) if node_type == current_item: cbox.setCurrentIndex(idx) return cbox elif role == 'preset_combo': pass elif role == 'spin_scale': spin = QSpinBox(parent) spin.setValue(index.data(PropertiesTreeModel.DATA_ROLE)) spin.setMinimum(1) spin.setMaximum(100) def update_scale(newValue): positions = index.parent().data( PropertiesTreeModel.MODEL_ROLE) oldValue = positions.absolute_scale positions.scale(newValue / oldValue) spin.valueChanged.connect(update_scale) return spin elif role == 'spin_x': spin = QSpinBox(parent) spin.setValue(index.data(PropertiesTreeModel.DATA_ROLE)) def update_x(newValue): positions = index.parent().parent().data( PropertiesTreeModel.MODEL_ROLE) print( f"update x, positions:{positions}, translation:{positions.translation}" ) oldValue = positions.translation["x"] positions.translate(newValue - oldValue, 0) spin.valueChanged.connect(update_x) return spin elif role == 'spin_y': spin = QSpinBox(parent) spin.setValue(index.data(PropertiesTreeModel.DATA_ROLE)) def update_y(newValue): positions = index.parent().parent().data( PropertiesTreeModel.MODEL_ROLE) oldValue = positions.translation["y"] positions.translate(0, newValue - oldValue) spin.valueChanged.connect(update_y) return spin elif role == 'rotate_slider': slider = QSlider(parent) slider.setOrientation(Qt.Horizontal) slider.setMinimum(0) slider.setMaximum(359) slider.setValue(index.data(PropertiesTreeModel.DATA_ROLE)) slider.setAutoFillBackground(True) def update_rotation(newValue): positions = index.parent().data( PropertiesTreeModel.MODEL_ROLE) oldValue = positions.angle print(f"rotate by: {newValue - oldValue}") print(f"X before: {positions.x}") positions.rotate(newValue - oldValue) print(f"X after: {positions.x}") slider.valueChanged.connect(update_rotation) return slider return super().createEditor(parent, option, index)
class RunICADialog(QDialog): def __init__(self, parent, nchan, have_picard=True, have_sklearn=True): super().__init__(parent) self.setWindowTitle("Run ICA") vbox = QVBoxLayout(self) grid = QGridLayout() grid.addWidget(QLabel("Method:"), 0, 0) self.method = QComboBox() self.methods = {"Infomax": "infomax"} if have_sklearn: self.methods["FastICA"] = "fastica" if have_picard: self.methods["Picard"] = "picard" self.method.addItems(self.methods.keys()) if have_picard: self.method.setCurrentText("Picard") else: self.method.setCurrentText("Infomax") min_len = max(len(key) for key in self.methods.keys()) self.method.setMinimumContentsLength(min_len) grid.addWidget(self.method, 0, 1) self.extended_label = QLabel("Extended:") grid.addWidget(self.extended_label, 1, 0) self.extended = QCheckBox() self.extended.setChecked(True) grid.addWidget(self.extended, 1, 1) self.ortho_label = QLabel("Orthogonal:") grid.addWidget(self.ortho_label, 2, 0) self.ortho = QCheckBox() self.ortho.setChecked(False) grid.addWidget(self.ortho, 2, 1) self.toggle_options() self.method.currentIndexChanged.connect(self.toggle_options) grid.addWidget(QLabel("Number of components:"), 3, 0) self.n_components = QSpinBox() self.n_components.setMinimum(0) self.n_components.setMaximum(nchan) self.n_components.setValue(nchan) self.n_components.setAlignment(Qt.AlignRight) grid.addWidget(self.n_components, 3, 1) grid.addWidget(QLabel("Exclude bad segments:"), 4, 0) self.exclude_bad_segments = QCheckBox() self.exclude_bad_segments.setChecked(True) grid.addWidget(self.exclude_bad_segments) vbox.addLayout(grid) buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) vbox.addWidget(buttonbox) buttonbox.accepted.connect(self.accept) buttonbox.rejected.connect(self.reject) vbox.setSizeConstraint(QVBoxLayout.SetFixedSize) @Slot() def toggle_options(self): """Toggle extended options. """ if self.method.currentText() == "Picard": self.extended_label.show() self.extended.show() self.ortho_label.show() self.ortho.show() elif self.method.currentText() == "Infomax": self.extended_label.show() self.extended.show() self.ortho_label.hide() self.ortho.hide() else: self.extended_label.hide() self.extended.hide() self.ortho_label.hide() self.ortho.hide()
class QtLabelsControls(QtLayerControls): """Qt view and controls for the napari Labels layer. Parameters ---------- layer : napari.layers.Labels An instance of a napari Labels layer. Attributes ---------- button_group : qtpy.QtWidgets.QButtonGroup Button group of labels layer modes: PAN_ZOOM, PICKER, PAINT, ERASE, or FILL. colormapUpdate : qtpy.QtWidgets.QPushButton Button to update colormap of label layer. contigCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is contiguous. fill_button : qtpy.QtWidgets.QtModeRadioButton Button to select FILL mode on Labels layer. grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Labels An instance of a napari Labels layer. ndimCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is n-dimensional. paint_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAINT mode on Labels layer. panzoom_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAN_ZOOM mode on Labels layer. pick_button : qtpy.QtWidgets.QtModeRadioButton Button to select PICKER mode on Labels layer. erase_button : qtpy.QtWidgets.QtModeRadioButton Button to select ERASE mode on Labels layer. selectionSpinBox : qtpy.QtWidgets.QSpinBox Widget to select a specific label by its index. Raises ------ ValueError Raise error if label mode is not PAN_ZOOM, PICKER, PAINT, ERASE, or FILL. """ def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect(self._on_selection_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contig_change) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.events.preserve_labels.connect( self._on_preserve_labels_change ) self.layer.events.color_mode.connect(self._on_color_mode_change) # selection spinbox self.selectionSpinBox = QSpinBox() self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.setSingleStep(1) self.selectionSpinBox.setMinimum(0) self.selectionSpinBox.setMaximum(2147483647) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self.selectionSpinBox.setAlignment(Qt.AlignCenter) self._on_selection_change() sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged.connect(self.changeSize) self.brushSizeSlider = sld self._on_brush_size_change() contig_cb = QCheckBox() contig_cb.setToolTip('contiguous editing') contig_cb.stateChanged.connect(self.change_contig) self.contigCheckBox = contig_cb self._on_contig_change() ndim_cb = QCheckBox() ndim_cb.setToolTip('n-dimensional editing') ndim_cb.stateChanged.connect(self.change_ndim) self.ndimCheckBox = ndim_cb self._on_n_dim_change() preserve_labels_cb = QCheckBox() preserve_labels_cb.setToolTip( 'preserve existing labels while painting' ) preserve_labels_cb.stateChanged.connect(self.change_preserve_labels) self.preserveLabelsCheckBox = preserve_labels_cb self._on_preserve_labels_change() # shuffle colormap button self.colormapUpdate = QtModePushButton( None, 'shuffle', slot=self.changeColor, tooltip='shuffle colors', ) self.panzoom_button = QtModeRadioButton( layer, 'zoom', Mode.PAN_ZOOM, tooltip='Pan/zoom mode (Space)', checked=True, ) self.pick_button = QtModeRadioButton( layer, 'picker', Mode.PICK, tooltip='Pick mode' ) self.paint_button = QtModeRadioButton( layer, 'paint', Mode.PAINT, tooltip='Paint mode' ) btn = 'Cmd' if sys.platform == 'darwin' else 'Ctrl' self.fill_button = QtModeRadioButton( layer, 'fill', Mode.FILL, tooltip=f'Fill mode ({btn})' ) self.erase_button = QtModeRadioButton( layer, 'erase', Mode.ERASE, tooltip='Erase mode (Alt)' ) self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.button_group.addButton(self.erase_button) self._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.colormapUpdate) button_row.addWidget(self.erase_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.pick_button) button_row.addWidget(self.panzoom_button) button_row.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) color_mode_comboBox = QComboBox(self) color_mode_comboBox.addItems(LabelColorMode.keys()) index = color_mode_comboBox.findText( self.layer.color_mode, Qt.MatchFixedString ) color_mode_comboBox.setCurrentIndex(index) color_mode_comboBox.activated[str].connect(self.change_color_mode) self.colorModeComboBox = color_mode_comboBox self._on_color_mode_change() color_layout = QHBoxLayout() color_layout.addWidget(QtColorBox(layer)) color_layout.addWidget(self.selectionSpinBox) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 0, 1, 4) self.grid_layout.addWidget(QLabel('label:'), 1, 0, 1, 1) self.grid_layout.addLayout(color_layout, 1, 1, 1, 3) self.grid_layout.addWidget(QLabel('opacity:'), 2, 0, 1, 1) self.grid_layout.addWidget(self.opacitySlider, 2, 1, 1, 3) self.grid_layout.addWidget(QLabel('brush size:'), 3, 0, 1, 1) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 3) self.grid_layout.addWidget(QLabel('blending:'), 4, 0, 1, 1) self.grid_layout.addWidget(self.blendComboBox, 4, 1, 1, 3) self.grid_layout.addWidget(QLabel('color mode:'), 5, 0, 1, 1) self.grid_layout.addWidget(self.colorModeComboBox, 5, 1, 1, 3) self.grid_layout.addWidget(QLabel('contiguous:'), 6, 0, 1, 1) self.grid_layout.addWidget(self.contigCheckBox, 6, 1, 1, 1) self.grid_layout.addWidget(QLabel('n-dim:'), 6, 2, 1, 1) self.grid_layout.addWidget(self.ndimCheckBox, 6, 3, 1, 1) self.grid_layout.addWidget(QLabel('preserve labels:'), 7, 0, 1, 2) self.grid_layout.addWidget(self.preserveLabelsCheckBox, 7, 1, 1, 1) self.grid_layout.setRowStretch(8, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def mouseMoveEvent(self, event): """On mouse move, set layer status equal to the current selected mode. Available mode options are: PAN_ZOOM, PICKER, PAINT, ERASE or FILL Parameters ---------- event : qtpy.QtCore.QEvent Event from the Qt context. """ self.layer.status = str(self.layer.mode) def _on_mode_change(self, event): """Receive layer model mode change event and update checkbox ticks. Parameters ---------- event : qtpy.QtCore.QEvent Event from the Qt context. Raises ------ ValueError Raise error if event.mode is not PAN_ZOOM, PICK, PAINT, ERASE, or FILL """ mode = event.mode if mode == Mode.PAN_ZOOM: self.panzoom_button.setChecked(True) elif mode == Mode.PICK: self.pick_button.setChecked(True) elif mode == Mode.PAINT: self.paint_button.setChecked(True) elif mode == Mode.FILL: self.fill_button.setChecked(True) elif mode == Mode.ERASE: self.erase_button.setChecked(True) else: raise ValueError("Mode not recognized") def changeColor(self): """Change colormap of the label layer.""" self.layer.new_colormap() def changeSelection(self, value): """Change currently selected label. Parameters ---------- value : int Index of label to select. """ self.layer.selected_label = value self.selectionSpinBox.clearFocus() self.setFocus() def changeSize(self, value): """Change paint brush size. Parameters ---------- value : float Size of the paint brush. """ self.layer.brush_size = value def change_contig(self, state): """Toggle contiguous state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if labels are contiguous. """ if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): """Toggle n-dimensional state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if label layer is n-dimensional. """ if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def change_preserve_labels(self, state): """Toggle preserve_labels state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if overwriting label is enabled. """ if state == Qt.Checked: self.layer.preserve_labels = True else: self.layer.preserve_labels = False def change_color_mode(self, new_mode): """Change color mode of label layer. Parameters ---------- new_mode : str AUTO (default) allows color to be set via a hash function with a seed. DIRECT allows color of each label to be set directly by a color dictionary. """ self.layer.color_mode = new_mode def _on_selection_change(self, event=None): """Receive layer model label selection change event and update spinbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selectionSpinBox.setValue(int(value)) def _on_brush_size_change(self, event=None): """Receive layer model brush size change event and update the slider. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brushSizeSlider.setValue(value) def _on_n_dim_change(self, event=None): """Receive layer model n-dim mode change event and update the checkbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.n_dimensional.blocker(): self.ndimCheckBox.setChecked(self.layer.n_dimensional) def _on_contig_change(self, event=None): """Receive layer model contiguous change event and update the checkbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.contiguous.blocker(): self.contigCheckBox.setChecked(self.layer.contiguous) def _on_preserve_labels_change(self, event=None): """Receive layer model preserve_labels event and update the checkbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.preserve_labels.blocker(): self.preserveLabelsCheckBox.setChecked(self.layer.preserve_labels) def _on_color_mode_change(self, event=None): """Receive layer model color. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.color_mode.blocker(): index = self.colorModeComboBox.findText( self.layer.color_mode, Qt.MatchFixedString ) self.blendComboBox.setCurrentIndex(index) def _on_editable_change(self, event=None): """Receive layer model editable change event & enable/disable buttons. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ disable_with_opacity( self, ['pick_button', 'paint_button', 'fill_button'], self.layer.editable, )
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events._ndisplay.connect(self._on_ndisplay_change) self.layer.events.rendering.connect(self._on_rendering_change) self.layer.events.selected_label.connect( self._on_selected_label_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contiguous_change) self.layer.events.n_edit_dimensions.connect( self._on_n_edit_dimensions_change) self.layer.events.contour.connect(self._on_contour_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.events.preserve_labels.connect( self._on_preserve_labels_change) self.layer.events.color_mode.connect(self._on_color_mode_change) # selection spinbox self.selectionSpinBox = QLargeIntSpinBox() dtype_lims = get_dtype_limits(get_dtype(layer)) self.selectionSpinBox.setRange(*dtype_lims) self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self.selectionSpinBox.setAlignment(Qt.AlignCenter) self._on_selected_label_change() self.maskSelectionCheckBox = QCheckBox() self.maskSelectionCheckBox.setCheckState(Qt.CheckState.Unchecked) self.maskSelectionCheckBox.stateChanged.connect(self.maskSelection) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged.connect(self.changeSize) self.brushSizeSlider = sld self._on_brush_size_change() contig_cb = QCheckBox() contig_cb.setToolTip(trans._('contiguous editing')) contig_cb.stateChanged.connect(self.change_contig) self.contigCheckBox = contig_cb self._on_contiguous_change() ndim_sb = QSpinBox() self.ndimSpinBox = ndim_sb ndim_sb.setToolTip(trans._('number of dimensions for label editing')) ndim_sb.valueChanged.connect(self.change_n_edit_dim) ndim_sb.setMinimum(2) ndim_sb.setMaximum(self.layer.ndim) ndim_sb.setSingleStep(1) ndim_sb.setAlignment(Qt.AlignCenter) self._on_n_edit_dimensions_change() self.contourSpinBox = QLargeIntSpinBox() self.contourSpinBox.setRange(*dtype_lims) self.contourSpinBox.setToolTip(trans._('display contours of labels')) self.contourSpinBox.valueChanged.connect(self.change_contour) self.contourSpinBox.setKeyboardTracking(False) self.contourSpinBox.setAlignment(Qt.AlignCenter) self._on_contour_change() preserve_labels_cb = QCheckBox() preserve_labels_cb.setToolTip( trans._('preserve existing labels while painting')) preserve_labels_cb.stateChanged.connect(self.change_preserve_labels) self.preserveLabelsCheckBox = preserve_labels_cb self._on_preserve_labels_change() selectedColorCheckbox = QCheckBox() selectedColorCheckbox.setToolTip( trans._("Display only selected label")) selectedColorCheckbox.stateChanged.connect(self.toggle_selected_mode) self.selectedColorCheckbox = selectedColorCheckbox # shuffle colormap button self.colormapUpdate = QtModePushButton( None, 'shuffle', slot=self.changeColor, tooltip=trans._('shuffle colors'), ) self.panzoom_button = QtModeRadioButton( layer, 'zoom', Mode.PAN_ZOOM, checked=True, ) action_manager.bind_button('napari:activate_label_pan_zoom_mode', self.panzoom_button) self.pick_button = QtModeRadioButton(layer, 'picker', Mode.PICK) action_manager.bind_button('napari:activate_label_picker_mode', self.pick_button) self.paint_button = QtModeRadioButton(layer, 'paint', Mode.PAINT) action_manager.bind_button('napari:activate_paint_mode', self.paint_button) self.fill_button = QtModeRadioButton( layer, 'fill', Mode.FILL, ) action_manager.bind_button( 'napari:activate_fill_mode', self.fill_button, extra_tooltip_text=trans._( "Toggle with {shortcut}", shortcut=Shortcut("Control"), ), ) self.erase_button = QtModeRadioButton( layer, 'erase', Mode.ERASE, ) action_manager.bind_button( 'napari:activate_label_erase_mode', self.erase_button, extra_tooltip_text=trans._( "Toggle with {shortcut}", shortcut=Shortcut("Alt"), ), ) # don't bind with action manager as this would remove "Toggle with {shortcut}" self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.button_group.addButton(self.erase_button) self._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.colormapUpdate) button_row.addWidget(self.erase_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.pick_button) button_row.addWidget(self.panzoom_button) button_row.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) renderComboBox = QComboBox(self) rendering_options = [i.value for i in LabelsRendering] renderComboBox.addItems(rendering_options) index = renderComboBox.findText(self.layer.rendering, Qt.MatchFixedString) renderComboBox.setCurrentIndex(index) renderComboBox.activated[str].connect(self.changeRendering) self.renderComboBox = renderComboBox self.renderLabel = QLabel(trans._('rendering:')) self._on_ndisplay_change() color_mode_comboBox = QComboBox(self) for index, (data, text) in enumerate(LABEL_COLOR_MODE_TRANSLATIONS.items()): data = data.value color_mode_comboBox.addItem(text, data) if self.layer.color_mode == data: color_mode_comboBox.setCurrentIndex(index) color_mode_comboBox.activated.connect(self.change_color_mode) self.colorModeComboBox = color_mode_comboBox self._on_color_mode_change() color_layout = QHBoxLayout() self.colorBox = QtColorBox(layer) color_layout.addWidget(self.colorBox) color_layout.addWidget(self.selectionSpinBox) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 0, 1, 4) self.grid_layout.addWidget(QLabel(trans._('label:')), 1, 0, 1, 1) self.grid_layout.addWidget(self.maskSelectionCheckBox, 1, 1, 1, 1) self.grid_layout.addLayout(color_layout, 1, 2, 1, 2) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 2, 0, 1, 1) self.grid_layout.addWidget(self.opacitySlider, 2, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('brush size:')), 3, 0, 1, 1) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('blending:')), 5, 0, 1, 1) self.grid_layout.addWidget(self.blendComboBox, 5, 1, 1, 3) self.grid_layout.addWidget(self.renderLabel, 6, 0, 1, 1) self.grid_layout.addWidget(self.renderComboBox, 6, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('color mode:')), 7, 0, 1, 1) self.grid_layout.addWidget(self.colorModeComboBox, 7, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('contour:')), 8, 0, 1, 1) self.grid_layout.addWidget(self.contourSpinBox, 8, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('n edit dim:')), 9, 0, 1, 1) self.grid_layout.addWidget(self.ndimSpinBox, 9, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('contiguous:')), 10, 0, 1, 1) self.grid_layout.addWidget(self.contigCheckBox, 10, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('preserve\nlabels:')), 11, 0, 1, 2) self.grid_layout.addWidget(self.preserveLabelsCheckBox, 11, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('show\nselected:')), 11, 2, 1, 1) self.grid_layout.addWidget(self.selectedColorCheckbox, 11, 3, 1, 1) self.grid_layout.setRowStretch(12, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)