# Source code for enaml.widgets.field

    #------------------------------------------------------------------------------
    # Copyright (c) 2013-2025, Nucleic Development Team.
    #
    # Distributed under the terms of the Modified BSD License.
    #
    # The full license is in the file LICENSE, distributed with this software.
    #------------------------------------------------------------------------------
    from atom.api import (
        Bool, Int, Str, Enum, List, Typed, ForwardTyped, set_default
    )

    from enaml.core.declarative import d_, observe
    from enaml.validator import Validator

    from .control import Control, ProxyControl

    class ProxyField(ProxyControl):
        """ The abstract definition of a proxy Field object.

        """
        #: A reference to the Field declaration.
        declaration = ForwardTyped(lambda: Field)

        def set_text(self, text):
            raise NotImplementedError

        def set_mask(self, mask):
            raise NotImplementedError

        def set_submit_triggers(self, triggers):
            raise NotImplementedError

        def set_sync_time(self, time):
            raise NotImplementedError

        def set_placeholder(self, placeholder):
            raise NotImplementedError

        def set_echo_mode(self, mode):
            raise NotImplementedError

        def set_max_length(self, length):
            raise NotImplementedError

        def set_read_only(self, read_only):
            raise NotImplementedError

        def set_text_align(self, text_align):
            raise NotImplementedError

        def field_text(self):
            raise NotImplementedError

    class Field(Control):
        """ A single line editable text widget.

        """
        #: The unicode text to display in the field.
        text = d_(Str())

        #: The mask to use for text input
        #: http://qt-project.org/doc/qt-4.8/qlineedit.html#inputMask-prop
        #:
        #: The summary of the mask grammar is as follows:
        #: A   ASCII alphabetic character required. A-Z, a-z.
        #: a   ASCII alphabetic character permitted but not required.
        #: N   ASCII alphanumeric character required. A-Z, a-z, 0-9.
        #: n   ASCII alphanumeric character permitted but not required.
        #: X   Any character required.
        #: x   Any character permitted but not required.
        #: 9   ASCII digit required. 0-9.
        #: 0   ASCII digit permitted but not required.
        #: D   ASCII digit required. 1-9.
        #: d   ASCII digit permitted but not required (1-9).
        #: #   ASCII digit or plus/minus sign permitted but not required.
        #: H   Hexadecimal character required. A-F, a-f, 0-9.
        #: h   Hexadecimal character permitted but not required.
        #: B   Binary character required. 0-1.
        #: b   Binary character permitted but not required.
        #: >   All following alphabetic characters are uppercased.
        #: <   All following alphabetic characters are lowercased.
        #: !   Switch off case conversion.
        #: \   Use \ to escape the special characters listed above to use them as separators.
        #:
        #: The mask consists of a string of mask characters and separators, optionally
        #: followed by a semicolon and the character used for blanks
        #: Eg: 9 digit phone number: (999) 999-9999;_
        mask = d_(Str())

        #: The validator to use for this field. If the validator provides
        #: a client side validator, then text will only be submitted if it
        #: passes that validator.
        validator = d_(Typed(Validator))

        #: The list of actions which should cause the client to submit its
        #: text to the server for validation and update. The currently
        #: supported values are 'lost_focus', 'return_pressed', and 'auto_sync'.
        #: The 'auto_sync' mode will attempt to validate and synchronize the
        #: text when the user stops typing.
        submit_triggers = d_(List(
            Enum('lost_focus', 'return_pressed', 'auto_sync'),
            ['lost_focus', 'return_pressed']
        ))

        #: Time in ms after which the client submit its text to the server for
        #: validation and update when the user stop typing. This is used only when
        #: the 'auto_sync' mode is part of the submit_triggers.
        sync_time = d_(Int(300))

        #: The grayed-out text to display if the field is empty and the
        #: widget doesn't have focus. Defaults to the empty string.
        placeholder = d_(Str())

        #: How to display the text in the field. Valid values are 'normal'
        #: which displays the text as normal, 'password' which displays the
        #: text with an obscured character, and 'silent' which displays no
        #: text at all but still allows input.
        echo_mode = d_(Enum('normal', 'password', 'silent'))

        #: The maximum length of the field in characters. The default value
        #: is Zero and indicates there is no maximum length.
        max_length = d_(Int(0))

        #: Whether or not the field is read only. Defaults to False.
        read_only = d_(Bool(False))

        #: Alignment for the text inside the field. Defaults to 'left'.
        text_align = d_(Enum('left', 'right', 'center'))

        #: How strongly a component hugs it's contents' width. Fields ignore
        #: the width hug by default, so they expand freely in width.
        hug_width = set_default('ignore')

        #: A reference to the ProxyField object.
        proxy = Typed(ProxyField)

        #--------------------------------------------------------------------------
        # Observers
        #--------------------------------------------------------------------------
        @observe('text', 'mask', 'submit_triggers', 'placeholder', 'echo_mode',
            'max_length', 'read_only', 'text_align', 'sync_time')
        def _update_proxy(self, change):
            """ An observer which sends state change to the proxy.

            """
            # The superclass implementation is sufficient.
            super(Field, self)._update_proxy(change)

        #--------------------------------------------------------------------------
        # Public API
        #--------------------------------------------------------------------------

        def field_text(self):
            """ Get the text stored in the field control.

            Depending on the state of the field, this text may be different
            than that stored in the 'text' attribute.

            Returns
            -------
            result : unicode
                The unicode text stored in the field.

            """
            if self.proxy_is_active:
                return self.proxy.field_text()
            return ''