import muUtils
import muLicenseDialog
import importlib
import muLicenseStatus

importlib.reload(muUtils)
importlib.reload(muLicenseDialog)
importlib.reload(muLicenseStatus)

from functools import partial
from qt import QtWidgets, QtCore, QtGui, toQtObject
import maya.OpenMayaUI as omui
import maya.cmds as cmds
import maya.mel as mel
import webbrowser
import os

module_path = cmds.moduleInfo(path=True, moduleName="mush3d")
icon_folder = module_path + "/icons/"

bnt_style = """
    QPushButton, QToolButton {
        background-color: #5e5e5e;
        border: 1px solid #5a5a5a;
        border-radius: 4px;
        padding: 4px;
        color: white;
    }

    QPushButton:hover, QToolButton:hover {
        background-color: #676767;
        border: 1px solid #777;
    }

    QPushButton:pressed, QToolButton:pressed {
        background-color: #1f1f1f;
        border: 1px solid #888;
    }

    QPushButton:checked, QToolButton:checked {
        background-color: #2d2d2d;
        border: 1px solid #aaa;
    }
"""

bnt_transparent_style = """
    QToolButton {
        background-color: transparent;
        border: none;
        border-radius: 0px;
        padding: 0px;
    }
    QToolButton:hover {
        background-color: rgba(255, 255, 255, 0.1);  /* subtle hover if you want */
    }
    QToolButton:pressed {
        background-color: rgba(255, 255, 255, 0.2);
    }
"""

def create_button(image, size, func, tool_tip):
    bnt = QtWidgets.QPushButton()
    bnt.setIcon(QtGui.QIcon(icon_folder + image))
    bnt.setIconSize(size)
    bnt.setToolTip(tool_tip)
    bnt.clicked.connect(func)
    bnt.setStyleSheet(bnt_style)
    return bnt

class BrushBar(QtWidgets.QWidget):
    brushSelected = QtCore.Signal(str)

    def __init__(self, parent=None):
        super(BrushBar, self).__init__(parent)

        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(2)

        self.deformer = None

        self.buttons = {}
        brush_names = ["clay", "move", "crease", "inflate", "clone", "wrinkle", "vector", "erase", "mask" ]
        module_path = cmds.moduleInfo(path=True, moduleName="mush3d")
        icon_path = module_path + "/icons"

        for brush_name in brush_names:
            icon_file = icon_path + "/mu_" + brush_name + ".png"
            btn = QtWidgets.QPushButton()
            btn.setCheckable(True)
            btn.setIcon(QtGui.QIcon(icon_file))
            btn.setIconSize(QtCore.QSize(32, 32))
            btn.setToolTip(brush_name)
            btn.setFixedSize(36, 36)
            btn.clicked.connect(partial(self.select_brush, brush_name))
            btn.setStyleSheet(bnt_style)
            layout.addWidget(btn, alignment=QtCore.Qt.AlignHCenter)
            self.buttons[brush_name] = btn

        layout.addStretch()

    def select_brush(self, brush_name):
        # deselect all
        for other_name, btn in self.buttons.items():
            btn.setChecked(False)

        if not muUtils.is_deformer_valid(self.deformer):
            cmds.warning("deformer not set.")
            return

        indices = muUtils.get_selected_layers_indices(self.deformer)

        if not indices or len(indices) != 1:
            cmds.warning("Select a single layer to sculpt.")
            return

        for other_name, btn in self.buttons.items():
            btn.setChecked(other_name == brush_name)

        symmetry = muUtils.get_symmetry()

        ctx = cmds.currentCtx()
        if "mush3dCtxCmd" in ctx:
            cmds.mush3dCtxCmd(ctx, edit=True, brushName=brush_name)
        else:
            ctx = cmds.mush3dCtxCmd(deformer=self.deformer, brushName=brush_name, symmetry=int(symmetry))
            cmds.setToolTo(ctx)

        muUtils.set_opacity(muUtils.get_opacity())

        self.brushSelected.emit(brush_name)

    def setDeformer(self, deformer):
        self.deformer = deformer

    def unselectAllButtons(self):
        for btn in self.buttons.values():
            btn.blockSignals(True)
            btn.setChecked(False)
            btn.blockSignals(False)

class SelectDeformerGrp(QtWidgets.QWidget):
    deformerSelected = QtCore.Signal(str)

    def __init__(self, parent=None):
        super(SelectDeformerGrp, self).__init__(parent)
        self.build_ui()
        self.deformer = None
    def setDeformer(self, deformer):
        if deformer and cmds.ls(deformer, type="muCorrectiveShape"):
            self.deformer = deformer
            self.field.setText(deformer)
            self.deformerSelected.emit(deformer)
        else:
            self.deformer = None
            self.field.setText("")

    def currentDeformer(self):
        return getattr(self, 'deformer', None)

    def build_ui(self):
        layout = QtWidgets.QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        label = QtWidgets.QLabel("Deformer:")
        layout.addWidget(label)

        self.field = QtWidgets.QLineEdit()
        self.field.setReadOnly(True)
        layout.addWidget(self.field)

        self.menu = QtWidgets.QMenu(self)

        bnt_size = QtCore.QSize(22, 22)

        self.pick = QtWidgets.QToolButton()
        self.pick.setStyleSheet(bnt_transparent_style)
        self.pick.setAutoRaise(True)
        self.pick.setPopupMode(QtWidgets.QToolButton.DelayedPopup)
        self.pick.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        self.pick.setIconSize(bnt_size)
        self.pick.setIcon(QtGui.QIcon(icon_folder + "mu_pickDeformer.png"))
        self.pick.clicked.connect(self.show_menu)
        self.pick.setToolTip("Select or create a mush3d deformer.")

        trash = QtWidgets.QToolButton()
        trash.setStyleSheet(bnt_transparent_style)
        trash.setIconSize(bnt_size)
        trash.setIcon(QtGui.QIcon(icon_folder + "mu_trash.png"))
        trash.clicked.connect(self.delete_deformer)
        trash.setToolTip("Delete the current deformer.")

        layout.addWidget(self.pick)
        layout.addWidget(trash)
        layout.setSpacing(2)  
        layout.setContentsMargins(0, 0, 0, 0)

    def show_menu(self):
        self.menu.clear()

        deformers = muUtils.listMuDeformers()
        for d in deformers:
            act = self.menu.addAction(d)
            act.triggered.connect(partial(self.select_deformer_item, d))

        self.menu.addSeparator()
        add_new = self.menu.addAction("Add New")
        add_new.triggered.connect(partial(self.select_deformer_item, "Add New"))

        self.menu.exec_(self.pick.mapToGlobal(QtCore.QPoint(0, self.pick.height())))

    def select_deformer_item(self, name):
        if name == "Add New":
            self.addNewDeformer()
        else:
            self.setDeformer(name)

    def addNewDeformer(self):
        new_name = muUtils.createDeformer()
        if new_name:
            self.setDeformer(new_name)
        else:
            QtWidgets.QMessageBox.warning(self, "Error", "Failed to create new deformer. Select a single mesh to apply the deformer.")

    def delete_deformer(self):
        if self.deformer and cmds.ls(self.deformer):
            cmds.delete(self.deformer)

class Settings(QtWidgets.QGroupBox):
    def __init__(self, parent=None):
        super(Settings, self).__init__("Settings", parent)
        self.deformer = None
        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(8, 8, 8, 8)
        layout.setSpacing(8)

        # Grid layout for buttons
        grid = QtWidgets.QGridLayout()

        # Lower res
        self.lower_btn = QtWidgets.QPushButton("Lower Res")
        self.lower_btn.clicked.connect(self.lowerRes)
        grid.addWidget(self.lower_btn, 0, 0)

        # Higher res
        self.higher_btn = QtWidgets.QPushButton("Higher Res")
        self.higher_btn.clicked.connect(self.higherRes)
        grid.addWidget(self.higher_btn, 0, 1)

        layout.addLayout(grid)

        # Wireframe opacity slider
        wire_layout = QtWidgets.QHBoxLayout()
        label = QtWidgets.QLabel("Wireframe Opacity")
        wire_layout.addWidget(label)

        self.wire_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.wire_slider.setRange(0, 100)
        self.wire_slider.setValue(muUtils.get_opacity())
        self.wire_slider.valueChanged.connect(self.set_wireframe_opacity)
        wire_layout.addWidget(self.wire_slider)
        layout.addLayout(wire_layout)

        # Symmetry toggle
        sym_layout = QtWidgets.QHBoxLayout()
        self.symmetry_chk = QtWidgets.QCheckBox("Symmetry")
        self.symmetry_chk.setChecked(muUtils.get_symmetry())
        self.symmetry_chk.toggled.connect(self.set_symmetry)
        sym_layout.addWidget(self.symmetry_chk)
        sym_layout.addStretch()
        layout.addLayout(sym_layout)

        # extract vector displacement
        vec_layout = QtWidgets.QHBoxLayout()
        vectorDisp = QtWidgets.QPushButton("Extract Vector Map")
        vectorDisp.clicked.connect(self.extractVectorMap)
        vec_layout.addWidget(vectorDisp)
        vec_layout.addStretch()
        layout.addLayout(vec_layout)

    def extractVectorMap(self):
        muUtils.extract_vector_map()

    def setDeformer(self, deformer):
        self.deformer = deformer

    def lowerRes(self):
        ctx = cmds.currentCtx()
        if "mush3dCtxCmd" in ctx:
            cmds.mush3dCtxCmd(ctx, edit=True, operation="down")

    def higherRes(self):
        ctx = cmds.currentCtx()
        if "mush3dCtxCmd" in ctx:
            cmds.mush3dCtxCmd(ctx, edit=True, operation="up")

    def set_wireframe_opacity(self, value):
        muUtils.set_opacity(value)

    def set_symmetry(self, enabled):
        muUtils.set_symmetry(enabled)

class LayerElement(QtWidgets.QTableWidgetItem):
    def __init__(self, deformer, layerIndex):
        self.deformer = deformer
        self.layerIndex = layerIndex
        item_name = self.get_layer_name()
        super(LayerElement, self).__init__(item_name)

    def get_layer_name(self):
        attr = "{}.layer[{}]".format(self.deformer, self.layerIndex)
        return cmds.getAttr(attr + ".layerName")

    def set_layer_name(self, name):
        attr = "{}.layer[{}].layerName".format(self.deformer, self.layerIndex)
        cmds.setAttr(attr, name, type="string")
        self.setText(name)

    def is_valid(self):
        if not cmds.objExists(self.deformer):
            return False
        multi_indices = cmds.getAttr(self.deformer + ".layer", mi=1) or []
        return self.layerIndex in multi_indices

    def update_tweak_connection(self):
        muUtils.connect_tweak(self.deformer, self.layerIndex)

class LayerView(QtWidgets.QWidget):
    layerSelected = QtCore.Signal(str, int)

    def __init__(self, parent=None):
        super(LayerView, self).__init__(parent)
        self.deformer = None
        self.build_ui()

    def build_ui(self):
        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        bnt_size = QtCore.QSize(22, 22)

        add = create_button("mu_addLayer.png", bnt_size, self.add_layer, "Add a new layer.")
        remove = create_button("mu_removeLayer.png", bnt_size, self.remove_layer, "Remove the selected layer.")
        auto_anim = create_button("mu_autoAnim.png", bnt_size, self.auto_anim, "Auto animate selected layers.")
        mesh2Layer = create_button("mu_meshToLayer.png", bnt_size, self.mesh_2_layer, 
            "Select the base and offset meshes, the difference between them will be added to the layer deltas.")
        setReferenceMesh = create_button("mu_setReferenceMesh.png", bnt_size, self.set_reference_mesh, 
            "Pick the reference mesh for Clone, and the rest mesh for Wrinkle.")

        bnt_layout = QtWidgets.QHBoxLayout() 
        bnt_layout.setSpacing(2)
        bnt_layout.setContentsMargins(0, 0, 0, 0)
        bnt_layout.addWidget(add)
        bnt_layout.addWidget(remove)
        bnt_layout.addStretch()
        bnt_layout.addWidget(auto_anim)
        bnt_layout.addWidget(mesh2Layer)
        bnt_layout.addWidget(setReferenceMesh)
        layout.addLayout(bnt_layout)

        self.table = QtWidgets.QTableWidget(0, 4)
        self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.table.setEditTriggers(QtWidgets.QAbstractItemView.DoubleClicked)
        self.table.itemChanged.connect(self.on_item_changed)
        self.table.itemSelectionChanged.connect(self.on_item_selected)
        self.table.cellClicked.connect(self.on_cell_clicked)
        self.table.verticalHeader().setVisible(False)

        # FULL header setup using only setHorizontalHeaderItem (no setHorizontalHeaderLabels!)
        eye_item = QtWidgets.QTableWidgetItem("     ")
        eye_icon = QtGui.QIcon(QtGui.QPixmap(icon_folder + "mu_eye.png"))
        eye_item.setIcon(eye_icon)
        eye_item.setToolTip("Visibility")
        eye_item.setTextAlignment(QtCore.Qt.AlignCenter)
        eye_item.setText("")

        self.table.setHorizontalHeaderItem(0, eye_item)
        self.table.setHorizontalHeaderItem(1, QtWidgets.QTableWidgetItem("Layer"))
        self.table.setHorizontalHeaderItem(2, QtWidgets.QTableWidgetItem("Intensity"))
        self.table.setHorizontalHeaderItem(3, QtWidgets.QTableWidgetItem("Frame"))

        header = self.table.horizontalHeader()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
        header.setSectionResizeMode(1, QtWidgets.QHeaderView.Interactive)
        header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
        header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)

        # Force column size AFTER layout pass to override Qt BS
        self.table.setColumnWidth(0, 20)
        self.table.setColumnWidth(1, 80)
        self.table.setColumnWidth(2, 120)
        self.table.setColumnWidth(3, 32)

        palette = self.table.palette()
        palette.setColor(QtGui.QPalette.Base, QtGui.QColor("#383838"))
        palette.setColor(QtGui.QPalette.Text, QtGui.QColor("white"))
        self.table.setPalette(palette)

        layout.addWidget(self.table)



    def on_item_changed(self, item):
        if isinstance(item, LayerElement):
            item.set_layer_name(item.text())

    def on_item_selected(self):
        selection = self.table.selectionModel().selectedRows()
        if not selection:
            muUtils.update_deformer_layer_selection(self.deformer, [])
            return

        indices = []
        for model_index in selection:
            row = model_index.row()
            item = self.table.item(row, 1)
            if isinstance(item, LayerElement):
                indices.append(item.layerIndex)
                item.update_tweak_connection()

        muUtils.update_deformer_layer_selection(self.deformer, indices)

        if indices:
            self.layerSelected.emit(self.deformer, indices[0]) 

    def on_cell_clicked(self, row, column):
        # Only react to the "Frame" column (index 3)
        if column != 3:
            return

        item = self.table.item(row, column)
        if not item:
            return

        try:
            frame = int(item.text())
            cmds.currentTime(frame, edit=True)
        except ValueError:
            cmds.warning("Invalid frame value clicked.")

    def setDeformer(self, deformer):
        self.deformer = deformer

        self.table.blockSignals(True)
        self.table.clearContents()
        self.table.setRowCount(0)

        if not deformer or not cmds.objExists(deformer):
            self.table.blockSignals(False)
            return

        indices = cmds.getAttr(deformer + ".layer", multiIndices=True) or []
        for i in indices:
            row = self.table.rowCount()
            self.table.insertRow(row)

            # Column 0 – Visibility
            visibility_attr = "{}.layer[{}].visibility".format(deformer, i)
            checkbox = QtWidgets.QCheckBox()
            checkbox.setChecked(cmds.getAttr(visibility_attr))
            checkbox.setStyleSheet("margin-left:4px; margin-right:4px;")
            checkbox.stateChanged.connect(
                lambda state, attr=visibility_attr: cmds.setAttr(attr, bool(state))
            )
            self.table.setCellWidget(row, 0, checkbox)

            # Column 1 – Layer name
            name_item = LayerElement(deformer, i)
            name_item.setFlags(name_item.flags() | QtCore.Qt.ItemIsEditable)
            self.table.setItem(row, 1, name_item)

            # Column 2 – Intensity slider
            intensity_attr = "{}.layer[{}].intensity".format(deformer, i)
            slider = muUtils.create_attrFieldSliderGrp(intensity_attr, self.table)
            self.table.setCellWidget(row, 2, slider)

            # Column 3 – Frame (read-only)
            base_time_attr = "{}.layer[{}].baseTime".format(deformer, i)
            value = cmds.getAttr(base_time_attr)
            fps = mel.eval("currentTimeUnitToFPS()")
            frame = int(value * fps)
            frame_item = QtWidgets.QTableWidgetItem(str(frame))
            frame_item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            frame_item.setTextAlignment(QtCore.Qt.AlignCenter)
            self.table.setItem(row, 3, frame_item)

        self.table.blockSignals(False)

        # After refreshing the table, restore selection if it exists
        selected = muUtils.get_selected_layers_indices(self.deformer)
        if selected:
            for row in range(self.table.rowCount()):
                item = self.table.item(row, 1)
                if isinstance(item, LayerElement) and item.layerIndex in selected:
                    self.table.selectRow(row)
                    # Optionally update tweak connections again
                    item.update_tweak_connection()

            # Emit signal again so layer settings panel updates
            self.layerSelected.emit(self.deformer, selected[0])

    def add_layer(self):
        if not self.deformer:
            cmds.warning("No deformer selected.")
            return

        new_index = muUtils.addLayer(self.deformer)
        if new_index is not None:
            current_time = cmds.currentTime(q=True)
            fps = mel.eval("currentTimeUnitToFPS()")
            seconds = current_time / fps
            attr = "{}.layer[{}].baseTime".format(self.deformer, new_index)
            cmds.setAttr(attr, seconds)

            self.setDeformer(self.deformer)
            last_row = self.table.rowCount() - 1
            self.table.setCurrentCell(last_row, 0)

    def remove_layer(self):
        if not self.deformer:
            cmds.warning("No deformer selected.")
            return

        selection = self.table.selectionModel().selectedRows()
        if not selection:
            cmds.warning("No layers selected to delete.")
            return

        self.table.blockSignals(True)

        items_to_delete = []
        indices_to_delete = []

        for model_index in selection:
            row = model_index.row()
            item = self.table.item(row, 1)
            if isinstance(item, LayerElement):
                items_to_delete.append(item)
                indices_to_delete.append(item.layerIndex)

        muUtils.delete_layers(self.deformer, indices_to_delete)

        # Now remove the rows of those items
        for item in items_to_delete:
            row = self.table.row(item)
            self.table.removeRow(row)

        muUtils.update_deformer_layer_selection(self.deformer, [])

        self.table.blockSignals(False)

    def auto_anim(self):
        if not muUtils.is_deformer_valid(self.deformer):
            return
        muUtils.solve_selected_layers(self.deformer)

    def mesh_2_layer(self):
        muUtils.mesh_to_layer(self.deformer)

    def set_reference_mesh(self):
        muUtils.set_reference_mesh()

class LayerSettingsPanel(QtWidgets.QGroupBox):
    def __init__(self, title="Layer Settings", parent=None):
        super(LayerSettingsPanel, self).__init__(title, parent)
        self.layout = QtWidgets.QVBoxLayout(self)
        self.setLayout(self.layout)
        self.layout.setContentsMargins(4, 2, 4, 2)  # tiny margin
        self.setFixedHeight(80)

    def set_layer(self, deformer, layer_index):
        for i in reversed(range(self.layout.count())):
            widget = self.layout.itemAt(i).widget()
            if widget:
                widget.setParent(None)

        attr1 = "{}.layer[{}].tangentSpace".format(deformer, layer_index)
        attr2 = "{}.layer[{}].iterations".format(deformer, layer_index)

        w1 = muUtils.create_attrControlGrp(attr1, parent=self)
        w2 = muUtils.create_attrControlGrp(attr2, parent=self)

        self.layout.addWidget(w1)
        self.layout.addWidget(w2)

class muEditorWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(muEditorWindow, self).__init__(parent)
        self.setWindowTitle("Mush3D Editor")
        self.setMinimumSize(300, 400)
        self.setObjectName("muEditorWindow")
        self.jobs_global = []
        self.jobs_deformer = []
        self.build_menu()
        self.build_ui()

    def build_menu(self):
        mb = self.menuBar()
        lic_menu = mb.addMenu("Licensing")
        act = lic_menu.addAction("Apply license")
        act.triggered.connect(self.apply_license)

        doc_menu = mb.addMenu("Documentation")
        doc_act = doc_menu.addAction("Open")
        doc_act.triggered.connect(self.open_documentation)

    def open_documentation(self):
        module_path = cmds.moduleInfo(path=True, moduleName="mush3d")
        doc_path = os.path.abspath(os.path.join(module_path, "docs", "mush3d4Maya_documentation.html"))
        if os.path.exists(doc_path):
            webbrowser.open('file://' + doc_path)
        else:
            cmds.warning("Documentation file not found at: " + doc_path)

    def apply_license(self):
        dlg = muLicenseDialog.LicenseDialog(self)
        dlg.exec_()  

    def build_ui(self):
        # main widget
        main_widget = QtWidgets.QWidget()
        self.setCentralWidget(main_widget)

        # main layout
        main_layout = QtWidgets.QHBoxLayout(main_widget)
        main_layout.setContentsMargins(8,8,8,8)  
        main_layout.setSpacing(8)

        # Left panel with BrushBar and SelectDeformerGrp
        self.brush_bar = BrushBar()
        main_layout.addWidget(self.brush_bar)

        # add a  layout for all the rest of the widgets
        layout = QtWidgets.QVBoxLayout()
        main_layout.addLayout(layout)

        # add the rest of the widgets
        self.deformer_selector = SelectDeformerGrp()
        self.deformer_selector.deformerSelected.connect(self.on_deformer_selected)
        layout.addWidget(self.deformer_selector)

        self.layer_view = LayerView()
        layout.addWidget(self.layer_view)

        self.layer_settings = LayerSettingsPanel()
        layout.addWidget(self.layer_settings)

        self.settings = Settings()
        layout.addWidget(self.settings)

        self.license_status = muLicenseStatus.LicenseStatusWidget()
        layout.addWidget(self.license_status)

        self.layer_view.layerSelected.connect(self.layer_settings.set_layer)


    def on_deformer_selected(self, deformer):
        # Kill existing scriptJobs
        for jid in self.jobs_deformer:
            if cmds.scriptJob(exists=jid):
                cmds.scriptJob(kill=jid, force=True)
        self.jobs_deformer = []  # clear the list

        self.layer_view.setDeformer(deformer)   
        self.brush_bar.setDeformer(deformer)
        self.settings.setDeformer(deformer)

        # Add delete watcher for the selected deformer
        if deformer:
            job_id = cmds.scriptJob(
                nodeDeleted=(deformer, self.on_deformer_deleted),
                protected=True)
            self.jobs_deformer.append(job_id)

    ###############
    # Script Jobs #
    ###############

    def showEvent(self, event):
        super().showEvent(event)
        self.jobs_global.append(cmds.scriptJob(
            event=["ToolChanged", self.on_tool_changed], protected=True))
        
        self.jobs_global.append(cmds.scriptJob(
            event=["SceneOpened", self.on_scene_opened], protected=True))
        
        self.jobs_global.append(cmds.scriptJob(
            event=["NewSceneOpened", self.on_scene_opened], protected=True))

    def closeEvent(self, event):
        for jid in self.jobs_global + self.jobs_deformer:
            if cmds.scriptJob(exists=jid):
                cmds.scriptJob(kill=jid, force=True)

    def on_tool_changed(self, *args):
        ctx = cmds.currentCtx()
        if "mush3dCtxCmd" not in ctx:
            self.brush_bar.unselectAllButtons()

    def on_scene_opened(self):
        self.reset_ui()

    def reset_ui(self):
        self.deformer_selector.setDeformer(None)
        self.layer_view.setDeformer(None)
        self.layer_settings.set_layer = lambda *_: None
        self.settings.setDeformer(None)
        self.brush_bar.setDeformer(None)
        self.brush_bar.unselectAllButtons()

    def on_deformer_deleted(self):
        self.reset_ui()
        cmds.setToolTo('selectSuperContext')

def show():
    if not muUtils.ensurePluginLoaded():
        return

    for widget in QtWidgets.QApplication.topLevelWidgets():
        if widget.objectName() == "muEditorWindow":
            widget.close()

    main_window = toQtObject(omui.MQtUtil.mainWindow())
    window = muEditorWindow(parent=main_window)
    window.show()
