def show_tip( widget: QWidget, pos: QPoint, text: str, timeout=-1, textFormat=Qt.AutoText, wordWrap=None): """Show a tooltip; used for invalid custom thresholds""" propname = __name__ + "::show_tip_qlabel" if timeout < 0: timeout = widget.toolTipDuration() if timeout < 0: timeout = 5000 + 40 * max(0, len(text) - 100) tip = widget.property(propname) if not text and tip is None: return def hide(): w = tip.parent() w.setProperty(propname, None) tip.timer.stop() tip.close() tip.deleteLater() if not isinstance(tip, QLabel): tip = QLabel(objectName="tip-label", focusPolicy=Qt.NoFocus) tip.setBackgroundRole(QPalette.ToolTipBase) tip.setForegroundRole(QPalette.ToolTipText) tip.setPalette(QToolTip.palette()) tip.setFont(QApplication.font("QTipLabel")) tip.setContentsMargins(2, 2, 2, 2) tip.timer = QTimer(tip, singleShot=True, objectName="hide-timer") tip.timer.timeout.connect(hide) widget.setProperty(propname, tip) tip.setParent(widget, Qt.ToolTip) tip.setText(text) tip.setTextFormat(textFormat) if wordWrap is None: wordWrap = textFormat != Qt.PlainText tip.setWordWrap(wordWrap) if not text: hide() else: tip.timer.start(timeout) tip.show() tip.move(pos)
def mousePressEvent(self, event): if event.button() == Qt.LeftButton: if self.__fulltext: popup = QMenu(self) label = QLabel( self, textInteractionFlags=Qt.TextBrowserInteraction, openExternalLinks=self.__openExternalLinks, ) label.setContentsMargins(4, 4, 4, 4) label.setText( self.__styled(self.__defaultStyleSheet, self.__fulltext)) label.linkActivated.connect(self.linkActivated) label.linkHovered.connect(self.linkHovered) action = QWidgetAction(popup) action.setDefaultWidget(label) popup.addAction(action) popup.popup(event.globalPos(), action) event.accept() return else: super().mousePressEvent(event)
def make_signal_labels(self, prefix): self._prefix = prefix # `in_data[, ]` for i, signal in enumerate(OWPythonScript.signal_names): # adding an empty b tag like this adjusts the # line height to match the rest of the labels signal_display_name = signal signal_lbl = QLabel('<b></b>' + prefix + signal_display_name, self) signal_lbl.setFont(self.font()) signal_lbl.setContentsMargins(0, 0, 0, 0) self.layout().addWidget(signal_lbl) self.signal_labels[signal] = signal_lbl if i >= len(OWPythonScript.signal_names) - 1: break comma_lbl = QLabel(', ') comma_lbl.setFont(self.font()) comma_lbl.setContentsMargins(0, 0, 0, 0) comma_lbl.setStyleSheet( '.QLabel { color: ' + self.highlighting_scheme[Punctuation].split(' ')[-1] + '; }') self.layout().addWidget(comma_lbl)
def __init__(self, parent, highlighting_scheme, font): super().__init__(parent, highlighting_scheme, font) self.indentation_level = 1 self.signal_labels = {} self._prefix = None layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) # `return ` ret_lbl = QLabel('<b style="color: ' + \ highlighting_scheme[Keyword].split(' ')[-1] + \ ';">return </b>', self) ret_lbl.setFont(self.font()) ret_lbl.setContentsMargins(0, 0, 0, 0) layout.addWidget(ret_lbl) # `out_data[, ]` * 4 self.make_signal_labels('out_') layout.addStretch() self.setLayout(layout)
class PreviewDialog(QDialog): """A Dialog for selecting an item from a PreviewItem. """ currentIndexChanged = Signal(int) def __init__(self, parent=None, flags=Qt.WindowFlags(0), model=None, **kwargs): QDialog.__init__(self, parent, flags, **kwargs) self.__setupUi() if model is not None: self.setModel(model) def __setupUi(self): layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0) heading = self.tr("Preview") heading = u"<h3>{0}</h3>".format(heading) self.__heading = QLabel(heading, self, objectName="heading") self.__heading.setContentsMargins(12, 12, 12, 0) self.__browser = previewbrowser.PreviewBrowser(self) self.__buttons = QDialogButtonBox(QDialogButtonBox.Open | \ QDialogButtonBox.Cancel, Qt.Horizontal,) self.__buttons.button(QDialogButtonBox.Open).setAutoDefault(True) # Set the Open dialog as disabled until the current index changes self.__buttons.button(QDialogButtonBox.Open).setEnabled(False) # The QDialogButtonsWidget messes with the layout if it is # contained directly in the QDialog. So we create an extra # layer of indirection. buttons = QWidget(objectName="button-container") buttons_l = QVBoxLayout() buttons_l.setContentsMargins(12, 0, 12, 12) buttons.setLayout(buttons_l) buttons_l.addWidget(self.__buttons) layout.addWidget(self.__heading) layout.addWidget(self.__browser) layout.addWidget(buttons) self.__buttons.accepted.connect(self.accept) self.__buttons.rejected.connect(self.reject) self.__browser.currentIndexChanged.connect( self.__on_currentIndexChanged) self.__browser.activated.connect(self.__on_activated) layout.setSizeConstraint(QVBoxLayout.SetFixedSize) self.setLayout(layout) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) def setItems(self, items): """Set the items (a list of strings) for preview/selection. """ model = QStringListModel(items) self.setModel(model) def setModel(self, model): """Set the model for preview/selection. """ self.__browser.setModel(model) def model(self): """Return the model. """ return self.__browser.model() def currentIndex(self): return self.__browser.currentIndex() def setCurrentIndex(self, index): """Set the current selected (shown) index. """ self.__browser.setCurrentIndex(index) def setHeading(self, heading): """Set `heading` as the heading string ('<h3>Preview</h3>' by default). """ self.__heading.setText(heading) def heading(self): """Return the heading string. """ def __on_currentIndexChanged(self, index): button = self.__buttons.button(QDialogButtonBox.Open) button.setEnabled(index >= 0) self.currentIndexChanged.emit(index) def __on_activated(self, index): if self.currentIndex() != index: self.setCurrentIndex(index) self.accept()
class PreviewDialog(QDialog): """A Dialog for selecting an item from a PreviewItem. """ currentIndexChanged = Signal(int) def __init__(self, parent=None, flags=Qt.WindowFlags(0), model=None, **kwargs): QDialog.__init__(self, parent, flags, **kwargs) self.__setupUi() if model is not None: self.setModel(model) def __setupUi(self): layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0) heading = self.tr("Preview") heading = "<h3>{0}</h3>".format(heading) self.__heading = QLabel(heading, self, objectName="heading") self.__heading.setContentsMargins(12, 12, 12, 0) self.__browser = previewbrowser.PreviewBrowser(self) self.__buttons = QDialogButtonBox(QDialogButtonBox.Open | \ QDialogButtonBox.Cancel, Qt.Horizontal,) self.__buttons.button(QDialogButtonBox.Open).setAutoDefault(True) # Set the Open dialog as disabled until the current index changes self.__buttons.button(QDialogButtonBox.Open).setEnabled(False) # The QDialogButtonsWidget messes with the layout if it is # contained directly in the QDialog. So we create an extra # layer of indirection. buttons = QWidget(objectName="button-container") buttons_l = QVBoxLayout() buttons_l.setContentsMargins(12, 0, 12, 12) buttons.setLayout(buttons_l) buttons_l.addWidget(self.__buttons) layout.addWidget(self.__heading) layout.addWidget(self.__browser) layout.addWidget(buttons) self.__buttons.accepted.connect(self.accept) self.__buttons.rejected.connect(self.reject) self.__browser.currentIndexChanged.connect( self.__on_currentIndexChanged ) self.__browser.activated.connect(self.__on_activated) layout.setSizeConstraint(QVBoxLayout.SetFixedSize) self.setLayout(layout) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) def setItems(self, items): """Set the items (a list of strings) for preview/selection. """ model = QStringListModel(items) self.setModel(model) def setModel(self, model): """Set the model for preview/selection. """ self.__browser.setModel(model) def model(self): """Return the model. """ return self.__browser.model() def currentIndex(self): return self.__browser.currentIndex() def setCurrentIndex(self, index): """Set the current selected (shown) index. """ self.__browser.setCurrentIndex(index) def setHeading(self, heading): """Set `heading` as the heading string ('<h3>Preview</h3>' by default). """ self.__heading.setText(heading) def heading(self): """Return the heading string. """ def __on_currentIndexChanged(self, index): button = self.__buttons.button(QDialogButtonBox.Open) button.setEnabled(index >= 0) self.currentIndexChanged.emit(index) def __on_activated(self, index): if self.currentIndex() != index: self.setCurrentIndex(index) self.accept()
class NotificationMessageWidget(QWidget): #: Emitted when a button with the AcceptRole is clicked accepted = Signal() #: Emitted when a button with the RejectRole is clicked rejected = Signal() #: Emitted when a button is clicked clicked = Signal(QAbstractButton) class StandardButton(enum.IntEnum): NoButton, Ok, Close = 0x0, 0x1, 0x2 NoButton, Ok, Close = list(StandardButton) class ButtonRole(enum.IntEnum): InvalidRole, AcceptRole, RejectRole, DismissRole = 0, 1, 2, 3 InvalidRole, AcceptRole, RejectRole, DismissRole = list(ButtonRole) _Button = namedtuple("_Button", ["button", "role", "stdbutton"]) def __init__(self, parent=None, icon=QIcon(), title="", text="", wordWrap=False, textFormat=Qt.PlainText, standardButtons=NoButton, acceptLabel="Ok", rejectLabel="No", **kwargs): super().__init__(parent, **kwargs) self._title = title self._text = text self._icon = QIcon() self._wordWrap = wordWrap self._standardButtons = NotificationMessageWidget.NoButton self._buttons = [] self._acceptLabel = acceptLabel self._rejectLabel = rejectLabel self._iconlabel = QLabel(objectName="icon-label") self._titlelabel = QLabel(objectName="title-label", text=title, wordWrap=wordWrap, textFormat=textFormat) self._textlabel = QLabel(objectName="text-label", text=text, wordWrap=wordWrap, textFormat=textFormat) self._textlabel.setTextInteractionFlags(Qt.TextBrowserInteraction) self._textlabel.setOpenExternalLinks(True) if sys.platform == "darwin": self._titlelabel.setAttribute(Qt.WA_MacSmallSize) self._textlabel.setAttribute(Qt.WA_MacSmallSize) layout = QHBoxLayout() self._iconlabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self._iconlabel) layout.setAlignment(self._iconlabel, Qt.AlignTop) message_layout = QVBoxLayout() self._titlelabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) if sys.platform == "darwin": self._titlelabel.setContentsMargins(0, 1, 0, 0) else: self._titlelabel.setContentsMargins(0, 0, 0, 0) message_layout.addWidget(self._titlelabel) self._textlabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) message_layout.addWidget(self._textlabel) self.button_layout = QHBoxLayout() self.button_layout.setAlignment(Qt.AlignLeft) message_layout.addLayout(self.button_layout) layout.addLayout(message_layout) layout.setSpacing(7) self.setLayout(layout) self.setIcon(icon) self.setStandardButtons(standardButtons) def setText(self, text): """ Set the current message text. :type message: str """ if self._text != text: self._text = text self._textlabel.setText(text) def text(self): """ Return the current message text. :rtype: str """ return self._text def setTitle(self, title): """ Set the current title text. :type title: str """ if self._title != title: self._title = title self._titleLabel.setText(title) def title(self): """ Return the current title text. :rtype: str """ return self._title def setIcon(self, icon): """ Set the message icon. :type icon: QIcon | QPixmap | QString | QStyle.StandardPixmap """ if isinstance(icon, QStyle.StandardPixmap): icon = self.style().standardIcon(icon) else: icon = QIcon(icon) if self._icon != icon: self._icon = QIcon(icon) if not self._icon.isNull(): size = self.style().pixelMetric(QStyle.PM_SmallIconSize, None, self) pm = self._icon.pixmap(QSize(size, size)) else: pm = QPixmap() self._iconlabel.setPixmap(pm) self._iconlabel.setVisible(not pm.isNull()) def icon(self): """ Return the current icon. :rtype: QIcon """ return QIcon(self._icon) def setWordWrap(self, wordWrap): """ Set the message text wrap property :type wordWrap: bool """ if self._wordWrap != wordWrap: self._wordWrap = wordWrap self._textlabel.setWordWrap(wordWrap) def wordWrap(self): """ Return the message text wrap property. :rtype: bool """ return self._wordWrap def setTextFormat(self, textFormat): """ Set message text format :type textFormat: Qt.TextFormat """ self._textlabel.setTextFormat(textFormat) def textFormat(self): """ Return the message text format. :rtype: Qt.TextFormat """ return self._textlabel.textFormat() def setAcceptLabel(self, label): """ Set the accept button label. :type label: str """ self._acceptLabel = label def acceptLabel(self): """ Return the accept button label. :rtype str """ return self._acceptLabel def setRejectLabel(self, label): """ Set the reject button label. :type label: str """ self._rejectLabel = label def rejectLabel(self): """ Return the reject button label. :rtype str """ return self._rejectLabel def setStandardButtons(self, buttons): for button in NotificationMessageWidget.StandardButton: existing = self.button(button) if button & buttons and existing is None: self.addButton(button) elif existing is not None: self.removeButton(existing) def standardButtons(self): return functools.reduce( operator.ior, (slot.stdbutton for slot in self._buttons if slot.stdbutton is not None), NotificationMessageWidget.NoButton) def addButton(self, button, *rolearg): """ addButton(QAbstractButton, ButtonRole) addButton(str, ButtonRole) addButton(StandardButton) Add and return a button """ stdbutton = None if isinstance(button, QAbstractButton): if len(rolearg) != 1: raise TypeError("Wrong number of arguments for " "addButton(QAbstractButton, role)") role = rolearg[0] elif isinstance(button, NotificationMessageWidget.StandardButton): if rolearg: raise TypeError("Wrong number of arguments for " "addButton(StandardButton)") stdbutton = button if button == NotificationMessageWidget.Ok: role = NotificationMessageWidget.AcceptRole button = QPushButton(self._acceptLabel, default=False, autoDefault=False) elif button == NotificationMessageWidget.Close: role = NotificationMessageWidget.RejectRole button = QPushButton(self._rejectLabel, default=False, autoDefault=False) elif isinstance(button, str): if len(rolearg) != 1: raise TypeError("Wrong number of arguments for " "addButton(str, ButtonRole)") role = rolearg[0] button = QPushButton(button, default=False, autoDefault=False) if sys.platform == "darwin": button.setAttribute(Qt.WA_MacSmallSize) self._buttons.append( NotificationMessageWidget._Button(button, role, stdbutton)) button.clicked.connect(self._button_clicked) self._relayout() return button def _relayout(self): for slot in self._buttons: self.button_layout.removeWidget(slot.button) order = { NotificationWidget.AcceptRole: 0, NotificationWidget.RejectRole: 1, } ordered = sorted([ b for b in self._buttons if self.buttonRole(b.button) != NotificationMessageWidget.DismissRole ], key=lambda slot: order.get(slot.role, -1)) prev = self._textlabel for slot in ordered: self.button_layout.addWidget(slot.button) QWidget.setTabOrder(prev, slot.button) def removeButton(self, button): """ Remove a `button`. :type button: QAbstractButton """ slot = [s for s in self._buttons if s.button is button] if slot: slot = slot[0] self._buttons.remove(slot) self.layout().removeWidget(slot.button) slot.button.setParent(None) def buttonRole(self, button): """ Return the ButtonRole for button :type button: QAbstractButton """ for slot in self._buttons: if slot.button is button: return slot.role return NotificationMessageWidget.InvalidRole def button(self, standardButton): """ Return the button for the StandardButton. :type standardButton: StandardButton """ for slot in self._buttons: if slot.stdbutton == standardButton: return slot.button return None def _button_clicked(self): button = self.sender() role = self.buttonRole(button) self.clicked.emit(button) if role == NotificationMessageWidget.AcceptRole: self.accepted.emit() self.close() elif role == NotificationMessageWidget.RejectRole: self.rejected.emit() self.close()