def decorate_welcome_icon(icon, background_color): """Return a `QIcon` with a circle shaped background. """ welcome_icon = QIcon() sizes = [32, 48, 64, 80, 128, 256] background_color = NAMED_COLORS.get(background_color, background_color) background_color = QColor(background_color) grad = radial_gradient(background_color) for size in sizes: icon_size = QSize(5 * size / 8, 5 * size / 8) icon_rect = QRect(QPoint(0, 0), icon_size) pixmap = QPixmap(size, size) pixmap.fill(Qt.transparent) p = QPainter(pixmap) p.setRenderHint(QPainter.Antialiasing, True) p.setBrush(QBrush(grad)) p.setPen(Qt.NoPen) ellipse_rect = QRect(0, 0, size, size) p.drawEllipse(ellipse_rect) icon_rect.moveCenter(ellipse_rect.center()) icon.paint(p, icon_rect, Qt.AlignCenter, ) p.end() welcome_icon.addPixmap(pixmap) return welcome_icon
class IconWidget(QWidget): """ A widget displaying an `QIcon` """ def __init__(self, parent=None, icon=QIcon(), iconSize=QSize(), **kwargs): sizePolicy = kwargs.pop("sizePolicy", QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) super().__init__(parent, **kwargs) self.__icon = QIcon(icon) self.__iconSize = QSize(iconSize) self.setSizePolicy(sizePolicy) def setIcon(self, icon): # type: (QIcon) -> None if self.__icon != icon: self.__icon = QIcon(icon) self.updateGeometry() self.update() def icon(self): # type: () -> QIcon return QIcon(self.__icon) def iconSize(self): # type: () -> QSize if not self.__iconSize.isValid(): size = self.style().pixelMetric(QStyle.PM_ButtonIconSize) return QSize(size, size) else: return QSize(self.__iconSize) def setIconSize(self, iconSize): # type: (QSize) -> None if self.__iconSize != iconSize: self.__iconSize = QSize(iconSize) self.updateGeometry() self.update() def sizeHint(self): sh = self.iconSize() m = self.contentsMargins() return QSize(sh.width() + m.left() + m.right(), sh.height() + m.top() + m.bottom()) def paintEvent(self, event): painter = QStylePainter(self) opt = QStyleOption() opt.initFrom(self) painter.drawPrimitive(QStyle.PE_Widget, opt) if not self.__icon.isNull(): rect = self.contentsRect() if opt.state & QStyle.State_Active: mode = QIcon.Active else: mode = QIcon.Disabled self.__icon.paint(painter, rect, Qt.AlignCenter, mode, QIcon.Off) painter.end()
def __init__(self, *args, **kwargs): QDockWidget.__init__(self, *args, **kwargs) self.__expandedWidget = None self.__collapsedWidget = None self.__expanded = True self.__trueMinimumWidth = -1 self.setFeatures(QDockWidget.DockWidgetClosable | \ QDockWidget.DockWidgetMovable) self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.featuresChanged.connect(self.__onFeaturesChanged) self.dockLocationChanged.connect(self.__onDockLocationChanged) # Use the toolbar horizontal extension button icon as the default # for the expand/collapse button icon = self.style().standardIcon( QStyle.SP_ToolBarHorizontalExtensionButton) # Mirror the icon transform = QTransform() transform = transform.scale(-1.0, 1.0) icon_rev = QIcon() for s in (8, 12, 14, 16, 18, 24, 32, 48, 64): pm = icon.pixmap(s, s) icon_rev.addPixmap(pm.transformed(transform)) self.__iconRight = QIcon(icon) self.__iconLeft = QIcon(icon_rev) close = self.findChild(QAbstractButton, name="qt_dockwidget_closebutton") close.installEventFilter(self) self.__closeButton = close self.__stack = AnimatedStackedWidget() self.__stack.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.__stack.transitionStarted.connect(self.__onTransitionStarted) self.__stack.transitionFinished.connect(self.__onTransitionFinished) QDockWidget.setWidget(self, self.__stack) self.__closeButton.setIcon(self.__iconLeft)
def __init__(self, *args): super().__init__(*args) self.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.__backgroundIcon = QIcon() self.__autoScroll = False self.__autoScrollMargin = 16 self.__autoScrollTimer = QTimer(self) self.__autoScrollTimer.timeout.connect(self.__autoScrollAdvance) # scale factor accumulating partial increments from wheel events self.__zoomLevel = 100 # effective scale level(rounded to whole integers) self.__effectiveZoomLevel = 100 self.__zoomInAction = QAction( self.tr("Zoom in"), self, objectName="action-zoom-in", shortcut=QKeySequence.ZoomIn, triggered=self.zoomIn, ) self.__zoomOutAction = QAction( self.tr("Zoom out"), self, objectName="action-zoom-out", shortcut=QKeySequence.ZoomOut, triggered=self.zoomOut ) self.__zoomResetAction = QAction( self.tr("Reset Zoom"), self, objectName="action-zoom-reset", triggered=self.zoomReset, shortcut=QKeySequence(Qt.ControlModifier | Qt.Key_0) )
def __init__(self, parent=None, icon=None, iconSize=None, **kwargs): QGraphicsItem.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemUsesExtendedStyleOption, True) if icon is None: icon = QIcon() if iconSize is None: style = QApplication.instance().style() size = style.pixelMetric(style.PM_LargeIconSize) iconSize = QSize(size, size) self.__transformationMode = Qt.SmoothTransformation self.__iconSize = QSize(iconSize) self.__icon = QIcon(icon) self._opacity = 1 self.anim = QPropertyAnimation(self, b"opacity") self.anim.setDuration(350) self.anim.setStartValue(1) self.anim.setKeyValueAt(0.5, 0) self.anim.setEndValue(1) self.anim.setEasingCurve(QEasingCurve.OutQuad) self.anim.setLoopCount(5)
def __init__(self, parent=None, icon=QIcon(), text="", wordWrap=False, textFormat=Qt.AutoText, standardButtons=NoButton, **kwargs): super().__init__(parent, **kwargs) self.__text = text self.__icon = QIcon() self.__wordWrap = wordWrap self.__standardButtons = MessageWidget.NoButton self.__buttons = [] layout = QHBoxLayout() layout.setContentsMargins(8, 0, 8, 0) self.__iconlabel = QLabel(objectName="icon-label") self.__iconlabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.__textlabel = QLabel(objectName="text-label", text=text, wordWrap=wordWrap, textFormat=textFormat) if sys.platform == "darwin": self.__textlabel.setAttribute(Qt.WA_MacSmallSize) layout.addWidget(self.__iconlabel) layout.addWidget(self.__textlabel) self.setLayout(layout) self.setIcon(icon) self.setStandardButtons(standardButtons)
def __init__(self, parent=None, icon=QIcon(), iconSize=QSize(), **kwargs): sizePolicy = kwargs.pop("sizePolicy", QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) super().__init__(parent, **kwargs) self.__icon = QIcon(icon) self.__iconSize = QSize(iconSize) self.setSizePolicy(sizePolicy)
def setIcon(self, icon): """ Set the icon (:class:`QIcon`). """ if self.__icon != icon: self.__icon = QIcon(icon) self.update()
def get(self, name, default=None): path = self.find(name) if not path: path = self.find(self.DEFAULT_ICON if default is None else default) if not path: raise IOError(2, "Cannot find %r in %s" % (name, self.search_paths())) if self.is_icon_glob(path): icons = self.icon_glob(path) else: icons = [path] from AnyQt.QtGui import QIcon icon = QIcon() for path in icons: icon.addFile(path) return icon
def __init__(self, *args): QGraphicsView.__init__(self, *args) self.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.__backgroundIcon = QIcon() self.__autoScroll = False self.__autoScrollMargin = 16 self.__autoScrollTimer = QTimer(self) self.__autoScrollTimer.timeout.connect(self.__autoScrollAdvance)
def get(self, name, default=None): if name: path = self.find(name) else: path = None if path is None: path = self.find(self.DEFAULT_ICON if default is None else default) if path is None: return QIcon() if self.is_icon_glob(path): icons = self.icon_glob(path) else: icons = [path] icon = QIcon() for path in icons: icon.addFile(path) return icon
def __init__(self, parent=None, icon=None, iconSize=None, **kwargs): QGraphicsItem.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemUsesExtendedStyleOption, True) if icon is None: icon = QIcon() if iconSize is None: style = QApplication.instance().style() size = style.pixelMetric(style.PM_LargeIconSize) iconSize = QSize(size, size) self.__transformationMode = Qt.SmoothTransformation self.__iconSize = QSize(iconSize) self.__icon = QIcon(icon)
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 welcome_dialog_paged(self): # type: (CanvasMainWindow) -> None """ Show a modal multipaged welcome screen. """ dlg = PagedDialog( self, windowTitle=self.tr("Orange Data Mining"), ) dlg.setWindowModality(Qt.ApplicationModal) dlg.setAttribute(Qt.WA_DeleteOnClose) dlg.layout().setSizeConstraint(QVBoxLayout.SetFixedSize) dlg.setStyleSheet(""" TabView::item:selected { background: rgb(243, 171, 86); } """) main = FancyWelcomeScreen() spec = welcome_screen_specs() if spec.image: background = QImage(spec.image) else: background = QImage("canvas_icons:orange-start-background.png") main.setImage(background) if spec.css: main.setStyleSheet(spec.css) else: main.setStyleSheet( "StartItem { background-color: rgb(123, 164, 214) }") def decorate_icon(icon): return decorate_welcome_icon(icon, "#6dacb2") for i, item in zip(range(3), spec.items): main.setItemText(i, item.text) main.setItemToolTip(i, item.tooltip) main.setItemIcon(i, decorate_icon(QIcon(item.icon))) main.setItemActiveIcon(i, decorate_icon(QIcon(item.active_icon))) main.item(i).setProperty("path", item.path) main.setCurrentIndex(0) main.activated.connect(lambda: openselectedbutton.click()) PageWelcome = dlg.addPage(sc_icon("Welcome.svg"), "Welcome", main) examples = workflows.example_workflows() items = [previewmodel.PreviewItem(path=t.abspath()) for t in examples] model = previewmodel.PreviewModel(items=items) model.delayedScanUpdate() browser = previewbrowser.PreviewBrowser() browser.setModel(model) PageTemplates = dlg.addPage(sc_icon("Templates.svg"), "Templates", browser) browser.activated.connect(lambda: openselectedbutton.click()) recent = [ previewmodel.PreviewItem(name=item.title, path=item.path) for item in self.recent_schemes ] model = previewmodel.PreviewModel(items=recent) browser = previewbrowser.PreviewBrowser() browser.setModel(model) model.delayedScanUpdate() PageRecent = dlg.addPage(self.recent_action.icon(), "Recent", browser) browser.activated.connect(lambda: openselectedbutton.click()) dlg.setPageEnabled(PageRecent, model.rowCount() > 0) page = SingleLinkPage( image=QImage( resource_path("icons/getting-started-video-tutorials.png")), heading="Getting Started", link=QUrl("https://www.youtube.com/watch?v=3nMcI4Hxm7c"), ) page.setContentsMargins(25, 25, 25, 25) PageGetStarted = dlg.addPage( canvas_icons("YouTube.svg"), "Get Started", page, ) buttons = dlg.buttonBox() buttons.setVisible(True) buttons.setStandardButtons(QDialogButtonBox.Open | QDialogButtonBox.Cancel) # choose the selected workflow button openselectedbutton = buttons.button(QDialogButtonBox.Open) openselectedbutton.setText(self.tr("Open")) openselectedbutton.setToolTip("Open the selected workflow") openselectedbutton.setDefault(True) newbutton = QPushButton("New", toolTip="Create a new workflow") s = QShortcut(QKeySequence.New, newbutton) s.activated.connect(newbutton.click) buttons.addButton(newbutton, QDialogButtonBox.AcceptRole) openexisting = QPushButton("Open Existing\N{HORIZONTAL ELLIPSIS}", toolTip="Open an existing workflow file") s = QShortcut(QKeySequence.Open, dlg) s.activated.connect(openexisting.click) buttons.addButton(openexisting, QDialogButtonBox.AcceptRole) settings = QSettings() show_start_key = "startup/show-welcome-screen" show_start = QCheckBox("Show at startup", checked=settings.value(show_start_key, True, type=bool)) # Abusing ResetRole to push the check box to the left in all button # layouts. buttons.addButton(show_start, QDialogButtonBox.ResetRole) def update_show_at_startup(value): settings.setValue(show_start_key, value) show_start.toggled.connect(update_show_at_startup) def on_page_changed(index): if index == PageWelcome: openselectedbutton.setEnabled(True) elif index == PageTemplates: openselectedbutton.setEnabled(bool(examples)) elif index == PageRecent: openselectedbutton.setEnabled(bool(recent)) elif index == PageGetStarted: openselectedbutton.setEnabled(False) else: openselectedbutton.setEnabled(False) dlg.currentIndexChanged.connect(on_page_changed) def open_example_workflow(path): # open a workflow without filename/directory tracking. wf = self.new_scheme_from(path) if self.is_transient(): window = self else: window = self.create_new_window() window.show() window.raise_() window.activateWindow() window.set_new_scheme(wf) def on_clicked(button): current = dlg.currentIndex() path = None open_workflow_file = None if current in {PageTemplates, PageWelcome}: open_workflow_file = open_example_workflow elif current == PageRecent: open_workflow_file = self.open_scheme_file if button is openselectedbutton and \ current in {PageTemplates, PageRecent}: w = dlg.widget(current) assert isinstance(w, previewbrowser.PreviewBrowser) assert w.currentIndex() != -1 model = w.model() item = model.item(w.currentIndex()) path = item.path() elif button is openselectedbutton and current == PageWelcome: w = dlg.widget(current) assert isinstance(w, FancyWelcomeScreen) assert w.currentIndex() != -1 path = w.item(w.currentIndex()).property("path") if path is not None: open_workflow_file(path) dlg.accept() buttons.clicked.connect(on_clicked) def on_open_existing(): filedlg = self._open_workflow_dialog() filedlg.fileSelected.connect(self.open_scheme_file) filedlg.accepted.connect(dlg.accept) filedlg.exec() openexisting.clicked.connect(on_open_existing) def new_window(): if not self.is_transient(): self.new_workflow_window() dlg.accept() newbutton.clicked.connect(new_window) dlg.show()
class GraphicsIconItem(QGraphicsWidget): """ A graphics item displaying an :class:`QIcon`. """ def __init__(self, parent=None, icon=None, iconSize=None, **kwargs): QGraphicsItem.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemUsesExtendedStyleOption, True) if icon is None: icon = QIcon() if iconSize is None: style = QApplication.instance().style() size = style.pixelMetric(style.PM_LargeIconSize) iconSize = QSize(size, size) self.__transformationMode = Qt.SmoothTransformation self.__iconSize = QSize(iconSize) self.__icon = QIcon(icon) self._opacity = 1 self.anim = QPropertyAnimation(self, b"opacity") self.anim.setDuration(350) self.anim.setStartValue(1) self.anim.setKeyValueAt(0.5, 0) self.anim.setEndValue(1) self.anim.setEasingCurve(QEasingCurve.OutQuad) self.anim.setLoopCount(5) def setIcon(self, icon): """ Set the icon (:class:`QIcon`). """ if self.__icon != icon: self.__icon = QIcon(icon) self.update() def getOpacity(self): return self._opacity def setOpacity(self, o): self._opacity = o self.update() opacity = Property(float, fget=getOpacity, fset=setOpacity) def icon(self): """ Return the icon (:class:`QIcon`). """ return QIcon(self.__icon) def setIconSize(self, size): """ Set the icon (and this item's) size (:class:`QSize`). """ if self.__iconSize != size: self.prepareGeometryChange() self.__iconSize = QSize(size) self.update() def iconSize(self): """ Return the icon size (:class:`QSize`). """ return QSize(self.__iconSize) def setTransformationMode(self, mode): """ Set pixmap transformation mode. (`Qt.SmoothTransformation` or `Qt.FastTransformation`). """ if self.__transformationMode != mode: self.__transformationMode = mode self.update() def transformationMode(self): """ Return the pixmap transformation mode. """ return self.__transformationMode def boundingRect(self): return QRectF(0, 0, self.__iconSize.width(), self.__iconSize.height()) def paint(self, painter, option, widget=None): if not self.__icon.isNull(): if option.state & QStyle.State_Selected: mode = QIcon.Selected elif option.state & QStyle.State_Enabled: mode = QIcon.Normal elif option.state & QStyle.State_Active: mode = QIcon.Active else: mode = QIcon.Disabled w, h = self.__iconSize.width(), self.__iconSize.height() target = QRect(0, 0, w, h) painter.setRenderHint( QPainter.SmoothPixmapTransform, self.__transformationMode == Qt.SmoothTransformation ) painter.setOpacity(self._opacity) self.__icon.paint(painter, target, Qt.AlignCenter, mode)
class MessageWidget(QWidget): """ A widget displaying a simple message to the user. This is an alternative to a full QMessageBox intended for inline modeless messages. [[icon] {Message text} (Ok) (Cancel)] """ #: 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 with the HelpRole is clicked helpRequested = Signal() #: Emitted when a button is clicked clicked = Signal(QAbstractButton) class StandardButton(enum.IntEnum): NoButton, Ok, Close, Help = 0x0, 0x1, 0x2, 0x4 NoButton, Ok, Close, Help = list(StandardButton) class ButtonRole(enum.IntEnum): InvalidRole, AcceptRole, RejectRole, HelpRole = 0, 1, 2, 3 InvalidRole, AcceptRole, RejectRole, HelpRole = list(ButtonRole) _Button = namedtuple("_Button", ["button", "role", "stdbutton"]) def __init__(self, parent=None, icon=QIcon(), text="", wordWrap=False, textFormat=Qt.AutoText, standardButtons=NoButton, **kwargs): super().__init__(parent, **kwargs) self.__text = text self.__icon = QIcon() self.__wordWrap = wordWrap self.__standardButtons = MessageWidget.NoButton self.__buttons = [] layout = QHBoxLayout() layout.setContentsMargins(8, 0, 8, 0) self.__iconlabel = QLabel(objectName="icon-label") self.__iconlabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.__textlabel = QLabel(objectName="text-label", text=text, wordWrap=wordWrap, textFormat=textFormat) if sys.platform == "darwin": self.__textlabel.setAttribute(Qt.WA_MacSmallSize) layout.addWidget(self.__iconlabel) layout.addWidget(self.__textlabel) 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 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 changeEvent(self, event): # reimplemented if event.type() == 177: # QEvent.MacSizeChange: ... super().changeEvent(event) def setStandardButtons(self, buttons): for button in MessageWidget.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), MessageWidget.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, MessageWidget.StandardButton): if len(rolearg) != 0: raise TypeError("Wrong number of arguments for " "addButton(StandardButton)") stdbutton = button if button == MessageWidget.Ok: role = MessageWidget.AcceptRole button = QPushButton("Ok", default=False, autoDefault=False) elif button == MessageWidget.Close: role = MessageWidget.RejectRole # button = QPushButton( # default=False, autoDefault=False, flat=True, # icon=QIcon(self.style().standardIcon( # QStyle.SP_TitleBarCloseButton))) button = SimpleButton( icon=QIcon(self.style().standardIcon( QStyle.SP_TitleBarCloseButton))) elif button == MessageWidget.Help: role = MessageWidget.HelpRole button = QPushButton("Help", 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(MessageWidget._Button(button, role, stdbutton)) button.clicked.connect(self.__button_clicked) self.__relayout() return 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: QAbsstractButton """ for slot in self.__buttons: if slot.button is button: return slot.role else: return MessageWidget.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 else: return None def __button_clicked(self): button = self.sender() role = self.buttonRole(button) self.clicked.emit(button) if role == MessageWidget.AcceptRole: self.accepted.emit() self.close() elif role == MessageWidget.RejectRole: self.rejected.emit() self.close() elif role == MessageWidget.HelpRole: self.helpRequested.emit() def __relayout(self): for slot in self.__buttons: self.layout().removeWidget(slot.button) order = { MessageOverlayWidget.HelpRole: 0, MessageOverlayWidget.AcceptRole: 2, MessageOverlayWidget.RejectRole: 3, } orderd = sorted(self.__buttons, key=lambda slot: order.get(slot.role, -1)) prev = self.__textlabel for slot in orderd: self.layout().addWidget(slot.button) QWidget.setTabOrder(prev, slot.button)
def summarize(messages): # type: (List[Message]) -> Message """ Summarize a list of messages into a single message instance Parameters ---------- messages: List[Message] Returns ------- message: Message """ if not messages: return Message() if len(messages) == 1: return messages[0] lead, errors, warnings, info = categorize(messages) severity = Severity.Information icon = QIcon() leading_text = "" text_parts = [] if lead is not None: severity = lead.severity icon = lead.icon leading_text = lead.text elif errors: severity = Severity.Error elif warnings: severity = Severity.Warning def format_plural(fstr, items, *args, **kwargs): return fstr.format(len(items), *args, s="s" if len(items) != 1 else "", **kwargs) if errors: text_parts.append(format_plural("{} error{s}", errors)) if warnings: text_parts.append(format_plural("{} warning{s}", warnings)) if info: if not (errors and warnings and lead): text_parts.append(format_plural("{} message{s}", info)) else: text_parts.append(format_plural("{} other", info)) if leading_text: text = leading_text if text_parts: text = text + " (" + ", ".join(text_parts) + ")" else: text = ", ".join(text_parts) detailed = "<hr/>".join(m.asHtml() for m in chain([lead], errors, warnings, info) if m is not None and not m.isEmpty()) return Message(severity, icon, text, detailedText=detailed, textFormat=Qt.RichText)
def icon(self): # type: () -> QIcon return QIcon(self.__icon)
def icon(self, value): if isinstance(value, (str, bytes)): self._form.setIcon(QIcon(value)) else: self._form.setIcon(value)
def backgroundIcon(self): return QIcon(self.__backgroundIcon)
def sc_icon(filename): return QIcon( pkg_resources.resource_filename("orangecontrib.single_cell.launcher", "icons/" + filename))
class CanvasView(QGraphicsView): """Canvas View handles the zooming. """ def __init__(self, *args): QGraphicsView.__init__(self, *args) self.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.__backgroundIcon = QIcon() self.__autoScroll = False self.__autoScrollMargin = 16 self.__autoScrollTimer = QTimer(self) self.__autoScrollTimer.timeout.connect(self.__autoScrollAdvance) def setScene(self, scene): QGraphicsView.setScene(self, scene) self._ensureSceneRect(scene) def _ensureSceneRect(self, scene): r = scene.addRect(QRectF(0, 0, 400, 400)) scene.sceneRect() scene.removeItem(r) def setAutoScrollMargin(self, margin): self.__autoScrollMargin = margin def autoScrollMargin(self): return self.__autoScrollMargin def setAutoScroll(self, enable): self.__autoScroll = enable def autoScroll(self): return self.__autoScroll def mousePressEvent(self, event): QGraphicsView.mousePressEvent(self, event) def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: if not self.__autoScrollTimer.isActive() and \ self.__shouldAutoScroll(event.pos()): self.__startAutoScroll() QGraphicsView.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): if event.button() & Qt.LeftButton: self.__stopAutoScroll() return QGraphicsView.mouseReleaseEvent(self, event) def __shouldAutoScroll(self, pos): if self.__autoScroll: margin = self.__autoScrollMargin viewrect = self.contentsRect() rect = viewrect.adjusted(margin, margin, -margin, -margin) # only do auto scroll when on the viewport's margins return not rect.contains(pos) and viewrect.contains(pos) else: return False def __startAutoScroll(self): self.__autoScrollTimer.start(10) log.debug("Auto scroll timer started") def __stopAutoScroll(self): if self.__autoScrollTimer.isActive(): self.__autoScrollTimer.stop() log.debug("Auto scroll timer stopped") def __autoScrollAdvance(self): """Advance the auto scroll """ pos = QCursor.pos() pos = self.mapFromGlobal(pos) margin = self.__autoScrollMargin vvalue = self.verticalScrollBar().value() hvalue = self.horizontalScrollBar().value() vrect = QRect(0, 0, self.width(), self.height()) # What should be the speed advance = 10 # We only do auto scroll if the mouse is inside the view. if vrect.contains(pos): if pos.x() < vrect.left() + margin: self.horizontalScrollBar().setValue(hvalue - advance) if pos.y() < vrect.top() + margin: self.verticalScrollBar().setValue(vvalue - advance) if pos.x() > vrect.right() - margin: self.horizontalScrollBar().setValue(hvalue + advance) if pos.y() > vrect.bottom() - margin: self.verticalScrollBar().setValue(vvalue + advance) if self.verticalScrollBar().value() == vvalue and \ self.horizontalScrollBar().value() == hvalue: self.__stopAutoScroll() else: self.__stopAutoScroll() log.debug("Auto scroll advance") def setBackgroundIcon(self, icon): if not isinstance(icon, QIcon): raise TypeError("A QIcon expected.") if self.__backgroundIcon != icon: self.__backgroundIcon = icon self.viewport().update() def backgroundIcon(self): return QIcon(self.__backgroundIcon) def drawBackground(self, painter, rect): QGraphicsView.drawBackground(self, painter, rect) if not self.__backgroundIcon.isNull(): painter.setClipRect(rect) vrect = QRect(QPoint(0, 0), self.viewport().size()) vrect = self.mapToScene(vrect).boundingRect() pm = self.__backgroundIcon.pixmap( vrect.size().toSize().boundedTo(QSize(200, 200)) ) pmrect = QRect(QPoint(0, 0), pm.size()) pmrect.moveCenter(vrect.center().toPoint()) if rect.toRect().intersects(pmrect): painter.drawPixmap(pmrect, pm)
def setIconActive(self, icon): self.__icon_active = QIcon(icon) self.update()
def iconActive(self): return QIcon(self.__icon_active)
def setIcon(self, icon): self.__icon = QIcon(icon) self.update()
def icon(self): if self.__active: return QIcon(self.__icon_active) else: return QIcon(self.__icon)
def icon(self): """ Return the icon. """ return QIcon(self.__icon)
def qvariant_to_icon(variant): value = qtcompat.qunwrap(variant) if isinstance(value, QIcon): return value else: return QIcon()
class GraphicsIconItem(QGraphicsItem): """ A graphics item displaying an :class:`QIcon`. """ def __init__(self, parent=None, icon=None, iconSize=None, **kwargs): QGraphicsItem.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemUsesExtendedStyleOption, True) if icon is None: icon = QIcon() if iconSize is None: style = QApplication.instance().style() size = style.pixelMetric(style.PM_LargeIconSize) iconSize = QSize(size, size) self.__transformationMode = Qt.SmoothTransformation self.__iconSize = QSize(iconSize) self.__icon = QIcon(icon) def setIcon(self, icon): """ Set the icon (:class:`QIcon`). """ if self.__icon != icon: self.__icon = QIcon(icon) self.update() def icon(self): """ Return the icon (:class:`QIcon`). """ return QIcon(self.__icon) def setIconSize(self, size): """ Set the icon (and this item's) size (:class:`QSize`). """ if self.__iconSize != size: self.prepareGeometryChange() self.__iconSize = QSize(size) self.update() def iconSize(self): """ Return the icon size (:class:`QSize`). """ return QSize(self.__iconSize) def setTransformationMode(self, mode): """ Set pixmap transformation mode. (`Qt.SmoothTransformation` or `Qt.FastTransformation`). """ if self.__transformationMode != mode: self.__transformationMode = mode self.update() def transformationMode(self): """ Return the pixmap transformation mode. """ return self.__transformationMode def boundingRect(self): return QRectF(0, 0, self.__iconSize.width(), self.__iconSize.height()) def paint(self, painter, option, widget=None): if not self.__icon.isNull(): if option.state & QStyle.State_Selected: mode = QIcon.Selected elif option.state & QStyle.State_Enabled: mode = QIcon.Normal elif option.state & QStyle.State_Active: mode = QIcon.Active else: mode = QIcon.Disabled w, h = self.__iconSize.width(), self.__iconSize.height() target = QRect(0, 0, w, h) painter.setRenderHint( QPainter.SmoothPixmapTransform, self.__transformationMode == Qt.SmoothTransformation) self.__icon.paint(painter, target, Qt.AlignCenter, mode)
class CanvasView(QGraphicsView): """Canvas View handles the zooming. """ def __init__(self, *args): super().__init__(*args) self.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.grabGesture(Qt.PinchGesture) self.__backgroundIcon = QIcon() self.__autoScroll = False self.__autoScrollMargin = 16 self.__autoScrollTimer = QTimer(self) self.__autoScrollTimer.timeout.connect(self.__autoScrollAdvance) # scale factor accumulating partial increments from wheel events self.__zoomLevel = 100 # effective scale level(rounded to whole integers) self.__effectiveZoomLevel = 100 self.__zoomInAction = QAction( self.tr("Zoom in"), self, objectName="action-zoom-in", shortcut=QKeySequence.ZoomIn, triggered=self.zoomIn, ) self.__zoomOutAction = QAction(self.tr("Zoom out"), self, objectName="action-zoom-out", shortcut=QKeySequence.ZoomOut, triggered=self.zoomOut) self.__zoomResetAction = QAction( self.tr("Reset Zoom"), self, objectName="action-zoom-reset", triggered=self.zoomReset, shortcut=QKeySequence(Qt.ControlModifier | Qt.Key_0)) def setScene(self, scene): super().setScene(scene) self._ensureSceneRect(scene) def _ensureSceneRect(self, scene): r = scene.addRect(QRectF(0, 0, 400, 400)) scene.sceneRect() scene.removeItem(r) def setAutoScrollMargin(self, margin): self.__autoScrollMargin = margin def autoScrollMargin(self): return self.__autoScrollMargin def setAutoScroll(self, enable): self.__autoScroll = enable def autoScroll(self): return self.__autoScroll def mousePressEvent(self, event): super().mousePressEvent(event) def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: if not self.__autoScrollTimer.isActive() and \ self.__shouldAutoScroll(event.pos()): self.__startAutoScroll() super().mouseMoveEvent(event) def mouseReleaseEvent(self, event): if event.button() & Qt.LeftButton: self.__stopAutoScroll() return super().mouseReleaseEvent(event) def wheelEvent(self, event: QWheelEvent): if event.modifiers() & Qt.ControlModifier \ and event.buttons() == Qt.NoButton: # Zoom delta = event.angleDelta().y() # use mouse position as anchor while zooming anchor = self.transformationAnchor() self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.__setZoomLevel(self.__zoomLevel + 10 * delta / 120) self.setTransformationAnchor(anchor) event.accept() elif event.source() == Qt.MouseEventNotSynthesized \ and (event.angleDelta().x() == 0 \ and not self.verticalScrollBar().isVisible()) \ or (sys.platform == 'darwin' and event.modifiers() & Qt.ShiftModifier or sys.platform != 'darwin' and event.modifiers() & Qt.AltModifier): # Scroll horizontally x, y = event.angleDelta().x(), event.angleDelta().y() sign_value = x if x != 0 else y sign = 1 if sign_value >= 0 else -1 new_angle_delta = QPoint(sign * max(abs(x), abs(y), sign_value), 0) new_pixel_delta = QPoint(0, 0) new_modifiers = event.modifiers() & ~(Qt.ShiftModifier | Qt.AltModifier) new_event = QWheelEvent(event.pos(), event.globalPos(), new_pixel_delta, new_angle_delta, event.buttons(), new_modifiers, event.phase(), event.inverted(), event.source()) event.accept() super().wheelEvent(new_event) else: super().wheelEvent(event) def gestureEvent(self, event: QGestureEvent): gesture = event.gesture(Qt.PinchGesture) if gesture is None: return if gesture.state() == Qt.GestureStarted: event.accept(gesture) elif gesture.changeFlags() & QPinchGesture.ScaleFactorChanged: anchor = gesture.centerPoint().toPoint() anchor = self.mapToScene(anchor) self.__setZoomLevel(self.__zoomLevel * gesture.scaleFactor(), anchor=anchor) event.accept() elif gesture.state() == Qt.GestureFinished: event.accept() def event(self, event: QEvent) -> bool: if event.type() == QEvent.Gesture: self.gestureEvent(cast(QGestureEvent, event)) return super().event(event) def zoomIn(self): self.__setZoomLevel(self.__zoomLevel + 10) def zoomOut(self): self.__setZoomLevel(self.__zoomLevel - 10) def zoomReset(self): """ Reset the zoom level. """ self.__setZoomLevel(100) def zoomLevel(self): # type: () -> float """ Return the current zoom level. Level is expressed in percentages; 100 is unscaled, 50 is half size, ... """ return self.__effectiveZoomLevel def setZoomLevel(self, level): self.__setZoomLevel(level) def __setZoomLevel(self, scale, anchor=None): # type: (float, Optional[QPointF]) -> None self.__zoomLevel = max(30, min(scale, 300)) scale = round(self.__zoomLevel) self.__zoomOutAction.setEnabled(scale != 30) self.__zoomInAction.setEnabled(scale != 300) if self.__effectiveZoomLevel != scale: self.__effectiveZoomLevel = scale transform = QTransform() transform.scale(scale / 100, scale / 100) if anchor is not None: anchor = self.mapFromScene(anchor) self.setTransform(transform) if anchor is not None: center = self.viewport().rect().center() diff = self.mapToScene(center) - self.mapToScene(anchor) self.centerOn(anchor + diff) self.zoomLevelChanged.emit(scale) zoomLevelChanged = Signal(float) zoomLevel_ = Property(float, zoomLevel, setZoomLevel, notify=zoomLevelChanged) def __shouldAutoScroll(self, pos): if self.__autoScroll: margin = self.__autoScrollMargin viewrect = self.contentsRect() rect = viewrect.adjusted(margin, margin, -margin, -margin) # only do auto scroll when on the viewport's margins return not rect.contains(pos) and viewrect.contains(pos) else: return False def __startAutoScroll(self): self.__autoScrollTimer.start(10) log.debug("Auto scroll timer started") def __stopAutoScroll(self): if self.__autoScrollTimer.isActive(): self.__autoScrollTimer.stop() log.debug("Auto scroll timer stopped") def __autoScrollAdvance(self): """Advance the auto scroll """ pos = QCursor.pos() pos = self.mapFromGlobal(pos) margin = self.__autoScrollMargin vvalue = self.verticalScrollBar().value() hvalue = self.horizontalScrollBar().value() vrect = QRect(0, 0, self.width(), self.height()) # What should be the speed advance = 10 # We only do auto scroll if the mouse is inside the view. if vrect.contains(pos): if pos.x() < vrect.left() + margin: self.horizontalScrollBar().setValue(hvalue - advance) if pos.y() < vrect.top() + margin: self.verticalScrollBar().setValue(vvalue - advance) if pos.x() > vrect.right() - margin: self.horizontalScrollBar().setValue(hvalue + advance) if pos.y() > vrect.bottom() - margin: self.verticalScrollBar().setValue(vvalue + advance) if self.verticalScrollBar().value() == vvalue and \ self.horizontalScrollBar().value() == hvalue: self.__stopAutoScroll() else: self.__stopAutoScroll() log.debug("Auto scroll advance") def setBackgroundIcon(self, icon): if not isinstance(icon, QIcon): raise TypeError("A QIcon expected.") if self.__backgroundIcon != icon: self.__backgroundIcon = icon self.viewport().update() def backgroundIcon(self): return QIcon(self.__backgroundIcon) def drawBackground(self, painter, rect): super().drawBackground(painter, rect) if not self.__backgroundIcon.isNull(): painter.setClipRect(rect) vrect = QRect(QPoint(0, 0), self.viewport().size()) vrect = self.mapToScene(vrect).boundingRect() pm = self.__backgroundIcon.pixmap(vrect.size().toSize().boundedTo( QSize(200, 200))) pmrect = QRect(QPoint(0, 0), pm.size()) pmrect.moveCenter(vrect.center().toPoint()) if rect.toRect().intersects(pmrect): painter.drawPixmap(pmrect, pm)
def icon(self): """ Return the icon (:class:`QIcon`). """ return QIcon(self.__icon)
def toNotification(self): return Notification(title=self.title, text=self.text, accept_button_label=self.accept_button_label, reject_button_label=self.reject_button_label, icon=QIcon(resource_filename(self.icon)))
def application_icon(): """ Return the main application icon. """ path = pkg_resources.resource_filename(__name__, "icons/orange-canvas.svg") return QIcon(path)
def setIcon(self, icon): # type: (QIcon) -> None if self.__icon != icon: self.__icon = QIcon(icon) self.updateGeometry() self.update()
def __init__(self, color=QColor(Qt.white), size=12): p = QPixmap(size, size) p.fill(color) self.color = color QIcon.__init__(self, p)
def icon(self): return QIcon(super().icon)
def __init__(self, parent): super().__init__(parent) self._icon_remove = QIcon(pkg_resources.resource_filename( __name__, "icons/delete.svg")) self._icon_scheme = QIcon(pkg_resources.resource_filename( __name__, "icons/scheme.svg"))
class IconWidget(QWidget): """ A widget displaying an `QIcon` """ def __init__(self, parent=None, icon=QIcon(), iconSize=QSize(), **kwargs): sizePolicy = kwargs.pop( "sizePolicy", QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) super().__init__(parent, **kwargs) self._opacity = 1 self.__icon = QIcon(icon) self.__iconSize = QSize(iconSize) self.setSizePolicy(sizePolicy) def setIcon(self, icon): # type: (QIcon) -> None if self.__icon != icon: self.__icon = QIcon(icon) self.updateGeometry() self.update() def getOpacity(self): return self._opacity def setOpacity(self, o): self._opacity = o self.update() opacity = Property(float, fget=getOpacity, fset=setOpacity) def icon(self): # type: () -> QIcon return QIcon(self.__icon) def iconSize(self): # type: () -> QSize if not self.__iconSize.isValid(): size = self.style().pixelMetric(QStyle.PM_ButtonIconSize) return QSize(size, size) else: return QSize(self.__iconSize) def setIconSize(self, iconSize): # type: (QSize) -> None if self.__iconSize != iconSize: self.__iconSize = QSize(iconSize) self.updateGeometry() self.update() def sizeHint(self): sh = self.iconSize() m = self.contentsMargins() return QSize(sh.width() + m.left() + m.right(), sh.height() + m.top() + m.bottom()) def paintEvent(self, event): painter = QStylePainter(self) painter.setOpacity(self._opacity) opt = QStyleOption() opt.initFrom(self) painter.drawPrimitive(QStyle.PE_Widget, opt) if not self.__icon.isNull(): rect = self.contentsRect() if opt.state & QStyle.State_Active: mode = QIcon.Active else: mode = QIcon.Disabled self.__icon.paint(painter, rect, Qt.AlignCenter, mode, QIcon.Off) painter.end()
def _clear_icons(self): model = self.model() for i in range(model.rowCount()): model.item(i, Column.remove).setIcon(QIcon()) model.item(i, Column.scheme).setIcon(QIcon())
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)
def basic_icon(): pixmap = QPixmap(15, 15) pixmap.fill(QColor("red")) return QIcon(pixmap)
class GraphicsIconItem(QGraphicsItem): """ A graphics item displaying an :class:`QIcon`. """ def __init__(self, parent=None, icon=None, iconSize=None, **kwargs): QGraphicsItem.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemUsesExtendedStyleOption, True) if icon is None: icon = QIcon() if iconSize is None: style = QApplication.instance().style() size = style.pixelMetric(style.PM_LargeIconSize) iconSize = QSize(size, size) self.__transformationMode = Qt.SmoothTransformation self.__iconSize = QSize(iconSize) self.__icon = QIcon(icon) def setIcon(self, icon): """ Set the icon (:class:`QIcon`). """ if self.__icon != icon: self.__icon = QIcon(icon) self.update() def icon(self): """ Return the icon (:class:`QIcon`). """ return QIcon(self.__icon) def setIconSize(self, size): """ Set the icon (and this item's) size (:class:`QSize`). """ if self.__iconSize != size: self.prepareGeometryChange() self.__iconSize = QSize(size) self.update() def iconSize(self): """ Return the icon size (:class:`QSize`). """ return QSize(self.__iconSize) def setTransformationMode(self, mode): """ Set pixmap transformation mode. (`Qt.SmoothTransformation` or `Qt.FastTransformation`). """ if self.__transformationMode != mode: self.__transformationMode = mode self.update() def transformationMode(self): """ Return the pixmap transformation mode. """ return self.__transformationMode def boundingRect(self): return QRectF(0, 0, self.__iconSize.width(), self.__iconSize.height()) def paint(self, painter, option, widget=None): if not self.__icon.isNull(): if option.state & QStyle.State_Selected: mode = QIcon.Selected elif option.state & QStyle.State_Enabled: mode = QIcon.Normal elif option.state & QStyle.State_Active: mode = QIcon.Active else: mode = QIcon.Disabled transform = self.sceneTransform() if widget is not None: # 'widget' is the QGraphicsView.viewport() view = widget.parent() if isinstance(view, QGraphicsView): # Combine the scene transform with the view transform. view_transform = view.transform() transform = view_transform * view_transform lod = option.levelOfDetailFromTransform(transform) w, h = self.__iconSize.width(), self.__iconSize.height() target = QRectF(0, 0, w, h) source = QRectF(0, 0, w * lod, w * lod).toRect() # The actual size of the requested pixmap can be smaller. size = self.__icon.actualSize(source.size(), mode=mode) source.setSize(size) pixmap = self.__icon.pixmap(source.size(), mode=mode) painter.setRenderHint( QPainter.SmoothPixmapTransform, self.__transformationMode == Qt.SmoothTransformation ) painter.drawPixmap(target, pixmap, QRectF(source))
import os from AnyQt.QtGui import QIcon, QPixmap from AnyQt.QtWidgets import QStyle, qApp def path(filename): """ :param filename: :return: """ return os.path.join(os.path.dirname(__file__), filename) PYFORMS_ICON_VIDEOPLAYER_PAUSE_PLAY = QIcon() PYFORMS_ICON_VIDEOPLAYER_PAUSE_PLAY.addPixmap(qApp.style().standardPixmap( QStyle.SP_MediaPlay), mode=QIcon.Normal, state=QIcon.Off) PYFORMS_ICON_VIDEOPLAYER_PAUSE_PLAY.addPixmap(qApp.style().standardPixmap( QStyle.SP_MediaPause), mode=QIcon.Normal, state=QIcon.On) PYFORMS_ICON_VIDEOPLAYER_DETACH = QIcon() PYFORMS_ICON_VIDEOPLAYER_DETACH.addPixmap(qApp.style().standardPixmap( QStyle.SP_TitleBarMaxButton), mode=QIcon.Normal) PYFORMS_ICON_CODEEDITOR_SAVE = QIcon(qApp.style().standardPixmap( QStyle.SP_DialogSaveButton)) PYFORMS_ICON_CODEEDITOR_DISCARD = QIcon(qApp.style().standardPixmap(
def _paletteicon(self, colors, size): return QIcon( createDiscPalettePixmap(size.width(), size.height(), colors))
def variable_icon(dtype): vtype = _VarMap.get(dtype, dtype) try: return gui.attributeIconDict[vtype] except Exception: return QIcon()
class CanvasView(QGraphicsView): """Canvas View handles the zooming. """ def __init__(self, *args): super().__init__(*args) self.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.__backgroundIcon = QIcon() self.__autoScroll = False self.__autoScrollMargin = 16 self.__autoScrollTimer = QTimer(self) self.__autoScrollTimer.timeout.connect(self.__autoScrollAdvance) # scale factor accumulating partial increments from wheel events self.__zoomLevel = 100 # effective scale level(rounded to whole integers) self.__effectiveZoomLevel = 100 self.__zoomInAction = QAction( self.tr("Zoom in"), self, objectName="action-zoom-in", shortcut=QKeySequence.ZoomIn, triggered=self.zoomIn, ) self.__zoomOutAction = QAction( self.tr("Zoom out"), self, objectName="action-zoom-out", shortcut=QKeySequence.ZoomOut, triggered=self.zoomOut ) self.__zoomResetAction = QAction( self.tr("Reset Zoom"), self, objectName="action-zoom-reset", triggered=self.zoomReset, shortcut=QKeySequence(Qt.ControlModifier | Qt.Key_0) ) def setScene(self, scene): super().setScene(scene) self._ensureSceneRect(scene) def _ensureSceneRect(self, scene): r = scene.addRect(QRectF(0, 0, 400, 400)) scene.sceneRect() scene.removeItem(r) def setAutoScrollMargin(self, margin): self.__autoScrollMargin = margin def autoScrollMargin(self): return self.__autoScrollMargin def setAutoScroll(self, enable): self.__autoScroll = enable def autoScroll(self): return self.__autoScroll def mousePressEvent(self, event): super().mousePressEvent(event) def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: if not self.__autoScrollTimer.isActive() and \ self.__shouldAutoScroll(event.pos()): self.__startAutoScroll() super().mouseMoveEvent(event) def mouseReleaseEvent(self, event): if event.button() & Qt.LeftButton: self.__stopAutoScroll() return super().mouseReleaseEvent(event) def wheelEvent(self, event: QWheelEvent): if event.modifiers() & Qt.ControlModifier \ and event.buttons() == Qt.NoButton: delta = event.angleDelta().y() # use mouse position as anchor while zooming anchor = self.transformationAnchor() self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.__setZoomLevel(self.__zoomLevel + 10 * delta / 120) self.setTransformationAnchor(anchor) event.accept() else: super().wheelEvent(event) def zoomIn(self): self.__setZoomLevel(self.__zoomLevel + 10) def zoomOut(self): self.__setZoomLevel(self.__zoomLevel - 10) def zoomReset(self): """ Reset the zoom level. """ self.__setZoomLevel(100) def zoomLevel(self): # type: () -> float """ Return the current zoom level. Level is expressed in percentages; 100 is unscaled, 50 is half size, ... """ return self.__effectiveZoomLevel def setZoomLevel(self, level): self.__setZoomLevel(level) def __setZoomLevel(self, scale): self.__zoomLevel = max(30, min(scale, 300)) scale = round(self.__zoomLevel) self.__zoomOutAction.setEnabled(scale != 30) self.__zoomInAction.setEnabled(scale != 300) if self.__effectiveZoomLevel != scale: self.__effectiveZoomLevel = scale transform = QTransform() transform.scale(scale / 100, scale / 100) self.setTransform(transform) self.zoomLevelChanged.emit(scale) zoomLevelChanged = Signal(float) zoomLevel_ = Property( float, zoomLevel, setZoomLevel, notify=zoomLevelChanged ) def __shouldAutoScroll(self, pos): if self.__autoScroll: margin = self.__autoScrollMargin viewrect = self.contentsRect() rect = viewrect.adjusted(margin, margin, -margin, -margin) # only do auto scroll when on the viewport's margins return not rect.contains(pos) and viewrect.contains(pos) else: return False def __startAutoScroll(self): self.__autoScrollTimer.start(10) log.debug("Auto scroll timer started") def __stopAutoScroll(self): if self.__autoScrollTimer.isActive(): self.__autoScrollTimer.stop() log.debug("Auto scroll timer stopped") def __autoScrollAdvance(self): """Advance the auto scroll """ pos = QCursor.pos() pos = self.mapFromGlobal(pos) margin = self.__autoScrollMargin vvalue = self.verticalScrollBar().value() hvalue = self.horizontalScrollBar().value() vrect = QRect(0, 0, self.width(), self.height()) # What should be the speed advance = 10 # We only do auto scroll if the mouse is inside the view. if vrect.contains(pos): if pos.x() < vrect.left() + margin: self.horizontalScrollBar().setValue(hvalue - advance) if pos.y() < vrect.top() + margin: self.verticalScrollBar().setValue(vvalue - advance) if pos.x() > vrect.right() - margin: self.horizontalScrollBar().setValue(hvalue + advance) if pos.y() > vrect.bottom() - margin: self.verticalScrollBar().setValue(vvalue + advance) if self.verticalScrollBar().value() == vvalue and \ self.horizontalScrollBar().value() == hvalue: self.__stopAutoScroll() else: self.__stopAutoScroll() log.debug("Auto scroll advance") def setBackgroundIcon(self, icon): if not isinstance(icon, QIcon): raise TypeError("A QIcon expected.") if self.__backgroundIcon != icon: self.__backgroundIcon = icon self.viewport().update() def backgroundIcon(self): return QIcon(self.__backgroundIcon) def drawBackground(self, painter, rect): super().drawBackground(painter, rect) if not self.__backgroundIcon.isNull(): painter.setClipRect(rect) vrect = QRect(QPoint(0, 0), self.viewport().size()) vrect = self.mapToScene(vrect).boundingRect() pm = self.__backgroundIcon.pixmap( vrect.size().toSize().boundedTo(QSize(200, 200)) ) pmrect = QRect(QPoint(0, 0), pm.size()) pmrect.moveCenter(vrect.center().toPoint()) if rect.toRect().intersects(pmrect): painter.drawPixmap(pmrect, pm)
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) NoButton, Ok, Close = list(StandardButton)[:3] InvalidRole, AcceptRole, RejectRole = list(ButtonRole)[:3] _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.buttonLayout = QHBoxLayout() self.buttonLayout.setAlignment(Qt.AlignLeft) message_layout.addLayout(self.buttonLayout) 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 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, 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.buttonLayout.removeWidget(slot.button) order = { NotificationWidget.AcceptRole: 0, NotificationWidget.RejectRole: 1, } ordered = sorted([b for b in self._buttons], key=lambda slot: order.get(slot.role, -1)) prev = self._textlabel for slot in ordered: self.buttonLayout.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() elif role == NotificationMessageWidget.RejectRole: self.rejected.emit()
class GraphicsIconItem(QGraphicsItem): """ A graphics item displaying an :class:`QIcon`. """ def __init__(self, parent=None, icon=None, iconSize=None, **kwargs): QGraphicsItem.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemUsesExtendedStyleOption, True) if icon is None: icon = QIcon() if iconSize is None: style = QApplication.instance().style() size = style.pixelMetric(style.PM_LargeIconSize) iconSize = QSize(size, size) self.__transformationMode = Qt.SmoothTransformation self.__iconSize = QSize(iconSize) self.__icon = QIcon(icon) def setIcon(self, icon): """ Set the icon (:class:`QIcon`). """ if self.__icon != icon: self.__icon = QIcon(icon) self.update() def icon(self): """ Return the icon (:class:`QIcon`). """ return QIcon(self.__icon) def setIconSize(self, size): """ Set the icon (and this item's) size (:class:`QSize`). """ if self.__iconSize != size: self.prepareGeometryChange() self.__iconSize = QSize(size) self.update() def iconSize(self): """ Return the icon size (:class:`QSize`). """ return QSize(self.__iconSize) def setTransformationMode(self, mode): """ Set pixmap transformation mode. (`Qt.SmoothTransformation` or `Qt.FastTransformation`). """ if self.__transformationMode != mode: self.__transformationMode = mode self.update() def transformationMode(self): """ Return the pixmap transformation mode. """ return self.__transformationMode def boundingRect(self): return QRectF(0, 0, self.__iconSize.width(), self.__iconSize.height()) def paint(self, painter, option, widget=None): if not self.__icon.isNull(): if option.state & QStyle.State_Selected: mode = QIcon.Selected elif option.state & QStyle.State_Enabled: mode = QIcon.Normal elif option.state & QStyle.State_Active: mode = QIcon.Active else: mode = QIcon.Disabled w, h = self.__iconSize.width(), self.__iconSize.height() target = QRect(0, 0, w, h) painter.setRenderHint( QPainter.SmoothPixmapTransform, self.__transformationMode == Qt.SmoothTransformation ) self.__icon.paint(painter, target, Qt.AlignCenter, mode)
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.buttonLayout = QHBoxLayout() self.buttonLayout.setAlignment(Qt.AlignLeft) message_layout.addLayout(self.buttonLayout) layout.addLayout(message_layout) layout.setSpacing(7) self.setLayout(layout) self.setIcon(icon) self.setStandardButtons(standardButtons)
def _init_ui(self): namesBox = gui.vBox(self.controlArea, "Names") hbox = gui.hBox(namesBox, margin=0, spacing=0) gui.lineEdit(hbox, self, "attr1", "Variable X: ", controlWidth=80, orientation=Qt.Horizontal, callback=self._attr_name_changed) gui.separator(hbox, 21) hbox = gui.hBox(namesBox, margin=0, spacing=0) attr2 = gui.lineEdit(hbox, self, "attr2", "Variable Y: ", controlWidth=80, orientation=Qt.Horizontal, callback=self._attr_name_changed) gui.separator(hbox) gui.checkBox(hbox, self, "hasAttr2", '', disables=attr2, labelWidth=0, callback=self.set_dimensions) gui.separator(namesBox) gui.widgetLabel(namesBox, "Labels") self.classValuesView = listView = QListView( selectionMode=QListView.SingleSelection, sizePolicy=QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Maximum)) listView.setModel(self.class_model) itemmodels.select_row(listView, 0) namesBox.layout().addWidget(listView) self.addClassLabel = QAction("+", self, toolTip="Add new class label", triggered=self.add_new_class_label) self.removeClassLabel = QAction( unicodedata.lookup("MINUS SIGN"), self, toolTip="Remove selected class label", triggered=self.remove_selected_class_label) actionsWidget = itemmodels.ModelActionsWidget( [self.addClassLabel, self.removeClassLabel], self) actionsWidget.layout().addStretch(10) actionsWidget.layout().setSpacing(1) namesBox.layout().addWidget(actionsWidget) tBox = gui.vBox(self.controlArea, "Tools", addSpace=True) buttonBox = gui.hBox(tBox) toolsBox = gui.widgetBox(buttonBox, orientation=QGridLayout()) self.toolActions = QActionGroup(self) self.toolActions.setExclusive(True) self.toolButtons = [] for i, (name, tooltip, tool, icon) in enumerate(self.TOOLS): action = QAction( name, self, toolTip=tooltip, checkable=tool.checkable, icon=QIcon(icon), ) action.triggered.connect(partial(self.set_current_tool, tool)) button = QToolButton(iconSize=QSize(24, 24), toolButtonStyle=Qt.ToolButtonTextUnderIcon, sizePolicy=QSizePolicy( QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)) button.setDefaultAction(action) self.toolButtons.append((button, tool)) toolsBox.layout().addWidget(button, i / 3, i % 3) self.toolActions.addAction(action) for column in range(3): toolsBox.layout().setColumnMinimumWidth(column, 10) toolsBox.layout().setColumnStretch(column, 1) undo = self.undo_stack.createUndoAction(self) redo = self.undo_stack.createRedoAction(self) undo.setShortcut(QKeySequence.Undo) redo.setShortcut(QKeySequence.Redo) self.addActions([undo, redo]) self.undo_stack.indexChanged.connect(lambda _: self.invalidate()) gui.separator(tBox) indBox = gui.indentedBox(tBox, sep=8) form = QFormLayout(formAlignment=Qt.AlignLeft, labelAlignment=Qt.AlignLeft, fieldGrowthPolicy=QFormLayout.AllNonFixedFieldsGrow) indBox.layout().addLayout(form) slider = gui.hSlider(indBox, self, "brushRadius", minValue=1, maxValue=100, createLabel=False) form.addRow("Radius:", slider) slider = gui.hSlider(indBox, self, "density", None, minValue=1, maxValue=100, createLabel=False) form.addRow("Intensity:", slider) self.btResetToInput = gui.button(tBox, self, "Reset to Input Data", self.reset_to_input) self.btResetToInput.setDisabled(True) gui.rubber(self.controlArea) gui.auto_commit(self.left_side, self, "autocommit", "Send") # main area GUI viewbox = PaintViewBox(enableMouse=False) self.plotview = pg.PlotWidget(background="w", viewBox=viewbox) self.plotview.sizeHint = lambda: QSize( 200, 100) # Minimum size for 1-d painting self.plot = self.plotview.getPlotItem() axis_color = self.palette().color(QPalette.Text) axis_pen = QPen(axis_color) tickfont = QFont(self.font()) tickfont.setPixelSize(max(int(tickfont.pixelSize() * 2 // 3), 11)) axis = self.plot.getAxis("bottom") axis.setLabel(self.attr1) axis.setPen(axis_pen) axis.setTickFont(tickfont) axis = self.plot.getAxis("left") axis.setLabel(self.attr2) axis.setPen(axis_pen) axis.setTickFont(tickfont) if not self.hasAttr2: self.plot.hideAxis('left') self.plot.hideButtons() self.plot.setXRange(0, 1, padding=0.01) self.mainArea.layout().addWidget(self.plotview) # enable brush tool self.toolActions.actions()[0].setChecked(True) self.set_current_tool(self.TOOLS[0][2]) self.set_dimensions()
def __init__(self): self.data = None box = gui.vBox(self.controlArea, 'Moving Transform') def _disable_fixed_wlen(): fixed_wlen.setDisabled(not self.non_overlapping) self.view.repaint() self.on_changed() gui.checkBox(box, self, 'non_overlapping', label=self._NON_OVERLAPPING_WINDOWS, callback=_disable_fixed_wlen, tooltip='If this is checked, instead of rolling windows ' 'through the series, they are applied side-to-side, ' 'so the resulting output series will be some ' 'length-of-fixed-window-times shorter.') fixed_wlen = gui.spin(box, self, 'fixed_wlen', 2, 1000, label='Fixed window width:', callback=self.on_changed) fixed_wlen.setDisabled(not self.non_overlapping) # TODO: allow the user to choose left-aligned, right-aligned, or center-aligned window class TableView(gui.TableView): def __init__(self, parent): super().__init__(parent, editTriggers=(self.SelectedClicked | self.CurrentChanged | self.DoubleClicked | self.EditKeyPressed), ) self.horizontalHeader().setStretchLastSection(False) agg_functions = ListModel(AGG_FUNCTIONS + [Cumulative_sum, Cumulative_product], parent=self) self.setItemDelegateForColumn(0, self.VariableDelegate(parent)) self.setItemDelegateForColumn(1, self.SpinDelegate(parent)) self.setItemDelegateForColumn(2, self.ComboDelegate(self, agg_functions)) class _ItemDelegate(QStyledItemDelegate): def updateEditorGeometry(self, widget, option, _index): widget.setGeometry(option.rect) class ComboDelegate(_ItemDelegate): def __init__(self, parent=None, combo_model=None): super().__init__(parent) self._parent = parent if combo_model is not None: self._combo_model = combo_model def createEditor(self, parent, _QStyleOptionViewItem, index): combo = QComboBox(parent) combo.setModel(self._combo_model) return combo def setEditorData(self, combo, index): var = index.model().data(index, Qt.EditRole) combo.setCurrentIndex(self._combo_model.indexOf(var)) def setModelData(self, combo, model, index): var = self._combo_model[combo.currentIndex()] model.setData(index, var, Qt.EditRole) class VariableDelegate(ComboDelegate): @property def _combo_model(self): return self._parent.var_model class SpinDelegate(_ItemDelegate): def paint(self, painter, option, index): # Don't paint window length if non-overlapping windows set if not self.parent().non_overlapping: super().paint(painter, option, index) def createEditor(self, parent, _QStyleOptionViewItem, _index): # Don't edit window length if non-overlapping windows set if self.parent().non_overlapping: return None spin = QSpinBox(parent, minimum=1, maximum=1000) return spin def setEditorData(self, spin, index): spin.setValue(index.model().data(index, Qt.EditRole)) def setModelData(self, spin, model, index): spin.interpretText() model.setData(index, spin.value(), Qt.EditRole) self.var_model = VariableListModel(parent=self) self.table_model = model = PyTableModel(self.transformations, parent=self, editable=True) model.setHorizontalHeaderLabels(['Series', 'Window width', 'Aggregation function']) model.dataChanged.connect(self.on_changed) self.view = view = TableView(self) view.setModel(model) box.layout().addWidget(view) hbox = gui.hBox(box) from os.path import dirname, join self.add_button = button = gui.button( hbox, self, 'Add &Transform', callback=self.on_add_transform) button.setIcon(QIcon(join(dirname(__file__), 'icons', 'LineChart-plus.png'))) self.del_button = button = gui.button( hbox, self, '&Delete Selected', callback=self.on_del_transform) QIcon.setThemeName('gnome') # Works for me button.setIcon(QIcon.fromTheme('edit-delete')) gui.auto_commit(box, self, 'autocommit', '&Apply')