class WebPage(myQtWeb.QWebEnginePage): """ Web page subclass to manage hyperlinks for WebEngine Note: This can't be used for WebKit because the acceptNavigationRequest method has a different functionality for it. """ linkClicked = qt.Signal(qt.QUrl) showHelp = qt.Signal() linkDelegationPolicy = 0 def setLinkDelegationPolicy(self, policy): self.linkDelegationPolicy = policy def acceptNavigationRequest(self, url, navigation_type, isMainFrame): """ Overloaded method to handle links ourselves """ strURL = str(url.toString()) if strURL.endswith('png') or strURL.endswith('ico'): return False elif strURL.startswith('file'): if strURL.endswith('tutorial.html') or\ strURL.endswith('tutorial'): self.linkClicked.emit(url) return False else: return True else: self.linkClicked.emit(url) return False
class AbstractCalibrationTask(qt.QWidget): widgetShow = qt.Signal() widgetHide = qt.Signal() nextTaskRequested = qt.Signal() def __init__(self): super(AbstractCalibrationTask, self).__init__() self.__model = None self.installEventFilter(self) def initNextStep(self): if hasattr(self, "_nextStep"): self._nextStep.clicked.connect(self.nextTask) def eventFilter(self, widget, event): result = super(AbstractCalibrationTask, self).eventFilter(widget, event) if event.type() == qt.QEvent.Show: self.widgetShow.emit() elif event.type() == qt.QEvent.Hide: self.widgetHide.emit() return result def model(self): return self.__model def setModel(self, model): self.__model = model self._updateModel(model) def nextTask(self): self.nextTaskRequested.emit()
class ProjectTree(TreeView): sigDelegateEvent = Qt.Signal(object, object) def delegateEvent(self, column, node, *args, **kwargs): # TODO : proper event event = (args and args[0]) or None self.sigDelegateEvent.emit(node, event)
class MainToolBar(qt.QToolBar): """ Toolbar consisted with text labeled actions """ sigSetStage = qt.Signal(object) def __init__(self, parent=None, *args, **kwargs): super(MainToolBar, self).__init__(parent=parent, *args, **kwargs) # Setup font self.font = qt.QFont("Verdana") self.font.setPointSize(16) # Mode action group self.modeActionGroup = qt.QActionGroup(self) # Align right self.setLayoutDirection(qt.Qt.RightToLeft) # Build children self.buildActions() def buildActions(self): action = qt.QAction("EXAFS", self) # action.triggered.connect(partial(self.setMode, mode='exafs')) action.setFont(self.font) # action.setProperty("isMode", True) action.setCheckable(True) action.setActionGroup(self.modeActionGroup) action.setChecked(True) self.addAction(action)
class AbstractModel(qt.QObject): changed = qt.Signal() def __init__(self, parent=None): qt.QObject.__init__(self, parent) self.__isLocked = 0 self.__wasChanged = False def isValid(self): return True def wasChanged(self): if self.__isLocked > 0: self.__wasChanged = True else: self.changed.emit() def lockSignals(self): self.__isLocked = self.__isLocked + 1 def unlockSignals(self): assert self.__isLocked > 0 self.__isLocked = self.__isLocked - 1 if self.__isLocked == 0 and self.__wasChanged: self.__wasChanged = False self.wasChanged()
class ThreadSafePlot1D(Plot1D): """Add a thread-safe :meth:`addCurveThreadSafe` method to Plot1D. """ _sigAddCurve = qt.Signal(tuple, dict) """Signal used to perform addCurve in the main thread. It takes args and kwargs as arguments. """ def __init__(self, parent=None): super(ThreadSafePlot1D, self).__init__(parent) # Connect the signal to the method actually calling addCurve self._sigAddCurve.connect(self.__addCurve) def __addCurve(self, args, kwargs): """Private method calling addCurve from _sigAddCurve""" self.addCurve(*args, **kwargs) def addCurveThreadSafe(self, *args, **kwargs): """Thread-safe version of :meth:`silx.gui.plot.Plot.addCurve` This method takes the same arguments as Plot.addCurve. WARNING: This method does not return a value as opposed to Plot.addCurve """ self._sigAddCurve.emit(args, kwargs)
class _DefaultScatterProfileRoiEditor(qt.QWidget): sigDataCommited = qt.Signal() def __init__(self, parent=None): qt.QWidget.__init__(self, parent=parent) self._nPoints = qt.QSpinBox(self) self._nPoints.setRange(1, 9999) self._nPoints.setValue(1024) self._nPoints.valueChanged[int].connect(self.__widgetChanged) layout = qt.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) label = qt.QLabel('Samples:') label.setToolTip("Number of sample points of the profile") layout.addWidget(label) layout.addWidget(self._nPoints) def __widgetChanged(self, value=None): self.commitData() def commitData(self): self.sigDataCommited.emit() def setEditorData(self, roi): with blockSignals(self._nPoints): self._nPoints.setValue(roi.getNPoints()) def setRoiData(self, roi): nPoints = self._nPoints.value() roi.setNPoints(nPoints)
class QColorEditor(qt.QWidget): """ QColor editor. """ sigColorChanged = qt.Signal(object) color = property(lambda self: qt.QColor(self.__color)) @color.setter def color(self, color): self._setColor(color) self.__previousColor = color def __init__(self, *args, **kwargs): super(QColorEditor, self).__init__(*args, **kwargs) layout = qt.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) button = qt.QToolButton() icon = qt.QIcon(qt.QPixmap(32, 32)) button.setIcon(icon) layout.addWidget(button) button.clicked.connect(self.__showColorDialog) layout.addStretch(1) self.__color = None self.__previousColor = None def sizeHint(self): return qt.QSize(0, 0) def _setColor(self, qColor): button = self.findChild(qt.QToolButton) pixmap = qt.QPixmap(32, 32) pixmap.fill(qColor) button.setIcon(qt.QIcon(pixmap)) self.__color = qColor def __showColorDialog(self): dialog = qt.QColorDialog(parent=self) if sys.platform == 'darwin': # Use of native color dialog on macos might cause problems dialog.setOption(qt.QColorDialog.DontUseNativeDialog, True) self.__previousColor = self.__color dialog.setAttribute(qt.Qt.WA_DeleteOnClose) dialog.setModal(True) dialog.currentColorChanged.connect(self.__colorChanged) dialog.finished.connect(self.__dialogClosed) dialog.show() def __colorChanged(self, color): self.__color = color self._setColor(color) self.sigColorChanged.emit(color) def __dialogClosed(self, result): if result == qt.QDialog.Rejected: self.__colorChanged(self.__previousColor) self.__previousColor = None
class ItemDelegate(Qt.QStyledItemDelegate): sigDelegateEvent = Qt.Signal(object, object, object) def __init__(self, parent=None): super(ItemDelegate, self).__init__(parent) def sizeHint(self, option, index): hint = index.data(ModelRoles.InternalDataRole).sizeHint(index.column()) if hint.isValid(): return hint return super(ItemDelegate, self).sizeHint(option, index) def createEditor(self, parent, option, index): node = index.data(role=ModelRoles.InternalDataRole) if node: editor = node.getEditor(parent, option, index) if editor: if isinstance(editor, EditorMixin): editor.setViewCallback(self.__notifyView) editor.setModelCallback(self.__notifyModel) return editor return super(ItemDelegate, self).createEditor(parent, option, index) def __notifyModel(self, editor, *args, **kwargs): node = editor.node if node: node._openedEditorEvent(editor, editor.column, args, kwargs) # self.commitData.emit(editor) def __notifyView(self, editor, *args, **kwargs): self.sigDelegateEvent.emit(editor.node, args, kwargs) def updateEditorGeometry(self, editor, option, index): editor.setGeometry(option.rect) def setEditorData(self, editor, index): node = index.data(role=ModelRoles.InternalDataRole) if node and node.setEditorData(editor, index.column()): return super(ItemDelegate, self).setEditorData(editor, index) def setModelData(self, editor, model, index): node = index.data(role=ModelRoles.InternalDataRole) if node: if node._setModelData(editor, index.column()): return node.setData(index.column(), editor.getEditorData(), role=Qt.Qt.EditRole) super(ItemDelegate, self).setModelData(editor, model, index) def paint(self, painter, option, index): klass = index.data(role=ModelRoles.EditorClassRole) if klass is not None: if (not getattr(klass, 'persistent', False) and klass.paint(painter, option, index)): return super(ItemDelegate, self).paint(painter, option, index)
class _NoProfileRoiEditor(qt.QWidget): sigDataCommited = qt.Signal() def setEditorData(self, roi): pass def setRoiData(self, roi): pass
class KindsSelector(qt.QListWidget): """List widget allowing to select plot item kinds ("curve", "scatter", "image"...) """ sigSelectedKindsChanged = qt.Signal(list) def __init__(self, parent=None, kinds=None): """ :param parent: Parent QWidget or None :param tuple(str) kinds: Sequence of kinds. If None, the default behavior is to provide a checkbox for all possible item kinds. """ qt.QListWidget.__init__(self, parent) self.plot_item_kinds = [] self.setAvailableKinds( kinds if kinds is not None else PlotWidget.ITEM_KINDS) self.setSelectionMode(qt.QAbstractItemView.ExtendedSelection) self.selectAll() self.itemSelectionChanged.connect(self.emitSigKindsSelectionChanged) def emitSigKindsSelectionChanged(self): self.sigSelectedKindsChanged.emit(self.selectedKinds) @property def selectedKinds(self): """Tuple of all selected kinds (as strings).""" # check for updates when self.itemSelectionChanged return [item.text() for item in self.selectedItems()] def setAvailableKinds(self, kinds): """Set a list of kinds to be displayed. :param list[str] kinds: Sequence of kinds """ self.plot_item_kinds = kinds self.clear() for kind in self.plot_item_kinds: item = qt.QListWidgetItem(self) item.setText(kind) self.addItem(item) def selectAll(self): """Select all available kinds.""" if self.selectionMode() in [ qt.QAbstractItemView.SingleSelection, qt.QAbstractItemView.NoSelection ]: raise RuntimeError("selectAll requires a multiple selection mode") for i in range(self.count()): self.item(i).setSelected(True)
class AbstractModel(qt.QObject): changed = qt.Signal() def __init__(self, parent=None): qt.QObject.__init__(self, parent) self.__isLocked = 0 self.__wasChanged = False def isValid(self): return True def wasChanged(self): """Emit the change event in case of the model was not locked. :returns: True if the signal was emitted. """ if self.__isLocked > 0: self.__wasChanged = True return False else: self.changed.emit() return True def isLocked(self): """Returns True if the events are locked. :rtype: bool """ return self.__isLocked > 0 @contextlib.contextmanager def lockContext(self): """Context manager to lock and unlock signals.""" self.lockSignals() yield self self.unlockSignals() def lockSignals(self): """Lock the change events """ self.__isLocked = self.__isLocked + 1 def unlockSignals(self): """Unlock the change events :returns: False if the model is still locked, else True """ assert self.__isLocked > 0 self.__isLocked = self.__isLocked - 1 if self.__isLocked == 0 and self.__wasChanged: self.__wasChanged = False self.wasChanged() return self.__isLocked == 0
class RoiAxisWidget(Qt.QWidget): """ Widget with a double slider and two line edit displaying the slider range. """ sigSliderMoved = Qt.Signal(object) """ Signal triggered when the slider is moved. Equivalent to connecting directly to the sliders sigSliderMoved signal. """ def slider(self): """ The RangeSlider instance of this widget. :return: """ return self.__slider def __init__(self, label=None, **kwargs): """ :param label: text displayed above the slider. :param kwargs: """ super(RoiAxisWidget, self).__init__(**kwargs) layout = Qt.QGridLayout(self) qLabel = FixedSizeLabel(nChar=1) qLabel.setFrameStyle(Qt.QFrame.NoFrame | Qt.QFrame.Plain) qLabel.setText(label) slider = self.__slider = RangeSlider() leftEdit = self.__leftEdit = StyledLineEdit(nChar=7) rightEdit = self.__rightEdit = StyledLineEdit(nChar=7) leftEdit.setReadOnly(True) rightEdit.setReadOnly(True) layout.addWidget(qLabel, 0, 0) layout.addWidget(slider, 0, 1, 1, 2) layout.addWidget(leftEdit, 1, 1) layout.addWidget(rightEdit, 1, 2) layout.setColumnStretch(3, 1) slider.sigSliderMoved.connect(self.__sliderMoved) slider.sigSliderMoved.connect(self.sigSliderMoved) def __sliderMoved(self, event): """ Slot triggered when one of the slider is moved. Updates the line edits. :param event: :return: """ self.__leftEdit.setText('{0:6g}'.format(event.left)) self.__rightEdit.setText('{0:6g}'.format(event.right))
class DataViewWidget(Qt.QMainWindow): sigProcessApplied = Qt.Signal(object) def __init__(self, index, parent=None, **kwargs): super(DataViewWidget, self).__init__(parent, **kwargs) self.__index = Qt.QPersistentModelIndex(index) def _emitEvent(self, event): self.sigProcessApplied.emit(event) index = property(lambda self: self.__index)
class _ToggleableUrlSelectionTable(qt.QWidget): _BUTTON_ICON = qt.QStyle.SP_ToolBarHorizontalExtensionButton # noqa sigCurrentUrlChanged = qt.Signal(str) """Signal emitted when the active/current url change""" def __init__(self, parent=None) -> None: qt.QWidget.__init__(self, parent) self.setLayout(qt.QGridLayout()) self._toggleButton = qt.QPushButton(parent=self) self.layout().addWidget(self._toggleButton, 0, 2, 1, 1) self._toggleButton.setSizePolicy(qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed) self._urlsTable = UrlList(parent=self) self.layout().addWidget(self._urlsTable, 1, 1, 1, 2) # set up self._setButtonIcon(show=True) # Signal / slot connection self._toggleButton.clicked.connect(self.toggleUrlSelectionTable) self._urlsTable.sigCurrentUrlChanged.connect(self._propagateSignal) # expose API self.setUrls = self._urlsTable.setUrls self.setUrl = self._urlsTable.setUrl self.currentItem = self._urlsTable.currentItem def toggleUrlSelectionTable(self): visible = not self.urlSelectionTableIsVisible() self._setButtonIcon(show=visible) self._urlsTable.setVisible(visible) def _setButtonIcon(self, show): style = qt.QApplication.instance().style() # return a QIcon icon = style.standardIcon(self._BUTTON_ICON) if show is False: pixmap = icon.pixmap(32, 32).transformed(qt.QTransform().scale(-1, 1)) icon = qt.QIcon(pixmap) self._toggleButton.setIcon(icon) def urlSelectionTableIsVisible(self): return self._urlsTable.isVisible() def _propagateSignal(self, url): self.sigCurrentUrlChanged.emit(url) def clear(self): self._urlsTable.clear()
class ProjectChooser(Qt.QWidget): sigProjectPicked = Qt.Signal(object) projectSummary = property( lambda self: self.findChild(ProjectSummaryWidget)) def __init__(self, parent=None): super(ProjectChooser, self).__init__(parent) layout = Qt.QVBoxLayout(self) self.__isValid = False self.__selectedPath = None group = GroupBox('Please select the project file to open.') layout.addWidget(group) grpLayout = Qt.QHBoxLayout(group) filePicker = FileChooser(fileMode=Qt.QFileDialog.ExistingFile) filePicker.setObjectName('PROJ_FILEPICKER') grpLayout.addWidget(filePicker) filePicker.sigSelectionChanged.connect(self.__filePicked) fileDialog = filePicker.fileDialog fileDialog.setNameFilters( ['Xsocs project files (*.prj)', 'Any files (*)']) group = GroupBox('Project Summary') layout.addWidget(group) grpLayout = Qt.QVBoxLayout(group) view = ProjectSummaryWidget() grpLayout.addWidget(view) def __filePicked(self, selectedPath): self.__selectedPath = selectedPath view = self.projectSummary view.setProjectFile(selectedPath) valid = view.isValidProject() self.__isValid = valid if valid: self.sigProjectPicked.emit(selectedPath) else: self.sigProjectPicked.emit('') def isValid(self): return self.__isValid
class DoubleSpinBoxWithSignal(qt.QDoubleSpinBox): """ QDoubleSpinBox with return key signal """ return_stroked = qt.Signal() def keyPressEvent(self, ev): """ Parameters ---------- ev : QEvent """ if ev.key() in (qt.Qt.Key_Return, qt.Qt.Key_Enter): self.return_stroked.emit() else: super(DoubleSpinBoxWithSignal, self).keyPressEvent(ev)
class _HorizontalSlider(HorizontalSliderWithBrowser): sigCurrentUrlIndexChanged = qt.Signal(int) def __init__(self, parent): super(_HorizontalSlider, self).__init__(parent=parent) # connect signal / slot self.valueChanged.connect(self._urlChanged) def setUrlIndex(self, index): self.setValue(index) self.sigCurrentUrlIndexChanged.emit(index) def _urlChanged(self, value): self.sigCurrentUrlIndexChanged.emit(value)
class PlanesWidget(qt.QWidget): """Widget for the plane/perspective selection :param parent: the parent QWidget """ sigPlaneSelectionChanged = qt.Signal(int) def __init__(self, parent): super(PlanesWidget, self).__init__(parent) self.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Minimum) layout0 = qt.QHBoxLayout() self.setLayout(layout0) layout0.setContentsMargins(0, 0, 0, 0) layout0.addWidget(qt.QLabel("Axes selection:")) # By default, the first dimension (dim0) is the frame index/depth/z, # the second dimension is the image row number/y axis # and the third dimension is the image column index/x axis # 1 # | 0 # |/__2 self.qcbAxisSelection = qt.QComboBox(self) self.qcbAxisSelection.addItem(icons.getQIcon("cube-front"), 'Dim1-Dim2') self.qcbAxisSelection.addItem(icons.getQIcon("cube-bottom"), 'Dim0-Dim2') self.qcbAxisSelection.addItem(icons.getQIcon("cube-left"), 'Dim0-Dim1') self.qcbAxisSelection.currentIndexChanged[int].connect( self.__planeSelectionChanged) layout0.addWidget(self.qcbAxisSelection) def __planeSelectionChanged(self, idx): """Callback function when the combobox selection changes idx is the dimension number orthogonal to the slice plane, following the convention: - slice plane Dim1-Dim2: perspective 0 - slice plane Dim0-Dim2: perspective 1 - slice plane Dim0-Dim1: perspective 2 """ self.sigPlaneSelectionChanged.emit(idx)
class ItemDelegate(qt.QStyledItemDelegate): """ Delegate for the QTreeView filled with SubjectItems. """ sigDelegateEvent = qt.Signal(str) def __init__(self, parent=None): super(ItemDelegate, self).__init__(parent) def createEditor(self, parent, option, index): item = index.model().itemFromIndex(index) if item: if isinstance(item, SubjectItem): editor = item.getEditor(parent, option, index) if editor: editor.setAutoFillBackground(True) if hasattr(editor, 'sigViewTask'): editor.sigViewTask.connect(self.__viewTask) return editor editor = super(ItemDelegate, self).createEditor(parent, option, index) return editor def updateEditorGeometry(self, editor, option, index): editor.setGeometry(option.rect) def setEditorData(self, editor, index): item = index.model().itemFromIndex(index) if item: if isinstance(item, SubjectItem) and item.setEditorData(editor): return super(ItemDelegate, self).setEditorData(editor, index) def setModelData(self, editor, model, index): item = index.model().itemFromIndex(index) if isinstance(item, SubjectItem) and item._setModelData(editor): return super(ItemDelegate, self).setModelData(editor, model, index) def __viewTask(self, task): self.sigDelegateEvent.emit(task)
class UrlList(qt.QWidget): """List of URLs the user to select an URL""" sigCurrentUrlChanged = qt.Signal(str) """Signal emitted when the active/current url change""" def __init__(self, parent=None): super(UrlList, self).__init__(parent) self.setLayout(qt.QVBoxLayout()) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self._listWidget = qt.QListWidget(parent=self) self.layout().addWidget(self._listWidget) # connect signal / Slot self._listWidget.currentItemChanged.connect( self._notifyCurrentUrlChanged) # expose API self.currentItem = self._listWidget.currentItem def setUrls(self, urls: list) -> None: url_names = [] [url_names.append(url.path()) for url in urls] self._listWidget.addItems(url_names) def _notifyCurrentUrlChanged(self, current, previous): if current is None: pass else: self.sigCurrentUrlChanged.emit(current.text()) def setUrl(self, url: DataUrl) -> None: assert isinstance(url, DataUrl) sel_items = self._listWidget.findItems(url.path(), qt.Qt.MatchExactly) if sel_items is None: _logger.warning(url.path(), ' is not registered in the list.') else: assert len(sel_items) == 1 item = sel_items[0] self._listWidget.setCurrentItem(item) self.sigCurrentUrlChanged.emit(item.text()) def clear(self): self._listWidget.clear()
class _DefaultImageProfileRoiEditor(qt.QWidget): sigDataCommited = qt.Signal() def __init__(self, parent=None): qt.QWidget.__init__(self, parent=parent) layout = qt.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) self._initLayout(layout) def _initLayout(self, layout): self._lineWidth = qt.QSpinBox(self) self._lineWidth.setRange(1, 1000) self._lineWidth.setValue(1) self._lineWidth.valueChanged[int].connect(self._widgetChanged) self._methodsButton = ProfileOptionToolButton(parent=self, plot=None) self._methodsButton.sigMethodChanged.connect(self._widgetChanged) label = qt.QLabel('W:') label.setToolTip("Line width in pixels") layout.addWidget(label) layout.addWidget(self._lineWidth) layout.addWidget(self._methodsButton) def _widgetChanged(self, value=None): self.commitData() def commitData(self): self.sigDataCommited.emit() def setEditorData(self, roi): with blockSignals(self._lineWidth): self._lineWidth.setValue(roi.getProfileLineWidth()) with blockSignals(self._methodsButton): method = roi.getProfileMethod() self._methodsButton.setMethod(method) def setRoiData(self, roi): lineWidth = self._lineWidth.value() roi.setProfileLineWidth(lineWidth) method = self._methodsButton.getMethod() roi.setProfileMethod(method)
class _SignalHandler(Qt.QObject): node = property(lambda self: self.__node()) sigInternalDataChanged = Qt.Signal(object) def __init__(self, node): super(_SignalHandler, self).__init__() self.__node = weakref.ref(node) self.indices = None self.sig = None self.child = None def internalDataChanged(self, data): node = self.__node() sender = self.sender().node if node: node._childInternalDataChanged(sender, data)
class QCheckBoxItem(qt.QCheckBox): """:class:`qt.QCheckBox` augmented with a ``sigCellChanged`` signal to emit a tuple of ``(row, column)`` coordinates when the check box has been clicked on. This signal can be used to locate the modified check box in a table. :param row: Row number of the table cell containing this widget :param col: Column number of the table cell containing this widget""" sigCellChanged = qt.Signal(int, int) """Signal emitted when this ``QCheckBox`` is clicked. A ``(row, column)`` tuple is passed.""" def __init__(self, parent=None, row=None, col=None): self._row = row self._col = col qt.QCheckBox.__init__(self, parent) self.clicked.connect(self._cellChanged) def _cellChanged(self): self.sigCellChanged.emit(self._row, self._col)
class QComboTableItem(qt.QComboBox): """:class:`qt.QComboBox` augmented with a ``sigCellChanged`` signal to emit a tuple of ``(row, column)`` coordinates when the value is changed. This signal can be used to locate the modified combo box in a table. :param row: Row number of the table cell containing this widget :param col: Column number of the table cell containing this widget""" sigCellChanged = qt.Signal(int, int) """Signal emitted when this ``QComboBox`` is activated. A ``(row, column)`` tuple is passed.""" def __init__(self, parent=None, row=None, col=None): self._row = row self._col = col qt.QComboBox.__init__(self, parent) self.activated[int].connect(self._cellChanged) def _cellChanged(self, idx): # noqa self.sigCellChanged.emit(self._row, self._col)
class QSpaceButton(EditorMixin, Qt.QWidget): persistent = True sigValueChanged = Qt.Signal() def __init__(self, parent, option, index): super(QSpaceButton, self).__init__(parent, option, index) layout = Qt.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) icon = icons.getQIcon('item-ndim') button = Qt.QToolButton() button.setIcon(icon) layout.addWidget(button) layout.addStretch(1) button.clicked.connect(self.__clicked) def __clicked(self): # node = self.node event = {'event': 'qspace'} self.notifyView(event)
class QtProxifier(qt.QObject): """Provide a safe Qt object from an unsafe object.""" _callRequested = qt.Signal(str, tuple, dict) def __init__(self, target): qt.QObject.__init__(self) self.__target = target self._callRequested.connect(self.__callRequested) def _target(self): return self.__target def __getattr__(self, name): """Convert a call request to a Qt signal""" def createSignal(*args, **kwargs): method = getattr(self.__target, name) result = concurrent.submitToQtMainThread(method, *args, **kwargs) return result return createSignal
class IntensityTree(TreeView): sigCurrentChanged = Qt.Signal(object) def __init__(self, intensityGroupItem, **kwargs): super(IntensityTree, self).__init__(**kwargs) model = IntensityModel() iGroupNode = IntensityTotalNode(h5File=intensityGroupItem.filename, h5Path=intensityGroupItem.path) model.appendGroup(iGroupNode) self.setModel(model) self.setShowUniqueGroup(True) self.setExpanded(self.model().index(0, 0), True) model.startModel() def currentChanged(self, current, previous): super(IntensityTree, self).currentChanged(current, previous) node = current.data(ModelRoles.InternalDataRole) if not node: return self.sigCurrentChanged.emit(node)
class FitButton(EditorMixin, Qt.QWidget): persistent = True sigValueChanged = Qt.Signal() def __init__(self, parent, option, index): super(FitButton, self).__init__(parent, option, index) layout = Qt.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) icon = icons.getQIcon('plot-widget') button = Qt.QToolButton() button.setIcon(icon) button.clicked.connect(self.__clicked) layout.addWidget(button) button = Qt.QToolButton() style = Qt.QApplication.style() icon = style.standardIcon(Qt.QStyle.SP_DialogSaveButton) button.setIcon(icon) button.clicked.connect(self.__export) layout.addWidget(button) layout.addStretch(1) def __clicked(self): event = {'event': 'fit'} self.notifyView(event) def __export(self): fitItem = h5NodeToProjectItem(self.node) workdir = fitItem.projectRoot().workdir itemBasename = os.path.basename(fitItem.fitFile).rsplit('.')[0] itemBasename += '.txt' dialog = Qt.QFileDialog(self, 'Export fit results.') dialog.setFileMode(Qt.QFileDialog.AnyFile) dialog.setAcceptMode(Qt.QFileDialog.AcceptSave) dialog.selectFile(os.path.join(workdir, itemBasename)) if dialog.exec_(): csvPath = dialog.selectedFiles()[0] fitItem.fitH5.export_csv(fitItem.fitH5.entries()[0], csvPath)
class IsoSurfaceAddRemoveWidget(qt.QWidget): sigViewTask = qt.Signal(str) """Signal for the tree view to perform some task""" def __init__(self, parent, item): super(IsoSurfaceAddRemoveWidget, self).__init__(parent) self._item = item layout = qt.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) addBtn = qt.QToolButton() addBtn.setText('+') addBtn.setToolButtonStyle(qt.Qt.ToolButtonTextOnly) layout.addWidget(addBtn) addBtn.clicked.connect(self.__addClicked) removeBtn = qt.QToolButton() removeBtn.setText('-') removeBtn.setToolButtonStyle(qt.Qt.ToolButtonTextOnly) layout.addWidget(removeBtn) removeBtn.clicked.connect(self.__removeClicked) layout.addStretch(1) def __addClicked(self): sfview = self._item.subject if not sfview: return dataRange = sfview.getDataRange() if dataRange is None: dataRange = [0, 1] sfview.addIsosurface( numpy.mean((dataRange[0], dataRange[-1])), '#0000FF') def __removeClicked(self): self.sigViewTask.emit('remove_iso')