import carb
import carb.input
import carb.settings
import omni.kit.ui
import omni.appwindow
import omni.kit.menu.utils
import omni.ui as ui
from carb.input import KeyboardInput as Key

class WindowExtension:
    def __init__(self):
        self._appwindow = omni.appwindow.get_default_app_window()
        self._settings = carb.settings.get_settings()

        self.WINDOW_UI_TOGGLE_VISIBILITY_MENU = "Window/UI Toggle Visibility"
        self.WINDOW_FULLSCREEN_MODE_MENU = "Window/Fullscreen Mode"
        self.WINDOW_DPI_SCALE_INCREASE_MENU = "Window/DPI Scale/Increase"
        self.WINDOW_DPI_SCALE_DECREASE_MENU = "Window/DPI Scale/Decrease"
        self.WINDOW_DPI_SCALE_RESET_MENU = "Window/DPI Scale/Reset"

        self.SHOW_DPI_SCALE_MENU_SETTING = "/app/window/showDpiScaleMenu"
        self.DPI_SCALE_OVERRIDE_SETTING = "/app/window/dpiScaleOverride"
        self.DPI_SCALE_OVERRIDE_DEFAULT = -1.0
        self.DPI_SCALE_OVERRIDE_MIN = 0.5
        self.DPI_SCALE_OVERRIDE_MAX = 5.0
        self.DPI_SCALE_OVERRIDE_STEP = 0.5

        self.menus = []

        menu = omni.kit.ui.get_editor_menu()
        if menu:
            window_ui_toggle_visibility_menu = menu.add_item(self.WINDOW_UI_TOGGLE_VISIBILITY_MENU, None, priority=51)
            window_ui_toggle_visibility_action = omni.kit.menu.utils.add_action_to_menu(self.WINDOW_UI_TOGGLE_VISIBILITY_MENU, lambda *_: self.on_toggle_ui(), "UiToggle", (0, Key.F7))
            self.menus.append((window_ui_toggle_visibility_menu, window_ui_toggle_visibility_action))

            window_fullscreen_mode_menu = menu.add_item(self.WINDOW_FULLSCREEN_MODE_MENU, None, priority=52)
            window_fullscreen_mode_menu_action = omni.kit.menu.utils.add_action_to_menu(self.WINDOW_FULLSCREEN_MODE_MENU, lambda *_: self.on_fullscreen(), "FullscreenMode", (0, Key.F11))
            self.menus.append((window_fullscreen_mode_menu, window_fullscreen_mode_menu_action))

            self._settings.set_default_bool(self.SHOW_DPI_SCALE_MENU_SETTING, False)
            if self._settings.get_as_bool(self.SHOW_DPI_SCALE_MENU_SETTING):
                window_dpi_scale_increase_menu = menu.add_item(self.WINDOW_DPI_SCALE_INCREASE_MENU, None, priority=53)
                window_dpi_scale_increase_menu_action = omni.kit.menu.utils.add_action_to_menu(self.WINDOW_DPI_SCALE_INCREASE_MENU, lambda *_: self.on_dpi_scale_increase(), "DPIScaleIncrease", (carb.input.KEYBOARD_MODIFIER_FLAG_CONTROL, Key.EQUAL))
                self.menus.append((window_dpi_scale_increase_menu, window_dpi_scale_increase_menu_action))

                window_dpi_scale_decrease_menu = menu.add_item(self.WINDOW_DPI_SCALE_DECREASE_MENU, None, priority=54)
                window_dpi_scale_decrease_menu_action = omni.kit.menu.utils.add_action_to_menu(self.WINDOW_DPI_SCALE_DECREASE_MENU, lambda *_: self.on_dpi_scale_decrease(), "DPIScaleDecrease", (carb.input.KEYBOARD_MODIFIER_FLAG_CONTROL, Key.MINUS))
                self.menus.append((window_dpi_scale_decrease_menu, window_dpi_scale_decrease_menu_action))

                window_dpi_scale_reset_menu = menu.add_item(self.WINDOW_DPI_SCALE_RESET_MENU, None, priority=55)
                window_dpi_scale_reset_menu_action = omni.kit.menu.utils.add_action_to_menu(self.WINDOW_DPI_SCALE_RESET_MENU, lambda *_: self.on_dpi_scale_reset(), "DPIScaleReset")
                self.menus.append((window_dpi_scale_reset_menu, window_dpi_scale_reset_menu_action))

            # Sort top level menus:
            menu.set_priority("Window", -6)

    def __del__(self):
        self.menus = None

    def add_menu(self, *argv, **kwargs):
        new_menu = omni.kit.ui.get_editor_menu().add_item(*argv, **kwargs)
        self.menus.append(new_menu)
        return new_menu

    def set_ui_hidden(self, hide):
        self._settings.set("/app/window/hideUi", hide)

    def is_ui_hidden(self):
        return self._settings.get("/app/window/hideUi")

    def on_toggle_ui(self):
        self.set_ui_hidden(not self.is_ui_hidden())

    def on_fullscreen(self):
        display_mode_lock = self._settings.get(f"/app/window/displayModeLock")
        if display_mode_lock:
            # Always stay in fullscreen_mode, only hide or show UI.
            self.set_ui_hidden(not self.is_ui_hidden())
        else:
            # Only toggle fullscreen on/off when not display_mode_lock
            was_fullscreen = self._appwindow.is_fullscreen()
            self._appwindow.set_fullscreen(not was_fullscreen)

            # Always hide UI in fullscreen
            self.set_ui_hidden(not was_fullscreen)

    def step_and_clamp_dpi_scale_override(self, increase):
        # Get the current value.
        dpi_scale = self._settings.get_as_float(self.DPI_SCALE_OVERRIDE_SETTING)
        if dpi_scale == self.DPI_SCALE_OVERRIDE_DEFAULT:
            dpi_scale = ui.Workspace.get_dpi_scale()

        # Increase or decrease the current value by the setp value.
        if increase:
            dpi_scale += self.DPI_SCALE_OVERRIDE_STEP
        else:
            dpi_scale -= self.DPI_SCALE_OVERRIDE_STEP

        # Clamp the new value between the min/max values.
        dpi_scale = max(min(dpi_scale, self.DPI_SCALE_OVERRIDE_MAX), self.DPI_SCALE_OVERRIDE_MIN)

        # Set the new value.
        self._settings.set(self.DPI_SCALE_OVERRIDE_SETTING, dpi_scale)

    def on_dpi_scale_increase(self):
        self.step_and_clamp_dpi_scale_override(True)

    def on_dpi_scale_decrease(self):
        self.step_and_clamp_dpi_scale_override(False)

    def on_dpi_scale_reset(self):
        self._settings.set(self.DPI_SCALE_OVERRIDE_SETTING, self.DPI_SCALE_OVERRIDE_DEFAULT)
