def zoom_to_items(self, items): """Centres view on the centre of the items and, if view is set to 'fit to view', sets the zoom level to encompass items. Emits viewport_changed. """ united = unite_rects(i.sceneBoundingRect() for i in items) if 'whole_scene' == self.zoom_mode: debug_print('Ensuring [{0}] items visible'.format(len(items))) self.ensureVisible(united) self.viewport_changed.emit(self.normalised_scene_rect()) else: debug_print('Showing [{0}] items'.format(len(items))) # Add some padding around the selection padding = 20 if 'follow_selection' == self.zoom_mode: # Update zoom united.adjust(-padding, -padding, 2 * padding, 2 * padding) self.fitInView(united, Qt.KeepAspectRatio) if self.absolute_zoom > self.MAXIMUM_ZOOM: # new_absolute_zoom() emits viewport_changed self.new_absolute_zoom(self.MAXIMUM_ZOOM) else: self.viewport_changed.emit(self.normalised_scene_rect()) else: # zoom_mode == fixed self.ensureVisible(united, xMargin=padding, yMargin=padding)
def new_absolute_zoom(self, factor): """Sets a new absolute zoom """ f = factor scene_rect = self.scene().sceneRect() # Scene view_rect = self.viewport().rect() # Available space # The size of the scene if the new transform is applied t_scene_rect = QtGui.QTransform.fromScale(f, f).mapRect(scene_rect) if (t_scene_rect.width() < view_rect.width() and t_scene_rect.height() < view_rect.height()): # The user wants to zoom out so that the image is smaller than the # view self.zoom_home() else: f = min(self.MAXIMUM_ZOOM, f) msg = 'Change absolute zoom from [{0}] to [{1}]' debug_print(msg.format(self.absolute_zoom, f)) self.setTransform(QtGui.QTransform.fromScale(f, f)) self.fit_to_view = False selected = self.scene().selectedItems() if selected: # Centre on selected items #self.ensureVisible(unite_rects([i.rect() for i in selected])) self.centerOn( unite_rects([i.rect() for i in selected]).center())
def selectionChanged(self, selected, deselected): """QAbstractItemView virtual """ # Tell the scene about the new selection # TODO LH Use a timer to implement a delayed refresh if not self.handling_selection_update: # TODO Context for this debug_print('GraphicsItemView.selectionChanged') self.handling_selection_update = True try: current = set(self.scene.selectedItems()) new = set(self._rows[i.row()] for i in self.selectionModel().selectedIndexes()) for item in new.difference(current): item.setSelected(True) item.update() for item in current.difference(new): item.setSelected(False) item.update() if 1 == len(new): rect = new.pop().rect() for view in self.scene.views(): view.centerOn(rect.center()) elif 1 < len(new): # Ensure that the selected items are visible rect = unite_rects([i.rect() for i in new]) debug_print('GraphicsItemView will make visible', rect) new.pop().ensureVisible(rect) finally: self.handling_selection_update = False
def new_absolute_zoom(self, factor): """Sets a new absolute zoom and emits viewport_changed. """ f = factor scene_rect = self.scene().sceneRect() # Scene view_rect = self.viewport().rect() # Available space # The size of the scene if the new transform is applied t_scene_rect = QTransform.fromScale(f, f).mapRect(scene_rect) if (t_scene_rect.width() < view_rect.width() and t_scene_rect.height() < view_rect.height()): # The user wants to zoom out so that the image is smaller than the # view self.zoom_home() else: f = min(self.MAXIMUM_ZOOM, f) msg = 'Change absolute zoom from [{0}] to [{1}]' debug_print(msg.format(self.absolute_zoom, f)) selected = self.scene().selectedItems() if not selected: # No selection so we want to centre on the mouse cursor, if it # is within the view. We need to get the mouse position in # scene coords before applying the zoom. mouse_pos = self.mapFromGlobal(QCursor.pos()) if self.rect().contains(mouse_pos, proper=True): mouse_pos = self.mapToScene(mouse_pos) else: mouse_pos = None self.setTransform(QTransform.fromScale(f, f)) if selected: # Centre on selected items self.centerOn( unite_rects(i.sceneBoundingRect() for i in selected).center() ) elif mouse_pos: # Centre on mouse position self.centerOn(mouse_pos) else: # Default behaviour is fine pass self.viewport_changed.emit(self.normalised_scene_rect())
def new_absolute_zoom(self, factor): """Sets a new absolute zoom and emits viewport_changed. """ f = factor scene_rect = self.scene().sceneRect() # Scene view_rect = self.viewport().rect() # Available space # The size of the scene if the new transform is applied t_scene_rect = QTransform.fromScale(f, f).mapRect(scene_rect) if (t_scene_rect.width() < view_rect.width() and t_scene_rect.height() < view_rect.height()): # The user wants to zoom out so that the image is smaller than the # view self.zoom_home() else: f = min(self.MAXIMUM_ZOOM, f) msg = 'Change absolute zoom from [{0}] to [{1}]' debug_print(msg.format(self.absolute_zoom, f)) selected = self.scene().selectedItems() if not selected: # No selection so we want to centre on the mouse cursor, if it # is within the view. We need to get the mouse position in # scene coords before applying the zoom. mouse_pos = self.mapFromGlobal(QCursor.pos()) if self.rect().contains(mouse_pos, proper=True): mouse_pos = self.mapToScene(mouse_pos) else: mouse_pos = None self.setTransform(QTransform.fromScale(f, f)) if selected: # Centre on selected items self.centerOn( unite_rects(i.sceneBoundingRect() for i in selected).center()) elif mouse_pos: # Centre on mouse position self.centerOn(mouse_pos) else: # Default behaviour is fine pass self.viewport_changed.emit(self.normalised_scene_rect())
def zoom_to_items(self, items): """Centres view on the centre of the items and, if view is set to 'fit to view', sets the zoom level to encompass items. """ united = unite_rects(i.sceneBoundingRect() for i in items) if self.fit_to_view: debug_print('Ensuring [{0}] items visible'.format(len(items))) self.ensureVisible(united) else: # Some space # TODO LH Space should be in visible units debug_print('Zooming on [{0}] items'.format(len(items))) united.adjust(-20, -20, 40, 40) self.fitInView(united, Qt.KeepAspectRatio) # TODO LH Need a better solution if self.absolute_zoom > self.MAXIMUM_ZOOM: self.new_absolute_zoom(self.MAXIMUM_ZOOM)
def toggle_zoom(self): """Toggles between 'fit to screen' and a mild zoom / zoom to selected """ if self.fit_to_view: selected = self.scene().selectedItems() if selected: r = unite_rects([i.rect() for i in selected]) # Some space r.adjust(-20, -20, 40, 40) self.fitInView(r, Qt.KeepAspectRatio) self.fit_to_view = False # TODO LH Need a better solution if self.absolute_zoom > self.MAXIMUM_ZOOM: self.new_absolute_zoom(self.MAXIMUM_ZOOM) else: self.new_relative_zoom(4.0) else: self.zoom_home()