# Copyright (c) 2021-2022, 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.
#
__all__ = ["IconMenuDelegate"]

from typing import Optional, Callable
import omni.ui as ui

class IconMenuDelegate(ui.MenuDelegate):
    """
    The menu delegate that draws in the menu bar the given icon and
    optionally the text.
    """

    def __init__(
        self,
        name: str,
        text: bool = False,
        width: ui.Length = 30,
        height: ui.Length = 30,
        has_triangle: bool = True,
        triangle_size: float = 6,
        checked: bool = False,
        enabled: bool = True,
        triggered_fn: Callable[[None], None] = None,
        right_clicked_fn: Callable[[None], None] = None,
        tooltip: Optional[str] = None,
        build_custom_widgets: Callable[[ui.MenuItem], None] = None
    ):
        super().__init__(propagate=False)
        self._name = name
        self._text = text
        self._width = width
        self._icon_width = width
        self._height = height
        self._has_triangle = has_triangle
        self._triangle_size = triangle_size
        self._checked = checked
        self._enabled = enabled
        self.__label = None
        self.__tooltip = tooltip or ""

        self._triggered_fn = triggered_fn
        self._right_clicked_fn = right_clicked_fn

        self._container: Optional[ui.Widget] = None
        self.__label_size = 0
        self.__build_custom_widgets = build_custom_widgets

    def build_item(self, item: ui.MenuItem):
        icon_type = "Menu.Item.Icon"
        self._container = ui.ZStack(checked=self._checked, height=self._height)
        with self._container:
            if self._has_triangle:
                with ui.VStack():
                    with ui.HStack():
                        ui.Spacer()
                        with ui.VStack(width=self._triangle_size):
                            ui.Spacer()
                            ui.Triangle(
                                width=self._triangle_size,
                                height=self._triangle_size,
                                alignment=ui.Alignment.RIGHT_TOP,
                                style_type_name_override="MenuBar.Item.Triangle",
                            )
                        ui.Spacer(width=2)
                    ui.Spacer(height=2)

            ui.Rectangle(style_type_name_override="MenuBar.Item.Background")
            spacer_width = 4
            with ui.HStack(height=self._height, spacing=spacer_width):
                self.icon = self._build_icon()
                if self._text:
                    self.__label_container = ui.HStack(spacing=4)
                    with self.__label_container:
                        self.__label = ui.Label(item.text, height=self._height)
                        if self.__build_custom_widgets:
                            self.__build_custom_widgets(item)
                        ui.Spacer(width=4)

                    def __label_size_changed(menu_item):
                        if self.__label_container.computed_width + spacer_width > self.__label_size:
                            self.__label_size = self.__label_container.computed_width + spacer_width
                    self.__label_container.set_computed_content_size_changed_fn(lambda m=item: __label_size_changed(m))

            ui.Rectangle(style_type_name_override="Menubar.Hover")

        if self._triggered_fn or self._right_clicked_fn:
            self._container.set_mouse_released_fn(lambda x, y, b, a: self._on_mouse_released(b))

    @property
    def text_size(self) -> float:
        """
        Size of text displayed.
        """
        return self.__label_size

    @property
    def text_visible(self) -> bool:
        return self._text

    @text_visible.setter
    def text_visible(self, value: bool) -> None:
        # Here only set status but need menu invilidate outside to refresh
        self._text = value

    @property
    def checked(self) -> bool:
        return self._container.checked if self._container else self._checked

    @checked.setter
    def checked(self, value) -> None:
        self._checked = value
        if self._container:
            self._container.checked = value

    @property
    def enabled(self) -> bool:
        return self._enabled

    @enabled.setter
    def enabled(self, value) -> None:
        self._enabled = value
        if self._container:
            self._container.enabled = value

    @property
    def text(self):
        return self.__label.text if self.__label else ''

    @text.setter
    def text(self, txt: str):
        if self.__label:
            self.__label.text = str(txt)

    def destroy(self):
        self.__build_custom_widgets = None

    def _on_mouse_released(self, button: int) -> None:
        if button == 0:
            if self._triggered_fn:
                self._triggered_fn()
        elif button == 1:
            if self._right_clicked_fn:
                self._right_clicked_fn()

    def _build_icon(self):
        return ui.ImageWithProvider(
            style_type_name_override="Menu.Item.Icon",
            name=self._name,
            width=self._icon_width,
            height=self._height,
            tooltip=self.__tooltip,
        )
