297 lines
11 KiB
Python
297 lines
11 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Tool - Qt Compatibility Module
|
|
Provides cross-version Qt compatibility support for Maya
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import importlib
|
|
import maya.cmds as cmds
|
|
import maya.mel as mel
|
|
|
|
# 全局变量
|
|
QT_VERSION = None
|
|
QtCore = None
|
|
QtGui = None
|
|
QtWidgets = None
|
|
wrapInstance = None
|
|
unwrapInstance = None
|
|
|
|
def init_qt():
|
|
"""Initialize Qt module, automatically selecting appropriate Qt binding based on Maya version"""
|
|
global QT_VERSION, QtCore, QtGui, QtWidgets, wrapInstance, unwrapInstance
|
|
|
|
# Get Maya version
|
|
maya_version = int(cmds.about(version=True).split()[0])
|
|
|
|
# Maya 2025+ use PySide6
|
|
if maya_version >= 2025:
|
|
try:
|
|
from PySide6 import QtCore, QtGui, QtWidgets
|
|
from shiboken6 import wrapInstance
|
|
QT_VERSION = "PySide6"
|
|
print(f"QtCompat: Using PySide6 (Maya {maya_version})")
|
|
|
|
# Define unwrapInstance function
|
|
try:
|
|
from shiboken6 import wrapInstance as _wrapInstance
|
|
from shiboken6 import getCppPointer
|
|
|
|
def unwrapInstance(object):
|
|
"""Convert Qt object to C++ pointer"""
|
|
return getCppPointer(object)[0]
|
|
|
|
except ImportError:
|
|
def unwrapInstance(object):
|
|
"""Unable to get C++ pointer, return None"""
|
|
print("QtCompat: shiboken6.getCppPointer not available")
|
|
return None
|
|
|
|
except ImportError as e:
|
|
print(f"QtCompat: PySide6 import error: {str(e)}")
|
|
try:
|
|
from PySide2 import QtCore, QtGui, QtWidgets
|
|
from shiboken2 import wrapInstance
|
|
QT_VERSION = "PySide2"
|
|
print(f"QtCompat: Using PySide2 (fallback mode, Maya {maya_version})")
|
|
|
|
# Define unwrapInstance function
|
|
try:
|
|
from shiboken2 import wrapInstance as _wrapInstance
|
|
from shiboken2 import getCppPointer
|
|
|
|
def unwrapInstance(object):
|
|
"""Convert Qt object to C++ pointer"""
|
|
return getCppPointer(object)[0]
|
|
|
|
except ImportError:
|
|
def unwrapInstance(object):
|
|
"""Unable to get C++ pointer, return None"""
|
|
print("QtCompat: shiboken2.getCppPointer not available")
|
|
return None
|
|
|
|
except ImportError:
|
|
cmds.error("QtCompat: Unable to import PySide6 or PySide2, please ensure they are installed")
|
|
|
|
# Maya 2022-2024 use PySide2
|
|
elif maya_version >= 2022:
|
|
try:
|
|
from PySide2 import QtCore, QtGui, QtWidgets
|
|
from shiboken2 import wrapInstance
|
|
QT_VERSION = "PySide2"
|
|
print(f"QtCompat: Using PySide2 (Maya {maya_version})")
|
|
|
|
# Define unwrapInstance function
|
|
try:
|
|
from shiboken2 import wrapInstance as _wrapInstance
|
|
from shiboken2 import getCppPointer
|
|
|
|
def unwrapInstance(object):
|
|
"""Convert Qt object to C++ pointer"""
|
|
return getCppPointer(object)[0]
|
|
|
|
except ImportError:
|
|
def unwrapInstance(object):
|
|
"""Unable to get C++ pointer, return None"""
|
|
print("QtCompat: shiboken2.getCppPointer not available")
|
|
return None
|
|
|
|
except ImportError as e:
|
|
print(f"QtCompat: PySide2 import error: {str(e)}")
|
|
try:
|
|
from PySide6 import QtCore, QtGui, QtWidgets
|
|
from shiboken6 import wrapInstance
|
|
QT_VERSION = "PySide6"
|
|
print(f"QtCompat: Using PySide6 (non-standard configuration, Maya {maya_version})")
|
|
|
|
# Define unwrapInstance function
|
|
try:
|
|
from shiboken6 import wrapInstance as _wrapInstance
|
|
from shiboken6 import getCppPointer
|
|
|
|
def unwrapInstance(object):
|
|
"""Convert Qt object to C++ pointer"""
|
|
return getCppPointer(object)[0]
|
|
|
|
except ImportError:
|
|
def unwrapInstance(object):
|
|
"""Unable to get C++ pointer, return None"""
|
|
print("QtCompat: shiboken6.getCppPointer not available")
|
|
return None
|
|
|
|
except ImportError:
|
|
cmds.error("QtCompat: Unable to import PySide2 or PySide6, please ensure they are installed")
|
|
|
|
# Maya 2020-2021 use PySide2 or PySide
|
|
else:
|
|
try:
|
|
from PySide2 import QtCore, QtGui, QtWidgets
|
|
from shiboken2 import wrapInstance
|
|
QT_VERSION = "PySide2"
|
|
print(f"QtCompat: Using PySide2 (Maya {maya_version})")
|
|
|
|
# Define unwrapInstance function
|
|
try:
|
|
from shiboken2 import wrapInstance as _wrapInstance
|
|
from shiboken2 import getCppPointer
|
|
|
|
def unwrapInstance(object):
|
|
"""Convert Qt object to C++ pointer"""
|
|
return getCppPointer(object)[0]
|
|
|
|
except ImportError:
|
|
def unwrapInstance(object):
|
|
"""Unable to get C++ pointer, return None"""
|
|
print("QtCompat: shiboken2.getCppPointer not available")
|
|
return None
|
|
|
|
except ImportError:
|
|
try:
|
|
from PySide import QtCore, QtGui
|
|
from PySide import QtGui as QtWidgets # PySide中没有QtWidgets
|
|
from shiboken import wrapInstance
|
|
QT_VERSION = "PySide"
|
|
print(f"QtCompat: Using PySide (Maya {maya_version})")
|
|
|
|
# Define unwrapInstance function
|
|
try:
|
|
from shiboken import wrapInstance as _wrapInstance
|
|
from shiboken import getCppPointer
|
|
|
|
def unwrapInstance(object):
|
|
"""Convert Qt object to C++ pointer"""
|
|
return getCppPointer(object)[0]
|
|
|
|
except ImportError:
|
|
def unwrapInstance(object):
|
|
"""Unable to get C++ pointer, return None"""
|
|
print("QtCompat: shiboken.getCppPointer not available")
|
|
return None
|
|
|
|
except ImportError:
|
|
cmds.error("QtCompat: Unable to import PySide or PySide2, please ensure they are installed")
|
|
|
|
# Export global variables
|
|
globals()["QtCore"] = QtCore
|
|
globals()["QtGui"] = QtGui
|
|
globals()["QtWidgets"] = QtWidgets
|
|
globals()["wrapInstance"] = wrapInstance
|
|
globals()["unwrapInstance"] = unwrapInstance
|
|
|
|
return QT_VERSION
|
|
|
|
def maya_main_window():
|
|
"""Get Maya main window QWidget"""
|
|
import maya.OpenMayaUI as omui
|
|
|
|
if QT_VERSION in ["PySide2", "PySide6"]:
|
|
main_window_ptr = omui.MQtUtil.mainWindow()
|
|
if main_window_ptr:
|
|
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
|
|
else: # PySide
|
|
main_window_ptr = omui.MQtUtil.mainWindow()
|
|
if main_window_ptr:
|
|
return wrapInstance(long(main_window_ptr), QtWidgets.QWidget)
|
|
|
|
return None
|
|
|
|
def load_ui_file(ui_file, parent=None):
|
|
"""Load UI file and return created window"""
|
|
if QT_VERSION == "PySide6":
|
|
from PySide6.QtUiTools import QUiLoader
|
|
loader = QUiLoader()
|
|
ui_file_obj = QtCore.QFile(ui_file)
|
|
ui_file_obj.open(QtCore.QFile.ReadOnly)
|
|
ui = loader.load(ui_file_obj, parent)
|
|
ui_file_obj.close()
|
|
return ui
|
|
elif QT_VERSION == "PySide2":
|
|
from PySide2.QtUiTools import QUiLoader
|
|
loader = QUiLoader()
|
|
ui_file_obj = QtCore.QFile(ui_file)
|
|
ui_file_obj.open(QtCore.QFile.ReadOnly)
|
|
ui = loader.load(ui_file_obj, parent)
|
|
ui_file_obj.close()
|
|
return ui
|
|
else: # PySide
|
|
from PySide.QtUiTools import QUiLoader
|
|
loader = QUiLoader()
|
|
ui_file_obj = QtCore.QFile(ui_file)
|
|
ui_file_obj.open(QtCore.QFile.ReadOnly)
|
|
ui = loader.load(ui_file_obj, parent)
|
|
ui_file_obj.close()
|
|
return ui
|
|
|
|
def compile_ui_file(ui_file, py_file=None):
|
|
"""Compile UI file to Python file"""
|
|
if not py_file:
|
|
py_file = os.path.splitext(ui_file)[0] + ".py"
|
|
|
|
if QT_VERSION == "PySide6":
|
|
from PySide6.QtUiTools import pysideuic
|
|
with open(py_file, "w") as f:
|
|
pysideuic.compileUi(ui_file, f)
|
|
elif QT_VERSION == "PySide2":
|
|
from PySide2.QtUiTools import pysideuic
|
|
with open(py_file, "w") as f:
|
|
pysideuic.compileUi(ui_file, f)
|
|
else: # PySide
|
|
from PySide.QtUiTools import pysideuic
|
|
with open(py_file, "w") as f:
|
|
pysideuic.compileUi(ui_file, f)
|
|
|
|
return py_file
|
|
|
|
def get_save_file_name(parent=None, caption="", dir="", filter=""):
|
|
"""Get save file name, compatible with different Qt versions"""
|
|
if QT_VERSION in ["PySide2", "PySide6"]:
|
|
return QtWidgets.QFileDialog.getSaveFileName(parent, caption, dir, filter)[0]
|
|
else: # PySide
|
|
return QtWidgets.QFileDialog.getSaveFileName(parent, caption, dir, filter)
|
|
|
|
def get_open_file_name(parent=None, caption="", dir="", filter=""):
|
|
"""Get open file name, compatible with different Qt versions"""
|
|
if QT_VERSION in ["PySide2", "PySide6"]:
|
|
return QtWidgets.QFileDialog.getOpenFileName(parent, caption, dir, filter)[0]
|
|
else: # PySide
|
|
return QtWidgets.QFileDialog.getOpenFileName(parent, caption, dir, filter)
|
|
|
|
def get_existing_directory(parent=None, caption="", dir=""):
|
|
"""Get existing directory, compatible with different Qt versions"""
|
|
if QT_VERSION in ["PySide2", "PySide6"]:
|
|
return QtWidgets.QFileDialog.getExistingDirectory(parent, caption, dir)
|
|
else: # PySide
|
|
return QtWidgets.QFileDialog.getExistingDirectory(parent, caption, dir)
|
|
|
|
def get_icon(icon_path):
|
|
"""Get icon, compatible with different Qt versions"""
|
|
if os.path.exists(icon_path):
|
|
return QtGui.QIcon(icon_path)
|
|
return QtGui.QIcon()
|
|
|
|
def get_pixmap(image_path):
|
|
"""Get pixmap, compatible with different Qt versions"""
|
|
if os.path.exists(image_path):
|
|
return QtGui.QPixmap(image_path)
|
|
return QtGui.QPixmap()
|
|
|
|
def get_color(parent=None, title="Choose Color", initial=None):
|
|
"""Get color, compatible with different Qt versions"""
|
|
if initial is None:
|
|
initial = QtGui.QColor(255, 255, 255)
|
|
|
|
if QT_VERSION == "PySide6":
|
|
color = QtWidgets.QColorDialog.getColor(initial, parent, title)
|
|
else: # PySide2 or PySide
|
|
color = QtWidgets.QColorDialog.getColor(initial, parent, title)
|
|
|
|
if color.isValid():
|
|
return color
|
|
return None
|
|
|
|
# Initialize Qt module
|
|
init_qt()
|