class AnimateDialog(QDialog): def __init__(self, vpoints: Sequence[VPoint], vlinks: Sequence[VLink], path: _Paths, slider_path: _SliderPaths, monochrome: bool, parent: QWidget): super(AnimateDialog, self).__init__(parent) self.setWindowTitle("Vector Animation") self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint & ~Qt.WindowContextHelpButtonHint) self.setMinimumSize(800, 600) self.setModal(True) main_layout = QVBoxLayout(self) self.canvas = _DynamicCanvas(vpoints, vlinks, path, slider_path, self) self.canvas.set_monochrome_mode(monochrome) self.canvas.update_pos.connect(self.__set_pos) layout = QHBoxLayout(self) pt_option = QComboBox(self) pt_option.addItems([f"P{p}" for p in range(len(vpoints))]) layout.addWidget(pt_option) value_label = QLabel(self) @Slot(int) def show_values(ind: int): vel, vel_deg = self.canvas.get_vel(ind) acc, acc_deg = self.canvas.get_acc(ind) value_label.setText( f"Velocity: {vel:.04f} ({vel_deg:.04f}deg) | " f"Acceleration: {acc:.04f} ({acc_deg:.04f}deg)") pt_option.currentIndexChanged.connect(show_values) layout.addWidget(value_label) self.pos_label = QLabel(self) layout.addItem( QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)) layout.addWidget(self.pos_label) main_layout.addLayout(layout) main_layout.addWidget(self.canvas) layout = QHBoxLayout(self) self.play = QPushButton(QIcon(QPixmap(":/icons/play.png")), "", self) self.play.setCheckable(True) self.play.clicked.connect(self.__play) layout.addWidget(self.play) self.slider = QSlider(Qt.Horizontal, self) self.slider.setMaximum(max(len(p) for p in path) - 1) self.slider.valueChanged.connect(self.canvas.set_index) layout.addWidget(self.slider) layout.addWidget(QLabel("Total times:", self)) factor = QDoubleSpinBox(self) factor.valueChanged.connect(self.canvas.set_factor) factor.setSuffix('s') factor.setRange(0.01, 999999) factor.setValue(10) layout.addWidget(factor) main_layout.addLayout(layout) self.timer = QTimer() self.timer.setInterval(10) self.timer.timeout.connect(self.__move_ind) @Slot() def __move_ind(self): """Move indicator.""" value = self.slider.value() + 1 self.slider.setValue(value) if value > self.slider.maximum(): self.slider.setValue(0) @Slot(float, float) def __set_pos(self, x: float, y: float) -> None: """Set mouse position.""" self.pos_label.setText(f"({x:.04f}, {y:.04f})") @Slot() def __play(self): """Start playing.""" if self.play.isChecked(): self.timer.start() else: self.timer.stop()
class QtReQueueControls(QWidget): def __init__(self, model, parent=None): super().__init__(parent) self.model = model self._lb_queue_state = QLabel("STOPPED") self._pb_queue_start = QPushButton("Start") self._pb_queue_start.setEnabled(False) self._pb_queue_start.clicked.connect(self._pb_queue_start_clicked) self._pb_queue_stop = QPushButton("Stop") self._pb_queue_stop.setEnabled(False) self._pb_queue_stop.setCheckable(True) self._pb_queue_stop.clicked.connect(self._pb_queue_stop_clicked) self._group_box = QGroupBox("Queue") vbox = QVBoxLayout() vbox.addWidget(self._lb_queue_state, alignment=Qt.AlignHCenter) vbox.addWidget(self._pb_queue_start) vbox.addWidget(self._pb_queue_stop) self._group_box.setLayout(vbox) vbox = QVBoxLayout() vbox.addWidget(self._group_box) self.setLayout(vbox) self.model.events.status_changed.connect(self.on_update_widgets) def on_update_widgets(self, event): # None should be converted to False: is_connected = bool(event.is_connected) status = event.status worker_exists = status.get("worker_environment_exists", False) running_item_uid = status.get("running_item_uid", None) queue_stop_pending = status.get("queue_stop_pending", False) s = "RUNNING" if running_item_uid else "STOPPED" self._lb_queue_state.setText(s) self._pb_queue_start.setEnabled(is_connected and worker_exists and not bool(running_item_uid)) self._pb_queue_stop.setEnabled(is_connected and worker_exists and bool(running_item_uid)) self._pb_queue_stop.setChecked(queue_stop_pending) def _pb_queue_start_clicked(self): try: self.model.queue_start() except Exception as ex: print(f"Exception: {ex}") def _pb_queue_stop_clicked(self): try: if self._pb_queue_stop.isChecked(): print("Stopping the queue") self.model.queue_stop() else: print("Cancelling stop") self.model.queue_stop_cancel() except Exception as ex: print(f"Exception: {ex}")
class LibraryWidget(QWidget): sigImageChanged = Signal() def __init__(self): super(LibraryWidget, self).__init__() self.image_items = [] self.views = [] self.current_image_item = None self.setLayout(QHBoxLayout()) self.right_layout = QVBoxLayout() self.scroll_widget = QScrollArea() self.scroll_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.scroll_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scroll_widget.setWidgetResizable(True) self.flow_widget = QWidget() self.flow_layout = FlowLayout() self.flow_widget.setLayout(self.flow_layout) self.scroll_widget.setWidget(self.flow_widget) self.layout().addWidget(self.scroll_widget) self.hist_widget = HistogramLUTWidget() self.hist_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.hist_widget.item.sigLevelChangeFinished.connect(self.set_levels) self.hist_widget.item.sigLookupTableChanged.connect( self.set_lookup_table) self.layout().addLayout(self.right_layout) self.right_layout.addWidget(self.hist_widget) self.link_button = QPushButton("Link Axes") self.link_button.setCheckable(True) self.right_layout.addWidget(self.link_button) # TODO: use Qt styling pallet for theming # self.setStyleSheet("background-color:#000;") self.current_view = None self.axes_linked = False def set_slice(self, *args, **kwargs): # TODO: support generic orthogonal slicing print('slice:', args, kwargs) def set_levels(self, *args, **kwargs): levels = self.hist_widget.item.getLevels() for image_item in self.image_items: image_item.setLevels(levels) def set_lookup_table(self, *args, **kwargs): if self.current_image_item and self.current_image_item.image is not None: lut = self.hist_widget.item.getLookupTable( self.current_image_item.image) for image_item in self.image_items: image_item.setLookupTable(lut) def set_current_imageitem(self, imageitem: ImageItem): if self.current_image_item: self.current_image_item.deactivate() self.current_image_item = imageitem self.current_view = imageitem.getViewBox() self.current_image_item.activate() self.hist_widget.item.setImageItem(self.current_image_item) def propagate_axes(self): if self.link_button.isChecked(): view = self.sender() view_rect = view.viewRect() for other_view in self.views: if other_view is not view: with QSignalBlocker(other_view): other_view.setRange(rect=view_rect, padding=0) def add_image(self, image, label): w = QFrame() w.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) w.setLineWidth(2) w.setFixedSize(QSize(500, 500)) w.setLayout(QVBoxLayout()) gv = ScrollableGraphicsLayoutWidget() vb = ViewBox(lockAspect=True) ii = ActivatableImageItem(image=image) ii.sigActivated.connect(self.set_current_imageitem) self.hist_widget.item.setImageItem(ii) self.current_image_item = ii self.image_items.append(ii) self.views.append(vb) vb.sigRangeChangedManually.connect(self.propagate_axes) vb.addItem(ii) gv.addItem(vb) self.set_current_imageitem(ii) w.layout().addWidget(gv) l = QLabel(label) # l.setStyleSheet("color: white;") w.layout().addWidget(l) self.flow_layout.addWidget(w) self.last_vb = vb def update_image(self, index, image, label): if index < len(self.image_items): self.image_items[index].setImage(image) else: self.add_image(image, label)