class RectangleSelectionAction(UserInteraction): """ Select items in the scene using a Rectangle selection """ def __init__(self, document, *args, **kwargs): UserInteraction.__init__(self, document, *args, **kwargs) # The initial selection at drag start self.initial_selection = None # Selection when last updated in a mouseMoveEvent self.last_selection = None # A selection rect (`QRectF`) self.selection_rect = None # Keyboard modifiers self.modifiers = 0 def mousePressEvent(self, event): pos = event.scenePos() any_item = self.scene.item_at(pos) if not any_item and event.button() & Qt.LeftButton: self.modifiers = event.modifiers() self.selection_rect = QRectF(pos, QSizeF(0, 0)) self.rect_item = QGraphicsRectItem( self.selection_rect.normalized() ) self.rect_item.setPen( QPen(QBrush(QColor(51, 153, 255, 192)), 0.4, Qt.SolidLine, Qt.RoundCap) ) self.rect_item.setBrush( QBrush(QColor(168, 202, 236, 192)) ) self.rect_item.setZValue(-100) # Clear the focus if necessary. if not self.scene.stickyFocus(): self.scene.clearFocus() if not self.modifiers & Qt.ControlModifier: self.scene.clearSelection() event.accept() return True else: self.cancel(self.ErrorReason) return False def mouseMoveEvent(self, event): if not self.rect_item.scene(): # Add the rect item to the scene when the mouse moves. self.scene.addItem(self.rect_item) self.update_selection(event) return True def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: if self.initial_selection is None: # A single click. self.scene.clearSelection() else: self.update_selection(event) self.end() return True def update_selection(self, event): """ Update the selection rectangle from a QGraphicsSceneMouseEvent `event` instance. """ if self.initial_selection is None: self.initial_selection = set(self.scene.selectedItems()) self.last_selection = self.initial_selection pos = event.scenePos() self.selection_rect = QRectF(self.selection_rect.topLeft(), pos) # Make sure the rect_item does not cause the scene rect to grow. rect = self._bound_selection_rect(self.selection_rect.normalized()) # Need that 0.5 constant otherwise the sceneRect will still # grow (anti-aliasing correction by QGraphicsScene?) pw = self.rect_item.pen().width() + 0.5 self.rect_item.setRect(rect.adjusted(pw, pw, -pw, -pw)) selected = self.scene.items(self.selection_rect.normalized(), Qt.IntersectsItemShape, Qt.AscendingOrder) selected = set([item for item in selected if \ item.flags() & Qt.ItemIsSelectable]) if self.modifiers & Qt.ControlModifier: for item in selected | self.last_selection | \ self.initial_selection: item.setSelected( (item in selected) ^ (item in self.initial_selection) ) else: for item in selected.union(self.last_selection): item.setSelected(item in selected) self.last_selection = set(self.scene.selectedItems()) def end(self): self.initial_selection = None self.last_selection = None self.modifiers = 0 self.rect_item.hide() if self.rect_item.scene() is not None: self.scene.removeItem(self.rect_item) UserInteraction.end(self) def viewport_rect(self): """ Return the bounding rect of the document's viewport on the scene. """ view = self.document.view() vsize = view.viewport().size() viewportrect = QRect(0, 0, vsize.width(), vsize.height()) return view.mapToScene(viewportrect).boundingRect() def _bound_selection_rect(self, rect): """ Bound the selection `rect` to a sensible size. """ srect = self.scene.sceneRect() vrect = self.viewport_rect() maxrect = srect.united(vrect) return rect.intersected(maxrect)
class RectangleSelectionAction(UserInteraction): """ Select items in the scene using a Rectangle selection """ def __init__(self, document, *args, **kwargs): UserInteraction.__init__(self, document, *args, **kwargs) # The initial selection at drag start self.initial_selection = None # Selection when last updated in a mouseMoveEvent self.last_selection = None # A selection rect (`QRectF`) self.selection_rect = None # Keyboard modifiers self.modifiers = 0 def mousePressEvent(self, event): pos = event.scenePos() any_item = self.scene.item_at(pos) if not any_item and event.button() & Qt.LeftButton: self.modifiers = event.modifiers() self.selection_rect = QRectF(pos, QSizeF(0, 0)) self.rect_item = QGraphicsRectItem( self.selection_rect.normalized()) self.rect_item.setPen( QPen(QBrush(QColor(51, 153, 255, 192)), 0.4, Qt.SolidLine, Qt.RoundCap)) self.rect_item.setBrush(QBrush(QColor(168, 202, 236, 192))) self.rect_item.setZValue(-100) # Clear the focus if necessary. if not self.scene.stickyFocus(): self.scene.clearFocus() if not self.modifiers & Qt.ControlModifier: self.scene.clearSelection() event.accept() return True else: self.cancel(self.ErrorReason) return False def mouseMoveEvent(self, event): if not self.rect_item.scene(): # Add the rect item to the scene when the mouse moves. self.scene.addItem(self.rect_item) self.update_selection(event) return True def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: if self.initial_selection is None: # A single click. self.scene.clearSelection() else: self.update_selection(event) self.end() return True def update_selection(self, event): """ Update the selection rectangle from a QGraphicsSceneMouseEvent `event` instance. """ if self.initial_selection is None: self.initial_selection = set(self.scene.selectedItems()) self.last_selection = self.initial_selection pos = event.scenePos() self.selection_rect = QRectF(self.selection_rect.topLeft(), pos) # Make sure the rect_item does not cause the scene rect to grow. rect = self._bound_selection_rect(self.selection_rect.normalized()) # Need that 0.5 constant otherwise the sceneRect will still # grow (anti-aliasing correction by QGraphicsScene?) pw = self.rect_item.pen().width() + 0.5 self.rect_item.setRect(rect.adjusted(pw, pw, -pw, -pw)) selected = self.scene.items(self.selection_rect.normalized(), Qt.IntersectsItemShape, Qt.AscendingOrder) selected = set([item for item in selected if \ item.flags() & Qt.ItemIsSelectable]) if self.modifiers & Qt.ControlModifier: for item in selected | self.last_selection | \ self.initial_selection: item.setSelected((item in selected) ^ (item in self.initial_selection)) else: for item in selected.union(self.last_selection): item.setSelected(item in selected) self.last_selection = set(self.scene.selectedItems()) def end(self): self.initial_selection = None self.last_selection = None self.modifiers = 0 self.rect_item.hide() if self.rect_item.scene() is not None: self.scene.removeItem(self.rect_item) UserInteraction.end(self) def viewport_rect(self): """ Return the bounding rect of the document's viewport on the scene. """ view = self.document.view() vsize = view.viewport().size() viewportrect = QRect(0, 0, vsize.width(), vsize.height()) return view.mapToScene(viewportrect).boundingRect() def _bound_selection_rect(self, rect): """ Bound the selection `rect` to a sensible size. """ srect = self.scene.sceneRect() vrect = self.viewport_rect() maxrect = srect.united(vrect) return rect.intersected(maxrect)