# Source code for enaml.core.declarative

    #------------------------------------------------------------------------------
    # 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 ChangeType, Event, Typed, Str, observe as default_observe
    from atom.datastructures.api import sortedmap

    from .declarative_meta import DeclarativeMeta
    from .expression_engine import ExpressionEngine
    from .object import Object, flag_generator, flag_property

    #: Declarative observe ignores create events
    OBSERVE_CHANGE_TYPES = ChangeType.ANY & ~ChangeType.CREATE

    def observe(*names, change_types=OBSERVE_CHANGE_TYPES):
        """ An observe decorator which ignores the created event by default.

        Parameters
        ----------
        *names
            The str names of the attributes to observe on the object.
            These must be of the form 'foo' or 'foo.bar'.
        change_types
            The flag specifying the type of changes to observe.

        """
        return default_observe(*names, change_types=change_types)

    def d_(member, readable=True, writable=True, final=True):
        """ Mark an Atom member as bindable from Enaml syntax.

        Parameters
        ----------
        member : Member
            The atom member to mark as bindable from Enaml syntax.

        readable : bool, optional
            Whether the member is readable from Enaml syntax. The member
            must be readable to use the '>>', ':=', and '::' operators.
            The default is True.

        writable : bool, optional
            Whether the member is writable from Enaml syntax. The member
            must be writable to use the '=', '<<', and ':=' operators.
            The default is True.

        final : bool, optional
            Whether or not the member can be redefined from Enaml syntax
            using the 'attr' keyword. The default is True and indicates
            that the member cannot be overridden.

        """
        metadata = member.metadata
        if metadata is None:
            metadata = member.metadata = {}
        metadata['d_member'] = True
        metadata['d_readable'] = readable
        metadata['d_writable'] = writable
        metadata['d_final'] = final
        return member

    def d_func(func):
        """ Mark a method as overridable from Enaml syntax.

        Parameters
        ----------
        func : FunctionType
            The function to tag as declarative.

        Returns
        -------
        result : func
            The original function tagged with the compiler metadata.

        """
        func._d_func = True
        return func

    #: The flag indicating that the Declarative object has been initialized.
    INITIALIZED_FLAG = next(flag_generator)

    class Declarative(Object, metaclass=DeclarativeMeta):
        """ The most base class of the Enaml declarative objects.

        This class provides the core functionality required of declarative
        Enaml types. It can be used directly in a declarative Enaml object
        tree to store and react to state changes. It has no concept of a
        visual representation; that functionality is added by subclasses.

        """

        #: Export the 'name' attribute as a declarative member.
        name = d_(Str())

        #: An event fired when an object is initialized. It is triggered
        #: once during the object lifetime, at the end of the initialize
        #: method.
        initialized = d_(Event(), writable=False)

        #: A property which gets and sets the initialized flag. This should
        #: not be manipulated directly by user code.
        is_initialized = flag_property(INITIALIZED_FLAG)

        #: Storage space for the declarative runtime. This value should not
        #: be manipulated by user code.
        _d_storage = Typed(sortedmap, ())

        #: Storage space for the declarative engine. This value should not
        #: be manipulated by user code.
        _d_engine = Typed(ExpressionEngine)

        def initialize(self):
            """ Initialize this object all of its children recursively.

            This is called to give the objects in the tree the opportunity
            to initialize additional state which depends upon the object
            tree being fully built. It is the responsibility of external
            code to call this method at the appropriate time. This will
            emit the `initialized` signal after all of the children have
            been initialized.

            """
            # Iterate over a copy since the children add and remove
            # other children during initialization.
            for child in self.children[:]:
                if isinstance(child, Declarative):
                    child.initialize()
            self.is_initialized = True
            self.initialized()

        def destroy(self):
            """ An overridden destructor method for declarative cleanup.

            """
            self.is_initialized = False
            del self._d_storage
            del self._d_engine
            super(Declarative, self).destroy()

        def child_added(self, child):
            """ An overridden child added event handler.

            This handler will automatically initialize a declarative child
            if this object itself has already been initialized.

            """
            super(Declarative, self).child_added(child)
            if isinstance(child, Declarative):
                if self.is_initialized and not child.is_initialized:
                    child.initialize()