o
    o_U                     @   s0  d dl mZmZ d dlmZmZmZmZmZ d dl	m
Z
 d dlmZ d dlmZ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 G dd deZG dd deZG dd deZG dd deZG dd deZ G dd dedeZ!G dd deZ"dd Z#e$dkre#  dS dS )    )divisionprint_function)Text
WidgetWrapdelegate_to_widget_mixinBOXFLOW)CompositeCanvas)connect_signal)ColumnsOverlay)is_mouse_press)calc_coords)disconnect_signal)python3_repr)WidgetDecoration)ACTIVATEc                   @   s8   e Zd ZdZdZdddZdddZdd	 Zd
d ZdS )SelectableIconFTr   c                 C   s   | j | || _dS )a  
        :param text: markup for this widget; see :class:`Text` for
                     description of text markup
        :param cursor_position: position the cursor will appear in the
                                text when this widget is in focus

        This is a text widget that is selectable.  A cursor
        displayed at a fixed location in the text when in focus.
        This widget has no special handling of keyboard or mouse input.
        N)_SelectableIcon__super__init___cursor_position)selftextcursor_position r   ,/usr/lib/python3/dist-packages/urwid/wimp.pyr   '   s   
zSelectableIcon.__init__c                 C   s*   | j ||}|rt|}| ||_|S )a  
        Render the text content of this widget with a cursor when
        in focus.

        >>> si = SelectableIcon(u"[!]")
        >>> si
        <SelectableIcon selectable flow widget '[!]'>
        >>> si.render((4,), focus=True).cursor
        (0, 0)
        >>> si = SelectableIcon("((*))", 2)
        >>> si.render((8,), focus=True).cursor
        (2, 0)
        >>> si.render((2,), focus=True).cursor
        (0, 1)
        )r   renderr	   get_cursor_coordscursor)r   sizefocuscr   r   r   r   5   s
   zSelectableIcon.renderc                 C   sL   | j t| jkr
dS |\}| |}t| j|| j \}}||kr"dS ||fS )z
        Return the position of the cursor if visible.  This method
        is required for widgets that display a cursor.
        N)r   lenr   get_line_translationr   )r   r   maxcoltransxyr   r   r   r   L   s   
z SelectableIcon.get_cursor_coordsc                 C   s   |S )zn
        No keys are handled by this widget.  This method is
        required for selectable widgets.
        r   r   r   keyr   r   r   keypress\   s   zSelectableIcon.keypressN)r   F)	__name__
__module____qualname__ignore_focus_selectabler   r   r   r*   r   r   r   r   r   $   s    

r   c                   @   s   e Zd ZdS )CheckBoxErrorN)r,   r-   r.   r   r   r   r   r1   c   s    r1   c                   @   s   e Zd Zdd ZeddeddedddZdZd	d
gZ		d"ddZdd Z	dd Z
dd Zdd ZeeZd#ddZdd ZeeeZdd Zdd Zd d! ZdS )$CheckBoxc                 C   
   t tgS N	frozensetr   r   r   r   r   sizingg      
zCheckBox.sizingz[X]   z[ ]z[#]TFmixed   change
postchangeFNc                 C   sd   | j d td| _|| _d| _|rtd| d| jd< |r&t| d|| | 	| | 
| dS )a  
        :param label: markup for check box label
        :param state: False, True or "mixed"
        :param has_mixed: True if "mixed" is a state to cycle through
        :param on_state_change: shorthand for connect_signal()
                                function call for a single callback
        :param user_data: user_data for on_state_change

        Signals supported: ``'change'``, ``"postchange"``

        Register signal handler with::

          urwid.connect_signal(check_box, 'change', callback, user_data)

        where callback is callback(check_box, new_state [,user_data])
        Unregister signal handlers with::

          urwid.disconnect_signal(check_box, 'change', callback, user_data)

        >>> CheckBox(u"Confirm")
        <CheckBox selectable flow widget 'Confirm' state=False>
        >>> CheckBox(u"Yogourt", "mixed", True)
        <CheckBox selectable flow widget 'Yogourt' state='mixed'>
        >>> cb = CheckBox(u"Extra onions", True)
        >>> cb
        <CheckBox selectable flow widget 'Extra onions' state=True>
        >>> cb.render((20,), focus=True).text # ... = b in Python 3
        [...'[X] Extra onions    ']
        N z[%s]r:   Tr>   )_CheckBox__superr   r   _label	has_mixed_stater   statesr
   	set_label	set_state)r   labelstaterC   on_state_change	user_datachecked_symbolr   r   r   r   u   s   

zCheckBox.__init__c                 C      | j  t| jg S r4   )rA   _repr_wordsr   rH   r7   r   r   r   rN      s   zCheckBox._repr_wordsc                 C   s   t | j | jdS )N)rI   )dictrA   _repr_attrsrI   r7   r   r   r   rP      s   
zCheckBox._repr_attrsc                 C      | j | dS )au  
        Change the check box label.

        label -- markup for label.  See Text widget for description
        of text markup.

        >>> cb = CheckBox(u"foo")
        >>> cb
        <CheckBox selectable flow widget 'foo' state=False>
        >>> cb.set_label(('bright_attr', u"bar"))
        >>> cb
        <CheckBox selectable flow widget 'bar' state=False>
        NrB   set_textr   rH   r   r   r   rF      s   zCheckBox.set_labelc                 C      | j jS )a>  
        Return label text.

        >>> cb = CheckBox(u"Seriously")
        >>> print(cb.get_label())
        Seriously
        >>> print(cb.label)
        Seriously
        >>> cb.set_label([('bright_attr', u"flashy"), u" normal"])
        >>> print(cb.label)  #  only text is returned
        flashy normal
        rB   r   r7   r   r   r   	get_label   s   zCheckBox.get_labelTc                 C   s   | j |krdS || jvrtdt| t|f | j }|r'|dur'| d| || _ td| j| j| f| jg| _d| j_	|rK|durM| d| dS dS dS )a  
        Set the CheckBox state.

        state -- True, False or "mixed"
        do_callback -- False to suppress signal from this change

        >>> changes = []
        >>> def callback_a(cb, state, user_data):
        ...     changes.append("A %r %r" % (state, user_data))
        >>> def callback_b(cb, state):
        ...     changes.append("B %r" % state)
        >>> cb = CheckBox('test', False, False)
        >>> key1 = connect_signal(cb, 'change', callback_a, "user_a")
        >>> key2 = connect_signal(cb, 'change', callback_b)
        >>> cb.set_state(True) # both callbacks will be triggered
        >>> cb.state
        True
        >>> disconnect_signal(cb, 'change', callback_a, "user_a")
        >>> cb.state = False
        >>> cb.state
        False
        >>> cb.set_state(True)
        >>> cb.state
        True
        >>> cb.set_state(False, False) # don't send signal
        >>> changes
        ["A True 'user_a'", 'B True', 'B False', 'B True']
        Nz%s Invalid state: %sr>   fixedr   r?   )
rD   rE   r1   repr_emitr   reserve_columnsrB   _w	focus_col)r   rI   do_callback	old_stater   r   r   rG      s$   

zCheckBox.set_statec                 C   s   | j S )z!Return the state of the checkbox.)rD   r7   r   r   r   	get_state   s   zCheckBox.get_statec                 C   s   | j | tkr	|S |   dS )a  
        Toggle state on 'activate' command.

        >>> assert CheckBox._command_map[' '] == 'activate'
        >>> assert CheckBox._command_map['enter'] == 'activate'
        >>> size = (10,)
        >>> cb = CheckBox('press me')
        >>> cb.state
        False
        >>> cb.keypress(size, ' ')
        >>> cb.state
        True
        >>> cb.keypress(size, ' ')
        >>> cb.state
        False
        N)_command_mapr   toggle_stater(   r   r   r   r*     s   zCheckBox.keypressc                 C   s`   | j dkr| d dS | j dkr"| jr| d dS | d dS | j dkr.| d dS dS )aM  
        Cycle to the next valid state.

        >>> cb = CheckBox("3-state", has_mixed=True)
        >>> cb.state
        False
        >>> cb.toggle_state()
        >>> cb.state
        True
        >>> cb.toggle_state()
        >>> cb.state
        'mixed'
        >>> cb.toggle_state()
        >>> cb.state
        False
        FTr<   N)rI   rG   rC   r7   r   r   r   rb     s   


zCheckBox.toggle_statec                 C   s    |dkst |s
dS |   dS )a  
        Toggle state on button 1 press.

        >>> size = (20,)
        >>> cb = CheckBox("clickme")
        >>> cb.state
        False
        >>> cb.mouse_event(size, 'mouse press', 1, 2, 0, True)
        True
        >>> cb.state
        True
        r:   FT)r   rb   r   r   eventbuttonr&   r'   r    r   r   r   mouse_event3  s   zCheckBox.mouse_event)FFNNNT)r,   r-   r.   r8   r   rE   r[   signalsr   rN   rP   rF   rW   propertyrH   rG   r`   rI   r*   rb   rf   r   r   r   r   r2   f   s,    
,
2
r2   c                   @   sN   e Zd ZeddeddedddZdZ		dd	d
ZdddZdd ZdS )RadioButtonz(X)r:   z( )z(#)r;   r=   
first TrueNc                 C   s6   |dkr| }|| _ | j||d|| ||  dS )a  
        :param group: list for radio buttons in same group
        :param label: markup for radio button label
        :param state: False, True, "mixed" or "first True"
        :param on_state_change: shorthand for connect_signal()
                                function call for a single 'change' callback
        :param user_data: user_data for on_state_change

        This function will append the new radio button to group.
        "first True" will set to True if group is empty.

        Signals supported: ``'change'``, ``"postchange"``

        Register signal handler with::

          urwid.connect_signal(radio_button, 'change', callback, user_data)

        where callback is callback(radio_button, new_state [,user_data])
        Unregister signal handlers with::

          urwid.disconnect_signal(radio_button, 'change', callback, user_data)

        >>> bgroup = [] # button group
        >>> b1 = RadioButton(bgroup, u"Agree")
        >>> b2 = RadioButton(bgroup, u"Disagree")
        >>> len(bgroup)
        2
        >>> b1
        <RadioButton selectable flow widget 'Agree' state=True>
        >>> b2
        <RadioButton selectable flow widget 'Disagree' state=False>
        >>> b2.render((15,), focus=True).text # ... = b in Python 3
        [...'( ) Disagree   ']
        rk   FN)group_RadioButton__superr   append)r   rl   rH   rI   rJ   rK   r   r   r   r   M  s   $zRadioButton.__init__Tc                 C   sR   | j |krdS | j|| |durdS | jD ]}|| u rq|j r&|d qdS )a  
        Set the RadioButton state.

        state -- True, False or "mixed"

        do_callback -- False to suppress signal from this change

        If state is True all other radio buttons in the same button
        group will be set to False.

        >>> bgroup = [] # button group
        >>> b1 = RadioButton(bgroup, u"Agree")
        >>> b2 = RadioButton(bgroup, u"Disagree")
        >>> b3 = RadioButton(bgroup, u"Unsure")
        >>> b1.state, b2.state, b3.state
        (True, False, False)
        >>> b2.set_state(True)
        >>> b1.state, b2.state, b3.state
        (False, True, False)
        >>> def relabel_button(radio_button, new_state):
        ...     radio_button.set_label(u"Think Harder!")
        >>> key = connect_signal(b3, 'change', relabel_button)
        >>> b3
        <RadioButton selectable flow widget 'Unsure' state=False>
        >>> b3.set_state(True) # this will trigger the callback
        >>> b3
        <RadioButton selectable flow widget 'Think Harder!' state=True>
        NTF)rD   rm   rG   rl   )r   rI   r^   cbr   r   r   rG   {  s   



zRadioButton.set_statec                 C   s   |  d dS )a  
        Set state to True.

        >>> bgroup = [] # button group
        >>> b1 = RadioButton(bgroup, "Agree")
        >>> b2 = RadioButton(bgroup, "Disagree")
        >>> b1.state, b2.state
        (True, False)
        >>> b2.toggle_state()
        >>> b1.state, b2.state
        (False, True)
        >>> b2.toggle_state()
        >>> b1.state, b2.state
        (False, True)
        TN)rG   r7   r   r   r   rb     s   zRadioButton.toggle_state)rk   NNrg   )	r,   r-   r.   r   rE   r[   r   rG   rb   r   r   r   r   rj   F  s    

..rj   c                   @   sd   e Zd Zdd ZedZedZdgZdddZd	d
 Z	dd Z
dd ZeeZdd Zdd ZdS )Buttonc                 C   r3   r4   r5   r7   r   r   r   r8     r9   zButton.sizing<>clickNc                 C   s\   t dd| _tdd| jf| jdd| jfgdd}| j| |r't| d|| | | dS )a  
        :param label: markup for button label
        :param on_press: shorthand for connect_signal()
                         function call for a single callback
        :param user_data: user_data for on_press

        Signals supported: ``'click'``

        Register signal handler with::

          urwid.connect_signal(button, 'click', callback, user_data)

        where callback is callback(button [,user_data])
        Unregister signal handlers with::

          urwid.disconnect_signal(button, 'click', callback, user_data)

        >>> Button(u"Ok")
        <Button selectable flow widget 'Ok'>
        >>> b = Button("Cancel")
        >>> b.render((15,), focus=True).text # ... = b in Python 3
        [...'< Cancel      >']
        r@   r   rX   r:   )dividecharsrs   N)	r   rB   r   button_leftbutton_right_Button__superr   r
   rF   )r   rH   on_pressrK   colsr   r   r   r     s   

zButton.__init__c                 C   rM   r4   )rw   rN   r   rH   r7   r   r   r   rN     s   zButton._repr_wordsc                 C   rQ   )z
        Change the button label.

        label -- markup for button label

        >>> b = Button("Ok")
        >>> b.set_label(u"Yup yup")
        >>> b
        <Button selectable flow widget 'Yup yup'>
        NrR   rT   r   r   r   rF     s   zButton.set_labelc                 C   rU   )z
        Return label text.

        >>> b = Button(u"Ok")
        >>> print(b.get_label())
        Ok
        >>> print(b.label)
        Ok
        rV   r7   r   r   r   rW     s   
zButton.get_labelc                 C   s    | j | tkr	|S | d dS )aD  
        Send 'click' signal on 'activate' command.

        >>> assert Button._command_map[' '] == 'activate'
        >>> assert Button._command_map['enter'] == 'activate'
        >>> size = (15,)
        >>> b = Button(u"Cancel")
        >>> clicked_buttons = []
        >>> def handle_click(button):
        ...     clicked_buttons.append(button.label)
        >>> key = connect_signal(b, 'click', handle_click)
        >>> b.keypress(size, 'enter')
        >>> b.keypress(size, ' ')
        >>> clicked_buttons # ... = u in Python 2
        [...'Cancel', ...'Cancel']
        rs   N)ra   r   rZ   r(   r   r   r   r*     s   zButton.keypressc                 C   s"   |dkst |s
dS | d dS )a  
        Send 'click' signal on button 1 press.

        >>> size = (15,)
        >>> b = Button(u"Ok")
        >>> clicked_buttons = []
        >>> def handle_click(button):
        ...     clicked_buttons.append(button.label)
        >>> key = connect_signal(b, 'click', handle_click)
        >>> b.mouse_event(size, 'mouse press', 1, 4, 0, True)
        True
        >>> b.mouse_event(size, 'mouse press', 2, 4, 0, True) # ignored
        False
        >>> clicked_buttons # ... = u in Python 2
        [...'Ok']
        r:   Frs   T)r   rZ   rc   r   r   r   rf   !  s   
zButton.mouse_event)NN)r,   r-   r.   r8   r   ru   rv   rh   r   rN   rF   rW   ri   rH   r*   rf   r   r   r   r   rp     s    
'rp   c                   @   s>   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdddZdS )PopUpLauncherc                 C   s   | j | d | _d S r4   )_PopUpLauncher__superr   _pop_up_widgetr   original_widgetr   r   r   r   ;  s   
zPopUpLauncher.__init__c                 C      t d)z
        Subclass must override this method and return a widget
        to be used for the pop-up.  This method is called once each time
        the pop-up is opened.
        "Subclass must override this methodNotImplementedErrorr7   r   r   r   create_pop_up?  s   zPopUpLauncher.create_pop_upc                 C   r   )z
        Subclass must override this method and have it return a dict, eg:

        {'left':0, 'top':1, 'overlay_width':30, 'overlay_height':4}

        This method is called each time this widget is rendered.
        r   r   r7   r   r   r   get_pop_up_parametersG  s   z#PopUpLauncher.get_pop_up_parametersc                 C   s   |   | _|   d S r4   )r   r|   _invalidater7   r   r   r   open_pop_upQ  s   
zPopUpLauncher.open_pop_upc                 C   s   d | _ |   d S r4   )r|   r   r7   r   r   r   close_pop_upU  s   zPopUpLauncher.close_pop_upFc                 C   s8   | j ||}| jrt|}|j| jfi |   |S r4   )r{   r   r|   r	   
set_pop_upr   )r   r   r    canvr   r   r   r   Y  s
   zPopUpLauncher.renderNr+   )	r,   r-   r.   r   r   r   r   r   r   r   r   r   r   rz   9  s    
rz   _original_widgetc                   @   sf   e Zd ZeegZdZdd Zdd ZdddZ	d	d
 Z
dd Zdd Zdd Zdd ZdddZdS )PopUpTargetTc                 C   s   | j | d | _| j| _d S r4   )_PopUpTarget__superr   _pop_upr   _current_widgetr}   r   r   r   r   g  s   zPopUpTarget.__init__c           
      C   s   | j j||d}|| _| }|rA|\}}\}}}	| j|kr2|| _t|| j d|f|d|f|	| _d S | jd|f|d|f|	 d S d | _| j | _d S )Nr    z
fixed leftz	fixed top)r   r   _cache_original_canvas
get_pop_upr   r   r   set_overlay_parameters)
r   r   r    r   pop_uplefttopwoverlay_widthoverlay_heightr   r   r   _update_overlayl  s&   

zPopUpTarget._update_overlayFc                 C   s   |  || | jj||dS )Nr   )r   r   r   r   r   r    r   r   r   r        zPopUpTarget.renderc                 C      |  |d | j|S NT)r   r   r   r   r   r   r   r   r        zPopUpTarget.get_cursor_coordsc                 C   r   r   )r   r   get_pref_colr   r   r   r   r     r   zPopUpTarget.get_pref_colc                 C   s   |  |d | j||S r   )r   r   r*   r(   r   r   r   r*     s   zPopUpTarget.keypressc                 C   s   |  |d | j|||S r   )r   r   move_cursor_to_coords)r   r   r&   r'   r   r   r   r     r   z!PopUpTarget.move_cursor_to_coordsc                 C   s"   |  || | j||||||S r4   )r   r   rf   rc   r   r   r   rf     s   zPopUpTarget.mouse_eventNc                 C   s   |  || | j|S r4   )r   r   packr   r   r   r   r     r   zPopUpTarget.packr+   )NF)r,   r-   r.   setr   _sizingr0   r   r   r   r   r   r*   r   rf   r   r   r   r   r   r   a  s    

r   c                  C   s   dd l } |   d S )Nr   )doctesttestmod)r   r   r   r   _test  s   r   __main__N)%
__future__r   r   urwid.widgetr   r   r   r   r   urwid.canvasr	   urwid.signalsr
   urwid.containerr   r   
urwid.utilr   urwid.text_layoutr   r   urwid.split_reprr   urwid.decorationr   urwid.command_mapr   r   	Exceptionr1   r2   rj   rp   rz   r   r   r,   r   r   r   r   <module>   s2   ? av}(:
