# Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.  Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#
"""The documentation of the omni.ui aka UI Framework"""

from omni import ui
from omni.ui import color as cl
from .doc_page import DocPage
import inspect


def simple_dnd():
    def drag(url):
        """Called for the drag operation. Returns drag data."""
        return url

    def drop_accept(url):
        """Called to check the drag data is acceptable."""
        return True

    def drop(widget, event):
        """Called when dropping the data."""
        widget.source_url = event.mime_data

    def drag_area(url):
        """Create a draggable image."""
        image = ui.Image(url, width=64, height=64)
        image.set_drag_fn(lambda: drag(url))

    def drop_area():
        """A drop area that shows image when drop."""
        with ui.ZStack(width=64, height=64):
            ui.Rectangle()
            image = ui.Image()

        image.set_accept_drop_fn(drop_accept)
        image.set_drop_fn(lambda a, w=image: drop(w, a))

    with ui.HStack():
        drag_area("resources/icons/Nav_Flymode.png")
        drag_area("resources/icons/Move_64.png")
        ui.Spacer(width=64)
        drop_area()


def complex_dnd():
    def drag(url):
        # Draw the image and the image name in the drag tooltip
        with ui.VStack():
            ui.Image(url, width=32, height=32)
            ui.Label(url)
        return url

    def drop_accept(url, ext):
        # Accept drops of specific extension only
        return url.endswith(ext)

    def drop(widget, event):
        widget.source_url = event.mime_data

    def drag_area(url):
        image = ui.Image(url, width=64, height=64)
        image.set_drag_fn(lambda: drag(url))

    def drop_area(ext):
        # If drop is acceptable, the rectangle is blue
        style = {}
        style["Rectangle"] = {"background_color": cl("#999999")}
        style["Rectangle:drop"] = {"background_color": cl("#004499")}

        stack = ui.ZStack(width=64, height=64)
        with stack:
            ui.Rectangle(style=style)
            ui.Label(f"Accepts {ext}")
            image = ui.Image(style={"margin": 2})

        stack.set_accept_drop_fn(lambda d, e=ext: drop_accept(d, e))
        stack.set_drop_fn(lambda a, w=image: drop(w, a))

    with ui.HStack():
        drag_area("resources/icons/sound.png")
        drag_area("resources/icons/stage.png")
        drag_area("resources/glyphs/menu_audio.svg")
        drag_area("resources/glyphs/menu_camera.svg")
        ui.Spacer(width=64)
        drop_area(".png")
        ui.Spacer(width=64)
        drop_area(".svg")


class DNDDoc(DocPage):
    """The document for Drag and Drop"""

    def create_doc(self, navigate_to=None):
        self._section_title("Drag and Drop")

        self._caption("Minimal Example", navigate_to)

        self._text(
            "Omni::UI includes methods to perform Drag and Drop operations quickly. Drag and Drop with Omni::UI is "
            "straightforward."
        )

        self._text(
            "A drag and drop operation consists of three parts: the drag, accept the drop, and the drop. For drag, "
            "Widget has a single callback drag_fn. By adding this function to a widget, you set the callback attached "
            "to the drag operation. The function should return the string data to drag."
        )

        self._text(
            "To accept the drop Widget has a callback accept_drop_fn. It's called when the mouse enters the widget "
            "area. It takes the drag string data and should return either the widget can accept this data for the "
            "drop."
        )

        self._text(
            "For the drop part, Widget has a callback drop_fn. With this method, we specify if Widget accepts drops. "
            "And it's called when the user drops the string data to the widget."
        )

        simple_dnd()
        self._code(inspect.getsource(simple_dnd).split("\n", 1)[-1])

        self._caption("Styling and Tooltips", navigate_to)

        self._text("It's possible to customize the drag tooltip with creating widgets in drag_fn.")

        self._text(
            "To show the drop widget accepts drops visually, there is a style 'drop', and it's propagated to the "
            "children widgets."
        )

        complex_dnd()
        self._code(inspect.getsource(complex_dnd).split("\n", 1)[-1])

        ui.Spacer(height=10)
