
    AHjW                    L   d Z ddlmZ ddlZddlmZmZ ddlZddl	m
Z
 ddlmZmZ ddlmZ ddlmZmZmZmZmZmZ dd	lmZmZ dd
lmZ 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ G d de      Z G d de      Zej@                  jC                  d       G d dee                Z"y)z

This module contains the `Pilot` class used by [App.run_test][textual.app.App.run_test] to programmatically operate an app.

See the guide on how to [test Textual apps](/guide/testing).

    )annotationsN)AnyGeneric)wait_for_idle)App
ReturnType)HeadlessDriver)Click	MouseDown
MouseEvent	MouseMoveMouseUpResize)OffsetSize)Widgetc                Z    | j                   j                  |z   \  }}| ||dd||||||d}|S )zNGet the arguments to pass into mouse messages for the click and hover methods.r   )widgetxydelta_xdelta_ybuttonshiftmetactrlscreen_xscreen_y)regionoffset)	targetr    r   r   r   controlclick_xclick_ymessage_argumentss	            E/root/tools/cai/cai_env/lib/python3.12/site-packages/textual/pilot.py_get_mouse_message_argumentsr'      sN     }}++f4GW     c                      e Zd ZdZy)OutOfBoundszFRaised when the pilot mouse target is outside of the (visible) screen.N__name__
__module____qualname____doc__ r(   r&   r*   r*   2   s    Pr(   r*   c                      e Zd ZdZy)WaitForScreenTimeoutzException raised if messages aren't being processed quickly enough.

    If this occurs, the most likely explanation is some kind of deadlock in the app code.
    Nr+   r0   r(   r&   r2   r2   6   s    r(   r2   T)angularc                     e Zd ZdZddZddZedd       ZddZddZ		 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 ddZ
	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 dd	Z	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 dd
Z	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 d	 	 	 	 	 ddZ	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d dZd!d"dZd#d$dZd%dZd%dZd&dZy)'PilotzPilot object to drive an app.c                    || _         y N_app)selfapps     r&   __init__zPilot.__init__A   s	    	r(   c              #  ,   K   d| j                   f y w)Nr;   r8   r:   s    r&   __rich_repr__zPilot.__rich_repr__D   s     TYYs   c                    | j                   S )z$App: A reference to the application.r8   r>   s    r&   r;   z	Pilot.appG   s     yyr(   c                   K   |r<| j                   j                  |       d{    | j                          d{    yy7 7 w)zOSimulate key-presses.

        Args:
            *keys: Keys to press.
        N)r9   _press_keys_wait_for_screen)r:   keyss     r&   presszPilot.pressL   sA      ))''---''))) -)s   !AAAAAAc                   K   t        ||      }t        | j                  j                  t              r|| j                  j                  _        | j                  j                  t        ||             | j                          d{    y7 w)zResize the terminal to the given dimensions.

        Args:
            width: The new width of the terminal.
            height: The new height of the terminal.
        N)	r   
isinstancer;   _driverr	   _sizepost_messager   pause)r:   widthheightsizes       r&   resize_terminalzPilot.resize_terminalV   sb      E6"dhh&&7%)DHH"fT401jjls   BBBBNc           	        K   	 | j                  t        t        g||d|||       d{   S 7 # t        $ r}|dd}~ww xY ww)a  Simulate a [`MouseDown`][textual.events.MouseDown] event at a specified position.

        The final position for the event is computed based on the selector provided and
        the offset specified and it must be within the visible area of the screen.

        Args:
            widget: A widget or selector used as an origin
                for the event offset. If this is not specified, the offset is interpreted
                relative to the screen. You can use this parameter to try to target a
                specific widget. However, if the widget is currently hidden or obscured by
                another widget, the event may not land on the widget you specified.
            offset: The offset for the event. The offset is relative to the selector / widget
                provided or to the screen, if no selector is provided.
            shift: Simulate the event with the shift key held down.
            meta: Simulate the event with the meta key held down.
            control: Simulate the event with the control key held down.

        Raises:
            OutOfBounds: If the position for the event is outside of the (visible) screen.

        Returns:
            True if no selector was specified or if the event landed on the selected
                widget, False otherwise.
           r   r    r   r   r   r"   N)_post_mouse_eventsr   r   r*   r:   r   r    r   r   r"   errors          r&   
mouse_downzPilot.mouse_downd   sa     @	"00I& 1      	"T!	".   A%0 .0 A0 	A<AAc           	        K   	 | j                  t        t        g||d|||       d{   S 7 # t        $ r}|dd}~ww xY ww)a  Simulate a [`MouseUp`][textual.events.MouseUp] event at a specified position.

        The final position for the event is computed based on the selector provided and
        the offset specified and it must be within the visible area of the screen.

        Args:
            widget: A widget or selector used as an origin
                for the event offset. If this is not specified, the offset is interpreted
                relative to the screen. You can use this parameter to try to target a
                specific widget. However, if the widget is currently hidden or obscured by
                another widget, the event may not land on the widget you specified.
            offset: The offset for the event. The offset is relative to the widget / selector
                provided or to the screen, if no selector is provided.
            shift: Simulate the event with the shift key held down.
            meta: Simulate the event with the meta key held down.
            control: Simulate the event with the control key held down.

        Raises:
            OutOfBounds: If the position for the event is outside of the (visible) screen.

        Returns:
            True if no selector was specified or if the event landed on the selected
                widget, False otherwise.
        rQ   rR   N)rS   r   r   r*   rT   s          r&   mouse_upzPilot.mouse_up   sa     @	"00G$ 1      	"T!	"rW   c           
        K   	 | j                  t        t        t        g||d||||       d{   S 7 # t        $ r}|dd}~ww xY ww)a  Simulate clicking with the mouse at a specified position.

        The final position to be clicked is computed based on the selector provided and
        the offset specified and it must be within the visible area of the screen.

        Implementation note: This method bypasses the normal event processing in `App.on_event`.

        Example:
            The code below runs an app and clicks its only button right in the middle:
            ```py
            async with SingleButtonApp().run_test() as pilot:
                await pilot.click(Button, offset=(8, 1))
            ```

        Args:
            widget: A widget or selector used as an origin
                for the click offset. If this is not specified, the offset is interpreted
                relative to the screen. You can use this parameter to try to click on a
                specific widget. However, if the widget is currently hidden or obscured by
                another widget, the click may not land on the widget you specified.
            offset: The offset to click. The offset is relative to the widget / selector provided
                or to the screen, if no selector is provided.
            shift: Click with the shift key held down.
            meta: Click with the meta key held down.
            control: Click with the control key held down.
            times: The number of times to click. 2 will double-click, 3 will triple-click, etc.

        Raises:
            OutOfBounds: If the position to be clicked is outside of the (visible) screen.

        Returns:
            `True` if no selector was specified or if the selected widget was under the mouse
                when the click was initiated. `False` is the selected widget was not under the pointer.
        rQ   )r   r    r   r   r   r"   timesN)rS   r   r   r
   r*   )r:   r   r    r   r   r"   r[   rU   s           r&   clickzPilot.click   sf     V	"00GU+ 1 	 	 	 	  	"T!	"s0   A
+6 46 A
6 	AAAA
c                L   K   | j                  |||||d       d{   S 7 w)a  Simulate double clicking with the mouse at a specified position.

        Alias for `pilot.click(..., times=2)`.

        The final position to be clicked is computed based on the selector provided and
        the offset specified and it must be within the visible area of the screen.

        Implementation note: This method bypasses the normal event processing in `App.on_event`.

        Example:
            The code below runs an app and double-clicks its only button right in the middle:
            ```py
            async with SingleButtonApp().run_test() as pilot:
                await pilot.double_click(Button, offset=(8, 1))
            ```

        Args:
            widget: A widget or selector used as an origin
                for the click offset. If this is not specified, the offset is interpreted
                relative to the screen. You can use this parameter to try to click on a
                specific widget. However, if the widget is currently hidden or obscured by
                another widget, the click may not land on the widget you specified.
            offset: The offset to click. The offset is relative to the widget / selector provided
                or to the screen, if no selector is provided.
            shift: Click with the shift key held down.
            meta: Click with the meta key held down.
            control: Click with the control key held down.

        Raises:
            OutOfBounds: If the position to be clicked is outside of the (visible) screen.

        Returns:
            `True` if no selector was specified or if the selected widget was under the mouse
                when the click was initiated. `False` is the selected widget was not under the pointer.
           r[   Nr\   r:   r   r    r   r   r"   s         r&   double_clickzPilot.double_click   *     V ZZtWAZNNNN   $"$c                L   K   | j                  |||||d       d{   S 7 w)a  Simulate triple clicking with the mouse at a specified position.

        Alias for `pilot.click(..., times=3)`.

        The final position to be clicked is computed based on the selector provided and
        the offset specified and it must be within the visible area of the screen.

        Implementation note: This method bypasses the normal event processing in `App.on_event`.

        Example:
            The code below runs an app and triple-clicks its only button right in the middle:
            ```py
            async with SingleButtonApp().run_test() as pilot:
                await pilot.triple_click(Button, offset=(8, 1))
            ```

        Args:
            widget: A widget or selector used as an origin
                for the click offset. If this is not specified, the offset is interpreted
                relative to the screen. You can use this parameter to try to click on a
                specific widget. However, if the widget is currently hidden or obscured by
                another widget, the click may not land on the widget you specified.
            offset: The offset to click. The offset is relative to the widget / selector provided
                or to the screen, if no selector is provided.
            shift: Click with the shift key held down.
            meta: Click with the meta key held down.
            control: Click with the control key held down.

        Raises:
            OutOfBounds: If the position to be clicked is outside of the (visible) screen.

        Returns:
            `True` if no selector was specified or if the selected widget was under the mouse
                when the click was initiated. `False` is the selected widget was not under the pointer.
           r_   Nr`   ra   s         r&   triple_clickzPilot.triple_click$  rc   rd   c                   K   | j                          d{    	 | j                  t        g||d       d{   S 7 '7 # t        $ r}|dd}~ww xY ww)a9  Simulate hovering with the mouse cursor at a specified position.

        The final position to be hovered is computed based on the selector provided and
        the offset specified and it must be within the visible area of the screen.

        Args:
            widget: A widget or selector used as an origin
                for the hover offset. If this is not specified, the offset is interpreted
                relative to the screen. You can use this parameter to try to hover a
                specific widget. However, if the widget is currently hidden or obscured by
                another widget, the hover may not land on the widget you specified.
            offset: The offset to hover. The offset is relative to the widget / selector provided
                or to the screen, if no selector is provided.

        Raises:
            OutOfBounds: If the position to be hovered is outside of the (visible) screen.

        Returns:
            True if no selector was specified or if the hover landed on the selected
                widget, False otherwise.
        Nr   )r   )rK   rS   r   r*   )r:   r   r    rU   s       r&   hoverzPilot.hoverQ  s\     8 jjl	"00)ffUV0WWW 	W 	"T!	"s@   A>AA A A A A 	AAAAc	                F  K   | j                   }	|	j                  }
||
}n$t        |t              r|}n|
j	                  |      }t        ||||||      }t        |d   |d         }||
j                  vrt        d      d}t        d|dz         D ]g  }|D ]`  }| j                          d{    |}|t        u ri |d|i}| |	j                  | \  }} |di |}||	_        |
j                  |       b i | j                          d{    |du xs ||u S 7 p7 w)	a  Simulate a series of mouse events to be fired at a given position.

        The final position for the events is computed based on the selector provided and
        the offset specified and it must be within the visible area of the screen.

        This function abstracts away the commonalities of the other mouse event-related
        functions that the pilot exposes.

        Args:
            widget: A widget or selector used as the origin
                for the event's offset. If this is not specified, the offset is interpreted
                relative to the screen. You can use this parameter to try to target a
                specific widget. However, if the widget is currently hidden or obscured by
                another widget, the events may not land on the widget you specified.
            offset: The offset for the events. The offset is relative to the widget / selector
                provided or to the screen, if no selector is provided.
            shift: Simulate the events with the shift key held down.
            meta: Simulate the events with the meta key held down.
            control: Simulate the events with the control key held down.
            times: The number of times to click. 2 will double-click, 3 will triple-click, etc.
        Raises:
            OutOfBounds: If the position for the events is outside of the (visible) screen.

        Returns:
            True if no selector was specified or if the *final* event landed on the
                selected widget, False otherwise.
        N)r   r   r   r"   r   r   z<Target offset is outside of currently-visible screen region.rQ   chainr0   )r;   screenrG   r   	query_oner'   r   r   r*   rangerK   r
   get_widget_atmouse_position_forward_event)r:   eventsr   r    r   r   r   r"   r[   r;   rl   target_widgetr%   	widget_atrk   mouse_event_clskwargs_events                      r&   rS   zPilot._post_mouse_eventss  sg    L hh>"M'"M",,V4M8
 )#.0A#0FG&N  	1eai( 	-E#) -jjl"" +"e+777F$#43#4#4f#=LIq'1&1
 &,"%%e,)-	-. jjl~;m!;;- #* 	s%   B*D!,D-A!D!DD!D!c                  K   	 | j                   j                  }| j                   g|j                  d      }dt	        j
                         d
fd}|D ]  }|j                  |      sdz   rt	        j                  j                               t	        j                  | j                   j                  j                               g}t	        j                  ||t        j                         d{   \  }}|D ]  }	|	j                           t        |      t        |      k(  }
|
rt        d	      dkD  ryy# t        $ r Y yw xY w7 Xw)a  Wait for the current screen and its children to have processed all pending events.

        Args:
            timeout: A timeout in seconds to wait.

        Returns:
            `True` if all events were processed. `False` if an exception occurred,
            meaning that not all events could be processed.

        Raises:
            WaitForScreenTimeout: If the screen and its children didn't finish processing within the timeout.
        FT)	with_selfr   c                 <     dz    dk(  rj                          yy)z@Decrement internal counter, and set an event if it reaches zero.rQ   r   N)set)countcount_zero_events   r&   decrement_counterz1Pilot._wait_for_screen.<locals>.decrement_counter  s&     QJEz $$& r(   rQ   )timeoutreturn_whenNz@Timed out while waiting for widgets to process pending messages.returnNone)r;   rl   	Exceptionwalk_childrenasyncioEvent
call_latercreate_taskwait_exception_eventFIRST_COMPLETEDcancellenr2   )r:   r   rl   childrenr   childwait_forrw   pendingtask	timed_outr}   r~   s              @@r&   rC   zPilot._wait_for_screen  sR    	XX__F HHDv33d3CD"==?	'  	E 12
	  ##$4$9$9$;<##DHH$=$=$B$B$DEH  '||#33  JAw    HW5I*V  qy[  		2s<   EE AE/BE;E<A	E	EEEEc                   K   | j                          d{    |t        d       d{    nt        j                  |       d{    | j                  j
                  j                          y7 \7 I7 -w)zjInsert a pause.

        Args:
            delay: Seconds to pause, or None to wait for cpu idle.
        Nr   )rC   r   r   sleepr;   rl   _on_timer_update)r:   delays     r&   rK   zPilot.pause  s`      ##%%%="""--&&&((* 	&"&s1   A9A3A9A5A9	A7
*A95A97A9c                   K   | j                   j                  j                          d{    | j                  j                  j                          y7 )w)z+Wait for any current animation to complete.N)r9   animatorr   r;   rl   r   r>   s    r&   wait_for_animationzPilot.wait_for_animation  s;     ii  ..000((* 	1s   (AA*Ac                @  K   | j                          d{    | j                  j                  j                          d{    | j                          d{    t	                d{    | j
                  j                  j                          y7 7 U7 ?7 /w)z:Wait for any current and scheduled animations to complete.N)rC   r9   r   wait_until_completer   r;   rl   r   r>   s    r&   wait_for_scheduled_animationsz#Pilot.wait_for_scheduled_animations  sv     ##%%%ii  44666##%%%o((*	 	&6%sE   BB+BBBBB,B-*BBBBc                   K   | j                          d{    t                d{    | j                  j                  |       y7 27 "w)zExit the app with the given result.

        Args:
            result: The app result returned by `run` or `run_async`.
        N)rC   r   r;   exit)r:   results     r&   r   z
Pilot.exit&  s>      ##%%%of 	&s   AA	AA!AA)r;   App[ReturnType]r   r   )r   zrich.repr.Result)r   r   )rD   strr   r   )rL   intrM   r   r   r   )Nr   r   FFF)r   "Widget | type[Widget] | str | Noner    tuple[int, int]r   boolr   r   r"   r   r   r   )Nr   FFFrQ   )r   r   r    r   r   r   r   r   r"   r   r[   r   r   r   )Nr   )r   )Widget | type[Widget] | str | None | Noner    r   r   r   )Nr   r   FFFrQ   )rr   zlist[type[MouseEvent]]r   r   r    r   r   r   r   r   r   r   r"   r   r[   r   r   r   )g      >@)r   floatr   r   r7   )r   zfloat | Noner   r   r   )r   r   r   r   )r,   r-   r.   r/   r<   r?   propertyr;   rE   rO   rV   rY   r\   rb   rg   ri   rS   rC   rK   r   r   r   r0   r(   r&   r5   r5   =   s   '  *  6:"(+"2+"  +" 	+"
 +" +" 
+"^ 6:"(+"2+"  +" 	+"
 +" +" 
+"^ 6:"(7"27"  7" 	7"
 7" 7" 7" 
7"v 6:"(+O2+O  +O 	+O
 +O +O 
+O^ 6:"(+O2+O  +O 	+O
 +O +O 
+O^ =A"( "9 "   " 
	 "J =A"(X<&X< :X<  	X<
 X< X< X< X< X< 
X<t<|++
+r(   r5   )r   r   FFF)r!   r   r    r   r   r   r   r   r   r   r"   r   r   zdict[str, Any])#r/   
__future__r   r   typingr   r   	rich.reprrichtextual._waitr   textual.appr   r   textual.drivers.headless_driverr	   textual.eventsr
   r   r   r   r   r   textual.geometryr   r   textual.widgetr   r'   r   r*   r2   reprautor5   r0   r(   r&   <module>r      s    #    ' ' : S S ) !
 %  	
   4Q) Q9  pGJ p pr(   