# 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 for Field """

from .doc_page import DocPage
from omni import ui
import inspect

SPACING = 5


def field_callbacks():
    def on_value(label):
        label.text = "Value is changed"

    def on_begin(label):
        label.text = "Editing is started"

    def on_end(label):
        label.text = "Editing is finished"

    label = ui.Label("Nothing happened", name="text")
    model = ui.StringField().model
    model.add_value_changed_fn(lambda m, l=label: on_value(l))
    model.add_begin_edit_fn(lambda m, l=label: on_begin(l))
    model.add_end_edit_fn(lambda m, l=label: on_end(l))


def multiline_field():
    initial_text = inspect.getsource(field_callbacks)
    model = ui.SimpleStringModel(initial_text)
    field = ui.StringField(model, multiline=True)


class FieldDoc(DocPage):
    """ document for Field"""

    def create_doc(self, navigate_to=None):
        self._section_title("Field")

        self._caption("StringField", navigate_to)

        self._text(
            "The StringField widget is a one-line text editor. A field allows the user to enter and edit a single line "
            "of plain text. It's implemented using the model-delegate-view pattern and uses AbstractValueModel as the central "
            "component of the system."
        )

        self._text("The following example demonstrates the way how to connect a StringField and a Label.")

        field_style = {
            "Field": {
                "background_color": 0xFFFFFFFF,
                "background_selected_color": 0xFFD77800,
                "border_color": 0xFF444444,
                "border_radius": 1,
                "border_width": 0.5,
                "color": 0xFF444444,
                "font_size": 16.0,
            },
            "Field:hovered": {"border_color": 0xFF000000},
            "Field:pressed": {"background_color": 0xFFFFFFFF, "border_color": 0xFF995400, "border_width": 0.75},
        }

        def setText(label, text):
            """Sets text on the label"""
            # This function exists because lambda cannot contain assignment
            label.text = f"You wrote '{text}'"

        with ui.HStack():
            field = ui.StringField(style=field_style)
            ui.Spacer(width=SPACING)
            label = ui.Label("", name="text")
            field.model.add_value_changed_fn(lambda m, label=label: setText(label, m.get_value_as_string()))

        self._code(
            """
        def setText(label, text):
            '''Sets text on the label'''
            # This function exists because lambda cannot contain assignment
            label.text = f"You wrote '{text}'"

        with ui.HStack():
            field = ui.StringField(style=field_style)
            label = ui.Label("")
            field.model.add_value_changed_fn(
                lambda m, label=label: setText(label, m.get_value_as_string()))
            """
        )

        self._text(
            "The following example demonstrates that the model decides the content of the field. The field can have "
            "only one of two options, either 'True' or 'False' because the model supports only those two possibilities."
        )

        with ui.HStack():
            checkbox = ui.CheckBox(width=0)
            field = ui.StringField()
            field.model = checkbox.model

        self._code(
            """
        with ui.HStack():
            checkbox = ui.CheckBox(width=0)
            field = ui.StringField()
            field.model = checkbox.model
            """
        )

        self._text(
            "In this example, the field can have anything because the model accepts any string, but the model returns "
            "bool for checkbox, and the checkbox is off when the string is empty or 'False'."
        )

        with ui.HStack():
            checkbox = ui.CheckBox(width=0)
            field = ui.StringField()
            checkbox.model = field.model

        self._code(
            """
        with ui.HStack():
            checkbox = ui.CheckBox(width=0)
            field = ui.StringField()
            checkbox.model = field.model
            """
        )

        self._caption("FloatField and IntField", navigate_to)

        self._text(
            "There are fields for string, float and int models. The following example shows how they interact with "
            "each other:"
        )

        self._text("All three fields share the same SimpleFloatModel:")
        with ui.HStack():
            self._text("FloatField")
            self._text("IntField")
            self._text("StringField")
        with ui.HStack():
            left = ui.FloatField()
            center = ui.IntField()
            right = ui.StringField()
            center.model = left.model
            right.model = left.model

        self._text("All three fields share the same SimpleIntModel:")
        with ui.HStack():
            self._text("FloatField")
            self._text("IntField")
            self._text("StringField")
        with ui.HStack():
            left = ui.FloatField()
            center = ui.IntField()
            right = ui.StringField()
            left.model = center.model
            right.model = center.model

        self._text("All three fields share the same SimpleStringModel:")
        with ui.HStack():
            self._text("FloatField")
            self._text("IntField")
            self._text("StringField")
        with ui.HStack():
            left = ui.FloatField()
            center = ui.IntField()
            right = ui.StringField()
            left.model = right.model
            center.model = right.model

        self._text(
            "The widget doesn't keep the data due to the model-delegate-view pattern. However, there are two ways to track the "
            "state of the widget. It's possible to reimplement AbstractValueModel, for details see the chapter "
            "`AbstractValueModel`. The second way is using the callbacks of the model. This is a minimal example "
            "of callbacks."
        )

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

        self._caption("Multiline StringField", navigate_to)

        self._text(
            "Property `multiline` of `StringField` allows to press enter and create a new line. It's possible to "
            "finish editing with Ctrl-Enter."
        )

        with ui.Frame(style=field_style, height=300):
            multiline_field()
        self._code(inspect.getsource(multiline_field).split("\n", 1)[-1])

        ui.Spacer(height=10)
