def __init__(self, parent=None, title="", text="", textFormat=Qt.AutoText, icon=QIcon(), wordWrap=True, standardButtons=NoButton, acceptLabel="Ok", rejectLabel="No", **kwargs): super().__init__(parent, **kwargs) self._margin = 10 # used in stylesheet and for dismiss button layout = QHBoxLayout() if sys.platform == "darwin": layout.setContentsMargins(6, 6, 6, 6) else: layout.setContentsMargins(9, 9, 9, 9) self.setStyleSheet(""" NotificationWidget { margin: """ + str(self._margin) + """px; background: #626262; border: 1px solid #999999; border-radius: 8px; } NotificationWidget QLabel#text-label { color: white; } NotificationWidget QLabel#title-label { color: white; font-weight: bold; }""") self._msgwidget = NotificationMessageWidget( parent=self, title=title, text=text, textFormat=textFormat, icon=icon, wordWrap=wordWrap, standardButtons=standardButtons, acceptLabel=acceptLabel, rejectLabel=rejectLabel) self._msgwidget.accepted.connect(self.accepted) self._msgwidget.rejected.connect(self.rejected) self._msgwidget.clicked.connect(self.clicked) self._dismiss_button = SimpleButton( parent=self, icon=QIcon(self.style().standardIcon( QStyle.SP_TitleBarCloseButton))) self._dismiss_button.setFixedSize(18, 18) self._dismiss_button.clicked.connect(self.dismissed) def dismiss_handler(): self.clicked.emit(self._dismiss_button) self._dismiss_button.clicked.connect(dismiss_handler) layout.addWidget(self._msgwidget) self.setLayout(layout) self.setFixedWidth(400)
def set_basic_layout(self): """Provide the basic widget layout Which parts are created is regulated by class attributes `want_main_area`, `want_control_area`, `want_message_bar` and `buttons_area_orientation`, the presence of method `send_report` and attribute `graph_name`. """ self.setLayout(QVBoxLayout()) self.layout().setContentsMargins(2, 2, 2, 2) if not self.resizing_enabled: self.layout().setSizeConstraint(QVBoxLayout.SetFixedSize) self.want_main_area = self.want_main_area or self.graph_name self._create_default_buttons() self._insert_splitter() if self.want_control_area: self._insert_control_area() if self.want_main_area: self._insert_main_area() if self.want_message_bar: # Use a OverlayWidget for status bar positioning. c = OverlayWidget(self, alignment=Qt.AlignBottom) c.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) c.setWidget(self) c.setLayout(QVBoxLayout()) c.layout().setContentsMargins(0, 0, 0, 0) sb = QStatusBar() sb.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Maximum) sb.setSizeGripEnabled(self.resizing_enabled) c.layout().addWidget(sb) help = self.__help_action icon = QIcon(gui.resource_filename("icons/help.svg")) icon.addFile(gui.resource_filename("icons/help-hover.svg"), mode=QIcon.Active) help_button = SimpleButton( icon=icon, toolTip="Show widget help", visible=help.isVisible(), ) @help.changed.connect def _(): help_button.setVisible(help.isVisible()) help_button.setEnabled(help.isEnabled()) help_button.clicked.connect(help.trigger) sb.addWidget(help_button) if self.graph_name is not None: icon = QIcon(gui.resource_filename("icons/chart.svg")) icon.addFile(gui.resource_filename("icons/chart-hover.svg"), mode=QIcon.Active) b = SimpleButton( icon=icon, toolTip="Save Image", ) b.clicked.connect(self.save_graph) sb.addWidget(b) if hasattr(self, "send_report"): icon = QIcon(gui.resource_filename("icons/report.svg")) icon.addFile(gui.resource_filename("icons/report-hover.svg"), mode=QIcon.Active) b = SimpleButton(icon=icon, toolTip="Report") b.clicked.connect(self.show_report) sb.addWidget(b) self.message_bar = MessagesWidget(self) self.message_bar.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) pb = QProgressBar(maximumWidth=120, minimum=0, maximum=100) pb.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Ignored) pb.setAttribute(Qt.WA_LayoutUsesWidgetRect) pb.setAttribute(Qt.WA_MacMiniSize) pb.hide() sb.addPermanentWidget(pb) sb.addPermanentWidget(self.message_bar) def statechanged(): pb.setVisible(bool(self.processingState) or self.isBlocking()) if self.isBlocking() and not self.processingState: pb.setRange(0, 0) # indeterminate pb elif self.processingState: pb.setRange(0, 100) # determinate pb self.processingStateChanged.connect(statechanged) self.blockingStateChanged.connect(statechanged) @self.progressBarValueChanged.connect def _(val): pb.setValue(int(val)) # Reserve the bottom margins for the status bar margins = self.layout().contentsMargins() margins.setBottom(sb.sizeHint().height()) self.setContentsMargins(margins)
class NotificationWidget(QWidget): #: Emitted when a button with an Accept role is clicked accepted = Signal() #: Emitted when a button with a Reject role is clicked rejected = Signal() #: Emitted when a button with a Dismiss role is clicked dismissed = Signal() #: Emitted when a button is clicked clicked = Signal(QAbstractButton) NoButton, Ok, Close = list(NotificationMessageWidget.StandardButton) InvalidRole, AcceptRole, RejectRole, DismissRole = \ list(NotificationMessageWidget.ButtonRole) def __init__(self, parent=None, title="", text="", textFormat=Qt.AutoText, icon=QIcon(), wordWrap=True, standardButtons=NoButton, acceptLabel="Ok", rejectLabel="No", **kwargs): super().__init__(parent, **kwargs) self._margin = 10 # used in stylesheet and for dismiss button layout = QHBoxLayout() if sys.platform == "darwin": layout.setContentsMargins(6, 6, 6, 6) else: layout.setContentsMargins(9, 9, 9, 9) self.setStyleSheet(""" NotificationWidget { margin: """ + str(self._margin) + """px; background: #626262; border: 1px solid #999999; border-radius: 8px; } NotificationWidget QLabel#text-label { color: white; } NotificationWidget QLabel#title-label { color: white; font-weight: bold; }""") self._msgwidget = NotificationMessageWidget( parent=self, title=title, text=text, textFormat=textFormat, icon=icon, wordWrap=wordWrap, standardButtons=standardButtons, acceptLabel=acceptLabel, rejectLabel=rejectLabel) self._msgwidget.accepted.connect(self.accepted) self._msgwidget.rejected.connect(self.rejected) self._msgwidget.clicked.connect(self.clicked) self._dismiss_button = SimpleButton( parent=self, icon=QIcon(self.style().standardIcon( QStyle.SP_TitleBarCloseButton))) self._dismiss_button.setFixedSize(18, 18) self._dismiss_button.clicked.connect(self.dismissed) def dismiss_handler(): self.clicked.emit(self._dismiss_button) self._dismiss_button.clicked.connect(dismiss_handler) layout.addWidget(self._msgwidget) self.setLayout(layout) self.setFixedWidth(400) def resizeEvent(self, event): super().resizeEvent(event) if sys.platform == "darwin": corner_margin = 6 else: corner_margin = 7 x = self.width() - self._dismiss_button.width( ) - self._margin - corner_margin y = self._margin + corner_margin self._dismiss_button.move(x, y) def clone(self): cloned = NotificationWidget( parent=self.parent(), title=self.title(), text=self.text(), textFormat=self._msgwidget.textFormat(), icon=self.icon(), standardButtons=self._msgwidget.standardButtons(), acceptLabel=self._msgwidget.acceptLabel(), rejectLabel=self._msgwidget.rejectLabel()) cloned.accepted.connect(self.accepted) cloned.rejected.connect(self.rejected) cloned.dismissed.connect(self.dismissed) # each canvas displays a clone of the original notification, # therefore the cloned buttons' events are connected to the original's # pylint: disable=protected-access button_map = dict( zip([b.button for b in cloned._msgwidget._buttons] + [cloned._dismiss_button], [b.button for b in self._msgwidget._buttons] + [self._dismiss_button])) cloned.clicked.connect(lambda b: self.clicked.emit(button_map[b])) return cloned def paintEvent(self, event): opt = QStyleOption() opt.initFrom(self) painter = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self) @proxydoc(NotificationMessageWidget.setText) def setText(self, text): self._msgwidget.setText(text) @proxydoc(NotificationMessageWidget.text) def text(self): return self._msgwidget.text() @proxydoc(NotificationMessageWidget.setTitle) def setTitle(self, title): self._msgwidget.setTitle(title) @proxydoc(NotificationMessageWidget.title) def title(self): return self._msgwidget.title() @proxydoc(NotificationMessageWidget.setIcon) def setIcon(self, icon): self._msgwidget.setIcon(icon) @proxydoc(NotificationMessageWidget.icon) def icon(self): return self._msgwidget.icon() @proxydoc(NotificationMessageWidget.textFormat) def textFormat(self): return self._msgwidget.textFormat() @proxydoc(NotificationMessageWidget.setTextFormat) def setTextFormat(self, textFormat): self._msgwidget.setTextFormat(textFormat) @proxydoc(NotificationMessageWidget.setStandardButtons) def setStandardButtons(self, buttons): self._msgwidget.setStandardButtons(buttons) @proxydoc(NotificationMessageWidget.addButton) def addButton(self, *args): return self._msgwidget.addButton(*args) @proxydoc(NotificationMessageWidget.removeButton) def removeButton(self, button): self._msgwidget.removeButton(button) @proxydoc(NotificationMessageWidget.buttonRole) def buttonRole(self, button): if button is self._dismiss_button: return NotificationWidget.DismissRole return self._msgwidget.buttonRole(button) @proxydoc(NotificationMessageWidget.button) def button(self, standardButton): return self._msgwidget.button(standardButton)