Files
Nexus/2023/scripts/rigging_tools/ngskintools2/ui/mainwindow.py
2025-11-24 08:27:50 +08:00

224 lines
6.3 KiB
Python

from maya import OpenMayaUI as omui
from maya import cmds
from ngSkinTools2.api.log import getLogger
from ngSkinTools2.api.pyside import QtCore, QtGui, QtWidgets, QWidget, wrap_instance
from ngSkinTools2.api.session import session
from ngSkinTools2.ui.options import config
from .. import cleanup, signal, version
from ..observableValue import ObservableValue
from . import (
aboutwindow,
dialogs,
hotkeys_setup,
qt,
tabLayerEffects,
tabMirror,
tabPaint,
tabSetWeights,
tabTools,
targetui,
updatewindow,
)
from .layout import scale_multiplier
log = getLogger("main window")
def get_image_path(file_name):
import os
for i in os.getenv("XBMLANGPATH", "").split(os.path.pathsep):
result = os.path.join(i, file_name)
if os.path.isfile(result):
return result
return file_name
def build_menu(parent, actions):
menu = QtWidgets.QMenuBar(parent=parent)
def top_level_menu(label):
sub_item = menu.addMenu(label)
sub_item.setSeparatorsCollapsible(False)
sub_item.setTearOffEnabled(True)
return sub_item
sub = top_level_menu("File")
sub.addSeparator().setText("Import/Export")
sub.addAction(actions.importFile)
sub.addAction(actions.exportFile)
sub = top_level_menu("Layers")
sub.addSeparator().setText("Layer actions")
sub.addAction(actions.initialize)
sub.addAction(actions.import_v1)
actions.addLayersActions(sub)
sub.addSeparator().setText("Copy")
sub.addAction(actions.transfer)
sub = top_level_menu("Tools")
sub.addAction(actions.add_influences)
sub.addAction(actions.toolsAssignFromClosestJoint)
sub.addSeparator()
sub.addAction(actions.transfer)
sub.addSeparator()
sub.addAction(actions.toolsDeleteCustomNodesOnSelection)
sub.addAction(actions.toolsDeleteCustomNodes)
sub = top_level_menu("View")
sub.addAction(actions.show_used_influences_only)
sub = top_level_menu("Help")
sub.addAction(actions.documentation.user_guide)
sub.addAction(actions.documentation.api_root)
sub.addAction(actions.documentation.changelog)
sub.addAction(actions.documentation.contact)
sub.addSeparator()
sub.addAction(actions.check_for_updates)
sub.addAction("About...").triggered.connect(lambda: aboutwindow.show(parent))
return menu
def build_rmb_menu_layers(view, actions):
view.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
actions.addLayersActions(view)
class MainWindowOptions:
current_tab = ObservableValue(0)
def build_ui(parent):
"""
:type parent: QWidget
"""
options = MainWindowOptions()
window = QtWidgets.QWidget(parent)
session.addQtWidgetReference(window)
from ngSkinTools2.ui.actions import Actions
actions = Actions(parent=window, session=session)
tabs = QtWidgets.QTabWidget(window)
tabs.addTab(tabPaint.build_ui(tabs, actions), "Paint")
tabs.addTab(tabSetWeights.build_ui(tabs), "Set Weights")
tabs.addTab(tabMirror.build_ui(tabs), "Mirror")
tabs.addTab(tabLayerEffects.build_ui(), "Effects")
tabs.addTab(tabTools.build_ui(actions, session), "Tools")
@signal.on(options.current_tab.changed)
def set_current_tab():
tabs.setCurrentIndex(options.current_tab())
layers_toolbar = QtWidgets.QToolBar()
layers_toolbar.addAction(actions.addLayer)
layers_toolbar.setOrientation(QtCore.Qt.Vertical)
spacing_h = 5
spacing_v = 5
layers_row = targetui.build_target_ui(window, actions, session)
split = QtWidgets.QSplitter(orientation=QtCore.Qt.Vertical, parent=window)
split.addWidget(layers_row)
split.addWidget(tabs)
split.setStretchFactor(0, 2)
split.setStretchFactor(1, 3)
split.setContentsMargins(spacing_h, spacing_v, spacing_h, spacing_v)
def build_icon_label():
w = QWidget()
w.setStyleSheet("background-color: #dcce87;color: #373737;")
l = QtWidgets.QHBoxLayout()
icon = QtWidgets.QLabel()
icon.setPixmap(QtGui.QIcon(":/error.png").pixmap(16 * scale_multiplier, 16 * scale_multiplier))
icon.setFixedSize(16 * scale_multiplier, 16 * scale_multiplier)
text = QtWidgets.QLabel("<placeholder>")
text.setWordWrap(True)
text.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
l.addWidget(icon)
l.addWidget(text)
w.setContentsMargins(0, 0, 0, 0)
w.setLayout(l)
return w, text.setText
layout = QtWidgets.QVBoxLayout(window)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(build_menu(window, actions))
layout.addWidget(split)
window.setLayout(layout)
hotkeys_setup.install_hotkeys()
dialogs.promptsParent = window
if config.checkForUpdatesAtStartup():
updatewindow.silent_check_and_show_if_available(qt.mainWindow)
return window, options
DOCK_NAME = 'ngSkinTools2_mainWindow'
def workspace_control_permanent_script():
from ngSkinTools2 import workspace_control_main_window
return "import {f.__module__}; {f.__module__}.{f.__name__}()".format(f=workspace_control_main_window)
# noinspection PyShadowingBuiltins
def open():
"""
opens main window
"""
if not cmds.workspaceControl(DOCK_NAME, q=True, exists=True):
# build UI script in type-safe manner
cmds.workspaceControl(
DOCK_NAME,
retain=False,
floating=True,
# ttc=["AttributeEditor",-1],
uiScript=workspace_control_permanent_script(),
)
# bring tab to front
cmds.evalDeferred(lambda *args: cmds.workspaceControl(DOCK_NAME, e=True, r=True))
def close():
from maya import cmds
# noinspection PyBroadException
try:
cmds.deleteUI(DOCK_NAME)
except:
pass
pass
cleanup.registerCleanupHandler(close)
def resume_in_workspace_control():
"""
this method is responsible for resuming workspace control when Maya is building/restoring UI as part of it's
workspace management cycle (open UI for the first time, restart maya, change workspace, etc)
"""
cmds.workspaceControl(DOCK_NAME, e=True, label="ngSkinTools " + version.pluginVersion())
widget = wrap_instance(omui.MQtUtil.findControl(DOCK_NAME), QtWidgets.QWidget)
ui, _ = build_ui(widget)
widget.layout().addWidget(ui)