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 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 paint(self, painter, option: QStyleOptionViewItem, index: QModelIndex) -> None: text = index.data(RealLabelHint) colors = index.data(RealJobColorHint) painter.save() painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, True) border_pen = QPen() border_pen.setColor(QColorConstants.Black) border_pen.setWidth(1) if option.state & QStyle.State_Selected: # selection outline select_color = QColorConstants.Blue painter.setBrush(select_color) painter.setPen(border_pen) painter.drawRect(option.rect) # job status margin = 5 rect = QRect( option.rect.x() + margin, option.rect.y() + margin, option.rect.width() - (margin * 2), option.rect.height() - (margin * 2), ) painter.fillRect(rect, index.data(RealStatusColorHint)) self._paint_inner_grid(painter, option.rect, colors) text_pen = QPen() text_pen.setColor(select_color) painter.setPen(text_pen) painter.drawText(option.rect, Qt.AlignCenter, text) else: # # job status painter.setBrush(index.data(RealStatusColorHint)) painter.setPen(border_pen) painter.drawRect(option.rect) self._paint_inner_grid(painter, option.rect, colors) text_pen = QPen() text_pen.setColor(QColorConstants.Black) painter.setPen(text_pen) painter.drawText(option.rect, Qt.AlignCenter, text) painter.restore()
def paint(self, painter, option: QStyleOptionViewItem, index: QModelIndex) -> None: text = index.data(RealLabelHint) colors = tuple(index.data(RealJobColorHint)) real_status_color = index.data(RealStatusColorHint) painter.save() painter.setRenderHint(QPainter.Antialiasing, False) painter.setRenderHint(QPainter.TextAntialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, False) border_pen = QPen() border_pen.setColor(QColorConstants.Black) border_pen.setWidth(1) painter.setBrush(QColorConstants.Blue) painter.setPen(border_pen) painter.drawRect(option.rect) margin = 0 if option.state & QStyle.State_Selected: margin = 5 real_status_rect = QRect( option.rect.x() + margin, option.rect.y() + margin, option.rect.width() - (margin * 2), option.rect.height() - (margin * 2), ) painter.setBrush(QColorConstants.Gray) painter.setBrush(real_status_color) painter.drawRect(real_status_rect) job_rect_margin = 10 job_rect = QRect( option.rect.x() + job_rect_margin, option.rect.y() + job_rect_margin, option.rect.width() - (job_rect_margin * 2), option.rect.height() - (job_rect_margin * 2), ) self._paint_inner_grid(painter, job_rect, colors) text_pen = QPen() text_pen.setColor(QColorConstants.Black) painter.setPen(text_pen) painter.drawText(option.rect, Qt.AlignCenter, text) painter.restore()
def paint(self, painter: QPainter, style: QStyleOptionViewItem, model: QModelIndex): if model.data() not in image_dict: image_dict[model.data()] = create_colormap_image( model.data(), self.color_dict) rect = QRect(style.rect.x(), style.rect.y() + 2, style.rect.width(), style.rect.height() - 4) painter.drawImage(rect, image_dict[model.data()]) if int(style.state & QStyle.State_HasFocus): painter.save() pen = QPen() pen.setWidth(5) painter.setPen(pen) painter.drawRect(rect) painter.restore()
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: QStyleOptionViewItem, index: QModelIndex) -> None: data = index.data(ProgressRole) if data is None: return nr_reals = data["nr_reals"] status = data["status"] delta = option.rect.width() / nr_reals painter.save() painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, True) painter.fillRect(option.rect, self.background_color) i = 0 for state, color_ref in REAL_STATE_TO_COLOR.items(): if state not in status: continue state_progress = status[state] x = math.ceil(option.rect.x() + i * delta) y = option.rect.y() w = math.ceil(state_progress * delta) h = option.rect.height() color = QColor(*color_ref) painter.fillRect(x, y, w, h, color) i += state_progress painter.restore()
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 editorEvent( self, event: QtCore.QEvent, model: QtCore.QAbstractItemModel, option: QStyleOptionViewItem, index: QtCore.QModelIndex, ) -> bool: """Called when an event has occured in the editor. This can be used to customize how the delegate handles mouse/key events """ if (event.type() == event.MouseButtonRelease and event.button() == Qt.RightButton): self.show_context_menu(index, model, event.globalPos(), option.widget) # if the user clicks quickly on the visibility checkbox, we *don't* # want it to be interpreted as a double-click. We want the visibilty # to simply be toggled. if event.type() == event.MouseButtonDblClick: self.initStyleOption(option, index) style = option.widget.style() check_rect = style.subElementRect( style.SE_ItemViewItemCheckIndicator, option, option.widget) if check_rect.contains(event.pos()): cur_state = index.data(Qt.CheckStateRole) if model.flags(index) & Qt.ItemIsUserTristate: state = Qt.CheckState((cur_state + 1) % 3) else: state = Qt.Unchecked if cur_state else Qt.Checked return model.setData(index, state, Qt.CheckStateRole) # refer all other events to the QStyledItemDelegate return super().editorEvent(event, model, option, index)
def data(self, index: QModelIndex, role: Qt.ItemDataRole): """Return data at `index` for the requested `role`. see https://doc.qt.io/qt-5/model-view-programming.html#item-roles """ if role == Qt.EditRole: return index.data(Qt.UserRole).name if role == Qt.DecorationRole: # thumbnail key_frame = index.data(Qt.UserRole) return QImage( key_frame.thumbnail, key_frame.thumbnail.shape[1], key_frame.thumbnail.shape[0], QImage.Format_RGBA8888, ) if role == Qt.SizeHintRole: # determines size of item return QSize(160, 34) return super().data(index, role)
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): """ Paint a checkbox without the label. """ data = index.data() if data is None: logger.error(f"No data found at {index.row()}, {index.column()}") data = 0 self.drawCheck(painter, option, option.rect, Qt.Unchecked if int(data) == 0 else Qt.Checked) self.drawFocus(painter, option, option.rect)
def is_matching_canvas_type(self, index: QModelIndex, match_index: QModelIndex): match_intent = match_index.data(EnsembleModel.object_role) intent = index.data(EnsembleModel.object_role) if not isinstance(intent, Intent): print( f"WARNING: during matching, index {index.data} is not an Intent" ) return False if not isinstance(match_intent, Intent): print( f"WARNING: during matching, match_index {index.data} is not an Intent" ) return False # assert isinstance(intent, Intent) # assert isinstance(match_intent, Intent) # Ignore self matching if intent is match_intent: return False match_canvas_type_string = match_intent.canvas intent_canvas_type_string = intent.canvas match_intent_canvas_type = pluginmanager.get_plugin_by_name( match_canvas_type_string, "IntentCanvasPlugin") intent_canvas_type = pluginmanager.get_plugin_by_name( intent_canvas_type_string, "IntentCanvasPlugin") if not issubclass(intent_canvas_type, match_intent_canvas_type) \ and not issubclass(match_intent_canvas_type, intent_canvas_type): return False # By definition, if a match_key is not provided, the intent is un-matchable if intent.match_key is None or match_intent.match_key is None: return False if intent.match_key != match_intent.match_key: return False return True
def dataChanged(self, topLeft: QModelIndex, bottomRight: QModelIndex, roles=None): """ Re-implements the QAbstractItemView.dataChanged() slot. When the data attached to the Qt.CheckStateRole has been changed, this will either render a Hint or remove the Hint visualization. Parameters ---------- topLeft For now, the only index we are concerned with, which corresponds to the item's check state changing. bottomRight (Unused right now) roles List of roles attached to the data state change. """ if roles is None: roles = [] if self.model(): # empty list indicates ALL roles have changed (see documentation) if Qt.CheckStateRole in roles or len(roles) == 0: hint = topLeft.data(Qt.UserRole) if hint: if topLeft.data(Qt.CheckStateRole) == Qt.Checked: if hint.group not in [ self._tabWidget.tabText(index) for index in range(self._tabWidget.count()) ]: canvas = hint.init_canvas(addLegend=True) self._tabWidget.addTab(canvas, hint.group) else: canvas = self._findTab(hint.group) hint.visualize(canvas) else: hint.remove() super(HintTabView, self).dataChanged(topLeft, bottomRight, roles)
def createEditor( self, parent: QWidget, option: QStyleOptionViewItem, index: QtCore.QModelIndex, ) -> QWidget: """User has double clicked on layer name.""" # necessary for geometry, otherwise editor takes up full width. self.get_layer_icon(option, index) editor = super().createEditor(parent, option, index) # make sure editor has same alignment as the display name editor.setAlignment(Qt.Alignment(index.data(Qt.TextAlignmentRole))) return editor
def _activate(self, index: QModelIndex): display = index.data( HappiClientModel.displayRole) # try to get display from model if not display: happi_item = index.data(HappiClientModel.happiItemRole) device = from_container(happi_item) try: device.wait_for_connection() except TimeoutError as ex: msg.logError(ex) controller_name = happi_item.extraneous.get( "controller_class", "typhos") controller = pluginmanager.get_plugin_by_name( controller_name, 'ControllerPlugin') display = controller(device) # Stash display back on the model self.model().setData(index, display, HappiClientModel.displayRole) self.sigShowControl.emit(display)
def setData(self, index: QModelIndex, value: Any, role: Qt.ItemDataRole = Qt.EditRole) -> bool: if not index.isValid(): return False if role == self.active_role: self._set_active_data(index, value) elif role == Qt.DisplayRole: # Intercept display text changes for ensembles (i.e. renaming) so we can update the title # also ONLY update the title if it is the active item if index.data(self.data_type_role ) == WorkspaceDataType.Ensemble and index.data( self.active_role): self._update_title(value) # Add other role handling here else: ... return super(EnsembleModel, self).setData(index, value, role)
def paint(self, painter, option: QStyleOptionViewItem, index: QModelIndex) -> None: data = index.data(ProgressRole) nr_reals = 0 status = {} if data: nr_reals = data["nr_reals"] status = data["status"] painter.save() painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, True) background_color = QApplication.palette().color(QPalette.Window) painter.fillRect(option.rect.x(), option.rect.y(), option.rect.width(), 30, background_color) total_states = len(REAL_STATE_TO_COLOR.items()) d = math.ceil(option.rect.width() / total_states) x_pos = 0 for state, color_ref in REAL_STATE_TO_COLOR.items(): state_progress = 0 if state in status: state_progress = status[state] x = x_pos y = option.rect.y() w = d h = option.rect.height() margin = 5 painter.setBrush(QColor(*color_ref)) painter.drawRect(x, y + margin, 20, 20) painter.drawText( x + 25, y + margin, w - 25, h, Qt.AlignLeft, f"{state} ({state_progress}/{nr_reals})", ) x_pos += d painter.restore()
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex) -> None: super().paint(painter, option, index) cellState: CellState = index.data(Qt.BackgroundRole) if cellState == CellState.Invalid: padding = 0 x = option.rect.x() + padding y = option.rect.y() + padding w = option.rect.width() - 1 - padding h = option.rect.height() - 1 - padding pen = QPen() pen.setColor(QColor(*(Color.Red).value)) pen.setWidth(1) painter.setPen(pen) painter.drawRect(QRect(x, y, w, h))
def currentChanged(self: QAbstractItemView, current: QModelIndex, previous: QModelIndex): """The Qt current item has changed. Update the python model.""" self._root.selection._current = current.data(Qt.UserRole) return super().currentChanged(current, previous)