# 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 Windows"""

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

import carb.settings


SPACING = 5


def popup_example(self):
    class StrModel(ui.AbstractValueModel):
        def __init__(self, **kwargs):
            super().__init__()
            self.__str = ""
            self.__parent = None
            self.__window = None
            self.__frame = None
            self.__tooltips = ["Hello", "World", "Hello World"]
            self.__kwargs = kwargs

        def set_parent(self, parent):
            self.__parent = parent

        def set_value(self, value):
            self.__str = str(value)
            self._value_changed()
            self._set_tips()

        def get_value_as_string(self):
            return self.__str

        def begin_edit(self):
            if self.__window and self.__window.visible:
                return

            # Create and show the window with field and list of tips
            self.__window = ui.Window("0", **self.__kwargs)
            with self.__window.frame:
                with ui.VStack(width=0, height=0):
                    width = self.__parent.computed_content_width
                    # Field with the same model
                    field = ui.StringField(self, width=width)
                    field.focus_keyboard()
                    self.__frame = ui.Frame()
            self.__window.position_x = self.__parent.screen_position_x
            self.__window.position_y = self.__parent.screen_position_y
            self._set_tips()

        def _set_tips(self):
            """Generates list of tips"""
            if not self.__frame:
                return

            found = False
            with self.__frame:
                with ui.VStack():
                    for t in self.__tooltips:
                        if self.__str and self.__str in t:
                            ui.Button(t)
                            found = True

                    if not found:
                        for t in self.__tooltips:
                            ui.Button(t)

        def destroy(self):
            self.__parent = None
            self.__frame = None
            self.__window = None

    window_args = {
        "flags": ui.WINDOW_FLAGS_POPUP | ui.WINDOW_FLAGS_NO_TITLE_BAR,
        "auto_resize": True,
        "padding_x": 0,
        "padding_y": 0,
    }
    self._model = StrModel(**window_args)
    self._field = ui.StringField(self._model)
    self._model.set_parent(self._field)


class WindowDoc(DocPage):
    """ document Windows classes"""

    def __init__(self, extension_path):
        super().__init__(extension_path)
        self._window_example = None
        self._modal_window_example = None
        self._no_close_window_example = None
        self._style_window_example = None
        self._simple_toolbar = None
        self._rotating_toolbar = None
        self._toolbar_rotation = ui.DockPosition.BOTTOM
        self._modal_test = []
        self._model = None

    def clean(self):
        self._model = None

    def build_toolbar(self):
        """Caled to load the extension"""

        def top_toolbar_changeAxis(frame, axis):
            with frame:
                stack = None
                if axis == ui.ToolBarAxis.X:
                    stack = ui.HStack(spacing=15, height=24)
                else:
                    stack = ui.VStack(spacing=15, height=24)

                with stack:
                    ui.Spacer()
                    ui.Image("resources/icons/Select_model_64.png", width=24, height=24)
                    ui.Image("resources/icons/Move_64.png", width=24, height=24)
                    ui.Image("resources/icons/Rotate_global.png", width=24, height=24)
                    ui.Image("resources/icons/Scale_64.png", width=24, height=24)
                    ui.Image("resources/icons/Snap_64.png", width=24, height=24)
                    ui.Spacer()

        self._top_toolbar = ui.ToolBar("UI ToolBar", noTabBar=False, padding_x=0, padding_y=0)
        self._top_toolbar.set_axis_changed_fn(
            lambda axis, frame=self._top_toolbar.frame: top_toolbar_changeAxis(frame, axis)
        )
        top_toolbar_changeAxis(self._top_toolbar.frame, ui.ToolBarAxis.X)

        self._right_toolbar = ui.ToolBar("Right Size ToolBar", noTabBar=True, padding_x=5, padding_y=0)
        with self._right_toolbar.frame:
            with ui.VStack(spacing=15, width=25):
                ui.Spacer(height=1)
                ui.Image("resources/icons/Toolbars/Display@2x.png", width=20, height=20)
                ui.Image("resources/icons/Toolbars/Materials@2x.png", width=20, height=20)
                ui.Image("resources/icons/Toolbars/Sky@2x.png", width=20, height=20)
                ui.Image("resources/icons/Toolbars/DateAndTime@2x.png", width=20, height=20)
                ui.Image("resources/icons/Toolbars/SetLocation@2x.png", width=20, height=20)
                ui.Image("resources/icons/Toolbars/Weather@2x.png", width=20, height=20)
                ui.Image("resources/icons/SunStudy_64.png", width=20, height=20)
                ui.Spacer()

        self._left_toolbar = ui.ToolBar("Left Size ToolBar", noTabBar=True, padding_x=5, padding_y=0)
        with self._left_toolbar.frame:
            with ui.VStack(spacing=0):
                ui.Spacer(height=10)
                ui.Image("resources/icons/Toolbars/SceneHierarchy@2x.png", width=20, height=20)
                ui.Spacer()

        self._bottom_toolbar = ui.ToolBar("Bottom ToolBar", noTabBar=True, padding_x=0, padding_y=0)
        with self._bottom_toolbar.frame:
            with ui.HStack(height=18):
                ui.Spacer()
                with ui.ZStack(width=200, height=15):
                    ui.Rectangle(
                        width=120,
                        style={"background_color": cl("#809EAB"), "corner_flag": ui.CornerFlag.LEFT, "border_radius": 2},
                    )
                    ui.Rectangle(
                        width=200,
                        style={
                            "background_color": cl.transparent,
                            "border_color": cl("#222222"),
                            "border_width": 1.0,
                            "border_radius": 2,
                        },
                    )
                    ui.Label("FPS 30", style={"color": cl.white, "margin_width": 10, "font_size": 8})
                ui.Spacer()

        self._bottom_toolbar.dock_in_window("Viewport", ui.DockPosition.BOTTOM)
        self._top_toolbar.dock_in_window("Viewport", ui.DockPosition.TOP)
        self._left_toolbar.dock_in_window("Viewport", ui.DockPosition.LEFT)
        self._right_toolbar.dock_in_window("Viewport", ui.DockPosition.RIGHT)

        # TODO omni.ui: restore functionality for Kit Next
        self._settings = carb.settings.get_settings()
        self._settings.set("/app/docks/autoHideTabBar", True)
        self._settings.set("/app/docks/noWindowMenuButton", False)
        self._settings.set("app/window/showStatusBar", False)

        self._settings.set("app/window/showStatusBar", False)

        self._settings.set("/app/viewport/showSettingsMenu", True)
        self._settings.set("/app/viewport/showCameraMenu", False)
        self._settings.set("/app/viewport/showRendererMenu", True)

        self._settings.set("/app/viewport/showHideMenu", True)

        self._settings.set("/app/viewport/showLayerMenu", False)


    def create_and_show_window(self):
        if not self._window_example:
            self._window_example = ui.Window("Example Window", width=300, height=300)

            button_size = None
            button_dock = None
            with self._window_example.frame:
                with ui.VStack():
                    ui.Button("click me")
                    button_size = ui.Button("")

                    def move_me(window):
                        window.setPosition(200, 200)

                    def size_me(window):
                        window.width = 300
                        window.height = 300

                    ui.Button("move to 200,200", clicked_fn=lambda w=self._window_example: move_me(w))
                    ui.Button("set size 300,300", clicked_fn=lambda w=self._window_example: size_me(w))
                    button_dock = ui.Button("Undocked")

            def update_button(window, button):
                computed_width = (int)(button.computed_width)
                computed_height = (int)(button.computed_height)

                button.text = (
                    "Window size is {:.1f} x {:.1f}\n".format(window.width, window.height)
                    + "Window position is {:.1f} x {:.1f}\n".format(window.position_x, window.position_y)
                    + "Button size is {:.1f} x {:.1f}".format(computed_width, computed_height)
                )

            def update_docking(docked, button):
                button.text = "Docked" if docked else "Undocked"

            for fn in [
                self._window_example.set_width_changed_fn,
                self._window_example.set_height_changed_fn,
                self._window_example.set_position_x_changed_fn,
                self._window_example.set_position_y_changed_fn,
            ]:
                fn(lambda value, b=button_size, w=self._window_example: update_button(w, b))

            self._window_example.set_docked_changed_fn(lambda value, b=button_dock: update_docking(value, b))

        self._window_example.visible = True

    def close_modal_window_me(self):
        if self._modal_window_example:
            self._modal_window_example.visible = False

    def create_and_show_modal_window(self):
        if not self._modal_window_example:
            window_flags = ui.WINDOW_FLAGS_NO_RESIZE
            window_flags |= ui.WINDOW_FLAGS_NO_SCROLLBAR
            window_flags |= ui.WINDOW_FLAGS_MODAL
            self._modal_window_example = ui.Window("Example Modal Window", width=200, height=200, flags=window_flags)
            with self._modal_window_example.frame:
                with ui.VStack():
                    ui.Button("I am Modal")
                    ui.Button("You Can't Click outsite ")
                    ui.Button("click here to close me", height=100, clicked_fn=self.close_modal_window_me)

        self._modal_window_example.visible = True

    def create_and_show_window_no_close(self):
        if not self._no_close_window_example:
            window_flags = ui.WINDOW_FLAGS_NO_CLOSE
            self._no_close_window_example = ui.Window(
                "Example Modal Window",
                width=400,
                height=200,
                flags=window_flags,
                visibility_changed_fn=self._update_window_visible,
            )

            with self._no_close_window_example.frame:
                with ui.VStack():
                    ui.Button("I dont have Close button")
                    ui.Button("my Size is 400x200 ")

                    def close_me(window):
                        if window:
                            window.visible = False

                    ui.Button(
                        "click here to close me",
                        height=100,
                        clicked_fn=lambda w=self._no_close_window_example: close_me(w),
                    )

        self._no_close_window_example.visible = True

    def create_styled_window(self):
        if not self._style_window_example:
            self._style_window_example = ui.Window("Styled Window Example", width=300, height=300)

            self._style_window_example.frame.set_style(
                {
                    "Window": {
                        "background_color": cl.blue,
                        "border_radius": 10,
                        "border_width": 5,
                        "border_color": cl.red,
                    }
                }
            )

            with self._style_window_example.frame:
                with ui.VStack():
                    ui.Button("I am a Styled Window")
                    ui.Spacer(height=10)
                    ui.Button(
                        """Style is attached to 'Window'

{"Window": {"background_color": cl.blue,
                "border_radius": 10,
                "border_width": 5,
                "border_color": cl.red}""",
                        height=200,
                    )

        self._style_window_example.visible = True

    def _update_window_visible(self, value):
        self._window_checkbox.model.set_value(value)

    def create_simple_toolbar(self):
        if self._simple_toolbar:
            self._simple_toolbar.visible = not self._simple_toolbar.visible
        else:
            self._simple_toolbar = ui.ToolBar("simple toolbar", noTabBar=True)
            with self._simple_toolbar.frame:
                with ui.HStack(spacing=15, height=28):
                    ui.Spacer()
                    ui.Image("resources/icons/Select_model_64.png", width=24, height=24)
                    ui.Image("resources/icons/Move_64.png", width=24, height=24)
                    ui.Image("resources/icons/Rotate_global.png", width=24, height=24)
                    ui.Image("resources/icons/Scale_64.png", width=24, height=24)
                    ui.Image("resources/icons/Snap_64.png", width=24, height=24)
                    ui.Spacer()

        self._simple_toolbar.dock_in_window("Viewport", ui.DockPosition.TOP)
        self._simple_toolbar.frame.set_style({"Window": {"background_color": cl("#DDDDDD")}})

    def create_rotating_toolbar(self):
        if not self._rotating_toolbar:

            def toolbar_changeAxis(frame, axis):
                with frame:
                    stack = None
                    if axis == ui.ToolBarAxis.X:
                        stack = ui.HStack(spacing=15, height=30)
                    else:
                        stack = ui.VStack(spacing=15, width=30)

                    with stack:
                        ui.Spacer()
                        ui.Image("resources/icons/Select_model_64.png", width=24, height=24)
                        ui.Image("resources/icons/Move_64.png", width=24, height=24)
                        ui.Image("resources/icons/Rotate_global.png", width=24, height=24)
                        ui.Image("resources/icons/Scale_64.png", width=24, height=24)
                        ui.Image("resources/icons/Snap_64.png", width=24, height=24)
                        ui.Spacer()

            self._rotating_toolbar = ui.ToolBar("Rotating ToolBar", noTabBar=False, padding_x=5, padding_y=5, margin=5)
            self._rotating_toolbar.set_axis_changed_fn(
                lambda axis, frame=self._rotating_toolbar.frame: toolbar_changeAxis(frame, axis)
            )
            toolbar_changeAxis(self._rotating_toolbar.frame, ui.ToolBarAxis.X)

        if self._toolbar_rotation == ui.DockPosition.RIGHT:
            self._toolbar_rotation = ui.DockPosition.BOTTOM
        else:
            self._toolbar_rotation = ui.DockPosition.RIGHT

        self._rotating_toolbar.dock_in_window("Viewport", self._toolbar_rotation)

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

        self._text(
            "With omni ui you can create a varierty of Window type and style"
            " the main Window type are floating window that can optionally be docked into the Main Window.\n"
            "There are also other type of window like ToolBar, DialogBox, Etc that you can use"
        )

        self._caption("Window", navigate_to)
        self._text("This class is used to construct a regular Window")

        with ui.ScrollingFrame(height=350, vertical_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF):
            with ui.VStack(height=0):
                with ui.HStack(width=0):
                    ui.Button("click for window Example", width=180, clicked_fn=self.create_and_show_window)
                    ui.Label("this create a regular Window", name="text", width=180, style={"margin_width": 10})
                    ui.Label(
                        """
                    ui.Window("Example Window",
                              position_x=100,
                              position_y=100)""",
                        name="text",
                    )

                with ui.HStack(width=0):
                    ui.Button("Window without close", width=180, clicked_fn=self.create_and_show_window_no_close)
                    self._window_checkbox = ui.CheckBox(style={"margin": 5})

                    # this Tie the window visibility with the checkox
                    def update_check_box(value, self):
                        self._no_close_window_example.visible = value

                    self._window_checkbox.model.add_value_changed_fn(
                        lambda a, this=self: update_check_box(a.get_value_as_bool(), self)
                    )
                    ui.Label("this create a regular Window", name="text", width=150, style={"margin_width": 10})
                    ui.Label('ui.Window("Example Window", )', name="text")

                # Modal example is off because there are few issue but this MR need to go in
                with ui.HStack(width=0):
                    ui.Button("click for Custom Window", width=180, clicked_fn=self.create_and_show_modal_window)
                    ui.Label("this create a custom Window", name="text", width=180, style={"margin_width": 10})
                    ui.Label(
                        "window_flags = ui.WINDOW_FLAGS_NO_COLLAPSE\n"
                        "window_flags |= ui.WINDOW_FLAGS_NO_RESIZE\n"
                        "window_flags |= ui.WINDOW_FLAGS_NO_CLOSE\n"
                        "window_flags |= ui.WINDOW_FLAGS_NO_SCROLLBAR\n"
                        "window_flags |= ui.WINDOW_FLAGS_NO_TITLE_BAR\n\n"
                        "ui.Window('Example Window', flags=window_flags",
                        name="text",
                    )

                with ui.HStack(width=0):
                    ui.Button("click for Styled Window", width=180, clicked_fn=self.create_styled_window)
                    ui.Spacer(width=20)
                    ui.Label(
                        """
self._style_window_example = ui.Window("Styled Window Example", width=300, height=300)

self._style_window_example.frame.set_style({"Window": {"background_color": cl.blue,
                                    "border_radius": 10,
                                    "border_width": 5,
                                    "border_color": cl.red})

with self._style_window_example.frame:
    with ui.VStack():
        ui.Button("I am a Styled Window")
        ui.Button("Style is attached to 'Window'", height=200)""",
                        name="text",
                    )

        self._text("All the Window Flags")
        self._text(
            """    WINDOW_FLAGS_NONE
    WINDOW_FLAGS_NO_TITLE_BAR
    WINDOW_FLAGS_NO_RESIZE
    WINDOW_FLAGS_NO_MOVE
    WINDOW_FLAGS_NO_SCROLLBAR
    WINDOW_FLAGS_NO_COLLAPSE
    WINDOW_FLAGS_NO_SAVED_SETTINGS
    WINDOW_FLAGS_SHOW_HORIZONTAL_SCROLLBAR
    WINDOW_FLAGS_FORCE_VERTICAL_SCROLLBAR
    WINDOW_FLAGS_FORCE_HORIZONTAL_SCROLLBAR
    WINDOW_FLAGS_NO_FOCUS_ON_APPEARING
    WINDOW_FLAGS_NO_CLOSE
        """
        )

        self._text("Available Window Properties, call can be used in the constructor")
        self._text(
            """    title : set the title for the window

    visible: set the window to be visible or not

    frame: read only property to get the frame of the window

    padding_x: padding on the window around the Frame

    padding_y: padding on the window around the Frame

    flags: the window flags, not that you can pass then on the constructor but also change them after !
        """
        )

        self._caption("ToolBar", navigate_to)

        with ui.ScrollingFrame(height=60, vertical_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF):
            with ui.VStack(height=0):
                with ui.HStack(width=0):
                    ui.Button("ToolBar Example", width=180, clicked_fn=self.create_simple_toolbar)
                    ui.Label("this create a ToolBar Docked at the top", name="text", width=280)
                    ui.Label("""ui.ToolBar("Awesome ToolBar", noTabBar=True)""", name="text")

                with ui.HStack(width=0):
                    ui.Button("Axis changing ToolBar Example", width=180, clicked_fn=self.create_rotating_toolbar)
                    ui.Label("see how the orientation of the toolbar can change", name="text", width=280)
                    ui.Label("""ui.ToolBar("Awesome ToolBar")""", name="text")

        self._text(
            "This file contain a very complete example of many type of toolbar\n" "location is " + __file__ + "\n"
        )

        self._caption("Multiple Modal Windows", navigate_to)

        self._text(
            "Omni::UI supports the conception of multiple modal windows. When the new modal window is created, it "
            "makes other modal windows inactive. And when it's destroyed, the previous modal window becomes active, "
            "blocking all other windows."
        )

        ui.Button("Multiple Modal Windows", clicked_fn=self._on_modal_in_modal_clicked)

        self._caption("Overlay Other Windows", navigate_to)

        self._text(
            "When creating two windows with the same title, only one window will be displayed, and it will contain "
            "the widgets from both windows. This ability allows for overlaying omni.ui Widgets to any ImGui window. "
            "For example, it's possible to add a button to the viewport with creating a new window with the title "
            '"Viewport".'
        )

        def overlay_viewport(self):
            self._overlay_window = None

            def create_overlay_window(self):
                if self._overlay_window:
                    self._overlay_window = None
                else:
                    self._overlay_window = ui.Window("Viewport")
                    with self._overlay_window.frame:
                        with ui.HStack():
                            ui.Spacer()
                            ui.Label("Hello World", width=0)
                            ui.Spacer()

            self._overaly_button = ui.Button(
                "Create or Remove Viewport Label",
                style=self._style_system,
                clicked_fn=lambda: create_overlay_window(self),
            )

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

        self._caption("Workspace", navigate_to)

        class WindowItem(ui.AbstractItem):
            def __init__(self, window):
                super().__init__()
                # Don't keep the window because it prevents the window from closing.
                self._window_title = window.title
                self.title_model = ui.SimpleStringModel(self._window_title)
                self.type_model = ui.SimpleStringModel(type(window).__name__)

            @property
            def window(self):
                return ui.Workspace.get_window(self._window_title)

        class WindowModel(ui.AbstractItemModel):
            def __init__(self):
                super().__init__()
                self._root = ui.SimpleStringModel("Windows")
                self.update()

            def update(self):
                self._children = [WindowItem(i) for i in ui.Workspace.get_windows()]
                self._item_changed(None)

            def get_item_children(self, item):
                if item is not None:
                    return []

                return self._children

            def get_item_value_model_count(self, item):
                return 2

            def get_item_value_model(self, item, column_id):
                if item is None:
                    return self._root

                if column_id == 0:
                    return item.title_model
                if column_id == 1:
                    return item.type_model

        self._window_model = WindowModel()
        self._tree_left = None
        self._tree_right = None

        with ui.VStack(style=self._style_system):
            ui.Button("Refresh", clicked_fn=lambda: self._window_model.update())
            with ui.HStack():
                ui.Button("Clear", clicked_fn=ui.Workspace.clear)
                ui.Button("Focus", clicked_fn=lambda: self._focus(self._tree_left.selection))
            with ui.HStack():
                ui.Button("Visibile", clicked_fn=lambda: self._set_visibility(self._tree_left.selection, True))
                ui.Button("Invisibile", clicked_fn=lambda: self._set_visibility(self._tree_left.selection, False))
                ui.Button("Toggle Visibility", clicked_fn=lambda: self._set_visibility(self._tree_left.selection, None))
            with ui.HStack():
                ui.Button(
                    "Dock Right",
                    clicked_fn=lambda: self._dock(
                        self._tree_left.selection, self._tree_right.selection, ui.DockPosition.RIGHT
                    ),
                )
                ui.Button(
                    "Dock Left",
                    clicked_fn=lambda: self._dock(
                        self._tree_left.selection, self._tree_right.selection, ui.DockPosition.LEFT
                    ),
                )
                ui.Button(
                    "Dock Top",
                    clicked_fn=lambda: self._dock(
                        self._tree_left.selection, self._tree_right.selection, ui.DockPosition.TOP
                    ),
                )
                ui.Button(
                    "Dock Bottom",
                    clicked_fn=lambda: self._dock(
                        self._tree_left.selection, self._tree_right.selection, ui.DockPosition.BOTTOM
                    ),
                )
                ui.Button(
                    "Dock Same",
                    clicked_fn=lambda: self._dock(
                        self._tree_left.selection, self._tree_right.selection, ui.DockPosition.SAME
                    ),
                )
                ui.Button("Undock", clicked_fn=lambda: self._undock(self._tree_left.selection))
            with ui.HStack():
                ui.Button("Move Left", clicked_fn=lambda: self._left(self._tree_left.selection))
                ui.Button("MoveRight", clicked_fn=lambda: self._right(self._tree_left.selection))
            with ui.HStack():
                ui.Button(
                    "Reverse Docking Tabs of Neighbours",
                    clicked_fn=lambda: self._dock_reorder(self._tree_left.selection),
                )
                ui.Button("Hide Tabs", clicked_fn=lambda: self._tabs(self._tree_left.selection, False))
                ui.Button("Show Tabs", clicked_fn=lambda: self._tabs(self._tree_left.selection, True))

        with ui.HStack(height=400):
            with ui.ScrollingFrame(
                horizontal_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF,
                vertical_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_ON,
                style_type_name_override="TreeView",
            ):
                self._tree_left = ui.TreeView(self._window_model, column_widths=[ui.Fraction(1), 80])
            with ui.ScrollingFrame(
                horizontal_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF,
                vertical_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_ON,
                style_type_name_override="TreeView",
            ):
                self._tree_right = ui.TreeView(self._window_model, column_widths=[ui.Fraction(1), 80])

        self._caption("Popup", navigate_to)
        self._text(
            "The Popup window is a window that disappears when the user clicks outside of the window. To create a popup "
            "window, it's necessary to use the flag ui.WINDOW_FLAGS_POPUP. It's very useful for creating a menu with "
            "custom widgets inside."
        )

        self._text("Start typing for popup")

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

        # some padding at the bottom
        ui.Spacer(height=100)

    def _undock(self, selection):
        if not selection:
            return

        for item in selection:
            item.window.undock()

    def _dock(self, left, right, position):
        if not left or not right:
            return

        target = right[0].window

        for item in left:
            item.window.dock_in(target, position)

    def _left(self, selection):
        if not selection:
            return

        for item in selection:
            item.window.position_x -= 100

    def _right(self, selection):
        if not selection:
            return

        for item in selection:
            item.window.position_x += 100

    def _set_visibility(self, selection, visible):
        if not selection:
            return

        for item in selection:
            if visible is not None:
                item.window.visible = visible
            else:
                item.window.visible = not item.window.visible

    def _dock_reorder(self, selection):
        if not selection:
            return

        docking_groups = [ui.Workspace.get_docked_neighbours(item.window) for item in selection]

        for group in docking_groups:
            # Reverse order
            for i, window in enumerate(reversed(group)):
                window.dock_order = i

    def _on_modal_in_modal_clicked(self):
        def close_me(id):
            self._modal_test[id].visible = False

        def put_on_front(id):
            if not self._modal_test[id]:
                return
            self._modal_test[id].set_top_modal()

        def toggle(id):
            if not self._modal_test[id]:
                return
            self._modal_test[id].visible = not self._modal_test[id].visible

        window_id = len(self._modal_test)
        prev_id = max(0, window_id - 1)

        window_flags = ui.WINDOW_FLAGS_NO_RESIZE
        window_flags |= ui.WINDOW_FLAGS_NO_SCROLLBAR
        window_flags |= ui.WINDOW_FLAGS_MODAL

        modal_window = ui.Window(f"Modal Window #{window_id}", width=200, height=200, flags=window_flags)
        self._modal_test.append(modal_window)

        with modal_window.frame:
            with ui.VStack(height=0):
                ui.Label(f"This is the window #{window_id}")
                ui.Button("One Modal More", clicked_fn=self._on_modal_in_modal_clicked)
                ui.Button(f"Bring #{prev_id} To Top", clicked_fn=lambda id=prev_id: put_on_front(id))
                ui.Button(f"Toggle visibility of #{prev_id}", clicked_fn=lambda id=prev_id: toggle(id))
                ui.Button("Close", clicked_fn=lambda id=window_id: close_me(id))
