U
    Peb                     @   s  d Z dZddlZddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZmZmZmZmZmZmZmZmZ ed G dd dej ej!Z"G dd dej#ej!Z$G dd dej%Z&G dd dej'Z(dd Z)dd Z*dd Z+dS )a  
Inspector
=========

.. versionadded:: 1.0.9

.. warning::

    This module is highly experimental, use it with care.

The Inspector is a tool for finding a widget in the widget tree by clicking or
tapping on it.
Some keyboard shortcuts are activated:

    * "Ctrl + e": activate / deactivate the inspector view
    * "Escape": cancel widget lookup first, then hide the inspector view

Available inspector interactions:

    * tap once on a widget to select it without leaving inspect mode
    * double tap on a widget to select and leave inspect mode (then you can
      manipulate the widget again)

Some properties can be edited live. However, due to the delayed usage of
some properties, it might crash if you don't handle all the cases.

Usage
-----

For normal module usage, please see the :mod:`~kivy.modules` documentation.

The Inspector, however, can also be imported and used just like a normal
python module. This has the added advantage of being able to activate and
deactivate the module programmatically::

    from kivy.core.window import Window
    from kivy.app import App
    from kivy.uix.button import Button
    from kivy.modules import inspector

    class Demo(App):
        def build(self):
            button = Button(text="Test")
            inspector.create_inspector(Window, button)
            return button

    Demo().run()

To remove the Inspector, you can do the following::

    inspector.stop(Window, button)

)startstopcreate_inspector    N)partial)chain)	Animation)Logger)Matrix)Clock)Builder)Factory)	WeakProxy)	ObjectPropertyBooleanPropertyListPropertyNumericPropertyStringPropertyOptionPropertyReferenceListPropertyAliasPropertyVariableListPropertya  
<Inspector>:
    layout: layout
    widgettree: widgettree
    treeview: treeview
    content: content
    BoxLayout:
        orientation: 'vertical'
        id: layout
        size_hint_y: None
        height: 250
        padding: 5
        spacing: 5
        top: 0

        canvas:
            Color:
                rgb: .4, .4, .4
            Rectangle:
                pos: self.x, self.top
                size: self.width, 1
            Color:
                rgba: .185, .18, .18, .95
            Rectangle:
                pos: self.pos
                size: self.size

        # Top Bar
        BoxLayout:
            size_hint_y: None
            height: 50
            spacing: 5
            Button:
                text: 'Move to Top'
                on_release: root.toggle_position(args[0])
                size_hint_x: None
                width: 120

            ToggleButton:
                text: 'Inspect'
                on_state: root.inspect_enabled = args[1] == 'down'
                size_hint_x: None
                state: 'down' if root.inspect_enabled else 'normal'
                width: 80

            Button:
                text: 'Parent'
                on_release:
                    root.highlight_widget(root.widget.parent) if root.widget                             else None
                size_hint_x: None
                width: 80

            Button:
                text: '%r' % root.widget
                on_release: root.show_widget_info()

            Button:
                text: 'X'
                size_hint_x: None
                width: 50
                on_release: root.activated = False

        # Bottom Bar
        BoxLayout:
            ScrollView:
                scroll_type: ['bars', 'content']
                bar_width: 10
                size_hint_x: 0.0001

                WidgetTree:
                    id: widgettree
                    hide_root: True
                    size_hint: None, None
                    height: self.minimum_height
                    width: max(self.parent.width, self.minimum_width)
                    selected_widget: root.widget
                    on_select_widget: root.highlight_widget(args[1])

            Splitter:
                sizeable_from: 'left'
                min_size: self.parent.width / 2
                max_size: self.parent.width

                BoxLayout:
                    ScrollView:
                        scroll_type: ['bars', 'content']
                        bar_width: 10
                        TreeView:
                            id: treeview
                            size_hint_y: None
                            hide_root: True
                            height: self.minimum_height

                    Splitter:
                        sizeable_from: 'left'
                        keep_within_parent: True
                        rescale_with_parent: True
                        max_size: self.parent.width / 2
                        min_size: 0

                        ScrollView:
                            id: content

<TreeViewProperty>:
    height: max(lkey.texture_size[1], ltext.texture_size[1])
    Label:
        id: lkey
        text: root.key
        text_size: (self.width, None)
        width: 150
        size_hint_x: None
    Label:
        id: ltext
        text: [repr(getattr(root.widget, root.key, '')), root.refresh][0]                if root.widget else ''
        text_size: (self.width, None)

<-TreeViewWidget>:
    height: self.texture_size[1] + sp(4)
    size_hint_x: None
    width: self.texture_size[0] + sp(4)

    canvas.before:
        Color:
            rgba: self.color_selected if self.is_selected else (0, 0, 0, 0)
        Rectangle:
            pos: self.pos
            size: self.size
        Color:
            rgba: 1, 1, 1, int(not self.is_leaf)
        Rectangle:
            source:
                ('atlas://data/images/defaulttheme/tree_%s' %
                ('opened' if self.is_open else 'closed'))
            size: 16, 16
            pos: self.x - 20, self.center_y - 8

    canvas:
        Color:
            rgba:
                (self.disabled_color if self.disabled else
                (self.color if not self.markup else (1, 1, 1, 1)))
        Rectangle:
            texture: self.texture
            size: self.texture_size
            pos:
                (int(self.center_x - self.texture_size[0] / 2.),
                int(self.center_y - self.texture_size[1] / 2.))
c                   @   sJ   e Zd ZedddZdd ZeedddZedddZedZ	e
dZdS )	TreeViewPropertyNTZ	allownonec                 C   s.   | j }|d krd S | }|d kr*d | _ d S |S N
widget_ref)selfwr r   :/tmp/pip-unpacked-wheel-xzebddm3/kivy/modules/inspector.py_get_widget   s    zTreeViewProperty._get_widgetr   )bindF)__name__
__module____qualname__r   r   r    r   widgetkey	inspectorr   refreshr   r   r   r   r      s   	r   c                   @   s   e Zd ZedZdS )TreeViewWidgetN)r"   r#   r$   r   r%   r   r   r   r   r)      s   r)   c                       sb   e Zd ZedddZdZ fddZdd Zd	d
 Zdd Z	d fdd	Z
dd Zdd Z  ZS )
WidgetTreeNTr   )on_select_widgetc                    s$   t t| jf | t| j| _d S r   )superr*   __init__r
   Zcreate_trigger_update_scrollupdate_scrollr   kwargs	__class__r   r   r-     s    zWidgetTree.__init__c              	   C   sH   |   D ]:}|jsqz|j|kr*|W   S W q tk
r@   Y qX qd S r   )iterate_all_nodesparent_noder%   ReferenceErrorr   r%   noder   r   r   find_node_by_widget  s    
zWidgetTree.find_node_by_widgetc                 C   sH   |rD|  |}|rD| |d |rDt|trD|js<| | |j}qd S )NF)r9   select_node
isinstancer)   is_openZtoggle_noder5   r7   r   r   r   update_selected_widget  s    

z!WidgetTree.update_selected_widgetc                 C   s   |r|  | |   d S r   )r=   r/   )r   instr%   r   r   r   on_selected_widget  s    
zWidgetTree.on_selected_widgetc                    sB   t t| | |r>z| d|jj W n tk
r<   Y nX d S )Nr+   )r,   r*   r:   dispatchr%   __self__r6   )r   r8   Zselect_widgetr2   r   r   r:     s    zWidgetTree.select_nodec                 C   s   d S r   r   )r   r%   r   r   r   r+   '  s    zWidgetTree.on_select_widgetc                 G   s   | j }|sd S | j| d S r   )Z_selected_nodeparentZ	scroll_to)r   argsr8   r   r   r   r.   *  s    zWidgetTree._update_scroll)T)r"   r#   r$   r   Zselected_widgetZ
__events__r-   r9   r=   r?   r:   r+   r.   __classcell__r   r   r2   r   r*      s   
r*   c                       s&  e Zd ZedddZedZedZedZedZ	edZ
edZedZedZdZ fddZ fddZ fd	d
Z fddZdd Zdd Zd2ddZdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd3d$d%Zd&d' Zd(d) Z d*d+ Z!d,d- Z"d4d.d/Z#d0d1 Z$  Z%S )5	InspectorNTr   Fc              	      s   | dd | _tt| jf | d| _| jjD t	dddd| _
t  tt | _tjdd| _t  W 5 Q R X t| jd d S )NwinF   r   g      ?r   r   )size)poprF   r,   rE   r-   avoid_bring_to_topZcanvasbeforer   ZColorZgcolorZ
PushMatrixZ	Transformr	   
gtransformZ	RectanglegrectZ	PopMatrixr
   schedule_intervalupdate_widget_graphicsr0   r2   r   r   r-   H  s    
zInspector.__init__c                    sV   t t| |}d|jks$|jdkrR|sR| jrR| j|j  |jrNd| _| 	  d}|S )NbuttonleftFT)
r,   rE   on_touch_downZprofilerQ   inspect_enabledhighlight_atposZis_double_tapshow_widget_infor   touchretr2   r   r   rS   T  s    zInspector.on_touch_downc                    s.   t t| |}|s*| jr*| j|j  d}|S NT)r,   rE   on_touch_moverT   rU   rV   rX   r2   r   r   r\   _  s
    
zInspector.on_touch_movec                    s"   t t| |}|s| jrd}|S r[   )r,   rE   on_touch_uprT   rX   r2   r   r   r]   f  s    
zInspector.on_touch_upc                 C   s4   | j s| jsd S d| _ ||  ||  d| _ d S NTF)rK   	activatedremove_widget
add_widget)r   rF   childrenr   r   r   on_window_childrenl  s    

zInspector.on_window_childrenc                 C   sf   d }| j j}tdd |D dd t|D }|D ]$}|| kr@q2| |||}|r2 qXq2| | d S )Nc                 s   s   | ]}t |tjr|V  qd S r   r;   r   Z	ModalView.0cr   r   r   	<genexpr>z  s      z)Inspector.highlight_at.<locals>.<genexpr>c                 s   s   | ]}t |tjs|V  qd S r   rd   re   r   r   r   rh   {  s   )rF   rb   r   reversedpickhighlight_widget)r   xyr%   Zwin_childrenrb   childr   r   r   rU   t  s    zInspector.highlight_atc                 G   s(   || _ |sd| j_| jr$|r$|   d S NrH   )r%   rN   rI   widget_inforW   )r   r%   infolargsr   r   r   rk     s
    
zInspector.highlight_widgetc                 G   sV   | j s
d S | jd kr d| j_d S | jj| j_| j }| jj | krR|| j_d S ro   )r_   r%   rN   rI   Zget_window_matrixrM   matrixget)r   rr   rs   r   r   r   rP     s    

z Inspector.update_widget_graphicsc                 C   s   |j dk}|rnd|_ | jr2tdddd| j ntdddd| j | jjd }| j| | j| nfd|_ | jrt| jddd| j nt| jd ddd	| j | jjd }| j| | j| || _	d S )
NzMove to BottomzMove to Top   out_quad333333?toptd<   rG   rm   rz   r{   )
textrp   r   r   layoutrb   r`   ra   height	at_bottom)r   rQ   Z	to_bottomZ
bottom_barr   r   r   toggle_position  s*    
zInspector.toggle_positionc                 C   s^   d }t |dr|js|S |||rZ|}|||\}}t|jD ]}| |||pV|}qB|S )Nvisible)hasattrr   Zcollide_pointZto_localri   rb   rj   )r   r%   rl   rm   rZ   Zx2y2rn   r   r   r   rj     s    zInspector.pickc                 C   s   |sZd| j _| jr"tdddd}nt| jddd}|j| jd || j d | _	d| _
n| j|  td	 | jrtd
ddd| j nt| jd
 ddd| j | j}|d krt| jd }| _n|  |   d S )NrH   r   rv   rw   rx   r}   )Zon_completeFzInspector: inspector activatedr|   rG   )rN   rI   r   r   r   r!   animation_closer   r   r%   rp   rF   ra   r   rq   _update_widget_tree_evr
   rO   update_widget_tree)r   instancer_   ZanimZevr   r   r   on_activated  s0    
 zInspector.on_activatedc                 C   s   | j sd| _| j|  | j  | j}t| D ]}d |_	|
| q4d | _| jd k	rd| j  | j}t| D ]}|
| qvtd d S )NFz Inspector: inspector deactivated)r_   rT   rF   r`   contentclear_widgetstreeviewlistr4   r   remove_node_window_noder   cancel
widgettreer   rq   )r   r   valuer   r8   r   r   r   r   r     s    


zInspector.animation_closec              	   C   s  | j   | j}| j}t| d d  D ]}d |_|| q*|s| jrbt	dddd
| j nt	| jd ddd
| j d| _d S d| _| jrt	dddd
| j nt	| jddd
| j t| d d  D ]}|| qt|  }|  d }t|tkr|j}n
t|}|D ]Z}t||d	}|j| jd
 z"|jf |t| jt|i W n   Y nX || q(d S )Nr|   rv   rw   rx   r}   FTru   )r&   r   )Zis_selected)r   r   r%   r   r   r4   r   r   r   r   r   r   r   rp   Z
propertieskeyssorttyper   Z__ref__weakrefrefr   r!   show_propertyr   update_node_contentadd_node)r   r%   r   r8   r   Z	wk_widgetr&   r   r   r   rW     sJ    


 zInspector.show_widget_infoc                 G   s"   | }|d krd S d|_ d|_ d S r^   )r(   )r   r8   rr   r   r   r   r     s
    zInspector.update_node_contentc                 G   sv   |d }|dkrJt |dh@ rJt |dddh@ sJ| j | _| jrFd| _dS |dkrr| jrbd	| _dS | jrrd	| _dS d S )
Ne   ZctrlshiftZaltmetaT   F)setr_   rT   )r   rF   Zscancoderr   	modifiersr   r   r   keyboard_shortcut   s"    
zInspector.keyboard_shortcutr   c                 G   s8  |dkrd S d }|d kr>d}|j }|j}||}	t||}nd}|}d }	d }
t|	ts\|rt|ttfkrrd}
n*t|tt	fkrd}
nt|t
tfkrd}
t|	ts|
dkrtjt|pddd}|jt| j|||d n8t|	ts|
dkr"tj|pddd}|jt| j|||d nt|	tsPt|	tsPt|	tsP|
dkrtjd	d d
}|j|dd t|D ]h\}}tjt|d dd}t|tjr|jt| j|dd n|jt| j||||d || qxn2t|	t rjtjd	d d
}|j|dd |	j!D ]N}tj"|||kr0dndt|j#d dd}|jt| j$||d || qnt|	t%rt|tjrtjt|d}|jt| j|d n,t|tj&rtj'|d}ntj(t|d}n@t|	t)r|rdnd}tj"||d}|jt| j*|||d | j+,  |r4| j+| d S )NFTstringnumericr    )r~   	multiline)r~   rG   )colssize_hint_yr   )Zminimum_height,   )r~   r   r   )Z
on_releasedownnormal)r~   stategroupr   r   )Zon_press)Ztexture)r~   r   )-r%   r&   propertygetattrr;   r   r   strintfloattupler   r   r   Z	TextInputr!   r   save_property_numericr   save_property_textr   r   r   Z
GridLayoutsetter	enumerateZButtonreprZWidgetrk   r   ra   r   optionsZToggleButtonuidsave_property_optionr   ZTextureZImageLabelr   save_property_booleanr   r   )r   r   r   r&   indexrr   r   nestedr%   propZdtypeiitemrQ   optionr   r   r   r   r   0  s    
      
  
    
zInspector.show_propertyc                 C   sF   z4|dkr t |jt|||< nt||t |j W n   Y nX d S Nr   )r   r~   r   setattrr   r%   r&   r   r   r   r   r   r   r     s    zInspector.save_property_numericc                 C   s>   z,|dkr|j t|||< nt|||j  W n   Y nX d S r   )r~   r   r   r   r   r   r   r     s    zInspector.save_property_textc                 C   sD   z2|j dk}|dkr$|t|||< nt||| W n   Y nX d S )Nr   r   )r   r   r   r   r   r   r   r     s    
zInspector.save_property_booleanc                 G   s$   zt |||j W n   Y nX d S r   )r   r~   )r   r%   r&   r   rr   r   r   r   r     s    zInspector.save_property_optionc           	   	   C   s   | j }g }i }|jd d  D ]2}z|||j< W n tk
rB   Y nX || q|jD ]R}|| krdqV||kr~||| |}n|t|jj	|j
|d|}|||f qV|S )Nr~   r%   r<   )r   nodesr%   r6   r   rb   r   r)   r3   r"   Z	proxy_refappend)	r   r8   r%   r<   treeZupdate_nodesr   Zcnodern   r   r   r   _update_widget_tree_node  s.    
 z"Inspector._update_widget_tree_nodec                 G   s~   t | dr| js*| jtd| jdd| _| j| j| jdd}|rl|d d  }g }|D ]}|| j| 7 }qVq>| j| j d S )Nr   ZWindowTr   )r<   )	r   r   r   r   r)   rF   r   r=   r%   )r   rC   r   Zntmpr8   r   r   r   r     s    zInspector.update_widget_tree)T)Nr   )F)&r"   r#   r$   r   r%   r   r   r   r   rT   r_   rp   r   r   r   r-   rS   r\   r]   rc   rU   rk   rP   r   rj   r   r   rW   r   r   r   r   r   r   r   r   r   rD   r   r   r2   r   rE   2  s@   
(
Y		

rE   c                 G   s&   t | d|_| j|jj|jjd dS )a  Create an Inspector instance attached to the *ctx* and bound to the
    Window's :meth:`~kivy.core.window.WindowBase.on_keyboard` event for
    capturing the keyboard shortcut.

        :Parameters:
            `win`: A :class:`Window <kivy.core.window.WindowBase>`
                The application Window to bind to.
            `ctx`: A :class:`~kivy.uix.widget.Widget` or subclass
                The Widget to be inspected.

    )rF   rb   Zon_keyboardN)rE   r'   r!   rc   r   )rF   ctxrr   r   r   r   r     s    
r   c                 C   s   t tt| ||_d S r   )r
   Zschedule_oncer   r   ev_late_createrF   r   r   r   r   r     s    
r   c                 C   sL   t |dr|j  |`t |drH| j|jj|jjd | |j |`dS )z:Stop and unload any active Inspectors for the given *ctx*.r   r'   r   N)r   r   r   Zunbindr'   rc   r   r`   r   r   r   r   r     s    



r   ),__doc____all__r   	functoolsr   	itertoolsr   Zkivy.animationr   Zkivy.loggerr   Zkivy.graphics.transformationr	   Z
kivy.clockr
   Z	kivy.langr   Zkivy.factoryr   Zkivy.weakproxyr   Zkivy.propertiesr   r   r   r   r   r   r   r   r   load_stringZ	BoxLayoutZTreeViewNoder   r   r)   ZTreeViewr*   ZFloatLayoutrE   r   r   r   r   r   r   r   <module>   s0   6,
 6   #