def drop_canvas(self, key: QModelIndex): # TODO: do we use this anywhere? return intent = key.data(IntentsModel.intent_role) canvas = key.data(EnsembleModel.canvas_role) if canvas: canvas_can_be_removed = canvas.unrender(intent) if canvas_can_be_removed: key.model().removeRow(key.row(), key.parent()) key.model().layoutChanged.emit()
def flags(self, index: QModelIndex) -> Qt.ItemFlags: """Returns the item flags for the given `index`. This describes the properties of a given item in the model. We set them to be editable, checkable, dragable, droppable, etc... If index is not a list, we additionally set `Qt.ItemNeverHasChildren` (for optimization). Editable models must return a value containing `Qt.ItemIsEditable`. See Qt.ItemFlags https://doc.qt.io/qt-5/qt.html#ItemFlag-enum """ if ( not index.isValid() or index.row() >= len(self._root) or index.model() is not self ): # we allow drops outside the items return Qt.ItemIsDropEnabled base_flags = ( Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled ) if isinstance(self.getItem(index), MutableSequence): return base_flags | Qt.ItemIsDropEnabled return base_flags | Qt.ItemNeverHasChildren
def editorEvent(self, event: QtCore.QEvent, model: QtCore.QAbstractItemModel, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> bool: decorationRect = option.rect if event.type() == QEvent.MouseButtonPress: item = index.model().data(index, Qt.UserRole) if isinstance(item, QVariant): return QStyledItemDelegate.editorEvent(self, event, model, option, index) type = item['type'] value = item['value'] if type == 'device_activity': text_rect = calculate_text_rect( value['device'], font=ResourceLoader().qt_font_text_xs) if calculate_middle_rect(decorationRect, text_rect.width(), text_rect.height(), x=110, y=15).contains(event.pos()): print('点击了设备{device}'.format(device=value['device'])) return QStyledItemDelegate.editorEvent(self, event, model, option, index)
def canvas_from_index(self, index: QModelIndex): if not index.isValid(): return None if index.data( EnsembleModel.data_type_role) != WorkspaceDataType.Intent: print(f'WARNING: canvas_from_index index {index} is not an intent') return None # Canvas exists for index, return # TODO: in tab view, with multiple intents selected (e.g. 2 rows checked), # non-0 row intents (every intent except first) does not have a valid object in canvas_role canvas = index.model().data(index, EnsembleModel.canvas_role) if canvas: return canvas # There is another canvas we know about we should use for match_index in self.all_intent_indexes(index.model()): if self.is_matching_canvas_type(index, match_index): canvas = match_index.model().data(match_index, EnsembleModel.canvas_role) if canvas is not None: index.model().setData(index, canvas, EnsembleModel.canvas_role) return canvas # Does not exist, create new canvas and return intent = index.model().data(index, EnsembleModel.object_role) canvas_class_name = intent.canvas registry = pluginmanager canvas = self.canvas_from_registry(canvas_class_name, registry, intent.canvas_name) index.model().setData(index, canvas, EnsembleModel.canvas_role) return canvas
def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> None: viewOption = QStyleOptionViewItem(option) self.initStyleOption(viewOption, index) QStyledItemDelegate.paint(self, painter, viewOption, index) item = index.model().data(index, Qt.UserRole) if isinstance(item, QVariant): return value = item['value'] type = item['type'] if type == 'checkbox': # 数据转换 value = True if value == 1 else 0 # 绘制单选框 checkBoxStyle = QStyleOptionButton() checkBoxStyle.state = QStyle.State_On if value else QStyle.State_Off checkBoxStyle.state |= QStyle.State_Enabled # 计算位置 size = item['size'] rect = calculate_middle_rect(option.rect, size, size) checkBoxStyle.rect = rect checkBox = QCheckBox() QApplication.style().drawPrimitive(QStyle.PE_IndicatorCheckBox, checkBoxStyle, painter, checkBox) if type == 'tag': painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHints(QPainter.SmoothPixmapTransform) path = QPainterPath() # 绘制文本 self.font = ResourceLoader().qt_font_text_tag text_color = item['text_color'] border_color = item['border_color'] text = value padding_v = 2 padding_h = 4 border_radius = 2 border_width = 1 painter.setFont(item['font']) painter.setPen(text_color) fm = QFontMetrics(painter.font()) w = fm.width(text) h = fm.height() # 计算位置 rect = calculate_middle_rect(option.rect, w + padding_h * 2, h + padding_v * 2) rectf = QRectF(rect.x(), rect.y(), rect.width(), rect.height()) painter.drawText( QRect(rectf.x() + padding_h, rectf.y() + padding_v, w, h), Qt.TextWordWrap, text) # 绘制边框 path.addRoundedRect(rectf, border_radius, border_radius) painter.strokePath(path, QPen(border_color, border_width))
def sizeHint(self, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> QtCore.QSize: if not index.isValid(): return QSize() item = index.model().data(index, Qt.UserRole) type = item['type'] if type == 'string': return QSize(0, 50) if type == 'device_activity': return QSize(0, 70) if type == 'load_more': return QSize(0, 40) if type == 'no_more': return QSize(0, 40)
def editorEvent(self, event: QtCore.QEvent, model: QtCore.QAbstractItemModel, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> bool: decorationRect = option.rect if event.type() == QEvent.MouseButtonPress and calculate_middle_rect( decorationRect, 20, 20).contains(event.pos()): item = index.model().data(index, Qt.UserRole) if isinstance(item, QVariant): return QStyledItemDelegate.editorEvent(self, event, model, option, index) value = item['value'] type = item['type'] if type == 'checkbox': # 数据转换 value = 1 if value == 0 else 0 model.setData(index, value, Qt.DisplayRole) return QStyledItemDelegate.editorEvent(self, event, model, option, index)
def setEditorData(self, editor: QWidget, index: QModelIndex): value = index.model().data(index, Qt.DisplayRole) editor.setText(value)
def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> None: if not index.isValid(): return if option.state & QStyle.State_Selected: pass if option.state & QStyle.State_MouseOver: pass item = index.model().data(index, Qt.UserRole) if isinstance(item, QVariant): return painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHints(QPainter.SmoothPixmapTransform) value = item['value'] type = item['type'] x = option.rect.x() y = option.rect.y() w = option.rect.width() h = option.rect.height() if type == 'device_activity': painter.save() # 图标 icon = QImage(ResourceLoader().icon_path(value['icon'])) rect_icon = QRectF(x + 20, y + 13, 44, 44) painter.drawImage(rect_icon, icon) # 设备标签 painter.setFont(ResourceLoader().qt_font_text_xs) rect = calculate_text_rect('设备', painter=painter, x=x + 70, y=y + 15) painter.drawText(rect, Qt.TextSingleLine, '设备') # 设备编号 painter.setPen(ResourceLoader().qt_color_label_link) painter.setFont(ResourceLoader().qt_font_text_xs) rect = calculate_text_rect(value['device'], painter=painter, x=x + 110, y=y + 15) painter.drawText(rect, Qt.TextSingleLine, value['device']) # 活动内容 painter.setPen(ResourceLoader().qt_color_sub_text) painter.setFont(ResourceLoader().qt_font_text_xss) content = value['content'] + ',' + toDateStr() rect = calculate_text_rect(content, painter=painter, x=x + 70, y=y + 40) painter.drawText(rect, Qt.TextSingleLine, content) # 绘制边框 path = QPainterPath() path.addRoundedRect(QRectF(x + 4, y + 4, w - 8, h - 8), 4, 4) painter.strokePath(path, QPen(ResourceLoader().qt_color_background, 1)) painter.restore() elif type == 'load_more': # 绘制加载图标 # painter.save() # painter.translate(x+16, y+16) # self.loading_rotate += 5 # painter.rotate(self.loading_rotate%360) # icon = qtawesome.icon('mdi.loading', color=ResourceLoader().qt_color_sub_text) # icon_pixmap = icon.pixmap(QSize(32, 32)) # painter.drawPixmap(QRect(-16, -16, 32, 32), icon_pixmap) # painter.restore() # 绘制加载信息 painter.save() painter.setFont(ResourceLoader().qt_font_text_xs) painter.setPen(ResourceLoader().qt_color_sub_text) _rect = calculate_text_rect('~~~ 正在努力加载 ~~~', painter=painter) rect = calculate_middle_rect(option.rect, width=_rect.width(), height=_rect.height()) painter.drawText(rect, Qt.TextSingleLine, '~~~ 正在努力加载 ~~~') painter.restore() elif type == 'no_more': painter.save() painter.setFont(ResourceLoader().qt_font_text_xs) painter.setPen(ResourceLoader().qt_color_sub_text) _rect = calculate_text_rect('--- 我是有底线的 ---', painter=painter) rect = calculate_middle_rect(option.rect, width=_rect.width(), height=_rect.height()) painter.drawText(rect, Qt.TextSingleLine, '--- 我是有底线的 ---') painter.restore() else: self.initStyleOption(option, index) QStyledItemDelegate.paint(self, painter, option, index)