"""Module used to build consistent UI for Colorium's tools using maya.cmds."""

import maya.cmds as cmds
import colorium.data_binding as data_binding


class CUI(object):
    """Base class for a Colorium UI."""

    @property
    def name(self):
        """The name of the UI."""

        return self._name

    @name.setter
    def name(self, value):
        self._name = value


    @property
    def controller(self):
        """The controller associated with the UI."""

        return self._controller

    @controller.setter
    def controller(self, value):
        self._controller = value


    @property
    def main_window(self):
        """The name of the UI's main window."""

        return self._main_window

    @main_window.setter
    def main_window(self, value):
        self._main_window = value


    @property
    def main_frame(self):
        """The name of the UI's main frame."""

        return self._main_frame

    @main_frame.setter
    def main_frame(self, value):
        self._main_frame = value


    @property
    def main_layout(self):
        """The name of the UI's main layout."""

        return self._main_layout

    @main_layout.setter
    def main_layout(self, value):
        self._main_layout = value


    def __init__(self, name, controller):
        self._controls = []

        self._name = name
        self._controller = None
        self._main_window = ''
        self._main_frame = ''
        self._main_layout = ''

        if not self._controller or self._controller != controller:
            self._controller = controller
            self._controller.ui = self

        self.display_ui(self._controller.display_ui_callback)


    def display_ui(self, callback):
        """
        Displays the tool's UI.
        """

        self.build_main_window()
        self.build_main_layout()
        self.build_ui()

        for control in self._controls:
            control.build_ui()

        callback()


    def build_ui(self):
        """
        Builds the tool's UI.
        """

        pass


    def add_control(self, control):
        """Adds a control to the UI's controls."""

        if control not in self._controls:
            self._controls.append(control)


    def remove_control(self, control):
        """Removes a control from the UI's controls."""

        if control in self._controls:
            self._controls.remove(control)


    def get_control_by_name(self, name):
        """Returns a control from the UI's controls by it's name."""

        for control in self._controls:
            if control.name == name:
                return control


    def build_main_window(self):
        """Builds the main window."""

        self._main_window = self.build_window("win_main", self._name)


    def build_window(self, name="untitled", title="untitled"):
        """Helper function that builds a window using maya.cmds."""

        window_exists = cmds.window(name, q=True, ex=True)

        if window_exists:
            cmds.deleteUI(name, window=True)

        window = cmds.window(name, t=title, rtf=True, tlb=True)

        cmds.showWindow(window)

        return window


    def build_main_layout(self):
        """Builds the main layout."""

        self._main_frame = cmds.frameLayout("frm_main", p=self._main_window, lv=False, mh=5, mw=5)
        self._main_layout = cmds.columnLayout("lay_main", p=self._main_frame, adj=True)


class CController(object):
    """Base class for a Colorium UI Controller."""

    @property
    def ui(self):
        """The UI associated with the controller."""
        return self._ui

    @ui.setter
    def ui(self, value):
        self._ui = value


    def __init__(self):
        self._ui = None


    def display_ui_callback(self):
        """Called at the end of the method Display of the associated UI instance. Used for post-display operations."""

        pass


class CToggleable():
    """\"Interface\" used to define toggleable controls."""

    def toggle(self, value):
        """Method used to enable/disable the control."""

        pass


class CUIElement(object):
    """Base class for a Colorium UI Element."""

    @property
    def name(self):
        """The name of the CUIElement."""

        return self._name

    @name.setter
    def name(self, value):
        self._name = value


    @property
    def title(self):
        """The title of the CUIElement."""

        return self._title

    @title.setter
    def title(self, value):
        self._title = value


    @property
    def parent(self):
        """The name of the CUIElement's parent."""

        return self._parent

    @parent.setter
    def parent(self, value):
        self._parent = value


    def __init__(self, name, title, parent):
        self._name = name
        self._title = title
        self._parent = parent


class CLayout(CUIElement):
    """Base class for a Colorium UI Layout."""

    def __init__(self, name, title, parent, childrens=None):
        super(CLayout, self).__init__(name, title, parent)

        self._childrens = childrens if childrens else []


    def add_children(self, children):
        """Add a given children to the CLayout's childrens."""

        if children not in self._childrens:
            self._childrens.append(children)


    def remove_children(self, children):
        """Remove a given children from the CLayout's childrens."""

        if children in self._childrens:
            self._childrens.remove(children)


class CControl(CUIElement, data_binding.CBindable):
    """Base class for a Colorium UI Control."""

    def __init__(self, name, title, parent):
        super(CControl, self).__init__(name, title, parent)
        data_binding.CBindable.__init__(self)


    def build_ui(self):
        """Method used to build the control's UI."""

        pass


class CInlineLayout(CLayout):
    """Class representing an Inline Layout. It's childrens are placed side by side, aligned on the left or on the right."""

    def __init__(self, name, title, parent, childrens=None, align="left"):
        super(CInlineLayout, self).__init__(name, title, parent)

        self._childrens = childrens if childrens else []
        self._align = align


    def build_ui(self):
        """Method used to build the control's UI."""

        align_offset = 0
        align_adjustement_column = len(self._childrens) + 1
        if self._align == "right":
            align_offset = 1
            align_adjustement_column = 1

        column_attachments = []
        for children in range(1 + align_offset, len(self._childrens) + 1 + align_offset):
            if children == 1 + align_offset:
                column_attachments.append((children, "right", 2.5))
            elif children == len(self._childrens) + align_offset:
                column_attachments.append((children, "left", 2.5))
            else:
                column_attachments.append((children, "both", 2.5))

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=len(self._childrens) + 1, cat=column_attachments, adj=align_adjustement_column)

        if self._align == "right":
            cmds.separator("sep_{}".format(self._name), vis=False)

        if self._childrens:
            for children in self._childrens:
                children.parent = layout
                children.build_ui()

        if self._align == "left":
            cmds.separator("sep_{}".format(self._name), vis=False)


class CTextInput(CControl, CToggleable):
    """Class that represents a Text Input. Used to write text."""

    @property
    def text(self):
        """The text written in the Text Input."""

        return self.__text

    @text.setter
    def text(self, value):
        self.__text = value

        cmds.textField("txt_{}".format(self._name), e=True, tx=value)

        self.notify_property_changed("text", value)
        print('\'text\' property of CTextInput set to \'{}\'').format(value)


    @property
    def enabled(self):
        """The state of the Text Input."""

        return self.__enabled

    @enabled.setter
    def enabled(self, value):
        self.__enabled = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)
        cmds.control("txt_{}".format(self._name), e=True, en=value)

        self.notify_property_changed("enabled", value)
        print('\'enabled\' property of CTextInput set to \'{}\'').format(value)


    def __init__(self, name, title, parent, enabled=True, changed_command=None, toggle_command=None, toggleable=False, default_value=""):
        super(CTextInput, self).__init__(name, title, parent)

        self.__text = default_value
        self.__enabled = enabled
        self.__toggleable = toggleable
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented
        self.__toggle_command = toggle_command if toggle_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=3, cat=[(2, "right", 5)], cw=[(1, 25), (2, 100)], adj=3)

        if self.__toggleable:
            cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__enabled, cc=self.toggle)
        else:
            cmds.separator("sep_{}".format(self._name), vis=False)

        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.textField("txt_{}".format(self._name), p=layout, tx=self.__text, en=self.__enabled, cc=self.text_changed)


    def text_changed(self, value):
        """Method called when the Text Input's text changed."""

        self.__changed_command(value)

        self.text = value


    def toggle(self, value):
        """Method called when the Text Input's state changed."""

        self.__toggle_command(value)

        self.enabled = value

        cmds.control("txt_{}".format(self._name), e=True, en=value)


class CIntInput(CControl, CToggleable):
    """Class that represents a Int Input. Used to write numbers."""

    @property
    def value(self):
        """The number written in the Int Input."""

        return self.__value

    @value.setter
    def value(self, value):
        self.__value = value

        cmds.intSliderGrp("int_{}".format(self._name), e=True, v=value)

        self.notify_property_changed("value", value)
        print('\'value\' property of CIntInput set to \'{}\'').format(value)


    @property
    def enabled(self):
        """The state of the Int Input."""

        return self.__enabled

    @enabled.setter
    def enabled(self, value):
        self.__enabled = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)
        cmds.control("int_{}".format(self._name), e=True, en=value)

        self.notify_property_changed("enabled", value)
        print('\'enabled\' property of CIntInput set to \'{}\'').format(value)


    def __init__(self, name, title, parent, enabled=True, min_value=1, max_value=10, changed_command=None, toggle_command=None, toggleable=False, default_value=1):
        super(CIntInput, self).__init__(name, title, parent)

        self.__value = default_value
        self.__enabled = enabled
        self.__toggleable = toggleable
        self.__min = min_value
        self.__max = max_value
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented
        self.__toggle_command = toggle_command if toggle_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=3, cat=[(2, "right", 5)], cw=[(1, 25), (2, 100)], adj=3)

        if self.__toggleable:
            cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__enabled, cc=self.toggle)
        else:
            cmds.separator("sep_{}".format(self._name), vis=False)

        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.intSliderGrp("int_{}".format(self._name), p=layout, v=self.__value, f=True, min=self.__min, max=self.__max, en=self.__enabled, cc=self.value_changed)


    def value_changed(self, value):
        """Method called when the Int Input's value changed."""

        self.__changed_command(value)

        self.value = value


    def toggle(self, value):
        """Method called when the Int Input's state changed."""

        self.__toggle_command(value)

        self.enabled = value

        cmds.control("int_{}".format(self._name), e=True, en=value)


class CComboInput(CControl, CToggleable):
    """Class that represents a Combo Input. Used to choose a value from a list of values."""

    @property
    def value(self):
        """The chosen value of the Combo Input."""

        return self.__value

    @value.setter
    def value(self, value):
        self.__value = value

        cmds.optionMenu("cmb_{}".format(self._name), e=True, v=value)

        self.notify_property_changed("value", value)
        print('\'value\' property of CComboInput set to \'{}\'').format(value)


    @property
    def enabled(self):
        """The state of the Combo Input."""

        return self.__enabled

    @enabled.setter
    def enabled(self, value):
        self.__enabled = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)
        cmds.control("cmb_{}".format(self._name), e=True, en=value)

        self.notify_property_changed("enabled", value)
        print('\'enabled\' property of CComboInput set to \'{}\'').format(value)


    def __init__(self, name, title, parent, enabled=True, items=None, changed_command=None, toggle_command=None, toggleable=False, default_value=""):
        super(CComboInput, self).__init__(name, title, parent)

        self.__value = default_value
        self.__enabled = enabled
        self.__toggleable = toggleable
        self.__items = items if items else []
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented
        self.__toggle_command = toggle_command if toggle_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=3, cat=[(2, "right", 5)], cw=[(1, 25), (2, 100)], adj=3)

        if self.__toggleable:
            cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__enabled, cc=self.toggle)
        else:
            cmds.separator("sep_{}".format(self._name), vis=False)

        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.optionMenu("cmb_{}".format(self._name), p=layout, en=self.__enabled, cc=self.value_changed)

        for item in self.__items:
            cmds.menuItem("itm_{}_{}".format(self._name, item), l=item)

        if self.__value in self.__items:
            cmds.optionMenu("cmb_{}".format(self._name), e=True, v=self.__value)


    def value_changed(self, value):
        """Method called when the Combo Input's value changed."""

        self.__changed_command(value)

        self.value = value


    def toggle(self, value):
        """Method called when the Combo Input's state changed."""

        self.__toggle_command(value)

        self.enabled = value

        cmds.control("cmb_{}".format(self._name), e=True, en=value)


class CFilePathInput(CControl, CToggleable):
    """Class that represents a File Path Input. Used to write a file path and open it in the explorer."""

    @property
    def text(self):
        """The file path written in the File Path Input."""

        return self.__text

    @text.setter
    def text(self, value):
        self.__text = value

        cmds.textField("txt_{}".format(self._name), e=True, tx=value)

        self.notify_property_changed("text", value)
        print('\'text\' property of CFilePathInput set to \'{}\'').format(value)


    @property
    def enabled(self):
        """The state of the File Path Input."""

        return self.__enabled

    @enabled.setter
    def enabled(self, value):
        self.__enabled = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)
        cmds.control("txt_{}".format(self._name), e=True, en=value)

        self.notify_property_changed("enabled", value)
        print('\'enabled\' property of CFilePathInput set to \'{}\'').format(value)


    def __init__(self, name, title, parent, enabled=True, changed_command=None, open_command=None, toggle_command=None, toggleable=False, default_value=""):
        super(CFilePathInput, self).__init__(name, title, parent)

        self.__text = default_value
        self.__enabled = enabled
        self.__toggleable = toggleable
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented
        self.__open_command = open_command if open_command else lambda value: NotImplemented
        self.__toggle_command = toggle_command if toggle_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=4, cat=[(2, "right", 5), (4, "left", 5)], cw=[(1, 25), (2, 100), (4, 100)], adj=3)

        if self.__toggleable:
            cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__enabled, cc=self.toggle)
        else:
            cmds.separator("sep_{}".format(self._name), vis=False)

        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.textField("txt_{}".format(self._name), p=layout, tx=self.__text, en=self.__enabled, cc=self.text_changed)
        cmds.button("btn_open_{}".format(self._name), p=layout, l="Open", w=60, c=self.__open_command)


    def text_changed(self, value):
        """Method called when the File Path Input's value changed."""

        self.__changed_command(value)

        self.text = value


    def toggle(self, value):
        """Method called when the File Path Input's state changed."""

        self.__toggle_command(value)

        self.enabled = value

        cmds.control("txt_{}".format(self._name), e=True, en=value)


class CButtonControl(CControl):
    """Class that represents a Button Control. Used to execute a command."""

    def __init__(self, name, title, parent, command=None):
        super(CButtonControl, self).__init__(name, title, parent)

        self._command = command if command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        cmds.button("btn_{}".format(self._name), l=self._title, p=self._parent, w=60, c=self._command)


class CCheckControl(CControl):
    """Class that represents a Check Controle. Used to be turned on or off."""

    @property
    def value(self):
        """The value of the Check Control."""

        return self.__value

    @value.setter
    def value(self, value):
        self.__value = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)

        self.notify_property_changed("value", value)
        print('\'value\' property of CCheckControl set to \'{}\'').format(value)


    def __init__(self, name, title, parent, changed_command=None, default_value=False):
        super(CCheckControl, self).__init__(name, title, parent)

        self.__value = default_value
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=3, cat=[(2, "right", 5)], cw=[(1, 25), (2, 100)], adj=3)

        cmds.separator("sep_{}".format(self._name), vis=False)
        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__value, cc=self.value_changed)


    def value_changed(self, value):
        """Method called when the Check Control's value changed."""

        self.__changed_command(value)

        self.value = value

"""Module used to build consistent UI for Colorium's tools using maya.cmds."""

import maya.cmds as cmds
import colorium.data_binding as data_binding


class CUI(object):
    """Base class for a Colorium UI."""

    @property
    def name(self):
        """The name of the UI."""

        return self._name

    @name.setter
    def name(self, value):
        self._name = value


    @property
    def controller(self):
        """The controller associated with the UI."""

        return self._controller

    @controller.setter
    def controller(self, value):
        self._controller = value


    @property
    def main_window(self):
        """The name of the UI's main window."""

        return self._main_window

    @main_window.setter
    def main_window(self, value):
        self._main_window = value


    @property
    def main_frame(self):
        """The name of the UI's main frame."""

        return self._main_frame

    @main_frame.setter
    def main_frame(self, value):
        self._main_frame = value


    @property
    def main_layout(self):
        """The name of the UI's main layout."""

        return self._main_layout

    @main_layout.setter
    def main_layout(self, value):
        self._main_layout = value


    def __init__(self, name, controller):
        self._controls = []

        self._name = name
        self._controller = None
        self._main_window = ''
        self._main_frame = ''
        self._main_layout = ''

        if not self._controller or self._controller != controller:
            self._controller = controller
            self._controller.ui = self

        self.display_ui(self._controller.display_ui_callback)


    def display_ui(self, callback):
        """
        Displays the tool's UI.
        """

        self.build_main_window()
        self.build_main_layout()
        self.build_ui()

        for control in self._controls:
            control.build_ui()

        callback()


    def build_ui(self):
        """
        Builds the tool's UI.
        """

        pass


    def add_control(self, control):
        """Adds a control to the UI's controls."""

        if control not in self._controls:
            self._controls.append(control)


    def remove_control(self, control):
        """Removes a control from the UI's controls."""

        if control in self._controls:
            self._controls.remove(control)


    def get_control_by_name(self, name):
        """Returns a control from the UI's controls by it's name."""

        for control in self._controls:
            if control.name == name:
                return control


    def build_main_window(self):
        """Builds the main window."""

        self._main_window = self.build_window("win_main", self._name)


    def build_window(self, name="untitled", title="untitled"):
        """Helper function that builds a window using maya.cmds."""

        window_exists = cmds.window(name, q=True, ex=True)

        if window_exists:
            cmds.deleteUI(name, window=True)

        window = cmds.window(name, t=title, rtf=True, tlb=True)

        cmds.showWindow(window)

        return window


    def build_main_layout(self):
        """Builds the main layout."""

        self._main_frame = cmds.frameLayout("frm_main", p=self._main_window, lv=False, mh=5, mw=5)
        self._main_layout = cmds.columnLayout("lay_main", p=self._main_frame, adj=True)


class CController(object):
    """Base class for a Colorium UI Controller."""

    @property
    def ui(self):
        """The UI associated with the controller."""
        return self._ui

    @ui.setter
    def ui(self, value):
        self._ui = value


    def __init__(self):
        self._ui = None


    def display_ui_callback(self):
        """Called at the end of the method Display of the associated UI instance. Used for post-display operations."""

        pass


class CToggleable():
    """\"Interface\" used to define toggleable controls."""

    def toggle(self, value):
        """Method used to enable/disable the control."""

        pass


class CUIElement(object):
    """Base class for a Colorium UI Element."""

    @property
    def name(self):
        """The name of the CUIElement."""

        return self._name

    @name.setter
    def name(self, value):
        self._name = value


    @property
    def title(self):
        """The title of the CUIElement."""

        return self._title

    @title.setter
    def title(self, value):
        self._title = value


    @property
    def parent(self):
        """The name of the CUIElement's parent."""

        return self._parent

    @parent.setter
    def parent(self, value):
        self._parent = value


    def __init__(self, name, title, parent):
        self._name = name
        self._title = title
        self._parent = parent


class CLayout(CUIElement):
    """Base class for a Colorium UI Layout."""

    def __init__(self, name, title, parent, childrens=None):
        super(CLayout, self).__init__(name, title, parent)

        self._childrens = childrens if childrens else []


    def add_children(self, children):
        """Add a given children to the CLayout's childrens."""

        if children not in self._childrens:
            self._childrens.append(children)


    def remove_children(self, children):
        """Remove a given children from the CLayout's childrens."""

        if children in self._childrens:
            self._childrens.remove(children)


class CControl(CUIElement, data_binding.CBindable):
    """Base class for a Colorium UI Control."""

    def __init__(self, name, title, parent):
        super(CControl, self).__init__(name, title, parent)
        data_binding.CBindable.__init__(self)


    def build_ui(self):
        """Method used to build the control's UI."""

        pass


class CInlineLayout(CLayout):
    """Class representing an Inline Layout. It's childrens are placed side by side, aligned on the left or on the right."""

    def __init__(self, name, title, parent, childrens=None, align="left"):
        super(CInlineLayout, self).__init__(name, title, parent)

        self._childrens = childrens if childrens else []
        self._align = align


    def build_ui(self):
        """Method used to build the control's UI."""

        align_offset = 0
        align_adjustement_column = len(self._childrens) + 1
        if self._align == "right":
            align_offset = 1
            align_adjustement_column = 1

        column_attachments = []
        for children in range(1 + align_offset, len(self._childrens) + 1 + align_offset):
            if children == 1 + align_offset:
                column_attachments.append((children, "right", 2.5))
            elif children == len(self._childrens) + align_offset:
                column_attachments.append((children, "left", 2.5))
            else:
                column_attachments.append((children, "both", 2.5))

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=len(self._childrens) + 1, cat=column_attachments, adj=align_adjustement_column)

        if self._align == "right":
            cmds.separator("sep_{}".format(self._name), vis=False)

        if self._childrens:
            for children in self._childrens:
                children.parent = layout
                children.build_ui()

        if self._align == "left":
            cmds.separator("sep_{}".format(self._name), vis=False)


class CTextInput(CControl, CToggleable):
    """Class that represents a Text Input. Used to write text."""

    @property
    def text(self):
        """The text written in the Text Input."""

        return self.__text

    @text.setter
    def text(self, value):
        self.__text = value

        cmds.textField("txt_{}".format(self._name), e=True, tx=value)

        self.notify_property_changed("text", value)
        print('\'text\' property of CTextInput set to \'{}\'').format(value)


    @property
    def enabled(self):
        """The state of the Text Input."""

        return self.__enabled

    @enabled.setter
    def enabled(self, value):
        self.__enabled = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)
        cmds.control("txt_{}".format(self._name), e=True, en=value)

        self.notify_property_changed("enabled", value)
        print('\'enabled\' property of CTextInput set to \'{}\'').format(value)


    def __init__(self, name, title, parent, enabled=True, changed_command=None, toggle_command=None, toggleable=False, default_value=""):
        super(CTextInput, self).__init__(name, title, parent)

        self.__text = default_value
        self.__enabled = enabled
        self.__toggleable = toggleable
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented
        self.__toggle_command = toggle_command if toggle_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=3, cat=[(2, "right", 5)], cw=[(1, 25), (2, 100)], adj=3)

        if self.__toggleable:
            cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__enabled, cc=self.toggle)
        else:
            cmds.separator("sep_{}".format(self._name), vis=False)

        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.textField("txt_{}".format(self._name), p=layout, tx=self.__text, en=self.__enabled, cc=self.text_changed)


    def text_changed(self, value):
        """Method called when the Text Input's text changed."""

        self.__changed_command(value)

        self.text = value


    def toggle(self, value):
        """Method called when the Text Input's state changed."""

        self.__toggle_command(value)

        self.enabled = value

        cmds.control("txt_{}".format(self._name), e=True, en=value)


class CIntInput(CControl, CToggleable):
    """Class that represents a Int Input. Used to write numbers."""

    @property
    def value(self):
        """The number written in the Int Input."""

        return self.__value

    @value.setter
    def value(self, value):
        self.__value = value

        cmds.intSliderGrp("int_{}".format(self._name), e=True, v=value)

        self.notify_property_changed("value", value)
        print('\'value\' property of CIntInput set to \'{}\'').format(value)


    @property
    def enabled(self):
        """The state of the Int Input."""

        return self.__enabled

    @enabled.setter
    def enabled(self, value):
        self.__enabled = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)
        cmds.control("int_{}".format(self._name), e=True, en=value)

        self.notify_property_changed("enabled", value)
        print('\'enabled\' property of CIntInput set to \'{}\'').format(value)


    def __init__(self, name, title, parent, enabled=True, min_value=1, max_value=10, changed_command=None, toggle_command=None, toggleable=False, default_value=1):
        super(CIntInput, self).__init__(name, title, parent)

        self.__value = default_value
        self.__enabled = enabled
        self.__toggleable = toggleable
        self.__min = min_value
        self.__max = max_value
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented
        self.__toggle_command = toggle_command if toggle_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=3, cat=[(2, "right", 5)], cw=[(1, 25), (2, 100)], adj=3)

        if self.__toggleable:
            cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__enabled, cc=self.toggle)
        else:
            cmds.separator("sep_{}".format(self._name), vis=False)

        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.intSliderGrp("int_{}".format(self._name), p=layout, v=self.__value, f=True, min=self.__min, max=self.__max, en=self.__enabled, cc=self.value_changed)


    def value_changed(self, value):
        """Method called when the Int Input's value changed."""

        self.__changed_command(value)

        self.value = value


    def toggle(self, value):
        """Method called when the Int Input's state changed."""

        self.__toggle_command(value)

        self.enabled = value

        cmds.control("int_{}".format(self._name), e=True, en=value)


class CComboInput(CControl, CToggleable):
    """Class that represents a Combo Input. Used to choose a value from a list of values."""

    @property
    def value(self):
        """The chosen value of the Combo Input."""

        return self.__value

    @value.setter
    def value(self, value):
        self.__value = value

        cmds.optionMenu("cmb_{}".format(self._name), e=True, v=value)

        self.notify_property_changed("value", value)
        print('\'value\' property of CComboInput set to \'{}\'').format(value)


    @property
    def enabled(self):
        """The state of the Combo Input."""

        return self.__enabled

    @enabled.setter
    def enabled(self, value):
        self.__enabled = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)
        cmds.control("cmb_{}".format(self._name), e=True, en=value)

        self.notify_property_changed("enabled", value)
        print('\'enabled\' property of CComboInput set to \'{}\'').format(value)


    def __init__(self, name, title, parent, enabled=True, items=None, changed_command=None, toggle_command=None, toggleable=False, default_value=""):
        super(CComboInput, self).__init__(name, title, parent)

        self.__value = default_value
        self.__enabled = enabled
        self.__toggleable = toggleable
        self.__items = items if items else []
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented
        self.__toggle_command = toggle_command if toggle_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=3, cat=[(2, "right", 5)], cw=[(1, 25), (2, 100)], adj=3)

        if self.__toggleable:
            cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__enabled, cc=self.toggle)
        else:
            cmds.separator("sep_{}".format(self._name), vis=False)

        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.optionMenu("cmb_{}".format(self._name), p=layout, en=self.__enabled, cc=self.value_changed)

        for item in self.__items:
            cmds.menuItem("itm_{}_{}".format(self._name, item), l=item)

        if self.__value in self.__items:
            cmds.optionMenu("cmb_{}".format(self._name), e=True, v=self.__value)


    def value_changed(self, value):
        """Method called when the Combo Input's value changed."""

        self.__changed_command(value)

        self.value = value


    def toggle(self, value):
        """Method called when the Combo Input's state changed."""

        self.__toggle_command(value)

        self.enabled = value

        cmds.control("cmb_{}".format(self._name), e=True, en=value)


class CFilePathInput(CControl, CToggleable):
    """Class that represents a File Path Input. Used to write a file path and open it in the explorer."""

    @property
    def text(self):
        """The file path written in the File Path Input."""

        return self.__text

    @text.setter
    def text(self, value):
        self.__text = value

        cmds.textField("txt_{}".format(self._name), e=True, tx=value)

        self.notify_property_changed("text", value)
        print('\'text\' property of CFilePathInput set to \'{}\'').format(value)


    @property
    def enabled(self):
        """The state of the File Path Input."""

        return self.__enabled

    @enabled.setter
    def enabled(self, value):
        self.__enabled = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)
        cmds.control("txt_{}".format(self._name), e=True, en=value)

        self.notify_property_changed("enabled", value)
        print('\'enabled\' property of CFilePathInput set to \'{}\'').format(value)


    def __init__(self, name, title, parent, enabled=True, changed_command=None, open_command=None, toggle_command=None, toggleable=False, default_value=""):
        super(CFilePathInput, self).__init__(name, title, parent)

        self.__text = default_value
        self.__enabled = enabled
        self.__toggleable = toggleable
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented
        self.__open_command = open_command if open_command else lambda value: NotImplemented
        self.__toggle_command = toggle_command if toggle_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=4, cat=[(2, "right", 5), (4, "left", 5)], cw=[(1, 25), (2, 100), (4, 100)], adj=3)

        if self.__toggleable:
            cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__enabled, cc=self.toggle)
        else:
            cmds.separator("sep_{}".format(self._name), vis=False)

        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.textField("txt_{}".format(self._name), p=layout, tx=self.__text, en=self.__enabled, cc=self.text_changed)
        cmds.button("btn_open_{}".format(self._name), p=layout, l="Open", w=60, c=self.__open_command)


    def text_changed(self, value):
        """Method called when the File Path Input's value changed."""

        self.__changed_command(value)

        self.text = value


    def toggle(self, value):
        """Method called when the File Path Input's state changed."""

        self.__toggle_command(value)

        self.enabled = value

        cmds.control("txt_{}".format(self._name), e=True, en=value)


class CButtonControl(CControl):
    """Class that represents a Button Control. Used to execute a command."""

    def __init__(self, name, title, parent, command=None):
        super(CButtonControl, self).__init__(name, title, parent)

        self._command = command if command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        cmds.button("btn_{}".format(self._name), l=self._title, p=self._parent, w=60, c=self._command)


class CCheckControl(CControl):
    """Class that represents a Check Controle. Used to be turned on or off."""

    @property
    def value(self):
        """The value of the Check Control."""

        return self.__value

    @value.setter
    def value(self, value):
        self.__value = value

        cmds.checkBox("chk_{}".format(self._name), e=True, v=value)

        self.notify_property_changed("value", value)
        print('\'value\' property of CCheckControl set to \'{}\'').format(value)


    def __init__(self, name, title, parent, changed_command=None, default_value=False):
        super(CCheckControl, self).__init__(name, title, parent)

        self.__value = default_value
        self.__changed_command = changed_command if changed_command else lambda value: NotImplemented


    def build_ui(self):
        """Method used to build the control's UI."""

        layout = cmds.rowLayout("lay_{}".format(self._name), p=self._parent, nc=3, cat=[(2, "right", 5)], cw=[(1, 25), (2, 100)], adj=3)

        cmds.separator("sep_{}".format(self._name), vis=False)
        cmds.text("lbl_{}".format(self._name), p=layout, l=self._title, al="right")
        cmds.checkBox("chk_{}".format(self._name), p=layout, l="", v=self.__value, cc=self.value_changed)


    def value_changed(self, value):
        """Method called when the Check Control's value changed."""

        self.__changed_command(value)

        self.value = value

Module used to build consistent UI for Colorium's tools using maya.cmds. Base class for a Colorium UI. The name of the UI. The controller associated with the UI. The name of the UI's main window. The name of the UI's main frame. The name of the UI's main layout. Displays the tool's UI. Builds the tool's UI. Adds a control to the UI's controls. Removes a control from the UI's controls. Returns a control from the UI's controls by it's name. Builds the main window. Helper function that builds a window using maya.cmds. Builds the main layout. Base class for a Colorium UI Controller. The UI associated with the controller. Called at the end of the method Display of the associated UI instance. Used for post-display operations. \"Interface\" used to define toggleable controls. Method used to enable/disable the control. Base class for a Colorium UI Element. The name of the CUIElement. The title of the CUIElement. The name of the CUIElement's parent. Base class for a Colorium UI Layout. Add a given children to the CLayout's childrens. Remove a given children from the CLayout's childrens. Base class for a Colorium UI Control. Method used to build the control's UI. Class representing an Inline Layout. It's childrens are placed side by side, aligned on the left or on the right. Method used to build the control's UI. Class that represents a Text Input. Used to write text. The text written in the Text Input. The state of the Text Input. Method used to build the control's UI. Method called when the Text Input's text changed. Method called when the Text Input's state changed. Class that represents a Int Input. Used to write numbers. The number written in the Int Input. The state of the Int Input. Method used to build the control's UI. Method called when the Int Input's value changed. Method called when the Int Input's state changed. Class that represents a Combo Input. Used to choose a value from a list of values. The chosen value of the Combo Input. The state of the Combo Input. Method used to build the control's UI. Method called when the Combo Input's value changed. Method called when the Combo Input's state changed. Class that represents a File Path Input. Used to write a file path and open it in the explorer. The file path written in the File Path Input. The state of the File Path Input. Method used to build the control's UI. Method called when the File Path Input's value changed. Method called when the File Path Input's state changed. Class that represents a Button Control. Used to execute a command. Method used to build the control's UI. Class that represents a Check Controle. Used to be turned on or off. The value of the Check Control. Method used to build the control's UI. Method called when the Check Control's value changed.