Source code for spinetoolbox.widgets.custom_qgraphicsscene

######################################################################################################################
# Copyright (C) 2017-2020 Spine project consortium
# This file is part of Spine Toolbox.
# Spine Toolbox is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
# Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
# any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Custom QGraphicsScene used in the Design View.

:author: P. Savolainen (VTT)
:date:   13.2.2019
"""

from PySide2.QtCore import Slot, QItemSelectionModel
from PySide2.QtGui import QColor, QPen, QBrush
from ..graphics_items import ProjectItemIcon
from .shrinking_scene import ShrinkingScene
from .toolbars import DraggableWidget


[docs]class CustomQGraphicsScene(ShrinkingScene): """A scene that handles drag and drop events of DraggableWidget sources.""" def __init__(self, parent, toolbox): """ Args: parent (QObject): scene's parent object toolbox (ToolboxUI): reference to the main window """ super().__init__(400.0, 300.0, parent) self._toolbox = toolbox self.item_shadow = None self.sync_selection = True # Set background attributes settings = toolbox.qsettings() grid = settings.value("appSettings/bgGrid", defaultValue="false") self.bg_grid = grid != "false" bg_color = settings.value("appSettings/bgColor", defaultValue="false") self.bg_color = QColor("#f5f5f5") if bg_color == "false" else bg_color self.connect_signals()
[docs] def connect_signals(self): """Connect scene signals.""" self.changed.connect(self.scene_changed) self.selectionChanged.connect(self.handle_selection_changed)
[docs] def resize_scene(self): """Resize scene to be at least the size of items bounding rectangle. Does not let the scene shrink.""" scene_rect = self.sceneRect() items_rect = self.itemsBoundingRect() union_rect = scene_rect | items_rect self.setSceneRect(union_rect)
@Slot("QList<QRectF>", name="scene_changed")
[docs] def scene_changed(self, rects): """Resize scene as it changes.""" scene_rect = self.sceneRect() if all(scene_rect.contains(rect) for rect in rects): return self.resize_scene()
@Slot(name="handle_selection_changed")
[docs] def handle_selection_changed(self): """Synchronize selection with the project tree.""" if not self.sync_selection: return selected_items = [item for item in self.selectedItems() if isinstance(item, ProjectItemIcon)] selected_inds = [self._toolbox.project_item_model.find_item(item.name()) for item in selected_items] self._toolbox.ui.treeView_project.clearSelection() for ind in selected_inds: self._toolbox.ui.treeView_project.selectionModel().select(ind, QItemSelectionModel.Select) # Make last item selected the current index in project tree view if bool(selected_inds): self._toolbox.ui.treeView_project.selectionModel().setCurrentIndex( selected_inds[-1], QItemSelectionModel.NoUpdate
)
[docs] def set_bg_color(self, color): """Change background color when this is changed in Settings. Args: color (QColor): Background color """ self.bg_color = color
[docs] def set_bg_grid(self, bg): """Enable or disable background grid. Args: bg (boolean): True to draw grid, False to fill background with a solid color """ self.bg_grid = bg
[docs] def dragLeaveEvent(self, event): """Accept event.""" event.accept()
[docs] def dragEnterEvent(self, event): """Accept event. Then call the super class method only if drag source is not a DraggableWidget (from Add Item toolbar).""" event.accept() source = event.source() if not isinstance(source, DraggableWidget): super().dragEnterEvent(event)
[docs] def dragMoveEvent(self, event): """Accept event. Then call the super class method only if drag source is not a DraggableWidget (from Add Item toolbar).""" event.accept() source = event.source() if not isinstance(source, DraggableWidget): super().dragMoveEvent(event)
[docs] def dropEvent(self, event): """Only accept drops when the source is an instance of DraggableWidget (from Add Item toolbar). Capture text from event's mimedata and show the appropriate 'Add Item form.' """ source = event.source() if not isinstance(source, DraggableWidget): super().dropEvent(event) return if not self._toolbox.project(): self._toolbox.msg.emit("Please open or create a project first") event.ignore() return event.acceptProposedAction() category = event.mimeData().text() pos = event.scenePos() w = 70 h = 70 x = pos.x() - w / 2 y = pos.y() - h / 2 icon_maker = self._toolbox.categories[category]["icon_maker"] self.item_shadow = icon_maker(self._toolbox, x, y, w, h, None) self._toolbox.show_add_project_item_form(category, pos.x(), pos.y())
[docs] def drawBackground(self, painter, rect): """Reimplemented method to make a custom background. Args: painter (QPainter): Painter that is used to paint background rect (QRectF): The exposed (viewport) rectangle in scene coordinates """ scene_rect = self.sceneRect() rect = rect.intersected(scene_rect) # Limit to only draw background for the scene rectangle if not self.bg_grid: painter.fillRect(rect, QBrush(self.bg_color)) return step = 20 # Grid step painter.setPen(QPen(QColor(0, 0, 0, 40))) # Draw horizontal grid start = round(rect.top(), step) if start > rect.top(): start -= step y = start while y < rect.bottom(): painter.drawLine(rect.left(), y, rect.right(), y) y += step # Now draw vertical grid start = round(rect.left(), step) if start > rect.left(): start -= step x = start while x < rect.right(): painter.drawLine(x, rect.top(), x, rect.bottom()) x += step