a
    =b$                     @   sR   d Z ddlmZ ddlZddlmZmZmZ ddl	m
Z
mZ G dd dejZdS )	z8
Base class for Plugins that interact with ImageViewer.
    )warnN   )	QtWidgetsQtCoreSignal)RequiredAttr
init_qtappc                       s   e Zd ZdZd Zede Zeej	Z
eeZd( fdd		Zd
d Zdd Zdd Zdd Zdd Zdd Zdd Zedd Zdd Zdd Zd) fdd	Zd d! Zd"d# Zd$d% Zd&d' Z  ZS )*Plugina]
  Base class for plugins that interact with an ImageViewer.

    A plugin connects an image filter (or another function) to an image viewer.
    Note that a Plugin is initialized *without* an image viewer and attached in
    a later step. See example below for details.

    Parameters
    ----------
    image_viewer : ImageViewer
        Window containing image used in measurement/manipulation.
    image_filter : function
        Function that gets called to update image in image viewer. This value
        can be `None` if, for example, you have a plugin that extracts
        information from an image and doesn't manipulate it. Alternatively,
        this function can be defined as a method in a Plugin subclass.
    height, width : int
        Size of plugin window in pixels. Note that Qt will automatically resize
        a window to fit components. So if you're adding rows of components, you
        can leave `height = 0` and just let Qt determine the final height.
    useblit : bool
        If True, use blitting to speed up animation. Only available on some
        Matplotlib backends. If None, set to True when using Agg backend.
        This only has an effect if you draw on top of an image viewer.

    Attributes
    ----------
    image_viewer : ImageViewer
        Window containing image used in measurement.
    name : str
        Name of plugin. This is displayed as the window title.
    artist : list
        List of Matplotlib artists and canvastools. Any artists created by the
        plugin should be added to this list so that it gets cleaned up on
        close.

    Examples
    --------
    >>> from skimage.viewer import ImageViewer
    >>> from skimage.viewer.widgets import Slider
    >>> from skimage import data
    >>>
    >>> plugin = Plugin(image_filter=lambda img,
    ...                 threshold: img > threshold) # doctest: +SKIP
    >>> plugin += Slider('threshold', 0, 255)       # doctest: +SKIP
    >>>
    >>> image = data.coins()
    >>> viewer = ImageViewer(image)       # doctest: +SKIP
    >>> viewer += plugin                  # doctest: +SKIP
    >>> thresholded = viewer.show()[0][0] # doctest: +SKIP

    The plugin will automatically delegate parameters to `image_filter` based
    on its parameter type, i.e., `ptype` (widgets for required arguments must
    be added in the order they appear in the function). The image attached
    to the viewer is **automatically passed as the first argument** to the
    filter function.

    #TODO: Add flag so image is not passed to filter function by default.

    `ptype = 'kwarg'` is the default for most widgets so it's unnecessary here.

    z!%s is not attached to ImageViewerNr     Tbottomc                    s   t   tt|   || _d | _t| ds2|| _n|d urBtd | 	| j
 t| | _| || d| _g | _i | _|| _g | _g | _d S )Nimage_filterzbIf the Plugin class defines an `image_filter` method, then the `image_filter` argument is ignored.r   )r   superr	   __init__dockimage_viewerhasattrr   r   ZsetWindowTitlenamer   ZQGridLayoutlayoutZresizerow	argumentskeyword_argumentsuseblitZcidsartists)selfr   Zheightwidthr   r   	__class__ :lib/python3.9/site-packages/skimage/viewer/plugins/base.pyr   P   s"    
zPlugin.__init__c                 C   sD   |  | | tjj || _| jj|  | jjg| _	| 
  dS )aw  Attach the plugin to an ImageViewer.

        Note that the ImageViewer will automatically call this method when the
        plugin is added to the ImageViewer. For example::

            viewer += Plugin(...)

        Also note that `attach` automatically calls the filter function so that
        the image matches the filtered value specified by attached widgets.
        N)Z	setParentZsetWindowFlagsr   ZQtZDialogr   pluginsappendZoriginal_imager   filter_image)r   r   r   r   r   attachk   s    
zPlugin.attachc                 C   s   |j dkr,|jdd}|| j|< | j|_n2|j dkrL| j| | j|_n|j dkr^| j|_| |_	| j
|| jd |  jd7  _dS )	a1  Add widget to plugin.

        Alternatively, Plugin's `__add__` method is overloaded to add widgets::

            plugin += Widget(...)

        Widgets can adjust required or optional arguments of filter function or
        parameters for the plugin. This is specified by the Widget's `ptype`.
        kwarg _argpluginr      N)Zptyper   replacer   r!   callbackr   r    update_pluginr'   r   Z	addWidgetr   )r   widgetr   r   r   r   
add_widget   s    






zPlugin.add_widgetc                 C   s   |  | | S N)r-   )r   r,   r   r   r   __add__   s    
zPlugin.__add__c                    sd    j du rdS  fdd jD } fdd j D } j |i |} |  j| dS )zyCall `image_filter` with widget args and kwargs

        Note: `display_filtered_image` is automatically called.
        Nc                    s   g | ]}  |qS r   
_get_value).0ar   r   r   
<listcomp>       z'Plugin.filter_image.<locals>.<listcomp>c                    s   i | ]\}}|  |qS r   r0   )r2   r   r3   r4   r   r   
<dictcomp>   s   z'Plugin.filter_image.<locals>.<dictcomp>)r   r   r   itemsdisplay_filtered_imageimage_changedemit)r   Z
widget_argr   kwargsZfilteredr   r4   r   r!      s    


zPlugin.filter_imagec                 C   s   t |ds|S |jS )Nval)r   r=   )r   Zparamr   r   r   r1      s    zPlugin._get_valuec                 C   s    || j d< | | |   dS )zUpdate the original image argument passed to the filter function.

        This method is called by the viewer when the original image is updated.
        r   N)r   _on_new_imager!   r   imager   r   r   _update_original_image   s    

zPlugin._update_original_imagec                 C   s   dS )z:Override this method to update your plugin for new images.Nr   r?   r   r   r   r>      s    zPlugin._on_new_imagec                 C   s   | j jS )zReturn filtered image.r   r@   r4   r   r   r   filtered_image   s    zPlugin.filtered_imagec                 C   s   || j _dS )zDisplay the filtered image on image viewer.

        If you don't want to simply replace the displayed image with the
        filtered image (e.g., you want to display a transparent overlay),
        you can override this method.
        NrB   r?   r   r   r   r9      s    zPlugin.display_filtered_imagec                 C   s   t | || dS )zUpdate keyword parameters of the plugin itself.

        These parameters will typically be implemented as class properties so
        that they update the image or some other component.
        N)setattr)r   r   valuer   r   r   r+      s    zPlugin.update_pluginc                    sF   t t|   |   |   |  }| |  }| j	| dS )zShow plugin.N)
r   r	   showZactivateWindowZraise_ZframeGeometryxr   _startedr;   )r   Zmain_windowsizeZx_hintr   r   r   rF      s    zPlugin.showc                 C   s   |    |   dS )zOn close disconnect all artists and events from ImageViewer.

        Note that artists must be appended to `self.artists`.
        N)clean_upclose)r   Zeventr   r   r   
closeEvent   s    zPlugin.closeEventc                 C   s:   |    | | jjv r"| jj|  | j  | j  d S r.   )remove_image_artistsr   r   removeZreset_imageZredrawr4   r   r   r   rJ      s
    
zPlugin.clean_upc                 C   s   | j D ]}|  qdS )z6Remove artists that are connected to the image viewer.N)r   rN   )r   r3   r   r   r   rM      s    
zPlugin.remove_image_artistsc                 C   s   | j jdfS )a  Return the plugin's representation and data.

        Returns
        -------
        image : array, same shape as ``self.image_viewer.image``, or None
            The filtered image.
        data : None
            Any data associated with the plugin.

        Notes
        -----
        Derived classes should override this method to return a tuple
        containing an *overlay* of the same shape of the image, and a
        *data* object. Either of these is optional: return ``None`` if
        you don't want to return a value.
        NrB   r4   r   r   r   output   s    zPlugin.output)Nr   r
   Tr   )T)__name__
__module____qualname____doc__r   r   r   r   npZndarrayr:   intrH   r   r"   r-   r/   r!   r1   rA   r>   propertyrC   r9   r+   rF   rL   rJ   rM   rO   __classcell__r   r   r   r   r	      s0   =
  	
	r	   )rS   warningsr   ZnumpyrT   Zqtr   r   r   Zutilsr   r   ZQDialogr	   r   r   r   r   <module>   s
   