U
    Peڰ                     @   s  d Z dZddl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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" 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/m0Z0m1Z1m2Z2m3Z3 G dd de,Z4G dd de Z5G dd de5Z6G dd de5Z7G d d! d!e5Z8G d"d# d#e5Z9G d$d% d%e7Z:G d&d' d'e5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 d0d1 d1eZ@G d2d3 d3eZAG d4d5 d5eAZBG d6d7 d7eAZCG d8d9 d9eAZDG d:d; d;eAZEG d<d= d=e@ZFG d>d? d?e ZGG d@dA dAeZHG dBdC dCe ZIG dDdE dEe$ZJeKdFkrddGlLmMZM G dHdI dIeMZNeN O  dS )Ja  
Settings
========

.. versionadded:: 1.0.7

This module provides a complete and extensible framework for adding a
Settings interface to your application. By default, the interface uses
a :class:`SettingsWithSpinner`, which consists of a
:class:`~kivy.uix.spinner.Spinner` (top) to switch between individual
settings panels (bottom). See :ref:`differentlayouts` for some
alternatives.

.. image:: images/settingswithspinner_kivy.jpg
    :align: center

A :class:`SettingsPanel` represents a group of configurable options. The
:attr:`SettingsPanel.title` property is used by :class:`Settings` when a panel
is added: it determines the name of the sidebar button. SettingsPanel controls
a :class:`~kivy.config.ConfigParser` instance.

The panel can be automatically constructed from a JSON definition file: you
describe the settings you want and corresponding sections/keys in the
ConfigParser instance... and you're done!

Settings are also integrated into the :class:`~kivy.app.App` class. Use
:meth:`Settings.add_kivy_panel` to configure the Kivy core settings in a panel.


.. _settings_json:

Create a panel from JSON
------------------------

To create a panel from a JSON-file, you need two things:

    * a :class:`~kivy.config.ConfigParser` instance with default values
    * a JSON file

.. warning::

    The :class:`kivy.config.ConfigParser` is required. You cannot use the
    default ConfigParser from Python libraries.

You must create and handle the :class:`~kivy.config.ConfigParser`
object. SettingsPanel will read the values from the associated
ConfigParser instance. Make sure you have set default values (using
:attr:`~kivy.config.ConfigParser.setdefaults`) for all the sections/keys
in your JSON file!

The JSON file contains structured information to describe the available
settings. Here is an example::

    [
        {
            "type": "title",
            "title": "Windows"
        },
        {
            "type": "bool",
            "title": "Fullscreen",
            "desc": "Set the window in windowed or fullscreen",
            "section": "graphics",
            "key": "fullscreen"
        }
    ]

Each element in the root list represents a setting that the user can
configure. Only the "type" key is mandatory: an instance of the associated
class will be created and used for the setting - other keys are assigned to
corresponding properties of that class.

    ============== =================================================
    Type           Associated class
    -------------- -------------------------------------------------
    title          :class:`SettingTitle`
    bool           :class:`SettingBoolean`
    numeric        :class:`SettingNumeric`
    options        :class:`SettingOptions`
    string         :class:`SettingString`
    path           :class:`SettingPath`
    color          :class:`SettingColor`
    ============== =================================================

    .. versionadded:: 1.1.0
        Added :attr:`SettingPath` type

    .. versionadded:: 2.1.0
        Added :attr:`SettingColor` type

In the JSON example above, the first element is of type "title". It will create
a new instance of :class:`SettingTitle` and apply the rest of the key-value
pairs to the properties of that class, i.e. "title": "Windows" sets the
:attr:`~SettingsPanel.title` property of the panel to "Windows".

To load the JSON example to a :class:`Settings` instance, use the
:meth:`Settings.add_json_panel` method. It will automatically instantiate a
:class:`SettingsPanel` and add it to :class:`Settings`::

    from kivy.config import ConfigParser

    config = ConfigParser()
    config.read('myconfig.ini')

    s = Settings()
    s.add_json_panel('My custom panel', config, 'settings_custom.json')
    s.add_json_panel('Another panel', config, 'settings_test2.json')

    # then use the s as a widget...


.. _differentlayouts:

Different panel layouts
-----------------------

A kivy :class:`~kivy.app.App` can automatically create and display a
:class:`Settings` instance. See the :attr:`~kivy.app.App.settings_cls`
documentation for details on how to choose which settings class to
display.

Several pre-built settings widgets are available. All except
:class:`SettingsWithNoMenu` include close buttons triggering the
on_close event.

- :class:`Settings`: Displays settings with a sidebar at the left to
  switch between json panels.

- :class:`SettingsWithSidebar`: A trivial subclass of
  :class:`Settings`.

- :class:`SettingsWithSpinner`: Displays settings with a spinner at
  the top, which can be used to switch between json panels. Uses
  :class:`InterfaceWithSpinner` as the
  :attr:`~Settings.interface_cls`. This is the default behavior from
  Kivy 1.8.0.

- :class:`SettingsWithTabbedPanel`: Displays json panels as individual
  tabs in a :class:`~kivy.uix.tabbedpanel.TabbedPanel`. Uses
  :class:`InterfaceWithTabbedPanel` as the :attr:`~Settings.interface_cls`.

- :class:`SettingsWithNoMenu`: Displays a single json panel, with no
  way to switch to other panels and no close button. This makes it
  impossible for the user to exit unless
  :meth:`~kivy.app.App.close_settings` is overridden with a different
  close trigger! Uses :class:`InterfaceWithNoMenu` as the
  :attr:`~Settings.interface_cls`.

You can construct your own settings panels with any layout you choose
by setting :attr:`Settings.interface_cls`. This should be a widget
that displays a json settings panel with some way to switch between
panels. An instance will be automatically created by :class:`Settings`.

Interface widgets may be anything you like, but *must* have a method
add_panel that receives newly created json settings panels for the
interface to display. See the documentation for
:class:`InterfaceWithSidebar` for more information. They may
optionally dispatch an on_close event, for instance if a close button
is clicked. This event is used by :class:`Settings` to trigger its own
on_close event.

For a complete, working example, please see
:file:`kivy/examples/settings/main.py`.

)SettingsSettingsPanelSettingItemSettingStringSettingPathSettingBooleanSettingNumericSettingOptionsSettingTitleSettingsWithSidebarSettingsWithSpinnerSettingsWithTabbedPanelSettingsWithNoMenuInterfaceWithSidebarContentPanelMenuSidebar    N)Factory)dp)ConfigParser)	Animation)string_types	text_type)Window)	BoxLayout)TabbedPanelHeader)Button)FileChooserListView)ColorPicker)
ScrollView)FloatLayout)
GridLayout)Label)Popup)	TextInput)ToggleButton)Widget)ObjectPropertyStringPropertyListPropertyBooleanPropertyNumericPropertyDictPropertyc                   @   s   e Zd ZdS )SettingSpacerN)__name__
__module____qualname__ r0   r0   5/tmp/pip-unpacked-wheel-xzebddm3/kivy/uix/settings.pyr,      s   r,   c                       s   e Zd ZdZe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dZ fd	d
Z fddZ fddZ fddZdd Zdd Z  ZS )r   a  Base class for individual settings (within a panel). This class cannot
    be used directly; it is used for implementing the other setting classes.
    It builds a row with a title/description (left) and a setting control
    (right).

    Look at :class:`SettingBoolean`, :class:`SettingNumeric` and
    :class:`SettingOptions` for usage examples.

    :Events:
        `on_release`
            Fired when the item is touched and then released.

    z<No title set>NTZ	allownoneFr   
on_releasec                    s*   t t| jf | | j| j| j| _d S N)superr   __init__panel	get_valuesectionkeyvalueselfkwargs	__class__r0   r1   r7   %  s    zSettingItem.__init__c                    s*   | j d krtt| j||S | j j||S r5   )contentr6   r   
add_widgetr>   argsr?   r@   r0   r1   rC   )  s    
zSettingItem.add_widgetc                    s:   | j |j sd S | jrd S ||  d| _tt| |S )N   )collide_pointposdisabledZgrabselected_alphar6   r   on_touch_downr>   touchr@   r0   r1   rK   .  s    
zSettingItem.on_touch_downc                    sF   |j | kr6||  | d tdddd|  dS tt| |S )Nr4   r   g      ?Zout_quad)rJ   dtT)Zgrab_currentZungrabdispatchr   startr6   r   on_touch_uprL   r@   r0   r1   rR   7  s    


zSettingItem.on_touch_upc                 C   s   d S r5   r0   r>   r0   r0   r1   r4   ?  s    zSettingItem.on_releasec                 C   s>   | j r| jsd S | j}t|ts(t|}|| j | j| d S r5   )r:   r;   r8   
isinstancer   str	set_value)r>   instancer<   r8   r0   r0   r1   on_valueB  s    
zSettingItem.on_value)r-   r.   r/   __doc__r'   titledescr)   rI   r:   r;   r&   r<   r8   rB   r*   rJ   
__events__r7   rC   rK   rR   r4   rX   __classcell__r0   r0   r@   r1   r      s"   			r   c                   @   s   e Zd ZdZeddgZdS )r   zImplementation of a boolean setting on top of a :class:`SettingItem`.
    It is visualized with a :class:`~kivy.uix.switch.Switch` widget.
    By default, 0 and 1 are used for values: you can change them by setting
    :attr:`values`.
    01N)r-   r.   r/   rY   r(   valuesr0   r0   r0   r1   r   L  s   r   c                   @   sD   e Zd ZdZedddZedZdd Zdd Zd	d
 Z	dd Z
dS )r   a*  Implementation of a string setting on top of a :class:`SettingItem`.
    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when
    clicked, will open a :class:`~kivy.uix.popup.Popup` with a
    :class:`~kivy.uix.textinput.Textinput` so the user can enter a custom
    value.
    NTr2   c                 C   s   |d krd S |  d| j d S Nr4   Zfbind_create_popupr>   rW   r<   r0   r0   r1   on_panelz  s    zSettingString.on_panelc                 G   s(   | j rd| j _| jr| j  d | _d S NF	textinputZfocuspopupdismissr>   largsr0   r0   r1   _dismiss  s
    
zSettingString._dismissc                 C   s   |    | jj }|| _d S r5   )rm   rh   textstripr<   rd   r0   r0   r1   	_validate  s    zSettingString._validatec                 C   s   t ddd}tdtj td}t| j|d|dfd | _}t| j	d	d
d dd | _
}|j| jd || _
|t  || |t  |t  t d ddd}tdd}|j| jd || tdd}|j| jd || || |  d S )Nvertical5dpZorientationspacingffffff?  NNZ250dp)rZ   rB   	size_hintsizeZ24spFZ42sp)rn   Z	font_size	multilinesize_hint_yheight)Zon_text_validate50dpr{   r|   rt   Okrn   r3   Cancel)r   minr   widthr   r"   rZ   ri   r#   r<   rh   bindrp   rC   r%   r,   r   rm   open)r>   rW   rB   popup_widthri   rh   	btnlayoutbtnr0   r0   r1   rc     s<         





zSettingString._create_popup)r-   r.   r/   rY   r&   ri   rh   re   rm   rp   rc   r0   r0   r0   r1   r   c  s   r   c                   @   sT   e Zd ZdZedddZedZedZedZ	dd Z
dd	 Zd
d Zdd ZdS )r   aQ  Implementation of a Path setting on top of a :class:`SettingItem`.
    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when
    clicked, will open a :class:`~kivy.uix.popup.Popup` with a
    :class:`~kivy.uix.filechooser.FileChooserListView` so the user can enter
    a custom value.

    .. versionadded:: 1.1.0
    NTr2   Fc                 C   s   |d krd S |  d| j d S ra   rb   rd   r0   r0   r1   re     s    zSettingPath.on_panelc                 G   s(   | j rd| j _| jr| j  d | _d S rf   rg   rk   r0   r0   r1   rm     s
    
zSettingPath._dismissc                 C   s.   |    | jj}|sd S tj|d | _d S )Nr   )rm   rh   Z	selectionospathrealpathr<   rd   r0   r0   r1   rp     s
    zSettingPath._validatec           	      C   s   t ddd}tdtj td}t| j|d|d | _}| jpDt	
 }t|d| j| jd	 | _}|j| jd
 || |t  t d ddd}tdd}|j| jd || tdd}|j| jd || || |  d S )Nrq      rs   ru   rv   Ng?rZ   rB   rx   r   )rF   rF   )r   rx   	dirselectshow_hidden)Zon_pathr}   rr   r~   r   r   r3   r   )r   r   r   r   r   r"   rZ   ri   r<   r   getcwdr   r   r   rh   r   rp   rC   r,   r   rm   r   )	r>   rW   rB   r   ri   Zinitial_pathrh   r   r   r0   r0   r1   rc     s6        





zSettingPath._create_popup)r-   r.   r/   rY   r&   ri   rh   r)   r   r   re   rm   rp   rc   r0   r0   r0   r1   r     s   	
		r   c                   @   s<   e Zd ZdZedddZdd Zdd Zd	d
 Zdd Z	dS )SettingColorac  Implementation of a color setting on top of a :class:`SettingItem`.
    It is visualized with a :class:`~kivy.uix.label.Label` widget and a
    colored canvas rectangle that, when clicked, will open a
    :class:`~kivy.uix.popup.Popup` with a
    :class:`~kivy.uix.colorpicker.ColorPicker` so the user can choose a color.

    .. versionadded:: 2.0.1
    NTr2   c                 C   s   |d krd S | j | jd d S )Nr3   )r   rc   rd   r0   r0   r1   re   !  s    zSettingColor.on_panelc                 G   s   | j r| j   d | _ d S r5   )ri   rj   rk   r0   r0   r1   rm   &  s    
zSettingColor._dismissc                 C   s    |    t| jj}|| _d S r5   )rm   utilsZget_hex_from_colorcolorpickercolorr<   rd   r0   r0   r1   rp   +  s    zSettingColor._validatec                 C   s   t ddd}tdtj td}t| j|d|d | _}tt	
| jd | _}|j| jd	 || _|| |t  t d d
dd}tdd}|j| jd || tdd}|j| jd || || |  d S )Nrq   rr   rs   ru   rv   r   r   )r   )Zon_colorr}   r~   r   r   r3   r   )r   r   r   r   r   r"   rZ   ri   r   r   Zget_color_from_hexr<   r   r   rp   rC   r,   r   rm   r   )r>   rW   rB   r   ri   r   r   r   r0   r0   r1   rc   0  s.      





zSettingColor._create_popup)
r-   r.   r/   rY   r&   ri   re   rm   rp   rc   r0   r0   r0   r1   r     s   	r   c                   @   s   e Zd ZdZdd ZdS )r   a-  Implementation of a numeric setting on top of a :class:`SettingString`.
    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when
    clicked, will open a :class:`~kivy.uix.popup.Popup` with a
    :class:`~kivy.uix.textinput.Textinput` so the user can enter a custom
    value.
    c                 C   s`   dt | jk}|   z.|r0tt| jj| _ntt| jj| _W n tk
rZ   Y d S X d S )N.)	rU   r<   rm   r   floatrh   rn   int
ValueError)r>   rW   Zis_floatr0   r0   r1   rp   V  s    zSettingNumeric._validateN)r-   r.   r/   rY   rp   r0   r0   r0   r1   r   N  s   r   c                   @   s<   e Zd ZdZeg ZedddZdd Zdd Z	d	d
 Z
dS )r   a  Implementation of an option list on top of a :class:`SettingItem`.
    It is visualized with a :class:`~kivy.uix.label.Label` widget that, when
    clicked, will open a :class:`~kivy.uix.popup.Popup` with a
    list of options from which the user can select.
    NTr2   c                 C   s   |d krd S |  d| j d S ra   rb   rd   r0   r0   r1   re   z  s    zSettingOptions.on_panelc                 C   s   |j | _| j  d S r5   )rn   r<   ri   rj   )r>   rW   r0   r0   r1   _set_option  s    zSettingOptions._set_optionc           	      C   s   t ddd}tdtj td}t|| jd|dfd | _}t| j	td	 td
 |_
|td dd t| j}| j	D ]<}|| jkrdnd}t|||d}|j| jd || qz|t  tdd tdd}|j|jd || |  d S )Nrq   rr   rs   ru   rv   rw   Z400dp)rB   rZ   rx   ry   7      rF   )r{   r|   Zdownnormal)rn   stategroupr3   r   2   )rn   r{   r|   )r   r   r   r   r   r"   rZ   ri   lenoptionsr|   rC   r%   rU   uidr<   r$   r   r   r,   r   rj   r   )	r>   rW   rB   r   ri   r   optionr   r   r0   r0   r1   rc     s*      


zSettingOptions._create_popup)r-   r.   r/   rY   r(   r   r&   ri   re   r   rc   r0   r0   r0   r1   r   d  s   r   c                   @   s   e Zd ZdZejZedZdS )r	   zEA simple title label, used to organize the settings in sections.
    N)	r-   r.   r/   rY   r!   rn   rZ   r&   r8   r0   r0   r0   r1   r	     s   r	   c                       sT   e Zd ZdZedZedddZedZ fddZ	dd	 Z
d
d Zdd Z  ZS )r   zoThis class is used to construct panel settings, for use with a
    :class:`Settings` instance or subclass.
    zDefault titleNTr2   c                    s"   | dd tt| jf | d S )NcolsrF   )
setdefaultr6   r   r7   r=   r@   r0   r1   r7     s    zSettingsPanel.__init__c                 C   s"   |d krd S t |tstdd S )NzPInvalid config object, you must use akivy.config.ConfigParser, not another one !)rT   r   	Exceptionrd   r0   r0   r1   	on_config  s    
zSettingsPanel.on_configc                 C   s   | j }|sdS |||S )a0  Return the value of the section/key from the :attr:`config`
        ConfigParser instance. This function is used by :class:`SettingItem` to
        get the value for a given section/key.

        If you don't want to use a ConfigParser instance, you might want to
        override this function.
        N)configget)r>   r:   r;   r   r0   r0   r1   r9     s    zSettingsPanel.get_valuec                 C   sX   |  ||}||krd S | j}|r8|||| |  | j}|rT|d|||| d S )Non_config_change)r9   r   setwritesettingsrP   )r>   r:   r;   r<   currentr   r   r0   r0   r1   rV     s       zSettingsPanel.set_value)r-   r.   r/   rY   r'   rZ   r&   r   r   r7   r   r9   rV   r]   r0   r0   r@   r1   r     s   r   c                       s@   e Zd ZdZe Ze ZdZ fddZdd Z	dd Z
  ZS )	r   ax  The default Settings interface class. It displays a sidebar menu
    with names of available settings panels, which may be used to switch
    which one is currently displayed.

    See :meth:`~InterfaceWithSidebar.add_panel` for information on the
    method you must implement if creating your own interface.

    This class also dispatches an event 'on_close', which is triggered
    when the sidebar menu's close button is released. If creating your
    own interface widget, it should also dispatch such an event which
    will automatically be caught by :class:`Settings` and used to
    trigger its own 'on_close' event.

    on_closec                    s.   t t j||  jjj fddd d S )Nc                    s
     dS Nr   rP   jrS   r0   r1   <lambda>      z/InterfaceWithSidebar.__init__.<locals>.<lambda>r3   )r6   r   r7   menuclose_buttonr   rD   r@   rS   r1   r7     s    
zInterfaceWithSidebar.__init__c                 C   s"   | j || | j||| dS )a  This method is used by Settings to add new panels for possible
        display. Any replacement for ContentPanel *must* implement
        this method.

        :Parameters:
            `panel`: :class:`SettingsPanel`
                It should be stored and the interface should provide a way to
                switch between panels.
            `name`:
                The name of the panel as a string. It may be used to represent
                the panel but isn't necessarily unique.
            `uid`:
                A unique int identifying the panel. It should be used to
                identify and switch between panels.

        N)r   add_itemrB   	add_panelr>   r8   namer   r0   r0   r1   r   	  s    zInterfaceWithSidebar.add_panelc                 G   s   d S r5   r0   r>   rE   r0   r0   r1   r     s    zInterfaceWithSidebar.on_close)r-   r.   r/   rY   r&   r   rB   r\   r7   r   r   r]   r0   r0   r@   r1   r     s   	r   c                       s@   e Zd ZdZdZe Ze Z fddZdd Z	dd Z
  ZS )	InterfaceWithSpinnera  A settings interface that displays a spinner at the top for
    switching between panels.

    The workings of this class are considered internal and are not
    documented. See :meth:`InterfaceWithSidebar` for
    information on implementing your own interface class.

    r   c                    s.   t t j||  jjj fddd d S )Nc                    s
     dS r   r   r   rS   r0   r1   r   @  r   z/InterfaceWithSpinner.__init__.<locals>.<lambda>r3   )r6   r   r7   r   r   r   rD   r@   rS   r1   r7   =  s    
zInterfaceWithSpinner.__init__c                 C   s"   | j ||| | j|| dS )a{  This method is used by Settings to add new panels for possible
        display. Any replacement for ContentPanel *must* implement
        this method.

        :Parameters:
            `panel`: :class:`SettingsPanel`
                It should be stored and the interface should provide a way to
                switch between panels.
            `name`:
                The name of the panel as a string. It may be used to represent
                the panel but may not be unique.
            `uid`:
                A unique int identifying the panel. It should be used to
                identify and switch between panels.

        N)rB   r   r   r   r   r0   r0   r1   r   B  s    zInterfaceWithSpinner.add_panelc                 G   s   d S r5   r0   r   r0   r0   r1   r   V  s    zInterfaceWithSpinner.on_close)r-   r.   r/   rY   r\   r&   r   rB   r7   r   r   r]   r0   r0   r@   r1   r   !  s   		r   c                       sV   e Zd ZdZei Ze ZedZe	dZ
dd Zdd Z fdd	Zd
d Z  ZS )r   a  A class for displaying settings panels. It displays a single
    settings panel at a time, taking up the full size and shape of the
    ContentPanel. It is used by :class:`InterfaceWithSidebar` and
    :class:`InterfaceWithSpinner` to display settings.

    Nr   c                 C   s   || j |< | js|| _dS )a9  This method is used by Settings to add new panels for possible
        display. Any replacement for ContentPanel *must* implement
        this method.

        :Parameters:
            `panel`: :class:`SettingsPanel`
                It should be stored and displayed when requested.
            `name`:
                The name of the panel as a string. It may be used to represent
                the panel.
            `uid`:
                A unique int identifying the panel. It should be stored and
                used to identify panels when switching.

        N)panelscurrent_uidr   r0   r0   r1   r     s    
zContentPanel.add_panelc                 G   sH   | j }|| jkrD| jdk	r&| | j | j| }| | || _dS dS )aP  The uid of the currently displayed panel. Changing this will
        automatically change the displayed panel.

        :Parameters:
            `uid`:
                A panel uid. It should be used to retrieve and display
                a settings panel that has previously been added with
                :meth:`add_panel`.

        NTF)r   r   current_panelremove_widgetrC   )r>   rE   r   Z	new_panelr0   r0   r1   on_current_uid  s    



zContentPanel.on_current_uidc                    s0   | j d krtt| j|| n| j j|| d S r5   )	containerr6   r   rC   rD   r@   r0   r1   rC     s    
zContentPanel.add_widgetc                 O   s   | j j|| d S r5   )r   r   rD   r0   r0   r1   r     s    zContentPanel.remove_widget)r-   r.   r/   rY   r+   r   r&   r   r   r*   r   r   r   rC   r   r]   r0   r0   r@   r1   r   Z  s   	r   c                       s|   e Zd ZdZedZeeZdZ fddZ	 fddZ
dd	 Zd
d Zdd Zdd ZdddZdddZdd Z  ZS )r   a  Settings UI. Check module documentation for more information on how
    to use this class.

    :Events:
        `on_config_change`: ConfigParser instance, section, key, value
            Fired when the section's key-value pair of a ConfigParser changes.

            .. warning:

                value will be str/unicode type, regardless of the setting
                type (numeric, boolean, etc)
        `on_close`
            Fired by the default panel when the Close button is pressed.

        N)r   r   c                    sx   i | _ tt| j|| |   | dt | dt | dt | dt	 | dt
 | dt | dt d S )Nstringboolnumericr   rZ   r   r   )_typesr6   r   r7   add_interfaceregister_typer   r   r   r   r	   r   r   )r>   rE   Zkargsr@   r0   r1   r7     s    zSettings.__init__c                    s$   | j |j r tt| | dS d S NT)rG   rH   r6   r   rK   rL   r@   r0   r1   rK     s    zSettings.on_touch_downc                 C   s   || j |< dS )zERegister a new type that can be used in the JSON definition.
        N)r   )r>   tpclsr0   r0   r1   r     s    zSettings.register_typec                 G   s   d S r5   r0   r   r0   r0   r1   r     s    zSettings.on_closec                    sJ    j }t|trt|}| }| _ |  jj fddd dS )z(Internal) creates an instance of :attr:`Settings.interface_cls`,
        and sets it to :attr:`~Settings.interface`. When json panels are
        created, they will be added to this interface which will display them
        to the user.
        c                    s
     dS r   r   r   rS   r0   r1   r     r   z(Settings.add_interface.<locals>.<lambda>r   N)interface_clsrT   r   r   r   	interfacerC   r   )r>   r   r   r0   rS   r1   r     s    


zSettings.add_interfacec                 C   s   d S r5   r0   )r>   r   r:   r;   r<   r0   r0   r1   r   	  s    zSettings.on_config_changec                 C   s4   |  ||||}|j}| jdk	r0| j||| dS )a|  Create and add a new :class:`SettingsPanel` using the configuration
        `config` with the JSON definition `filename`. If `filename` is not set,
        then the JSON definition is read from the `data` parameter instead.

        Check the :ref:`settings_json` section in the documentation for more
        information about JSON format and the usage of this function.
        N)create_json_panelr   r   r   )r>   rZ   r   filenamedatar8   r   r0   r0   r1   add_json_panel  s    
zSettings.add_json_panelc              	   C   s   |dkr|dkrt d|dk	rFt|d}t| }W 5 Q R X n
t|}t|tkrdtdt|| |d}|D ]}d|krtd|d }| j	
|}	|	dkrtd|d  |d= i }
| D ]\}}||
t|< q|	f d	|i|
}|| qv|S )
zCreate new :class:`SettingsPanel`.

        .. versionadded:: 1.5.0

        Check the documentation of :meth:`add_json_panel` for more information.
        Nz,You must specify either the filename or datarz The first element must be a list)rZ   r   r   typez*One setting are missing the "type" elementz+No class registered to handle the <%s> typer8   )r   r   jsonloadsreadr   listr   r   r   r   itemsrU   rC   )r>   rZ   r   r   r   fdr8   Zsettingttyper   Zstr_settingsr;   itemrW   r0   r0   r1   r     s6    
zSettings.create_json_panelc                 C   s<   ddl m} ddlm} ddlm} | d|||d dS )a&  Add a panel for configuring Kivy. This panel acts directly on the
        kivy configuration. Feel free to include or exclude it in your
        configuration.

        See :meth:`~kivy.app.App.use_kivy_settings` for information on
        enabling/disabling the automatic kivy panel.

        r   )kivy_data_dir)Config)joinZKivyzsettings_kivy.jsonN)Zkivyr   kivy.configr   os.pathr   r   )r>   r   r   r   r0   r0   r1   add_kivy_panelC  s    	zSettings.add_kivy_panel)NN)NN)r-   r.   r/   rY   r&   r   r   r   r\   r7   rK   r   r   r   r   r   r   r   r]   r0   r0   r@   r1   r     s   	

*r   c                   @   s   e Zd ZdZdS )r
   zA settings widget that displays settings panels with a sidebar to
    switch between them. This is the default behaviour of
    :class:`Settings`, and this widget is a trivial wrapper subclass.

    N)r-   r.   r/   rY   r0   r0   r0   r1   r
   S  s   r
   c                       s    e Zd ZdZ fddZ  ZS )r   zxA settings widget that displays one settings panel at a time with a
    spinner at the top to switch between them.

    c                    s   t | _tt| j|| d S r5   )r   r   r6   r   r7   rD   r@   r0   r1   r7   `  s    zSettingsWithSpinner.__init__r-   r.   r/   rY   r7   r]   r0   r0   r@   r1   r   [  s   r   c                       s,   e Zd ZdZdZ fddZdd Z  ZS )r   zrA settings widget that displays settings panels as pages in a
    :class:`~kivy.uix.tabbedpanel.TabbedPanel`.
    r   c                    s   t | _tt| j|| d S r5   )InterfaceWithTabbedPanelr   r6   r   r7   rD   r@   r0   r1   r7   l  s    z SettingsWithTabbedPanel.__init__c                 G   s   d S r5   r0   r   r0   r0   r1   r   p  s    z SettingsWithTabbedPanel.on_close)r-   r.   r/   rY   r\   r7   r   r]   r0   r0   r@   r1   r   e  s   r   c                       s    e Zd ZdZ fddZ  ZS )r   a   A settings widget that displays a single settings panel with *no*
    Close button. It will not accept more than one Settings panel. It
    is intended for use in programs with few enough settings that a
    full panel switcher is not useful.

    .. warning::

        This Settings panel does *not* provide a Close
        button, and so it is impossible to leave the settings screen
        unless you also add other behaviour or override
        :meth:`~kivy.app.App.display_settings` and
        :meth:`~kivy.app.App.close_settings`.

    c                    s   t | _tt| j|| d S r5   )InterfaceWithNoMenur   r6   r   r7   rD   r@   r0   r1   r7     s    zSettingsWithNoMenu.__init__r   r0   r0   r@   r1   r   t  s   r   c                       s    e Zd ZdZ fddZ  ZS )r   a  The interface widget used by :class:`SettingsWithNoMenu`. It
    stores and displays a single settings panel.

    This widget is considered internal and is not documented. See the
    :class:`ContentPanel` for information on defining your own content
    widget.

    c                    s8   | j d k	r"t| j jdkr"tdtt| j|| d S )Nr   z8ContentNoMenu cannot accept more than one settings panel)r   r   childrenr   r6   r   rC   rD   r@   r0   r1   rC     s
    zInterfaceWithNoMenu.add_widget)r-   r.   r/   rY   rC   r]   r0   r0   r@   r1   r     s   r   c                       s@   e Zd ZdZe Ze ZdZ fddZdd Z	dd Z
  ZS )	r   a'  The content widget used by :class:`SettingsWithTabbedPanel`. It
    stores and displays Settings panels in tabs of a TabbedPanel.

    This widget is considered internal and is not documented. See
    :class:`InterfaceWithSidebar` for information on defining your own
    interface widget.

    r   c                    s,   t t j||  jj fddd d S )Nc                    s
     dS r   r   r   rS   r0   r1   r     r   z3InterfaceWithTabbedPanel.__init__.<locals>.<lambda>r3   )r6   r   r7   r   r   rD   r@   rS   r1   r7     s    z!InterfaceWithTabbedPanel.__init__c                 C   sF   t  }|| | jjs*|| j_|| j_nt||d}| j| d S )N)rn   rB   )r   rC   tabbedpanelZdefault_tab_contentZdefault_tab_textr   )r>   r8   r   r   Z
scrollviewZ	panelitemr0   r0   r1   r     s    

z"InterfaceWithTabbedPanel.add_panelc                 G   s   d S r5   r0   r   r0   r0   r1   r     s    z!InterfaceWithTabbedPanel.on_close)r-   r.   r/   rY   r&   r   r   r\   r7   r   r   r]   r0   r0   r@   r1   r     s   
r   c                   @   sJ   e Zd ZdZedZedZe Ze	i Z
e Ze Zdd Zdd ZdS )MenuSpinnera  The menu class used by :class:`SettingsWithSpinner`. It provides a
    sidebar with an entry for each settings panel.

    This widget is considered internal and is not documented. See
    :class:`MenuSidebar` for information on menus and creating your own menu
    class.

    r   c                 C   sj   | j j}||kr>d}|d| |kr0|d7 }q|d| }|| j|< | j j| | j jsf|| j _d S )N   z {}rF   )spinnerr`   formatpanel_namesappendrn   )r>   r   r   r`   ir0   r0   r1   r     s    

zMenuSpinner.add_itemc                 G   s   | j }| j| | _d S r5   )spinner_textr   selected_uid)r>   rE   rn   r0   r0   r1   on_spinner_text  s    zMenuSpinner.on_spinner_textN)r-   r.   r/   rY   r*   r   r&   r   r   r+   r   r'   r   r   r   r0   r0   r0   r1   r     s   r   c                   @   s8   e Zd ZdZedZedZedZdd Z	dd Z
dS )r   zThe menu used by :class:`InterfaceWithSidebar`. It provides a
    sidebar with an entry for each settings panel, which the user may
    click to select.

    r   Nc                 C   s>   t ||| d}t| jjdkr$d|_| jdk	r:| j| dS )a  This method is used to add new panels to the menu.

        :Parameters:
            `name`:
                The name (a string) of the panel. It should be used
                to represent the panel in the menu.
            `uid`:
                The name (an int) of the panel. It should be used internally
                to represent the panel and used to set self.selected_uid when
                the panel is changed.

        )rn   r   r   r   TN)SettingSidebarLabelr   buttons_layoutr   selectedrC   )r>   r   r   labelr0   r0   r1   r     s
    
zMenuSidebar.add_itemc                 G   s$   | j jD ]}|j| jkrd|_qdS )zt(internal) unselects any currently selected menu buttons, unless
        they represent the current panel.

        FN)r   r   r   r   r   )r>   rE   buttonr0   r0   r1   on_selected_uid  s    zMenuSidebar.on_selected_uid)r-   r.   r/   rY   r*   r   r&   r   r   r   r   r0   r0   r0   r1   r     s   
	r   c                   @   s,   e Zd ZedZedZedZdd Z	dS )r   Fr   Nc                 C   s$   | j |j sd S d| _| j| j_d S r   )rG   rH   r   r   r   r   rL   r0   r0   r1   rK     s    z!SettingSidebarLabel.on_touch_down)
r-   r.   r/   r)   r   r*   r   r&   r   rK   r0   r0   r0   r1   r     s   r   __main__)Appc                   @   s4   e Zd ZeddddddgZdd Zd	d
 ZdS )SettingsAppr   z
Test colorzYour chosen Colorcolorselection	testcolor)r   rZ   r[   r:   r;   c                 C   s4   t  }|  |jd| j| jd |j| jd |S )NzColor settings)r   r   )r   r   r   r   demo_json_settingsr   stop)r>   sr0   r0   r1   build3  s    zSettingsApp.buildc                 C   s   | dddi d S )Nr   r   z#FF0000)Zsetdefaults)r>   r   r0   r0   r1   build_config<  s    zSettingsApp.build_configN)r-   r.   r/   r   dumpsr   r  r  r0   r0   r0   r1   r   )  s   		r   )PrY   __all__r   r   Z
kivy.utilsr   Zkivy.factoryr   Zkivy.metricsr   r   r   Zkivy.animationr   Zkivy.compatr   r   Zkivy.core.windowr   Zkivy.uix.boxlayoutr   Zkivy.uix.tabbedpanelr   Zkivy.uix.buttonr   Zkivy.uix.filechooserr   Zkivy.uix.colorpickerr   Zkivy.uix.scrollviewr   Zkivy.uix.floatlayoutr   Zkivy.uix.gridlayoutr    Zkivy.uix.labelr!   Zkivy.uix.popupr"   Zkivy.uix.textinputr#   Zkivy.uix.togglebuttonr$   Zkivy.uix.widgetr%   Zkivy.propertiesr&   r'   r(   r)   r*   r+   r,   r   r   r   r   r   r   r   r	   r   r   r   r   r   r
   r   r   r   r   r   r   r   r   r-   Zkivy.appr   r   runr0   r0   r0   r1   <module>   sl    '  Kb>;	:?9\ 
 !@
