class QtVectorsControls(QtLayerControls): """Qt view and controls for the napari Vectors layer. Parameters ---------- layer : napari.layers.Vectors An instance of a napari Vectors layer. Attributes ---------- edgeColorSwatch : qtpy.QtWidgets.QFrame Color swatch showing display color of vectors. edgeComboBox : qtpy.QtWidgets.QComboBox Dropdown widget to select display color for vectors. grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Vectors An instance of a napari Vectors layer. lengthSpinBox : qtpy.QtWidgets.QDoubleSpinBox Spin box widget controlling line length of vectors. Multiplicative factor on projections for length of all vectors. widthSpinBox : qtpy.QtWidgets.QDoubleSpinBox Spin box widget controlling edge line width of vectors. """ def __init__(self, layer): super().__init__(layer) self.layer.events.edge_width.connect(self._on_width_change) self.layer.events.length.connect(self._on_len_change) self.layer.events.edge_color.connect(self._on_edge_color_change) # vector color adjustment and widget edge_comboBox = QComboBox() edge_comboBox.addItems(self.layer._colors) edge_comboBox.activated[str].connect(self.change_edge_color) self.edgeComboBox = edge_comboBox self.edgeColorSwatch = QFrame() self.edgeColorSwatch.setObjectName('swatch') self.edgeColorSwatch.setToolTip('Edge color swatch') self._on_edge_color_change() # line width in pixels self.widthSpinBox = QDoubleSpinBox() self.widthSpinBox.setKeyboardTracking(False) self.widthSpinBox.setSingleStep(0.1) self.widthSpinBox.setMinimum(0.1) self.widthSpinBox.setValue(self.layer.edge_width) self.widthSpinBox.valueChanged.connect(self.change_width) # line length self.lengthSpinBox = QDoubleSpinBox() self.lengthSpinBox.setKeyboardTracking(False) self.lengthSpinBox.setSingleStep(0.1) self.lengthSpinBox.setValue(self.layer.length) self.lengthSpinBox.setMinimum(0.1) self.lengthSpinBox.valueChanged.connect(self.change_length) # 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, 1, 2) self.grid_layout.addWidget(QLabel('width:'), 1, 0) self.grid_layout.addWidget(self.widthSpinBox, 1, 1, 1, 2) self.grid_layout.addWidget(QLabel('length:'), 2, 0) self.grid_layout.addWidget(self.lengthSpinBox, 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('edge color:'), 4, 0) self.grid_layout.addWidget(self.edgeComboBox, 4, 2) self.grid_layout.addWidget(self.edgeColorSwatch, 4, 1) self.grid_layout.setRowStretch(5, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def change_edge_color(self, text): """Change edge color of vectors on the layer model. Parameters ---------- text : str Edge color for vectors, color name or hex string. Eg: 'white', 'red', 'blue', '#00ff00', etc. """ self.layer.edge_color = text def change_width(self, value): """Change edge line width of vectors on the layer model. Parameters ---------- value : float Line width of vectors. """ self.layer.edge_width = value self.widthSpinBox.clearFocus() self.setFocus() def change_length(self, value): """Change length of vectors on the layer model. Multiplicative factor on projections for length of all vectors. Parameters ---------- value : float Length of vectors. """ self.layer.length = value self.lengthSpinBox.clearFocus() self.setFocus() def _on_len_change(self, event=None): """Change length of vectors. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.length.blocker(): self.lengthSpinBox.setValue(self.layer.length) def _on_width_change(self, event=None): """"Receive layer model width change event and update width spinbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.edge_width.blocker(): self.widthSpinBox.setValue(self.layer.edge_width) def _on_edge_color_change(self, event=None): """"Receive layer model edge color change event & update color swatch. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context, by default None. """ with self.layer.events.edge_color.blocker(): index = self.edgeComboBox.findText( self.layer.edge_color, Qt.MatchFixedString ) self.edgeComboBox.setCurrentIndex(index) color = Color(self.layer.edge_color).hex self.edgeColorSwatch.setStyleSheet("background-color: " + color)
class QtVectorsControls(QtLayerControls): """Qt view and controls for the napari Vectors layer. Parameters ---------- layer : napari.layers.Vectors An instance of a napari Vectors layer. Attributes ---------- edge_color_label : qtpy.QtWidgets.QLabel Label for edgeColorSwatch edgeColorSwatch : qtpy.QtWidgets.QFrame Color swatch showing display color of vectors. edgeComboBox : qtpy.QtWidgets.QComboBox Dropdown widget to select display color for vectors. color_mode_comboBox : qtpy.QtWidgets.QComboBox Dropdown widget to select edge_color_mode for the vectors. color_prop_box : qtpy.QtWidgets.QComboBox Dropdown widget to select _edge_color_property for the vectors. edge_prop_label : qtpy.QtWidgets.QLabel Label for color_prop_box grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Vectors An instance of a napari Vectors layer. lengthSpinBox : qtpy.QtWidgets.QDoubleSpinBox Spin box widget controlling line length of vectors. Multiplicative factor on projections for length of all vectors. widthSpinBox : qtpy.QtWidgets.QDoubleSpinBox Spin box widget controlling edge line width of vectors. """ def __init__(self, layer): super().__init__(layer) self.layer.events.edge_width.connect(self._on_edge_width_change) self.layer.events.length.connect(self._on_length_change) self.layer.events.edge_color_mode.connect( self._on_edge_color_mode_change) self.layer.events.edge_color.connect(self._on_edge_color_change) # dropdown to select the property for mapping edge_color color_properties = self._get_property_values() color_prop_box = QComboBox(self) color_prop_box.activated[str].connect(self.change_edge_color_property) color_prop_box.addItems(color_properties) self.color_prop_box = color_prop_box self.edge_prop_label = QLabel(trans._('edge property:')) # vector direct color mode adjustment and widget self.edgeColorEdit = QColorSwatchEdit( initial_color=self.layer.edge_color, tooltip=trans._('click to set current edge color', ), ) self.edgeColorEdit.color_changed.connect(self.change_edge_color_direct) self.edge_color_label = QLabel(trans._('edge color:')) self._on_edge_color_change() # dropdown to select the edge color mode colorModeComboBox = QComboBox(self) color_modes = [e.value for e in ColorMode] colorModeComboBox.addItems(color_modes) colorModeComboBox.activated[str].connect(self.change_edge_color_mode) self.color_mode_comboBox = colorModeComboBox self._on_edge_color_mode_change() # line width in pixels self.widthSpinBox = QDoubleSpinBox() self.widthSpinBox.setKeyboardTracking(False) self.widthSpinBox.setSingleStep(0.1) self.widthSpinBox.setMinimum(0.1) self.widthSpinBox.setMaximum(np.inf) self.widthSpinBox.setValue(self.layer.edge_width) self.widthSpinBox.valueChanged.connect(self.change_width) # line length self.lengthSpinBox = QDoubleSpinBox() self.lengthSpinBox.setKeyboardTracking(False) self.lengthSpinBox.setSingleStep(0.1) self.lengthSpinBox.setValue(self.layer.length) self.lengthSpinBox.setMinimum(0.1) self.lengthSpinBox.setMaximum(np.inf) self.lengthSpinBox.valueChanged.connect(self.change_length) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 0, 0) self.grid_layout.addWidget(self.opacitySlider, 0, 1, 1, 2) self.grid_layout.addWidget(QLabel(trans._('width:')), 1, 0) self.grid_layout.addWidget(self.widthSpinBox, 1, 1, 1, 2) self.grid_layout.addWidget(QLabel(trans._('length:')), 2, 0) self.grid_layout.addWidget(self.lengthSpinBox, 2, 1, 1, 2) self.grid_layout.addWidget(QLabel(trans._('blending:')), 3, 0) self.grid_layout.addWidget(self.blendComboBox, 3, 1, 1, 2) self.grid_layout.addWidget(QLabel(trans._('edge color mode:')), 4, 0) self.grid_layout.addWidget(self.color_mode_comboBox, 4, 1, 1, 2) self.grid_layout.addWidget(self.edge_color_label, 5, 0) self.grid_layout.addWidget(self.edgeColorEdit, 5, 1, 1, 2) self.grid_layout.addWidget(self.edge_prop_label, 6, 0) self.grid_layout.addWidget(self.color_prop_box, 6, 1, 1, 2) self.grid_layout.setRowStretch(7, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def change_edge_color_property(self, property: str): """Change edge_color_property of vectors on the layer model. This property is the property the edge color is mapped to. Parameters ---------- property : str property to map the edge color to """ mode = self.layer.edge_color_mode try: self.layer.edge_color = property self.layer.edge_color_mode = mode except TypeError: # if the selected property is the wrong type for the current color mode # the color mode will be changed to the appropriate type, so we must update self._on_edge_color_mode_change() raise def change_edge_color_mode(self, mode: str): """Change edge color mode of vectors on the layer model. Parameters ---------- mode : str Edge color for vectors. Must be: 'direct', 'cycle', or 'colormap' """ old_mode = self.layer.edge_color_mode with self.layer.events.edge_color_mode.blocker(): try: self.layer.edge_color_mode = mode self._update_edge_color_gui(mode) except ValueError: # if the color mode was invalid, revert to the old mode self.layer.edge_color_mode = old_mode raise def change_edge_color_direct(self, color: np.ndarray): """Change edge color of vectors on the layer model. Parameters ---------- color : np.ndarray Edge color for vectors, in an RGBA array """ self.layer.edge_color = color def change_width(self, value): """Change edge line width of vectors on the layer model. Parameters ---------- value : float Line width of vectors. """ self.layer.edge_width = value self.widthSpinBox.clearFocus() self.setFocus() def change_length(self, value): """Change length of vectors on the layer model. Multiplicative factor on projections for length of all vectors. Parameters ---------- value : float Length of vectors. """ self.layer.length = value self.lengthSpinBox.clearFocus() self.setFocus() def _update_edge_color_gui(self, mode: str): """Update the GUI element associated with edge_color. This is typically used when edge_color_mode changes Parameters ---------- mode : str The new edge_color mode the GUI needs to be updated for. Should be: 'direct', 'cycle', 'colormap' """ if mode in ('cycle', 'colormap'): self.edgeColorEdit.setHidden(True) self.edge_color_label.setHidden(True) self.color_prop_box.setHidden(False) self.edge_prop_label.setHidden(False) elif mode == 'direct': self.edgeColorEdit.setHidden(False) self.edge_color_label.setHidden(False) self.color_prop_box.setHidden(True) self.edge_prop_label.setHidden(True) def _get_property_values(self): """Get the current property values from the Vectors layer Returns ------- property_values : np.ndarray array of all of the union of the property names (keys) in Vectors.properties and Vectors._property_choices """ property_choices = [*self.layer._property_choices] properties = [*self.layer.properties] property_values = np.union1d(property_choices, properties) return property_values def _on_length_change(self, event=None): """Change length of vectors. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method, by default None. """ with self.layer.events.length.blocker(): self.lengthSpinBox.setValue(self.layer.length) def _on_edge_width_change(self, event=None): """Receive layer model width change event and update width spinbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method, by default None. """ with self.layer.events.edge_width.blocker(): self.widthSpinBox.setValue(self.layer.edge_width) def _on_edge_color_mode_change(self, event=None): """Receive layer model edge color mode change event & update dropdown. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method, by default None. """ with qt_signals_blocked(self.color_mode_comboBox): mode = self.layer._edge.color_mode index = self.color_mode_comboBox.findText(mode, Qt.MatchFixedString) self.color_mode_comboBox.setCurrentIndex(index) self._update_edge_color_gui(mode) def _on_edge_color_change(self, event=None): """Receive layer model edge color change event & update dropdown. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method, by default None. """ if self.layer._edge.color_mode == ColorMode.DIRECT: with qt_signals_blocked(self.edgeColorEdit): self.edgeColorEdit.setColor(self.layer.edge_color[0]) elif self.layer._edge.color_mode in ( ColorMode.CYCLE, ColorMode.COLORMAP, ): with qt_signals_blocked(self.color_prop_box): prop = self.layer._edge.color_properties.name index = self.color_prop_box.findText(prop, Qt.MatchFixedString) self.color_prop_box.setCurrentIndex(index)
class QtVectorsControls(QtLayerControls): def __init__(self, layer): super().__init__(layer) self.layer.events.edge_width.connect(self._on_width_change) self.layer.events.length.connect(self._on_len_change) self.layer.events.edge_color.connect(self._on_edge_color_change) # vector color adjustment and widget 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.change_edge_color(text)) self.edgeComboBox = edge_comboBox self.edgeColorSwatch = QFrame() self.edgeColorSwatch.setObjectName('swatch') self.edgeColorSwatch.setToolTip('Edge color swatch') self._on_edge_color_change(None) # line width in pixels self.widthSpinBox = QDoubleSpinBox() self.widthSpinBox.setKeyboardTracking(False) self.widthSpinBox.setSingleStep(0.1) self.widthSpinBox.setMinimum(0.1) value = self.layer.edge_width self.widthSpinBox.setValue(value) self.widthSpinBox.valueChanged.connect(self.change_width) # line length self.lengthSpinBox = QDoubleSpinBox() self.lengthSpinBox.setKeyboardTracking(False) self.lengthSpinBox.setSingleStep(0.1) value = self.layer.length self.lengthSpinBox.setValue(value) self.lengthSpinBox.setMinimum(0.1) self.lengthSpinBox.valueChanged.connect(self.change_length) # 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('width:'), 1, 0) self.grid_layout.addWidget(self.widthSpinBox, 1, 1, 1, 2) self.grid_layout.addWidget(QLabel('length:'), 2, 0) self.grid_layout.addWidget(self.lengthSpinBox, 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('edge color:'), 4, 0) self.grid_layout.addWidget(self.edgeComboBox, 4, 2) self.grid_layout.addWidget(self.edgeColorSwatch, 4, 1) self.grid_layout.setRowStretch(5, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def change_edge_color(self, text): self.layer.edge_color = text def change_connector_type(self, text): self.layer.connector = text def change_width(self, value): self.layer.edge_width = value self.widthSpinBox.clearFocus() self.setFocus() def change_length(self, value): self.layer.length = value self.lengthSpinBox.clearFocus() self.setFocus() def _on_len_change(self, event): with self.layer.events.length.blocker(): self.lengthSpinBox.setValue(self.layer.length) def _on_width_change(self, event): with self.layer.events.edge_width.blocker(): self.widthSpinBox.setValue(self.layer.edge_width) def _on_edge_color_change(self, event): with self.layer.events.edge_color.blocker(): index = self.edgeComboBox.findText(self.layer.edge_color, Qt.MatchFixedString) self.edgeComboBox.setCurrentIndex(index) color = Color(self.layer.edge_color).hex self.edgeColorSwatch.setStyleSheet("background-color: " + color)