def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): """Renders the delegate using the given painter and style option for the item specified by index. :param painter: A QPainter object to draw :param option: Options to describe what should be drawn :param index: _description_ """ if not index.isValid(): return # Initialize the style options. This is not very Pythonic as it uses C++ # references under the hood so opt is affected by the second call opt = QStyleOptionViewItem(option) self.initStyleOption(opt, index) # Standard setup, paint, restore operation painter.save() try: painter.setClipRect(opt.rect) foreground_colour, background_colour = index.data(Qt.ForegroundRole), index.data(Qt.BackgroundRole) if foreground_colour is not None: painter.setPen(foreground_colour) if background_colour is not None: painter.fillRect(option.rect, background_colour) padding = self._padding opt.rect = option.rect.adjusted(padding, padding, -padding, -padding) painter.drawText(opt.rect, int(Qt.AlignLeft | Qt.AlignVCenter), opt.fontMetrics.elidedText(opt.text, Qt.ElideRight, opt.rect.width())) finally: painter.restore()
def paint(self, painter, option, index): options = QStyleOptionViewItem(option) self.initStyleOption(options, index) style = QApplication.style() if options.widget is None else options.widget.style() doc = QTextDocument() doc.setDocumentMargin(self._margin) doc.setHtml(options.text) options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) painter.save() if style.objectName() == "oxygen": painter.translate(textRect.topLeft() + QPoint(5, -9)) else: painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): options = QStyleOptionViewItem(option) self.initStyleOption(options, index) style = (QApplication.style() if options.widget is None else options.widget.style()) doc = QTextDocument() doc.setDocumentMargin(self._margin) doc.setHtml(options.text) options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) painter.save() # Adjustments for the file switcher if hasattr(options.widget, 'files_list'): if style.objectName() in ['oxygen', 'qtcurve', 'breeze']: if options.widget.files_list: painter.translate(textRect.topLeft() + QPoint(4, -9)) else: painter.translate(textRect.topLeft()) else: if options.widget.files_list: painter.translate(textRect.topLeft() + QPoint(4, 4)) else: painter.translate(textRect.topLeft() + QPoint(2, 4)) else: painter.translate(textRect.topLeft() + QPoint(0, -3)) doc.documentLayout().draw(painter, ctx) painter.restore()
def _style_option(self, index): """Get default style option for index""" option = QStyleOptionViewItem() option.font = self.font() option.rect = self.visualRect(index) option.state = QStyle.State_Enabled return option
def paint( self, painter: QPainter, style: QStyleOptionViewItem, model: QModelIndex, ): style2 = QStyleOptionViewItem(style) cbar_rect = QRect( style.rect.x(), style.rect.y() + PADDING, style.rect.width() - TEXT_WIDTH, style.rect.height() - 2 * PADDING, ) text_rect = QRect( style.rect.width() - TEXT_WIDTH, style.rect.y() + PADDING, style.rect.width(), style.rect.height() - 2 * PADDING, ) style2.rect = text_rect super().paint(painter, style2, model) cbar = make_colorbar(ensure_colormap(model.data()), (18, 100)) image = QImage( cbar, cbar.shape[1], cbar.shape[0], QImage.Format_RGBA8888, ) painter.drawImage(cbar_rect, image)
def paint(self, painter, option, index): options = QStyleOptionViewItem(option) self.initStyleOption(options, index) style = (QApplication.style() if options.widget is None else options.widget.style()) doc = QTextDocument() doc.setDocumentMargin(self._margin) doc.setHtml(options.text) options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options) painter.save() if style.objectName() == 'oxygen': painter.translate(textRect.topLeft() + QPoint(5, -9)) else: painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
def paint(self, painter, option, index): options = QStyleOptionViewItem(option) self.initStyleOption(options, index) style = (QApplication.style() if options.widget is None else options.widget.style()) doc = QTextDocument() text = options.text doc.setHtml(text) doc.setDocumentMargin(0) # This needs to be an empty string to avoid the overlapping the # normal text of the QTreeWidgetItem options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options, None) painter.save() painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
def test_custom_eliding_delegate_respects_padding(self): padding = 3 delegate = CustomTextElidingDelegate(padding) painter = mock.MagicMock(spec=QPainter) # we cannot mock the style & index as they are passed to a C++ type that expects real types style, model = QStyleOptionViewItem(), QStandardItemModel(1, 1) style.rect = QRect(0, 0, 99, 29) # give a non-zero sized rectangle to paint in text = str(math.pi) model.setData(model.index(0, 0), text, Qt.DisplayRole) delegate.paint(painter, style, model.index(0, 0)) painter.save.assert_called_once() painter.setPen.assert_not_called() painter.fillRect.assert_not_called() painter.drawText.assert_called_once() painter.restore.assert_called_once() # first call and second argument is the text that will be painted # the exact text depends on the font metric so we have a looser requirement # for matching drawn_text = painter.drawText.call_args[0][2] self.assertTrue(drawn_text.startswith("3.141592")) # Qt uses the 'horizontal ellipsis' unicode symbol for ellision. # To avoid confusion with it look like 3 separate '.' characters in code # we use the unicode codepoint directly self.assertTrue(drawn_text.endswith(b"\xe2\x80\xa6".decode("utf-8")))
def _draw_fold_indicator(self, top, mouse_over, collapsed, painter): """ Draw the fold indicator/trigger (arrow). :param top: Top position :param mouse_over: Whether the mouse is over the indicator :param collapsed: Whether the trigger is collapsed or not. :param painter: QPainter """ rect = QRect(0, top, self.sizeHint().width(), self.sizeHint().height()) if self._native_icons: opt = QStyleOptionViewItem() opt.rect = rect opt.state = (QStyle.State_Active | QStyle.State_Item | QStyle.State_Children) if not collapsed: opt.state |= QStyle.State_Open if mouse_over: opt.state |= (QStyle.State_MouseOver | QStyle.State_Enabled | QStyle.State_Selected) opt.palette.setBrush(QPalette.Window, self.palette().highlight()) opt.rect.translate(-2, 0) self.style().drawPrimitive(QStyle.PE_IndicatorBranch, opt, painter, self) else: index = 0 if not collapsed: index = 2 if mouse_over: index += 1 ima.icon(self._indicators_icons[index]).paint(painter, rect)
def test_custom_eliding_delegate_respects_forgeround_color(self): padding = 3 delegate = CustomTextElidingDelegate(padding) painter = mock.MagicMock(spec=QPainter) # we cannot mock the style & index as they are passed to a C++ type that expects real types style, model = QStyleOptionViewItem(), QStandardItemModel(1, 1) style.rect = QRect(0, 0, 99, 29) # give a non-zero sized rectangle to paint in text, foreground = str(math.pi), QColor(10, 10, 10) model.setData(model.index(0, 0), text, Qt.DisplayRole) model.setData(model.index(0, 0), foreground, Qt.ForegroundRole) delegate.paint(painter, style, model.index(0, 0)) painter.setPen.assert_called_once_with(foreground) painter.fillRect.assert_not_called()
def paint(self, painter, option, index): """ Overrides the selection highlight color. https://www.qtcentre.org/threads/41299-How-to-Change-QTreeView-highlight-color Note: this can actually do alot more than that with the QPalette... which is something I should learn how to use apparently... """ from qtpy.QtGui import QPalette item = index.internalPointer() new_option = QStyleOptionViewItem(option) brush = QBrush() if item.isEnabled(): color = QColor(*iColor["rgba_text"]) else: color = QColor(*iColor["rgba_text_disabled"]) # TODO highlight selection color??? # why did I move this here? brush.setColor(color) # brush2 = QBrush(QColor(0, 255, 0, 128)) new_option.palette.setBrush(QPalette.Normal, QPalette.HighlightedText, brush) # new_option.palette.setBrush(QPalette.Normal, QPalette.Highlight, brush2) QStyledItemDelegate.paint(self, painter, new_option, index) # if option.state == QStyle.State_Selected: # brush2 = QBrush(QColor(0, 255, 255, 128)) return
def sizeHint(self, option, index): options = QStyleOptionViewItem(option) self.initStyleOption(options, index) doc = QTextDocument() doc.setHtml(options.text) doc.setTextWidth(options.rect.width()) size = QSize(int(doc.idealWidth()), int(doc.size().height())) return size
def sizeHint(self, option, index): options = QStyleOptionViewItem(option) self.initStyleOption(options, index) doc = QTextDocument() doc.setHtml(options.text) return QSize(doc.idealWidth(), doc.size().height() - 2)
def test_custom_eliding_delegate_respects_background_color(self): padding = 3 delegate = CustomTextElidingDelegate(padding) painter = mock.MagicMock(spec=QPainter) # we cannot mock the style & index as they are passed to a C++ type that expects real types style, model = QStyleOptionViewItem(), QStandardItemModel(1, 1) style.rect = QRect(0, 0, 99, 29) # give a non-zero sized rectangle to paint in text, background = str(math.pi), QColor(5, 5, 5) model.setData(model.index(0, 0), text, Qt.DisplayRole) model.setData(model.index(0, 0), background, Qt.BackgroundRole) delegate.paint(painter, style, model.index(0, 0)) painter.setPen.assert_not_called() painter.fillRect.assert_called_once() # the background color object seems different but we only care about value equality self.assertEqual(background, painter.fillRect.call_args[0][1])
def _prepare_text_document(self, option, index): # This logic must be shared between paint and sizeHint for consistency options = QStyleOptionViewItem(option) self.initStyleOption(options, index) doc = QTextDocument() doc.setDocumentMargin(self._margin) doc.setHtml(options.text) return options, doc
def paint(self, painter, option, index): options = QStyleOptionViewItem(option) self.initStyleOption(options, index) style = (QApplication.style() if options.widget is None else options.widget.style()) # Set background color for selected and hovered items. # Inspired by: # - https://stackoverflow.com/a/43253004/438386 # - https://stackoverflow.com/a/27274233/438386 # This is commented for now until we find a way to correctly colorize # the entire line with a single color. # if options.state & QStyle.State_Selected: # # This only applies when the selected item doesn't have focus # if not (options.state & QStyle.State_HasFocus): # options.palette.setBrush( # QPalette.Highlight, # QBrush(self._background_color) # ) if options.state & QStyle.State_MouseOver: painter.fillRect(option.rect, self._background_color) # Set text doc = QTextDocument() text = options.text doc.setHtml(text) doc.setDocumentMargin(0) # This needs to be an empty string to avoid overlapping the # normal text of the QTreeWidgetItem options.text = "" style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options, None) painter.save() painter.translate(textRect.topLeft() + QPoint(0, 4)) doc.documentLayout().draw(painter, ctx) painter.restore()
def test_custom_eliding_delegate_does_nothing_for_invalid_indices(self): delegate = CustomTextElidingDelegate(padding=5) painter = mock.MagicMock(spec=QPainter) # we cannot mock the style &index as they are passed to a C++ type that expects real types style, invalid_index = QStyleOptionViewItem(), QModelIndex() delegate.paint(painter, style, invalid_index) painter.save.assert_not_called() painter.drawText.assert_not_called() painter.restore.assert_not_called()
def initStyleOption(self, option: QStyleOptionViewItem, index: QModelIndex) -> None: super().initStyleOption(option, index) option.textElideMode = Qt.ElideMiddle
def paint(self, painter, options, index): new_options = QStyleOptionViewItem(options) text_color = self.get_text_color(index.data()) new_options.palette.setColor(QPalette.Text, text_color) super(StatusItemDelegate, self).paint(painter, new_options, index)