123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- from qtpy import QtCore
- from qtpy.QtCore import Qt
- from qtpy import QtGui
- from qtpy.QtGui import QPalette
- from qtpy import QtWidgets
- from qtpy.QtWidgets import QStyle
- # https://stackoverflow.com/a/2039745/4158863
- class HTMLDelegate(QtWidgets.QStyledItemDelegate):
- def __init__(self, parent=None):
- super(HTMLDelegate, self).__init__()
- self.doc = QtGui.QTextDocument(self)
- def paint(self, painter, option, index):
- painter.save()
- options = QtWidgets.QStyleOptionViewItem(option)
- self.initStyleOption(options, index)
- self.doc.setHtml(options.text)
- options.text = ""
- style = (
- QtWidgets.QApplication.style()
- if options.widget is None
- else options.widget.style()
- )
- style.drawControl(QStyle.CE_ItemViewItem, options, painter)
- ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
- if option.state & QStyle.State_Selected:
- ctx.palette.setColor(
- QPalette.Text,
- option.palette.color(
- QPalette.Active, QPalette.HighlightedText
- ),
- )
- else:
- ctx.palette.setColor(
- QPalette.Text,
- option.palette.color(QPalette.Active, QPalette.Text),
- )
- textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options)
- if index.column() != 0:
- textRect.adjust(5, 0, 0, 0)
- thefuckyourshitup_constant = 4
- margin = (option.rect.height() - options.fontMetrics.height()) // 2
- margin = margin - thefuckyourshitup_constant
- textRect.setTop(textRect.top() + margin)
- painter.translate(textRect.topLeft())
- painter.setClipRect(textRect.translated(-textRect.topLeft()))
- self.doc.documentLayout().draw(painter, ctx)
- painter.restore()
- def sizeHint(self, option, index):
- thefuckyourshitup_constant = 4
- return QtCore.QSize(
- self.doc.idealWidth(),
- self.doc.size().height() - thefuckyourshitup_constant,
- )
- class LabelListWidgetItem(QtGui.QStandardItem):
- def __init__(self, text=None, shape=None):
- super(LabelListWidgetItem, self).__init__()
- self.setText(text)
- self.setShape(shape)
- self.setCheckable(True)
- self.setCheckState(Qt.Checked)
- self.setEditable(False)
- self.setTextAlignment(Qt.AlignBottom)
- def clone(self):
- return LabelListWidgetItem(self.text(), self.shape())
- def setShape(self, shape):
- self.setData(shape, Qt.UserRole)
- def shape(self):
- return self.data(Qt.UserRole)
- def __hash__(self):
- return id(self)
- def __repr__(self):
- return '{}("{}")'.format(self.__class__.__name__, self.text())
- class LabelListWidget(QtWidgets.QListView):
- itemDoubleClicked = QtCore.Signal(LabelListWidgetItem)
- itemSelectionChanged = QtCore.Signal(list, list)
- itemDropped = QtCore.Signal()
- def __init__(self):
- super(LabelListWidget, self).__init__()
- self._selectedItems = []
- self.setWindowFlags(Qt.Window)
- self.setModel(QtGui.QStandardItemModel())
- self.model().setItemPrototype(LabelListWidgetItem())
- self.setItemDelegate(HTMLDelegate())
- self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
- self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
- self.setDefaultDropAction(Qt.MoveAction)
- self.doubleClicked.connect(self.itemDoubleClickedEvent)
- self.selectionModel().selectionChanged.connect(
- self.itemSelectionChangedEvent
- )
- def __len__(self):
- return self.model().rowCount()
- def __getitem__(self, i):
- return self.model().item(i)
- def __iter__(self):
- for i in range(len(self)):
- yield self[i]
- def dropEvent(self, event):
- super(LabelListWidget, self).dropEvent(event)
- self.itemDropped.emit()
- @property
- def itemChanged(self):
- return self.model().itemChanged
- def itemSelectionChangedEvent(self, selected, deselected):
- selected = [self.model().itemFromIndex(i) for i in selected.indexes()]
- deselected = [
- self.model().itemFromIndex(i) for i in deselected.indexes()
- ]
- self.itemSelectionChanged.emit(selected, deselected)
- def itemDoubleClickedEvent(self, index):
- self.itemDoubleClicked.emit(self.model().itemFromIndex(index))
- def selectedItems(self):
- return [self.model().itemFromIndex(i) for i in self.selectedIndexes()]
- def scrollToItem(self, item):
- self.scrollTo(self.model().indexFromItem(item))
- def addItem(self, item):
- if not isinstance(item, LabelListWidgetItem):
- raise TypeError("item must be LabelListWidgetItem")
- self.model().setItem(self.model().rowCount(), 0, item)
- item.setSizeHint(self.itemDelegate().sizeHint(None, None))
- def selectItem(self, item):
- index = self.model().indexFromItem(item)
- self.selectionModel().select(index, QtCore.QItemSelectionModel.Select)
- def findItemByShape(self, shape):
- for row in range(self.model().rowCount()):
- item = self.model().item(row, 0)
- if item.shape() == shape:
- return item
- def clear(self):
- self.model().clear()
|