def addSpinBox( self, attribute_name, title, tool_tip=None, min_value=1, max_value=10, single_step=1, ): sb = QSpinBox() self[attribute_name] = sb sb.setMaximumHeight(25) sb_layout = QHBoxLayout() sb_layout.addWidget(sb) sb_layout.addStretch() self.addRow(title, sb_layout) if tool_tip is not None: sb.setToolTip(tool_tip) sb.setMinimum(min_value) sb.setMaximum(max_value) sb.setSingleStep(single_step) def getter(self): return self[attribute_name].value() def setter(self, value): self[attribute_name].setValue(value) self.updateProperty(attribute_name, getter, setter) return sb
def _create(self, initial_value: int, spin_range: range) -> QSpinBox: """Return the configured QSpinBox. Parameters ---------- initial_value : int The initial value of the QSpinBox. spin_range : range The start/stop/step of the QSpinBox. Return ------ QSpinBox The configured QSpinBox. """ spin = QSpinBox() spin.setMinimum(spin_range.start) spin.setMaximum(spin_range.stop) spin.setSingleStep(spin_range.step) spin.setValue(initial_value) spin.setKeyboardTracking(False) # correct? spin.setAlignment(Qt.AlignCenter) spin.valueChanged.connect(self._on_change) return spin
def createSpinBox(self, variable_name, variable_value, variable_type, analysis_module_variables_model): spinner = QSpinBox() spinner.setMinimumWidth(75) spinner.setMaximum(analysis_module_variables_model.getVariableMaximumValue(variable_name)) spinner.setMinimum(analysis_module_variables_model.getVariableMinimumValue(variable_name)) spinner.setSingleStep(analysis_module_variables_model.getVariableStepValue(variable_name)) if variable_value is not None: spinner.setValue(variable_value) spinner.valueChanged.connect(partial(self.valueChanged, variable_name, variable_type, spinner)) return spinner
class QTiffStackView(QWidget): #the view which the user of the videoviewer sees. #This class contains relevant 'client side' attributes e.g. buttons to get a frame, a slide bar and a timer. These attributes submit requests to the QTiffStackController to give the next frame etc. The controller returns either the requested frame or an error message def __init__(self): super(QTiffStackView, self).__init__() #add the image display. This is a subclass of QLabel, where paintEvent is overriden. self.frame_view = FrameView() #self.frame_view.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding) #add the slide bar which allows the user to manual flick through self.slideBar = QSlider(Qt.Horizontal) self.slideBar.setTickPosition(QSlider.TicksAbove) self.slideBar.setTracking(True) self.slideBar.setTickInterval(100) #add a counter which displays the frame which is currently displayed self.counter = QSpinBox() self.counter.setSingleStep(1) self.counter.setRange(self.slideBar.minimum(), self.slideBar.maximum()) #self explanatory self.play = QPushButton('Play') #when play button is pressed the timer takes control of the displaying of frames self.frametimer = QTimer() frame_rate = 30 self.frametimer.setInterval(frame_rate) #Add a sublayout to align the slidebar and frame counter next to eachother slidelyt = QHBoxLayout() slidelyt.addWidget(self.slideBar) slidelyt.addWidget(self.counter) #Add the main layout for the widget lyt = QVBoxLayout() lyt.addWidget(self.frame_view) lyt.addLayout(slidelyt) lyt.addWidget(self.play) self.setLayout(lyt) def updateRanges(self, maximum): assert type(maximum) == int self.slideBar.setMaximum(maximum) self.counter.setRange(self.slideBar.minimum(), self.slideBar.maximum())
class QtRender(QWidget): """Dockable widget for render controls. Attributes ---------- """ def __init__(self, layer): """Create our windgets. """ super().__init__() self.layer = layer self.layer.events.octree_level.connect(self._on_octree_level) layout = QVBoxLayout() spin_layout = QHBoxLayout() self.spin_level = QSpinBox() self.spin_level.setKeyboardTracking(False) self.spin_level.setSingleStep(1) self.spin_level.setMinimum(0) self.spin_level.setMaximum(10) self.spin_level.valueChanged.connect(self._on_spin) self.spin_level.setAlignment(Qt.AlignCenter) label = QLabel("Quadtree Level:") spin_layout.addWidget(label) spin_layout.addWidget(self.spin_level) layout.addLayout(spin_layout) self.setLayout(layout) # Get initial value. self._on_octree_level() def _on_spin(self, value): """Level spinbox changed. Parameters ---------- value : int New value of the spinbox """ self.layer.octree_level = value def _on_octree_level(self, event=None): value = self.layer.octree_level self.spin_level.setValue(value)
def create_spinbox(self, prefix, suffix, option, default=NoDefault, min_=None, max_=None, step=None, tip=None, section=None): if section is not None and section != self.CONF_SECTION: self.cross_section_options[option] = section widget = QWidget(self) if prefix: plabel = QLabel(prefix) widget.plabel = plabel else: plabel = None if suffix: slabel = QLabel(suffix) widget.slabel = slabel else: slabel = None if step is not None: if type(step) is int: spinbox = QSpinBox() else: spinbox = QDoubleSpinBox() spinbox.setDecimals(1) spinbox.setSingleStep(step) else: spinbox = QSpinBox() if min_ is not None: spinbox.setMinimum(min_) if max_ is not None: spinbox.setMaximum(max_) if tip is not None: spinbox.setToolTip(tip) self.spinboxes[spinbox] = (section, option, default) layout = QHBoxLayout() for subwidget in (plabel, spinbox, slabel): if subwidget is not None: layout.addWidget(subwidget) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) widget.spinbox = spinbox widget.setLayout(layout) return widget
def createSpinBox( self, variable_name, variable_value, analysis_module_variables_model, ): spinner = QSpinBox() spinner.setMinimumWidth(75) spinner.setMaximum( analysis_module_variables_model.getVariableMaximumValue( variable_name)) spinner.setMinimum( analysis_module_variables_model.getVariableMinimumValue( variable_name)) spinner.setSingleStep( analysis_module_variables_model.getVariableStepValue( variable_name)) spinner.setObjectName(variable_name) if variable_value is not None: spinner.setValue(variable_value) return spinner
class _SaveDialog(QFileDialog): def __init__(self, parent): QFileDialog.__init__(self, parent) self.setFileMode(QFileDialog.AnyFile) self.setAcceptMode(QFileDialog.AcceptSave) # Widgets self._chk_tight = QCheckBox('Tight layout') self._txt_dpi = QSpinBox() self._txt_dpi.setRange(1, 10000) self._txt_dpi.setSingleStep(50) self._txt_dpi.setSuffix('dpi') self._txt_dpi.setValue(100) # Layouts layout = self.layout() lyt_extras = QHBoxLayout() lyt_extras.addWidget(QLabel('Extra options')) lyt_extras.addWidget(self._chk_tight) lyt_extras.addWidget(QLabel('Resolution')) lyt_extras.addWidget(self._txt_dpi) layout.addLayout(lyt_extras, layout.rowCount(), 0, 1, layout.columnCount()) self.setLayout(layout) def tightLayout(self): return self._chk_tight.isChecked() def setTightLayout(self, tight): self._chk_tight.setChecked(tight) def dpi(self): return self._txt_dpi.value() def setDpi(self, dpi): self._txt_dpi.setValue(dpi)
def create_spinbox(self, prefix, suffix, option, default=NoDefault, min_=None, max_=None, step=None, tip=None): widget = QWidget(self) if prefix: plabel = QLabel(prefix) widget.plabel = plabel else: plabel = None if suffix: slabel = QLabel(suffix) widget.slabel = slabel else: slabel = None if step is not None: if type(step) is int: spinbox = QSpinBox() else: spinbox = QDoubleSpinBox() spinbox.setDecimals(1) spinbox.setSingleStep(step) else: spinbox = QSpinBox() if min_ is not None: spinbox.setMinimum(min_) if max_ is not None: spinbox.setMaximum(max_) if tip is not None: spinbox.setToolTip(tip) self.spinboxes[spinbox] = (option, default) layout = QHBoxLayout() for subwidget in (plabel, spinbox, slabel): if subwidget is not None: layout.addWidget(subwidget) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) widget.spinbox = spinbox widget.setLayout(layout) return widget
class QtLabelsProperties(QtLayerProperties): def __init__(self, layer): super().__init__(layer) self.layer.events.colormap.connect(self._on_colormap_change) self.layer.events.selected_label.connect(self._on_selection_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contig_change) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.colormap_update = QPushButton('click') self.colormap_update.setObjectName('shuffle') self.colormap_update.clicked.connect(self.changeColor) self.colormap_update.setFixedWidth(112) self.colormap_update.setFixedHeight(25) shuffle_label = QLabel('shuffle colors:') shuffle_label.setObjectName('shuffle-label') row = self.grid_layout.rowCount() self.grid_layout.addWidget(shuffle_label, row, self.name_column) self.grid_layout.addWidget( self.colormap_update, row, self.property_column ) # selection spinbox self.selection_spinbox = QSpinBox() self.selection_spinbox.setSingleStep(1) self.selection_spinbox.setMinimum(0) self.selection_spinbox.setMaximum(2147483647) self.selection_spinbox.setValue(self.layer.selected_label) self.selection_spinbox.setFixedWidth(75) self.selection_spinbox.valueChanged.connect(self.changeSelection) row = self.grid_layout.rowCount() self.grid_layout.addWidget(QLabel('label:'), row, self.name_column) self.grid_layout.addWidget( self.selection_spinbox, row, self.property_column ) sld = QSlider(Qt.Horizontal, self) sld.setFocusPolicy(Qt.NoFocus) sld.setFixedWidth(110) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) value = self.layer.brush_size if isinstance(value, Iterable): if isinstance(value, list): value = np.asarray(value) value = value[:2].mean() sld.setValue(int(value)) sld.valueChanged[int].connect(lambda value=sld: self.changeSize(value)) self.brush_size_slider = sld row = self.grid_layout.rowCount() self.grid_layout.addWidget( QLabel('brush size:'), row, self.name_column ) self.grid_layout.addWidget(sld, row, self.property_column) contig_cb = QCheckBox() contig_cb.setToolTip('contiguous editing') contig_cb.setChecked(self.layer.contiguous) contig_cb.stateChanged.connect( lambda state=contig_cb: self.change_contig(state) ) self.contig_checkbox = contig_cb row = self.grid_layout.rowCount() self.grid_layout.addWidget( QLabel('contiguous:'), row, self.name_column ) self.grid_layout.addWidget(contig_cb, row, self.property_column) ndim_cb = QCheckBox() ndim_cb.setToolTip('n-dimensional editing') ndim_cb.setChecked(self.layer.n_dimensional) ndim_cb.stateChanged.connect( lambda state=ndim_cb: self.change_ndim(state) ) self.ndim_checkbox = ndim_cb row = self.grid_layout.rowCount() self.grid_layout.addWidget(QLabel('n-dim:'), row, self.name_column) self.grid_layout.addWidget(ndim_cb, row, self.property_column) self.setExpanded(False) def changeColor(self): self.layer.new_colormap() def changeSelection(self, value): self.layer.selected_label = value def changeSize(self, value): self.layer.brush_size = value def change_contig(self, state): if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def _on_colormap_change(self, event): self.layer._node.cmap = self.layer.colormap def _on_selection_change(self, event): with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selection_spinbox.setValue(int(value)) def _on_brush_size_change(self, event): with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brush_size_slider.setValue(value) def _on_n_dim_change(self, event): with self.layer.events.n_dimensional.blocker(): self.ndim_checkbox.setChecked(self.layer.n_dimensional) def _on_contig_change(self, event): with self.layer.events.contiguous.blocker(): self.contig_checkbox.setChecked(self.layer.contiguous)
class MaskWidget(QWidget): values_changed = Signal() def __init__(self, settings: ImageSettings, parent=None): super().__init__(parent) self.setContentsMargins(0, 0, 0, 0) self.settings = settings self.dilate_radius = QSpinBox() self.dilate_radius.setRange(-100, 100) # self.dilate_radius.setButtonSymbols(QAbstractSpinBox.NoButtons) self.dilate_radius.setSingleStep(1) self.dilate_radius.setDisabled(True) self.dilate_dim = QEnumComboBox(enum_class=RadiusType) self.dilate_dim.setToolTip("With minus radius mask will be eroded") # noinspection PyUnresolvedReferences self.dilate_dim.currentIndexChanged.connect( partial(off_widget, self.dilate_radius, self.dilate_dim)) self.radius_information = QLabel() # noinspection PyUnresolvedReferences self.dilate_radius.valueChanged.connect(self.dilate_change) # noinspection PyUnresolvedReferences self.dilate_dim.currentIndexChanged.connect(self.dilate_change) self.fill_holes = QEnumComboBox(enum_class=RadiusType) self.max_hole_size = QSpinBox() self.max_hole_size.setRange(-1, 10000) self.max_hole_size.setValue(-1) self.max_hole_size.setSingleStep(100) self.max_hole_size.setDisabled(True) self.max_hole_size.setToolTip( "Maximum size of holes to be closed. -1 means that all holes will be closed" ) # noinspection PyUnresolvedReferences self.fill_holes.currentIndexChanged.connect( partial(off_widget, self.max_hole_size, self.fill_holes)) self.save_components = QCheckBox() self.clip_to_mask = QCheckBox() self.reversed_check = QCheckBox() # noinspection PyUnresolvedReferences self.dilate_radius.valueChanged.connect(self.values_changed.emit) # noinspection PyUnresolvedReferences self.dilate_dim.currentIndexChanged.connect(self.values_changed.emit) # noinspection PyUnresolvedReferences self.fill_holes.currentIndexChanged.connect(self.values_changed.emit) # noinspection PyUnresolvedReferences self.max_hole_size.valueChanged.connect(self.values_changed.emit) self.save_components.stateChanged.connect(self.values_changed.emit) self.clip_to_mask.stateChanged.connect(self.values_changed.emit) self.reversed_check.stateChanged.connect(self.values_changed.emit) layout = QVBoxLayout() layout1 = QHBoxLayout() layout1.addWidget(QLabel("Dilate mask:")) layout1.addWidget(self.dilate_dim) layout1.addWidget(QLabel("radius (in pix):")) layout1.addWidget(self.dilate_radius) layout.addLayout(layout1) layout2 = QHBoxLayout() layout2.addWidget(QLabel("Fill holes:")) layout2.addWidget(self.fill_holes) layout2.addWidget(QLabel("Max size:")) layout2.addWidget(self.max_hole_size) layout.addLayout(layout2) layout3 = QHBoxLayout() comp_lab = QLabel("Save components:") comp_lab.setToolTip( "save components information in mask. Dilation, " "holes filing will be done separately for each component") self.save_components.setToolTip(comp_lab.toolTip()) layout3.addWidget(comp_lab) layout3.addWidget(self.save_components) layout3.addStretch() clip_mask = QLabel("Clip to previous mask:") clip_mask.setToolTip("Useful dilated new mask") layout3.addWidget(clip_mask) layout3.addWidget(self.clip_to_mask) layout.addLayout(layout3) layout4 = QHBoxLayout() layout4.addWidget(QLabel("Reversed mask:")) layout4.addWidget(self.reversed_check) layout4.addStretch(1) layout.addLayout(layout4) self.setLayout(layout) self.dilate_change() def get_dilate_radius(self): radius = calculate_operation_radius(self.dilate_radius.value(), self.settings.image_spacing, self.dilate_dim.currentEnum()) if isinstance(radius, (list, tuple)): return [int(x + 0.5) for x in radius] return int(radius) def dilate_change(self): if self.dilate_radius.value() == 0 or self.dilate_dim.currentEnum( ) == RadiusType.NO: self.radius_information.setText("Dilation radius: 0") else: dilate_radius = self.get_dilate_radius() if isinstance(dilate_radius, list): self.radius_information.setText( f"Dilation radius: {dilate_radius[::-1]}") else: self.radius_information.setText( f"Dilation radius: {dilate_radius}") def get_mask_property(self): return MaskProperty( dilate=self.dilate_dim.currentEnum() if self.dilate_radius.value() != 0 else RadiusType.NO, dilate_radius=self.dilate_radius.value() if self.dilate_dim.currentEnum() != RadiusType.NO else 0, fill_holes=self.fill_holes.currentEnum() if self.max_hole_size.value() != 0 else RadiusType.NO, max_holes_size=self.max_hole_size.value() if self.fill_holes.currentEnum() != RadiusType.NO else 0, save_components=self.save_components.isChecked(), clip_to_mask=self.clip_to_mask.isChecked(), reversed_mask=self.reversed_check.isChecked(), ) def set_mask_property(self, prop: MaskProperty): self.dilate_dim.setCurrentEnum(prop.dilate) self.dilate_radius.setValue(prop.dilate_radius) self.fill_holes.setCurrentEnum(prop.fill_holes) self.max_hole_size.setValue(prop.max_holes_size) self.save_components.setChecked(prop.save_components) self.clip_to_mask.setChecked(prop.clip_to_mask) self.reversed_check.setChecked(prop.reversed_mask)
class QtLabelsControls(QtLayerControls): def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect(self._on_selection_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contig_change) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.layer.events.editable.connect(self._on_editable_change) # shuffle colormap button self.colormapUpdate = QPushButton('shuffle colors') self.colormapUpdate.setObjectName('shuffle') self.colormapUpdate.clicked.connect(self.changeColor) self.colormapUpdate.setFixedHeight(28) # selection spinbox self.selectionSpinBox = QSpinBox() self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.setSingleStep(1) self.selectionSpinBox.setMinimum(0) self.selectionSpinBox.setMaximum(2147483647) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self._on_selection_change(None) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged[int].connect(lambda value=sld: self.changeSize(value)) self.brushSizeSlider = sld self._on_brush_size_change(None) contig_cb = QCheckBox() contig_cb.setToolTip('contiguous editing') contig_cb.stateChanged.connect( lambda state=contig_cb: self.change_contig(state)) self.contigCheckBox = contig_cb self._on_contig_change(None) ndim_cb = QCheckBox() ndim_cb.setToolTip('n-dimensional editing') ndim_cb.stateChanged.connect( lambda state=ndim_cb: self.change_ndim(state)) self.ndimCheckBox = ndim_cb self._on_n_dim_change(None) self.panzoom_button = QtModeButton(layer, 'zoom', Mode.PAN_ZOOM, 'Pan/zoom mode') self.pick_button = QtModeButton(layer, 'picker', Mode.PICKER, 'Pick mode') self.paint_button = QtModeButton(layer, 'paint', Mode.PAINT, 'Paint mode') self.fill_button = QtModeButton(layer, 'fill', Mode.FILL, 'Fill mode') self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.panzoom_button.setChecked(True) self._on_editable_change(None) button_row = QHBoxLayout() button_row.addWidget(self.pick_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.panzoom_button) button_row.addStretch(1) button_row.setSpacing(4) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 1, 1, 2) self.grid_layout.addWidget(self.colormapUpdate, 0, 0) self.grid_layout.addWidget(QLabel('label:'), 1, 0) self.grid_layout.addWidget(self.selectionSpinBox, 1, 2) self.grid_layout.addWidget(QtColorBox(layer), 1, 1) self.grid_layout.addWidget(QLabel('opacity:'), 2, 0) self.grid_layout.addWidget(self.opacitySilder, 2, 1, 1, 2) self.grid_layout.addWidget(QLabel('brush size:'), 3, 0) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 2) self.grid_layout.addWidget(QLabel('blending:'), 4, 0) self.grid_layout.addWidget(self.blendComboBox, 4, 1, 1, 2) self.grid_layout.addWidget(QLabel('contiguous:'), 5, 0) self.grid_layout.addWidget(self.contigCheckBox, 5, 1) self.grid_layout.addWidget(QLabel('n-dim:'), 6, 0) self.grid_layout.addWidget(self.ndimCheckBox, 6, 1) self.grid_layout.setRowStretch(7, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def mouseMoveEvent(self, event): self.layer.status = str(self.layer.mode) def _on_mode_change(self, event): mode = event.mode if mode == Mode.PAN_ZOOM: self.panzoom_button.setChecked(True) elif mode == Mode.PICKER: self.pick_button.setChecked(True) elif mode == Mode.PAINT: self.paint_button.setChecked(True) elif mode == Mode.FILL: self.fill_button.setChecked(True) else: raise ValueError("Mode not recongnized") def changeColor(self): self.layer.new_colormap() def changeSelection(self, value): self.layer.selected_label = value self.selectionSpinBox.clearFocus() self.setFocus() def changeSize(self, value): self.layer.brush_size = value def change_contig(self, state): if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def _on_selection_change(self, event): with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selectionSpinBox.setValue(int(value)) def _on_brush_size_change(self, event): with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brushSizeSlider.setValue(value) def _on_n_dim_change(self, event): with self.layer.events.n_dimensional.blocker(): self.ndimCheckBox.setChecked(self.layer.n_dimensional) def _on_contig_change(self, event): with self.layer.events.contiguous.blocker(): self.contigCheckBox.setChecked(self.layer.contiguous) def _on_editable_change(self, event): self.pick_button.setEnabled(self.layer.editable) self.paint_button.setEnabled(self.layer.editable) self.fill_button.setEnabled(self.layer.editable)
class QtLabelsControls(QtLayerControls): """Qt view and controls for the napari Labels layer. Parameters ---------- layer : napari.layers.Labels An instance of a napari Labels layer. Attributes ---------- button_group : qtpy.QtWidgets.QButtonGroup Button group of labels layer modes: PAN_ZOOM, PICKER, PAINT, or FILL. colormapUpdate : qtpy.QtWidgets.QPushButton Button to update colormap of label layer. contigCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is contiguous. fill_button : qtpy.QtWidgets.QtModeRadioButton Button to select FILL mode on Labels layer. grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Labels An instance of a napari Labels layer. ndimCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is n-dimensional. paint_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAINT mode on Labels layer. panzoom_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAN_ZOOM mode on Labels layer. pick_button : qtpy.QtWidgets.QtModeRadioButton Button to select PICKER mode on Labels layer. selectionSpinBox : qtpy.QtWidgets.QSpinBox Widget to select a specfic label by its index. Raises ------ ValueError Raise error if label mode is not PAN_ZOOM, PICKER, PAINT, or FILL. """ def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect(self._on_selection_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contig_change) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.layer.events.editable.connect(self._on_editable_change) # shuffle colormap button self.colormapUpdate = QPushButton('shuffle colors') self.colormapUpdate.setObjectName('shuffleButton') self.colormapUpdate.clicked.connect(self.changeColor) # 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() self.panzoom_button = QtModeRadioButton(layer, 'zoom', Mode.PAN_ZOOM, tooltip='Pan/zoom mode', checked=True) self.pick_button = QtModeRadioButton(layer, 'picker', Mode.PICKER, tooltip='Pick mode') self.paint_button = QtModeRadioButton(layer, 'paint', Mode.PAINT, tooltip='Paint mode') self.fill_button = QtModeRadioButton(layer, 'fill', Mode.FILL, tooltip='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._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) 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.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) 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, 1) self.grid_layout.addWidget(self.colormapUpdate, 0, 0) self.grid_layout.addWidget(QLabel('label:'), 1, 0) self.grid_layout.addLayout(color_layout, 1, 1) self.grid_layout.addWidget(QLabel('opacity:'), 2, 0) self.grid_layout.addWidget(self.opacitySlider, 2, 1) self.grid_layout.addWidget(QLabel('brush size:'), 3, 0) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1) self.grid_layout.addWidget(QLabel('blending:'), 4, 0) self.grid_layout.addWidget(self.blendComboBox, 4, 1) self.grid_layout.addWidget(QLabel('contiguous:'), 5, 0) self.grid_layout.addWidget(self.contigCheckBox, 5, 1) self.grid_layout.addWidget(QLabel('n-dim:'), 6, 0) self.grid_layout.addWidget(self.ndimCheckBox, 6, 1) self.grid_layout.setRowStretch(7, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def mouseMoveEvent(self, event): """On mouse move, set layer status equal to the current selected mode. Available mode options are: PAN_ZOOM, PICKER, PAINT, or FILL Parameters ---------- event : qtpy.QtCore.QEvent Event from the Qt context. """ self.layer.status = str(self.layer.mode) def _on_mode_change(self, event): """Receive layer model mode change event and update checkbox ticks. Parameters ---------- event : qtpy.QtCore.QEvent Event from the Qt context. Raises ------ ValueError Raise error if event.mode is not PAN_ZOOM, PICKER, PAINT, or FILL """ mode = event.mode if mode == Mode.PAN_ZOOM: self.panzoom_button.setChecked(True) elif mode == Mode.PICKER: self.pick_button.setChecked(True) elif mode == Mode.PAINT: self.paint_button.setChecked(True) elif mode == Mode.FILL: self.fill_button.setChecked(True) else: raise ValueError("Mode not recognized") def changeColor(self): """Change colormap of the label layer.""" self.layer.new_colormap() def changeSelection(self, value): """Change currently selected label. Parameters ---------- value : int Index of label to select. """ self.layer.selected_label = value self.selectionSpinBox.clearFocus() self.setFocus() def changeSize(self, value): """Change paint brush size. Parameters ---------- value : float Size of the paint brush. """ self.layer.brush_size = value def change_contig(self, state): """Toggle contiguous state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if labels are contiguous. """ if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): """Toggle n-dimensional state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if label layer is n-dimensional. """ if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def _on_selection_change(self, event=None): """Receive layer model label selection change event and update spinbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selectionSpinBox.setValue(int(value)) def _on_brush_size_change(self, event=None): """Receive layer model brush size change event and update the slider. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brushSizeSlider.setValue(value) def _on_n_dim_change(self, event=None): """Receive layer model n-dim mode change event and update the checkbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.n_dimensional.blocker(): self.ndimCheckBox.setChecked(self.layer.n_dimensional) def _on_contig_change(self, event=None): """Receive layer model contiguous change event and update the checkbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.contiguous.blocker(): self.contigCheckBox.setChecked(self.layer.contiguous) def _on_editable_change(self, event=None): """Receive layer model editable change event & enable/disable buttons. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ disable_with_opacity( self, ['pick_button', 'paint_button', 'fill_button'], self.layer.editable, )
class EditGeometryProperties(PyDialog): force = True def __init__(self, data, win_parent=None): """ +------------------+ | Edit Actor Props | +------------------+------+ | Name1 | | Name2 | | Name3 | | Name4 | | | | Active_Name main | | Color box | | Line_Width 2 | | Point_Size 2 | | Bar_Scale 2 | | Opacity 0.5 | | Show/Hide | | | | Apply OK Cancel | +-------------------------+ """ PyDialog.__init__(self, data, win_parent) self.set_font_size(data['font_size']) del self.out_data['font_size'] self.setWindowTitle('Edit Geometry Properties') self.allow_update = True #default #self.win_parent = win_parent #self.out_data = data self.keys = sorted(data.keys()) self.keys = data.keys() keys = self.keys #nrows = len(keys) self.active_key = 'main' items = list(keys) header_labels = ['Groups'] table_model = Model(items, header_labels, self) view = SingleChoiceQTableView(self) #Call your custom QTableView here view.setModel(table_model) #if qt_version == 4: #view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.table = view #self.opacity_edit.valueChanged.connect(self.on_opacity) #mListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(itemClicked(QListWidgetItem*))); #self.table.itemClicked.connect(self.table.mouseDoubleClickEvent) actor_obj = data[self.active_key] name = actor_obj.name line_width = actor_obj.line_width point_size = actor_obj.point_size bar_scale = actor_obj.bar_scale opacity = actor_obj.opacity color = actor_obj.color show = actor_obj.is_visible self.representation = actor_obj.representation # table header = self.table.horizontalHeader() header.setStretchLastSection(True) self._default_is_apply = False self.name = QLabel("Name:") self.name_edit = QLineEdit(str(name)) self.name_edit.setDisabled(True) self.color = QLabel("Color:") self.color_edit = QPushButton() #self.color_edit.setFlat(True) color = self.out_data[self.active_key].color qcolor = QtGui.QColor() qcolor.setRgb(*color) #print('color =%s' % str(color)) palette = QtGui.QPalette(self.color_edit.palette()) # make a copy of the palette #palette.setColor(QtGui.QPalette.Active, QtGui.QPalette.Base, \ #qcolor) palette.setColor(QtGui.QPalette.Background, QtGui.QColor('blue')) # ButtonText self.color_edit.setPalette(palette) self.color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(color) + #"border:1px solid rgb(255, 170, 255); " "}") self.use_slider = True self.is_opacity_edit_active = False self.is_opacity_edit_slider_active = False self.is_line_width_edit_active = False self.is_line_width_edit_slider_active = False self.is_point_size_edit_active = False self.is_point_size_edit_slider_active = False self.is_bar_scale_edit_active = False self.is_bar_scale_edit_slider_active = False self.opacity = QLabel("Opacity:") self.opacity_edit = QDoubleSpinBox(self) self.opacity_edit.setRange(0.1, 1.0) self.opacity_edit.setDecimals(1) self.opacity_edit.setSingleStep(0.1) self.opacity_edit.setValue(opacity) if self.use_slider: self.opacity_slider_edit = QSlider(QtCore.Qt.Horizontal) self.opacity_slider_edit.setRange(1, 10) self.opacity_slider_edit.setValue(opacity * 10) self.opacity_slider_edit.setTickInterval(1) self.opacity_slider_edit.setTickPosition(QSlider.TicksBelow) self.line_width = QLabel("Line Width:") self.line_width_edit = QSpinBox(self) self.line_width_edit.setRange(1, MAX_LINE_WIDTH) self.line_width_edit.setSingleStep(1) self.line_width_edit.setValue(line_width) if self.use_slider: self.line_width_slider_edit = QSlider(QtCore.Qt.Horizontal) self.line_width_slider_edit.setRange(1, MAX_LINE_WIDTH) self.line_width_slider_edit.setValue(line_width) self.line_width_slider_edit.setTickInterval(1) self.line_width_slider_edit.setTickPosition(QSlider.TicksBelow) if self.representation in ['point', 'surface']: self.line_width.setEnabled(False) self.line_width_edit.setEnabled(False) self.line_width_slider_edit.setEnabled(False) self.point_size = QLabel("Point Size:") self.point_size_edit = QSpinBox(self) self.point_size_edit.setRange(1, MAX_POINT_SIZE) self.point_size_edit.setSingleStep(1) self.point_size_edit.setValue(point_size) self.point_size.setVisible(False) self.point_size_edit.setVisible(False) if self.use_slider: self.point_size_slider_edit = QSlider(QtCore.Qt.Horizontal) self.point_size_slider_edit.setRange(1, MAX_POINT_SIZE) self.point_size_slider_edit.setValue(point_size) self.point_size_slider_edit.setTickInterval(1) self.point_size_slider_edit.setTickPosition(QSlider.TicksBelow) self.point_size_slider_edit.setVisible(False) if self.representation in ['wire', 'surface']: self.point_size.setEnabled(False) self.point_size_edit.setEnabled(False) if self.use_slider: self.point_size_slider_edit.setEnabled(False) self.bar_scale = QLabel("Bar Scale:") self.bar_scale_edit = QDoubleSpinBox(self) #self.bar_scale_edit.setRange(0.01, 1.0) # was 0.1 #self.bar_scale_edit.setRange(0.05, 5.0) self.bar_scale_edit.setDecimals(1) #self.bar_scale_edit.setSingleStep(bar_scale / 10.) self.bar_scale_edit.setSingleStep(0.1) self.bar_scale_edit.setValue(bar_scale) #if self.use_slider: #self.bar_scale_slider_edit = QSlider(QtCore.Qt.Horizontal) #self.bar_scale_slider_edit.setRange(1, 100) # 1/0.05 = 100/5.0 #self.bar_scale_slider_edit.setValue(opacity * 0.05) #self.bar_scale_slider_edit.setTickInterval(10) #self.bar_scale_slider_edit.setTickPosition(QSlider.TicksBelow) if self.representation != 'bar': self.bar_scale.setEnabled(False) self.bar_scale_edit.setEnabled(False) self.bar_scale.setVisible(False) self.bar_scale_edit.setVisible(False) #self.bar_scale_slider_edit.setVisible(False) #self.bar_scale_slider_edit.setEnabled(False) # show/hide self.checkbox_show = QCheckBox("Show") self.checkbox_hide = QCheckBox("Hide") self.checkbox_show.setChecked(show) self.checkbox_hide.setChecked(not show) if name == 'main': self.color.setEnabled(False) self.color_edit.setEnabled(False) self.point_size.setEnabled(False) self.point_size_edit.setEnabled(False) if self.use_slider: self.point_size_slider_edit.setEnabled(False) self.cancel_button = QPushButton("Close") self.create_layout() self.set_connections() def on_delete(self, irow): """deletes an actor based on the row number""" if irow == 0: # main return nkeys = len(self.keys) if nkeys in [0, 1]: return name = self.keys[irow] nrows = nkeys - 1 self.keys.pop(irow) header_labels = ['Groups'] table_model = Model(self.keys, header_labels, self) self.table.setModel(table_model) if len(self.keys) == 0: self.update() self.set_as_null() return if irow == nrows: irow -= 1 new_name = self.keys[irow] self.update_active_name(new_name) if self.is_gui: self.win_parent.delete_actor(name) def set_as_null(self): """sets the null case""" self.name.setVisible(False) self.name_edit.setVisible(False) self.color.setVisible(False) self.color_edit.setVisible(False) self.line_width.setVisible(False) self.line_width_edit.setVisible(False) self.point_size.setVisible(False) self.point_size_edit.setVisible(False) self.bar_scale.setVisible(False) self.bar_scale_edit.setVisible(False) self.opacity.setVisible(False) self.opacity_edit.setVisible(False) self.opacity_slider_edit.setVisible(False) self.point_size_slider_edit.setVisible(False) self.line_width_slider_edit.setVisible(False) self.checkbox_show.setVisible(False) self.checkbox_hide.setVisible(False) def on_update_geometry_properties_window(self, data): """Not Implemented""" return #new_keys = sorted(data.keys()) #if self.active_key in new_keys: #i = new_keys.index(self.active_key) #else: #i = 0 #self.table.update_data(new_keys) #self.out_data = data #self.update_active_key(i) def update_active_key(self, index): """ Parameters ---------- index : PyQt4.QtCore.QModelIndex the index of the list Internal Parameters ------------------- name : str the name of obj obj : CoordProperties, AltGeometry the storage object for things like line_width, point_size, etc. """ name = str(index.data()) #print('name = %r' % name) #i = self.keys.index(self.active_key) self.update_active_name(name) def update_active_name(self, name): self.active_key = name self.name_edit.setText(name) obj = self.out_data[name] if isinstance(obj, CoordProperties): opacity = 1.0 representation = 'coord' is_visible = obj.is_visible elif isinstance(obj, AltGeometry): line_width = obj.line_width point_size = obj.point_size bar_scale = obj.bar_scale opacity = obj.opacity representation = obj.representation is_visible = obj.is_visible self.color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(obj.color) + #"border:1px solid rgb(255, 170, 255); " "}") self.allow_update = False self.force = False self.line_width_edit.setValue(line_width) self.point_size_edit.setValue(point_size) self.bar_scale_edit.setValue(bar_scale) self.force = True self.allow_update = True else: raise NotImplementedError(obj) #allowed_representations = [ #'main', 'surface', 'coord', 'toggle', 'wire', 'point', 'bar'] if self.representation != representation: self.representation = representation #if representation not in allowed_representations: #msg = 'name=%r; representation=%r is invalid\nrepresentations=%r' % ( #name, representation, allowed_representations) if self.representation == 'coord': self.color.setVisible(False) self.color_edit.setVisible(False) self.line_width.setVisible(False) self.line_width_edit.setVisible(False) self.point_size.setVisible(False) self.point_size_edit.setVisible(False) self.bar_scale.setVisible(False) self.bar_scale_edit.setVisible(False) self.opacity.setVisible(False) self.opacity_edit.setVisible(False) if self.use_slider: self.opacity_slider_edit.setVisible(False) self.point_size_slider_edit.setVisible(False) self.line_width_slider_edit.setVisible(False) #self.bar_scale_slider_edit.setVisible(False) else: self.color.setVisible(True) self.color_edit.setVisible(True) self.line_width.setVisible(True) self.line_width_edit.setVisible(True) self.point_size.setVisible(True) self.point_size_edit.setVisible(True) self.bar_scale.setVisible(True) #self.bar_scale_edit.setVisible(True) self.opacity.setVisible(True) self.opacity_edit.setVisible(True) if self.use_slider: self.opacity_slider_edit.setVisible(True) self.line_width_slider_edit.setVisible(True) self.point_size_slider_edit.setVisible(True) #self.bar_scale_slider_edit.setVisible(True) if name == 'main': self.color.setEnabled(False) self.color_edit.setEnabled(False) self.point_size.setEnabled(False) self.point_size_edit.setEnabled(False) self.line_width.setEnabled(True) self.line_width_edit.setEnabled(True) self.bar_scale.setEnabled(False) self.bar_scale_edit.setEnabled(False) show_points = False show_line_width = True show_bar_scale = False if self.use_slider: self.line_width_slider_edit.setEnabled(True) #self.bar_scale_slider_edit.setVisible(False) else: self.color.setEnabled(True) self.color_edit.setEnabled(True) show_points = False if self.representation in ['point', 'wire+point']: show_points = True show_line_width = False if self.representation in ['wire', 'wire+point', 'bar', 'toggle']: show_line_width = True if representation == 'bar': show_bar_scale = True else: show_bar_scale = False #self.bar_scale_button.setVisible(show_bar_scale) #self.bar_scale_edit.setSingleStep(bar_scale / 10.) #if self.use_slider: #self.bar_scale_slider_edit.setEnabled(False) self.point_size.setEnabled(show_points) self.point_size_edit.setEnabled(show_points) self.point_size.setVisible(show_points) self.point_size_edit.setVisible(show_points) self.line_width.setEnabled(show_line_width) self.line_width_edit.setEnabled(show_line_width) self.bar_scale.setEnabled(show_bar_scale) self.bar_scale_edit.setEnabled(show_bar_scale) self.bar_scale.setVisible(show_bar_scale) self.bar_scale_edit.setVisible(show_bar_scale) if self.use_slider: self.point_size_slider_edit.setEnabled(show_points) self.point_size_slider_edit.setVisible(show_points) self.line_width_slider_edit.setEnabled(show_line_width) #if self.representation in ['wire', 'surface']: self.opacity_edit.setValue(opacity) #if self.use_slider: #self.opacity_slider_edit.setValue(opacity*10) self.checkbox_show.setChecked(is_visible) self.checkbox_hide.setChecked(not is_visible) passed = self.on_validate() #self.on_apply(force=True) # TODO: was turned on...do I want this??? #self.allow_update = True def create_layout(self): ok_cancel_box = QHBoxLayout() ok_cancel_box.addWidget(self.cancel_button) grid = QGridLayout() irow = 0 grid.addWidget(self.name, irow, 0) grid.addWidget(self.name_edit, irow, 1) irow += 1 grid.addWidget(self.color, irow, 0) grid.addWidget(self.color_edit, irow, 1) irow += 1 grid.addWidget(self.opacity, irow, 0) if self.use_slider: grid.addWidget(self.opacity_edit, irow, 2) grid.addWidget(self.opacity_slider_edit, irow, 1) else: grid.addWidget(self.opacity_edit, irow, 1) irow += 1 grid.addWidget(self.line_width, irow, 0) if self.use_slider: grid.addWidget(self.line_width_edit, irow, 2) grid.addWidget(self.line_width_slider_edit, irow, 1) else: grid.addWidget(self.line_width_edit, irow, 1) irow += 1 grid.addWidget(self.point_size, irow, 0) if self.use_slider: grid.addWidget(self.point_size_edit, irow, 2) grid.addWidget(self.point_size_slider_edit, irow, 1) else: grid.addWidget(self.point_size_edit, irow, 1) irow += 1 grid.addWidget(self.bar_scale, irow, 0) if self.use_slider and 0: grid.addWidget(self.bar_scale_edit, irow, 2) grid.addWidget(self.bar_scale_slider_edit, irow, 1) else: grid.addWidget(self.bar_scale_edit, irow, 1) irow += 1 checkboxs = QButtonGroup(self) checkboxs.addButton(self.checkbox_show) checkboxs.addButton(self.checkbox_hide) vbox = QVBoxLayout() vbox.addWidget(self.table, stretch=1) vbox.addLayout(grid) vbox1 = QVBoxLayout() vbox1.addWidget(self.checkbox_show) vbox1.addWidget(self.checkbox_hide) vbox.addLayout(vbox1) vbox.addStretch() #vbox.addWidget(self.check_apply) vbox.addLayout(ok_cancel_box) self.setLayout(vbox) def set_connections(self): self.opacity_edit.valueChanged.connect(self.on_opacity) self.line_width_edit.valueChanged.connect(self.on_line_width) self.point_size_edit.valueChanged.connect(self.on_point_size) self.bar_scale_edit.valueChanged.connect(self.on_bar_scale) if self.use_slider: self.opacity_slider_edit.valueChanged.connect(self.on_opacity_slider) self.line_width_slider_edit.valueChanged.connect(self.on_line_width_slider) self.point_size_slider_edit.valueChanged.connect(self.on_point_size_slider) #self.bar_scale_slider_edit.valueChanged.connect(self.on_bar_scale_slider) # self.connect(self.opacity_edit, QtCore.SIGNAL('clicked()'), self.on_opacity) # self.connect(self.line_width, QtCore.SIGNAL('clicked()'), self.on_line_width) # self.connect(self.point_size, QtCore.SIGNAL('clicked()'), self.on_point_size) if qt_version == 4: self.connect(self, QtCore.SIGNAL('triggered()'), self.closeEvent) self.color_edit.clicked.connect(self.on_color) self.checkbox_show.clicked.connect(self.on_show) self.checkbox_hide.clicked.connect(self.on_hide) self.cancel_button.clicked.connect(self.on_cancel) # closeEvent def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Escape: self.close() def closeEvent(self, event): self.on_cancel() def on_color(self): """called when the user clicks on the color box""" name = self.active_key obj = self.out_data[name] rgb_color_ints = obj.color msg = name col = QColorDialog.getColor(QtGui.QColor(*rgb_color_ints), self, "Choose a %s color" % msg) if col.isValid(): color_float = col.getRgbF()[:3] obj.color = color_float color_int = [int(colori * 255) for colori in color_float] self.color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(color_int) + #"border:1px solid rgb(255, 170, 255); " "}") self.on_apply(force=self.force) #print(self.allow_update) def on_show(self): """shows the actor""" name = self.active_key is_checked = self.checkbox_show.isChecked() self.out_data[name].is_visible = is_checked self.on_apply(force=self.force) def on_hide(self): """hides the actor""" name = self.active_key is_checked = self.checkbox_hide.isChecked() self.out_data[name].is_visible = not is_checked self.on_apply(force=self.force) def on_line_width(self): """increases/decreases the wireframe (for solid bodies) or the bar thickness""" self.is_line_width_edit_active = True name = self.active_key line_width = self.line_width_edit.value() self.out_data[name].line_width = line_width if not self.is_line_width_edit_slider_active: if self.use_slider: self.line_width_slider_edit.setValue(line_width) self.is_line_width_edit_active = False self.on_apply(force=self.force) self.is_line_width_edit_active = False def on_line_width_slider(self): """increases/decreases the wireframe (for solid bodies) or the bar thickness""" self.is_line_width_edit_slider_active = True #name = self.active_key line_width = self.line_width_slider_edit.value() if not self.is_line_width_edit_active: self.line_width_edit.setValue(line_width) self.is_line_width_edit_slider_active = False def on_point_size(self): """increases/decreases the point size""" self.is_point_size_edit_active = True name = self.active_key point_size = self.point_size_edit.value() self.out_data[name].point_size = point_size if not self.is_point_size_edit_slider_active: if self.use_slider: self.point_size_slider_edit.setValue(point_size) self.is_point_size_edit_active = False self.on_apply(force=self.force) self.is_point_size_edit_active = False def on_point_size_slider(self): """increases/decreases the point size""" self.is_point_size_edit_slider_active = True #name = self.active_key point_size = self.point_size_slider_edit.value() if not self.is_point_size_edit_active: self.point_size_edit.setValue(point_size) self.is_point_size_edit_slider_active = False def on_bar_scale(self): """ Vectors start at some xyz coordinate and can increase in length. Increases/decreases the length scale factor. """ self.is_bar_scale_edit_active = True name = self.active_key float_bar_scale = self.bar_scale_edit.value() self.out_data[name].bar_scale = float_bar_scale if not self.is_bar_scale_edit_slider_active: #int_bar_scale = int(round(float_bar_scale * 20, 0)) #if self.use_slider: #self.bar_scale_slider_edit.setValue(int_bar_scale) self.is_bar_scale_edit_active = False self.on_apply(force=self.force) self.is_bar_scale_edit_active = False def on_bar_scale_slider(self): """ Vectors start at some xyz coordinate and can increase in length. Increases/decreases the length scale factor. """ self.is_bar_scale_edit_slider_active = True #name = self.active_key int_bar_scale = self.bar_scale_slider_edit.value() if not self.is_bar_scale_edit_active: float_bar_scale = int_bar_scale / 20. self.bar_scale_edit.setValue(float_bar_scale) self.is_bar_scale_edit_slider_active = False def on_opacity(self): """ opacity = 1.0 (solid/opaque) opacity = 0.0 (invisible) """ self.is_opacity_edit_active = True name = self.active_key float_opacity = self.opacity_edit.value() self.out_data[name].opacity = float_opacity if not self.is_opacity_edit_slider_active: int_opacity = int(round(float_opacity * 10, 0)) if self.use_slider: self.opacity_slider_edit.setValue(int_opacity) self.is_opacity_edit_active = False self.on_apply(force=self.force) self.is_opacity_edit_active = False def on_opacity_slider(self): """ opacity = 1.0 (solid/opaque) opacity = 0.0 (invisible) """ self.is_opacity_edit_slider_active = True #name = self.active_key int_opacity = self.opacity_slider_edit.value() if not self.is_opacity_edit_active: float_opacity = int_opacity / 10. self.opacity_edit.setValue(float_opacity) self.is_opacity_edit_slider_active = False def on_validate(self): self.out_data['clicked_ok'] = True self.out_data['clicked_cancel'] = False old_obj = self.out_data[self.active_key] old_obj.line_width = self.line_width_edit.value() old_obj.point_size = self.point_size_edit.value() old_obj.bar_scale = self.bar_scale_edit.value() old_obj.opacity = self.opacity_edit.value() #old_obj.color = self.color_edit old_obj.is_visible = self.checkbox_show.isChecked() return True #name_value, flag0 = self.check_name(self.name_edit) #ox_value, flag1 = self.check_float(self.transparency_edit) #if flag0 and flag1: #self.out_data['clicked_ok'] = True #return True #return False @property def is_gui(self): return hasattr(self.win_parent, 'on_update_geometry_properties') def on_apply(self, force=False): passed = self.on_validate() #print("passed=%s force=%s allow=%s" % (passed, force, self.allow_update)) if (passed or force) and self.allow_update and self.is_gui: #print('obj = %s' % self.out_data[self.active_key]) self.win_parent.on_update_geometry_properties(self.out_data, name=self.active_key) return passed def on_cancel(self): passed = self.on_apply(force=True) if passed: self.close()
class WingWindow(PyDialog): """ +-------------------+ | Legend Properties | +-----------------------+ | Title ______ Default | | Min ______ Default | | Max ______ Default | | Format ______ Default | | Scale ______ Default | | Phase ______ Default | | Number of Colors ____ | | Number of Labels ____ | | Label Size ____ | (TODO) | ColorMap ____ | (TODO) | | | x Min/Max (Blue->Red) | | o Max/Min (Red->Blue) | | | | x Vertical/Horizontal | | x Show/Hide | | | | Animate | | Apply OK Cancel | +-----------------------+ """ colormap_keys = ['metal', 'gold', 'grey'] def __init__(self, data, win_parent=None): PyDialog.__init__(self, data, win_parent) self._updated_legend = False self._animation_window_shown = False #self._icase = data['icase'] #self._default_icase = self._icase self._default_name = data['name'] self._color_int = data['color'] #self.setupUi(self) self.setWindowTitle('Wing') self.create_widgets() self.create_layout() #self.set_connections() self.set_font_size(data['font_size']) self.symmetry = data['symmetry'] self.transform = data['transform'] def create_widgets(self): """creates the menu objects""" self.create_general_widgets() self.create_xform_widgets() def create_general_widgets(self): """creates the menu objects""" # -------------------------------------------------------------- # Name self.name = QLabel("Name:") self.name_edit = QLineEdit(str(self._default_name)) self.colormap = QLabel("Color:") self.colormap_edit = QPushButtonColor(self._color_int, 'Select a color', parent=self) self.colormap_button = QPushButton("Advanced") self.colormap_button.setEnabled(False) # -------------------------------------------------------------- # TODO: the way these sliders work is they have some defined range # if you go outside the range, they "reset" to 50% and # are redefined from value-delta to value+delta, where # delta=nominal/2 num_u = 5 num_w = 10 self.tesselation_u = QLabel("Num_U") self.tesselation_u_edit = QJumpSlider(QtCore.Qt.Horizontal) self.tesselation_u_edit.setTickPosition(QSlider.TicksBelow) self.tesselation_u_edit.setRange(1, 10) self.tesselation_u_edit.setValue(num_u) self.tesselation_u_button = QLineEdit('') def int_func(val): return str(int(val)) self.tesselation_u_edit.set_forward_connection( self.tesselation_u_button, int_func) self.tesselation_w = QLabel("Num_W") self.tesselation_w_edit = QJumpSlider(QtCore.Qt.Horizontal) self.tesselation_w_edit.setTickPosition(QSlider.TicksBelow) self.tesselation_w_edit.setRange(1, 10) self.tesselation_w_edit.setValue(num_w) self.tesselation_w_button = QLineEdit('') # -------------------------------------------------------------- density = 1.0 self.density = QLabel("Density") self.density_edit = QLineEdit(str(density)) self.density_button = QCheckBox('Thin Shell') priority = 3 priority_max = 50 self.priority = QLabel('Priority') msg = ( 'Components compete for volume during the mass properties.\n' 'A lower priority (e.g., 0) takes precendence. Additionally, \n' 'when combined with a density of 0.0, this can be used to \n' 'create voids (empty regions).') self.priority.setToolTip(msg) self.priority_edit = QSpinBox(self) self.priority_edit.setRange(0, priority_max) self.priority_edit.setSingleStep(1) self.priority_edit.setValue(priority) # -------------------------------------------------------------- self.negative_volume_button = QCheckBox('Negative Volume') # -------------------------------------------------------------- #for key in self.colormap_keys: #self.colormap_edit.addItem(key) #self._colormap = 'grey' #self.colormap_edit.setCurrentIndex(self.colormap_keys.index(self._colormap)) # -------------------------------------------------------------- # the header self.grid2_title = QLabel("Color Scale:") # on / off self.show_radio = QRadioButton("Show") self.hide_radio = QRadioButton("Hide") widget = QWidget(self) show_hide_group = QButtonGroup(widget) # -------------------------------------------------------------- # closing self.apply_button = QPushButton("Apply") self.ok_button = QPushButton("OK") self.cancel_button = QPushButton("Cancel") def create_xform_widgets(self): xloc = 0.0 yloc = 0.0 zloc = 0.0 xrot = 0.0 yrot = 0.0 zrot = 0.0 rot_origin_angle = 0.0 self.xloc = QLabel("X Loc") self.xloc_edit = QJumpSlider(QtCore.Qt.Horizontal) self.xloc_button = QLineEdit(str(xloc)) self.xloc_edit.set_forward_connection(self.xloc_button, float_func) #self.xloc_edit.setTickPosition(QSlider.TicksBelow) self.xloc_edit.setRange(1, 10) self.xloc_edit.setValue(xloc) self.yloc = QLabel("Y Loc") self.yloc_edit = QJumpSlider(QtCore.Qt.Horizontal) self.yloc_button = QLineEdit(str(yloc)) self.yloc_edit.set_forward_connection(self.yloc_button, float_func) #self.yloc_edit.setTickPosition(QSlider.TicksBelow) self.yloc_edit.setRange(1, 10) self.yloc_edit.setValue(yloc) self.zloc = QLabel("Z Loc") self.zloc_edit = QJumpSlider(QtCore.Qt.Horizontal) self.zloc_button = QLineEdit(str(zloc)) self.zloc_edit.set_forward_connection(self.zloc_button, float_func) #self.zloc_edit.setTickPosition(QSlider.TicksBelow) self.zloc_edit.setRange(1, 10) self.zloc_edit.setValue(zloc) self.xrot = QLabel("X Rot") self.xrot_edit = QJumpSlider(QtCore.Qt.Horizontal) self.xrot_button = QLineEdit(str(xrot)) self.xrot_edit.set_forward_connection(self.xrot_button, float_func) #self.xrot_edit.setTickPosition(QSlider.TicksBelow) self.xrot_edit.setRange(1, 10) self.xrot_edit.setValue(xrot) self.yrot = QLabel("Y Rot") self.yrot_edit = QJumpSlider(QtCore.Qt.Horizontal) self.yrot_button = QLineEdit(str(yrot)) self.yrot_edit.set_forward_connection(self.yrot_button, float_func) #self.yrot_edit.setTickPosition(QSlider.TicksBelow) self.yrot_edit.setRange(1, 10) self.yrot_edit.setValue(yrot) self.zrot = QLabel("Z Rot") self.zrot_edit = QJumpSlider(QtCore.Qt.Horizontal) self.zrot_button = QLineEdit(str(zrot)) self.zrot_edit.set_forward_connection(self.zrot_button, float_func) #self.zrot_edit.setTickPosition(QSlider.TicksBelow) self.zrot_edit.setRange(1, 10) self.zrot_edit.setValue(zrot) self.rot_origin = QLabel("Rot Origin (X)") self.rot_origin_edit = QJumpSlider(QtCore.Qt.Horizontal) self.rot_origin_button = QLineEdit(str(rot_origin_angle)) self.rot_origin_edit.set_forward_connection(self.rot_origin_button, float_func) #self.rot_origin_edit.setTickPosition(QSlider.TicksBelow) self.rot_origin_edit.setRange(1, 10) self.rot_origin_edit.setValue(rot_origin_angle) def create_geom_layout(self): group_name_color = QGroupBox('Name and Color') group_tesselation = QGroupBox('Tesselation') group_mass_properties = QGroupBox('Mass Properties') group_cfd_mesh = QGroupBox('CFD Mesh') grid_name_color = QGridLayout() grid_name_color.addWidget(self.name, 0, 0) grid_name_color.addWidget(self.name_edit, 0, 1) grid_name_color.addWidget(self.colormap, 1, 0) grid_name_color.addWidget(self.colormap_edit, 1, 1) grid_name_color.addWidget(self.colormap_button, 1, 2) group_name_color.setLayout(grid_name_color) #-------------------------------------------------------- grid_tesselation = QGridLayout() grid_tesselation.addWidget(self.tesselation_u, 2, 0) grid_tesselation.addWidget(self.tesselation_u_edit, 2, 1) grid_tesselation.addWidget(self.tesselation_u_button, 2, 2) grid_tesselation.addWidget(self.tesselation_w, 3, 0) grid_tesselation.addWidget(self.tesselation_w_edit, 3, 1) grid_tesselation.addWidget(self.tesselation_w_button, 3, 2) group_tesselation.setLayout(grid_tesselation) #-------------------------------------------------------- grid_mass_properties = QGridLayout() grid_mass_properties.addWidget(self.density, 4, 0) grid_mass_properties.addWidget(self.density_edit, 4, 1) grid_mass_properties.addWidget(self.density_button, 4, 2) grid_mass_properties.addWidget(self.priority, 5, 0) grid_mass_properties.addWidget(self.priority_edit, 5, 1) group_mass_properties.setLayout(grid_mass_properties) #-------------------------------------------------------- grid_cfd_mesh = QGridLayout() grid_cfd_mesh.addWidget(self.negative_volume_button, 1, 0) group_cfd_mesh.setLayout(grid_cfd_mesh) #-------------------------------------------------------- # footer ok_cancel_box = QHBoxLayout() ok_cancel_box.addWidget(self.apply_button) ok_cancel_box.addWidget(self.ok_button) ok_cancel_box.addWidget(self.cancel_button) grid2 = QGridLayout() grid2.addWidget(self.grid2_title, 0, 0) #grid2.addWidget(self.low_to_high_radio, 1, 0) #grid2.addWidget(self.high_to_low_radio, 2, 0) #grid2.addWidget(self.vertical_radio, 1, 1) #grid2.addWidget(self.horizontal_radio, 2, 1) grid2.addWidget(self.show_radio, 1, 2) grid2.addWidget(self.hide_radio, 2, 2) vbox = QVBoxLayout() vbox.addWidget(group_name_color) vbox.addWidget(group_tesselation) vbox.addWidget(group_mass_properties) vbox.addWidget(group_cfd_mesh) #vbox.addLayout(checkboxes) #vbox.addLayout(grid2) vbox.addStretch() vbox.addLayout(ok_cancel_box) #-------------------------------------------------------- tab1 = QWidget() tab1.setLayout(vbox) return tab1 def create_xform_layout(self): group_transforms = QGroupBox('Transforms') group_symmetry = QGroupBox('Symmetry') group_scale_factor = QGroupBox('Scale Factor') group_attach_to_parent = QGroupBox('Attach To Parent') #-------------------------------------------------------- grid_location = QGridLayout() grid_location.addWidget(self.xloc, 0, 0) grid_location.addWidget(self.xloc_edit, 0, 1) grid_location.addWidget(self.xloc_button, 0, 2) grid_location.addWidget(self.yloc, 1, 0) grid_location.addWidget(self.yloc_edit, 1, 1) grid_location.addWidget(self.yloc_button, 1, 2) grid_location.addWidget(self.zloc, 2, 0) grid_location.addWidget(self.zloc_edit, 2, 1) grid_location.addWidget(self.zloc_button, 2, 2) #------------- grid_location.addWidget(self.xrot, 3, 0) grid_location.addWidget(self.xrot_edit, 3, 1) grid_location.addWidget(self.xrot_button, 3, 2) grid_location.addWidget(self.yrot, 4, 0) grid_location.addWidget(self.yrot_edit, 4, 1) grid_location.addWidget(self.yrot_button, 4, 2) grid_location.addWidget(self.zrot, 5, 0) grid_location.addWidget(self.zrot_edit, 5, 1) grid_location.addWidget(self.zrot_button, 5, 2) grid_location.addWidget(self.rot_origin, 6, 0) grid_location.addWidget(self.rot_origin_edit, 6, 1) grid_location.addWidget(self.rot_origin_button, 6, 2) group_transforms.setLayout(grid_location) #-------------------------------------------------------- self.about = QLabel('About') self.about_edit = QComboBox(self) for attach_item in ['0 : Global Origin', '1 : WingGeom']: self.about_edit.addItem(attach_item) self.attach_object = QComboBox(self) for attach_item in ['Attach', 'Object']: self.attach_object.addItem(attach_item) grid_symmetry = QHBoxLayout() grid_symmetry.addWidget(self.about) grid_symmetry.addWidget(self.about_edit) grid_symmetry.addWidget(self.attach_object) group_symmetry.setLayout(grid_symmetry) #-------------------------------------------------------- scale = 1.1 self.scale = QLabel('Scale') self.scale_edit = QJumpSlider(QtCore.Qt.Horizontal) self.scale_button = QLineEdit(str(scale)) self.scale_edit.set_forward_connection(self.scale_button, float_func) self.reset_button = QPushButton('Reset') self.accept_button = QPushButton('Accept') grid_scale_factor = QGridLayout() grid_scale_factor.addWidget(self.scale, 0, 0) grid_scale_factor.addWidget(self.scale_edit, 0, 1) grid_scale_factor.addWidget(self.scale_button, 0, 2) grid_scale_factor.addWidget(self.reset_button, 0, 3) grid_scale_factor.addWidget(self.accept_button, 0, 4) group_scale_factor.setLayout(grid_scale_factor) #-------------------------------------------------------- grid_attach_to_parent = QGridLayout() translate = QLabel('Translate:') rotate = QLabel('Rotate:') fzero_to_100 = lambda x: str(x / 100.) uvalue = 0.5 wvalue = 0.6 uname = QLabel('U:') uedit = QJumpSlider(QtCore.Qt.Horizontal) ubutton = QLineEdit(str(uvalue)) uedit.set_forward_connection(ubutton, fzero_to_100) uedit.setRange(0, 100) wname = QLabel('W:') wedit = QJumpSlider(QtCore.Qt.Horizontal) wbutton = QLineEdit(str(wvalue)) wedit.set_forward_connection(wbutton, fzero_to_100) wedit.setRange(0, 100) self.translate_none = QCheckBox('None') self.translate_comp = QCheckBox('Comp') self.translate_uw = QCheckBox('UW') self.rotate_none = QCheckBox('None') self.rotate_comp = QCheckBox('Comp') self.rotate_uw = QCheckBox('UW') grid_attach_to_parent.addWidget(translate, 0, 0) grid_attach_to_parent.addWidget(self.translate_none, 0, 1) grid_attach_to_parent.addWidget(self.translate_comp, 0, 2) grid_attach_to_parent.addWidget(self.translate_uw, 0, 3) grid_attach_to_parent.addWidget(rotate, 1, 0) grid_attach_to_parent.addWidget(self.rotate_none, 1, 1) grid_attach_to_parent.addWidget(self.rotate_comp, 1, 2) grid_attach_to_parent.addWidget(self.rotate_uw, 1, 3) grid_attach_to_parent.addWidget(uname, 2, 0) grid_attach_to_parent.addWidget(uedit, 2, 1) grid_attach_to_parent.addWidget(ubutton, 2, 2) grid_attach_to_parent.addWidget(wname, 3, 0) grid_attach_to_parent.addWidget(wedit, 3, 1) grid_attach_to_parent.addWidget(wbutton, 3, 2) group_attach_to_parent.setLayout(grid_attach_to_parent) #-------------------------------------------------------- vbox = QVBoxLayout() vbox.addWidget(group_transforms) vbox.addWidget(group_symmetry) vbox.addWidget(group_scale_factor) vbox.addWidget(group_attach_to_parent) vbox.addStretch() #-------------------------------------------------------- tab1 = QWidget() tab1.setLayout(vbox) return tab1 def create_subsurfaces_layout(self): tab1 = QWidget() #tab1.setLayout(vbox) return tab1 def create_design_layout(self): tab1 = QWidget() #tab1.setLayout(vbox) return tab1 def create_skinning_layout(self): tab1 = QWidget() #tab1.setLayout(vbox) return tab1 def create_xsec_layout(self): tab1 = QWidget() #tab1.setLayout(vbox) return tab1 def create_layout(self): """displays the menu objects""" tab1 = self.create_geom_layout() tab2 = self.create_xform_layout() tab3 = self.create_subsurfaces_layout() tab4 = self.create_design_layout() tab5 = self.create_skinning_layout() tab6 = self.create_xsec_layout() tab3.setEnabled(False) tab4.setEnabled(False) tab5.setEnabled(False) tab6.setEnabled(False) #Create central widget, add layout and set #central_widget = QtGui.QWidget() #central_widget.setLayout(vbox) #self.setCentralWidget(central_widget) tabs = QTabWidget() tabs.addTab(tab1, "Geom") tabs.addTab(tab2, "XForm") tabs.addTab(tab3, "Sub-Surfaces") # 2 tabs.addTab(tab4, "Design") tabs.addTab(tab5, "Skinning") tabs.addTab(tab6, "X-Sec") tabs.setTabEnabled(2, False) # 0-based tabs.setTabEnabled(3, False) # 0-based tabs.setTabEnabled(4, False) # 0-based tabs.setTabEnabled(5, False) # 0-based #================================================================= vbox2 = QVBoxLayout() vbox2.addWidget(tabs) self.setLayout(vbox2) def set_connections(self): """creates the actions for the buttons""" self.name_button.clicked.connect(self.on_default_name) self.min_button.clicked.connect(self.on_default_min) self.max_button.clicked.connect(self.on_default_max) self.format_button.clicked.connect(self.on_default_format) self.scale_button.clicked.connect(self.on_default_scale) self.phase_button.clicked.connect(self.on_default_phase) self.nlabels_button.clicked.connect(self.on_default_nlabels) self.labelsize_button.clicked.connect(self.on_default_labelsize) self.ncolors_button.clicked.connect(self.on_default_ncolors) self.colormap_button.clicked.connect(self.on_default_colormap) self.animate_button.clicked.connect(self.on_animate) self.show_radio.clicked.connect(self.on_show_hide) self.hide_radio.clicked.connect(self.on_show_hide) self.apply_button.clicked.connect(self.on_apply) self.ok_button.clicked.connect(self.on_ok) self.cancel_button.clicked.connect(self.on_cancel) if qt_version == 4: self.connect(self, QtCore.SIGNAL('triggered()'), self.closeEvent) #self.colormap_edit.activated[str].connect(self.onActivated) #else: # closeEvent??? def set_font_size(self, font_size): """ Updates the font size of the objects Parameters ---------- font_size : int the font size """ return if self.font_size == font_size: return self.font_size = font_size font = QFont() font.setPointSize(font_size) self.setFont(font) #self.name_edit.setFont(font) #self.min_edit.setFont(font) #self.max_edit.setFont(font) #self.format_edit.setFont(font) #self.scale_edit.setFont(font) #self.phase_edit.setFont(font) #self.nlabels_edit.setFont(font) #self.labelsize_edit.setFont(font) #self.ncolors_edit.setFont(font) def on_default_name(self): """action when user clicks 'Default' for name""" name = str(self._default_name) self.name_edit.setText(name) self.name_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_min(self): """action when user clicks 'Default' for min value""" self.min_edit.setText(str(self._default_min)) self.min_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_max(self): """action when user clicks 'Default' for max value""" self.max_edit.setText(str(self._default_max)) self.max_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_format(self): """action when user clicks 'Default' for the number format""" self.format_edit.setText(str(self._default_format)) self.format_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_scale(self): """action when user clicks 'Default' for scale factor""" self.scale_edit.setText(str(self._default_scale)) self.scale_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_phase(self): """action when user clicks 'Default' for phase angle""" self.phase_edit.setText(str(self._default_phase)) self.phase_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_ncolors(self): """action when user clicks 'Default' for number of colors""" self.ncolors_edit.setText(str(self._default_ncolors)) self.ncolors_edit.setStyleSheet("QLineEdit{background: white;}") #def on_default_colormap(self): #"""action when user clicks 'Default' for the color map""" #self.colormap_edit.setCurrentIndex(colormap_keys.index(self._default_colormap)) def on_default_nlabels(self): """action when user clicks 'Default' for number of labels""" self.nlabels_edit.setStyleSheet("QLineEdit{background: white;}") self.nlabels_edit.setText(str(self._default_nlabels)) def on_default_labelsize(self): """action when user clicks 'Default' for number of labelsize""" self.labelsize_edit.setText(str(self._default_labelsize)) self.labelsize_edit.setStyleSheet("QLineEdit{background: white;}") def on_show_hide(self): """action when user clicks the 'Show/Hide' radio button""" self.colormap_edit.setCurrentIndex( colormap_keys.index(self._default_colormap)) is_shown = self.show_radio.isChecked() self.vertical_radio.setEnabled(is_shown) self.horizontal_radio.setEnabled(is_shown) @staticmethod def check_name(cell): cell_value = cell.text() try: text = str(cell_value).strip() except UnicodeEncodeError: cell.setStyleSheet("QLineEdit{background: red;}") return None, False if len(text): cell.setStyleSheet("QLineEdit{background: white;}") return text, True else: cell.setStyleSheet("QLineEdit{background: red;}") return None, False #@staticmethod #def check_colormap(cell): #text = str(cell.text()).strip() #if text in colormap_keys: #cell.setStyleSheet("QLineEdit{background: white;}") #return text, True #else: #cell.setStyleSheet("QLineEdit{background: red;}") #return None, False def on_validate(self): name_value, flag0 = self.check_name(self.name_edit) min_value, flag1 = self.check_float(self.min_edit) max_value, flag2 = self.check_float(self.max_edit) format_value, flag3 = self.check_format(self.format_edit) scale, flag4 = self.check_float(self.scale_edit) phase, flag5 = self.check_float(self.phase_edit) nlabels, flag6 = self.check_positive_int_or_blank(self.nlabels_edit) ncolors, flag7 = self.check_positive_int_or_blank(self.ncolors_edit) labelsize, flag8 = self.check_positive_int_or_blank( self.labelsize_edit) colormap = str(self.colormap_edit.currentText()) if all([flag0, flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8]): if 'i' in format_value: format_value = '%i' assert isinstance(scale, float), scale self.out_data['name'] = name_value self.out_data['min'] = min_value self.out_data['max'] = max_value self.out_data['format'] = format_value self.out_data['scale'] = scale self.out_data['phase'] = phase self.out_data['nlabels'] = nlabels self.out_data['ncolors'] = ncolors self.out_data['labelsize'] = labelsize self.out_data['colormap'] = colormap self.out_data['is_low_to_high'] = self.low_to_high_radio.isChecked( ) self.out_data['is_horizontal'] = self.horizontal_radio.isChecked() self.out_data['is_shown'] = self.show_radio.isChecked() self.out_data['clicked_ok'] = True self.out_data['close'] = True #print('self.out_data = ', self.out_data) #print("name = %r" % self.name_edit.text()) #print("min = %r" % self.min_edit.text()) #print("max = %r" % self.max_edit.text()) #print("format = %r" % self.format_edit.text()) return True return False def on_apply(self): passed = self.on_validate() if passed: self.win_parent._apply_legend(self.out_data) return passed def on_ok(self): passed = self.on_apply() if passed: self.close() #self.destroy() def on_cancel(self): self.out_data['close'] = True self.close()
class EditNodeProperties(QDialog): def __init__(self, data, win_parent=None): """ +-----------------+ | Edit Node Props | +-----------------+------+ | LEwingTip | | Node2 | | Node3 | | Node4 | | | | All Nodes: | | Color red | | PointSize 3 | | Opacity 0.3 | | Show/Hide | | | | Name LEwingTip | | Location X Y Z | | Coord 0 | | CoordType R, C, S | | | | Previous Next | | | | Close | +------------------------+ """ QDialog.__init__(self, win_parent) self.setWindowTitle('Edit Node Properties') #default self.win_parent = win_parent self.out_data = data point_properties = data['point_properties'] print(point_properties) #name = point_properties.name point_size = point_properties.point_size opacity = point_properties.opacity color = point_properties.color show = point_properties.is_visible self.points = data['points'] self.keys = sorted(self.points.keys()) keys = self.keys #nrows = len(keys) active_point = data['active_point'] #self.active_key = keys[0] self.active_key = active_point name = self.active_key description = self.points[self.active_key][0] self._use_old_table = False items = ['Node %i' % val for val in keys] header_labels = ['Nodes'] table_model = Model(items, header_labels, self) view = SingleChoiceQTableView(self) #Call your custom QTableView here view.setModel(table_model) view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.table = view #self.representation = actor_obj.representation #print('rep =', self.representation) table = self.table #headers = [QtCore.QString('Groups')] header = table.horizontalHeader() header.setStretchLastSection(True) #---------------------------------------------- #self._default_is_apply = False self.color = QLabel("Color:") self.color_edit = QPushButton() #self.color_edit.setFlat(True) color = self.out_data['point_properties'].color opacity = self.out_data['point_properties'].opacity show = self.out_data['point_properties'].is_visible #color = self.out_data[self.active_key].color qcolor = QColor() qcolor.setRgb(*color) #print('color =%s' % str(color)) palette = QPalette( self.color_edit.palette()) # make a copy of the palette #palette.setColor(QPalette.Active, QPalette.Base, \ #qcolor) palette.setColor(QPalette.Background, QColor('blue')) # ButtonText self.color_edit.setPalette(palette) self.color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(color) + #"border:1px solid rgb(255, 170, 255); " "}") self.all_nodes_header = QLabel("All Nodes:") self.point_size = QLabel("Point Size:") self.point_size_edit = QSpinBox(self) self.point_size_edit.setRange(1, 10) self.point_size_edit.setSingleStep(1) self.point_size_edit.setValue(point_size) self.opacity = QLabel("Opacity:") self.opacity_edit = QDoubleSpinBox(self) self.opacity_edit.setRange(0.1, 1.0) self.opacity_edit.setDecimals(1) self.opacity_edit.setSingleStep(0.1) self.opacity_edit.setValue(opacity) # show/hide self.checkbox_show = QCheckBox("Show") self.checkbox_hide = QCheckBox("Hide") self.checkbox_show.setChecked(show) self.checkbox_hide.setChecked(not show) #---------------------------------------------- self.nodes_header = QLabel("Single Node:") self.name = QLabel("ID:") self.name_edit = QLineEdit('Node %i' % name) self.name_edit.setDisabled(True) self.description = QLabel("Description:") self.description_edit = QLineEdit(str(description)) #self.description_edit.setDisabled(True) location_x = 0.1 location_y = 0.1 location_z = 0.1 self.location = QLabel("Location:") self.location_x_edit = QDoubleSpinBox(self) self.location_y_edit = QDoubleSpinBox(self) self.location_z_edit = QDoubleSpinBox(self) #self.location_x_edit.setDecimals(1) delta_x = abs(location_x) / 100. if location_x != 0.0 else 0.1 delta_y = abs(location_y) / 100. if location_y != 0.0 else 0.1 delta_z = abs(location_z) / 100. if location_z != 0.0 else 0.1 self.location_x_edit.setSingleStep(delta_x) self.location_y_edit.setSingleStep(delta_y) self.location_z_edit.setSingleStep(delta_z) self.location_x_edit.setValue(location_x) self.location_y_edit.setValue(location_y) self.location_z_edit.setValue(location_z) self.coord = QLabel("Coord:") self.coord_edit = QSpinBox(self) self.coord_edit.setRange(0, 99999999) #self.coord_edit.setSingleStep(1) self.coord_edit.setValue(0) self.coord_type = QLabel("Coord Type:") #---------------------------------------------- # closing #if self._default_is_apply: #self.apply_button.setDisabled(True) self.close_button = QPushButton("Close") self.create_layout() self.set_connections() def update_active_key(self, index): name = self.active_key old_obj = self.out_data['points'][name] #self.active_key #self.points[self.active_key] old_obj[0] = str(self.description_edit.text()) #old_obj.coord = self.description_edit.value() #old_obj.description = self.description_edit.value() #old_obj.description = self.description_edit.value() str_name = str(index.data().toString()) name = int(str_name[5:]) #i = self.keys.index(self.active_key) self.active_key = name point = self.points[self.active_key] #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], self.name_edit.setText(str(self.active_key)) self.description_edit.setText(point[0]) self.coord_edit.setValue(point[1]) if point[2] == 'R': self.radio_rectangular.setChecked(True) elif point[2] == 'C': self.radio_cylindrical.setChecked(True) elif point[2] == 'S': self.radio_spherical.setChecked(True) self.location_x_edit.setValue(point[3]) self.location_y_edit.setValue(point[4]) self.location_z_edit.setValue(point[5]) #obj = self.out_data[name] #point_size = obj.point_size #opacity = obj.opacity #representation = obj.representation #is_visible = obj.is_visible #self.opacity_edit.setValue(opacity) #self.checkbox_show.setChecked(is_visible) #self.checkbox_hide.setChecked(not is_visible) #def on_name_select(self): #print('on_name_select') #return def create_layout(self): cancel_box = QHBoxLayout() cancel_box.addWidget(self.close_button) grid1 = QGridLayout() grid2 = QGridLayout() #----------------------------------------- # setup self.radio_rectangular = QRadioButton('Rectangular') self.radio_cylindrical = QRadioButton('Cylindrical') self.radio_spherical = QRadioButton('Spherical') coord_type_layout = QHBoxLayout() coord_type_layout.addWidget(self.radio_rectangular) coord_type_layout.addWidget(self.radio_cylindrical) coord_type_layout.addWidget(self.radio_spherical) location_layout = QHBoxLayout() location_layout.addWidget(self.location_x_edit) location_layout.addWidget(self.location_y_edit) location_layout.addWidget(self.location_z_edit) checkboxs = QButtonGroup(self) checkboxs.addButton(self.checkbox_show) checkboxs.addButton(self.checkbox_hide) vbox1 = QVBoxLayout() vbox1.addWidget(self.checkbox_show) vbox1.addWidget(self.checkbox_hide) #vbox1.addLayout(checkboxs) #----------------------------------------- irow = 0 grid1.addWidget(self.all_nodes_header, irow, 0) irow += 1 grid1.addWidget(self.color, irow, 0) grid1.addWidget(self.color_edit, irow, 1) irow += 1 grid1.addWidget(self.opacity, irow, 0) grid1.addWidget(self.opacity_edit, irow, 1) irow += 1 grid1.addWidget(self.point_size, irow, 0) grid1.addWidget(self.point_size_edit, irow, 1) irow += 1 #----------------------------------------- irow = 0 grid2.addWidget(self.nodes_header, irow, 0) irow += 1 grid2.addWidget(self.name, irow, 0) grid2.addWidget(self.name_edit, irow, 1) irow += 1 grid2.addWidget(self.description, irow, 0) grid2.addWidget(self.description_edit, irow, 1) irow += 1 #| All Nodes: | #| Color red | #| PointSize 3 | #| Opacity 0.3 | #| Show/Hide | #| | #| Name LEwingTip | #| Location X Y Z | #| Coord 0 | #| CoordType R, C, S | #| | #| Previous Next | grid2.addWidget(self.coord, irow, 0) grid2.addWidget(self.coord_edit, irow, 1) irow += 1 grid2.addWidget(self.coord_type, irow, 0) grid2.addLayout(coord_type_layout, irow, 1) irow += 1 grid2.addWidget(self.location, irow, 0) grid2.addLayout(location_layout, irow, 1) irow += 1 #------------------------------------ vbox = QVBoxLayout() vbox.addLayout(grid1) vbox.addLayout(vbox1) vbox.addStretch() vbox.addWidget(self.table) vbox.addLayout(grid2) vbox.addStretch() #vbox.addWidget(self.check_apply) vbox.addLayout(cancel_box) self.setLayout(vbox) def set_connections(self): """creates the actions for the menu""" self.opacity_edit.valueChanged.connect(self.on_opacity) #self.connect(self.point_size, QtCore.SIGNAL('clicked()'), self.on_point_size) #self.point_size_edit.clicked.connect(self.on_point_size) # need to update name?? self.color_edit.clicked.connect(self.on_color) self.checkbox_show.clicked.connect(self.on_show) self.checkbox_hide.clicked.connect(self.on_hide) self.description_edit.textEdited.connect( self.on_description) # valueChanged???? self.coord_edit.valueChanged.connect(self.on_coord) self.radio_rectangular.clicked.connect(self.on_coord_type) self.radio_cylindrical.clicked.connect(self.on_coord_type) self.radio_spherical.clicked.connect(self.on_coord_type) self.location_x_edit.valueChanged.connect(self.on_location_x) self.location_y_edit.valueChanged.connect(self.on_location_y) self.location_z_edit.valueChanged.connect(self.on_location_z) #self.connect(self.check_apply, QtCore.SIGNAL('clicked()'), self.on_check_apply) #self.connect(self.apply_button, QtCore.SIGNAL('clicked()'), self.on_apply) #self.connect(self.ok_button, QtCore.SIGNAL('clicked()'), self.on_ok) self.close_button.clicked.connect(self.on_close) def on_color(self): obj = self.out_data['point_properties'] rgb_color_ints = obj.color msg = 'Points' col = QColorDialog.getColor(QColor(*rgb_color_ints), self, "Choose a %s color" % msg) if col.isValid(): color = col.getRgbF()[:3] obj.color = color #print('new_color =', color) self.color_edit.setStyleSheet( "QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(obj.color) + #"border:1px solid rgb(255, 170, 255); " "}") def on_show(self): is_checked = self.checkbox_show.isChecked() self.out_data['point_properties'].is_visible = is_checked def on_hide(self): is_checked = self.checkbox_hide.isChecked() self.out_data['point_properties'].is_visible = not is_checked def on_point_size(self): point_size = self.point_size_edit.value() self.out_data['point_properties'].point_size = point_size def on_opacity(self): opacity = self.opacity_edit.value() self.out_data['point_properties'].opacity = opacity def on_description(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key description = self.description_edit.value() self.out_data['points'][name][0] = description def on_coord(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key coord_id = self.coord_edit.value() self.out_data['points'][name][1] = coord_id def on_coord_type(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key if self.radio_rectangular.isChecked(): coord_type = 'R' elif self.radio_cylindrical.isChecked(): coord_type = 'C' elif self.radio_spherical.isChecked(): coord_type = 'S' else: raise NotImplementedError() self.out_data['points'][name][2] = coord_type def on_location_x(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][3] = value def on_location_y(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][4] = value def on_location_z(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][5] = value def closeEvent(self, event): event.accept() #def on_default_name(self): #self.name_edit.setText(str(self._default_name)) #self.name_edit.setStyleSheet("QLineEdit{background: white;}") #def check_name(self, cell): #text = str(cell.text()).strip() #if len(text): #cell.setStyleSheet("QLineEdit{background: white;}") #return text, True #else: #cell.setStyleSheet("QLineEdit{background: red;}") #return None, False def on_validate(self): self.out_data['clicked_ok'] = True self.out_data['clicked_cancel'] = False old_obj = self.out_data[self.active_key] old_obj.point_size = self.point_size_edit.value() old_obj.opacity = self.opacity_edit.value() old_obj.is_visible = self.checkbox_show.isChecked() return True #name_value, flag0 = self.check_name(self.name_edit) #ox_value, flag1 = check_float(self.transparency_edit) #if flag0 and flag1: #self.out_data['clicked_ok'] = True #return True #return False def on_apply(self): passed = self.on_validate() if passed: self.win_parent.on_update_gui_nodes(self.out_data) return passed def on_ok(self): passed = self.on_apply() if passed: self.close() #self.destroy() def on_close(self): self.out_data['clicked_close'] = True self.close()
def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events._ndisplay.connect(self._on_ndisplay_change) self.layer.events.rendering.connect(self._on_rendering_change) self.layer.events.selected_label.connect( self._on_selected_label_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contiguous_change) self.layer.events.n_edit_dimensions.connect( self._on_n_edit_dimensions_change) self.layer.events.contour.connect(self._on_contour_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.events.preserve_labels.connect( self._on_preserve_labels_change) self.layer.events.color_mode.connect(self._on_color_mode_change) # selection spinbox self.selectionSpinBox = QLargeIntSpinBox() dtype_lims = get_dtype_limits(get_dtype(layer)) self.selectionSpinBox.setRange(*dtype_lims) self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self.selectionSpinBox.setAlignment(Qt.AlignCenter) self._on_selected_label_change() self.maskSelectionCheckBox = QCheckBox() self.maskSelectionCheckBox.setCheckState(Qt.CheckState.Unchecked) self.maskSelectionCheckBox.stateChanged.connect(self.maskSelection) sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged.connect(self.changeSize) self.brushSizeSlider = sld self._on_brush_size_change() contig_cb = QCheckBox() contig_cb.setToolTip(trans._('contiguous editing')) contig_cb.stateChanged.connect(self.change_contig) self.contigCheckBox = contig_cb self._on_contiguous_change() ndim_sb = QSpinBox() self.ndimSpinBox = ndim_sb ndim_sb.setToolTip(trans._('number of dimensions for label editing')) ndim_sb.valueChanged.connect(self.change_n_edit_dim) ndim_sb.setMinimum(2) ndim_sb.setMaximum(self.layer.ndim) ndim_sb.setSingleStep(1) ndim_sb.setAlignment(Qt.AlignCenter) self._on_n_edit_dimensions_change() self.contourSpinBox = QLargeIntSpinBox() self.contourSpinBox.setRange(*dtype_lims) self.contourSpinBox.setToolTip(trans._('display contours of labels')) self.contourSpinBox.valueChanged.connect(self.change_contour) self.contourSpinBox.setKeyboardTracking(False) self.contourSpinBox.setAlignment(Qt.AlignCenter) self._on_contour_change() preserve_labels_cb = QCheckBox() preserve_labels_cb.setToolTip( trans._('preserve existing labels while painting')) preserve_labels_cb.stateChanged.connect(self.change_preserve_labels) self.preserveLabelsCheckBox = preserve_labels_cb self._on_preserve_labels_change() selectedColorCheckbox = QCheckBox() selectedColorCheckbox.setToolTip( trans._("Display only selected label")) selectedColorCheckbox.stateChanged.connect(self.toggle_selected_mode) self.selectedColorCheckbox = selectedColorCheckbox # shuffle colormap button self.colormapUpdate = QtModePushButton( None, 'shuffle', slot=self.changeColor, tooltip=trans._('shuffle colors'), ) self.panzoom_button = QtModeRadioButton( layer, 'zoom', Mode.PAN_ZOOM, checked=True, ) action_manager.bind_button('napari:activate_label_pan_zoom_mode', self.panzoom_button) self.pick_button = QtModeRadioButton(layer, 'picker', Mode.PICK) action_manager.bind_button('napari:activate_label_picker_mode', self.pick_button) self.paint_button = QtModeRadioButton(layer, 'paint', Mode.PAINT) action_manager.bind_button('napari:activate_paint_mode', self.paint_button) self.fill_button = QtModeRadioButton( layer, 'fill', Mode.FILL, ) action_manager.bind_button( 'napari:activate_fill_mode', self.fill_button, extra_tooltip_text=trans._( "Toggle with {shortcut}", shortcut=Shortcut("Control"), ), ) self.erase_button = QtModeRadioButton( layer, 'erase', Mode.ERASE, ) action_manager.bind_button( 'napari:activate_label_erase_mode', self.erase_button, extra_tooltip_text=trans._( "Toggle with {shortcut}", shortcut=Shortcut("Alt"), ), ) # don't bind with action manager as this would remove "Toggle with {shortcut}" self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.button_group.addButton(self.erase_button) self._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.colormapUpdate) button_row.addWidget(self.erase_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.pick_button) button_row.addWidget(self.panzoom_button) button_row.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) renderComboBox = QComboBox(self) rendering_options = [i.value for i in LabelsRendering] renderComboBox.addItems(rendering_options) index = renderComboBox.findText(self.layer.rendering, Qt.MatchFixedString) renderComboBox.setCurrentIndex(index) renderComboBox.activated[str].connect(self.changeRendering) self.renderComboBox = renderComboBox self.renderLabel = QLabel(trans._('rendering:')) self._on_ndisplay_change() color_mode_comboBox = QComboBox(self) for index, (data, text) in enumerate(LABEL_COLOR_MODE_TRANSLATIONS.items()): data = data.value color_mode_comboBox.addItem(text, data) if self.layer.color_mode == data: color_mode_comboBox.setCurrentIndex(index) color_mode_comboBox.activated.connect(self.change_color_mode) self.colorModeComboBox = color_mode_comboBox self._on_color_mode_change() color_layout = QHBoxLayout() self.colorBox = QtColorBox(layer) color_layout.addWidget(self.colorBox) color_layout.addWidget(self.selectionSpinBox) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 0, 1, 4) self.grid_layout.addWidget(QLabel(trans._('label:')), 1, 0, 1, 1) self.grid_layout.addWidget(self.maskSelectionCheckBox, 1, 1, 1, 1) self.grid_layout.addLayout(color_layout, 1, 2, 1, 2) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 2, 0, 1, 1) self.grid_layout.addWidget(self.opacitySlider, 2, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('brush size:')), 3, 0, 1, 1) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('blending:')), 5, 0, 1, 1) self.grid_layout.addWidget(self.blendComboBox, 5, 1, 1, 3) self.grid_layout.addWidget(self.renderLabel, 6, 0, 1, 1) self.grid_layout.addWidget(self.renderComboBox, 6, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('color mode:')), 7, 0, 1, 1) self.grid_layout.addWidget(self.colorModeComboBox, 7, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('contour:')), 8, 0, 1, 1) self.grid_layout.addWidget(self.contourSpinBox, 8, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('n edit dim:')), 9, 0, 1, 1) self.grid_layout.addWidget(self.ndimSpinBox, 9, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('contiguous:')), 10, 0, 1, 1) self.grid_layout.addWidget(self.contigCheckBox, 10, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('preserve\nlabels:')), 11, 0, 1, 2) self.grid_layout.addWidget(self.preserveLabelsCheckBox, 11, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('show\nselected:')), 11, 2, 1, 1) self.grid_layout.addWidget(self.selectedColorCheckbox, 11, 3, 1, 1) self.grid_layout.setRowStretch(12, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
class BreakSurfaceMenu(QDialog): def __init__(self, data, win_parent=None): """ +-----------------+ | Break Surfaces | +-----------------+------+ | EngineInlet | | EngineOutlet | | | | Name EngineInlet | | RegionMode * RegionID | | * All | | | | AllowedRegions: | | Region ID 3 | | | | PickMode * All | | Pick Mode x On/Off | | Pick Angle 20 deg | | | | Revert | | RenumberRegions | | Close | +------------------------+ """ QDialog.__init__(self, win_parent) self.setWindowTitle('Break Surface') #default self.win_parent = win_parent self.out_data = data self.points = data['points'] self.keys = sorted(self.points.keys()) keys = self.keys nrows = len(keys) active_point = data['active_point'] #self.active_key = keys[0] self.active_key = active_point name = self.active_key description = self.points[self.active_key][0] self._use_old_table = False items = ['Node %i' % val for val in keys] header_labels = ['Nodes'] table_model = Model(items, header_labels, self) view = SingleChoiceQTableView(self) #Call your custom QTableView here view.setModel(table_model) header = view.horizontalHeader() header.setSectionResizeMode(0, QHeaderView.Stretch) #header.setResizeMode(QtGui.QHeaderView.Stretch) self.table = view #self.representation = actor_obj.representation #print('rep =', self.representation) table = self.table #headers = [QtCore.QString('Groups')] header = table.horizontalHeader() header.setStretchLastSection(True) #---------------------------------------------- #self._default_is_apply = False self.mode_header = QLabel("Mode:") nregions_max = 10 pick_angle = 20.0 region_id = 4 all_regions = True self.region_id = QLabel("Region ID:") self.region_id_edit = QSpinBox(self) self.region_id_edit.setRange(1, nregions_max) self.region_id_edit.setSingleStep(1) self.region_id_edit.setValue(region_id) self.pick_angle = QLabel("Pick Angle:") self.pick_angle_edit = QDoubleSpinBox(self) self.pick_angle_edit.setRange(0.0, 360.0) self.pick_angle_edit.setDecimals(3) self.pick_angle_edit.setSingleStep(0.5) self.pick_angle_edit.setValue(pick_angle) # region IDs/all self.checkbox_region_ids = QCheckBox("Region IDs") self.checkbox_region_all = QCheckBox("All Regions") self.checkbox_region_all.setChecked(all_regions) self.checkbox_region_ids.setChecked(not all_regions) # pick mode self.checkbox_pick_mode = QCheckBox("Pick Mode (Off=label)") self.checkbox_pick_mode.setChecked(False) #---------------------------------------------- self.nodes_header = QLabel("Single Node:") self.name = QLabel("ID:") self.name_edit = QLineEdit('Node %i' % name) self.name_edit.setDisabled(True) #---------------------------------------------- self.location_x = QLabel("X:") self.location_x_edit = QLineEdit('X') self.location_y = QLabel("Y:") self.location_y_edit = QLineEdit('Y') self.location_z = QLabel("Z:") self.location_z_edit = QLineEdit('Z') #---------------------------------------------- # remove these... self.description_edit = QLineEdit('Description') self.coord_edit = QSpinBox() #---------------------------------------------- # closing #if self._default_is_apply: #self.apply_button.setDisabled(True) self.close_button = QPushButton("Close") self.create_layout() #self.set_connections() def update_active_key(self, index): name = self.active_key old_obj = self.out_data['points'][name] #self.active_key #self.points[self.active_key] old_obj[0] = str(self.description_edit.text()) #old_obj.coord = self.description_edit.value() #old_obj.description = self.description_edit.value() #old_obj.description = self.description_edit.value() str_name = str(index.data()) name = int(str_name[5:]) #i = self.keys.index(self.active_key) self.active_key = name point = self.points[self.active_key] #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], self.name_edit.setText(str(self.active_key)) self.description_edit.setText(point[0]) self.coord_edit.setValue(point[1]) if point[2] == 'R': self.radio_rectangular.setChecked(True) elif point[2] == 'C': self.radio_cylindrical.setChecked(True) elif point[2] == 'S': self.radio_spherical.setChecked(True) self.location_x_edit.setText(str(point[3])) self.location_y_edit.setText(str(point[4])) self.location_z_edit.setText(str(point[5])) #obj = self.out_data[name] #point_size = obj.point_size #opacity = obj.opacity #representation = obj.representation #is_visible = obj.is_visible #self.opacity_edit.setValue(opacity) #self.checkbox_show.setChecked(is_visible) #self.checkbox_hide.setChecked(not is_visible) #def on_name_select(self): #print('on_name_select') #return def create_layout(self): cancel_box = QHBoxLayout() cancel_box.addWidget(self.close_button) grid1 = QGridLayout() grid2 = QGridLayout() #----------------------------------------- # setup self.radio_rectangular = QRadioButton('Rectangular') self.radio_cylindrical = QRadioButton('Cylindrical') self.radio_spherical = QRadioButton('Spherical') coord_type_layout = QHBoxLayout() coord_type_layout.addWidget(self.radio_rectangular) coord_type_layout.addWidget(self.radio_cylindrical) coord_type_layout.addWidget(self.radio_spherical) checkboxs = QButtonGroup(self) checkboxs.addButton(self.checkbox_region_all) checkboxs.addButton(self.checkbox_region_ids) vbox1 = QVBoxLayout() vbox1.addWidget(self.checkbox_region_all) vbox1.addWidget(self.checkbox_region_ids) #vbox1.addLayout(checkboxs) #----------------------------------------- irow = 0 grid2.addWidget(self.name, irow, 0) grid2.addWidget(self.name_edit, irow, 1) irow += 1 #grid2.addWidget(self.name, irow, 0) grid2.addWidget(self.description_edit, irow, 1) irow += 1 grid2.addWidget(self.location_x, irow, 0) grid2.addWidget(self.location_x_edit, irow, 1) irow += 1 grid2.addWidget(self.location_y, irow, 0) grid2.addWidget(self.location_y_edit, irow, 1) irow += 1 grid2.addWidget(self.location_z, irow, 0) grid2.addWidget(self.location_z_edit, irow, 1) irow += 1 #| Name EngineInlet | #| RegionMode * RegionID | #| * All | #| | #| AllowedRegions: | #| Region ID 3 | #| | #| PickMode * All | #| Pick Mode x On/Off | #| Pick Angle 20 deg | #| | #| Revert | #| RenumberRegions | #| Close | grid2.addWidget(self.region_id, irow, 0) grid2.addWidget(self.region_id_edit, irow, 1) irow += 1 #grid2.addWidget(self.pick_mode, irow, 0) grid2.addWidget(self.checkbox_pick_mode, irow, 0) irow += 1 grid2.addWidget(self.pick_angle, irow, 0) grid2.addWidget(self.pick_angle_edit, irow, 1) irow += 1 #grid2.addWidget(self.pi, irow, 0) #grid2.addLayout(coord_type_layout, irow, 1) #irow += 1 #grid2.addWidget(self.location, irow, 0) #grid2.addLayout(location_layout, irow, 1) #irow += 1 #------------------------------------ vbox = QVBoxLayout() vbox.addLayout(grid1) #vbox.addLayout(vbox1) #vbox.addStretch() vbox.addWidget(self.table) vbox.addLayout(grid2) vbox.addStretch() #vbox.addWidget(self.check_apply) vbox.addLayout(cancel_box) self.setLayout(vbox) def set_connections(self): self.opacity_edit.clicked.connect(self.on_opacity) self.point_size.clicked.connect(self.on_point_size) self.color_edit.clicked.connect(self.on_color) self.checkbox_show.clicked.connect(self.on_show) self.checkbox_hide.clicked.connect(self.on_hide) #self.connect(self.description_edit, QtCore.SIGNAL("valueChanged(int)"), self.on_description) #self.connect(self.coord_edit, QtCore.SIGNAL("valueChanged(int)"), self.on_coord) self.radio_rectangular.clicked.connect(self.on_coord_type) self.radio_cylindrical.clicked.connect(self.on_coord_type) self.radio_spherical.clicked.connect(self.on_coord_type) self.location_x_edit.clicked.connect(self.on_location_x) self.location_y_edit.clicked.connect(self.on_location_y) self.location_z_edit.clicked.connect(self.on_location_z) self.close_button.clicked.connect(self.on_close) #self.connect(self.check_apply, QtCore.SIGNAL('clicked()'), self.on_check_apply) #self.connect(self.apply_button, QtCore.SIGNAL('clicked()'), self.on_apply) #self.connect(self.ok_button, QtCore.SIGNAL('clicked()'), self.on_ok) self.close_button.clicked.connect(self.on_close) def on_color(self): obj = self.out_data['point_properties'] rgb_color_ints = obj.color msg = 'Points' col = QColorDialog.getColor(QtGui.QColor(*rgb_color_ints), self, "Choose a %s color" % msg) if col.isValid(): color = col.getRgbF()[:3] obj.color = color #print('new_color =', color) self.color_edit.setStyleSheet( "QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(obj.color) + #"border:1px solid rgb(255, 170, 255); " "}") def on_show(self): is_checked = self.checkbox_show.isChecked() self.out_data['point_properties'].is_visible = is_checked def on_hide(self): is_checked = self.checkbox_hide.isChecked() self.out_data['point_properties'].is_visible = not is_checked def on_point_size(self): point_size = self.point_size_edit.value() self.out_data['point_properties'].point_size = point_size def on_opacity(self): opacity = self.opacity_edit.value() self.out_data['point_properties'].opacity = opacity def on_description(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key description = self.description_edit.value() self.out_data['points'][name][0] = description def on_coord(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key coord_id = self.coord_edit.value() self.out_data['points'][name][1] = coord_id def on_coord_type(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key if self.radio_rectangular.isChecked(): coord_type = 'R' elif self.radio_cylindrical.isChecked(): coord_type = 'C' elif self.radio_spherical.isChecked(): coord_type = 'S' else: raise NotImplementedError() self.out_data['points'][name][2] = coord_type def on_location_x(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][3] = value def on_location_y(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][4] = value def on_location_z(self): #1 : ['LERoot', 0, 'R', 1.0, 2.0, 3.0], name = self.active_key value = self.coord_edit.value() self.out_data['points'][name][5] = value def closeEvent(self, event): event.accept() #def on_default_name(self): #self.name_edit.setText(str(self._default_name)) #self.name_edit.setStyleSheet("QLineEdit{background: white;}") #def check_float(self, cell): #text = cell.text() #try: #value = eval_float_from_string(text) #cell.setStyleSheet("QLineEdit{background: white;}") #return value, True #except ValueError: #cell.setStyleSheet("QLineEdit{background: red;}") #return None, False #def check_name(self, cell): #text = str(cell.text()).strip() #if len(text): #cell.setStyleSheet("QLineEdit{background: white;}") #return text, True #else: #cell.setStyleSheet("QLineEdit{background: red;}") #return None, False def on_validate(self): self.out_data['clicked_ok'] = True self.out_data['clicked_cancel'] = False old_obj = self.out_data[self.active_key] old_obj.point_size = self.point_size_edit.value() old_obj.opacity = self.opacity_edit.value() old_obj.is_visible = self.checkbox_show.isChecked() return True #name_value, flag0 = self.check_name(self.name_edit) #ox_value, flag1 = self.check_float(self.transparency_edit) #if flag0 and flag1: #self.out_data['clicked_ok'] = True #return True #return False def on_apply(self): passed = self.on_validate() if passed: self.win_parent.on_update_gui_nodes(self.out_data) return passed def on_ok(self): passed = self.on_apply() if passed: self.close() #self.destroy() def on_close(self): self.out_data['clicked_close'] = True self.close()
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_edit_dimensions.connect( self._on_n_edit_dimensions_change) self.layer.events.contour.connect(self._on_contour_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.events.preserve_labels.connect( self._on_preserve_labels_change) self.layer.events.color_mode.connect(self._on_color_mode_change) # selection spinbox self.selectionSpinBox = QtLargeIntSpinBox(self.layer.data.dtype) self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.setMinimum(0) 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_sb = QSpinBox() self.ndimSpinBox = ndim_sb ndim_sb.setToolTip(trans._('number of dimensions for label editing')) ndim_sb.valueChanged.connect(self.change_n_edit_dim) ndim_sb.setMinimum(2) ndim_sb.setMaximum(self.layer.ndim) ndim_sb.setSingleStep(1) ndim_sb.setAlignment(Qt.AlignCenter) self._on_n_edit_dimensions_change() contour_sb = QtLargeIntSpinBox(self.layer.data.dtype) 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.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 {shortcut}", shortcut=Shortcut("Control"), ), ) self.erase_button = QtModeRadioButton( layer, 'erase', Mode.ERASE, tooltip=trans._( "Erase mode (E) \nToggle with {shortcut}", shortcut=Shortcut("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) 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._('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._('n edit dim:')), 8, 0, 1, 1) self.grid_layout.addWidget(self.ndimSpinBox, 8, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('contiguous:')), 9, 0, 1, 1) self.grid_layout.addWidget(self.contigCheckBox, 9, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('preserve labels:')), 10, 0, 1, 2) self.grid_layout.addWidget(self.preserveLabelsCheckBox, 10, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('show selected:')), 10, 2, 1, 1) self.grid_layout.addWidget(self.selectedColorCheckbox, 10, 3, 1, 1) self.grid_layout.setRowStretch(10, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4)
class QtVectorsLayer(QtLayer): def __init__(self, layer): super().__init__(layer) self.layer.events.averaging.connect(self._on_avg_change) self.layer.events.width.connect(self._on_width_change) self.layer.events.length.connect(self._on_len_change) # vector color adjustment and widget face_comboBox = QComboBox() colors = self.layer._colors for c in colors: face_comboBox.addItem(c) index = face_comboBox.findText(self.layer.color, Qt.MatchFixedString) if index >= 0: face_comboBox.setCurrentIndex(index) face_comboBox.activated[str].connect( lambda text=face_comboBox: self.change_face_color(text)) self.grid_layout.addWidget(QLabel('color:'), 3, 0) self.grid_layout.addWidget(face_comboBox, 3, 1) # line width in pixels self.width_field = QDoubleSpinBox() self.width_field.setSingleStep(0.1) self.width_field.setMinimum(0.1) value = self.layer.width self.width_field.setValue(value) self.width_field.valueChanged.connect(self.change_width) self.grid_layout.addWidget(QLabel('width:'), 4, 0) self.grid_layout.addWidget(self.width_field, 4, 1) # averaging spinbox self.averaging_spinbox = QSpinBox() self.averaging_spinbox.setSingleStep(1) self.averaging_spinbox.setValue(1) self.averaging_spinbox.setMinimum(1) self.averaging_spinbox.valueChanged.connect(self.change_average_type) self.grid_layout.addWidget(QLabel('avg kernel'), 5, 0) self.grid_layout.addWidget(self.averaging_spinbox, 5, 1) # line length self.length_field = QDoubleSpinBox() self.length_field.setSingleStep(0.1) value = self.layer.length self.length_field.setValue(value) self.length_field.setMinimum(0.1) self.length_field.valueChanged.connect(self.change_length) self.grid_layout.addWidget(QLabel('length:'), 6, 0) self.grid_layout.addWidget(self.length_field, 6, 1) self.setExpanded(False) def change_face_color(self, text): self.layer.color = text def change_connector_type(self, text): self.layer.connector = text def change_average_type(self, value): self.layer.averaging = value def change_width(self, value): self.layer.width = value def change_length(self, value): self.layer.length = value def _on_avg_change(self, event): with self.layer.events.averaging.blocker(): self.averaging_spinbox.setValue(self.layer.averaging) def _on_len_change(self, event): with self.layer.events.length.blocker(): self.length_field.setValue(self.layer.length) def _on_width_change(self, event): with self.layer.events.width.blocker(): self.width_field.setValue(self.layer.width)
class Settings(QDialog): roiClicked = Signal(int, int) def __init__(self, parent=None): super(Settings, self).__init__(parent) # Create a form with some controls self.selector = QComboBox() self.selector.setEditable(True) self.cameraCols = QSpinBox() self.cameraCols.setMinimum(1) self.cameraCols.setMaximum(6) self.cameraCols.setValue(1) self.cameraRows = QSpinBox() self.cameraRows.setMinimum(1) self.cameraRows.setMaximum(6) self.cameraRows.setValue(1) self.scale = QSpinBox() self.scale.setRange(0, 5000) self.scale.setSingleStep(10) self.scale.setValue(0) self.fps = QSpinBox() self.fps.setRange(1, 30) self.fps.setValue(5) self.xDivs = QSpinBox() self.xDivs.setRange(1, 50) self.xDivs.setValue(5) self.yDivs = QSpinBox() self.yDivs.setRange(1, 50) self.yDivs.setValue(5) self.color = QCheckBox() self.container = None self.microscope = None self.url = QLineEdit('http://localhost:9998/jpg/image.jpg') self.okButton = QPushButton('OK') self.applyButton = QPushButton('Apply') self.cancelButton = QPushButton('Cancel') # Lay it out formLayout = QFormLayout() formLayout.addRow('Camera:', self.selector) rowsCols = QHBoxLayout() rowsCols.addWidget(self.cameraCols) rowsCols.addWidget(self.cameraRows) formLayout.addRow('Cameras:', rowsCols) formLayout.addRow('Camera URL:', self.url) formLayout.addRow('Image Scale:', self.scale) formLayout.addRow('Frame Rate:', self.fps) formLayout.addRow('X Divisions:', self.xDivs) formLayout.addRow('Y Divisions:', self.yDivs) formLayout.addRow('Color boxes:', self.color) # Create layout and add widgets layout = QVBoxLayout() hbox = QHBoxLayout() hbox.addStretch() hbox.addWidget(self.okButton) hbox.addWidget(self.applyButton) hbox.addWidget(self.cancelButton) hbox.addStretch() layout.addLayout(formLayout) layout.addLayout(hbox) self.setLayout(layout) self.okButton.clicked.connect(self.okClicked) self.applyButton.clicked.connect(self.applyClicked) self.cancelButton.clicked.connect(self.cancelClicked) # Connect up some signals and slots... self.selector.currentIndexChanged.connect(self.selectionChanged) self.cameraCols.valueChanged.connect(self.cameraColsChanged) self.cameraRows.valueChanged.connect(self.cameraRowsChanged) def setMicroscope(self, microscope): self.microscope = microscope self.updateForm() def setContainer(self, container): # Store a reference to the container, default to widget 0. self.container = container self.setMicroscope(container.microscope(0)) self.updateCameraSelect() def okClicked(self): self.updateMicroscope() self.accept() def applyClicked(self): self.updateMicroscope() def cancelClicked(self): self.reject() def updateCameraSelect(self): # Iterate over the microscopes and create entries in the select. self.selector.clear() for i in range(self.container.count): print(f'doing element {i}') self.selector.addItem(f'Camera {i + 1}', i) self.cameraCols.setValue(self.container.size[0]) self.cameraRows.setValue(self.container.size[1]) def selectionChanged(self, index): self.updateMicroscope() self.microscope = self.container.microscope(index) self.updateForm() def cameraColsChanged(self, value): if self.container is None: print('Error, no active container.') return self.container.size = [value, self.container.size[1]] self.updateCameraSelect() self.container.update() def cameraRowsChanged(self, value): if self.container is None: print('Error, no active container.') return self.container.size = [self.container.size[0], value] self.updateCameraSelect() self.container.update() def updateMicroscope(self): self.microscope.url = self.url.text() self.microscope.fps = self.fps.value() self.microscope.xDivs = self.xDivs.value() self.microscope.yDivs = self.yDivs.value() self.microscope.color = self.color.isChecked() self.microscope.scale = [self.scale.value(), 0] self.microscope.update() def updateForm(self): self.url.setText(self.microscope.url) self.fps.setValue(self.microscope.fps) self.xDivs.setValue(self.microscope.xDivs) self.yDivs.setValue(self.microscope.yDivs) self.color.setChecked(self.microscope.color) if len(self.microscope.scale) > 0: self.scale.setValue(self.microscope.scale[0])
class ConnectDialog(QDialog): """ A modal dialog window with widgets for modifying connection parameters. Changes + OK will change the parameters in the CbSdkConnection singleton, but will not actually connect. """ def __init__(self, parent=None): super(ConnectDialog, self).__init__(parent) # Get access to the CbSdkConnection instance, but don't connect yet. self.cbsdkConn = CbSdkConnection() # Widgets to show/edit connection parameters. layout = QVBoxLayout(self) # client-addr ip client_addr_layout = QHBoxLayout() client_addr_layout.addWidget(QLabel("client-addr")) self.clientIpEdit = QLineEdit(self.cbsdkConn.con_params['client-addr']) self.clientIpEdit.setInputMask("000.000.000.000;_") client_addr_layout.addWidget(self.clientIpEdit) layout.addLayout(client_addr_layout) # client-port int client_port_layout = QHBoxLayout() client_port_layout.addWidget(QLabel("client-port")) self.clientPortSpin = QSpinBox() self.clientPortSpin.setMinimum(0) self.clientPortSpin.setMaximum(99999) self.clientPortSpin.setSingleStep(1) self.clientPortSpin.setValue(self.cbsdkConn.con_params['client-port']) client_port_layout.addWidget(self.clientPortSpin) layout.addLayout(client_port_layout) # inst-addr ip inst_addr_layout = QHBoxLayout() inst_addr_layout.addWidget(QLabel("inst-addr")) self.instIpEdit = QLineEdit(self.cbsdkConn.con_params['inst-addr']) self.instIpEdit.setInputMask("000.000.000.000;_") inst_addr_layout.addWidget(self.instIpEdit) layout.addLayout(inst_addr_layout) # inst-port int inst_port_layout = QHBoxLayout() inst_port_layout.addWidget(QLabel("inst-port")) self.instPortSpin = QSpinBox() self.instPortSpin.setMinimum(0) self.instPortSpin.setMaximum(99999) self.instPortSpin.setSingleStep(1) self.instPortSpin.setValue(self.cbsdkConn.con_params['inst-port']) inst_port_layout.addWidget(self.instPortSpin) layout.addLayout(inst_port_layout) # receive-buffer-size int rec_buff_layout = QHBoxLayout() rec_buff_layout.addWidget(QLabel("receive-buffer-size")) self.recBuffSpin = QSpinBox() self.recBuffSpin.setMinimum(6 * 1024 * 1024) self.recBuffSpin.setMaximum(8 * 1024 * 1024) self.recBuffSpin.setSingleStep(1024 * 1024) self.recBuffSpin.setValue( self.cbsdkConn.con_params['receive-buffer-size']) rec_buff_layout.addWidget(self.recBuffSpin) layout.addLayout(rec_buff_layout) # OK and Cancel buttons buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) layout.addWidget(buttons) @staticmethod def do_connect_dialog(parent=None): dialog = ConnectDialog(parent) result = dialog.exec_() if result == QDialog.Accepted: dialog.cbsdkConn.disconnect() # Collect values from widgets and set them on dialog.cbsdkConn new_params = { 'client-addr': dialog.clientIpEdit.text(), 'client-port': dialog.clientPortSpin.value(), 'inst-addr': dialog.instIpEdit.text(), 'inst-port': dialog.instPortSpin.value(), 'receive-buffer-size': dialog.recBuffSpin.value() } dialog.cbsdkConn.con_params = new_params return dialog.cbsdkConn.connect() return -1
class AlgorithmOptions(QWidget): def __init__(self, settings: StackSettings, image_view: StackImageView): super().__init__() self.settings = settings self.view_name = image_view.name self.show_result = QEnumComboBox( enum_class=LabelEnum) # QCheckBox("Show result") self._set_show_label_from_settings() self.opacity = QDoubleSpinBox() self.opacity.setRange(0, 1) self.opacity.setSingleStep(0.1) self._set_opacity_from_settings() self.only_borders = QCheckBox("Only borders") self._set_border_mode_from_settings() self.borders_thick = QSpinBox() self.borders_thick.setRange(1, 25) self.borders_thick.setSingleStep(1) self._set_border_thick_from_settings() self.execute_in_background_btn = QPushButton("Execute in background") self.execute_in_background_btn.setToolTip( "Run calculation in background. Put result in multiple files panel" ) self.execute_btn = QPushButton("Execute") self.execute_btn.setStyleSheet("QPushButton{font-weight: bold;}") self.execute_all_btn = QPushButton("Execute all") self.execute_all_btn.setToolTip( "Execute in batch mode segmentation with current parameter. File list need to be specified in image tab." ) self.execute_all_btn.setDisabled(True) self.save_parameters_btn = QPushButton("Save parameters") self.block_execute_all_btn = False self.algorithm_choose_widget = AlgorithmChoose(settings, mask_algorithm_dict) self.algorithm_choose_widget.result.connect(self.execution_result_set) self.algorithm_choose_widget.finished.connect(self.execution_finished) self.algorithm_choose_widget.progress_signal.connect( self.progress_info) # self.stack_layout = QStackedLayout() self.keep_chosen_components_chk = QCheckBox("Save selected components") self.keep_chosen_components_chk.setToolTip( "Save chosen components when loading segmentation form file\n or from multiple file widget." ) self.keep_chosen_components_chk.stateChanged.connect( self.set_keep_chosen_components) self.keep_chosen_components_chk.setChecked( settings.keep_chosen_components) self.show_parameters = QPushButton("Show parameters") self.show_parameters.setToolTip( "Show parameters of segmentation for each components") self.show_parameters_widget = SegmentationInfoDialog( self.settings, self.algorithm_choose_widget.change_algorithm) self.show_parameters.clicked.connect(self.show_parameters_widget.show) self.choose_components = ChosenComponents() self.choose_components.check_change_signal.connect( image_view.refresh_selected) self.choose_components.mouse_leave.connect(image_view.component_unmark) self.choose_components.mouse_enter.connect(image_view.component_mark) # WARNING works only with one channels algorithms # SynchronizeValues.add_synchronization("channels_chose", widgets_list) self.chosen_list = [] self.progress_bar2 = QProgressBar() self.progress_bar2.setHidden(True) self.progress_bar = QProgressBar() self.progress_bar.setHidden(True) self.progress_info_lab = QLabel() self.progress_info_lab.setHidden(True) self.file_list = [] self.batch_process = BatchProceed() self.batch_process.progress_signal.connect(self.progress_info) self.batch_process.error_signal.connect(self.execution_all_error) self.batch_process.execution_done.connect(self.execution_all_done) self.batch_process.range_signal.connect(self.progress_bar.setRange) self.is_batch_process = False self.setContentsMargins(0, 0, 0, 0) main_layout = QVBoxLayout() # main_layout.setSpacing(0) opt_layout = QHBoxLayout() opt_layout.setContentsMargins(0, 0, 0, 0) opt_layout.addWidget(self.show_result) opt_layout.addWidget(right_label("Opacity:")) opt_layout.addWidget(self.opacity) main_layout.addLayout(opt_layout) opt_layout2 = QHBoxLayout() opt_layout2.setContentsMargins(0, 0, 0, 0) opt_layout2.addWidget(self.only_borders) opt_layout2.addWidget(right_label("Border thick:")) opt_layout2.addWidget(self.borders_thick) main_layout.addLayout(opt_layout2) btn_layout = QGridLayout() btn_layout.setContentsMargins(0, 0, 0, 0) btn_layout.addWidget(self.execute_btn, 0, 0) btn_layout.addWidget(self.execute_in_background_btn, 0, 1) btn_layout.addWidget(self.execute_all_btn, 1, 0) btn_layout.addWidget(self.save_parameters_btn, 1, 1) main_layout.addLayout(btn_layout) main_layout.addWidget(self.progress_bar2) main_layout.addWidget(self.progress_bar) main_layout.addWidget(self.progress_info_lab) main_layout.addWidget(self.algorithm_choose_widget, 1) # main_layout.addWidget(self.algorithm_choose) # main_layout.addLayout(self.stack_layout, 1) main_layout.addWidget(self.choose_components) down_layout = QHBoxLayout() down_layout.addWidget(self.keep_chosen_components_chk) down_layout.addWidget(self.show_parameters) main_layout.addLayout(down_layout) main_layout.addStretch() main_layout.setContentsMargins(0, 0, 0, 0) # main_layout.setSpacing(0) self.setLayout(main_layout) # noinspection PyUnresolvedReferences self.execute_in_background_btn.clicked.connect( self.execute_in_background) self.execute_btn.clicked.connect(self.execute_action) self.execute_all_btn.clicked.connect(self.execute_all_action) self.save_parameters_btn.clicked.connect(self.save_parameters) # noinspection PyUnresolvedReferences self.opacity.valueChanged.connect(self._set_opacity) # noinspection PyUnresolvedReferences self.show_result.currentEnumChanged.connect(self._set_show_label) self.only_borders.stateChanged.connect(self._set_border_mode) # noinspection PyUnresolvedReferences self.borders_thick.valueChanged.connect(self._set_border_thick) image_view.component_clicked.connect( self.choose_components.other_component_choose) settings.chosen_components_widget = self.choose_components settings.components_change_list.connect( self.choose_components.new_choose) settings.image_changed.connect( self.choose_components.remove_components) settings.connect_to_profile( f"{self.view_name}.image_state.only_border", self._set_border_mode_from_settings) settings.connect_to_profile( f"{self.view_name}.image_state.border_thick", self._set_border_thick_from_settings) settings.connect_to_profile(f"{self.view_name}.image_state.opacity", self._set_opacity_from_settings) settings.connect_to_profile(f"{self.view_name}.image_state.show_label", self._set_show_label_from_settings) def _set_border_mode(self, value: bool): self.settings.set_in_profile( f"{self.view_name}.image_state.only_border", value) def _set_border_thick(self, value: int): self.settings.set_in_profile( f"{self.view_name}.image_state.border_thick", value) def _set_opacity(self, value: float): self.settings.set_in_profile(f"{self.view_name}.image_state.opacity", value) def _set_show_label(self, value: LabelEnum): self.settings.set_in_profile( f"{self.view_name}.image_state.show_label", value) def _set_border_mode_from_settings(self): self.only_borders.setChecked( self.settings.get_from_profile( f"{self.view_name}.image_state.only_border", True)) def _set_border_thick_from_settings(self): self.borders_thick.setValue( self.settings.get_from_profile( f"{self.view_name}.image_state.border_thick", 1)) def _set_opacity_from_settings(self): self.opacity.setValue( self.settings.get_from_profile( f"{self.view_name}.image_state.opacity", 1.0)) def _set_show_label_from_settings(self): self.show_result.setCurrentEnum( self.settings.get_from_profile( f"{self.view_name}.image_state.show_label", LabelEnum.Show_results)) @Slot(int) def set_keep_chosen_components(self, val): self.settings.set_keep_chosen_components(val) def save_parameters(self): dial = PSaveDialog(io_functions.save_parameters_dict, system_widget=False, settings=self.settings, path=IO_SAVE_DIRECTORY) if not dial.exec_(): return res = dial.get_result() res.save_class.save(res.save_destination, self.algorithm_choose_widget.current_parameters()) def file_list_change(self, val): self.file_list = val if len(self.file_list) > 0 and not self.block_execute_all_btn: self.execute_all_btn.setEnabled(True) else: self.execute_all_btn.setDisabled(True) def get_chosen_components(self): return sorted(self.choose_components.get_chosen()) @property def segmentation(self): return self.settings.roi @segmentation.setter def segmentation(self, val): self.settings.roi = val def _image_changed(self): self.settings.roi = None self.choose_components.set_chose([], []) def _execute_in_background_init(self): if self.batch_process.isRunning(): return self.progress_bar2.setVisible(True) self.progress_bar2.setRange(0, self.batch_process.queue.qsize()) self.progress_bar2.setValue(self.batch_process.index) self.progress_bar.setVisible(True) self.progress_bar.setValue(0) self.execute_btn.setDisabled(True) self.batch_process.start() def execute_in_background(self): # TODO check if components are properly passed widget = self.algorithm_choose_widget.current_widget() segmentation_profile = widget.get_segmentation_profile() task = BatchTask(self.settings.get_project_info(), segmentation_profile, None) self.batch_process.add_task(task) self.progress_bar2.setRange(0, self.progress_bar2.maximum() + 1) self._execute_in_background_init() def execute_all_action(self): dial = PSaveDialog( SaveROI, settings=self.settings, system_widget=False, path="io.save_batch", file_mode=PSaveDialog.Directory, ) if not dial.exec_(): return folder_path = str(dial.selectedFiles()[0]) widget = self.algorithm_choose_widget.current_widget() save_parameters = dial.values segmentation_profile = widget.get_segmentation_profile() for file_path in self.file_list: task = BatchTask(file_path, segmentation_profile, (folder_path, save_parameters)) self.batch_process.add_task(task) self.progress_bar2.setRange( 0, self.progress_bar2.maximum() + len(self.file_list)) self._execute_in_background_init() def execution_all_error(self, text): QMessageBox.warning(self, "Proceed error", text) def execution_all_done(self): if not self.batch_process.queue.empty(): self._execute_in_background_init() return self.execute_btn.setEnabled(True) self.block_execute_all_btn = False if len(self.file_list) > 0: self.execute_all_btn.setEnabled(True) self.progress_bar.setHidden(True) self.progress_bar2.setHidden(True) self.progress_info_lab.setHidden(True) def execute_action(self): self.execute_btn.setDisabled(True) self.execute_all_btn.setDisabled(True) self.block_execute_all_btn = True self.is_batch_process = False self.progress_bar.setRange(0, 0) self.choose_components.setDisabled(True) chosen = sorted(self.choose_components.get_chosen()) blank = get_mask(self.settings.roi, self.settings.mask, chosen) if blank is not None: # Problem with handling time data in algorithms # TODO Fix This blank = blank[0] self.progress_bar.setHidden(False) widget: AlgorithmSettingsWidget = self.algorithm_choose_widget.current_widget( ) widget.set_mask(blank) self.progress_bar.setRange(0, widget.algorithm.get_steps_num()) widget.execute() self.chosen_list = chosen def progress_info(self, text, num, file_name="", file_num=0): self.progress_info_lab.setVisible(True) if file_name != "": self.progress_info_lab.setText(file_name + "\n" + text) else: self.progress_info_lab.setText(text) self.progress_bar.setValue(num) self.progress_bar2.setValue(file_num) def execution_finished(self): self.execute_btn.setEnabled(True) self.block_execute_all_btn = False if len(self.file_list) > 0: self.execute_all_btn.setEnabled(True) self.progress_bar.setHidden(True) self.progress_info_lab.setHidden(True) self.choose_components.setDisabled(False) def execution_result_set(self, result): self.settings.set_segmentation_result(result) def showEvent(self, _): widget = self.algorithm_choose_widget.current_widget() widget.image_changed(self.settings.image)
class MainWindow(QMainWindow): def selectFileToOpen(self): def getPreProcessingChoice(self, filename, filestructure): items = ("Choose the longest", "Merge all") item, okPressed = QInputDialog.getItem( self, "Multiple tracks/segments", "File '" + filename + "' contains more than one track/segment\n\n" + infos + "\nWhat to do?", items, 0, False) if okPressed and item: return items.index(item) else: return 0 # Try to recover the last used directory old_directory = self.settings.value("lastdirectory", str) # Check if the setting exists if old_directory is not None: # Check if it's not empty if old_directory: old_directory = old_directory else: old_directory = bombo.TRACKS_FOLDER else: old_directory = bombo.TRACKS_FOLDER # Open the dialog box fullfilename_list = QFileDialog.getOpenFileNames( self, 'Open .gpx', old_directory, "GPX files (*.gpx)") if os.environ['QT_API'] == 'pyqt': pass elif os.environ['QT_API'] == 'pyqt5': fullfilename_list = fullfilename_list[0] # Process every selected file for i, fullfilename in enumerate(fullfilename_list): # Process filename directory, filename = os.path.split(str(fullfilename)) filename, fileextension = os.path.splitext(filename) # Save the new directory in the application settings (it only # needs to be done once) if i == 0: # print "New directory to be saved: {}\n".format(directory) if os.environ['QT_API'] == 'pyqt': self.settings.setValue("lastdirectory", str(directory)) elif os.environ['QT_API'] == 'pyqt5': self.settings.setValue("lastdirectory", QtCore.QVariant(str(directory))) # Open file and inspect what's inside gpxraw, longest_traseg, Ntracks, Nsegments, infos = bombo.LoadGPX( fullfilename) # If there's more than one track or segment, ask how to proceed if (Ntracks > 1) or (Nsegments > 1): preprocessingchoice = getPreProcessingChoice( self, filename, infos) if preprocessingchoice == 0: preprocessedgpx = bombo.SelectOneTrackAndSegmentFromGPX( gpxraw, longest_traseg[0], longest_traseg[1]) listname = filename + " (longest)" elif preprocessingchoice == 1: preprocessedgpx = bombo.MergeAllTracksAndSegmentsFromGPX( gpxraw) listname = filename + " (merged)" else: preprocessedgpx = gpxraw listname = filename # Append the list of open GPX files using the next available color (that's the size of the list -1) self.gpxlist.append(preprocessedgpx) self.gpxnamelist.append(listname) newitem = QListWidgetItem(listname) newitem.setBackground( QtGui.QColor(self.palette[len(self.gpxlist) - 1])) self.tracklist.addItem(newitem) return def Go(self): if len(self.gpxselectedlist) > 0: # Temporarily change cursor QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) # Clear up global variables self.proc_coords = [] self.proc_measurements = [] self.proc_state_means = [] self.proc_state_vars = [] self.proc_new_coords = [] self.proc_new_gpx = [] self.proc_coords_to_plot = [] self.proc_coords_to_plot2 = [] self.proc_balloondata = [] # For every GPX file that is selected self.textWarningConsole.clear() for i, currentgpx in enumerate(self.gpxselectedlist): # Parse the GPX file gpx, coords, dinfos_before, warnings = bombo.ParseGPX( currentgpx, track_nr=0, segment_nr=0, use_srtm_elevation=bool(self.checkUseSRTM.isChecked())) self.textWarningConsole.append(warnings) # Kalman processing coords, measurements, state_means, state_vars, dinfos_during = bombo.ApplyKalmanFilter( coords, gpx, method=self.comboBoxProcessingMethod.currentIndex(), use_acceleration=self.checkUseAcceleration.isChecked(), extra_smooth=self.checkExtraSmooth.isChecked(), debug_plot=False) # Save data in GPX structure to compute speed and elevations new_coords, new_gpx, dinfos_after = bombo.SaveDataToCoordsAndGPX( coords, state_means) # Update GUI with the computed stats parent = QtGui.QStandardItem(self.gpxselectednamelist[i]) parent_beforeprocessing = QtGui.QStandardItem("Raw GPX stats") parent_beforeprocessing.appendRow([ QtGui.QStandardItem("Total distance"), QtGui.QStandardItem(dinfos_before['total_distance']) ]) parent_beforeprocessing_moving = QtGui.QStandardItem("Moving") parent_beforeprocessing_moving.appendRow([ QtGui.QStandardItem("Time"), QtGui.QStandardItem(dinfos_before['moving_time']) ]) parent_beforeprocessing_moving.appendRow([ QtGui.QStandardItem("Distance"), QtGui.QStandardItem(dinfos_before['moving_distance']) ]) parent_beforeprocessing.appendRow( parent_beforeprocessing_moving) parent_beforeprocessing_idle = QtGui.QStandardItem("Idle") parent_beforeprocessing_idle.appendRow([ QtGui.QStandardItem("Time"), QtGui.QStandardItem(dinfos_before['idle_time']) ]) parent_beforeprocessing_idle.appendRow([ QtGui.QStandardItem("Distance"), QtGui.QStandardItem(dinfos_before['idle_distance']) ]) parent_beforeprocessing.appendRow(parent_beforeprocessing_idle) parent_beforeprocessing.appendRow([ QtGui.QStandardItem("Elevation"), QtGui.QStandardItem(dinfos_before['elevation']) ]) parent_beforeprocessing.appendRow([ QtGui.QStandardItem("Climb"), QtGui.QStandardItem(dinfos_before['climb']) ]) parent.appendRow(parent_beforeprocessing) parent.appendRow([ QtGui.QStandardItem("Samples"), QtGui.QStandardItem(dinfos_during['nsamples']) ]) parent.appendRow([ QtGui.QStandardItem("Total distance"), QtGui.QStandardItem(dinfos_after['total_distance']) ]) parent_moving = QtGui.QStandardItem("Moving") parent_moving.appendRow([ QtGui.QStandardItem("Time"), QtGui.QStandardItem(dinfos_after['moving_time']) ]) parent_moving.appendRow([ QtGui.QStandardItem("Distance"), QtGui.QStandardItem(dinfos_after['moving_distance']) ]) parent.appendRow(parent_moving) parent_idle = QtGui.QStandardItem("Idle") parent_idle.appendRow([ QtGui.QStandardItem("Time"), QtGui.QStandardItem(dinfos_after['idle_time']) ]) parent_idle.appendRow([ QtGui.QStandardItem("Distance"), QtGui.QStandardItem(dinfos_after['idle_distance']) ]) parent.appendRow(parent_idle) parent.appendRow([ QtGui.QStandardItem("Elevation"), QtGui.QStandardItem(dinfos_after['elevation']) ]) parent.appendRow([ QtGui.QStandardItem("Climb"), QtGui.QStandardItem(dinfos_after['climb']) ]) self.treemodel.appendRow(parent) # Create balloondata for the html plot balloondata = { 'distance': np.cumsum( bombo.HaversineDistance(np.asarray(new_coords['lat']), np.asarray( new_coords['lon']))), 'elevation': np.asarray(new_coords['ele']), 'speed': None } # Create extra data for the html plot (fully implemented in bombo, not here) """ data = np.ones((len(lat_cleaned),2)) data[:,0] = h_filtered / np.max(h_filtered) * 0.0004 data[:,1] = np.hstack((np.asarray([0]), speed_h)) / np.max(np.hstack((np.asarray([0]), speed_h))) * 0.0004 tangentdata = {'data': data, 'sides': (0, 1), 'palette': ('blue','red')} """ # Save relevant output in global variables self.proc_coords.append(coords) self.proc_measurements.append(measurements) self.proc_state_means.append(state_means) self.proc_state_vars.append(state_vars) self.proc_new_coords.append(new_coords) self.proc_new_gpx.append(new_gpx) self.proc_coords_to_plot.append( np.vstack((new_coords['lat'], new_coords['lon'])).T) self.proc_coords_to_plot2.append( np.vstack((coords['lat'], coords['lon'])).T) self.proc_balloondata.append(balloondata) # Restore original cursor QApplication.restoreOverrideCursor() # Generate embedded plots if len(self.gpxselectedlist) == 1: self.plotEmbeddedElevationAndSpeed.update_figure( measurements, state_means, new_gpx.tracks[0].segments[0]) self.plotEmbeddedDetails.update_figure( measurements, state_means, state_vars, new_gpx.tracks[0].segments[0]) else: # Commentato per adesso # self.plotEmbeddedElevationAndSpeed.update_figure_multiple_tracks(self.proc_measurements, self.proc_state_means, self.proc_new_gpx) self.plotEmbeddedElevationAndSpeed.clear_figure() self.plotEmbeddedDetails.clear_figure() # Generate html plot, if only one track is selected, proceed with the complete output, otherwise just plot the traces if len(self.gpxselectedlist) is 1: bombo.PlotOnMap( coords_array_list=self.proc_coords_to_plot, coords_array2_list=self.proc_coords_to_plot2, coords_palette=self.selectedpalette, tangentdata=None, balloondata_list=self.proc_balloondata, rdp_reduction=self.checkUseRDP.isChecked(), showmap=bool(self.check2DMapInExternalBrowser.isChecked())) else: bombo.PlotOnMap( coords_array_list=self.proc_coords_to_plot, coords_array2_list=None, coords_palette=self.selectedpalette, tangentdata=None, balloondata_list=self.proc_balloondata, rdp_reduction=self.checkUseRDP.isChecked(), showmap=bool(self.check2DMapInExternalBrowser.isChecked())) self.map2d.load(QtCore.QUrl(bombo.MAP_2D_FILENAME)) self.map2d.show() # Generate 3D plot, only with one track for the moment if len(self.gpxselectedlist) == 1: if self.check3DMapSelection.isChecked(): tile_selection = 'auto' else: tile_selection = self.text3DMapName.text() terrain, track, warnings = bombo.Generate3DMap( new_coords['lat'], new_coords['lon'], tile_selection=tile_selection, margin=self.spinbox3DMargin.value(), elevation_scale=self.spinbox3DElevationScale.value(), mapping='coords', use_osm_texture=True, texture_type='osm', texture_zoom=self.spinbox3DOSMZoom.value(), texture_invert=self.check3DOSMInvert.isChecked(), use_proxy=self.use_proxy, proxy_data=self.proxy_config, verbose=False) self.textWarningConsole.append(warnings) if terrain is not None: self.map3d.update_plot(terrain, track) else: self.textWarningConsole.setText( "You need to open a .gpx file before!") return def PlotSpecificAreaDialog(self): def PlotSpecificArea(): # Save coordinates for the next time if os.environ['QT_API'] == 'pyqt': self.settings.setValue("last_point_coord_lat", self.spinboxLatDec.value()) self.settings.setValue("last_point_coord_lon", self.spinboxLonDec.value()) elif os.environ['QT_API'] == 'pyqt5': self.settings.setValue( "last_point_coord_lat", QtCore.QVariant(self.spinboxLatDec.value())) self.settings.setValue( "last_point_coord_lon", QtCore.QVariant(self.spinboxLonDec.value())) # Select the 3D Map tab self.tab.setCurrentIndex(2) # Plot if self.check3DMapSelection.isChecked(): tile_selection = 'auto' else: tile_selection = self.text3DMapName.text() terrain, track, warnings = bombo.Generate3DMap( [self.spinboxLatDec.value()], [self.spinboxLonDec.value()], tile_selection=tile_selection, margin=self.spinbox3DMargin.value(), elevation_scale=self.spinbox3DElevationScale.value(), mapping='coords', use_osm_texture=True, texture_type='osm', texture_zoom=self.spinbox3DOSMZoom.value(), texture_invert=self.check3DOSMInvert.isChecked(), use_proxy=self.use_proxy, proxy_data=self.proxy_config, verbose=False) self.textWarningConsole.append(warnings) if terrain is not None: self.map3d.update_plot(terrain, track) d.done(0) def Convert(): try: dd = bombo.parse_dms(self.textLatLonGMS.text()) self.spinboxLatDec.setValue(dd[0]) self.spinboxLonDec.setValue(dd[1]) except: pass d = QDialog() grid = QGridLayout() hBox_coordsGMS = QHBoxLayout() hBox_coordsGMS.setSpacing(5) label = QLabel('Coordinates (gms)') grid.addWidget(label, 0, 0) self.textLatLonGMS = QLineEdit() self.textLatLonGMS.setText("") grid.addWidget(self.textLatLonGMS, 0, 1, 1, 2) button1 = QPushButton("Convert to decimal") button1.clicked.connect(Convert) grid.addWidget(button1, 0, 3) label = QLabel('Coordinates (decimal)') grid.addWidget(label, 1, 0) self.spinboxLatDec = QDoubleSpinBox() self.spinboxLatDec.setRange(-90, +90) self.spinboxLatDec.setSingleStep(0.0000001) self.spinboxLatDec.setDecimals(7) grid.addWidget(self.spinboxLatDec, 1, 1) self.spinboxLonDec = QDoubleSpinBox() self.spinboxLonDec.setRange(-180, +180) self.spinboxLonDec.setSingleStep(0.0000001) self.spinboxLonDec.setDecimals(7) grid.addWidget(self.spinboxLonDec, 1, 2) # Try to recover the last used points try: old_lat = self.settings.value("last_point_coord_lat", type=float) old_lon = self.settings.value("last_point_coord_lon", type=float) self.spinboxLatDec.setValue(old_lat) self.spinboxLonDec.setValue(old_lon) except: # Coordinates of Mt. Rinjani in Indonesia self.spinboxLatDec.setValue(-8.4166000) self.spinboxLonDec.setValue(116.4666000) button2 = QPushButton("Show 3D map") button2.clicked.connect(PlotSpecificArea) grid.addWidget(button2, 1, 3) d.setWindowTitle("Show point on 3D map") d.setLayout(grid) d.setWindowModality(QtCore.Qt.ApplicationModal) d.exec_() def ProxyDialog(self): def SetProxy(): self.use_proxy = bool(self.checkUseProxy.isChecked()) self.proxy_config = self.textProxyConfig.text() if os.environ['QT_API'] == 'pyqt': self.settings.setValue("use_proxy", self.use_proxy) self.settings.setValue("proxy_config", str(self.proxy_config)) elif os.environ['QT_API'] == 'pyqt5': self.settings.setValue("use_proxy", QtCore.QVariant(self.use_proxy)) self.settings.setValue("proxy_config", QtCore.QVariant(str(self.proxy_config))) d.done(0) d = QDialog() box = QVBoxLayout() hBox_proxy = QHBoxLayout() hBox_proxy.setSpacing(5) label = QLabel('Proxy') hBox_proxy.addWidget(label) self.textProxyConfig = QLineEdit() try: self.textProxyConfig.setText( self.settings.value('proxy_config', str)) except: self.textProxyConfig.setText(bombo.PROXY_DATA) self.textProxyConfig.setMinimumWidth(200) hBox_proxy.addWidget(self.textProxyConfig) box.addLayout(hBox_proxy) self.checkUseProxy = QCheckBox("Use proxy") try: self.checkUseProxy.setChecked( self.settings.value('use_proxy', bool)) except: self.checkUseProxy.setChecked(bool(bombo.USE_PROXY)) box.addWidget(self.checkUseProxy) button = QPushButton("Save configuration") button.clicked.connect(SetProxy) box.addWidget(button) d.setWindowTitle("Proxy configuration") d.setLayout(box) d.setWindowModality(QtCore.Qt.ApplicationModal) d.exec_() def __init__(self, parent=None): super(MainWindow, self).__init__() self.initVariables() self.initUI() def initVariables(self): self.gpxlist = list() self.gpxnamelist = list() self.gpxselectedlist = list() self.gpxselectednamelist = list() self.palette = bombo.GeneratePalette(N=10) * 5 # replicated 5 times #self.palette = ["#0000FF", "#00FF00", "#00FFFF", "#FF0000", "#FF00FF", "#FFFF00", "#FFFFFF"] # test palette self.selectedpalette = list() self.proc_coords = list() self.proc_measurements = list() self.proc_state_means = list() self.proc_state_vars = list() self.proc_new_coords = list() self.proc_new_gpx = list() self.proc_coords_to_plot = list() self.proc_coords_to_plot2 = list() self.proc_balloondata = list() def initUI(self): def selection_changed(): # Retrieve selected items # selecteditems = self.tracklist.selectedItems() selectedindexes = self.tracklist.selectedIndexes() # Adding the selected items to the processing list self.gpxselectedlist[:] = [] self.gpxselectednamelist[:] = [] self.selectedpalette[:] = [] for i in selectedindexes: # print str(i.text()) self.gpxselectedlist.append(self.gpxlist[i.row()]) self.gpxselectednamelist.append(self.gpxnamelist[i.row()]) self.selectedpalette.append(self.palette[i.row()]) def ClearStats(): """ # Some other code that could be used in the future index = self.treemodel.indexFromItem(parent1) self.tree.expand(index) selmod = self.tree.selectionModel() index2 = self.treemodel.indexFromItem(child2) selmod.select(index2, QtCore.QItemSelectionModel.Select|QtCore.QItemSelectionModel.Rows) root = self.treemodel.invisibleRootItem() (item.parent() or root).removeChild(item) """ # Returns a list of indexes. In our case, for each row there are 2 indexes, cos there are 2 columns. for index in self.tree.selectedIndexes(): # Consider only the first columns if index.column() == 0: # Need to check if it's a top item (i.e. track), otherwise if a subitem (i.e. distance or time) is selected, the result might be buggy parent = index.parent() parent_item = self.treemodel.itemFromIndex(parent) if parent_item is None: self.treemodel.removeRow(index.row()) # Application Settings QtCore.QCoreApplication.setOrganizationName("Ste") QtCore.QCoreApplication.setOrganizationDomain( "https://github.com/stesalati/sport/") QtCore.QCoreApplication.setApplicationName("TrackAnalyser") # Config settings self.settings = QtCore.QSettings(self) # Proxy settings try: self.use_proxy = self.settings.value('use_proxy', bool) self.proxy_config = self.settings.value('proxy_config', str) except: self.use_proxy = bombo.USE_PROXY self.proxy_config = bombo.PROXY_DATA # Actions openfile = QAction(QtGui.QIcon("icons/openfile.png"), "Open .gpx", self) openfile.setShortcut("Ctrl+O") openfile.setStatusTip("Open file") openfile.triggered.connect(self.selectFileToOpen) go = QAction(QtGui.QIcon("icons/go.png"), "Go!", self) go.setShortcut("Ctrl+R") go.setStatusTip("Run analysis") go.triggered.connect(self.Go) clearstats = QAction(QtGui.QIcon("icons/clear.png"), "Clear stats", self) clearstats.setShortcut("Ctrl+C") clearstats.setStatusTip("Clear stats") clearstats.triggered.connect(ClearStats) sep1 = QAction(self) sep1.setSeparator(True) showpoint = QAction(QtGui.QIcon("icons/point.png"), "Show point", self) showpoint.setShortcut("Ctrl+P") showpoint.setStatusTip("Show point") showpoint.triggered.connect(self.PlotSpecificAreaDialog) sep2 = QAction(self) sep2.setSeparator(True) quitapp = QAction(QtGui.QIcon("icons/quit.png"), "Quit", self) quitapp.setShortcut("Ctrl+Q") quitapp.setStatusTip("Quit application") quitapp.triggered.connect(qApp.quit) configs = QAction(QtGui.QIcon("icons/configs.png"), "Configs", self) configs.setStatusTip("Configs") configs.triggered.connect(self.ProxyDialog) # Menubar mainMenu = self.menuBar() configMenu = mainMenu.addMenu('&Config') configMenu.addAction(configs) # Toolbar toolbar = self.addToolBar('My tools') toolbar.addAction(openfile) toolbar.addAction(go) toolbar.addAction(clearstats) toolbar.addAction(sep1) toolbar.addAction(showpoint) toolbar.addAction(sep2) toolbar.addAction(quitapp) toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) toolbar.setIconSize(QtCore.QSize(30, 30)) # Status bar self.statusBar().show() # Main widget (everything that's not toolbar, statusbar or menubar must be in this widget) self.scatola = QWidget() # Main horizontal impagination hBox = QHBoxLayout() hBox.setSpacing(5) # Vertical left column vBox_left = QVBoxLayout() vBox_left.setSpacing(5) # 1st vertical box, a list self.tracklist = QListWidget() vBox_left.addWidget(self.tracklist) self.tracklist.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tracklist.itemSelectionChanged.connect(selection_changed) self.tracklist.setMaximumHeight(120) # 2nd vertical box, containing several horizontal boxes, one for each setting vBox2 = QVBoxLayout() vBox2.setSpacing(5) # Just the group label labelSettings = QLabel('Settings') vBox2.addWidget(labelSettings) # Use/don't use corrected altitude self.checkUseSRTM = QCheckBox( "Use SRTM corrected elevation (needs Internet)") self.checkUseSRTM.setChecked(False) vBox2.addWidget(self.checkUseSRTM) # Choose processing method + use/don't use acceleration hBoxProcessingMethod = QHBoxLayout() labelProcessingMethod = QLabel('Processing method') hBoxProcessingMethod.addWidget(labelProcessingMethod) self.comboBoxProcessingMethod = QComboBox() self.comboBoxProcessingMethod.addItem("Just use available data") self.comboBoxProcessingMethod.addItem( "Fill all gaps at T=1s (resample)") self.comboBoxProcessingMethod.addItem("Fill only smaller gaps at T=1s") hBoxProcessingMethod.addWidget(self.comboBoxProcessingMethod) self.checkUseAcceleration = QCheckBox("Use acceleration") self.checkUseAcceleration.setChecked(False) hBoxProcessingMethod.addWidget(self.checkUseAcceleration) vBox2.addLayout(hBoxProcessingMethod) # Use/don't use variance smooth self.checkExtraSmooth = QCheckBox("Extra smooth") self.checkExtraSmooth.setChecked(False) vBox2.addWidget(self.checkExtraSmooth) # 2D interactive map settings hBox2DMap = QHBoxLayout() self.checkUseRDP = QCheckBox("Use RDP to reduce points") self.checkUseRDP.setChecked(False) hBox2DMap.addWidget(self.checkUseRDP) self.check2DMapInExternalBrowser = QCheckBox( "Show in external browser") self.check2DMapInExternalBrowser.setChecked(False) hBox2DMap.addWidget(self.check2DMapInExternalBrowser) vBox2.addLayout(hBox2DMap) # Settings for the 3D map line3DViewSettings = QFrame() #line3DViewSettings.setGeometry(QtCore.QRect(320, 150, 118, 3)) line3DViewSettings.setFrameShape(QFrame.HLine) line3DViewSettings.setFrameShadow(QFrame.Sunken) vBox2.addWidget(line3DViewSettings) label3DViewSettings = QLabel('3D view settings') vBox2.addWidget(label3DViewSettings) hBox3DMapSelection = QHBoxLayout() self.check3DMapSelection = QCheckBox( "Select elevation tiles automatically, otherwise") self.check3DMapSelection.setChecked(True) hBox3DMapSelection.addWidget(self.check3DMapSelection) self.text3DMapName = QLineEdit() self.text3DMapName.setText("Iceland.tif") hBox3DMapSelection.addWidget(self.text3DMapName) vBox2.addLayout(hBox3DMapSelection) hBox3D = QHBoxLayout() label3DMargin = QLabel('Margin') hBox3D.addWidget(label3DMargin) self.spinbox3DMargin = QSpinBox() self.spinbox3DMargin.setRange(50, 1000) self.spinbox3DMargin.setValue(100) self.spinbox3DMargin.setSingleStep(10) hBox3D.addWidget(self.spinbox3DMargin) labelSpace = QLabel(' ') hBox3D.addWidget(labelSpace) label3DElevationScale = QLabel('Elev. scale') hBox3D.addWidget(label3DElevationScale) self.spinbox3DElevationScale = QDoubleSpinBox() self.spinbox3DElevationScale.setRange(1, 50) self.spinbox3DElevationScale.setSingleStep(0.1) hBox3D.addWidget(self.spinbox3DElevationScale) hBox3D.addWidget(labelSpace) label3DOSMZoom = QLabel('Zoom') hBox3D.addWidget(label3DOSMZoom) self.spinbox3DOSMZoom = QSpinBox() self.spinbox3DOSMZoom.setRange(8, 15) self.spinbox3DOSMZoom.setValue(13) self.spinbox3DOSMZoom.setSingleStep(1) hBox3D.addWidget(self.spinbox3DOSMZoom) hBox3D.addWidget(labelSpace) self.check3DOSMInvert = QCheckBox("Invert") self.check3DOSMInvert.setChecked(False) hBox3D.addWidget(self.check3DOSMInvert) vBox2.addLayout(hBox3D) vBox_left.addLayout(vBox2) # 3rd stats tree lineTree = QFrame() lineTree.setFrameShape(QFrame.HLine) lineTree.setFrameShadow(QFrame.Sunken) vBox2.addWidget(lineTree) labelTree = QLabel('Track stats') vBox2.addWidget(labelTree) self.tree = QTreeView() self.tree.setSelectionBehavior(QAbstractItemView.SelectRows) self.treemodel = QtGui.QStandardItemModel() self.treemodel.setHorizontalHeaderLabels(['Name', 'Value']) self.tree.setModel(self.treemodel) self.tree.setUniformRowHeights(True) self.tree.setColumnWidth(0, 200) vBox_left.addWidget(self.tree) # 4th text, containing text messages/errors self.textWarningConsole = QTextEdit() self.textWarningConsole.setReadOnly(True) self.textWarningConsole.setFont(QtGui.QFont("Courier New", FONTSIZE)) self.textWarningConsole.clear() self.textWarningConsole.setMaximumHeight(50) vBox_left.addWidget(self.textWarningConsole) # I put "vBox_left" inside a widget and then the widget inside "hBox" # instead of just doing "hBox.addLayout(vBox_left) so I can set its # maximum width. vBox_left_widget = QWidget() vBox_left_widget.setLayout(vBox_left) vBox_left_widget.setMinimumWidth(400) vBox_left_widget.setMaximumWidth(500) hBox.addWidget(vBox_left_widget) # Vertical right column self.tab = QTabWidget() # Tab 1: Summary: elevation and speed tab1 = QWidget() # The tab layout vBox_tab = QVBoxLayout() vBox_tab.setSpacing(5) # Plot area self.plotEmbeddedElevationAndSpeed = EmbeddedPlot_ElevationSpeed( width=5, height=4, dpi=100) self.plotEmbeddedElevationAndSpeed.setMinimumWidth(800) # Add toolbar to the plot self.mpl_toolbar1 = NavigationToolbar( self.plotEmbeddedElevationAndSpeed, self.scatola) # Add widgets to the layout vBox_tab.addWidget(self.plotEmbeddedElevationAndSpeed) vBox_tab.addWidget(self.mpl_toolbar1) # Associate the layout to the tab tab1.setLayout(vBox_tab) # Tab 2: html 2D map tab2 = QWidget() # The tab layout vBox_tab = QVBoxLayout() vBox_tab.setSpacing(5) # Area self.map2d = QtWebEngineWidgets.QWebEngineView() # Add widgets to the layout vBox_tab.addWidget(self.map2d) # Associate the layout to the tab tab2.setLayout(vBox_tab) # Tab 3: 3D plot tab3 = QWidget() # The tab layout vBox_tab = QVBoxLayout() vBox_tab.setSpacing(5) # Area self.map3d = MayaviQWidget() # Add widgets to the layout vBox_tab.addWidget(self.map3d) # Associate the layout to the tab tab3.setLayout(vBox_tab) # Tab 4: Details tab4 = QWidget() # The tab layout vBox_tab = QVBoxLayout() vBox_tab.setSpacing(5) # Plot area self.plotEmbeddedDetails = EmbeddedPlot_Details(width=5, height=4, dpi=100) self.plotEmbeddedDetails.setMinimumWidth(800) # Add toolbar to the plot self.mpl_toolbar2 = NavigationToolbar(self.plotEmbeddedDetails, self.scatola) # Add widgets to the layout vBox_tab.addWidget(self.plotEmbeddedDetails) vBox_tab.addWidget(self.mpl_toolbar2) # Associate the layout to the tab tab4.setLayout(vBox_tab) # Associate tabs self.tab.addTab(tab1, "Summary") self.tab.addTab(tab2, "2D Map") self.tab.addTab(tab3, "3D Map") self.tab.addTab(tab4, "Details") hBox.addWidget(self.tab) # Setting hBox as main box self.scatola.setLayout(hBox) self.setCentralWidget(self.scatola) # Application settings self.setWindowTitle('TrackAnalyser') self.setWindowIcon((QtGui.QIcon('icons/app.png'))) self.setGeometry(100, 100, 1200, 700) self.show()
class QtLabelsControls(QtLayerControls): """Qt view and controls for the napari Labels layer. Parameters ---------- layer : napari.layers.Labels An instance of a napari Labels layer. Attributes ---------- button_group : qtpy.QtWidgets.QButtonGroup Button group of labels layer modes: PAN_ZOOM, PICKER, PAINT, ERASE, or FILL. colormapUpdate : qtpy.QtWidgets.QPushButton Button to update colormap of label layer. contigCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is contiguous. fill_button : qtpy.QtWidgets.QtModeRadioButton Button to select FILL mode on Labels layer. grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Labels An instance of a napari Labels layer. ndimCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is n-dimensional. paint_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAINT mode on Labels layer. panzoom_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAN_ZOOM mode on Labels layer. pick_button : qtpy.QtWidgets.QtModeRadioButton Button to select PICKER mode on Labels layer. erase_button : qtpy.QtWidgets.QtModeRadioButton Button to select ERASE mode on Labels layer. selectionSpinBox : qtpy.QtWidgets.QSpinBox Widget to select a specific label by its index. Raises ------ ValueError Raise error if label mode is not PAN_ZOOM, PICKER, PAINT, ERASE, or FILL. """ def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect( self._on_selected_label_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contiguous_change) self.layer.events.n_dimensional.connect(self._on_n_dimensional_change) self.layer.events.contour.connect(self._on_contour_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.events.preserve_labels.connect( self._on_preserve_labels_change) self.layer.events.color_mode.connect(self._on_color_mode_change) # selection spinbox self.selectionSpinBox = QSpinBox() self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.setSingleStep(1) self.selectionSpinBox.setMinimum(0) self.selectionSpinBox.setMaximum(1024) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self.selectionSpinBox.setAlignment(Qt.AlignCenter) self._on_selected_label_change() sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged.connect(self.changeSize) self.brushSizeSlider = sld self._on_brush_size_change() contig_cb = QCheckBox() contig_cb.setToolTip(trans._('contiguous editing')) contig_cb.stateChanged.connect(self.change_contig) self.contigCheckBox = contig_cb self._on_contiguous_change() ndim_cb = QCheckBox() ndim_cb.setToolTip(trans._('edit all dimensions')) ndim_cb.stateChanged.connect(self.change_ndim) self.ndimCheckBox = ndim_cb self._on_n_dimensional_change() contour_sb = QSpinBox() contour_sb.setToolTip(trans._('display contours of labels')) contour_sb.valueChanged.connect(self.change_contour) self.contourSpinBox = contour_sb self.contourSpinBox.setKeyboardTracking(False) self.contourSpinBox.setSingleStep(1) self.contourSpinBox.setMinimum(0) self.contourSpinBox.setMaximum(2147483647) self.contourSpinBox.setAlignment(Qt.AlignCenter) self._on_contour_change() preserve_labels_cb = QCheckBox() preserve_labels_cb.setToolTip( trans._('preserve existing labels while painting')) preserve_labels_cb.stateChanged.connect(self.change_preserve_labels) self.preserveLabelsCheckBox = preserve_labels_cb self._on_preserve_labels_change() selectedColorCheckbox = QCheckBox() selectedColorCheckbox.setToolTip( trans._("Display only selected label")) selectedColorCheckbox.stateChanged.connect(self.toggle_selected_mode) self.selectedColorCheckbox = selectedColorCheckbox # shuffle colormap button self.colormapUpdate = QtModePushButton( None, 'shuffle', slot=self.changeColor, tooltip=trans._('shuffle colors'), ) self.panzoom_button = QtModeRadioButton( layer, 'zoom', Mode.PAN_ZOOM, tooltip=trans._('Pan/zoom mode (Space)'), checked=True, ) self.pick_button = QtModeRadioButton(layer, 'picker', Mode.PICK, tooltip=trans._('Pick mode (L)')) self.paint_button = QtModeRadioButton( layer, 'paint', Mode.PAINT, tooltip=trans._('Paint mode (P)')) self.fill_button = QtModeRadioButton( layer, 'fill', Mode.FILL, tooltip=trans._("Fill mode (F) \nToggle with {key}".format( key=KEY_SYMBOLS['Control'])), ) self.erase_button = QtModeRadioButton( layer, 'erase', Mode.ERASE, tooltip=trans._("Erase mode (E) \nToggle with {key}".format( key=KEY_SYMBOLS['Alt'])), ) self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.button_group.addButton(self.erase_button) self._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.colormapUpdate) button_row.addWidget(self.erase_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.pick_button) button_row.addWidget(self.panzoom_button) button_row.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) brush_shape_comboBox = QComboBox(self) for index, (data, text) in enumerate(LABEL_BRUSH_SHAPE_TRANSLATIONS.items()): data = data.value brush_shape_comboBox.addItem(text, data) if self.layer.brush_shape == data: brush_shape_comboBox.setCurrentIndex(index) brush_shape_comboBox.activated[str].connect(self.change_brush_shape) self.brushShapeComboBox = brush_shape_comboBox self._on_brush_shape_change() color_mode_comboBox = QComboBox(self) for index, (data, text) in enumerate(LABEL_COLOR_MODE_TRANSLATIONS.items()): data = data.value color_mode_comboBox.addItem(text, data) if self.layer.color_mode == data: color_mode_comboBox.setCurrentIndex(index) color_mode_comboBox.activated[str].connect(self.change_color_mode) self.colorModeComboBox = color_mode_comboBox self._on_color_mode_change() color_layout = QHBoxLayout() self.colorBox = QtColorBox(layer) color_layout.addWidget(self.colorBox) color_layout.addWidget(self.selectionSpinBox) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 0, 1, 4) self.grid_layout.addWidget(QLabel(trans._('label:')), 1, 0, 1, 1) self.grid_layout.addLayout(color_layout, 1, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('opacity:')), 2, 0, 1, 1) self.grid_layout.addWidget(self.opacitySlider, 2, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('brush size:')), 3, 0, 1, 1) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('brush shape:')), 4, 0, 1, 1) self.grid_layout.addWidget(self.brushShapeComboBox, 4, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('blending:')), 5, 0, 1, 1) self.grid_layout.addWidget(self.blendComboBox, 5, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('color mode:')), 6, 0, 1, 1) self.grid_layout.addWidget(self.colorModeComboBox, 6, 1, 1, 3) self.grid_layout.addWidget(QLabel(trans._('contour:')), 7, 0, 1, 1) self.grid_layout.addWidget(self.contourSpinBox, 7, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('contiguous:')), 8, 0, 1, 1) self.grid_layout.addWidget(self.contigCheckBox, 8, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('n-dim:')), 8, 2, 1, 1) self.grid_layout.addWidget(self.ndimCheckBox, 8, 3, 1, 1) self.grid_layout.addWidget(QLabel(trans._('preserve labels:')), 9, 0, 1, 2) self.grid_layout.addWidget(self.preserveLabelsCheckBox, 9, 1, 1, 1) self.grid_layout.addWidget(QLabel(trans._('show selected:')), 9, 2, 1, 1) self.grid_layout.addWidget(self.selectedColorCheckbox, 9, 3, 1, 1) self.grid_layout.setRowStretch(9, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def _on_mode_change(self, event): """Receive layer model mode change event and update checkbox ticks. Parameters ---------- event : napari.utils.event.Event The napari event that triggered this method. Raises ------ ValueError Raise error if event.mode is not PAN_ZOOM, PICK, PAINT, ERASE, or FILL """ mode = event.mode if mode == Mode.PAN_ZOOM: self.panzoom_button.setChecked(True) elif mode == Mode.PICK: self.pick_button.setChecked(True) elif mode == Mode.PAINT: self.paint_button.setChecked(True) elif mode == Mode.FILL: self.fill_button.setChecked(True) elif mode == Mode.ERASE: self.erase_button.setChecked(True) else: raise ValueError(trans._("Mode not recognized")) def changeColor(self): """Change colormap of the label layer.""" self.layer.new_colormap() def changeSelection(self, value): """Change currently selected label. Parameters ---------- value : int Index of label to select. """ self.layer.selected_label = value self.selectionSpinBox.clearFocus() self.setFocus() def toggle_selected_mode(self, state): if state == Qt.Checked: self.layer.show_selected_label = True else: self.layer.show_selected_label = False def changeSize(self, value): """Change paint brush size. Parameters ---------- value : float Size of the paint brush. """ self.layer.brush_size = value def change_contig(self, state): """Toggle contiguous state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if labels are contiguous. """ if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): """Toggle n-dimensional state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if label layer is n-dimensional. """ if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def change_contour(self, value): """Change contour thickness. Parameters ---------- value : int Thickness of contour. """ self.layer.contour = value self.contourSpinBox.clearFocus() self.setFocus() def change_preserve_labels(self, state): """Toggle preserve_labels state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if overwriting label is enabled. """ if state == Qt.Checked: self.layer.preserve_labels = True else: self.layer.preserve_labels = False def change_color_mode(self, new_mode): """Change color mode of label layer. Parameters ---------- new_mode : str AUTO (default) allows color to be set via a hash function with a seed. DIRECT allows color of each label to be set directly by a color dictionary. """ self.layer.color_mode = self.colorModeComboBox.currentData() def change_brush_shape(self, brush_shape): """Change paintbrush shape of label layer. Parameters ---------- brush_shape : str CIRCLE (default) uses circle paintbrush (case insensitive). SQUARE uses square paintbrush (case insensitive). """ self.layer.brush_shape = self.brushShapeComboBox.currentData() def _on_contour_change(self, event=None): """Receive layer model contour value change event and update spinbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.contour.blocker(): value = self.layer.contour self.contourSpinBox.setValue(int(value)) def _on_selected_label_change(self, event=None): """Receive layer model label selection change event and update spinbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selectionSpinBox.setValue(int(value)) def _on_brush_size_change(self, event=None): """Receive layer model brush size change event and update the slider. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brushSizeSlider.setValue(value) def _on_n_dimensional_change(self, event=None): """Receive layer model n-dim mode change event and update the checkbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.n_dimensional.blocker(): self.ndimCheckBox.setChecked(self.layer.n_dimensional) def _on_contiguous_change(self, event=None): """Receive layer model contiguous change event and update the checkbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.contiguous.blocker(): self.contigCheckBox.setChecked(self.layer.contiguous) def _on_preserve_labels_change(self, event=None): """Receive layer model preserve_labels event and update the checkbox. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.preserve_labels.blocker(): self.preserveLabelsCheckBox.setChecked(self.layer.preserve_labels) def _on_color_mode_change(self, event=None): """Receive layer model color. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ with self.layer.events.color_mode.blocker(): # `self.colorModeComboBox.findData` is not returning the correct index. for index in range(self.colorModeComboBox.count()): if self.layer.color_mode == self.colorModeComboBox.itemData( index): self.colorModeComboBox.setCurrentIndex(index) break def _on_brush_shape_change(self, event=None): """Receive brush shape change event and update dropdown menu. Parameters ---------- event : napari.utils.event.Event The napari event that triggered this method. """ with self.layer.events.brush_shape.blocker(): # `self.brushShapeComboBox.findData` is not returning the correct index. for index in range(self.brushShapeComboBox.count()): if self.layer.brush_shape == self.brushShapeComboBox.itemData( index): self.brushShapeComboBox.setCurrentIndex(index) break def _on_editable_change(self, event=None): """Receive layer model editable change event & enable/disable buttons. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method. """ disable_with_opacity( self, ['pick_button', 'paint_button', 'fill_button'], self.layer.editable, )
class AnimationWindow(PyDialog): """ +-------------------+ | Animation | +-------------------------+ | icase ______ | | scale ______ Default | | time ______ Default | | | | nframes ______ Default | | resolu. ______ Default | | Dir ______ Browse | | iFrame ______ | | | | Animations: | | o Scale, Phase, Time | | | | x delete images | | x repeat | # TODO: change to an integer | x make gif | | | | Step, RunAll | | Close | +-------------------------+ TODO: add key-frame support """ def __init__(self, data, win_parent=None): PyDialog.__init__(self, data, win_parent) self.set_font_size(data['font_size']) self.istep = 0 self._animate_type = 'time' self._updated_animation = False self._active_deformation = 0. self._icase_fringe = data['icase_fringe'] self._icase_disp = data['icase_disp'] self._icase_vector = data['icase_vector'] self._default_name = data['name'] self._default_time = data['time'] self._default_fps = data['frames/sec'] self._default_resolution = data['resolution'] self._scale = data['scale'] self._default_scale = data['default_scale'] self._default_is_scale = data['is_scale'] self._arrow_scale = data['arrow_scale'] self._default_arrow_scale = data['default_arrow_scale'] self._phase = data['phase'] self._default_phase = data['default_phase'] self._default_dirname = data['dirname'] self._default_gif_name = os.path.join(self._default_dirname, data['name'] + '.gif') self.animation_types = [ 'Animate Scale', ] #'Animate Phase', #'Animate Time', #'Animate Frequency Sweep' #] self.setWindowTitle('Animate Model') self.create_widgets() self.create_layout() self.set_connections() self.is_gui = False if hasattr(self.win_parent, '_updated_legend'): self.win_parent.is_animate_open = True self.is_gui = True self.on_update_min_max_defaults() def create_widgets(self): """creates the menu objects""" self.box_scale = QGroupBox('Animate Scale') self.box_time = QGroupBox('Animate Time') icase_max = 1000 # TODO: update 1000 self.checkbox_fringe = QCheckBox('Animate') self.checkbox_fringe.setToolTip( 'Animate the fringe in addition to the deflection') #self.checkbox_disp = QCheckBox('Animate') self.checkbox_fringe.setEnabled(False) self.icase_fringe_label = QLabel("iCase (Fringe):") self.icase_fringe_edit = QSpinBox(self) self.icase_fringe_edit.setRange(0, icase_max) self.icase_fringe_edit.setSingleStep(1) if self._icase_fringe is not None: self.icase_fringe_edit.setValue(self._icase_fringe) self.icase_fringe_edit.setToolTip( 'Case Number for the Scale/Phase Animation Type.\n' 'Defaults to the result you had shown when you clicked "Create Animation".\n' 'iCase can be seen by clicking "Apply" on a result.') self.icase_disp_label = QLabel("iCase (Disp):") self.icase_disp_edit = QSpinBox(self) self.icase_disp_edit.setRange(1, icase_max) self.icase_disp_edit.setSingleStep(1) if self._icase_disp is not None: self.icase_disp_edit.setValue(self._icase_disp) self.checkbox_vector = QCheckBox('Animate') self.checkbox_vector.setToolTip( 'Animate the vector in addition to the deflection') self.checkbox_vector.hide() #self.checkbox_disp = QCheckBox('Animate') self.icase_vector_label = QLabel("iCase (Vector):") self.icase_vector_edit = QSpinBox(self) self.icase_vector_edit.setRange(1, icase_max) self.icase_vector_edit.setSingleStep(1) if self._icase_vector is not None: self.icase_vector_edit.setValue(self._icase_vector) self.scale_label = QLabel("True Scale:") self.scale_edit = QLineEdit(str(self._scale)) self.scale_button = QPushButton("Default") self.scale_edit.setToolTip('Scale factor of the "deflection"') self.scale_button.setToolTip('Sets the scale factor of the gif to %s' % self._scale) self.arrow_scale_label = QLabel("Arrow Scale:") self.arrow_scale_edit = QLineEdit(str(self._scale)) self.arrow_scale_button = QPushButton("Default") self.arrow_scale_edit.setToolTip('Scale factor of the "arrows"') self.arrow_scale_button.setToolTip( 'Sets the arrow scale factor of the gif to %s' % self._arrow_scale) self.arrow_scale_label.setVisible(False) self.arrow_scale_edit.setVisible(False) self.arrow_scale_button.setVisible(False) self.time_label = QLabel("Total Time (sec):") self.time_edit = QDoubleSpinBox(self) self.time_edit.setValue(self._default_time) self.time_edit.setRange(0.1, 5. * 60.) self.time_edit.setDecimals(2) self.time_edit.setSingleStep(0.1) self.time_button = QPushButton("Default") self.time_edit.setToolTip("Total time of the gif") self.time_button.setToolTip('Sets the total time of the gif to %.2f' % self._default_time) self.fps_label = QLabel("Frames/Second:") self.fps_edit = QSpinBox(self) self.fps_edit.setRange(1, 60) self.fps_edit.setSingleStep(1) self.fps_edit.setValue(self._default_fps) self.fps_button = QPushButton("Default") self.fps_edit.setToolTip( "A higher FPS is smoother, but may not play well for large gifs") self.fps_button.setToolTip('Sets the FPS to %s' % self._default_fps) self.resolution_label = QLabel("Resolution Scale:") self.resolution_edit = QSpinBox(self) self.resolution_edit.setRange(1, 5) self.resolution_edit.setSingleStep(1) self.resolution_edit.setValue(self._default_resolution) self.resolution_button = QPushButton("Default") self.resolution_edit.setToolTip( 'Scales the window resolution by an integer factor') self.resolution_button.setToolTip('Sets the resolution to %s' % self._default_resolution) #----------------- # Time plot self.fringe_label = QLabel("Fringe") self.icase_fringe_start_edit = QSpinBox(self) self.icase_fringe_start_edit.setRange(0, icase_max) self.icase_fringe_start_edit.setSingleStep(1) self.icase_fringe_start_edit.setValue(self._icase_fringe) self.icase_fringe_start_button = QPushButton("Default") self.icase_fringe_end_edit = QSpinBox(self) self.icase_fringe_end_edit.setRange(0, icase_max) self.icase_fringe_end_edit.setSingleStep(1) self.icase_fringe_end_edit.setValue(self._icase_fringe) self.icase_fringe_end_button = QPushButton("Default") self.icase_fringe_delta_edit = QSpinBox(self) self.icase_fringe_delta_edit.setRange(1, icase_max) self.icase_fringe_delta_edit.setSingleStep(1) self.icase_fringe_delta_edit.setValue(1) self.icase_fringe_delta_button = QPushButton("Default") self.displacement_label = QLabel("Displacement") self.icase_start = QLabel("iCase Start:") self.icase_disp_start_edit = QSpinBox(self) self.icase_disp_start_edit.setRange(0, icase_max) self.icase_disp_start_edit.setSingleStep(1) self.icase_disp_start_edit.setValue(self._icase_fringe) self.icase_disp_start_button = QPushButton("Default") self.icase_end_label = QLabel("iCase End:") self.icase_disp_end_edit = QSpinBox(self) self.icase_disp_end_edit.setRange(0, icase_max) self.icase_disp_end_edit.setSingleStep(1) self.icase_disp_end_edit.setValue(self._icase_fringe) self.icase_disp_end_button = QPushButton("Default") self.icase_delta_label = QLabel("iCase Delta:") self.icase_disp_delta_edit = QSpinBox(self) self.icase_disp_delta_edit.setRange(1, icase_max) self.icase_disp_delta_edit.setSingleStep(1) self.icase_disp_delta_edit.setValue(1) self.icase_disp_delta_button = QPushButton("Default") self.min_value_enable = QCheckBox() self.min_value_label = QLabel("Min Value:") self.min_value_edit = QLineEdit('') #self.min_value_edit.setRange(1, 1000) #self.min_value_edit.setSingleStep(1) #self.min_value_edit.setValue(1) self.min_value_button = QPushButton("Default") self.max_value_enable = QCheckBox() self.max_value_label = QLabel("Max Value:") self.max_value_edit = QLineEdit('') #self.min_value_edit.setRange(1, 1000) # TODO: update 1000 #self.min_value_edit.setSingleStep(1) #self.min_value_edit.setValue(1) self.max_value_button = QPushButton("Default") # TODO: enable this (uncomment) ------------------------------------------ #self.min_value_enable.hide() #self.min_value.hide() #self.min_value_edit.hide() #self.min_value_button.hide() #self.max_value_enable.hide() #self.max_value.hide() #self.max_value_edit.hide() #self.max_value_button.hide() # TODO: enable this (uncomment) ------------------------------------------ self.icase_disp_start_edit.setToolTip( 'The first frame of the animation') self.icase_disp_end_edit.setToolTip( 'The last frame of the animation\n' 'Assumes icase_start + nframes * icase_delta = icase_end') self.icase_disp_delta_edit.setToolTip( 'The frame step size (to skip non-consecutive results).\n' 'Frame skipping can be used to:\n' " - skip across results that you don't want to plot\n" ' - adjust the FPS') self.min_value_edit.setToolTip( 'Min value of the legend (not supported)') self.max_value_edit.setToolTip( 'Max value of the legend (not supported)') #'time' : 0., #'default_time' : 0, #'icase_start' : 10, #'icase_delta' : 3, #'min_value' : 0., #'max_value' : 1000., self.browse_folder_label = QLabel('Output Directory:') self.browse_folder_edit = QLineEdit(str(self._default_dirname)) self.browse_folder_button = QPushButton('Browse') self.browse_folder_edit.setToolTip( 'Location to save the png/gif files') self.gif_label = QLabel("Gif Filename:") self.gif_edit = QLineEdit(str(self._default_name + '.gif')) self.gif_button = QPushButton('Default') self.gif_edit.setToolTip('Name of the gif') self.gif_button.setToolTip('Sets the name of the gif to %s.gif' % self._default_name) # scale / phase if 1: # pragma: no cover self.animate_scale_radio = QRadioButton("Animate Scale") self.animate_phase_radio = QRadioButton("Animate Phase") self.animate_time_radio = QRadioButton("Animate Time") self.animate_freq_sweeep_radio = QRadioButton( "Animate Frequency Sweep") self.animate_scale_radio.setToolTip( 'Animates the scale factor based on the "Animation Type"') self.animate_time_radio.setToolTip( 'Animates the time/load/mode step') self.animate_scale_radio.setChecked(self._default_is_scale) self.animate_phase_radio.setChecked(not self._default_is_scale) self.animate_time_radio.setChecked(False) msg = 'Scale : Animates the scale factor based on the "Animation Profile"\n' if self._default_phase is None: self.animate_phase_radio.setDisabled(True) self.animate_phase_radio.setToolTip( 'Animates the phase angle ' '(only for complex results)') msg += 'Phase : Animates the phase angle (only for complex results)\n' else: self.animate_phase_radio.setToolTip("Animates the phase angle") msg += 'Phase : Animates the phase angle\n' msg += ( 'Time : Animates the time/load/mode step\n' 'Freq Sweep : Animates a complex result across a range of frequencies ' '(not supported)\n') self.animate_freq_sweeep_radio.setDisabled(True) self.animate_freq_sweeep_radio.setToolTip( 'Animates a complex result across a range of frequencies (not supported)' ) else: msg = 'Scale : Animates the scale factor based on the "Animation Profile"\n' if self._default_phase is None: #self.animate_phase_radio.setDisabled(True) #self.animate_phase_radio.setToolTip('Animates the phase angle ' #'(only for complex results)') msg += 'Phase : Animates the phase angle (only for complex results)\n' else: #self.animate_phase_radio.setToolTip("Animates the phase angle") msg += 'Phase : Animates the phase angle\n' msg += ( 'Time : Animates the time/load/mode step\n' 'Freq Sweep : Animates a complex result across a range of frequencies ' '(not supported)\n') self.animation_type = QLabel("Animation Type:") animation_type = OrderedDict() #scale_msg = 'Scale\n' #phase_msg = 'Phase\n' #time_msg = 'Time\n' #animation_types = [ #('Animate Scale', scale_msg), #('Animate Phase', phase_msg), #('Animate Time', time_msg), ##'Animate Frequency Sweep' #] if self._phase is not None: self.animation_types.append('Animate Phase') self.animation_types.append('Animate Time') self.animation_profile_label = QLabel("Animation Profile:") self.animation_profile_edit = QComboBox() for animation_profile in ANIMATION_PROFILES: self.animation_profile_edit.addItem(animation_profile) self.animation_profile_edit.setToolTip('The profile for a scaled GIF') self.animation_type_edit = QComboBox() # TODO: add a tooltip for each item for animation_type in self.animation_types: self.animation_type_edit.addItem(animation_type) #self.animation_type_edit.setToolTip('The profile for a scaled GIF') self.animation_type_edit.setToolTip(msg.rstrip()) self.csv_profile_label = QLabel("CSV profile:") self.csv_profile_edit = QLineEdit() self.csv_profile_browse_button = QPushButton('Browse') self.csv_profile_edit.setToolTip( 'The path to the CSV file of (Scale1, Scale2, Scale3, ...)') #widget = QWidget(self) #horizontal_vertical_group = QButtonGroup(widget) #horizontal_vertical_group.addButton(self.animate_scale_radio) #horizontal_vertical_group.addButton(self.animate_phase_radio) #horizontal_vertical_group.addButton(self.animate_time_radio) #horizontal_vertical_group.addButton(self.animate_freq_sweeep_radio) # animate in gui self.animate_in_gui_checkbox = QCheckBox("Animate In GUI?") self.animate_in_gui_checkbox.setChecked(True) # make images self.make_images_checkbox = QCheckBox("Make images?") self.make_images_checkbox.setChecked(True) # make images self.overwrite_images_checkbox = QCheckBox("Overwrite images?") self.overwrite_images_checkbox.setChecked(True) # delete images when finished self.delete_images_checkbox = QCheckBox("Delete images when finished?") self.delete_images_checkbox.setChecked(True) # endless loop self.repeat_checkbox = QCheckBox("Repeat?") self.repeat_checkbox.setChecked(True) self.repeat_checkbox.setToolTip( "Repeating creates an infinitely looping gif") # endless loop self.make_gif_checkbox = QCheckBox("Make Gif?") if IS_IMAGEIO: self.make_gif_checkbox.setChecked(True) else: self.make_gif_checkbox.setChecked(False) self.make_gif_checkbox.setEnabled(False) self.make_gif_checkbox.setToolTip( 'imageio is not available; install it') # bottom buttons self.step_button = QPushButton("Step") self.wipe_button = QPushButton("Wipe Deformed Shape") self.stop_button = QPushButton("Stop") self.run_button = QPushButton("Run") self.step_button.setToolTip( 'Steps through the animation (for testing)') self.wipe_button.setToolTip( 'Removes the existing "deflecton" from the animation') self.stop_button.setToolTip('Stops the animation') self.run_button.setToolTip('Creates the animation') self.step_button.hide() self.wipe_button.hide() self.wipe_button.setEnabled(False) #self.wipe_button.hide() self.stop_button.setEnabled(False) self.cancel_button = QPushButton("Close") #self.set_grid_time(enabled=False) #self.set_grid_scale(enabled=self._default_is_scale) if self._default_phase: self.on_animate_phase(force=True) set_combo_box_text(self.animation_type_edit, 'Animate Phase') else: self.on_animate_scale(force=True) def set_connections(self): """creates button actions""" self.checkbox_vector.clicked.connect(self.on_checkbox_vector) self.scale_button.clicked.connect(self.on_default_scale) self.arrow_scale_button.clicked.connect(self.on_default_arrow_scale) self.time_button.clicked.connect(self.on_default_time) self.fps_button.clicked.connect(self.on_default_fps) self.resolution_button.clicked.connect(self.on_default_resolution) self.browse_folder_button.clicked.connect(self.on_browse_folder) self.csv_profile_browse_button.clicked.connect(self.on_browse_csv) self.gif_button.clicked.connect(self.on_default_name) self.step_button.clicked.connect(self.on_step) self.wipe_button.clicked.connect(self.on_wipe) self.stop_button.clicked.connect(self.on_stop) self.run_button.clicked.connect(self.on_run) self.min_value_enable.clicked.connect(self.on_min_value_enable) self.max_value_enable.clicked.connect(self.on_max_value_enable) self.min_value_button.clicked.connect(self.on_min_value_default) self.max_value_button.clicked.connect(self.on_max_value_default) self.icase_disp_start_button.clicked.connect( self.on_update_min_max_defaults) #self.animate_scale_radio.clicked.connect(self.on_animate_scale) #self.animate_phase_radio.clicked.connect(self.on_animate_phase) #self.animate_time_radio.clicked.connect(self.on_animate_time) self.animation_type_edit.currentIndexChanged.connect(self.on_animate) #self.animate_freq_sweeep_radio self.cancel_button.clicked.connect(self.on_cancel) self.animate_in_gui_checkbox.clicked.connect(self.on_animate_in_gui) self.animate_in_gui_checkbox.setChecked(True) self.on_animate_in_gui() def on_checkbox_vector(self): is_enabled = self.checkbox_vector.isEnabled() is_checked = self.checkbox_vector.isChecked() enable_edit = is_enabled and is_checked self.icase_vector_label.setEnabled(is_checked) self.icase_vector_edit.setEnabled(enable_edit) def on_animate_in_gui(self): animate_in_gui = self.animate_in_gui_checkbox.isChecked() enable = not animate_in_gui if HIDE_WHEN_INACTIVE: self.make_images_checkbox.setVisible(enable) self.delete_images_checkbox.setVisible(enable) self.make_gif_checkbox.setVisible(enable) self.repeat_checkbox.setVisible(enable) self.resolution_button.setVisible(enable) self.resolution_label.setVisible(enable) self.resolution_edit.setVisible(enable) self.gif_label.setVisible(enable) self.gif_edit.setVisible(enable) self.gif_button.setVisible(enable) self.browse_folder_label.setVisible(enable) self.browse_folder_button.setVisible(enable) self.browse_folder_edit.setVisible(enable) self.step_button.setEnabled(enable) self.make_images_checkbox.setEnabled(enable) self.delete_images_checkbox.setEnabled(enable) self.make_gif_checkbox.setEnabled(enable) self.repeat_checkbox.setEnabled(enable) self.resolution_button.setEnabled(enable) self.resolution_edit.setEnabled(enable) self.gif_edit.setEnabled(enable) self.gif_button.setEnabled(enable) self.browse_folder_button.setEnabled(enable) self.browse_folder_edit.setEnabled(enable) self.step_button.setEnabled(enable) #wipe_button def on_animate(self, value): """ animate pulldown Parameters ---------- value : int index in animation_types """ #animation_types = ['Animate Scale', 'Animate Phase', 'Animate Time', #'Animate Frequency Sweep'] animation_type = self.animation_types[value] if animation_type == 'Animate Scale': self.on_animate_scale() elif animation_type == 'Animate Phase': self.on_animate_phase() elif animation_type == 'Animate Time': self.on_animate_time() else: raise NotImplementedError('value = ', value) def on_animate_time(self, force=False): """enables the secondary input""" #print('on_animate_time') if self._animate_type == 'scale' or force: self.set_grid_scale(False, 'time') self.set_grid_time(True, 'time') self._animate_type = 'time' def on_animate_scale(self, force=False): """enables the secondary input""" #print('on_animate_scale') self.set_grid_scale(True, 'scale') if self._animate_type == 'time' or force: self.set_grid_time(False, 'scale') self._animate_type = 'scale' def on_animate_phase(self, force=False): """enables the secondary input""" #print('on_animate_phase') if self._animate_type == 'scale' or force: self.set_grid_scale(False, 'phase') if self._animate_type == 'time' or force: self.set_grid_time(False, 'phase') self._animate_type = 'phase' def set_grid_scale(self, enabled=True, word=''): """enables/disables the secondary input""" #print('%s-set_grid_scale; enabled = %r' % (word, enabled)) if HIDE_WHEN_INACTIVE: self.box_scale.setVisible(enabled) self.animation_profile_label.setVisible(enabled) self.animation_profile_edit.setVisible(enabled) #self.min_value_enable.setVisible(enabled) #self.max_value_enable.setVisible(enabled) self.animation_profile_label.setEnabled(enabled) self.animation_profile_edit.setEnabled(enabled) # TODO: doesn't work... #self.csv_profile.setEnabled(enabled) #self.csv_profile_edit.setEnabled(enabled) #self.csv_profile_button.setEnabled(enabled) self.min_value_enable.setEnabled(enabled) self.max_value_enable.setEnabled(enabled) self.on_min_value_enable() self.on_max_value_enable() def set_grid_time(self, enabled=True, word=''): """enables/disables the secondary input""" #print('%s-set_grid_time; enabled = %r' % (word, enabled)) if HIDE_WHEN_INACTIVE: self.box_time.setVisible(enabled) self.checkbox_fringe.setVisible(not enabled) self.icase_fringe_label.setVisible(not enabled) self.icase_fringe_edit.setVisible(not enabled) self.icase_disp_label.setVisible(not enabled) self.icase_disp_edit.setVisible(not enabled) self.icase_vector_label.setVisible(not enabled) self.icase_vector_edit.setVisible(not enabled) #self.icase_fringe_delta_edit.setVisible(enabled) self.icase_disp_delta_edit.setVisible(enabled) self.icase_disp_delta_edit.setVisible(enabled) self.fps_label.setVisible(enabled) self.fps_edit.setVisible(enabled) self.fps_button.setVisible(enabled) self.displacement_label.setEnabled(enabled) self.fringe_label.setEnabled(enabled) self.icase_start.setEnabled(enabled) self.icase_disp_start_edit.setEnabled(enabled) self.icase_disp_start_button.setEnabled(enabled) self.icase_fringe_start_edit.setEnabled(enabled) self.icase_fringe_start_button.setEnabled(enabled) self.icase_end_label.setEnabled(enabled) self.icase_disp_end_edit.setEnabled(enabled) self.icase_disp_end_button.setEnabled(enabled) self.icase_fringe_end_edit.setEnabled(enabled) self.icase_fringe_end_button.setEnabled(enabled) self.icase_delta_label.setEnabled(enabled) self.icase_disp_delta_edit.setEnabled(enabled) self.icase_disp_delta_button.setEnabled(enabled) self.icase_fringe_delta_edit.setEnabled(enabled) self.icase_fringe_delta_button.setEnabled(enabled) #----------------------------------------------------------------------- is_min_enabled = self.min_value_enable.isChecked() self.min_value_label.setEnabled(is_min_enabled) self.min_value_edit.setEnabled(is_min_enabled) self.min_value_button.setEnabled(is_min_enabled) is_max_enabled = self.max_value_enable.isChecked() self.max_value_label.setEnabled(is_max_enabled) self.max_value_edit.setEnabled(is_max_enabled) self.max_value_button.setEnabled(is_max_enabled) self.min_value_enable.setEnabled(enabled) self.on_min_value_enable() #self.min_value.setEnabled(enabled) #self.min_value_edit.setEnabled(enabled) #self.min_value_button.setEnabled(enabled) self.max_value_enable.setEnabled(enabled) self.on_max_value_enable() #self.max_value.setEnabled(enabled) #self.max_value_edit.setEnabled(enabled) #self.max_value_button.setEnabled(enabled) self.icase_fringe_label.setEnabled(not enabled) self.icase_fringe_edit.setEnabled(not enabled) self.checkbox_fringe.setEnabled(not enabled) self.icase_disp_label.setEnabled(not enabled) self.icase_disp_edit.setEnabled(not enabled) self.icase_vector_label.setEnabled(not enabled) self.icase_vector_edit.setEnabled(not enabled) self.checkbox_vector.setEnabled(not enabled) self.on_checkbox_vector() self.fps_label.setEnabled(not enabled) self.fps_edit.setEnabled(not enabled) self.fps_button.setEnabled(not enabled) def on_min_value_enable(self): """ The min edit value box is enabled when we switch to time and the box is checked """ is_min_enabled = self.min_value_enable.isChecked( ) and self.min_value_enable.isEnabled() self.min_value_label.setEnabled(is_min_enabled) self.min_value_edit.setEnabled(is_min_enabled) self.min_value_button.setEnabled(is_min_enabled) def on_max_value_enable(self): """ The max edit value box is enabled when we switch to time and the box is checked """ is_max_enabled = self.max_value_enable.isChecked( ) and self.max_value_enable.isEnabled() self.max_value_label.setEnabled(is_max_enabled) self.max_value_edit.setEnabled(is_max_enabled) self.max_value_button.setEnabled(is_max_enabled) def on_update_min_max_defaults(self): """ When the icase is changed, the min/max value default message is changed """ icase = self.icase_disp_start_edit.value() min_value, max_value = self.get_min_max(icase) self.min_value_button.setToolTip('Sets the min value to %g' % min_value) self.max_value_button.setToolTip('Sets the max value to %g' % max_value) def on_min_value_default(self): """When min default icase is pressued, update the value""" icase = self.icase_disp_start_edit.value() min_value = self.get_min_max(icase)[0] self.min_value_edit.setText(str(min_value)) self.min_value_edit.setStyleSheet("QLineEdit{background: white;}") def on_max_value_default(self): """When max default icase is pressued, update the value""" icase = self.icase_disp_start_edit.value() max_value = self.get_min_max(icase)[1] self.max_value_edit.setText(str(max_value)) self.max_value_edit.setStyleSheet("QLineEdit{background: white;}") def on_browse_folder(self): """opens a folder dialog""" dirname = getexistingdirectory(parent=self, caption='Select a Directory', basedir='', options=QFileDialog.ShowDirsOnly) if not dirname: return self.browse_folder_edit.setText(dirname) def on_browse_csv(self): """opens a file dialog""" default_filename = '' file_types = 'Delimited Text (*.txt; *.dat; *.csv)' dirname = open_file_dialog(self, 'Select a CSV File', default_filename, file_types) if not dirname: return self.csv_profile_browse_button.setText(dirname) def on_default_name(self): """sets the default gif name""" self.gif_edit.setText(self._default_name + '.gif') def on_default_scale(self): """sets the default displacement scale factor""" self.scale_edit.setText(str(self._default_scale)) self.scale_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_arrow_scale(self): """sets the default arrow scale factor""" self.arrow_scale_edit.setText(str(self._default_arrow_scale)) self.arrow_scale_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_time(self): """sets the default gif time""" self.time_edit.setValue(self._default_time) def on_default_fps(self): """sets the default FPS""" self.fps_edit.setValue(self._default_fps) def on_default_resolution(self): """sets the default image resolution scale factor""" self.resolution_edit.setValue(self._default_resolution) def create_layout(self): """displays the menu objects""" grid = QGridLayout() irow = 0 grid.addWidget(self.icase_fringe_label, irow, 0) grid.addWidget(self.icase_fringe_edit, irow, 1) grid.addWidget(self.checkbox_fringe, irow, 2) irow += 1 grid.addWidget(self.icase_disp_label, irow, 0) grid.addWidget(self.icase_disp_edit, irow, 1) #grid.addWidget(self.checkbox_disp, irow, 2) irow += 1 grid.addWidget(self.icase_vector_label, irow, 0) grid.addWidget(self.icase_vector_edit, irow, 1) grid.addWidget(self.checkbox_vector, irow, 2) irow += 1 grid.addWidget(self.scale_label, irow, 0) grid.addWidget(self.scale_edit, irow, 1) grid.addWidget(self.scale_button, irow, 2) irow += 1 grid.addWidget(self.arrow_scale_label, irow, 0) grid.addWidget(self.arrow_scale_edit, irow, 1) grid.addWidget(self.arrow_scale_button, irow, 2) irow += 1 grid.addWidget(self.time_label, irow, 0) grid.addWidget(self.time_edit, irow, 1) grid.addWidget(self.time_button, irow, 2) irow += 1 # spacer spacer = QLabel('') grid.addWidget(self.fps_label, irow, 0) grid.addWidget(self.fps_edit, irow, 1) grid.addWidget(self.fps_button, irow, 2) irow += 1 grid.addWidget(self.animation_type, irow, 0) grid.addWidget(self.animation_type_edit, irow, 1) irow += 1 grid.addWidget(spacer, irow, 0) irow += 1 #---------- #Time grid_time = QGridLayout() jrow = 0 self.fringe_label.setAlignment(Qt.AlignCenter) self.displacement_label.setAlignment(Qt.AlignCenter) if not IS_TIME_FRINGE: self.fringe_label.hide() self.icase_fringe_delta_edit.hide() self.icase_fringe_start_edit.hide() self.icase_fringe_end_edit.hide() self.icase_fringe_delta_button.hide() grid_time.addWidget(self.displacement_label, jrow, 1) grid_time.addWidget(self.fringe_label, jrow, 2) jrow += 1 grid_time.addWidget(self.icase_start, jrow, 0) grid_time.addWidget(self.icase_disp_start_edit, jrow, 1) grid_time.addWidget(self.icase_fringe_start_edit, jrow, 2) #grid_time.addWidget(self.icase_disp_start_button, jrow, 2) jrow += 1 grid_time.addWidget(self.icase_end_label, jrow, 0) grid_time.addWidget(self.icase_disp_end_edit, jrow, 1) grid_time.addWidget(self.icase_fringe_end_edit, jrow, 2) #grid_time.addWidget(self.icase_end_button, jrow, 2) jrow += 1 grid_time.addWidget(self.icase_delta_label, jrow, 0) grid_time.addWidget(self.icase_disp_delta_edit, jrow, 1) grid_time.addWidget(self.icase_fringe_delta_edit, jrow, 2) #grid_time.addWidget(self.icase_delta_button, jrow, 2) jrow += 1 hbox_min = QHBoxLayout() hbox_min.addWidget(self.min_value_enable) hbox_min.addWidget(self.min_value_label) grid_time.addLayout(hbox_min, jrow, 0) grid_time.addWidget(self.min_value_edit, jrow, 1) grid_time.addWidget(self.min_value_button, jrow, 2) jrow += 1 hbox_max = QHBoxLayout() hbox_max.addWidget(self.max_value_enable) hbox_max.addWidget(self.max_value_label) grid_time.addLayout(hbox_max, jrow, 0) grid_time.addWidget(self.max_value_edit, jrow, 1) grid_time.addWidget(self.max_value_button, jrow, 2) jrow += 1 grid_time.addWidget(spacer, jrow, 0) jrow += 1 #-------------- grid_scale = QGridLayout() grid_scale.addWidget(self.animation_profile_label, 0, 0) grid_scale.addWidget(self.animation_profile_edit, 0, 1) #grid_scale.addWidget(self.csv_profile, 1, 0) #grid_scale.addWidget(self.csv_profile_edit, 1, 1) #grid_scale.addWidget(self.csv_profile_browse_button, 1, 2) self.csv_profile = QLabel("CSV profile:") self.csv_profile_edit = QLineEdit() self.csv_profile_button = QPushButton('Browse') #box_time = QVBoxLayout() # TODO: It's super annoying that the animate time box doesn't # line up with the previous box self.box_scale.setLayout(grid_scale) self.box_time.setLayout(grid_time) #---------- grid2 = QGridLayout() irow = 0 #grid2.addWidget(self.animate_scale_radio, 8, 0) #grid2.addWidget(self.animate_phase_radio, 8, 1) #grid2.addWidget(self.animate_time_radio, 8, 2) #grid2.addWidget(self.animate_freq_sweeep_radio, 8, 3) grid2.addWidget(self.animate_in_gui_checkbox, irow, 0) irow += 1 grid2.addWidget(self.resolution_label, irow, 0) grid2.addWidget(self.resolution_edit, irow, 1) grid2.addWidget(self.resolution_button, irow, 2) irow += 1 grid2.addWidget(self.browse_folder_label, irow, 0) grid2.addWidget(self.browse_folder_edit, irow, 1) grid2.addWidget(self.browse_folder_button, irow, 2) irow += 1 grid2.addWidget(self.gif_label, irow, 0) grid2.addWidget(self.gif_edit, irow, 1) grid2.addWidget(self.gif_button, irow, 2) irow += 1 grid2.addWidget(self.make_images_checkbox, irow, 0) #grid2.addWidget(self.overwrite_images_checkbox, irow, 0) grid2.addWidget(self.delete_images_checkbox, irow, 1) grid2.addWidget(self.make_gif_checkbox, irow, 2) irow += 1 grid2.addWidget(self.repeat_checkbox, irow, 0) irow += 1 grid2.addWidget(spacer, irow, 0) grid_hbox = QHBoxLayout() grid_hbox.addWidget(spacer) grid_hbox.addLayout(grid2) grid_hbox.addWidget(spacer) # bottom buttons step_run_box = QHBoxLayout() step_run_box.addWidget(self.step_button) step_run_box.addWidget(self.wipe_button) step_run_box.addWidget(self.stop_button) step_run_box.addWidget(self.run_button) ok_cancel_box = QHBoxLayout() ok_cancel_box.addWidget(self.cancel_button) vbox = QVBoxLayout() vbox.addLayout(grid) vbox.addWidget(self.box_scale) vbox.addWidget(self.box_time) #vbox.addLayout(checkboxes) vbox.addLayout(grid_hbox) vbox.addStretch() vbox.addLayout(step_run_box) vbox.addLayout(ok_cancel_box) self.setLayout(vbox) def on_step(self): """click the Step button""" passed, validate_out = self.on_validate() if passed: try: self._make_gif(validate_out, istep=self.istep) self.istep += 1 except IndexError: self._make_gif(validate_out, istep=0) self.istep += 1 self.wipe_button.setEnabled(True) def on_wipe(self): """click the Wipe button""" passed, validate_out = self.on_validate(wipe=True) if passed: self.istep = 0 self._make_gif(validate_out, istep=self.istep) self.wipe_button.setEnabled(False) self.stop_button.setEnabled(False) def on_stop(self): """click the Stop button""" #passed, validate_out = self.on_validate() #if passed: #self._make_gif(validate_out, stop_animation=True) if self.is_gui: self.win_parent.win_parent.stop_animation() self.wipe_button.setEnabled(True) self.stop_button.setEnabled(False) def on_run(self): """click the Run button""" self.istep = 0 self.wipe_button.setEnabled(False) self.stop_button.setEnabled(True) passed, validate_out = self.on_validate() if passed: self._make_gif(validate_out, istep=None) return passed def _make_gif(self, validate_out, istep=None, stop_animation=False): """interface for making the gif""" (icase_fringe, icase_disp, icase_vector, scale, time, fps, animate_in_gui, magnify, output_dir, gifbase, min_value, max_value) = validate_out fps = int(fps) gif_filename = None if not stop_animation and not animate_in_gui and gifbase is not None: if gifbase.lower().endswith('.gif'): gifbase = gifbase[:-4] gif_filename = os.path.join(output_dir, gifbase + '.gif') animate_fringe = self.checkbox_fringe.isChecked() animate_vector = self.checkbox_vector.isChecked() animate_scale = self.animate_scale_radio.isChecked() animate_phase = self.animate_phase_radio.isChecked() animate_time = self.animate_time_radio.isChecked() if not self.checkbox_vector.isEnabled(): icase_vector = None animate_scale = False animate_phase = False animate_time = False if self._animate_type == 'scale': animate_scale = True elif self._animate_type == 'phase': animate_phase = True elif self._animate_type == 'time': animate_time = True else: raise NotImplementedError(self._animate_type) make_images = self.make_images_checkbox.isChecked() delete_images = self.delete_images_checkbox.isChecked() make_gif = self.make_gif_checkbox.isChecked() animation_profile = str(self.animation_profile_edit.currentText()) icase_disp_start = self.icase_disp_start_edit.value() icase_disp_end = self.icase_disp_end_edit.value() icase_disp_delta = self.icase_disp_delta_edit.value() bool_repeat = self.repeat_checkbox.isChecked( ) # TODO: change this to an integer if bool_repeat: nrepeat = 0 else: nrepeat = 1 #self.out_data['is_shown'] = self.show_radio.isChecked() #icase = self._icase if self.is_gui: self.win_parent.win_parent.make_gif( gif_filename, scale, istep=istep, animate_scale=animate_scale, animate_phase=animate_phase, animate_time=animate_time, icase_fringe=icase_fringe, icase_disp=icase_disp, icase_vector=icase_vector, animate_fringe=animate_fringe, animate_vector=animate_vector, icase_start=icase_disp_start, icase_end=icase_disp_end, icase_delta=icase_disp_delta, time=time, animation_profile=animation_profile, nrepeat=nrepeat, fps=fps, magnify=magnify, make_images=make_images, delete_images=delete_images, make_gif=make_gif, stop_animation=stop_animation, animate_in_gui=animate_in_gui, min_value=min_value, max_value=max_value, ) self.out_data['clicked_ok'] = True self.out_data['close'] = True def get_min_max(self, icase): if self.is_gui: (obj, (i, name)) = self.win_parent.win_parent.result_cases[icase] min_value, max_value = obj.get_min_max(i, name) else: return 0., 1.0 return min_value, max_value def on_validate(self, wipe=False): """checks to see if the input is valid""" # requires no special validation icase_fringe, flag0 = check_int(self.icase_fringe_edit) icase_disp, unused_flaga = check_int(self.icase_disp_edit) icase_vector, unused_flagb = check_int(self.icase_vector_edit) #icase_disp = self._icase_disp #icase_vector = self._icase_vector scale, flag1 = check_float(self.scale_edit) time, flag2 = check_float(self.time_edit) fps, flag3 = check_float(self.fps_edit) min_value = max_value = None flag4 = flag5 = True if self.min_value_edit.isEnabled(): min_value, flag4 = check_float(self.min_value_edit) if self.max_value_edit.isEnabled(): max_value, flag5 = check_float(self.max_value_edit) if wipe: animate_in_gui = False scale = 0. flag1 = True else: animate_in_gui = self.animate_in_gui_checkbox.isChecked() if animate_in_gui or wipe: passed = all([flag0, flag1, flag2, flag3, flag4, flag5]) magnify, output_dir, gifbase = None, None, None else: magnify, flag6 = check_int(self.resolution_edit) output_dir, flag7 = self.check_path(self.browse_folder_edit) gifbase, flag8 = self.check_name(self.gif_edit) passed = all([ flag0, flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8 ]) return passed, (icase_fringe, icase_disp, icase_vector, scale, time, fps, animate_in_gui, magnify, output_dir, gifbase, min_value, max_value) @staticmethod def check_name(cell): """verifies that the data is string-able""" cell_value = cell.text() try: text = str(cell_value).strip() except UnicodeEncodeError: cell.setStyleSheet("QLineEdit{background: red;}") return None, False if len(text): cell.setStyleSheet("QLineEdit{background: white;}") return text, True else: cell.setStyleSheet("QLineEdit{background: red;}") return None, False def check_path(self, cell): """verifies that the path exists""" text, passed = self.check_name(cell) if not passed: return None, False if os.path.exists(text): cell.setStyleSheet("QLineEdit{background: white;}") return text, True else: cell.setStyleSheet("QLineEdit{background: red;}") return None, False #def on_ok(self): #"""click the OK button""" #passed = self.on_apply() #if passed: #self.win_parent._animation_window_shown = False #self.close() ##self.destroy() def on_cancel(self): """click the Cancel button""" self.on_stop() self.out_data['close'] = True self.close()
def spinbox_changevalue(text): print(text) layout = QVBoxLayout(w) card1 = PSpinBox(w) card1.setMaximumHeight(50) card1.set_range(100, 1051) card1.set_single_step(3) card1.set_text_alignment(Qt.AlignCenter) card1.valueChanged.connect(spinbox_changevalue) card2 = QFrame(w) card3 = QSpinBox(w) card3.setValue(10) card3.setRange(5, 30) card3.setFixedHeight(50) card3.setSingleStep(3) card4 = QLineEdit(w) card4.setFixedHeight(50) validator = QIntValidator(100, 500) card4.setValidator(validator) # print(validator.bottom()) # print(validator.top()) pos = 0 # ret = object # ret = validator.validate("501", pos) # print(ret) # ret = validator.validate("-5", pos) # print(ret == QValidator.Invalid)
class QtLabelsControls(QtLayerControls): """Qt view and controls for the napari Labels layer. Parameters ---------- layer : napari.layers.Labels An instance of a napari Labels layer. Attributes ---------- button_group : qtpy.QtWidgets.QButtonGroup Button group of labels layer modes: PAN_ZOOM, PICKER, PAINT, ERASE, or FILL. colormapUpdate : qtpy.QtWidgets.QPushButton Button to update colormap of label layer. contigCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is contiguous. fill_button : qtpy.QtWidgets.QtModeRadioButton Button to select FILL mode on Labels layer. grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Labels An instance of a napari Labels layer. ndimCheckBox : qtpy.QtWidgets.QCheckBox Checkbox to control if label layer is n-dimensional. paint_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAINT mode on Labels layer. panzoom_button : qtpy.QtWidgets.QtModeRadioButton Button to select PAN_ZOOM mode on Labels layer. pick_button : qtpy.QtWidgets.QtModeRadioButton Button to select PICKER mode on Labels layer. erase_button : qtpy.QtWidgets.QtModeRadioButton Button to select ERASE mode on Labels layer. selectionSpinBox : qtpy.QtWidgets.QSpinBox Widget to select a specific label by its index. Raises ------ ValueError Raise error if label mode is not PAN_ZOOM, PICKER, PAINT, ERASE, or FILL. """ def __init__(self, layer): super().__init__(layer) self.layer.events.mode.connect(self._on_mode_change) self.layer.events.selected_label.connect(self._on_selection_change) self.layer.events.brush_size.connect(self._on_brush_size_change) self.layer.events.contiguous.connect(self._on_contig_change) self.layer.events.n_dimensional.connect(self._on_n_dim_change) self.layer.events.editable.connect(self._on_editable_change) self.layer.events.preserve_labels.connect( self._on_preserve_labels_change ) self.layer.events.color_mode.connect(self._on_color_mode_change) # selection spinbox self.selectionSpinBox = QSpinBox() self.selectionSpinBox.setKeyboardTracking(False) self.selectionSpinBox.setSingleStep(1) self.selectionSpinBox.setMinimum(0) self.selectionSpinBox.setMaximum(2147483647) self.selectionSpinBox.valueChanged.connect(self.changeSelection) self.selectionSpinBox.setAlignment(Qt.AlignCenter) self._on_selection_change() sld = QSlider(Qt.Horizontal) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(1) sld.setMaximum(40) sld.setSingleStep(1) sld.valueChanged.connect(self.changeSize) self.brushSizeSlider = sld self._on_brush_size_change() contig_cb = QCheckBox() contig_cb.setToolTip('contiguous editing') contig_cb.stateChanged.connect(self.change_contig) self.contigCheckBox = contig_cb self._on_contig_change() ndim_cb = QCheckBox() ndim_cb.setToolTip('n-dimensional editing') ndim_cb.stateChanged.connect(self.change_ndim) self.ndimCheckBox = ndim_cb self._on_n_dim_change() preserve_labels_cb = QCheckBox() preserve_labels_cb.setToolTip( 'preserve existing labels while painting' ) preserve_labels_cb.stateChanged.connect(self.change_preserve_labels) self.preserveLabelsCheckBox = preserve_labels_cb self._on_preserve_labels_change() # shuffle colormap button self.colormapUpdate = QtModePushButton( None, 'shuffle', slot=self.changeColor, tooltip='shuffle colors', ) self.panzoom_button = QtModeRadioButton( layer, 'zoom', Mode.PAN_ZOOM, tooltip='Pan/zoom mode (Space)', checked=True, ) self.pick_button = QtModeRadioButton( layer, 'picker', Mode.PICK, tooltip='Pick mode' ) self.paint_button = QtModeRadioButton( layer, 'paint', Mode.PAINT, tooltip='Paint mode' ) btn = 'Cmd' if sys.platform == 'darwin' else 'Ctrl' self.fill_button = QtModeRadioButton( layer, 'fill', Mode.FILL, tooltip=f'Fill mode ({btn})' ) self.erase_button = QtModeRadioButton( layer, 'erase', Mode.ERASE, tooltip='Erase mode (Alt)' ) self.button_group = QButtonGroup(self) self.button_group.addButton(self.panzoom_button) self.button_group.addButton(self.paint_button) self.button_group.addButton(self.pick_button) self.button_group.addButton(self.fill_button) self.button_group.addButton(self.erase_button) self._on_editable_change() button_row = QHBoxLayout() button_row.addStretch(1) button_row.addWidget(self.colormapUpdate) button_row.addWidget(self.erase_button) button_row.addWidget(self.fill_button) button_row.addWidget(self.paint_button) button_row.addWidget(self.pick_button) button_row.addWidget(self.panzoom_button) button_row.setSpacing(4) button_row.setContentsMargins(0, 0, 0, 5) color_mode_comboBox = QComboBox(self) color_mode_comboBox.addItems(LabelColorMode.keys()) index = color_mode_comboBox.findText( self.layer.color_mode, Qt.MatchFixedString ) color_mode_comboBox.setCurrentIndex(index) color_mode_comboBox.activated[str].connect(self.change_color_mode) self.colorModeComboBox = color_mode_comboBox self._on_color_mode_change() color_layout = QHBoxLayout() color_layout.addWidget(QtColorBox(layer)) color_layout.addWidget(self.selectionSpinBox) # grid_layout created in QtLayerControls # addWidget(widget, row, column, [row_span, column_span]) self.grid_layout.addLayout(button_row, 0, 0, 1, 4) self.grid_layout.addWidget(QLabel('label:'), 1, 0, 1, 1) self.grid_layout.addLayout(color_layout, 1, 1, 1, 3) self.grid_layout.addWidget(QLabel('opacity:'), 2, 0, 1, 1) self.grid_layout.addWidget(self.opacitySlider, 2, 1, 1, 3) self.grid_layout.addWidget(QLabel('brush size:'), 3, 0, 1, 1) self.grid_layout.addWidget(self.brushSizeSlider, 3, 1, 1, 3) self.grid_layout.addWidget(QLabel('blending:'), 4, 0, 1, 1) self.grid_layout.addWidget(self.blendComboBox, 4, 1, 1, 3) self.grid_layout.addWidget(QLabel('color mode:'), 5, 0, 1, 1) self.grid_layout.addWidget(self.colorModeComboBox, 5, 1, 1, 3) self.grid_layout.addWidget(QLabel('contiguous:'), 6, 0, 1, 1) self.grid_layout.addWidget(self.contigCheckBox, 6, 1, 1, 1) self.grid_layout.addWidget(QLabel('n-dim:'), 6, 2, 1, 1) self.grid_layout.addWidget(self.ndimCheckBox, 6, 3, 1, 1) self.grid_layout.addWidget(QLabel('preserve labels:'), 7, 0, 1, 2) self.grid_layout.addWidget(self.preserveLabelsCheckBox, 7, 1, 1, 1) self.grid_layout.setRowStretch(8, 1) self.grid_layout.setColumnStretch(1, 1) self.grid_layout.setSpacing(4) def mouseMoveEvent(self, event): """On mouse move, set layer status equal to the current selected mode. Available mode options are: PAN_ZOOM, PICKER, PAINT, ERASE or FILL Parameters ---------- event : qtpy.QtCore.QEvent Event from the Qt context. """ self.layer.status = str(self.layer.mode) def _on_mode_change(self, event): """Receive layer model mode change event and update checkbox ticks. Parameters ---------- event : qtpy.QtCore.QEvent Event from the Qt context. Raises ------ ValueError Raise error if event.mode is not PAN_ZOOM, PICK, PAINT, ERASE, or FILL """ mode = event.mode if mode == Mode.PAN_ZOOM: self.panzoom_button.setChecked(True) elif mode == Mode.PICK: self.pick_button.setChecked(True) elif mode == Mode.PAINT: self.paint_button.setChecked(True) elif mode == Mode.FILL: self.fill_button.setChecked(True) elif mode == Mode.ERASE: self.erase_button.setChecked(True) else: raise ValueError("Mode not recognized") def changeColor(self): """Change colormap of the label layer.""" self.layer.new_colormap() def changeSelection(self, value): """Change currently selected label. Parameters ---------- value : int Index of label to select. """ self.layer.selected_label = value self.selectionSpinBox.clearFocus() self.setFocus() def changeSize(self, value): """Change paint brush size. Parameters ---------- value : float Size of the paint brush. """ self.layer.brush_size = value def change_contig(self, state): """Toggle contiguous state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if labels are contiguous. """ if state == Qt.Checked: self.layer.contiguous = True else: self.layer.contiguous = False def change_ndim(self, state): """Toggle n-dimensional state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if label layer is n-dimensional. """ if state == Qt.Checked: self.layer.n_dimensional = True else: self.layer.n_dimensional = False def change_preserve_labels(self, state): """Toggle preserve_labels state of label layer. Parameters ---------- state : QCheckBox Checkbox indicating if overwriting label is enabled. """ if state == Qt.Checked: self.layer.preserve_labels = True else: self.layer.preserve_labels = False def change_color_mode(self, new_mode): """Change color mode of label layer. Parameters ---------- new_mode : str AUTO (default) allows color to be set via a hash function with a seed. DIRECT allows color of each label to be set directly by a color dictionary. """ self.layer.color_mode = new_mode def _on_selection_change(self, event=None): """Receive layer model label selection change event and update spinbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.selected_label.blocker(): value = self.layer.selected_label self.selectionSpinBox.setValue(int(value)) def _on_brush_size_change(self, event=None): """Receive layer model brush size change event and update the slider. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.brush_size.blocker(): value = self.layer.brush_size value = np.clip(int(value), 1, 40) self.brushSizeSlider.setValue(value) def _on_n_dim_change(self, event=None): """Receive layer model n-dim mode change event and update the checkbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.n_dimensional.blocker(): self.ndimCheckBox.setChecked(self.layer.n_dimensional) def _on_contig_change(self, event=None): """Receive layer model contiguous change event and update the checkbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.contiguous.blocker(): self.contigCheckBox.setChecked(self.layer.contiguous) def _on_preserve_labels_change(self, event=None): """Receive layer model preserve_labels event and update the checkbox. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.preserve_labels.blocker(): self.preserveLabelsCheckBox.setChecked(self.layer.preserve_labels) def _on_color_mode_change(self, event=None): """Receive layer model color. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ with self.layer.events.color_mode.blocker(): index = self.colorModeComboBox.findText( self.layer.color_mode, Qt.MatchFixedString ) self.blendComboBox.setCurrentIndex(index) def _on_editable_change(self, event=None): """Receive layer model editable change event & enable/disable buttons. Parameters ---------- event : qtpy.QtCore.QEvent, optional. Event from the Qt context. """ disable_with_opacity( self, ['pick_button', 'paint_button', 'fill_button'], self.layer.editable, )
class EditBoundaryConditions(QDialog): def __init__(self, data, win_parent=None): """ +---------+ | Painter | +---------+---------+ | Name1 | | Name2 | | Name3 | | Name4 | | | | x by cell ___ | | x by angle ___ | | | | box elements | | | | Add Remove | | | | Apply OK Cancel | +-------------------+ """ QDialog.__init__(self, win_parent) self.setWindowTitle('Edit Boundary Conditions') #default self.win_parent = win_parent self.out_data = data self.keys = sorted(data.keys()) keys = self.keys nrows = len(keys) self.active_key = keys[0] self._use_old_table = False items = keys header_labels = ['Groups'] table_model = Model(items, header_labels, self) view = SingleChoiceQTableView(self) #Call your custom QTableView here view.setModel(table_model) #view.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch) #TODO: fixme self.table = view actor_obj = data[self.active_key] name = actor_obj.name line_width = actor_obj.line_width point_size = actor_obj.point_size opacity = actor_obj.opacity color = actor_obj.color show = actor_obj.is_visible self.representation = actor_obj.representation table = self.table #headers = [QtCore.QString('Groups')] header = table.horizontalHeader() header.setStretchLastSection(True) self._default_is_apply = False self.name = QLabel("Name:") self.name_edit = QLineEdit(str(name)) self.name_edit.setDisabled(True) self.color = QLabel("Color:") self.color_edit = QPushButton() #self.color_edit.setFlat(True) color = self.out_data[self.active_key].color qcolor = QtGui.QColor() qcolor.setRgb(*color) #print('color =%s' % str(color)) palette = QtGui.QPalette( self.color_edit.palette()) # make a copy of the palette #palette.setColor(QtGui.QPalette.Active, QtGui.QPalette.Base, \ #qcolor) palette.setColor(QtGui.QPalette.Background, QtGui.QColor('blue')) # ButtonText self.color_edit.setPalette(palette) self.color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(color) + #"border:1px solid rgb(255, 170, 255); " "}") self.opacity = QLabel('Opacity:') self.opacity_edit = QDoubleSpinBox(self) self.opacity_edit.setRange(0.1, 1.0) self.opacity_edit.setDecimals(1) self.opacity_edit.setSingleStep(0.1) self.opacity_edit.setValue(opacity) self.line_width = QLabel('Line Width:') self.line_width_edit = QSpinBox(self) self.line_width_edit.setRange(1, 10) self.line_width_edit.setSingleStep(1) self.line_width_edit.setValue(line_width) if self.representation in ['point', 'surface']: self.line_width.setEnabled(False) self.line_width_edit.setEnabled(False) self.point_size = QLabel('Point Size:') self.point_size_edit = QSpinBox(self) self.point_size_edit.setRange(1, 10) self.point_size_edit.setSingleStep(1) self.point_size_edit.setValue(point_size) if self.representation in ['wire', 'surface']: self.point_size.setEnabled(False) self.point_size_edit.setEnabled(False) # show/hide self.checkbox_show = QCheckBox("Show") self.checkbox_hide = QCheckBox("Hide") self.checkbox_show.setChecked(show) self.checkbox_hide.setChecked(not show) # closing self.apply_button = QPushButton("Apply") #if self._default_is_apply: #self.apply_button.setDisabled(True) self.ok_button = QPushButton("OK") self.cancel_button = QPushButton("Cancel") self.create_layout() self.set_connections() def update_active_key(self, index): old_obj = self.out_data[self.active_key] old_obj.line_width = self.line_width_edit.value() old_obj.point_size = self.point_size_edit.value() old_obj.opacity = self.opacity_edit.value() old_obj.is_visible = self.checkbox_show.isChecked() name = index.data() #i = self.keys.index(self.active_key) self.active_key = name self.name_edit.setText(name) obj = self.out_data[name] line_width = obj.line_width point_size = obj.point_size opacity = obj.opacity representation = obj.representation is_visible = obj.is_visible self.color_edit.setStyleSheet("QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(obj.color) + #"border:1px solid rgb(255, 170, 255); " "}") self.line_width_edit.setValue(line_width) self.point_size_edit.setValue(point_size) if self.representation != representation: self.representation = representation if self.representation == 'point': self.point_size.setEnabled(True) self.point_size_edit.setEnabled(True) else: self.point_size.setEnabled(False) self.point_size_edit.setEnabled(False) if self.representation == ['wire']: self.line_width.setEnabled(True) self.line_width_edit.setEnabled(True) else: self.line_width.setEnabled(False) self.line_width_edit.setEnabled(False) #if self.representation in ['wire', 'surface']: self.opacity_edit.setValue(opacity) self.checkbox_show.setChecked(is_visible) self.checkbox_hide.setChecked(not is_visible) #def on_name_select(self): #print('on_name_select') #return def create_layout(self): ok_cancel_box = QHBoxLayout() ok_cancel_box.addWidget(self.apply_button) ok_cancel_box.addWidget(self.ok_button) ok_cancel_box.addWidget(self.cancel_button) grid = QGridLayout() irow = 0 grid.addWidget(self.name, irow, 0) grid.addWidget(self.name_edit, irow, 1) irow += 1 grid.addWidget(self.color, irow, 0) grid.addWidget(self.color_edit, irow, 1) irow += 1 grid.addWidget(self.opacity, irow, 0) grid.addWidget(self.opacity_edit, irow, 1) irow += 1 grid.addWidget(self.line_width, irow, 0) grid.addWidget(self.line_width_edit, irow, 1) irow += 1 grid.addWidget(self.point_size, irow, 0) grid.addWidget(self.point_size_edit, irow, 1) irow += 1 checkboxs = QButtonGroup(self) checkboxs.addButton(self.checkbox_show) checkboxs.addButton(self.checkbox_hide) vbox = QVBoxLayout() vbox.addWidget(self.table) vbox.addLayout(grid) if 0: vbox.addWidget(self.checkbox_show) vbox.addWidget(self.checkbox_hide) else: vbox1 = QVBoxLayout() vbox1.addWidget(self.checkbox_show) vbox1.addWidget(self.checkbox_hide) vbox.addLayout(vbox1) vbox.addStretch() #vbox.addWidget(self.check_apply) vbox.addLayout(ok_cancel_box) self.setLayout(vbox) def set_connections(self): """creates the actions for the menu""" self.opacity_edit.valueChanged.connect(self.on_opacity) # clicked? self.line_width_edit.valueChanged.connect( self.on_line_width) # clicked? self.point_size_edit.valueChanged.connect( self.on_point_size) # clicked? self.color_edit.clicked.connect(self.on_color) self.checkbox_show.clicked.connect(self.on_show) self.checkbox_hide.clicked.connect(self.on_hide) #self.opacity_edit.clicked.connect(self.on_opacity) #self.connect(self.opacity_edit, QtCore.SIGNAL('clicked()'), self.on_opacity) #self.connect(self.line_width, QtCore.SIGNAL('clicked()'), self.on_line_width) #self.connect(self.point_size, QtCore.SIGNAL('clicked()'), self.on_point_size) #self.connect(self.color_edit, QtCore.SIGNAL('clicked()'), self.on_color) #self.connect(self.checkbox_show, QtCore.SIGNAL('clicked()'), self.on_show) #self.connect(self.checkbox_hide, QtCore.SIGNAL('clicked()'), self.on_hide) #self.connect(self.check_apply, QtCore.SIGNAL('clicked()'), self.on_check_apply) self.apply_button.clicked.connect(self.on_apply) self.ok_button.clicked.connect(self.on_ok) self.cancel_button.clicked.connect(self.on_cancel) #self.connect(self.apply_button, QtCore.SIGNAL('clicked()'), self.on_apply) #self.connect(self.ok_button, QtCore.SIGNAL('clicked()'), self.on_ok) #self.connect(self.cancel_button, QtCore.SIGNAL('clicked()'), self.on_cancel) #self.connect(self, QtCore.SIGNAL('triggered()'), self.closeEvent) def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Escape: self.close() def closeEvent(self, event): self.out_data['close'] = True event.accept() def on_color(self): name = self.active_key obj = self.out_data[name] rgb_color_ints = obj.color msg = name col = QColorDialog.getColor(QtGui.QColor(*rgb_color_ints), self, "Choose a %s color" % msg) if col.isValid(): color = col.getRgbF()[:3] obj.color = color #print('new_color =', color) self.color_edit.setStyleSheet( "QPushButton {" "background-color: rgb(%s, %s, %s);" % tuple(obj.color) + #"border:1px solid rgb(255, 170, 255); " "}") def on_show(self): name = self.active_key is_checked = self.checkbox_show.isChecked() self.out_data[name].is_visible = is_checked def on_hide(self): name = self.active_key is_checked = self.checkbox_hide.isChecked() self.out_data[name].is_visible = not is_checked def on_line_width(self): name = self.active_key line_width = self.line_width_edit.value() self.out_data[name].line_width = line_width def on_point_size(self): name = self.active_key point_size = self.point_size_edit.value() self.out_data[name].point_size = point_size def on_opacity(self): name = self.active_key opacity = self.opacity_edit.value() self.out_data[name].opacity = opacity #def on_axis(self, text): ##print(self.combo_axis.itemText()) #self._axis = str(text) #self.plane.setText('Point on %s? Plane:' % self._axis) #self.point_a.setText('Point on %s Axis:' % self._axis) #self.point_b.setText('Point on %s%s Plane:' % (self._axis, self._plane)) #def on_plane(self, text): #self._plane = str(text) #self.point_b.setText('Point on %s%s Plane:' % (self._axis, self._plane)) def on_check_apply(self): is_checked = self.check_apply.isChecked() self.apply_button.setDisabled(is_checked) def _on_float(self, field): try: eval_float_from_string(field.text()) field.setStyleSheet("QLineEdit{background: white;}") except ValueError: field.setStyleSheet("QLineEdit{background: red;}") #def on_default_name(self): #self.name_edit.setText(str(self._default_name)) #self.name_edit.setStyleSheet("QLineEdit{background: white;}") #def check_name(self, cell): #text = str(cell.text()).strip() #if len(text): #cell.setStyleSheet("QLineEdit{background: white;}") #return text, True #else: #cell.setStyleSheet("QLineEdit{background: red;}") #return None, False def on_validate(self): self.out_data['clicked_ok'] = True self.out_data['clicked_cancel'] = False old_obj = self.out_data[self.active_key] old_obj.line_width = self.line_width_edit.value() old_obj.point_size = self.point_size_edit.value() old_obj.opacity = self.opacity_edit.value() old_obj.is_visible = self.checkbox_show.isChecked() return True #name_value, flag0 = self.check_name(self.name_edit) #ox_value, flag1 = check_float(self.transparency_edit) #if flag0 and flag1: #self.out_data['clicked_ok'] = True #return True #return False def on_apply(self): passed = self.on_validate() if passed: self.win_parent.on_update_geometry_properties(self.out_data) return passed def on_ok(self): passed = self.on_apply() if passed: self.close() #self.destroy() def on_cancel(self): self.out_data['clicked_ok'] = False self.out_data['clicked_cancel'] = True self.close()