Source code for plotpy.items.shape.base

# -*- coding: utf-8 -*-
#
# Licensed under the terms of the BSD 3-Clause
# (see plotpy/LICENSE for details)

from __future__ import annotations

from typing import TYPE_CHECKING

from guidata.utils.misc import assert_interfaces_valid
from qwt import QwtPlotItem

from plotpy.coords import canvas_to_axes
from plotpy.interfaces import IBasePlotItem, IShapeItemType

if TYPE_CHECKING:
    from qtpy.QtCore import QPointF  # helping out python_qt_documentation

    from plotpy.interfaces import IItemType
    from plotpy.plot import BasePlot
    from plotpy.styles.base import ItemParameters


[docs] class AbstractShape(QwtPlotItem): """Abstract shape class""" __implements__ = (IBasePlotItem,) _readonly = False _private = False _can_select = True _can_resize = True _can_rotate = False # TODO: Implement shape rotation? _can_move = True def __init__(self) -> None: super().__init__() self.selected = False
[docs] def plot(self) -> BasePlot | None: """Return the plot this item belongs to Returns: Plot this item belongs to, or None if not attached to any """ return super().plot()
# ------IBasePlotItem API----------------------------------------------------
[docs] def get_icon_name(self) -> str: """Return the icon name Returns: Icon name """ return self._icon_name
[docs] def set_icon_name(self, icon_name: str) -> None: """Set the icon name Args: icon_name: Icon name """ self._icon_name = icon_name
[docs] def set_selectable(self, state: bool) -> None: """Set item selectable state Args: state: True if item is selectable, False otherwise """ self._can_select = state
[docs] def set_resizable(self, state: bool) -> None: """Set item resizable state (or any action triggered when moving an handle, e.g. rotation) Args: state: True if item is resizable, False otherwise """ self._can_resize = state
[docs] def set_movable(self, state: bool) -> None: """Set item movable state Args: state: True if item is movable, False otherwise """ self._can_move = state
[docs] def set_rotatable(self, state: bool) -> None: """Set item rotatable state Args: state: True if item is rotatable, False otherwise """ self._can_rotate = state
[docs] def can_select(self) -> bool: """ Returns True if this item can be selected Returns: bool: True if item can be selected, False otherwise """ return self._can_select
[docs] def can_resize(self) -> bool: """ Returns True if this item can be resized Returns: bool: True if item can be resized, False otherwise """ return self._can_resize
[docs] def can_rotate(self) -> bool: """ Returns True if this item can be rotated Returns: bool: True if item can be rotated, False otherwise """ return self._can_rotate
[docs] def can_move(self) -> bool: """ Returns True if this item can be moved Returns: bool: True if item can be moved, False otherwise """ return self._can_move
[docs] def types(self) -> tuple[type[IItemType], ...]: """Returns a group or category for this item. This should be a tuple of class objects inheriting from IItemType Returns: tuple: Tuple of class objects inheriting from IItemType """ return (IShapeItemType,)
[docs] def set_readonly(self, state: bool) -> None: """Set object readonly state Args: state: True if object is readonly, False otherwise """ self._readonly = state
[docs] def is_readonly(self) -> bool: """Return object readonly state Returns: bool: True if object is readonly, False otherwise """ return self._readonly
[docs] def set_private(self, state: bool) -> None: """Set object as private Args: state: True if object is private, False otherwise """ self._private = state
[docs] def is_private(self) -> bool: """Return True if object is private Returns: bool: True if object is private, False otherwise """ return self._private
[docs] def select(self) -> None: """ Select the object and eventually change its appearance to highlight the fact that it's selected """ self.selected = True self.invalidate_plot()
[docs] def unselect(self) -> None: """ Unselect the object and eventually restore its original appearance to highlight the fact that it's not selected anymore """ self.selected = False self.invalidate_plot()
[docs] def hit_test(self, pos: QPointF) -> tuple[float, float, bool, None]: """Return a tuple (distance, attach point, inside, other_object) Args: pos: Position Returns: tuple: Tuple with four elements: (distance, attach point, inside, other_object). Description of the returned values: * distance: distance in pixels (canvas coordinates) to the closest attach point * attach point: handle of the attach point * inside: True if the mouse button has been clicked inside the object * other_object: if not None, reference of the object which will be considered as hit instead of self """ pass
[docs] def update_item_parameters(self) -> None: """Update item parameters (dataset) from object properties""" pass
[docs] def get_item_parameters(self, itemparams: ItemParameters) -> None: """ Appends datasets to the list of DataSets describing the parameters used to customize apearance of this item Args: itemparams: Item parameters """
[docs] def set_item_parameters(self, itemparams): """ Change the appearance of this item according to the parameter set provided params is a list of Datasets of the same types as those returned by get_item_parameters """ pass
[docs] def move_local_point_to( self, handle: int, pos: QPointF, ctrl: bool = False ) -> None: """Move a handle as returned by hit_test to the new position Args: handle: Handle pos: Position ctrl: True if <Ctrl> button is being pressed, False otherwise """ pt = canvas_to_axes(self, pos) self.move_point_to(handle, pt, ctrl) plot: BasePlot = self.plot() if plot is not None: plot.SIG_ITEM_RESIZED.emit(self, 0, 0) plot.SIG_ITEM_HANDLE_MOVED.emit(self)
[docs] def move_local_shape(self, old_pos: QPointF, new_pos: QPointF) -> None: """Translate the shape such that old_pos becomes new_pos in canvas coordinates Args: old_pos: Old position new_pos: New position """ old_pt = canvas_to_axes(self, old_pos) new_pt = canvas_to_axes(self, new_pos) self.move_shape(old_pt, new_pt) plot: BasePlot = self.plot() if plot is not None: plot.SIG_ITEM_MOVED.emit(self, *(old_pt + new_pt))
[docs] def move_with_selection(self, delta_x: float, delta_y: float) -> None: """Translate the item together with other selected items Args: delta_x: Translation in plot coordinates along x-axis delta_y: Translation in plot coordinates along y-axis """ self.move_shape([0, 0], [delta_x, delta_y])
# ------Public API-----------------------------------------------------------
[docs] def move_point_to( self, handle: int, pos: tuple[float, float], ctrl: bool = False ) -> None: """Move a handle as returned by hit_test to the new position Args: handle: Handle pos: Position ctrl: True if <Ctrl> button is being pressed, False otherwise """ pass
[docs] def move_shape(self, old_pos: QPointF, new_pos: QPointF) -> None: """Translate the shape such that old_pos becomes new_pos in axis coordinates Args: old_pos: Old position new_pos: New position """ pass
[docs] def invalidate_plot(self) -> None: """Invalidate the plot to force a redraw""" plot: BasePlot = self.plot() if plot is not None: plot.invalidate()
[docs] def is_empty(self) -> bool: """Return True if the item is empty Returns: True if the item is empty, False otherwise """ return False
assert_interfaces_valid(AbstractShape)