def __init__(self, layer): super().__init__() self.layer = layer layer.events.blending.connect(self._on_blending_change) layer.events.opacity.connect(self._on_opacity_change) self.setObjectName('layer') self.setMouseTracking(True) self.grid_layout = QGridLayout(self) self.grid_layout.setContentsMargins(0, 0, 0, 0) self.grid_layout.setSpacing(2) self.grid_layout.setColumnMinimumWidth(0, 86) self.grid_layout.setColumnStretch(1, 1) self.setLayout(self.grid_layout) sld = QSlider(Qt.Horizontal, parent=self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.valueChanged.connect(self.changeOpacity) self.opacitySlider = sld self._on_opacity_change() blend_comboBox = QComboBox(self) blend_comboBox.addItems(Blending.keys()) index = blend_comboBox.findText( self.layer.blending, Qt.MatchFixedString ) blend_comboBox.setCurrentIndex(index) blend_comboBox.activated[str].connect(self.changeBlending) self.blendComboBox = blend_comboBox
def __init__(self, layer): super().__init__() self.layer = layer layer.events.blending.connect(self._on_blending_change) layer.events.opacity.connect(self._on_opacity_change) self.setObjectName('layer') self.setMouseTracking(True) self.grid_layout = QGridLayout() self.grid_layout.setContentsMargins(0, 0, 0, 0) self.grid_layout.setSpacing(2) self.setLayout(self.grid_layout) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.setValue(self.layer.opacity * 100) sld.valueChanged[int].connect( lambda value=sld: self.changeOpacity(value)) self.opacitySilder = sld blend_comboBox = QComboBox() for blend in Blending: blend_comboBox.addItem(str(blend)) index = blend_comboBox.findText(self.layer.blending, Qt.MatchFixedString) blend_comboBox.setCurrentIndex(index) blend_comboBox.activated[str].connect( lambda text=blend_comboBox: self.changeBlending(text)) self.blendComboBox = blend_comboBox
class LabeledSlider(QWidget): def __init__(self, text, *args, minimum=1, maximum=10, parent=None, **kwargs): super(LabeledSlider, self).__init__(parent) self.label = QLabel(text) self.slider = QSlider(*args, **kwargs) self.slider.setMinimum(minimum) self.slider.setMaximum(maximum) self.slider.setTickInterval(5) self.valuebox = QSpinBox() self.valuebox.setRange(minimum, maximum) self.valuebox.setValue(self.slider.value()) self.slider.valueChanged.connect(self.valuebox.setValue) self.valuebox.valueChanged.connect(self.slider.setValue) layout = QHBoxLayout() layout.addWidget(self.label) layout.addWidget(self.slider) layout.addWidget(self.valuebox) self.setLayout(layout)
class Viewer(QWidget): def __init__(self, video): super().__init__() self.framenum = 0 self.video = video self.label = QLabel(self) self.vidlength = video.shape[0]-1 lisbon = Lisbon() p = self.palette() p.setColor(self.backgroundRole(), Qt.cyan) self.setPalette(p) self.setAutoFillBackground(True) self.initSlider() self.initUI() def initUI(self): #initialise UI self.update() self.slider.setGeometry(10, self.pixmap.height()+10, self.pixmap.width(), 50) self.label.setMargin(10) self.setGeometry(0, 0, self.pixmap.width()+20, (self.pixmap.height()+self.slider.height()*2)) self.slider.valueChanged.connect(self.valuechange) def update(self): #Update displayed image lisbon = Lisbon() self.npimage = self.video[self.framenum] self.image = self.np2qt(self.npimage) self.pixmap = QPixmap(QPixmap.fromImage(self.image)) self.label.setPixmap(self.pixmap) def wheelEvent(self, event): #scroll through slices and go to beginning if reached max self.framenum = self.framenum + int(event.angleDelta().y()/120) if self.framenum > self.vidlength: self.framenum = 0 if self.framenum < 0: self.framenum = self.vidlength self.slider.setValue(self.framenum) self.update() def np2qt(self, image): #transform np cv2 image to qt format height, width, channel = image.shape bytesPerLine = 3 * width return QImage(image.data, width, height, bytesPerLine, QImage.Format_RGB888) def initSlider(self): self.slider = QSlider(Qt.Horizontal, self) self.slider.setMinimum(0) self.slider.setMaximum(self.vidlength) def valuechange(self): self.framenum = self.slider.value() self.update()
def __init__(self, layer): super().__init__(layer) self.layer.events.edge_width.connect(self._on_edge_width_change) self.layer.events.edge_color.connect(self._on_edge_color_change) self.layer.events.face_color.connect(self._on_face_color_change) sld = QSlider(Qt.Horizontal, self) sld.setFocusPolicy(Qt.NoFocus) sld.setFixedWidth(75) sld.setMinimum(0) sld.setMaximum(40) sld.setSingleStep(1) value = self.layer.edge_width if isinstance(value, Iterable): if isinstance(value, list): value = np.asarray(value) value = value.mean() sld.setValue(int(value)) sld.valueChanged[int].connect(lambda value=sld: self.changeWidth(value)) self.widthSlider = sld self.grid_layout.addWidget(QLabel('width:'), 3, 0) self.grid_layout.addWidget(sld, 3, 1) face_comboBox = QComboBox() colors = self.layer._colors for c in colors: face_comboBox.addItem(c) index = face_comboBox.findText( self.layer.face_color, Qt.MatchFixedString) if index >= 0: face_comboBox.setCurrentIndex(index) face_comboBox.activated[str].connect(lambda text=face_comboBox: self.changeFaceColor(text)) self.faceComboBox = face_comboBox self.grid_layout.addWidget(QLabel('face_color:'), 4, 0) self.grid_layout.addWidget(face_comboBox, 4, 1) edge_comboBox = QComboBox() colors = self.layer._colors for c in colors: edge_comboBox.addItem(c) index = edge_comboBox.findText( self.layer.edge_color, Qt.MatchFixedString) if index >= 0: edge_comboBox.setCurrentIndex(index) edge_comboBox.activated[str].connect(lambda text=edge_comboBox: self.changeEdgeColor(text)) self.edgeComboBox = edge_comboBox self.grid_layout.addWidget(QLabel('edge_color:'), 5, 0) self.grid_layout.addWidget(edge_comboBox, 5, 1) self.setExpanded(False)
class QLabeledSlider(QWidget): """ A labeled slider widget """ range = None integer = None def __init__(self, parent=None): super(QLabeledSlider, self).__init__(parent) self._range = range self._slider = QSlider() self._slider.setMinimum(0) self._slider.setMaximum(100) self._slider.setOrientation(Qt.Horizontal) self._label = QLabel('') self._layout = QHBoxLayout() self._layout.setContentsMargins(2, 2, 2, 2) self._layout.addWidget(self._slider) self._layout.addWidget(self._label) self._slider.valueChanged.connect(self._update_label) self.setLayout(self._layout) def _update_label(self, *args): self._label.setText(str(self.value())) @property def valueChanged(self): return self._slider.valueChanged def value(self, layer=None, view=None): value = self._slider.value() / 100. * (self.range[1] - self.range[0]) + self.range[0] if self.integer: return int(value) else: return (value) _in_set_value = False def setValue(self, value): if self._in_set_value: return self._in_set_value = True value = int(100 * (value - self.range[0]) / (self.range[1] - self.range[0])) self._slider.setValue(value) self._in_set_value = False
class QLabeledSlider(QWidget): """ A labeled slider widget """ range = None integer = None def __init__(self, parent=None): super(QLabeledSlider, self).__init__(parent) self._range = range self._slider = QSlider() self._slider.setMinimum(0) self._slider.setMaximum(100) self._slider.setOrientation(Qt.Horizontal) self._label = QLabel('') self._layout = QHBoxLayout() self._layout.setContentsMargins(2, 2, 2, 2) self._layout.addWidget(self._slider) self._layout.addWidget(self._label) self._slider.valueChanged.connect(self._update_label) self.setLayout(self._layout) def _update_label(self, *args): self._label.setText(str(self.value())) @property def valueChanged(self): return self._slider.valueChanged def value(self, layer=None, view=None): value = self._slider.value() / 100. * (self.range[1] - self.range[0]) + self.range[0] if self.integer: return int(value) else: return(value) _in_set_value = False def setValue(self, value): if self._in_set_value: return self._in_set_value = True value = int(100 * (value - self.range[0]) / (self.range[1] - self.range[0])) self._slider.setValue(value) self._in_set_value = False
def __init__(self, layer): super().__init__(layer) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.gamma.connect(self._on_gamma_change) self.layer.events.contrast_limits.connect( self._on_contrast_limits_change ) comboBox = QtColormapComboBox(self) comboBox.setObjectName("colormapComboBox") comboBox._allitems = set(self.layer.colormaps) for name, cm in AVAILABLE_COLORMAPS.items(): if name in self.layer.colormaps: comboBox.addItem(cm._display_name, name) comboBox.activated[str].connect(self.changeColor) self.colormapComboBox = comboBox # Create contrast_limits slider self.contrastLimitsSlider = QHRangeSlider( self.layer.contrast_limits, self.layer.contrast_limits_range, parent=self, ) self.contrastLimitsSlider.mousePressEvent = self._clim_mousepress set_clim = partial(setattr, self.layer, 'contrast_limits') set_climrange = partial(setattr, self.layer, 'contrast_limits_range') self.contrastLimitsSlider.valuesChanged.connect(set_clim) self.contrastLimitsSlider.rangeChanged.connect(set_climrange) # gamma slider sld = QSlider(Qt.Horizontal, parent=self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(2) sld.setMaximum(200) sld.setSingleStep(2) sld.setValue(100) sld.valueChanged.connect(self.gamma_slider_changed) self.gammaSlider = sld self._on_gamma_change() self.colorbarLabel = QLabel(parent=self) self.colorbarLabel.setObjectName('colorbar') self.colorbarLabel.setToolTip(trans._('Colorbar')) self._on_colormap_change()
def __init__(self, layer): super().__init__(layer) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.contrast_limits.connect( lambda e: self.contrast_limits_slider_update() ) self.layer.events.gamma.connect(lambda e: self.gamma_slider_update()) comboBox = QComboBox() for cmap in self.layer.colormaps: comboBox.addItem(cmap) comboBox._allitems = set(self.layer.colormaps) comboBox.activated[str].connect( lambda text=comboBox: self.changeColor(text) ) self.colormapComboBox = comboBox # Create contrast_limits slider self.contrastLimitsSlider = QHRangeSlider( slider_range=[0, 1, 0.0001], values=[0, 1] ) self.contrastLimitsSlider.setEmitWhileMoving(True) self.contrastLimitsSlider.collapsable = False self.contrastLimitsSlider.setEnabled(True) self.contrastLimitsSlider.rangeChanged.connect( self.contrast_limits_slider_changed ) self.contrast_limits_slider_update() # gamma slider sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(2) sld.setMaximum(200) sld.setSingleStep(2) sld.setValue(100) sld.valueChanged[int].connect(self.gamma_slider_changed) self.gammaSlider = sld self.gamma_slider_update() self.colorbarLabel = QLabel() self.colorbarLabel.setObjectName('colorbar') self.colorbarLabel.setToolTip('Colorbar') self._on_colormap_change(None)
def __init__(self, layer): super().__init__(layer) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.gamma.connect(self.gamma_slider_update) self.layer.events.contrast_limits.connect(self._on_clims_change) comboBox = QComboBox() comboBox.addItems(self.layer.colormaps) comboBox._allitems = set(self.layer.colormaps) comboBox.activated[str].connect(self.changeColor) self.colormapComboBox = comboBox # Create contrast_limits slider self.contrastLimitsSlider = QHRangeSlider( self.layer.contrast_limits, self.layer.contrast_limits_range ) self.contrastLimitsSlider.mousePressEvent = self._clim_mousepress set_clim = partial(setattr, self.layer, 'contrast_limits') set_climrange = partial(setattr, self.layer, 'contrast_limits_range') self.contrastLimitsSlider.valuesChanged.connect(set_clim) self.contrastLimitsSlider.rangeChanged.connect(set_climrange) # gamma slider sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(2) sld.setMaximum(200) sld.setSingleStep(2) sld.setValue(100) sld.valueChanged.connect(self.gamma_slider_changed) self.gammaSlider = sld self.gamma_slider_update() self.colorbarLabel = QLabel() self.colorbarLabel.setObjectName('colorbar') self.colorbarLabel.setToolTip('Colorbar') self._on_colormap_change()
def __init__(self, layer): super().__init__() self.layer = layer self.layer.events.blending.connect(self._on_blending_change) self.layer.events.opacity.connect(self._on_opacity_change) self.setAttribute(Qt.WA_DeleteOnClose) self.setObjectName('layer') self.setMouseTracking(True) self.grid_layout = QGridLayout(self) self.grid_layout.setContentsMargins(0, 0, 0, 0) self.grid_layout.setSpacing(2) self.grid_layout.setColumnMinimumWidth(0, 86) self.grid_layout.setColumnStretch(1, 1) self.setLayout(self.grid_layout) sld = QSlider(Qt.Horizontal, parent=self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.valueChanged.connect(self.changeOpacity) self.opacitySlider = sld self._on_opacity_change() blend_comboBox = QComboBox(self) for index, (data, text) in enumerate(BLENDING_TRANSLATIONS.items()): data = data.value blend_comboBox.addItem(text, data) if data == self.layer.blending: blend_comboBox.setCurrentIndex(index) blend_comboBox.activated[str].connect(self.changeBlending) self.blendComboBox = blend_comboBox
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)
class QtTracksControls(QtLayerControls): """Qt view and controls for the Tracks layer. Parameters ---------- layer : napari.layers.Tracks An instance of a Tracks layer. Attributes ---------- grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : layers.Tracks An instance of a Tracks layer. """ layer: 'napari.layers.Tracks' def __init__(self, layer): super().__init__(layer) # NOTE(arl): there are no events fired for changing checkboxes self.layer.events.tail_width.connect(self._on_tail_width_change) self.layer.events.tail_length.connect(self._on_tail_length_change) self.layer.events.head_length.connect(self._on_head_length_change) self.layer.events.properties.connect(self._on_properties_change) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.color_by.connect(self._on_color_by_change) # combo box for track coloring, we can get these from the properties # keys self.color_by_combobox = QComboBox() self.color_by_combobox.addItems(self.layer.properties_to_color_by) self.colormap_combobox = QComboBox() for name, colormap in AVAILABLE_COLORMAPS.items(): display_name = colormap._display_name self.colormap_combobox.addItem(display_name, name) # slider for track head length self.head_length_slider = QSlider(Qt.Horizontal) self.head_length_slider.setFocusPolicy(Qt.NoFocus) self.head_length_slider.setMinimum(0) self.head_length_slider.setMaximum(self.layer._max_length) self.head_length_slider.setSingleStep(1) # slider for track tail length self.tail_length_slider = QSlider(Qt.Horizontal) self.tail_length_slider.setFocusPolicy(Qt.NoFocus) self.tail_length_slider.setMinimum(1) self.tail_length_slider.setMaximum(self.layer._max_length) self.tail_length_slider.setSingleStep(1) # slider for track edge width self.tail_width_slider = QSlider(Qt.Horizontal) self.tail_width_slider.setFocusPolicy(Qt.NoFocus) self.tail_width_slider.setMinimum(1) self.tail_width_slider.setMaximum(int(2 * self.layer._max_width)) self.tail_width_slider.setSingleStep(1) # checkboxes for display self.id_checkbox = QCheckBox() self.tail_checkbox = QCheckBox() self.tail_checkbox.setChecked(True) self.graph_checkbox = QCheckBox() self.graph_checkbox.setChecked(True) self.tail_width_slider.valueChanged.connect(self.change_tail_width) self.tail_length_slider.valueChanged.connect(self.change_tail_length) self.head_length_slider.valueChanged.connect(self.change_head_length) self.tail_checkbox.stateChanged.connect(self.change_display_tail) self.id_checkbox.stateChanged.connect(self.change_display_id) self.graph_checkbox.stateChanged.connect(self.change_display_graph) self.color_by_combobox.currentTextChanged.connect(self.change_color_by) self.colormap_combobox.currentTextChanged.connect(self.change_colormap) self.layout().addRow(trans._('color by:'), self.color_by_combobox) self.layout().addRow(trans._('colormap:'), self.colormap_combobox) self.layout().addRow(trans._('blending:'), self.blendComboBox) self.layout().addRow(trans._('opacity:'), self.opacitySlider) self.layout().addRow(trans._('tail width:'), self.tail_width_slider) self.layout().addRow(trans._('tail length:'), self.tail_length_slider) self.layout().addRow(trans._('head length:'), self.head_length_slider) self.layout().addRow(trans._('tail:'), self.tail_checkbox) self.layout().addRow(trans._('show ID:'), self.id_checkbox) self.layout().addRow(trans._('graph:'), self.graph_checkbox) self._on_tail_length_change() self._on_tail_width_change() self._on_colormap_change() self._on_color_by_change() def _on_tail_width_change(self): """Receive layer model track line width change event and update slider.""" with self.layer.events.tail_width.blocker(): value = int(2 * self.layer.tail_width) self.tail_width_slider.setValue(value) def _on_tail_length_change(self): """Receive layer model track line width change event and update slider.""" with self.layer.events.tail_length.blocker(): value = self.layer.tail_length self.tail_length_slider.setValue(value) def _on_head_length_change(self): """Receive layer model track line width change event and update slider.""" with self.layer.events.head_length.blocker(): value = self.layer.head_length self.head_length_slider.setValue(value) def _on_properties_change(self): """Change the properties that can be used to color the tracks.""" with self.layer.events.properties.blocker(): with qt_signals_blocked(self.color_by_combobox): self.color_by_combobox.clear() self.color_by_combobox.addItems(self.layer.properties_to_color_by) def _on_colormap_change(self): """Receive layer model colormap change event and update combobox.""" with self.layer.events.colormap.blocker(): self.colormap_combobox.setCurrentIndex( self.colormap_combobox.findData(self.layer.colormap)) def _on_color_by_change(self): """Receive layer model color_by change event and update combobox.""" with self.layer.events.color_by.blocker(): color_by = self.layer.color_by idx = self.color_by_combobox.findText(color_by, Qt.MatchFixedString) self.color_by_combobox.setCurrentIndex(idx) def change_tail_width(self, value): """Change track line width of shapes on the layer model. Parameters ---------- value : float Line width of track tails. """ self.layer.tail_width = float(value) / 2.0 def change_tail_length(self, value): """Change edge line backward length of shapes on the layer model. Parameters ---------- value : int Line length of track tails. """ self.layer.tail_length = value def change_head_length(self, value): """Change edge line forward length of shapes on the layer model. Parameters ---------- value : int Line length of track tails. """ self.layer.head_length = value def change_display_tail(self, state): self.layer.display_tail = self.tail_checkbox.isChecked() def change_display_id(self, state): self.layer.display_id = self.id_checkbox.isChecked() def change_display_graph(self, state): self.layer.display_graph = self.graph_checkbox.isChecked() def change_color_by(self, value: str): self.layer.color_by = value def change_colormap(self, colormap: str): self.layer.colormap = self.colormap_combobox.currentData()
def __init__(self, layer): super().__init__(layer) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.layer.events.symbol.connect(self._on_symbol_change) self.layer.events.size.connect(self._on_size_change) self.layer.events.edge_color.connect(self._on_edge_color_change) self.layer.events.face_color.connect(self._on_face_color_change) sld = QSlider(Qt.Horizontal, self) sld.setFocusPolicy(Qt.NoFocus) sld.setFixedWidth(110) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) value = self.layer.size if isinstance(value, Iterable): if isinstance(value, list): value = np.asarray(value) value = value.mean() sld.setValue(int(value)) sld.valueChanged[int].connect(lambda value=sld: self.changeSize(value)) self.sizeSlider = sld self.grid_layout.addWidget(QLabel('size:'), 3, 0) self.grid_layout.addWidget(sld, 3, 1) face_comboBox = QComboBox() colors = self.layer._colors for c in colors: face_comboBox.addItem(c) index = face_comboBox.findText(self.layer.face_color, Qt.MatchFixedString) face_comboBox.setCurrentIndex(index) face_comboBox.activated[str].connect( lambda text=face_comboBox: self.changeFaceColor(text)) self.faceComboBox = face_comboBox self.grid_layout.addWidget(QLabel('face_color:'), 4, 0) self.grid_layout.addWidget(face_comboBox, 4, 1) edge_comboBox = QComboBox() colors = self.layer._colors for c in colors: edge_comboBox.addItem(c) index = edge_comboBox.findText(self.layer.edge_color, Qt.MatchFixedString) edge_comboBox.setCurrentIndex(index) edge_comboBox.activated[str].connect( lambda text=edge_comboBox: self.changeEdgeColor(text)) self.edgeComboBox = edge_comboBox self.grid_layout.addWidget(QLabel('edge_color:'), 5, 0) self.grid_layout.addWidget(edge_comboBox, 5, 1) symbol_comboBox = QComboBox() for s in Symbol: symbol_comboBox.addItem(str(s)) index = symbol_comboBox.findText(self.layer.symbol, Qt.MatchFixedString) symbol_comboBox.setCurrentIndex(index) symbol_comboBox.activated[str].connect( lambda text=symbol_comboBox: self.changeSymbol(text)) self.symbolComboBox = symbol_comboBox self.grid_layout.addWidget(QLabel('symbol:'), 6, 0) self.grid_layout.addWidget(symbol_comboBox, 6, 1) ndim_cb = QCheckBox() ndim_cb.setToolTip('N-dimensional markers') ndim_cb.setChecked(self.layer.n_dimensional) ndim_cb.stateChanged.connect( lambda state=ndim_cb: self.change_ndim(state)) self.ndimCheckBox = ndim_cb self.grid_layout.addWidget(QLabel('n-dim:'), 7, 0) self.grid_layout.addWidget(ndim_cb, 7, 1) self.setExpanded(False)
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)
class livestream(QWidget): i = 0 def __init__(self,qnd,images = None,annotations_on = True,annotate_coords = None,threshold_switch = False): QWidget.__init__(self) self.threshold_switch = threshold_switch self.video = images #frames buffer self.videobox = Label() if annotations_on and annotate_coords is not None: self.coords = annotate_coords self.videobox.switch = annotations_on self.videobox.activecoord = self.coords[0] if self.video is not None: self.videobox.activeframe = self.video[0] self.videobox.maxintens = self.video.shape[0] else: self.videobox.activeframe = np.loadtxt(os.getcwd() + '/defaultimage.txt') print(self.videobox.activeframe.shape) self.videobox.maxintens = np.max(self.videobox.activeframe) self.videobox.setGeometry(QtCore.QRect(70, 80, 310, 310)) self.videobox.h = 310 self.videobox.w = 310 self.lyt = QVBoxLayout() self.lyt.addWidget(self.videobox,5) self.setLayout(self.lyt) self.sl = QSlider(Qt.Horizontal) self.sl.setMinimum(0.0) if self.video is not None: self.sl.setMaximum(self.video.shape[0]) self.sl.valueChanged.connect(self.whenslidechanges) self.sl.setTickPosition(QSlider.TicksAbove) self.sl.setTracking(True) self.sl.setTickInterval(100) self.frame_counter = QDoubleSpinBox() if images is not None: self.frame = images[0] self.frame_counter.valueChanged.connect(self.video_time_update) self.frame_counter.setSingleStep(1) self.frame_counter.setRange(self.sl.minimum(),self.sl.maximum()) self.frame_counter.valueChanged.connect(self.sl.setValue) self.video_time = QDoubleSpinBox() self.video_time.setSingleStep(30) self.video_time.setRange(self.sl.minimum(),30*self.sl.maximum()) self.frameratetimer = QTimer() self.frameratetimer.setInterval(30) if self.video is not None: self.frameratetimer.timeout.connect(self.update_display) self.play_button = QPushButton('Play Video') self.play_button.clicked.connect(self.frameratetimer.start) self.stop_button = QPushButton('Stop Video') self.stop_button.clicked.connect(self.frameratetimer.stop) if self.video is not None: self.sl.valueChanged.connect(self.whenslidechanges) self.lyt.addWidget(self.play_button,0) self.lyt.addWidget(self.stop_button,1) self.lyt.addWidget(self.sl,2) self.lyt.addWidget(self.frame_counter,3) self.lyt.addWidget(self.video_time,4) self.show() def assign_images(self,images,centres = None): '''#first disconnect signals from eachother so nothing should change whilst video data is being updated self.sl.valueChanged.disconnect(self.video_time_update) self.frameratetimer.timeout.disconnect(self.update_display) self.frame_counter.valueChanged.disconnect(self.whenslidechanges) ''' self.video = images self.coords = centres self.videobox.activeframe = self.video[0] if self.coords is not None: self.videobox.activecoord = self.coords[0] #readjust slider and ticker values to dimensions of video self.sl.setMaximum(len(self.video)-1) self.frame_counter.setRange(self.sl.minimum(),self.sl.maximum()) self.video_time.setRange(self.sl.minimum(),30*self.sl.maximum()) #connect slider and timer etc. self.sl.valueChanged.connect(self.whenslidechanges) self.frameratetimer.timeout.connect(self.update_display) self.frame_counter.valueChanged.connect(self.video_time_update) self.videobox.maxintens = np.max(self.video) self.videobox.update() def update_display(self): if self.threshold_switch: frame = self.video[livestream.i] threshold = threshold_otsu(frame) mask = np.zeros_like(frame) mask[frame > threshold] = 1 self.videobox.maxintens = 1 self.videobox.activeframe = mask else: #if threshold switch is off display usual video, so change active frame source and reset maximum intensity for passing to qimage2ndarray self.videobox.activeframe = self.video[livestream.i] self.videobox.maxintens = np.max(self.video) try: self.videobox.activecoord = self.coords[livestream.i] if not self.videobox.switch: self.videobox.switch = True except: self.videobox.activecoord = None self.videobox.switch = False self.videobox.update() self.frame_counter.setValue(float(livestream.i)) livestream.i+=1 def whenslidechanges(self): if self.frameratetimer.isActive(): self.frameratetimer.stop() livestream.i = self.sl.value() self.update_display() livestream.i -=1 self.frameratetimer.start() else: livestream.i = self.sl.value() self.update_display() livestream.i -=1 def video_time_update(self): self.video_time.setValue(30*self.frame_counter.value()) def turn_on_threshold(self,threshold_switch): self.threshold_switch = threshold_switch self.update_display()
def __init__(self, layer): super().__init__() self.layer = layer layer.events.select.connect(lambda v: self.setSelected(True)) layer.events.deselect.connect(lambda v: self.setSelected(False)) layer.events.name.connect(self._on_layer_name_change) layer.events.blending.connect(self._on_blending_change) layer.events.opacity.connect(self._on_opacity_change) layer.events.visible.connect(self._on_visible_change) layer.events.thumbnail.connect(self._on_thumbnail_change) self.setObjectName('layer') self.vbox_layout = QVBoxLayout() self.top = QFrame() self.top_layout = QHBoxLayout() self.grid = QFrame() self.grid_layout = QGridLayout() self.vbox_layout.addWidget(self.top) self.vbox_layout.addWidget(self.grid) self.vbox_layout.setSpacing(0) self.top.setFixedHeight(38) self.top_layout.setContentsMargins(0, 0, 0, 0) self.grid_layout.setContentsMargins(0, 0, 0, 0) self.top_layout.setAlignment(Qt.AlignCenter) self.top.setLayout(self.top_layout) self.grid.setLayout(self.grid_layout) self.setLayout(self.vbox_layout) self.name_column = 0 self.property_column = 1 cb = QCheckBox(self) cb.setObjectName('visibility') cb.setToolTip('Layer visibility') cb.setChecked(self.layer.visible) cb.setProperty('mode', 'visibility') cb.stateChanged.connect(lambda state=cb: self.changeVisible(state)) self.visibleCheckBox = cb self.top_layout.addWidget(cb) tb = QLabel(self) tb.setObjectName('thumbmnail') tb.setToolTip('Layer thumbmnail') self.thumbnail_label = tb self._on_thumbnail_change(None) self.top_layout.addWidget(tb) textbox = QLineEdit(self) textbox.setText(layer.name) textbox.home(False) textbox.setToolTip('Layer name') textbox.setAcceptDrops(False) textbox.setEnabled(True) textbox.editingFinished.connect(self.changeText) self.nameTextBox = textbox self.top_layout.addWidget(textbox) pb = QPushButton(self) pb.setToolTip('Expand properties') pb.clicked.connect(self.changeExpanded) pb.setObjectName('expand') self.expand_button = pb self.top_layout.addWidget(pb) row = self.grid_layout.rowCount() sld = QSlider(Qt.Horizontal, self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.setValue(self.layer.opacity * 100) sld.valueChanged[int].connect( lambda value=sld: self.changeOpacity(value)) self.opacitySilder = sld row = self.grid_layout.rowCount() self.grid_layout.addWidget(QLabel('opacity:'), row, self.name_column) self.grid_layout.addWidget(sld, row, self.property_column) row = self.grid_layout.rowCount() blend_comboBox = QComboBox() for blend in Blending: blend_comboBox.addItem(str(blend)) index = blend_comboBox.findText(self.layer.blending, Qt.MatchFixedString) blend_comboBox.setCurrentIndex(index) blend_comboBox.activated[str].connect( lambda text=blend_comboBox: self.changeBlending(text)) self.blendComboBox = blend_comboBox self.grid_layout.addWidget(QLabel('blending:'), row, self.name_column) self.grid_layout.addWidget(blend_comboBox, row, self.property_column) msg = 'Click to select\nDrag to rearrange\nDouble click to expand' self.setToolTip(msg) self.setExpanded(False) self.setFixedWidth(250) self.grid_layout.setColumnMinimumWidth(0, 100) self.grid_layout.setColumnMinimumWidth(1, 100) self.setSelected(self.layer.selected)
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.edge_width.connect(self._on_edge_width_change) self.layer.events.current_edge_color.connect( self._on_current_edge_color_change) self.layer.events.current_face_color.connect( self._on_current_face_color_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.text.events.visible.connect(self._on_text_visibility_change) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(40) sld.setSingleStep(1) value = self.layer.current_edge_width if isinstance(value, Iterable): if isinstance(value, list): value = np.asarray(value) value = value.mean() sld.setValue(int(value)) sld.valueChanged.connect(self.changeWidth) self.widthSlider = sld self.select_button = QtModeRadioButton(layer, 'select', Mode.SELECT, tooltip='Select shapes') self.direct_button = QtModeRadioButton(layer, 'direct', Mode.DIRECT, tooltip='Select vertices') self.panzoom_button = QtModeRadioButton(layer, 'zoom', Mode.PAN_ZOOM, tooltip='Pan/zoom', checked=True) self.rectangle_button = QtModeRadioButton(layer, 'rectangle', Mode.ADD_RECTANGLE, tooltip='Add rectangles') self.ellipse_button = QtModeRadioButton(layer, 'ellipse', Mode.ADD_ELLIPSE, tooltip='Add ellipses') self.line_button = QtModeRadioButton(layer, 'line', Mode.ADD_LINE, tooltip='Add lines') self.path_button = QtModeRadioButton(layer, 'path', Mode.ADD_PATH, tooltip='Add paths') self.polygon_button = QtModeRadioButton(layer, 'polygon', Mode.ADD_POLYGON, tooltip='Add polygons') self.vertex_insert_button = QtModeRadioButton(layer, 'vertex_insert', Mode.VERTEX_INSERT, tooltip='Insert vertex') self.vertex_remove_button = QtModeRadioButton(layer, 'vertex_remove', Mode.VERTEX_REMOVE, tooltip='Remove vertex') self.move_front_button = QtModePushButton( layer, 'move_front', slot=self.layer.move_to_front, tooltip='Move to front', ) self.move_back_button = QtModePushButton( layer, 'move_back', slot=self.layer.move_to_back, tooltip='Move to back', ) self.delete_button = QtModePushButton( layer, 'delete_shape', slot=self.layer.remove_selected, tooltip='Delete selected shapes', ) self.button_group = QButtonGroup(self) self.button_group.addButton(self.select_button) self.button_group.addButton(self.direct_button) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.rectangle_button) self.button_group.addButton(self.ellipse_button) self.button_group.addButton(self.line_button) self.button_group.addButton(self.path_button) self.button_group.addButton(self.polygon_button) self.button_group.addButton(self.vertex_insert_button) self.button_group.addButton(self.vertex_remove_button) button_grid = QGridLayout() button_grid.addWidget(self.vertex_remove_button, 0, 2) button_grid.addWidget(self.vertex_insert_button, 0, 3) button_grid.addWidget(self.delete_button, 0, 4) button_grid.addWidget(self.direct_button, 0, 5) button_grid.addWidget(self.select_button, 0, 6) button_grid.addWidget(self.panzoom_button, 0, 7) button_grid.addWidget(self.move_back_button, 1, 1) button_grid.addWidget(self.move_front_button, 1, 2) button_grid.addWidget(self.ellipse_button, 1, 3) button_grid.addWidget(self.rectangle_button, 1, 4) button_grid.addWidget(self.polygon_button, 1, 5) button_grid.addWidget(self.line_button, 1, 6) button_grid.addWidget(self.path_button, 1, 7) button_grid.setContentsMargins(5, 0, 0, 5) button_grid.setColumnStretch(0, 1) button_grid.setSpacing(4) self.faceColorEdit = QColorSwatchEdit( initial_color=self.layer.current_face_color, tooltip='click to set current face color', ) self._on_current_face_color_change() self.edgeColorEdit = QColorSwatchEdit( initial_color=self.layer.current_edge_color, tooltip='click to set current edge color', ) self._on_current_edge_color_change() self.faceColorEdit.color_changed.connect(self.changeFaceColor) self.edgeColorEdit.color_changed.connect(self.changeEdgeColor) text_disp_cb = QCheckBox() text_disp_cb.setToolTip('toggle text visibility') text_disp_cb.setChecked(self.layer.text.visible) text_disp_cb.stateChanged.connect(self.change_text_visibility) self.textDispCheckBox = text_disp_cb # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_grid, 0, 0, 1, 2) self.grid_layout.addWidget(QLabel('opacity:'), 1, 0) self.grid_layout.addWidget(self.opacitySlider, 1, 1) self.grid_layout.addWidget(QLabel('edge width:'), 2, 0) self.grid_layout.addWidget(self.widthSlider, 2, 1) self.grid_layout.addWidget(QLabel('blending:'), 3, 0) self.grid_layout.addWidget(self.blendComboBox, 3, 1) self.grid_layout.addWidget(QLabel('face color:'), 4, 0) self.grid_layout.addWidget(self.faceColorEdit, 4, 1) self.grid_layout.addWidget(QLabel('edge color:'), 5, 0) self.grid_layout.addWidget(self.edgeColorEdit, 5, 1) self.grid_layout.addWidget(QLabel('display text:'), 6, 0) self.grid_layout.addWidget(self.textDispCheckBox, 6, 1) self.grid_layout.setRowStretch(7, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
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 __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 __init__(self, layer): super().__init__(layer) self.layer.events.interpolation.connect(self._on_interpolation_change) self.layer.events.rendering.connect(self._on_rendering_change) self.layer.events.iso_threshold.connect(self._on_iso_threshold_change) self.layer.dims.events.ndisplay.connect(self._on_ndisplay_change) interp_comboBox = QComboBox() for interp in Interpolation: interp_comboBox.addItem(str(interp)) index = interp_comboBox.findText(self.layer.interpolation, Qt.MatchFixedString) interp_comboBox.setCurrentIndex(index) interp_comboBox.activated[str].connect( lambda text=interp_comboBox: self.changeInterpolation(text)) self.interpComboBox = interp_comboBox self.interpLabel = QLabel('interpolation:') renderComboBox = QComboBox() for render in Rendering: renderComboBox.addItem(str(render)) index = renderComboBox.findText(self.layer.rendering, Qt.MatchFixedString) renderComboBox.setCurrentIndex(index) renderComboBox.activated[str].connect( lambda text=renderComboBox: self.changeRendering(text)) self.renderComboBox = renderComboBox self.renderLabel = QLabel('rendering:') sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.setValue(self.layer.iso_threshold * 100) sld.valueChanged[int].connect( lambda value=sld: self.changeIsoTheshold(value)) self.isoThesholdSilder = sld self.isoThesholdLabel = QLabel('iso threshold:') self._on_ndisplay_change(None) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addWidget(QLabel('opacity:'), 0, 0) self.grid_layout.addWidget(self.opacitySilder, 0, 1, 1, 2) self.grid_layout.addWidget(QLabel('contrast limits:'), 1, 0) self.grid_layout.addWidget(self.contrastLimitsSlider, 1, 1, 1, 2) self.grid_layout.addWidget(QLabel('gamma:'), 2, 0) self.grid_layout.addWidget(self.gammaSlider, 2, 1, 1, 2) self.grid_layout.addWidget(self.isoThesholdLabel, 3, 0) self.grid_layout.addWidget(self.isoThesholdSilder, 3, 1, 1, 2) self.grid_layout.addWidget(QLabel('colormap:'), 4, 0) self.grid_layout.addWidget(self.colormapComboBox, 4, 2) self.grid_layout.addWidget(self.colorbarLabel, 4, 1) self.grid_layout.addWidget(QLabel('blending:'), 5, 0) self.grid_layout.addWidget(self.blendComboBox, 5, 1, 1, 2) self.grid_layout.addWidget(self.renderLabel, 6, 0) self.grid_layout.addWidget(self.renderComboBox, 6, 1, 1, 2) self.grid_layout.addWidget(self.interpLabel, 7, 0) self.grid_layout.addWidget(self.interpComboBox, 7, 1, 1, 2) self.grid_layout.setRowStretch(8, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setVerticalSpacing(4)
class QtTracksControls(QtLayerControls): """Qt view and controls for the Tracks layer. Parameters ---------- layer : napari.layers.Tracks An instance of a Tracks layer. Attributes ---------- grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : layers.Tracks An instance of a Tracks layer. """ def __init__(self, layer): super().__init__(layer) # NOTE(arl): there are no events fired for changing checkboxes self.layer.events.tail_width.connect(self._on_tail_width_change) self.layer.events.tail_length.connect(self._on_tail_length_change) self.layer.events.properties.connect(self._on_properties_change) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.color_by.connect(self._on_color_by_change) # combo box for track coloring, we can get these from the properties # keys self.color_by_combobox = QComboBox() self.color_by_combobox.addItems(self.layer.properties_to_color_by) self.colormap_combobox = QComboBox() for name, colormap in AVAILABLE_COLORMAPS.items(): display_name = colormap._display_name self.colormap_combobox.addItem(display_name, name) # slider for track tail length self.tail_length_slider = QSlider(Qt.Horizontal) self.tail_length_slider.setFocusPolicy(Qt.NoFocus) self.tail_length_slider.setMinimum(1) self.tail_length_slider.setMaximum(MAX_TAIL_LENGTH) self.tail_length_slider.setSingleStep(1) # slider for track edge width self.tail_width_slider = QSlider(Qt.Horizontal) self.tail_width_slider.setFocusPolicy(Qt.NoFocus) self.tail_width_slider.setMinimum(1) self.tail_width_slider.setMaximum(MAX_TAIL_WIDTH) self.tail_width_slider.setSingleStep(1) # checkboxes for display self.id_checkbox = QCheckBox() self.tail_checkbox = QCheckBox() self.tail_checkbox.setChecked(True) self.graph_checkbox = QCheckBox() self.graph_checkbox.setChecked(True) self.tail_width_slider.valueChanged.connect(self.change_tail_width) self.tail_length_slider.valueChanged.connect(self.change_tail_length) self.tail_checkbox.stateChanged.connect(self.change_display_tail) self.id_checkbox.stateChanged.connect(self.change_display_id) self.graph_checkbox.stateChanged.connect(self.change_display_graph) self.color_by_combobox.currentTextChanged.connect(self.change_color_by) self.colormap_combobox.currentTextChanged.connect(self.change_colormap) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addWidget(QLabel(trans._('color by:')), 0, 0) self.grid_layout.addWidget(self.color_by_combobox, 0, 1) self.grid_layout.addWidget(QLabel(trans._('colormap:')), 1, 0) self.grid_layout.addWidget(self.colormap_combobox, 1, 1) self.grid_layout.addWidget(QLabel(trans._('blending:')), 2, 0) self.grid_layout.addWidget(self.blendComboBox, 2, 1) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 3, 0) self.grid_layout.addWidget(self.opacitySlider, 3, 1) self.grid_layout.addWidget(QLabel(trans._('tail width:')), 4, 0) self.grid_layout.addWidget(self.tail_width_slider, 4, 1) self.grid_layout.addWidget(QLabel(trans._('tail length:')), 5, 0) self.grid_layout.addWidget(self.tail_length_slider, 5, 1) self.grid_layout.addWidget(QLabel(trans._('tail:')), 6, 0) self.grid_layout.addWidget(self.tail_checkbox, 6, 1) self.grid_layout.addWidget(QLabel(trans._('show ID:')), 7, 0) self.grid_layout.addWidget(self.id_checkbox, 7, 1) self.grid_layout.addWidget(QLabel(trans._('graph:')), 8, 0) self.grid_layout.addWidget(self.graph_checkbox, 8, 1) self.grid_layout.setRowStretch(9, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) self._on_tail_length_change() self._on_tail_width_change() self._on_colormap_change() self._on_color_by_change() def _on_tail_width_change(self, event=None): """Receive layer model track line width change event and update slider. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.tail_width.blocker(): value = self.layer.tail_width value = np.clip(int(2 * value), 1, MAX_TAIL_WIDTH) self.tail_width_slider.setValue(value) def _on_tail_length_change(self, event=None): """Receive layer model track line width change event and update slider. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.tail_length.blocker(): value = self.layer.tail_length value = np.clip(value, 1, MAX_TAIL_LENGTH) self.tail_length_slider.setValue(value) def _on_properties_change(self, event=None): """Change the properties that can be used to color the tracks.""" with self.layer.events.properties.blocker(): with qt_signals_blocked(self.color_by_combobox): self.color_by_combobox.clear() self.color_by_combobox.addItems(self.layer.properties_to_color_by) def _on_colormap_change(self, event=None): """Receive layer model colormap change event and update combobox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.colormap.blocker(): self.colormap_combobox.setCurrentIndex( self.colormap_combobox.findData(self.layer.colormap)) def _on_color_by_change(self, event=None): """Receive layer model color_by change event and update combobox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.color_by.blocker(): color_by = self.layer.color_by idx = self.color_by_combobox.findText(color_by, Qt.MatchFixedString) self.color_by_combobox.setCurrentIndex(idx) def change_tail_width(self, value): """Change track line width of shapes on the layer model. Parameters ---------- value : float Line width of track tails. """ self.layer.tail_width = float(value) / 2.0 def change_tail_length(self, value): """Change edge line width of shapes on the layer model. Parameters ---------- value : int Line length of track tails. """ self.layer.tail_length = value def change_display_tail(self, state): self.layer.display_tail = self.tail_checkbox.isChecked() def change_display_id(self, state): self.layer.display_id = self.id_checkbox.isChecked() def change_display_graph(self, state): self.layer.display_graph = self.graph_checkbox.isChecked() def change_color_by(self, value: str): self.layer.color_by = value def change_colormap(self, colormap: str): self.layer.colormap = self.colormap_combobox.currentData()
class PyDMSlider(QFrame, PyDMWritableWidget): """ A QSlider with support for Channels and more from PyDM. Parameters ---------- parent : QWidget The parent widget for the Label init_channel : str, optional The channel to be used by the widget. """ actionTriggered = Signal(int) rangeChanged = Signal(float, float) sliderMoved = Signal(float) sliderPressed = Signal() sliderReleased = Signal() valueChanged = Signal(float) def __init__(self, parent=None, init_channel=None): QFrame.__init__(self, parent) PyDMWritableWidget.__init__(self, init_channel=init_channel) self.alarmSensitiveContent = True self.alarmSensitiveBorder = False # Internal values for properties self.set_enable_state() self._show_limit_labels = True self._show_value_label = True self._user_defined_limits = False self._needs_limit_info = True self._minimum = None self._maximum = None self._user_minimum = -10.0 self._user_maximum = 10.0 self._num_steps = 101 self._orientation = Qt.Horizontal # Set up all the internal widgets that make up a PyDMSlider. # We'll add all these things to layouts when we call setup_widgets_for_orientation label_size_policy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) self.low_lim_label = QLabel(self) self.low_lim_label.setObjectName("lowLimLabel") self.low_lim_label.setSizePolicy(label_size_policy) self.low_lim_label.setAlignment(Qt.AlignLeft | Qt.AlignTrailing | Qt.AlignVCenter) self.value_label = QLabel(self) self.value_label.setObjectName("valueLabel") self.value_label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.high_lim_label = QLabel(self) self.high_lim_label.setObjectName("highLimLabel") self.high_lim_label.setSizePolicy(label_size_policy) self.high_lim_label.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self._slider = QSlider(parent=self) self._slider.setOrientation(Qt.Horizontal) self._slider.sliderMoved.connect(self.internal_slider_moved) self._slider.sliderPressed.connect(self.internal_slider_pressed) self._slider.sliderReleased.connect(self.internal_slider_released) self._slider.valueChanged.connect(self.internal_slider_value_changed) # self.vertical_layout.addWidget(self._slider) # Other internal variables and final setup steps self._slider_position_to_value_map = None self._mute_internal_slider_changes = False self.setup_widgets_for_orientation(self._orientation) self.reset_slider_limits() def init_for_designer(self): """ Method called after the constructor to tweak configurations for when using the widget with the Qt Designer """ self.value = 0.0 @Property(Qt.Orientation) def orientation(self): """ The slider orientation (Horizontal or Vertical) Returns ------- int Qt.Horizontal or Qt.Vertical """ return self._orientation @orientation.setter def orientation(self, new_orientation): """ The slider orientation (Horizontal or Vertical) Parameters ---------- new_orientation : int Qt.Horizontal or Qt.Vertical """ self._orientation = new_orientation self.setup_widgets_for_orientation(new_orientation) def setup_widgets_for_orientation(self, new_orientation): """ Reconstruct the widget given the orientation. Parameters ---------- new_orientation : int Qt.Horizontal or Qt.Vertical """ if new_orientation not in (Qt.Horizontal, Qt.Vertical): logger.error( "Invalid orientation '{0}'. The existing layout will not change." .format(new_orientation)) return layout = None if new_orientation == Qt.Horizontal: layout = QVBoxLayout() layout.setContentsMargins(4, 0, 4, 4) label_layout = QHBoxLayout() label_layout.addWidget(self.low_lim_label) label_layout.addStretch(0) label_layout.addWidget(self.value_label) label_layout.addStretch(0) label_layout.addWidget(self.high_lim_label) layout.addLayout(label_layout) self._slider.setOrientation(new_orientation) layout.addWidget(self._slider) elif new_orientation == Qt.Vertical: layout = QHBoxLayout() layout.setContentsMargins(0, 4, 4, 4) label_layout = QVBoxLayout() label_layout.addWidget(self.high_lim_label) label_layout.addStretch(0) label_layout.addWidget(self.value_label) label_layout.addStretch(0) label_layout.addWidget(self.low_lim_label) layout.addLayout(label_layout) self._slider.setOrientation(new_orientation) layout.addWidget(self._slider) if self.layout() is not None: # Trick to remove the existing layout by re-parenting it in an empty widget. QWidget().setLayout(self.layout()) self.setLayout(layout) def update_labels(self): """ Update the limits and value labels with the correct values. """ def set_label(value, label_widget): if value is None: label_widget.setText("") else: label_widget.setText(self.format_string.format(value)) set_label(self.minimum, self.low_lim_label) set_label(self.maximum, self.high_lim_label) set_label(self.value, self.value_label) def reset_slider_limits(self): """ Reset the limits and adjust the labels properly for the slider. """ if self.minimum is None or self.maximum is None: self._needs_limit_info = True self.set_enable_state() return self._needs_limit_info = False self._slider.setMinimum(0) self._slider.setMaximum(self._num_steps - 1) self._slider.setSingleStep(1) self._slider.setPageStep(10) self._slider_position_to_value_map = np.linspace(self.minimum, self.maximum, num=self._num_steps) self.update_labels() self.set_slider_to_closest_value(self.value) self.rangeChanged.emit(self.minimum, self.maximum) self.set_enable_state() def find_closest_slider_position_to_value(self, val): """ Find and returns the index for the closest position on the slider for a given value. Parameters ---------- val : float Returns ------- int """ diff = abs(self._slider_position_to_value_map - float(val)) return np.argmin(diff) def set_slider_to_closest_value(self, val): """ Set the value for the slider according to a given value. Parameters ---------- val : float """ if val is None or self._needs_limit_info: return # When we set the slider to the closest value, it may end up at a slightly # different position than val (if val is not in self._slider_position_to_value_map) # We don't want that slight difference to get broacast out and put the channel # somewhere new. For example, if the slider can only be at 0.4 or 0.5, but a # new value comes in of 0.45, its more important to keep the 0.45 than to change # it to where the slider gets set. Therefore, we mute the internal slider changes # so that its valueChanged signal doesn't cause us to emit a signal to PyDM to change # the value of the channel. self._mute_internal_slider_changes = True self._slider.setValue(self.find_closest_slider_position_to_value(val)) self._mute_internal_slider_changes = False def value_changed(self, new_val): """ Callback invoked when the Channel value is changed. Parameters ---------- new_val : int or float The new value from the channel. """ PyDMWritableWidget.value_changed(self, new_val) if hasattr(self, "value_label"): self.value_label.setText(self.format_string.format(self.value)) if not self._slider.isSliderDown(): self.set_slider_to_closest_value(self.value) def ctrl_limit_changed(self, which, new_limit): """ Callback invoked when the Channel receives new control limit values. Parameters ---------- which : str Which control limit was changed. "UPPER" or "LOWER" new_limit : float New value for the control limit """ PyDMWritableWidget.ctrl_limit_changed(self, which, new_limit) if not self.userDefinedLimits: self.reset_slider_limits() def update_format_string(self): """ Reconstruct the format string to be used when representing the output value. Returns ------- format_string : str The format string to be used including or not the precision and unit """ fs = PyDMWritableWidget.update_format_string(self) self.update_labels() return fs def set_enable_state(self): """ Determines wether or not the widget must be enabled or not depending on the write access, connection state and presence of limits information """ self.setEnabled(self._write_access and self._connected and not self._needs_limit_info) @Slot(int) def internal_slider_action_triggered(self, action): self.actionTriggered.emit(action) @Slot(int) def internal_slider_moved(self, val): """ Method invoked when the slider is moved. Parameters ---------- val : float """ # The user has moved the slider, we need to update our value. # Only update the underlying value, not the self.value property, # because we don't need to reset the slider position. If we change # self.value, we can get into a loop where the position changes, which # updates the value, which changes the position again, etc etc. self.value = self._slider_position_to_value_map[val] self.sliderMoved.emit(self.value) @Slot() def internal_slider_pressed(self): """ Method invoked when the slider is pressed """ self.sliderPressed.emit() @Slot() def internal_slider_released(self): """ Method invoked when the slider is released """ self.sliderReleased.emit() @Slot(int) def internal_slider_value_changed(self, val): """ Method invoked when a new value is selected on the slider. This will cause the new value to be emitted to the signal unless `mute_internal_slider_changes` is True. Parameters ---------- val : int """ # At this point, our local copy of the value reflects the position of the # slider, now all we need to do is emit a signal to PyDM so that the data # plugin will send a put to the channel. Don't update self.value or self._value # in here, it is pointless at best, and could cause an infinite loop at worst. if not self._mute_internal_slider_changes: self.send_value_signal[float].emit(self.value) @Property(bool) def showLimitLabels(self): """ Whether or not the high and low limits should be displayed on the slider. Returns ------- bool """ return self._show_limit_labels @showLimitLabels.setter def showLimitLabels(self, checked): """ Whether or not the high and low limits should be displayed on the slider. Parameters ---------- checked : bool """ self._show_limit_labels = checked if checked: self.low_lim_label.show() self.high_lim_label.show() else: self.low_lim_label.hide() self.high_lim_label.hide() @Property(bool) def showValueLabel(self): """ Whether or not the current value should be displayed on the slider. Returns ------- bool """ return self._show_value_label @showValueLabel.setter def showValueLabel(self, checked): """ Whether or not the current value should be displayed on the slider. Parameters ---------- checked : bool """ self._show_value_label = checked if checked: self.value_label.show() else: self.value_label.hide() @Property(QSlider.TickPosition) def tickPosition(self): """ Where to draw tick marks for the slider. Returns ------- QSlider.TickPosition """ return self._slider.tickPosition() @tickPosition.setter def tickPosition(self, position): """ Where to draw tick marks for the slider. Parameter --------- position : QSlider.TickPosition """ self._slider.setTickPosition(position) @Property(bool) def userDefinedLimits(self): """ Wether or not to use limits defined by the user and not from the channel Returns ------- bool """ return self._user_defined_limits @userDefinedLimits.setter def userDefinedLimits(self, user_defined_limits): """ Wether or not to use limits defined by the user and not from the channel Parameters ---------- user_defined_limits : bool """ self._user_defined_limits = user_defined_limits self.reset_slider_limits() @Property(float) def userMinimum(self): """ Lower user defined limit value Returns ------- float """ return self._user_minimum @userMinimum.setter def userMinimum(self, new_min): """ Lower user defined limit value Parameters ---------- new_min : float """ self._user_minimum = float(new_min) if new_min is not None else None if self.userDefinedLimits: self.reset_slider_limits() @Property(float) def userMaximum(self): """ Upper user defined limit value Returns ------- float """ return self._user_maximum @userMaximum.setter def userMaximum(self, new_max): """ Upper user defined limit value Parameters ---------- new_max : float """ self._user_maximum = float(new_max) if new_max is not None else None if self.userDefinedLimits: self.reset_slider_limits() @property def minimum(self): """ The current value being used for the lower limit Returns ------- float """ if self.userDefinedLimits: return self._user_minimum return self._lower_ctrl_limit @property def maximum(self): """ The current value being used for the upper limit Returns ------- float """ if self.userDefinedLimits: return self._user_maximum return self._upper_ctrl_limit @Property(int) def num_steps(self): """ The number of steps on the slider Returns ------- int """ return self._num_steps @num_steps.setter def num_steps(self, new_steps): """ The number of steps on the slider Parameters ---------- new_steps : int """ self._num_steps = int(new_steps) self.reset_slider_limits()
class QtSizeSliderPreviewWidget(QWidget): """ Widget displaying a description, textedit and slider to adjust font size with preview. Parameters ---------- parent : qtpy.QtWidgets.QWidget, optional Default is None. description : str, optional Default is "". preview_text : str, optional Default is "". value : int, optional Default is None. min_value : int, optional Default is 1. max_value : int, optional Default is 50. unit : str, optional Default is "px". """ valueChanged = Signal(int) def __init__( self, parent: QWidget = None, description: str = None, preview_text: str = None, value: int = None, min_value: int = 1, max_value: int = 50, unit: str = "px", ): super().__init__(parent) description = description or "" preview_text = preview_text or "" self._value = value if value else self.fontMetrics().height() self._min_value = min_value self._max_value = max_value # Widget self._lineedit = QLineEdit() self._description_label = QLabel(self) self._unit_label = QLabel(self) self._slider = QSlider(Qt.Horizontal, self) self._slider_min_label = QLabel(self) self._slider_max_label = QLabel(self) self._preview = QtFontSizePreview(self) self._preview_label = QLabel(self) self._validator = None # Widgets setup self._description_label.setText(description) self._description_label.setWordWrap(True) self._unit_label.setText(unit) self._lineedit.setAlignment(Qt.AlignRight) self._slider_min_label.setText(str(min_value)) self._slider_max_label.setText(str(max_value)) self._slider.setMinimum(min_value) self._slider.setMaximum(max_value) self._preview.setText(preview_text) self._preview_label.setText(trans._("preview")) self._preview_label.setAlignment(Qt.AlignHCenter) self.setFocusProxy(self._lineedit) # Layout left_bottom_layout = QHBoxLayout() left_bottom_layout.addWidget(self._lineedit) left_bottom_layout.addWidget(self._unit_label) left_bottom_layout.addWidget(self._slider_min_label) left_bottom_layout.addWidget(self._slider) left_bottom_layout.addWidget(self._slider_max_label) left_layout = QVBoxLayout() left_layout.addWidget(self._description_label) left_layout.addLayout(left_bottom_layout) right_layout = QVBoxLayout() right_layout.addWidget(self._preview) right_layout.addWidget(self._preview_label) layout = QHBoxLayout() layout.addLayout(left_layout, 2) layout.addLayout(right_layout, 1) self.setLayout(layout) # Signals self._slider.valueChanged.connect(self._update_value) self._lineedit.textChanged.connect(self._update_value) self._update_line_width() self._update_validator() self._update_value(self._value) def _update_validator(self): self._validator = QIntValidator(self._min_value, self._max_value, self) self._lineedit.setValidator(self._validator) def _update_line_width(self): """Update width ofg line text edit.""" size = self._lineedit.fontMetrics().horizontalAdvance( "m" * (1 + len(str(self._max_value)))) self._lineedit.setMaximumWidth(size) self._lineedit.setMinimumWidth(size) def _update_value(self, value: int): """Update internal value and emit if changed.""" if value == "": value = int(self._value) value = int(value) if value > self._max_value: value = self._max_value elif value < self._min_value: value = self._min_value if value != self._value: self.valueChanged.emit(value) self._value = value self._refresh(self._value) def _refresh(self, value: int = None): """Refresh the value on all subwidgets.""" value = value if value else self._value self.blockSignals(True) self._lineedit.setText(str(value)) self._slider.setValue(value) font = QFont() font.setPixelSize(value) self._preview.setFont(font) font = QFont() font.setPixelSize(self.fontMetrics().height() - 4) self._preview_label.setFont(font) self.blockSignals(False) def description(self) -> str: """Return the current widget description. Returns ------- str The description text. """ return self._description_label.text() def setDescription(self, text: str): """Set the current widget description. Parameters ---------- text : str The description text. """ self._description_label.setText(text) def previewText(self) -> str: """Return the current preview text. Returns ------- str The current preview text. """ return self._preview.text() def setPreviewText(self, text: str): """Set the current preview text. Parameters ---------- text : str The current preview text. """ self._preview.setText(text) def unit(self) -> str: """Return the current unit text. Returns ------- str The current unit text. """ return self._unit_label.text() def setUnit(self, text: str): """Set the current unit text. Parameters ---------- text : str The current preview text. """ self._unit_label.setText(text) def minimum(self) -> int: """Return the current minimum value for the slider and value in textbox. Returns ------- int The minimum value for the slider. """ return self._min_value def setMinimum(self, value: int): """Set the current minimum value for the slider and value in textbox. Parameters ---------- value : int The minimum value for the slider. """ value = int(value) if value < self._max_value: self._min_value = value self._value = (self._min_value if self._value < self._min_value else self._value) self._slider_min_label.setText(str(value)) self._slider.setMinimum(value) self._update_validator() self._refresh() else: raise ValueError( trans._("Minimum value must be smaller than {}".format( self._max_value))) def maximum(self) -> int: """Return the maximum value for the slider and value in textbox. Returns ------- int The maximum value for the slider. """ return self._max_value def setMaximum(self, value: int): """Set the maximum value for the slider and value in textbox. Parameters ---------- value : int The maximum value for the slider. """ value = int(value) if value > self._min_value: self._max_value = value self._value = (self._max_value if self._value > self._max_value else self._value) self._slider_max_label.setText(str(value)) self._slider.setMaximum(value) self._update_validator() self._update_line_width() self._refresh() else: raise ValueError( trans._("Maximum value must be larger than {}".format( self._min_value))) def value(self) -> int: """Return the current widget value. Returns ------- int The current value. """ return self._value def setValue(self, value: int): """Set the current widget value. Parameters ---------- value : int The current value. """ self._update_value(value)
def __init__(self, layer): super().__init__(layer) self.layer.events.interpolation.connect(self._on_interpolation_change) self.layer.events.rendering.connect(self._on_rendering_change) self.layer.events.iso_threshold.connect(self._on_iso_threshold_change) self.layer.events.attenuation.connect(self._on_attenuation_change) self.layer.dims.events.ndisplay.connect(self._on_ndisplay_change) self.interpComboBox = QComboBox(self) self.interpComboBox.activated[str].connect(self.changeInterpolation) self.interpLabel = QLabel('interpolation:') renderComboBox = QComboBox(self) renderComboBox.addItems(Rendering.keys()) index = renderComboBox.findText( self.layer.rendering, Qt.MatchFixedString ) renderComboBox.setCurrentIndex(index) renderComboBox.activated[str].connect(self.changeRendering) self.renderComboBox = renderComboBox self.renderLabel = QLabel('rendering:') sld = QSlider(Qt.Horizontal, parent=self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.setValue(int(self.layer.iso_threshold * 100)) sld.valueChanged.connect(self.changeIsoThreshold) self.isoThresholdSlider = sld self.isoThresholdLabel = QLabel('iso threshold:') sld = QSlider(Qt.Horizontal, parent=self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.setValue(int(self.layer.attenuation * 200)) sld.valueChanged.connect(self.changeAttenuation) self.attenuationSlider = sld self.attenuationLabel = QLabel('attenuation:') self._on_ndisplay_change() colormap_layout = QHBoxLayout() colormap_layout.addWidget(self.colorbarLabel) colormap_layout.addWidget(self.colormapComboBox) colormap_layout.addStretch(1) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addWidget(QLabel('opacity:'), 0, 0) self.grid_layout.addWidget(self.opacitySlider, 0, 1) self.grid_layout.addWidget(QLabel('contrast limits:'), 1, 0) self.grid_layout.addWidget(self.contrastLimitsSlider, 1, 1) self.grid_layout.addWidget(QLabel('gamma:'), 2, 0) self.grid_layout.addWidget(self.gammaSlider, 2, 1) self.grid_layout.addWidget(QLabel('colormap:'), 3, 0) self.grid_layout.addLayout(colormap_layout, 3, 1) self.grid_layout.addWidget(QLabel('blending:'), 4, 0) self.grid_layout.addWidget(self.blendComboBox, 4, 1) self.grid_layout.addWidget(self.interpLabel, 5, 0) self.grid_layout.addWidget(self.interpComboBox, 5, 1) self.grid_layout.addWidget(self.renderLabel, 6, 0) self.grid_layout.addWidget(self.renderComboBox, 6, 1) self.grid_layout.addWidget(self.isoThresholdLabel, 7, 0) self.grid_layout.addWidget(self.isoThresholdSlider, 7, 1) self.grid_layout.addWidget(self.attenuationLabel, 8, 0) self.grid_layout.addWidget(self.attenuationSlider, 8, 1) self.grid_layout.setRowStretch(9, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
def create_wwwc_tab(apply_adjust): Conf = namedtuple("Conf", "min max step default") ww_conf = Conf(0, 2000, 1, 350) wc_conf = Conf(-2000, 2000, 1, 50) tab = QWidget() tab.layout = QFormLayout() # BUG: 只有一个负号的时候会变成0,应该保留负号 ww_edit = QLineEdit() ww_edit.setValidator(QtGui.QIntValidator(ww_conf.min, ww_conf.max)) ww_edit.setFixedWidth(50) wc_edit = QLineEdit() wc_edit.setValidator(QtGui.QIntValidator(wc_conf.min, wc_conf.max)) wc_edit.setFixedWidth(50) ww_slider = QSlider(Qt.Horizontal) # 窗宽滑动条 ww_slider.setMinimum(ww_conf.min) ww_slider.setMaximum(ww_conf.max) ww_slider.setSingleStep(ww_conf.step) ww_slider.setValue(ww_conf.default) wc_slider = QSlider(Qt.Horizontal) # 窗位滑动条 wc_slider.setMinimum(wc_conf.min) wc_slider.setMaximum(wc_conf.max) wc_slider.setSingleStep(wc_conf.step) wc_slider.setValue(wc_conf.default) ww_label = QLabel() ww_label.setText("窗宽: ") wc_label = QLabel() wc_label.setText("窗位: ") ww_combo = QHBoxLayout() ww_combo.addWidget(ww_edit) ww_combo.addWidget(ww_slider) wc_combo = QHBoxLayout() wc_combo.addWidget(wc_edit) wc_combo.addWidget(wc_slider) tab.layout.addRow(ww_label, ww_combo) tab.layout.addRow(wc_label, wc_combo) tab.setLayout(tab.layout) def slider_change(slider, editor): def func(): editor.setText(str(slider.value())) apply_adjust( functools.partial(wwwc, ww_slider.value(), wc_slider.value())) return func def edit_changed(editor, slider): def func(): value = editor.text() if value == "" or value == "-": value = 0 value = int(value) slider.setValue(value) return func ww_slider.valueChanged.connect(slider_change(ww_slider, ww_edit)) wc_slider.valueChanged.connect(slider_change(wc_slider, wc_edit)) ww_edit.textChanged.connect(edit_changed(ww_edit, ww_slider)) # wc_edit.textChanged.connect(wc_edit_change) return tab, "WW/WC"
class QtHighlightSizePreviewWidget(QDialog): """Creates custom widget to set highlight size. Parameters ---------- description : str Text to explain and display on widget. value : int Value of highlight size. min_value : int Minimum possible value of highlight size. max_value : int Maximum possible value of highlight size. unit : str Unit of highlight size. """ valueChanged = Signal(int) def __init__( self, parent: QWidget = None, description: str = "", value: int = 1, min_value: int = 1, max_value: int = 10, unit: str = "px", ): super().__init__(parent) self.setGeometry(300, 300, 125, 110) self._value = value if value else self.fontMetrics().height() self._min_value = min_value self._max_value = max_value # Widget self._lineedit = QLineEdit() self._description = QLabel(self) self._unit = QLabel(self) self._slider = QSlider(Qt.Horizontal) self._triangle = QtTriangle(self) self._slider_min_label = QLabel(self) self._slider_max_label = QLabel(self) self._preview = QtStar(self) self._preview_label = QLabel(self) self._validator = QIntValidator(min_value, max_value, self) # Widgets setup self._description.setText(description) self._description.setWordWrap(True) self._unit.setText(unit) self._unit.setAlignment(Qt.AlignBottom) self._lineedit.setValidator(self._validator) self._lineedit.setAlignment(Qt.AlignRight) self._lineedit.setAlignment(Qt.AlignBottom) self._slider_min_label.setText(str(min_value)) self._slider_min_label.setAlignment(Qt.AlignBottom) self._slider_max_label.setText(str(max_value)) self._slider_max_label.setAlignment(Qt.AlignBottom) self._slider.setMinimum(min_value) self._slider.setMaximum(max_value) self._preview.setValue(value) self._triangle.setValue(value) self._triangle.setMinimum(min_value) self._triangle.setMaximum(max_value) self._preview_label.setText(trans._("Preview")) self._preview_label.setAlignment(Qt.AlignHCenter) self._preview_label.setAlignment(Qt.AlignBottom) self._preview.setStyleSheet('border: 1px solid white;') # Signals self._slider.valueChanged.connect(self._update_value) self._lineedit.textChanged.connect(self._update_value) self._triangle.valueChanged.connect(self._update_value) # Layout triangle_layout = QHBoxLayout() triangle_layout.addWidget(self._triangle) triangle_layout.setContentsMargins(6, 35, 6, 0) triangle_slider_layout = QVBoxLayout() triangle_slider_layout.addLayout(triangle_layout) triangle_slider_layout.setContentsMargins(0, 0, 0, 0) triangle_slider_layout.addWidget(self._slider) triangle_slider_layout.setAlignment(Qt.AlignVCenter) # Bottom row layout lineedit_layout = QHBoxLayout() lineedit_layout.addWidget(self._lineedit) lineedit_layout.setAlignment(Qt.AlignBottom) bottom_left_layout = QHBoxLayout() bottom_left_layout.addLayout(lineedit_layout) bottom_left_layout.addWidget(self._unit) bottom_left_layout.addWidget(self._slider_min_label) bottom_left_layout.addLayout(triangle_slider_layout) bottom_left_layout.addWidget(self._slider_max_label) bottom_left_layout.setAlignment(Qt.AlignBottom) left_layout = QVBoxLayout() left_layout.addWidget(self._description) left_layout.addLayout(bottom_left_layout) left_layout.setAlignment(Qt.AlignLeft) preview_label_layout = QHBoxLayout() preview_label_layout.addWidget(self._preview_label) preview_label_layout.setAlignment(Qt.AlignHCenter) preview_layout = QVBoxLayout() preview_layout.addWidget(self._preview) preview_layout.addLayout(preview_label_layout) preview_layout.setAlignment(Qt.AlignCenter) layout = QHBoxLayout() layout.addLayout(left_layout) layout.addLayout(preview_layout) self.setLayout(layout) self._refresh() def _update_value(self, value): """Update highlight value. Parameters ---------- value: int Highlight value. """ if value == "": value = int(self._value) value = int(value) if value > self._max_value: value = self._max_value elif value < self._min_value: value = self._min_value if value != self._value: self.valueChanged.emit(value) self._value = value self._refresh() def _refresh(self): """Set every widget value to the new set value.""" self.blockSignals(True) self._lineedit.setText(str(self._value)) self._slider.setValue(self._value) self._triangle.setValue(self._value) self._preview.setValue(self._value) self.blockSignals(False) self.valueChanged.emit(self._value) def value(self): """Return current value. Returns ------- int Current value of highlight widget. """ return self._value def setValue(self, value): """Set new value and update widget. Parameters ---------- value: int Highlight value. """ self._update_value(value) self._refresh() def description(self): """Return the description text. Returns ------- str Current text in description. """ return self._description.text() def setDescription(self, text): """Set the description text. Parameters ---------- text: str Text to use in description box. """ self._description.setText(text) def unit(self): """Return highlight value unit text. Returns ------- str Current text in unit text. """ return self._unit.text() def setUnit(self, text): """Set highlight value unit. Parameters ---------- text: str Text used to describe units. """ self._unit.setText(text) def setMinimum(self, value): """Set minimum highlight value for star, triangle, text and slider. Parameters ---------- value: int Minimum highlight value. """ value = int(value) if value < self._max_value: self._min_value = value self._slider_min_label.setText(str(value)) self._slider.setMinimum(value) self._triangle.setMinimum(value) self._value = (self._min_value if self._value < self._min_value else self._value) self._refresh() else: raise ValueError( f"Minimum value must be smaller than {self._max_value}") def minimum(self): """Return minimum highlight value. Returns ------- int Minimum value of highlight widget. """ return self._min_value def setMaximum(self, value): """Set maximum highlight value. Parameters ---------- value: int Maximum highlight value. """ value = int(value) if value > self._min_value: self._max_value = value self._slider_max_label.setText(str(value)) self._slider.setMaximum(value) self._triangle.setMaximum(value) self._value = (self._max_value if self._value > self._max_value else self._value) self._refresh() else: raise ValueError( f"Maximum value must be larger than {self._min_value}") def maximum(self): """Return maximum highlight value. Returns ------- int Maximum value of highlight widget. """ return self._max_value
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self.set_mode) self.layer.events.edge_width.connect(self._on_edge_width_change) self.layer.events.edge_color.connect(self._on_edge_color_change) self.layer.events.face_color.connect(self._on_face_color_change) self.layer.events.editable.connect(self._on_editable_change) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(40) sld.setSingleStep(1) value = self.layer.edge_width if isinstance(value, Iterable): if isinstance(value, list): value = np.asarray(value) value = value.mean() sld.setValue(int(value)) sld.valueChanged[int].connect( lambda value=sld: self.changeWidth(value) ) self.widthSlider = sld face_comboBox = QComboBox() colors = self.layer._colors for c in colors: face_comboBox.addItem(c) face_comboBox.activated[str].connect( lambda text=face_comboBox: self.changeFaceColor(text) ) self.faceComboBox = face_comboBox self.faceColorSwatch = QFrame() self.faceColorSwatch.setObjectName('swatch') self.faceColorSwatch.setToolTip('Face color swatch') self._on_face_color_change(None) edge_comboBox = QComboBox() colors = self.layer._colors for c in colors: edge_comboBox.addItem(c) edge_comboBox.activated[str].connect( lambda text=edge_comboBox: self.changeEdgeColor(text) ) self.edgeComboBox = edge_comboBox self.edgeColorSwatch = QFrame() self.edgeColorSwatch.setObjectName('swatch') self.edgeColorSwatch.setToolTip('Edge color swatch') self._on_edge_color_change(None) self.select_button = QtModeButton( layer, 'select', Mode.SELECT, 'Select shapes' ) self.direct_button = QtModeButton( layer, 'direct', Mode.DIRECT, 'Select vertices' ) self.panzoom_button = QtModeButton( layer, 'zoom', Mode.PAN_ZOOM, 'Pan/zoom' ) self.rectangle_button = QtModeButton( layer, 'rectangle', Mode.ADD_RECTANGLE, 'Add rectangles' ) self.ellipse_button = QtModeButton( layer, 'ellipse', Mode.ADD_ELLIPSE, 'Add ellipses' ) self.line_button = QtModeButton( layer, 'line', Mode.ADD_LINE, 'Add lines' ) self.path_button = QtModeButton( layer, 'path', Mode.ADD_PATH, 'Add paths' ) self.polygon_button = QtModeButton( layer, 'polygon', Mode.ADD_POLYGON, 'Add polygons' ) self.vertex_insert_button = QtModeButton( layer, 'vertex_insert', Mode.VERTEX_INSERT, 'Insert vertex' ) self.vertex_remove_button = QtModeButton( layer, 'vertex_remove', Mode.VERTEX_REMOVE, 'Remove vertex' ) self.move_front_button = QtMoveFrontButton(layer) self.move_back_button = QtMoveBackButton(layer) self.delete_button = QtDeleteShapeButton(layer) self.panzoom_button.setChecked(True) self.button_group = QButtonGroup(self) self.button_group.addButton(self.select_button) self.button_group.addButton(self.direct_button) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.rectangle_button) self.button_group.addButton(self.ellipse_button) self.button_group.addButton(self.line_button) self.button_group.addButton(self.path_button) self.button_group.addButton(self.polygon_button) self.button_group.addButton(self.vertex_insert_button) self.button_group.addButton(self.vertex_remove_button) button_grid = QGridLayout() button_grid.addWidget(self.vertex_remove_button, 0, 1) button_grid.addWidget(self.vertex_insert_button, 0, 2) button_grid.addWidget(self.delete_button, 0, 3) button_grid.addWidget(self.direct_button, 0, 4) button_grid.addWidget(self.select_button, 0, 5) button_grid.addWidget(self.panzoom_button, 0, 6) button_grid.addWidget(self.move_back_button, 1, 0) button_grid.addWidget(self.move_front_button, 1, 1) button_grid.addWidget(self.ellipse_button, 1, 2) button_grid.addWidget(self.rectangle_button, 1, 3) button_grid.addWidget(self.polygon_button, 1, 4) button_grid.addWidget(self.line_button, 1, 5) button_grid.addWidget(self.path_button, 1, 6) button_grid.setColumnStretch(2, 2) button_grid.setSpacing(4) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_grid, 0, 0, 1, 3) self.grid_layout.addWidget(QLabel('opacity:'), 1, 0) self.grid_layout.addWidget(self.opacitySilder, 1, 1, 1, 2) self.grid_layout.addWidget(QLabel('edge width:'), 2, 0) self.grid_layout.addWidget(self.widthSlider, 2, 1, 1, 2) self.grid_layout.addWidget(QLabel('blending:'), 3, 0) self.grid_layout.addWidget(self.blendComboBox, 3, 1, 1, 2) self.grid_layout.addWidget(QLabel('face color:'), 4, 0) self.grid_layout.addWidget(self.faceComboBox, 4, 2) self.grid_layout.addWidget(self.faceColorSwatch, 4, 1) self.grid_layout.addWidget(QLabel('edge color:'), 5, 0) self.grid_layout.addWidget(self.edgeComboBox, 5, 2) self.grid_layout.addWidget(self.edgeColorSwatch, 5, 1) self.grid_layout.setRowStretch(6, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.n_dimensional.connect(self._on_n_dimensional_change) self.layer.events.symbol.connect(self._on_symbol_change) self.layer.events.size.connect(self._on_size_change) self.layer.events.current_edge_color.connect( self._on_current_edge_color_change) self.layer.events.current_face_color.connect( self._on_current_face_color_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.text.events.visible.connect(self._on_text_visibility_change) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(100) sld.setSingleStep(1) value = self.layer.current_size sld.setValue(int(value)) sld.valueChanged.connect(self.changeSize) self.sizeSlider = sld self.faceColorEdit = QColorSwatchEdit( initial_color=self.layer.current_face_color, tooltip='click to set current face color', ) self.edgeColorEdit = QColorSwatchEdit( initial_color=self.layer.current_edge_color, tooltip='click to set current edge color', ) self.faceColorEdit.color_changed.connect(self.changeFaceColor) self.edgeColorEdit.color_changed.connect(self.changeEdgeColor) symbol_comboBox = QComboBox() symbol_comboBox.addItems([str(s) for s in Symbol]) index = symbol_comboBox.findText(self.layer.symbol, Qt.MatchFixedString) symbol_comboBox.setCurrentIndex(index) symbol_comboBox.activated[str].connect(self.changeSymbol) self.symbolComboBox = symbol_comboBox ndim_cb = QCheckBox() ndim_cb.setToolTip('N-dimensional points') ndim_cb.setChecked(self.layer.n_dimensional) ndim_cb.stateChanged.connect(self.change_ndim) self.ndimCheckBox = ndim_cb self.select_button = QtModeRadioButton(layer, 'select_points', Mode.SELECT, tooltip='Select points') self.addition_button = QtModeRadioButton(layer, 'add_points', Mode.ADD, tooltip='Add points') self.panzoom_button = QtModeRadioButton(layer, 'pan_zoom', Mode.PAN_ZOOM, tooltip='Pan/zoom', checked=True) self.delete_button = QtModePushButton( layer, 'delete_shape', slot=self.layer.remove_selected, tooltip='Delete selected points', ) text_disp_cb = QCheckBox() text_disp_cb.setToolTip('toggle text visibility') text_disp_cb.setChecked(self.layer.text.visible) text_disp_cb.stateChanged.connect(self.change_text_visibility) self.textDispCheckBox = text_disp_cb self.button_group = QButtonGroup(self) self.button_group.addButton(self.select_button) self.button_group.addButton(self.addition_button) self.button_group.addButton(self.panzoom_button) button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.delete_button) button_row.addWidget(self.addition_button) button_row.addWidget(self.select_button) button_row.addWidget(self.panzoom_button) button_row.setContentsMargins(0, 0, 0, 5) 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) self.grid_layout.addWidget(QLabel('opacity:'), 1, 0) self.grid_layout.addWidget(self.opacitySlider, 1, 1) self.grid_layout.addWidget(QLabel('point size:'), 2, 0) self.grid_layout.addWidget(self.sizeSlider, 2, 1) self.grid_layout.addWidget(QLabel('blending:'), 3, 0) self.grid_layout.addWidget(self.blendComboBox, 3, 1) self.grid_layout.addWidget(QLabel('symbol:'), 4, 0) self.grid_layout.addWidget(self.symbolComboBox, 4, 1) self.grid_layout.addWidget(QLabel('face color:'), 5, 0) self.grid_layout.addWidget(self.faceColorEdit, 5, 1) self.grid_layout.addWidget(QLabel('edge color:'), 6, 0) self.grid_layout.addWidget(self.edgeColorEdit, 6, 1) self.grid_layout.addWidget(QLabel('display text:'), 7, 0) self.grid_layout.addWidget(self.textDispCheckBox, 7, 1) self.grid_layout.addWidget(QLabel('n-dim:'), 8, 0) self.grid_layout.addWidget(self.ndimCheckBox, 8, 1) self.grid_layout.setRowStretch(9, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
class MiscellaneousLauncher(QWidget): def __init__(self, parent): super().__init__() # set title self.setWindowTitle(config.thisTranslation["cp4"]) # set up variables self.parent = parent # setup interface self.setupUI() def setupUI(self): mainLayout = QGridLayout() leftLayout = QVBoxLayout() rightLayout = QVBoxLayout() self.highLightLauncher = HighlightLauncher(self) leftLayout.addWidget(self.highLightLauncher) rightLayout.addWidget(self.noteEditor()) rightLayout.addWidget(self.textToSpeechUtility()) rightLayout.addWidget(self.utilities()) rightLayout.addStretch() mainLayout.addLayout(leftLayout, 0, 0, 1, 2) mainLayout.addLayout(rightLayout, 0, 2, 1, 1) self.setLayout(mainLayout) def noteEditor(self): box = QGroupBox(config.thisTranslation["note_editor"]) subLayout = QHBoxLayout() button = QPushButton(config.thisTranslation["menu7_create"]) button.setToolTip(config.thisTranslation["menu7_create"]) button.clicked.connect(self.parent.parent.createNewNoteFile) subLayout.addWidget(button) button = QPushButton(config.thisTranslation["menu7_open"]) button.setToolTip(config.thisTranslation["menu7_open"]) button.clicked.connect(self.parent.parent.openTextFileDialog) subLayout.addWidget(button) box.setLayout(subLayout) return box def utilities(self): box = QGroupBox(config.thisTranslation["utilities"]) subLayout = QHBoxLayout() button = QPushButton(config.thisTranslation["presentation"]) button.setToolTip(config.thisTranslation["presentation"]) button.clicked.connect( lambda: self.parent.parent.runPlugin("Presentation")) subLayout.addWidget(button) if config.isYoutubeDownloaderInstalled: button = QPushButton(config.thisTranslation["youtube_utility"]) button.setToolTip(config.thisTranslation["youtube_utility"]) button.clicked.connect(self.parent.parent.openYouTube) subLayout.addWidget(button) box.setLayout(subLayout) return box def textToSpeechUtility(self): box = QGroupBox(config.thisTranslation["tts_utility"]) layout = QVBoxLayout() subLayout = QHBoxLayout() self.ttsEdit = QLineEdit() self.ttsEdit.setClearButtonEnabled(True) self.ttsEdit.setToolTip(config.thisTranslation["enter_text_here"]) self.ttsEdit.returnPressed.connect(self.speakText) subLayout.addWidget(self.ttsEdit) layout.addLayout(subLayout) self.ttsSlider = QSlider(Qt.Horizontal) self.ttsSlider.setToolTip(config.thisTranslation["adjustSpeed"]) self.ttsSlider.setMinimum(10) self.ttsSlider.setMaximum(310) self.ttsSlider.setValue(config.espeakSpeed if config.espeak else ( 160 + config.qttsSpeed * 150)) self.ttsSlider.valueChanged.connect( self.changeEspeakSpeed if config.espeak else self.changeQttsSpeed) layout.addWidget(self.ttsSlider) subLayout = QHBoxLayout() self.languageCombo = QComboBox() subLayout.addWidget(self.languageCombo) if config.espeak: languages = TtsLanguages().isoLang2epeakLang else: languages = TtsLanguages().isoLang2qlocaleLang self.languageCodes = list(languages.keys()) for code in self.languageCodes: self.languageCombo.addItem(languages[code][1]) # Check if selected tts engine has the language user specify. if not (config.ttsDefaultLangauge in self.languageCodes): config.ttsDefaultLangauge = "en" # Set initial index # It is essential. Otherwise, default tts language is changed by defaultTtsLanguageChanged method. ttsLanguageIndex = self.languageCodes.index(config.ttsDefaultLangauge) self.languageCombo.setCurrentIndex(ttsLanguageIndex) # Change default tts language as users select a new language self.languageCombo.currentIndexChanged.connect( self.defaultTtsLanguageChanged) button = QPushButton(config.thisTranslation["speak"]) button.setToolTip(config.thisTranslation["speak"]) button.clicked.connect(self.speakText) subLayout.addWidget(button) button = QPushButton(config.thisTranslation["stop"]) button.setToolTip(config.thisTranslation["stop"]) button.clicked.connect( self.parent.parent.textCommandParser.stopTtsAudio) subLayout.addWidget(button) layout.addLayout(subLayout) box.setLayout(layout) return box def defaultTtsLanguageChanged(self, index): config.ttsDefaultLangauge = self.languageCodes[index] def speakText(self): text = self.ttsEdit.text() if text: if config.isTtsInstalled: if ":::" in text: text = text.split(":::")[-1] command = "SPEAK:::{0}:::{1}".format( self.languageCodes[self.languageCombo.currentIndex()], text) self.parent.isRefreshing = True self.parent.runTextCommand(command) self.parent.isRefreshing = False else: self.parent.displayMessage( config.thisTranslation["message_noSupport"]) else: self.parent.displayMessage( config.thisTranslation["enterTextFirst"]) def changeQttsSpeed(self, value): config.qttsSpeed = (value * (1.5 / 300) - .5) def changeEspeakSpeed(self, value): config.espeakSpeed = value def refresh(self): ttsLanguageIndex = self.languageCodes.index(config.ttsDefaultLangauge) self.languageCombo.setCurrentIndex(ttsLanguageIndex) self.highLightLauncher.refresh()
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.edge_width.connect(self._on_edge_width_change) self.layer.events.current_edge_color.connect( self._on_current_edge_color_change ) self.layer.events.current_face_color.connect( self._on_current_face_color_change ) self.layer.events.editable.connect(self._on_editable_change) self.layer.text.events.visible.connect(self._on_text_visibility_change) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(40) sld.setSingleStep(1) value = self.layer.current_edge_width if isinstance(value, Iterable): if isinstance(value, list): value = np.asarray(value) value = value.mean() sld.setValue(int(value)) sld.valueChanged.connect(self.changeWidth) self.widthSlider = sld def _radio_button( parent, btn_name, mode, action_name, extra_tooltip_text='', **kwargs, ): """ Convenience local function to create a RadioButton and bind it to an action at the same time. Parameters ---------- parent : Any Parent of the generated QtModeRadioButton btn_name : str name fo the button mode : Enum Value Associated to current button action_name : str Action triggered when button pressed extra_tooltip_text : str Text you want added after the automatic tooltip set by the action manager **kwargs: Passed to QtModeRadioButton Returns ------- button: QtModeRadioButton button bound (or that will be bound to) to action `action_name` Notes ----- When shortcuts are modifed/added/removed via the action manager, the tooltip will be updated to reflect the new shortcut. """ action_name = 'napari:' + action_name btn = QtModeRadioButton(parent, btn_name, mode, **kwargs) action_manager.bind_button( action_name, btn, extra_tooltip_text='', ) return btn self.select_button = _radio_button( layer, 'select', Mode.SELECT, "activate_select_mode" ) self.direct_button = _radio_button( layer, 'direct', Mode.DIRECT, "activate_direct_mode" ) self.panzoom_button = _radio_button( layer, 'zoom', Mode.PAN_ZOOM, "napari:activate_shape_pan_zoom_mode", extra_tooltip_text=trans._('(or hold Space)'), checked=True, ) self.rectangle_button = _radio_button( layer, 'rectangle', Mode.ADD_RECTANGLE, "activate_add_rectangle_mode", ) self.ellipse_button = _radio_button( layer, 'ellipse', Mode.ADD_ELLIPSE, "activate_add_ellipse_mode", ) self.line_button = _radio_button( layer, 'line', Mode.ADD_LINE, "activate_add_line_mode" ) self.path_button = _radio_button( layer, 'path', Mode.ADD_PATH, "activate_add_path_mode" ) self.polygon_button = _radio_button( layer, 'polygon', Mode.ADD_POLYGON, "activate_add_polygon_mode", ) self.vertex_insert_button = _radio_button( layer, 'vertex_insert', Mode.VERTEX_INSERT, "activate_vertex_insert_mode", ) self.vertex_remove_button = _radio_button( layer, 'vertex_remove', Mode.VERTEX_REMOVE, "activate_vertex_remove_mode", ) self.move_front_button = QtModePushButton( layer, 'move_front', slot=self.layer.move_to_front, tooltip=trans._('Move to front'), ) action_manager.bind_button( 'napari:move_shapes_selection_to_front', self.move_front_button ) self.move_back_button = QtModePushButton( layer, 'move_back', slot=self.layer.move_to_back, tooltip=trans._('Move to back'), ) action_manager.bind_button( 'napari:move_shapes_selection_to_back', self.move_back_button ) self.delete_button = QtModePushButton( layer, 'delete_shape', slot=self.layer.remove_selected, tooltip=trans._( "Delete selected shapes ({shortcut})", shortcut=Shortcut('Backspace').platform, ), ) self.button_group = QButtonGroup(self) self.button_group.addButton(self.select_button) self.button_group.addButton(self.direct_button) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.rectangle_button) self.button_group.addButton(self.ellipse_button) self.button_group.addButton(self.line_button) self.button_group.addButton(self.path_button) self.button_group.addButton(self.polygon_button) self.button_group.addButton(self.vertex_insert_button) self.button_group.addButton(self.vertex_remove_button) button_grid = QGridLayout() button_grid.addWidget(self.vertex_remove_button, 0, 2) button_grid.addWidget(self.vertex_insert_button, 0, 3) button_grid.addWidget(self.delete_button, 0, 4) button_grid.addWidget(self.direct_button, 0, 5) button_grid.addWidget(self.select_button, 0, 6) button_grid.addWidget(self.panzoom_button, 0, 7) button_grid.addWidget(self.move_back_button, 1, 1) button_grid.addWidget(self.move_front_button, 1, 2) button_grid.addWidget(self.ellipse_button, 1, 3) button_grid.addWidget(self.rectangle_button, 1, 4) button_grid.addWidget(self.polygon_button, 1, 5) button_grid.addWidget(self.line_button, 1, 6) button_grid.addWidget(self.path_button, 1, 7) button_grid.setContentsMargins(5, 0, 0, 5) button_grid.setColumnStretch(0, 1) button_grid.setSpacing(4) self.faceColorEdit = QColorSwatchEdit( initial_color=self.layer.current_face_color, tooltip=trans._('click to set current face color'), ) self._on_current_face_color_change() self.edgeColorEdit = QColorSwatchEdit( initial_color=self.layer.current_edge_color, tooltip=trans._('click to set current edge color'), ) self._on_current_edge_color_change() self.faceColorEdit.color_changed.connect(self.changeFaceColor) self.edgeColorEdit.color_changed.connect(self.changeEdgeColor) text_disp_cb = QCheckBox() text_disp_cb.setToolTip(trans._('toggle text visibility')) text_disp_cb.setChecked(self.layer.text.visible) text_disp_cb.stateChanged.connect(self.change_text_visibility) self.textDispCheckBox = text_disp_cb # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_grid, 0, 0, 1, 2) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 1, 0) self.grid_layout.addWidget(self.opacitySlider, 1, 1) self.grid_layout.addWidget(QLabel(trans._('edge width:')), 2, 0) self.grid_layout.addWidget(self.widthSlider, 2, 1) self.grid_layout.addWidget(QLabel(trans._('blending:')), 3, 0) self.grid_layout.addWidget(self.blendComboBox, 3, 1) self.grid_layout.addWidget(QLabel(trans._('face color:')), 4, 0) self.grid_layout.addWidget(self.faceColorEdit, 4, 1) self.grid_layout.addWidget(QLabel(trans._('edge color:')), 5, 0) self.grid_layout.addWidget(self.edgeColorEdit, 5, 1) self.grid_layout.addWidget(QLabel(trans._('display text:')), 6, 0) self.grid_layout.addWidget(self.textDispCheckBox, 6, 1) self.grid_layout.setRowStretch(7, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
class PyDMSlider(QFrame, TextFormatter, PyDMWritableWidget): """ A QSlider with support for Channels and more from PyDM. Parameters ---------- parent : QWidget The parent widget for the Label init_channel : str, optional The channel to be used by the widget. """ actionTriggered = Signal(int) rangeChanged = Signal(float, float) sliderMoved = Signal(float) sliderPressed = Signal() sliderReleased = Signal() valueChanged = Signal(float) def __init__(self, parent=None, init_channel=None): QFrame.__init__(self, parent) PyDMWritableWidget.__init__(self, init_channel=init_channel) self.alarmSensitiveContent = True self.alarmSensitiveBorder = False # Internal values for properties self._show_limit_labels = True self._show_value_label = True self._user_defined_limits = False self._needs_limit_info = True self._minimum = None self._maximum = None self._user_minimum = -10.0 self._user_maximum = 10.0 self._num_steps = 101 self._orientation = Qt.Horizontal # Set up all the internal widgets that make up a PyDMSlider. # We'll add all these things to layouts when we call setup_widgets_for_orientation label_size_policy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) self.low_lim_label = QLabel(self) self.low_lim_label.setObjectName("lowLimLabel") self.low_lim_label.setSizePolicy(label_size_policy) self.low_lim_label.setAlignment(Qt.AlignLeft | Qt.AlignTrailing | Qt.AlignVCenter) self.value_label = QLabel(self) self.value_label.setObjectName("valueLabel") self.value_label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.high_lim_label = QLabel(self) self.high_lim_label.setObjectName("highLimLabel") self.high_lim_label.setSizePolicy(label_size_policy) self.high_lim_label.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self._slider = QSlider(parent=self) self._slider.setOrientation(Qt.Horizontal) self._slider.sliderMoved.connect(self.internal_slider_moved) self._slider.sliderPressed.connect(self.internal_slider_pressed) self._slider.sliderReleased.connect(self.internal_slider_released) self._slider.valueChanged.connect(self.internal_slider_value_changed) # self.vertical_layout.addWidget(self._slider) # Other internal variables and final setup steps self._slider_position_to_value_map = None self._mute_internal_slider_changes = False self.setup_widgets_for_orientation(self._orientation) self.reset_slider_limits() def init_for_designer(self): """ Method called after the constructor to tweak configurations for when using the widget with the Qt Designer """ self.value = 0.0 @Property(Qt.Orientation) def orientation(self): """ The slider orientation (Horizontal or Vertical) Returns ------- int Qt.Horizontal or Qt.Vertical """ return self._orientation @orientation.setter def orientation(self, new_orientation): """ The slider orientation (Horizontal or Vertical) Parameters ---------- new_orientation : int Qt.Horizontal or Qt.Vertical """ self._orientation = new_orientation self.setup_widgets_for_orientation(new_orientation) def setup_widgets_for_orientation(self, new_orientation): """ Reconstruct the widget given the orientation. Parameters ---------- new_orientation : int Qt.Horizontal or Qt.Vertical """ if new_orientation not in (Qt.Horizontal, Qt.Vertical): logger.error("Invalid orientation '{0}'. The existing layout will not change.".format(new_orientation)) return layout = None if new_orientation == Qt.Horizontal: layout = QVBoxLayout() layout.setContentsMargins(4, 0, 4, 4) label_layout = QHBoxLayout() label_layout.addWidget(self.low_lim_label) label_layout.addStretch(0) label_layout.addWidget(self.value_label) label_layout.addStretch(0) label_layout.addWidget(self.high_lim_label) layout.addLayout(label_layout) self._slider.setOrientation(new_orientation) layout.addWidget(self._slider) elif new_orientation == Qt.Vertical: layout = QHBoxLayout() layout.setContentsMargins(0, 4, 4, 4) label_layout = QVBoxLayout() label_layout.addWidget(self.high_lim_label) label_layout.addStretch(0) label_layout.addWidget(self.value_label) label_layout.addStretch(0) label_layout.addWidget(self.low_lim_label) layout.addLayout(label_layout) self._slider.setOrientation(new_orientation) layout.addWidget(self._slider) if self.layout() is not None: # Trick to remove the existing layout by re-parenting it in an empty widget. QWidget().setLayout(self.layout()) self.setLayout(layout) def update_labels(self): """ Update the limits and value labels with the correct values. """ def set_label(value, label_widget): if value is None: label_widget.setText("") else: label_widget.setText(self.format_string.format(value)) set_label(self.minimum, self.low_lim_label) set_label(self.maximum, self.high_lim_label) set_label(self.value, self.value_label) def reset_slider_limits(self): """ Reset the limits and adjust the labels properly for the slider. """ if self.minimum is None or self.maximum is None: self._needs_limit_info = True self.set_enable_state() return self._needs_limit_info = False self._slider.setMinimum(0) self._slider.setMaximum(self._num_steps - 1) self._slider.setSingleStep(1) self._slider.setPageStep(10) self._slider_position_to_value_map = np.linspace(self.minimum, self.maximum, num=self._num_steps) self.update_labels() self.set_slider_to_closest_value(self.value) self.rangeChanged.emit(self.minimum, self.maximum) self.set_enable_state() def find_closest_slider_position_to_value(self, val): """ Find and returns the index for the closest position on the slider for a given value. Parameters ---------- val : float Returns ------- int """ diff = abs(self._slider_position_to_value_map - float(val)) return np.argmin(diff) def set_slider_to_closest_value(self, val): """ Set the value for the slider according to a given value. Parameters ---------- val : float """ if val is None or self._needs_limit_info: return # When we set the slider to the closest value, it may end up at a slightly # different position than val (if val is not in self._slider_position_to_value_map) # We don't want that slight difference to get broacast out and put the channel # somewhere new. For example, if the slider can only be at 0.4 or 0.5, but a # new value comes in of 0.45, its more important to keep the 0.45 than to change # it to where the slider gets set. Therefore, we mute the internal slider changes # so that its valueChanged signal doesn't cause us to emit a signal to PyDM to change # the value of the channel. self._mute_internal_slider_changes = True self._slider.setValue(self.find_closest_slider_position_to_value(val)) self._mute_internal_slider_changes = False def value_changed(self, new_val): """ Callback invoked when the Channel value is changed. Parameters ---------- new_val : int or float The new value from the channel. """ PyDMWritableWidget.value_changed(self, new_val) if hasattr(self, "value_label"): self.value_label.setText(self.format_string.format(self.value)) if not self._slider.isSliderDown(): self.set_slider_to_closest_value(self.value) def ctrl_limit_changed(self, which, new_limit): """ Callback invoked when the Channel receives new control limit values. Parameters ---------- which : str Which control limit was changed. "UPPER" or "LOWER" new_limit : float New value for the control limit """ PyDMWritableWidget.ctrl_limit_changed(self, which, new_limit) if not self.userDefinedLimits: self.reset_slider_limits() def update_format_string(self): """ Reconstruct the format string to be used when representing the output value. Returns ------- format_string : str The format string to be used including or not the precision and unit """ fs = super(PyDMSlider, self).update_format_string() self.update_labels() return fs def set_enable_state(self): """ Determines wether or not the widget must be enabled or not depending on the write access, connection state and presence of limits information """ # Even though by documentation disabling parent QFrame (self), should disable internal # slider, in practice it still remains interactive (PyQt 5.12.1). Disabling explicitly, solves # the problem. should_enable = self._write_access and self._connected and not self._needs_limit_info self.setEnabled(should_enable) self._slider.setEnabled(should_enable) @Slot(int) def internal_slider_action_triggered(self, action): self.actionTriggered.emit(action) @Slot(int) def internal_slider_moved(self, val): """ Method invoked when the slider is moved. Parameters ---------- val : float """ # Avoid potential crash if limits are undefined if self._slider_position_to_value_map is None: return # The user has moved the slider, we need to update our value. # Only update the underlying value, not the self.value property, # because we don't need to reset the slider position. If we change # self.value, we can get into a loop where the position changes, which # updates the value, which changes the position again, etc etc. self.value = self._slider_position_to_value_map[val] self.sliderMoved.emit(self.value) @Slot() def internal_slider_pressed(self): """ Method invoked when the slider is pressed """ self.sliderPressed.emit() @Slot() def internal_slider_released(self): """ Method invoked when the slider is released """ self.sliderReleased.emit() @Slot(int) def internal_slider_value_changed(self, val): """ Method invoked when a new value is selected on the slider. This will cause the new value to be emitted to the signal unless `mute_internal_slider_changes` is True. Parameters ---------- val : int """ # At this point, our local copy of the value reflects the position of the # slider, now all we need to do is emit a signal to PyDM so that the data # plugin will send a put to the channel. Don't update self.value or self._value # in here, it is pointless at best, and could cause an infinite loop at worst. if not self._mute_internal_slider_changes: self.send_value_signal[float].emit(self.value) @Property(bool) def showLimitLabels(self): """ Whether or not the high and low limits should be displayed on the slider. Returns ------- bool """ return self._show_limit_labels @showLimitLabels.setter def showLimitLabels(self, checked): """ Whether or not the high and low limits should be displayed on the slider. Parameters ---------- checked : bool """ self._show_limit_labels = checked if checked: self.low_lim_label.show() self.high_lim_label.show() else: self.low_lim_label.hide() self.high_lim_label.hide() @Property(bool) def showValueLabel(self): """ Whether or not the current value should be displayed on the slider. Returns ------- bool """ return self._show_value_label @showValueLabel.setter def showValueLabel(self, checked): """ Whether or not the current value should be displayed on the slider. Parameters ---------- checked : bool """ self._show_value_label = checked if checked: self.value_label.show() else: self.value_label.hide() @Property(QSlider.TickPosition) def tickPosition(self): """ Where to draw tick marks for the slider. Returns ------- QSlider.TickPosition """ return self._slider.tickPosition() @tickPosition.setter def tickPosition(self, position): """ Where to draw tick marks for the slider. Parameter --------- position : QSlider.TickPosition """ self._slider.setTickPosition(position) @Property(bool) def userDefinedLimits(self): """ Wether or not to use limits defined by the user and not from the channel Returns ------- bool """ return self._user_defined_limits @userDefinedLimits.setter def userDefinedLimits(self, user_defined_limits): """ Wether or not to use limits defined by the user and not from the channel Parameters ---------- user_defined_limits : bool """ self._user_defined_limits = user_defined_limits self.reset_slider_limits() @Property(float) def userMinimum(self): """ Lower user defined limit value Returns ------- float """ return self._user_minimum @userMinimum.setter def userMinimum(self, new_min): """ Lower user defined limit value Parameters ---------- new_min : float """ self._user_minimum = float(new_min) if new_min is not None else None if self.userDefinedLimits: self.reset_slider_limits() @Property(float) def userMaximum(self): """ Upper user defined limit value Returns ------- float """ return self._user_maximum @userMaximum.setter def userMaximum(self, new_max): """ Upper user defined limit value Parameters ---------- new_max : float """ self._user_maximum = float(new_max) if new_max is not None else None if self.userDefinedLimits: self.reset_slider_limits() @property def minimum(self): """ The current value being used for the lower limit Returns ------- float """ if self.userDefinedLimits: return self._user_minimum return self._lower_ctrl_limit @property def maximum(self): """ The current value being used for the upper limit Returns ------- float """ if self.userDefinedLimits: return self._user_maximum return self._upper_ctrl_limit @Property(int) def num_steps(self): """ The number of steps on the slider Returns ------- int """ return self._num_steps @num_steps.setter def num_steps(self, new_steps): """ The number of steps on the slider Parameters ---------- new_steps : int """ self._num_steps = int(new_steps) self.reset_slider_limits()