Пример #1
0
    def add_instance(
            self, instance: "GameInstance"
    ) -> Tuple[QGraphicsItem, Callable[[], None]]:
        """Add instance to manage, return a disconnect function and the canvas"""
        positionChanged = lambda rect: self.on_instance_moved(instance, rect)
        instance.positionChanged.connect(positionChanged)

        focusChanged = lambda focus: self.on_instance_focus_change(
            instance, focus)
        instance.focusChanged.connect(focusChanged)

        instance_pos = instance.get_position()
        gfx = QGraphicsRectItem(rect=instance_pos)
        gfx.setPen(self.transparent_pen)
        gfx.setPos(instance_pos.x(), instance_pos.y())
        self.scene.addItem(gfx)
        self._instances[instance.wid] = gfx

        def disconnect():
            gfx.hide()
            self.scene.removeItem(gfx)
            instance.positionChanged.disconnect(positionChanged)
            instance.focusChanged.disconnect(focusChanged)

        return gfx, disconnect
Пример #2
0
    def _generate_indicators(self, **kwargs):  # pylint: disable=unused-argument
        """
        Paint arrow indicators of selected instructions and labels.
        """
        scene = self.scene()
        for item in self._map_indicator_items:
            scene.removeItem(item)
        self._map_indicator_items.clear()

        for addr in list(self.disasm_view.infodock.selected_insns) + list(
                self.disasm_view.infodock.selected_labels):
            pos = self._get_pos_from_addr(addr)
            if pos is None:
                continue

            pos -= 1  # this is the top-left x coordinate of our arrow body (the rectangle)

            pen = QPen(Qt.yellow)
            brush = QBrush(Qt.yellow)
            item = QGraphicsRectItem(QRectF(pos, 0, 2, 10), parent=self)
            item.setPen(pen)
            item.setBrush(brush)
            item.setZValue(self.ZVALUE_INDICATOR)
            self._map_indicator_items.append(item)

            triangle = QPolygonF()
            triangle.append(QPointF(pos - 1, 10))
            triangle.append(QPointF(pos + 3, 10))
            triangle.append(QPointF(pos + 1, 12))
            triangle.append(QPointF(pos - 1, 10))
            item = QGraphicsPolygonItem(triangle, parent=self)
            item.setPen(pen)
            item.setBrush(brush)
            item.setZValue(self.ZVALUE_INDICATOR)
            self._map_indicator_items.append(item)
Пример #3
0
    def overlay_rect(self, color: int, x: int, y: int, w: int, h: int,
                     timeout: int, line_width: int):
        pen = QPen(decode_color(color))
        pen.setWidthF(max(1.0, line_width / 10))

        gfx = QGraphicsRectItem(x, y, w, h)
        gfx.setPen(pen)

        self._finalize_gfx(gfx, timeout)
Пример #4
0
def createItem(x, scene):
    rectItem = QGraphicsRectItem(QRectF(x + 40, 40, 120, 120))
    scene.addItem(rectItem)
    rectItem.setPen(QPen(Qt.black))
    rectItem.setBrush(Qt.gray)

    innerRectItem = QGraphicsRectItem(QRectF(x + 50, 50, 45, 100), rectItem)
    innerRectItem.setPen(QPen(Qt.black))
    innerRectItem.setBrush(Qt.white)
    # scene.addItem(innerRectItem)

    ellipseItem = QGraphicsEllipseItem(QRectF(x + 105, 50, 45, 100), rectItem)
    ellipseItem.setPen(QPen(Qt.black))
    ellipseItem.setBrush(Qt.white)
    # scene.addItem(ellipseItem)
    return rectItem
Пример #5
0
class ObjectLabelItem(QGraphicsTextItem):
    """Provides a label for ObjectItem's."""

    entity_name_edited = Signal(str)

    def __init__(self, entity_item):
        """Initializes item.

        Args:
            entity_item (spinetoolbox.widgets.graph_view_graphics_items.EntityItem): The parent item.
        """
        super().__init__(entity_item)
        self.entity_item = entity_item
        self._font = QApplication.font()
        self._font.setPointSize(11)
        self.setFont(self._font)
        self.bg = QGraphicsRectItem(self)
        self.bg_color = QGuiApplication.palette().color(
            QPalette.Normal, QPalette.ToolTipBase)
        self.bg_color.setAlphaF(0.8)
        self.bg.setBrush(QBrush(self.bg_color))
        self.bg.setPen(Qt.NoPen)
        self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
        self.setAcceptHoverEvents(False)
        self._cursor = self.textCursor()
        self._text_backup = None

    def setPlainText(self, text):
        """Set texts and resets position.

        Args:
            text (str)
        """
        super().setPlainText(text)
        self.reset_position()

    def reset_position(self):
        """Adapts item geometry so text is always centered."""
        rectf = self.boundingRect()
        x = -rectf.width() / 2
        y = rectf.height() + 4
        self.setPos(x, y)
        self.bg.setRect(self.boundingRect())
Пример #6
0
    def _generate_hover_region(self):
        """
        Paint the memory region indicator.
        """
        if self._map_hover_region_item:
            self.scene().removeItem(self._map_hover_region_item)
            self._map_hover_region_item = None

        mr = self._map_hover_region
        if mr is None:
            return

        pw = 1.0
        hpw = pw / 2
        pen = QPen(Qt.red)
        pen.setWidth(pw)
        r = self._get_region_rect(mr)
        r = r.marginsRemoved(QMarginsF(hpw, hpw, hpw, hpw))
        item = QGraphicsRectItem(r, parent=self)
        item.setPen(pen)
        item.setZValue(self.ZVALUE_HOVER)
        self._map_hover_region_item = item
Пример #7
0
	def __init__(self, parent: QWidget = None) -> None:
		"""
		Create a GraphicsView for Facile.
		:param parent: The widget to embed the graphics view into
		:type parent: QWidget
		:return: None
		:rtype: NoneType
		"""
		super(FacileGraphicsView, self).__init__(parent)

		# set flags
		self.setDragMode(QGraphicsView.ScrollHandDrag)
		self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
		
		# show initial message
		scene = QGraphicsScene()
		box = QGraphicsRectItem(0, 0, 100, 100)
		box.setPen(QColor(Qt.transparent))
		box.setBrush(QColor(Qt.transparent))
		QGraphicsTextItem("Nothing to show here yet!", box)
		scene.addItem(box)
		
		self.setScene(scene)
Пример #8
0
    QWidget,
    QGraphicsSimpleTextItem,
    QGraphicsEllipseItem,
    QGraphicsPolygonItem,
)
from PySide2.QtGui import (QPen, QBrush, QPolygonF)
from PySide2.QtCore import (Qt, QRectF, QPoint, QPointF)

import sys

if __name__ == '__main__':
    app = QApplication(sys.argv)
    scene = QGraphicsScene(QRectF(-50, -50, 400, 200))

    rect = QGraphicsRectItem(scene.sceneRect().adjusted(1, 1, -1, -1))
    rect.setPen(QPen(Qt.red, 1))
    scene.addItem(rect)

    rectItem = QGraphicsRectItem(QRectF(-25, 25, 200, 40))
    rectItem.setPen(QPen(Qt.red, 3, Qt.DashDotLine))
    rectItem.setBrush(Qt.gray)
    scene.addItem(rectItem)
    print(f'Rect Pos: {rectItem.pos()}')

    textItem = QGraphicsSimpleTextItem("Foundation of Qt")
    scene.addItem(textItem)
    print(f'Text Pos: {textItem.pos()}')
    textItem.setPos(50, 0)
    print(f'Text Pos: {textItem.pos()}')

    ellipseItem = QGraphicsEllipseItem(QRectF(170, 20, 100, 75))
Пример #9
0
class EntityItem(QGraphicsPixmapItem):
    def __init__(self,
                 graph_view_form,
                 x,
                 y,
                 extent,
                 entity_id=None,
                 entity_class_id=None):
        """Initializes item

        Args:
            graph_view_form (GraphViewForm): 'owner'
            x (float): x-coordinate of central point
            y (float): y-coordinate of central point
            extent (int): Preferred extent
            entity_id (int, optional): The entity id in case of a non-wip item
            entity_class_id (int, optional): The entity class id in case of a wip item
        """
        if not entity_id and not entity_class_id:
            raise ValueError(
                "Can't create an RelationshipItem without relationship id nor relationship class id."
            )
        super().__init__()
        self._graph_view_form = graph_view_form
        self.db_mngr = graph_view_form.db_mngr
        self.db_map = graph_view_form.db_map
        self.entity_id = entity_id
        self._entity_class_id = entity_class_id
        self._entity_name = f"<WIP {self.entity_class_name}>"
        self.arc_items = list()
        self._extent = extent
        self.refresh_icon()
        self.setPos(x, y)
        rect = self.boundingRect()
        self.setOffset(-rect.width() / 2, -rect.height() / 2)
        self._press_pos = None
        self._merge_target = None
        self._moved_on_scene = False
        self._view_transform = QTransform(
        )  # To determine collisions in the view
        self._views_cursor = {}
        self._bg = None
        self._bg_brush = Qt.NoBrush
        self._init_bg()
        self._bg.setFlag(QGraphicsItem.ItemStacksBehindParent, enabled=True)
        self.is_wip = None
        self._question_item = None  # In case this becomes a template
        if not self.entity_id:
            self.become_wip()
        else:
            self.become_whole()
        self.setZValue(0)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIsMovable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIgnoresTransformations, enabled=True)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, enabled=True)
        self.setAcceptHoverEvents(True)
        self.setCursor(Qt.ArrowCursor)

    @property
    def entity_type(self):
        raise NotImplementedError()

    @property
    def entity_name(self):
        return self.db_mngr.get_item(self.db_map, self.entity_type,
                                     self.entity_id).get(
                                         "name", self._entity_name)

    @property
    def entity_class_type(self):
        return {
            "relationship": "relationship class",
            "object": "object class"
        }[self.entity_type]

    @property
    def entity_class_id(self):
        return self.db_mngr.get_item(self.db_map, self.entity_type,
                                     self.entity_id).get(
                                         "class_id", self._entity_class_id)

    @property
    def entity_class_name(self):
        return self.db_mngr.get_item(self.db_map, self.entity_class_type,
                                     self.entity_class_id)["name"]

    def boundingRect(self):
        return super().boundingRect() | self.childrenBoundingRect()

    def _init_bg(self):
        self._bg = QGraphicsRectItem(self.boundingRect(), self)
        self._bg.setPen(Qt.NoPen)

    def refresh_icon(self):
        """Refreshes the icon."""
        pixmap = self.db_mngr.entity_class_icon(
            self.db_map, self.entity_class_type,
            self.entity_class_id).pixmap(self._extent)
        self.setPixmap(pixmap)

    def shape(self):
        """Returns a shape containing the entire bounding rect, to work better with icon transparency."""
        path = QPainterPath()
        path.addRect(self.boundingRect())
        return path

    def paint(self, painter, option, widget=None):
        """Shows or hides the selection halo."""
        if option.state & (QStyle.State_Selected):
            self._paint_as_selected()
            option.state &= ~QStyle.State_Selected
        else:
            self._paint_as_deselected()
        super().paint(painter, option, widget)

    def _paint_as_selected(self):
        self._bg.setBrush(QGuiApplication.palette().highlight())

    def _paint_as_deselected(self):
        self._bg.setBrush(self._bg_brush)

    def add_arc_item(self, arc_item):
        """Adds an item to the list of arcs.

        Args:
            arc_item (ArcItem)
        """
        self.arc_items.append(arc_item)

    def become_wip(self):
        """Turns this item into a work-in-progress."""
        self.is_wip = True
        font = QFont("", 0.6 * self._extent)
        self._question_item = OutlinedTextItem("?", self, font)
        # Position question item
        rect = super().boundingRect()
        question_rect = self._question_item.boundingRect()
        x = rect.center().x() - question_rect.width() / 2
        y = rect.center().y() - question_rect.height() / 2
        self._question_item.setPos(x, y)
        self.setToolTip(self._make_wip_tool_tip())

    def _make_wip_tool_tip(self):
        raise NotImplementedError()

    def become_whole(self):
        """Removes the wip status from this item."""
        self.is_wip = False
        if self._question_item:
            self.scene().removeItem(self._question_item)

    def adjust_to_zoom(self, transform):
        """Saves the view's transform to determine collisions later on.

        Args:
            transform (QTransform): The view's transformation matrix after the zoom.
        """
        self._view_transform = transform
        factor = transform.m11()
        self.setFlag(QGraphicsItem.ItemIgnoresTransformations,
                     enabled=factor > 1)

    def device_rect(self):
        """Returns the item's rect in devices's coordinates.
        Used to accurately determine collisions.
        """
        return self.deviceTransform(self._view_transform).mapRect(
            super().boundingRect())

    def _find_merge_target(self):
        """Returns a suitable merge target if any.

        Returns:
            spinetoolbox.widgets.graph_view_graphics_items.EntityItem, NoneType
        """
        scene = self.scene()
        if not scene:
            return None
        colliding = [
            x for x in scene.items()
            if isinstance(x, EntityItem) and x is not self
            and x.device_rect().intersects(self.device_rect())
        ]
        return next(iter(colliding), None)

    # pylint: disable=no-self-use
    def _is_target_valid(self):
        """Whether or not the registered merge target is valid.

        Returns:
            bool
        """
        return False

    # pylint: disable=no-self-use
    def merge_into_target(self, force=False):
        """Merges this item into the registered target if valid.

        Returns:
            bool: True if merged, False if not.
        """
        return False

    def mousePressEvent(self, event):
        """Saves original position for bouncing purposes.

        Args:
            event (QGraphicsSceneMouseEvent)
        """
        super().mousePressEvent(event)
        self._press_pos = self.pos()
        self._merge_target = None

    def mouseMoveEvent(self, event):
        """Moves the item and all connected arcs. Also checks for a merge target
        and sets an appropriate mouse cursor.

        Args:
            event (QGraphicsSceneMouseEvent)
        """
        if event.buttons() & Qt.LeftButton == 0:
            super().mouseMoveEvent(event)
            return
        move_by = event.scenePos() - event.lastScenePos()
        # Move selected items together
        for item in self.scene().selectedItems():
            if isinstance(item, (EntityItem)):
                item.moveBy(move_by.x(), move_by.y())
                item.move_arc_items(move_by)
        self._merge_target = self._find_merge_target()
        for view in self.scene().views():
            self._views_cursor.setdefault(view, view.viewport().cursor())
            if not self._merge_target:
                try:
                    view.viewport().setCursor(self._views_cursor[view])
                except KeyError:
                    pass
                continue
            if self._is_target_valid():
                view.viewport().setCursor(Qt.DragCopyCursor)
            else:
                view.viewport().setCursor(Qt.ForbiddenCursor)

    def move_arc_items(self, pos_diff):
        """Moves arc items.

        Args:
            pos_diff (QPoint)
        """
        raise NotImplementedError()

    def mouseReleaseEvent(self, event):
        """Merges the item into the registered target if any. Bounces it if not possible.
        Shrinks the scene if needed.

        Args:
            event (QGraphicsSceneMouseEvent)
        """
        super().mouseReleaseEvent(event)
        if self._merge_target:
            if self.merge_into_target():
                return
            self._bounce_back(self.pos())
        if self._moved_on_scene:
            self._moved_on_scene = False
            scene = self.scene()
            scene.shrink_if_needed()
            scene.item_move_finished.emit(self)

    def _bounce_back(self, current_pos):
        """Bounces the item back from given position to its original position.

        Args:
            current_pos (QPoint)
        """
        if self._press_pos is None:
            return
        self.move_arc_items(self._press_pos - current_pos)
        self.setPos(self._press_pos)

    def itemChange(self, change, value):
        """
        Keeps track of item's movements on the scene.

        Args:
            change (GraphicsItemChange): a flag signalling the type of the change
            value: a value related to the change

        Returns:
            the same value given as input
        """
        if change == QGraphicsItem.ItemScenePositionHasChanged:
            self._moved_on_scene = True
        return value

    def set_all_visible(self, on):
        """Sets visibility status for this item and all arc items.

        Args:
            on (bool)
        """
        for item in self.arc_items:
            item.setVisible(on)
        self.setVisible(on)

    def wipe_out(self):
        """Removes this item and all its arc items from the scene."""
        self.scene().removeItem(self)
        for arc_item in self.arc_items:
            if arc_item.scene():
                arc_item.scene().removeItem(arc_item)
                other_item = arc_item.other_item(self)
                if other_item.is_wip:
                    other_item.wipe_out()

    def contextMenuEvent(self, e):
        """Shows context menu.

        Args:
            e (QGraphicsSceneMouseEvent): Mouse event
        """
        e.accept()
        if not self.isSelected() and not e.modifiers() & Qt.ControlModifier:
            self.scene().clearSelection()
        self.setSelected(True)
        self._show_item_context_menu_in_parent(e.screenPos())

    def _show_item_context_menu_in_parent(self, pos):
        raise NotImplementedError()
Пример #10
0
class MaskScene(QGraphicsScene):
    _stage_text = 'STAGE %s'

    def __init__(self, main_window, stage=1):
        super().__init__()
        self.main_window = main_window
        self.stage = stage
        self.upper_mask = QGraphicsRectItem(0, 0, content_width, 0)
        self.lower_mask = QGraphicsRectItem(0, content_height, content_width, 0)
        self.stage_text_item = QGraphicsTextItem()
        self.mask_height = 0
        self.animation_timer_1 = QTimer()
        self.animation_timer_2 = QTimer()
        self.animation_timer_3 = QTimer()
        self.selected = None
        self.init()

    def init(self):
        mask_brush = QBrush()
        mask_brush.setColor(Qt.gray)
        mask_brush.setStyle(Qt.SolidPattern)
        mask_pen = QPen()
        mask_pen.setColor(Qt.gray)
        self.upper_mask.setBrush(mask_brush)
        self.lower_mask.setBrush(mask_brush)
        self.upper_mask.setPen(mask_pen)
        self.lower_mask.setPen(mask_pen)
        self.addItem(self.upper_mask)
        self.addItem(self.lower_mask)

        font = QFont()
        font.setPointSize(20)
        font.setBold(True)
        self.stage_text_item.setPlainText(self._stage_text % self.stage)
        self.stage_text_item.setFont(font)
        self.stage_text_item.setDefaultTextColor(Qt.black)
        self.stage_text_item.setX(content_width / 2 - int(self.stage_text_item.boundingRect().width() / 2))
        self.stage_text_item.setY(content_height / 2 - int(self.stage_text_item.boundingRect().height() / 2))

        self.animation_timer_1.setInterval(interval)
        self.animation_timer_1.timeout.connect(self.animation_in)

        self.animation_timer_2.setSingleShot(True)
        self.animation_timer_2.timeout.connect(self.animation_hold)
        self.animation_timer_2.setInterval(800)

        self.animation_timer_3.setInterval(interval)
        self.animation_timer_3.timeout.connect(self.animation_out)

    def next_stage(self):
        self.stage += 1
        self.stage_text_item.setPlainText(self._stage_text % self.stage)

    def reset_stage(self):
        self.stage = 0
        self.stage_text_item.setPlainText(self._stage_text % self.stage)

    def animation_in(self):
        self.mask_height += 10
        finished = False
        if self.mask_height > content_height / 2:
            self.mask_height = content_height / 2
            finished = True
        self.upper_mask.setRect(0, 0, content_width, self.mask_height)
        self.lower_mask.setRect(0, content_height - self.mask_height, content_width, self.mask_height)
        if finished:
            self.addItem(self.stage_text_item)
            self.animation_timer_1.stop()
            self.animation_timer_2.start()

    def animation_out(self):
        self.mask_height -= 10
        finished = False
        if self.mask_height < 0:
            self.mask_height = 0
            finished = True
        self.upper_mask.setRect(0, 0, content_width, self.mask_height)
        self.lower_mask.setRect(0, content_height - self.mask_height, content_width, self.mask_height)
        if finished:
            self.animation_timer_3.stop()
            self.main_window.start_game(self.selected)

    def animation_hold(self):
        self.removeItem(self.stage_text_item)
        self.animation_timer_3.start()
        self.main_window.enter_game_scene()

    def start_animation(self, selected: int):
        self.animation_timer_1.start()
        self.selected = selected
Пример #11
0
class EntityItem(QGraphicsRectItem):
    """Base class for ObjectItem and RelationshipItem."""
    def __init__(self, spine_db_editor, x, y, extent, db_map_entity_id=None):
        """Initializes item

        Args:
            spine_db_editor (SpineDBEditor): 'owner'
            x (float): x-coordinate of central point
            y (float): y-coordinate of central point
            extent (int): Preferred extent
            db_map_entity_id (tuple): db_map, entity id
        """
        super().__init__()
        self._spine_db_editor = spine_db_editor
        self.db_mngr = spine_db_editor.db_mngr
        self.db_map_entity_id = db_map_entity_id
        self.arc_items = list()
        self._extent = extent
        self.setRect(-0.5 * self._extent, -0.5 * self._extent, self._extent,
                     self._extent)
        self.setPen(Qt.NoPen)
        self._svg_item = QGraphicsSvgItem(self)
        self._svg_item.setCacheMode(
            QGraphicsItem.CacheMode.NoCache
        )  # Needed for the exported pdf to be vector
        self.refresh_icon()
        self.setPos(x, y)
        self._moved_on_scene = False
        self._bg = None
        self._bg_brush = Qt.NoBrush
        self._init_bg()
        self._bg.setFlag(QGraphicsItem.ItemStacksBehindParent, enabled=True)
        self.setZValue(0)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIsMovable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIgnoresTransformations, enabled=True)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, enabled=True)
        self.setAcceptHoverEvents(True)
        self.setCursor(Qt.ArrowCursor)
        self.setToolTip(self._make_tool_tip())

    def _make_tool_tip(self):
        raise NotImplementedError()

    @property
    def entity_type(self):
        raise NotImplementedError()

    @property
    def entity_name(self):
        return self.db_mngr.get_item(self.db_map, self.entity_type,
                                     self.entity_id)["name"]

    @property
    def entity_class_type(self):
        return {
            "relationship": "relationship_class",
            "object": "object_class"
        }[self.entity_type]

    @property
    def entity_class_id(self):
        return self.db_mngr.get_item(self.db_map, self.entity_type,
                                     self.entity_id)["class_id"]

    @property
    def entity_class_name(self):
        return self.db_mngr.get_item(self.db_map, self.entity_class_type,
                                     self.entity_class_id)["name"]

    @property
    def db_map(self):
        return self.db_map_entity_id[0]

    @property
    def entity_id(self):
        return self.db_map_entity_id[1]

    @property
    def first_db_map(self):
        return self.db_map

    @property
    def display_data(self):
        return self.entity_name

    @property
    def display_database(self):
        return self.db_map.codename

    @property
    def db_maps(self):
        return (self.db_map, )

    def db_map_data(self, _db_map):
        # NOTE: Needed by EditObjectsDialog and EditRelationshipsDialog
        return self.db_mngr.get_item(self.db_map, self.entity_type,
                                     self.entity_id)

    def db_map_id(self, _db_map):
        # NOTE: Needed by EditObjectsDialog and EditRelationshipsDialog
        return self.entity_id

    def boundingRect(self):
        return super().boundingRect() | self.childrenBoundingRect()

    def moveBy(self, dx, dy):
        super().moveBy(dx, dy)
        self.update_arcs_line()

    def _init_bg(self):
        self._bg = QGraphicsRectItem(self.boundingRect(), self)
        self._bg.setPen(Qt.NoPen)

    def refresh_icon(self):
        """Refreshes the icon."""
        renderer = self.db_mngr.entity_class_renderer(self.db_map,
                                                      self.entity_class_type,
                                                      self.entity_class_id)
        self._set_renderer(renderer)

    def _set_renderer(self, renderer):
        self._svg_item.setSharedRenderer(renderer)
        size = renderer.defaultSize()
        scale = self._extent / max(size.width(), size.height())
        self._svg_item.setScale(scale)
        self._svg_item.setPos(self.rect().center() - 0.5 * scale *
                              QPointF(size.width(), size.height()))

    def shape(self):
        """Returns a shape containing the entire bounding rect, to work better with icon transparency."""
        path = QPainterPath()
        path.setFillRule(Qt.WindingFill)
        path.addRect(self._bg.boundingRect())
        return path

    def paint(self, painter, option, widget=None):
        """Shows or hides the selection halo."""
        if option.state & (QStyle.State_Selected):
            self._paint_as_selected()
            option.state &= ~QStyle.State_Selected
        else:
            self._paint_as_deselected()
        super().paint(painter, option, widget)

    def _paint_as_selected(self):
        self._bg.setBrush(QGuiApplication.palette().highlight())

    def _paint_as_deselected(self):
        self._bg.setBrush(self._bg_brush)

    def add_arc_item(self, arc_item):
        """Adds an item to the list of arcs.

        Args:
            arc_item (ArcItem)
        """
        self.arc_items.append(arc_item)
        arc_item.update_line()

    def apply_zoom(self, factor):
        """Applies zoom.

        Args:
            factor (float): The zoom factor.
        """
        if factor > 1:
            factor = 1
        self.setScale(factor)

    def apply_rotation(self, angle, center):
        """Applies rotation.

        Args:
            angle (float): The angle in degrees.
            center (QPoint): Rotates around this point.
        """
        line = QLineF(center, self.pos())
        line.setAngle(line.angle() + angle)
        self.setPos(line.p2())
        self.update_arcs_line()

    def block_move_by(self, dx, dy):
        self.moveBy(dx, dy)

    def mouseMoveEvent(self, event):
        """Moves the item and all connected arcs.

        Args:
            event (QGraphicsSceneMouseEvent)
        """
        if event.buttons() & Qt.LeftButton == 0:
            super().mouseMoveEvent(event)
            return
        move_by = event.scenePos() - event.lastScenePos()
        # Move selected items together
        for item in self.scene().selectedItems():
            if isinstance(item, (EntityItem)):
                item.block_move_by(move_by.x(), move_by.y())

    def update_arcs_line(self):
        """Moves arc items."""
        for item in self.arc_items:
            item.update_line()

    def itemChange(self, change, value):
        """
        Keeps track of item's movements on the scene.

        Args:
            change (GraphicsItemChange): a flag signalling the type of the change
            value: a value related to the change

        Returns:
            the same value given as input
        """
        if change == QGraphicsItem.ItemScenePositionHasChanged:
            self._moved_on_scene = True
        return value

    def set_all_visible(self, on):
        """Sets visibility status for this item and all arc items.

        Args:
            on (bool)
        """
        for item in self.arc_items:
            item.setVisible(on)
        self.setVisible(on)

    def _make_menu(self):
        return self._spine_db_editor.ui.graphicsView.make_items_menu()

    def contextMenuEvent(self, e):
        """Shows context menu.

        Args:
            e (QGraphicsSceneMouseEvent): Mouse event
        """
        e.accept()
        if not self.isSelected() and not e.modifiers() & Qt.ControlModifier:
            self.scene().clearSelection()
        self.setSelected(True)
        menu = self._make_menu()
        menu.popup(e.screenPos())
Пример #12
0
class EntityItem(QGraphicsPixmapItem):
    """Base class for ObjectItem and RelationshipItem."""
    def __init__(self, data_store_form, x, y, extent, entity_id=None):
        """Initializes item

        Args:
            data_store_form (DataStoreForm): 'owner'
            x (float): x-coordinate of central point
            y (float): y-coordinate of central point
            extent (int): Preferred extent
            entity_id (int): The entity id
        """
        super().__init__()
        self._data_store_form = data_store_form
        self.db_mngr = data_store_form.db_mngr
        self.db_map = data_store_form.db_map
        self.entity_id = entity_id
        self.arc_items = list()
        self._extent = extent
        self.refresh_icon()
        self.setPos(x, y)
        rect = self.boundingRect()
        self.setOffset(-rect.width() / 2, -rect.height() / 2)
        self._moved_on_scene = False
        self._bg = None
        self._bg_brush = Qt.NoBrush
        self._init_bg()
        self._bg.setFlag(QGraphicsItem.ItemStacksBehindParent, enabled=True)
        self.setZValue(0)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIsMovable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIgnoresTransformations, enabled=True)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, enabled=True)
        self.setAcceptHoverEvents(True)
        self.setCursor(Qt.ArrowCursor)

    @property
    def entity_type(self):
        raise NotImplementedError()

    @property
    def entity_name(self):
        return self.db_mngr.get_item(self.db_map, self.entity_type,
                                     self.entity_id)["name"]

    @property
    def entity_class_type(self):
        return {
            "relationship": "relationship class",
            "object": "object class"
        }[self.entity_type]

    @property
    def entity_class_id(self):
        return self.db_mngr.get_item(self.db_map, self.entity_type,
                                     self.entity_id)["class_id"]

    @property
    def entity_class_name(self):
        return self.db_mngr.get_item(self.db_map, self.entity_class_type,
                                     self.entity_class_id)["name"]

    @property
    def first_db_map(self):
        return self.db_map

    @property
    def display_data(self):
        return self.entity_name

    @property
    def display_database(self):
        return self.db_map.codename

    @property
    def db_maps(self):
        return (self.db_map, )

    def db_map_data(self, _db_map):
        return self.db_mngr.get_item(self.db_map, self.entity_type,
                                     self.entity_id)

    def db_map_id(self, _db_map):
        return self.entity_id

    def boundingRect(self):
        return super().boundingRect() | self.childrenBoundingRect()

    def moveBy(self, dx, dy):
        super().moveBy(dx, dy)
        self.update_arcs_line()

    def _init_bg(self):
        self._bg = QGraphicsRectItem(self.boundingRect(), self)
        self._bg.setPen(Qt.NoPen)

    def refresh_icon(self):
        """Refreshes the icon."""
        pixmap = self.db_mngr.entity_class_icon(
            self.db_map, self.entity_class_type,
            self.entity_class_id).pixmap(self._extent)
        self.setPixmap(pixmap)

    def shape(self):
        """Returns a shape containing the entire bounding rect, to work better with icon transparency."""
        path = QPainterPath()
        path.setFillRule(Qt.WindingFill)
        path.addRect(self._bg.boundingRect())
        return path

    def paint(self, painter, option, widget=None):
        """Shows or hides the selection halo."""
        if option.state & (QStyle.State_Selected):
            self._paint_as_selected()
            option.state &= ~QStyle.State_Selected
        else:
            self._paint_as_deselected()
        super().paint(painter, option, widget)

    def _paint_as_selected(self):
        self._bg.setBrush(QGuiApplication.palette().highlight())

    def _paint_as_deselected(self):
        self._bg.setBrush(self._bg_brush)

    def add_arc_item(self, arc_item):
        """Adds an item to the list of arcs.

        Args:
            arc_item (ArcItem)
        """
        self.arc_items.append(arc_item)
        arc_item.update_line()

    def apply_zoom(self, factor):
        """Applies zoom.

        Args:
            factor (float): The zoom factor.
        """
        if factor > 1:
            factor = 1
        self.setScale(factor)

    def apply_rotation(self, angle, center):
        """Applies rotation.

        Args:
            angle (float): The angle in degrees.
            center (QPoint): Rotates around this point.
        """
        line = QLineF(center, self.pos())
        line.setAngle(line.angle() + angle)
        self.setPos(line.p2())
        self.update_arcs_line()

    def block_move_by(self, dx, dy):
        self.moveBy(dx, dy)

    def mouseMoveEvent(self, event):
        """Moves the item and all connected arcs. Also checks for a merge target
        and sets an appropriate mouse cursor.

        Args:
            event (QGraphicsSceneMouseEvent)
        """
        if event.buttons() & Qt.LeftButton == 0:
            super().mouseMoveEvent(event)
            return
        move_by = event.scenePos() - event.lastScenePos()
        # Move selected items together
        for item in self.scene().selectedItems():
            if isinstance(item, (EntityItem)):
                item.block_move_by(move_by.x(), move_by.y())

    def update_arcs_line(self):
        """Moves arc items."""
        for item in self.arc_items:
            item.update_line()

    def itemChange(self, change, value):
        """
        Keeps track of item's movements on the scene.

        Args:
            change (GraphicsItemChange): a flag signalling the type of the change
            value: a value related to the change

        Returns:
            the same value given as input
        """
        if change == QGraphicsItem.ItemScenePositionHasChanged:
            self._moved_on_scene = True
        return value

    def set_all_visible(self, on):
        """Sets visibility status for this item and all arc items.

        Args:
            on (bool)
        """
        for item in self.arc_items:
            item.setVisible(on)
        self.setVisible(on)

    def _make_menu(self):
        menu = QMenu(self._data_store_form)
        menu.addAction(self._data_store_form.ui.actionSave_positions)
        menu.addAction(self._data_store_form.ui.actionClear_positions)
        menu.addSeparator()
        menu.addAction(self._data_store_form.ui.actionHide_selected)
        menu.addAction(self._data_store_form.ui.actionPrune_selected_entities)
        menu.addAction(self._data_store_form.ui.actionPrune_selected_classes)
        menu.addSeparator()
        menu.addAction(self._data_store_form.ui.actionEdit_selected)
        menu.addAction(self._data_store_form.ui.actionRemove_selected)
        return menu

    def contextMenuEvent(self, e):
        """Shows context menu.

        Args:
            e (QGraphicsSceneMouseEvent): Mouse event
        """
        e.accept()
        if not self.isSelected() and not e.modifiers() & Qt.ControlModifier:
            self.scene().clearSelection()
        self.setSelected(True)
        self._data_store_form._handle_menu_graph_about_to_show()
        self._menu.popup(e.screenPos())
Пример #13
0
class CanvasGraphicsView(QtWidgets.QGraphicsView):
    capture_complete = QtCore.Signal()

    def __init__(self, parent=None):
        super().__init__(parent)

        self.image = None
        self.rect_item = None
        self.start_pos = None

    def setup_scene(self, img: Image):
        #if img.mode != "RGB":
        #img = img.convert("RGB")
        self.image = img
        scene = CanvasGraphicsScene()
        self.setScene(scene)

        #scene固有の初期化
        qtimg = ImageQt(self.image)
        pixmap = QPixmap.fromImage(qtimg).copy()
        pixmap_item = QGraphicsPixmapItem(pixmap)
        self.scene().addItem(pixmap_item)
        pixmap_item.setPos(0, 0)
        self.rect_item = QGraphicsRectItem(0, 0, 200, 200)
        self.rect_item.setPen(QPen(QtCore.Qt.blue, 3))
        self.rect_item.hide()
        self.scene().addItem(self.rect_item)
        self.frame_rect_item = QGraphicsRectItem(0, 0, self.image.width - 3,
                                                 self.image.height - 3)
        self.frame_rect_item.setPen(QPen(QtCore.Qt.red, 5))
        self.scene().addItem(self.frame_rect_item)

        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        img = self.image
        self.setSceneRect(0, 0, img.width, img.height)
        self.setFixedSize(img.width, img.height)

        self._dragging = False
        pass

    def mousePressEvent(self, event):
        event.accept()
        if event.button() == QtCore.Qt.MouseButton.RightButton:
            #self._parent_window.accepted()
            self.capture_complete.emit()
            return
        else:
            self._dragging = True
            orig_pos = self.mapFromGlobal(QCursor.pos())
            scene_pos = self.mapToScene(orig_pos)
            #self.rect_item.show()
            self.start_pos = scene_pos

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.capture_complete.emit()

    def mouseMoveEvent(self, event):
        event.accept()
        if self._dragging:
            orig_pos = self.mapFromGlobal(QCursor.pos())
            now_pos = self.mapToScene(orig_pos)

            s_x = self.start_pos.x()
            s_y = self.start_pos.y()
            n_x = now_pos.x()
            n_y = now_pos.y()

            self.rect_item.setRect(s_x, s_y, max(0, n_x - s_x), n_y - s_y)

            self.rect_item.show()

    def mouseReleaseEvent(self, event):
        event.accept()
        orig_pos = self.mapFromGlobal(QCursor.pos())
        now_pos = self.mapToScene(orig_pos)

        s_x = self.start_pos.x()
        s_y = self.start_pos.y()
        n_x = now_pos.x()
        n_y = now_pos.y()
        data = {"rect": (s_x, s_y, n_x, n_y)}
        res = QtWidgets.QMessageBox.information(None, "確認", "この領域を保存しますか?",
                                                QtWidgets.QMessageBox.Yes,
                                                QtWidgets.QMessageBox.No)
        if res == QtWidgets.QMessageBox.Yes:
            import json
            with open(area_data_path, "w", encoding="utf-8") as f:
                json.dump(data, f)
            self.capture_complete.emit()

        self._dragging = False
        self.rect_item.hide()
Пример #14
0
    def _create_line_indicator(self, addr, item_map, color=Qt.yellow, show_frontier=False, z=None, z_frontier=None):
        """
        Generate a cursor at a given address.
        """
        pos_x = self._get_pos_from_addr(addr)
        if pos_x is None:
            return

        pen = QPen(color)
        brush = QBrush(color)
        height = self.height

        tri_width = 7
        tri_height = 4

        pos_x = int(pos_x - tri_width / 2)  # Center drawing
        center = pos_x + int(tri_width / 2)
        pos_y = 0
        frontier_width = int(0.15 * max(self.width, self.height))

        if show_frontier:
            # Draw frontier gradients
            r = QRectF(center - frontier_width, pos_y, frontier_width, height)
            bg = QLinearGradient(r.topLeft(), r.topRight())
            color = Qt.red
            top_color = QColor(color)
            top_color.setAlpha(0)
            bg.setColorAt(0, top_color)
            bottom_color = QColor(color)
            bottom_color.setAlpha(180)
            bg.setColorAt(1, bottom_color)

            i = QGraphicsRectItem(r, parent=self)
            i.setPen(Qt.NoPen)
            i.setBrush(bg)
            if z_frontier is not None:
                i.setZValue(z_frontier)
            item_map.append(i)

            r = QRectF(center, pos_y, frontier_width, height)
            bg = QLinearGradient(r.topLeft(), r.topRight())
            color = Qt.blue
            top_color = QColor(color)
            bg.setColorAt(0, top_color)
            bottom_color = QColor(color)
            bottom_color.setAlpha(0)
            bg.setColorAt(1, bottom_color)

            i = QGraphicsRectItem(r, parent=self)
            i.setPen(Qt.NoPen)
            i.setBrush(bg)
            if z_frontier is not None:
                i.setZValue(z_frontier)
            item_map.append(i)

        # Draw line
        i = QGraphicsLineItem(center, 0, center, height, parent=self)
        i.setPen(pen)
        if z is not None:
            i.setZValue(z)
        item_map.append(i)

        # Draw top and bottom triangles
        t = QPolygonF()
        t.append(QPointF(pos_x, pos_y))
        t.append(QPointF(pos_x + tri_width - 1, pos_y))
        t.append(QPointF(center, pos_y + tri_height - 1))
        t.append(QPointF(pos_x, pos_y))

        pos_y += height - 1
        b = QPolygonF()
        b.append(QPointF(pos_x, pos_y))
        b.append(QPointF(center, pos_y - tri_height + 1))
        b.append(QPointF(pos_x + tri_width - 1, pos_y))
        b.append(QPointF(pos_x, pos_y))

        for i in [QGraphicsPolygonItem(t, parent=self),
                  QGraphicsPolygonItem(b, parent=self)]:
            i.setPen(pen)
            i.setBrush(brush)
            if z is not None:
                i.setZValue(z)
            item_map.append(i)
Пример #15
0
class TextLineItem(QAbstractGraphicsShapeItem):
    """A one-line text item.

    Default origin point is at the left side of the baseline. This can change if setAlignMode is called. TextLineItem
    also supports drawing text background. Its brush can be set using setBackgroundBrush(). Text must not contain
    newline characters.
    """
    def __init__(self, text=None, parent=None):
        super().__init__(parent)

        self._text = text or ""
        self._elided_text = text or ""
        self._elide_mode = Qt.ElideRight
        self._align_mode = Qt.AlignLeft
        self._max_width = None
        self._font = QFont()
        self._bounding_rect = QRectF()
        """Bounding and drawing rectangle. Determined automatically."""

        self.background = QGraphicsRectItem(self)
        self.background.setPen(Qt.NoPen)
        self.background.setFlag(QGraphicsItem.ItemStacksBehindParent)

        self.adjust()

    def setText(self, text: str, /) -> None:
        if '\n' in text:
            raise ValueError("text must not contain newline characters")

        self.prepareGeometryChange()
        self._text = text
        self.adjust()

    def setElideMode(self, mode: int, /) -> None:
        """Elide mode specifies where the ellipsis should be located when the text is elided. Default value is 
        Qt.ElideRight.
        """
        self.prepareGeometryChange()
        self._elide_mode = mode
        self.adjust()

    def setAlignMode(self, mode: int, /) -> None:
        """Align mode specifies text alignment.

        Text alignment changes the origin point x position:  
        - If mode is Qt.AlignLeft, the origin point is on the left of the baseline.
        - If mode is Qt.AlignHCenter, the origin point is in the center of the baseline.
        - If mode is Qt.AlignRight, the origin point is on the right of the baseline.

        Vertical alignment has no meaning for one line of text and should not be set. Default value is Qt.AlignLeft.
        """
        self.prepareGeometryChange()
        self._align_mode = mode
        self.adjust()

    def setMaximumWidth(self, width, /):
        """Set the maximum width the text is allowed to be. `None` represents unlimited width."""
        self.prepareGeometryChange()
        self._max_width = width
        self.adjust()

    def setFont(self, font: QFont, /) -> None:
        self.prepareGeometryChange()
        self._font = font
        self.adjust()

    def setBackgroundBrush(self, brush: QBrush, /):
        self.background.setBrush(brush)

    def text(self) -> str:
        return self._text

    def elidedText(self) -> str:
        return self._elided_text

    def elideMode(self) -> int:
        return self._elide_mode

    def alignMode(self) -> int:
        return self._align_mode

    def maximumWidth(self):
        """Maximum width the text is allowed to be. `None` represents unlimited width."""
        return self._max_width

    def font(self) -> QFont:
        return self._font

    def backgroundBrush(self):
        return self.background.brush()

    def adjust(self):
        """Adjust the item's geometry in response to changes."""
        metrics = QFontMetricsF(self.font())

        # Get bounding rectangle for full text
        self._bounding_rect = metrics.boundingRect(self.text())

        # Constrain by maximum width
        if self.maximumWidth() is not None:
            self._bounding_rect.setWidth(self.maximumWidth())

        # Compute elided text
        self._elided_text = metrics.elidedText(self.text(), self.elideMode(),
                                               self.boundingRect().width())

        # Get bounding rectangle for elided text
        self._bounding_rect = metrics.boundingRect(self.elidedText())
        # It seems that for small characters like "..." the bounding rect returned is too small. Adjust it by a small
        # value.
        metrics_correction = px(1 / 72)
        self._bounding_rect.adjust(-metrics_correction, 0, metrics_correction,
                                   0)

        # Move origin point according to the alignment
        if self.alignMode() & Qt.AlignLeft:
            self._bounding_rect.moveLeft(0)
        elif self.alignMode() & Qt.AlignRight:
            self._bounding_rect.moveRight(0)
        else:
            self._bounding_rect.moveLeft(-self._bounding_rect.width() / 2)

        # Set background rect
        self.background.setRect(self.boundingRect())

    def boundingRect(self) -> QRectF:
        return self._bounding_rect

    def paint(self, painter: QPainter, option, widget=...) -> None:
        painter.setBrush(self.brush())
        painter.setPen(self.pen())
        painter.setFont(self.font())

        painter.drawText(self.boundingRect(), self.alignMode(),
                         self.elidedText())
Пример #16
0
class QScene2dViewer(AbstractGraphicViewer):
    drawaxis = False
    axis_center = None
    axis_x = None
    axis_y = None
    G = None

    def __init__(self, G):
        super().__init__()
        self.G = G
        #        self.setMinimunSize(400, 400)
        self.scale(1, -1)
        # AXIS
        self.axis_center = QGraphicsRectItem(-100, -100, 200, 200)
        self.axis_center.setPen(QPen(QColor("black")))
        self.axis_center.setBrush(QBrush(QColor("black")))
        self.axis_center.setZValue(5000)
        self.axis_x = QGraphicsRectItem(0, 0, 1000, 30)
        self.axis_x.setPen(QPen(QColor("red")))
        self.axis_x.setBrush(QBrush(QColor("red")))
        self.axis_x.setZValue(5000)
        self.axis_y = QGraphicsRectItem(0, 0, 30, 1000)
        self.axis_y.setPen(QPen(QColor("blue")))
        self.axis_y.setBrush(QBrush(QColor("blue")))
        self.axis_y.setZValue(5000)

        self.set_draw_axis(True)
        self.draw_axis()

    def create_graph(self):
        pass

    def set_draw_axis(self, visible):
        self.drawaxis = visible

    def draw_axis(self):
        if self.drawaxis:
            self.scene.addItem(self.axis_center)
            self.scene.addItem(self.axis_x)
            self.scene.addItem(self.axis_y)
        else:
            self.scene.removeItem(self.axis_center)
            self.scene.removeItem(self.axis_x)
            self.scene.removeItem(self.axis_y)

    # SLOTS
    def add_or_assign_node_slot(self, node_id, node_type, name=""):
        pass

    def add_or_assign_node_slot(self, node_id, node):
        pass

    def add_or_assign_edge_slot(self, from_node, to_node, node_type):
        pass

    def del_edge_slot(self, from_node, to_node, edge_tag):
        pass

    def del_node_slot(self, node_id):
        pass

    def node_change_slot(self, value, node_id, node_type, parent=None):
        pass

    def category_change_slot(self, value, parent=None):
        pass