# Drag And Drop Example

An example of the drag and drop functionality.

In addition to the source widgets in this example, the drop target can accept data from other processes that have draggable data, such as text from a web page. The source drag data can also be dropped onto other processes which support the ‘text/plain’ mime type used in this example.

The background color of the labels will update to indicate whether the drop target accepted or rejected the proposed drop action.

If a widget has the `DragEnabled` Feature flag enabled, the following declarative functions are available:

`drag_start`

  The start of the drag operation. Returns a DragData object.

`drag_end`

  The end of the drag operation. Indicates the result of the drop.

If a widget has the `DropEnabled` Feature flag enabled, the following declarative functions are available:

`drag_enter`

  Called when a drag operation enters the widget bounds. The event must be accepted in order to receive further drag drop events.

`drag_move`

  Called when a drag operation moves within the widget bounds. This is normally not implemented, but it can be useful is certain cases.

`drag_leave`

  Called when a drag operation leaves the widget bounds.

`drop`

  Called when the drag data is dropped on the widget. The event can be ignored to indicated to the drag source that the event was not accepted. Set the drop action to DropAction.Ignore for that case. By default, the event is accepted.

Tip

To see this example in action, download it from `drag_and_drop` and run:

    $ enaml-run drag_and_drop.enaml

## Screenshot

## Example Enaml Code

    #------------------------------------------------------------------------------
    # Copyright (c) 2014-2024,, Nucleic Development Team.
    #
    # Distributed under the terms of the Modified BSD License.
    #
    # The full license is in the file LICENSE, distributed with this software.
    #------------------------------------------------------------------------------
    """ An example of the drag and drop functionality.

    In addition to the source widgets in this example, the drop target can
    accept data from other processes that have draggable data, such as text
    from a web page. The source drag data can also be dropped onto other
    processes which support the 'text/plain' mime type used in this example.

    The background color of the labels will update to indicate whether the
    drop target accepted or rejected the proposed drop action.

    If a widget has the `DragEnabled` Feature flag enabled, the following
    declarative functions are available:

    `drag_start`
        The start of the drag operation. Returns a DragData object.

    `drag_end`
        The end of the drag operation. Indicates the result of the drop.

    If a widget has the `DropEnabled` Feature flag enabled, the following
    declarative functions are available:

    `drag_enter`
        Called when a drag operation enters the widget bounds. The event
        must be accepted in order to receive further drag drop events.

    `drag_move`
        Called when a drag operation moves within the widget bounds. This
        is normally not implemented, but it can be useful is certain cases.

    `drag_leave`
        Called when a drag operation leaves the widget bounds.

    `drop`
        Called when the drag data is dropped on the widget. The event
        can be ignored to indicated to the drag source that the event
        was not accepted. Set the drop action to DropAction.Ignore for
        that case. By default, the event is accepted.

    << autodoc-me >>
    """
    from enaml.drag_drop import DragData, DropAction
    from enaml.layout.api import hbox, vbox, align, spacer
    from enaml.styling import StyleSheet, Style, Setter
    from enaml.widgets.api import Window, Container, Label, Feature, MultilineField

    def create_drag_data(data):
        drag = DragData()
        drag.supported_actions = DropAction.Copy
        drag.mime_data.set_data('text/plain', data)
        return drag

    enamldef DragLabel(Label):
        attr data: bytes
        attr success = False
        style_class << 'success' if success else 'fail'
        features = Feature.DragEnabled
        drag_start => ():
            return create_drag_data(data)
        drag_end => (drag_data, result):
            self.success = result == DropAction.Copy

    enamldef DropField(MultilineField):
        features = Feature.DropEnabled
        drag_enter => (event):
            if event.mime_data().has_format('text/plain'):
                event.accept_proposed_action()
        drop => (event):
            self.text = event.mime_data().data('text/plain').decode('utf-8')

    enamldef ExampleStyleSheet(StyleSheet):
        Style:
            style_class = 'success'
            Setter:
                field = 'background-color'
                value = '#DDFFDD'
        Style:
            style_class = 'fail'
            Setter:
                field = 'background-color'
                value = '#FFDDDD'

    enamldef Main(Window):
        ExampleStyleSheet:
            pass
        Container:
            constraints = [
                hbox(vbox(lbl1, lbl2), target),
            ]
            DragLabel: lbl1:
                text = 'Drag Me 1'
                data = b'small\ndata'
            DragLabel: lbl2:
                text = 'Drag Me 2'
                data = b'\n'.join([bytes(str(i), 'utf-8') for i in range(100)])
            DropField: target:
                hug_width = 'strong'
                read_only = True