#!/usr/bin/env python # -*- coding: utf-8 -*- """ Tool - Settings Dialog Provides a dialog for managing user settings and preferences """ import os import sys import maya.cmds as cmds import maya.OpenMayaUI as omui try: from PySide2 import QtCore, QtGui, QtWidgets from shiboken2 import wrapInstance except ImportError: try: from PySide6 import QtCore, QtGui, QtWidgets from shiboken6 import wrapInstance except ImportError: from PySide import QtCore, QtGui, QtWidgets from shiboken import wrapInstance # Import configuration import config # Import settings utilities from utils.settings_utils import SettingsUtils class SettingsDialog(QtWidgets.QDialog): """Settings dialog for the Tool plugin""" def __init__(self, parent=None): """Initialize the settings dialog""" super(SettingsDialog, self).__init__(parent) self.setWindowTitle(f"{config.TOOL_NAME} - Settings") self.setMinimumSize(600, 500) self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint) # Initialize settings utility self.settings_utils = SettingsUtils() self.settings = self.settings_utils.get_all_settings() # Initialize UI self._create_widgets() self._create_layouts() self._create_connections() self._load_settings() def _create_widgets(self): """Create dialog widgets""" # Create tab widget self.tab_widget = QtWidgets.QTabWidget() # Create general settings page self.general_widget = QtWidgets.QWidget() self.general_layout = QtWidgets.QVBoxLayout(self.general_widget) # Language settings self.language_group = QtWidgets.QGroupBox("Language") self.language_layout = QtWidgets.QVBoxLayout(self.language_group) self.language_combo = QtWidgets.QComboBox() self.language_combo.addItem("Chinese (Simplified)", "zh_CN") self.language_combo.addItem("English", "en_US") self.language_layout.addWidget(self.language_combo) # Theme settings self.theme_group = QtWidgets.QGroupBox("Theme") self.theme_layout = QtWidgets.QVBoxLayout(self.theme_group) self.theme_combo = QtWidgets.QComboBox() self.theme_combo.addItem("Dark Theme", "dark") self.theme_combo.addItem("Light Theme", "light") self.theme_layout.addWidget(self.theme_combo) # Auto-save settings self.autosave_group = QtWidgets.QGroupBox("Auto Save") self.autosave_layout = QtWidgets.QVBoxLayout(self.autosave_group) self.autosave_check = QtWidgets.QCheckBox("Enable Auto Save") self.autosave_layout.addWidget(self.autosave_check) self.autosave_interval_layout = QtWidgets.QHBoxLayout() self.autosave_interval_label = QtWidgets.QLabel("Auto Save Interval (minutes):") self.autosave_interval_spin = QtWidgets.QSpinBox() self.autosave_interval_spin.setMinimum(1) self.autosave_interval_spin.setMaximum(60) self.autosave_interval_layout.addWidget(self.autosave_interval_label) self.autosave_interval_layout.addWidget(self.autosave_interval_spin) self.autosave_layout.addLayout(self.autosave_interval_layout) # Welcome message settings self.welcome_check = QtWidgets.QCheckBox("Show Welcome Message") # Add widgets to general settings page self.general_layout.addWidget(self.language_group) self.general_layout.addWidget(self.theme_group) self.general_layout.addWidget(self.autosave_group) self.general_layout.addWidget(self.welcome_check) self.general_layout.addStretch() # Create DNA settings page self.dna_widget = QtWidgets.QWidget() self.dna_layout = QtWidgets.QVBoxLayout(self.dna_widget) # DNA path settings self.dna_path_group = QtWidgets.QGroupBox("DNA File Path") self.dna_path_layout = QtWidgets.QVBoxLayout(self.dna_path_group) self.dna_path_layout_h = QtWidgets.QHBoxLayout() self.dna_path_edit = QtWidgets.QLineEdit() self.dna_path_button = QtWidgets.QPushButton("浏览...") self.dna_path_layout_h.addWidget(self.dna_path_edit) self.dna_path_layout_h.addWidget(self.dna_path_button) self.dna_path_layout.addLayout(self.dna_path_layout_h) # DNA选项设置 self.dna_options_group = QtWidgets.QGroupBox("DNA选项") self.dna_options_layout = QtWidgets.QVBoxLayout(self.dna_options_group) self.dna_autoload_check = QtWidgets.QCheckBox("自动加载上次使用的DNA文件") self.dna_backup_check = QtWidgets.QCheckBox("编辑前备份DNA文件") self.dna_options_layout.addWidget(self.dna_autoload_check) self.dna_options_layout.addWidget(self.dna_backup_check) # 添加控件到DNA设置页 self.dna_layout.addWidget(self.dna_path_group) self.dna_layout.addWidget(self.dna_options_group) self.dna_layout.addStretch() # 创建校准设置页 self.calibration_widget = QtWidgets.QWidget() self.calibration_layout = QtWidgets.QVBoxLayout(self.calibration_widget) # 校准选项设置 self.calibration_options_group = QtWidgets.QGroupBox("校准选项") self.calibration_options_layout = QtWidgets.QVBoxLayout(self.calibration_options_group) self.calibration_auto_check = QtWidgets.QCheckBox("自动校准") self.calibration_reference_check = QtWidgets.QCheckBox("显示参考骨骼") self.calibration_diff_check = QtWidgets.QCheckBox("显示差异") self.calibration_options_layout.addWidget(self.calibration_auto_check) self.calibration_options_layout.addWidget(self.calibration_reference_check) self.calibration_options_layout.addWidget(self.calibration_diff_check) # 添加控件到校准设置页 self.calibration_layout.addWidget(self.calibration_options_group) self.calibration_layout.addStretch() # 创建绑定设置页 self.binding_widget = QtWidgets.QWidget() self.binding_layout = QtWidgets.QVBoxLayout(self.binding_widget) # 绑定方法设置 self.binding_method_group = QtWidgets.QGroupBox("绑定方法") self.binding_method_layout = QtWidgets.QVBoxLayout(self.binding_method_group) self.binding_method_combo = QtWidgets.QComboBox() self.binding_method_combo.addItem("平滑绑定", "smooth") self.binding_method_combo.addItem("刚性绑定", "rigid") self.binding_method_combo.addItem("双四元数绑定", "dual_quaternion") self.binding_method_layout.addWidget(self.binding_method_combo) # 绑定选项设置 self.binding_options_group = QtWidgets.QGroupBox("绑定选项") self.binding_options_layout = QtWidgets.QVBoxLayout(self.binding_options_group) self.binding_mirror_check = QtWidgets.QCheckBox("镜像权重") self.binding_normalize_check = QtWidgets.QCheckBox("标准化权重") self.binding_options_layout.addWidget(self.binding_mirror_check) self.binding_options_layout.addWidget(self.binding_normalize_check) # 添加控件到绑定设置页 self.binding_layout.addWidget(self.binding_method_group) self.binding_layout.addWidget(self.binding_options_group) self.binding_layout.addStretch() # 创建BlendShape设置页 self.blendshape_widget = QtWidgets.QWidget() self.blendshape_layout = QtWidgets.QVBoxLayout(self.blendshape_widget) # 导出格式设置 self.blendshape_format_group = QtWidgets.QGroupBox("导出格式") self.blendshape_format_layout = QtWidgets.QVBoxLayout(self.blendshape_format_group) self.blendshape_format_combo = QtWidgets.QComboBox() self.blendshape_format_combo.addItem("OBJ格式", "obj") self.blendshape_format_combo.addItem("Maya ASCII格式", "ma") self.blendshape_format_combo.addItem("FBX格式", "fbx") self.blendshape_format_layout.addWidget(self.blendshape_format_combo) # BlendShape选项设置 self.blendshape_options_group = QtWidgets.QGroupBox("BlendShape选项") self.blendshape_options_layout = QtWidgets.QVBoxLayout(self.blendshape_options_group) self.blendshape_connect_check = QtWidgets.QCheckBox("自动连接到控制器") self.blendshape_corrective_check = QtWidgets.QCheckBox("创建修正形状") self.blendshape_options_layout.addWidget(self.blendshape_connect_check) self.blendshape_options_layout.addWidget(self.blendshape_corrective_check) # 添加控件到BlendShape设置页 self.blendshape_layout.addWidget(self.blendshape_format_group) self.blendshape_layout.addWidget(self.blendshape_options_group) self.blendshape_layout.addStretch() # 创建UI设置页 self.ui_widget = QtWidgets.QWidget() self.ui_layout = QtWidgets.QVBoxLayout(self.ui_widget) # 字体大小设置 self.ui_font_group = QtWidgets.QGroupBox("字体大小") self.ui_font_layout = QtWidgets.QVBoxLayout(self.ui_font_group) self.ui_font_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.ui_font_slider.setMinimum(8) self.ui_font_slider.setMaximum(14) self.ui_font_slider.setTickPosition(QtWidgets.QSlider.TicksBelow) self.ui_font_slider.setTickInterval(1) self.ui_font_label = QtWidgets.QLabel("9") self.ui_font_label.setAlignment(QtCore.Qt.AlignCenter) self.ui_font_layout.addWidget(self.ui_font_slider) self.ui_font_layout.addWidget(self.ui_font_label) # 图标大小设置 self.ui_icon_group = QtWidgets.QGroupBox("图标大小") self.ui_icon_layout = QtWidgets.QVBoxLayout(self.ui_icon_group) self.ui_icon_combo = QtWidgets.QComboBox() self.ui_icon_combo.addItem("小", "small") self.ui_icon_combo.addItem("中", "medium") self.ui_icon_combo.addItem("大", "large") self.ui_icon_layout.addWidget(self.ui_icon_combo) # UI选项设置 self.ui_options_group = QtWidgets.QGroupBox("UI选项") self.ui_options_layout = QtWidgets.QVBoxLayout(self.ui_options_group) self.ui_tooltips_check = QtWidgets.QCheckBox("显示工具提示") self.ui_confirm_check = QtWidgets.QCheckBox("退出时确认") self.ui_options_layout.addWidget(self.ui_tooltips_check) self.ui_options_layout.addWidget(self.ui_confirm_check) # 添加控件到UI设置页 self.ui_layout.addWidget(self.ui_font_group) self.ui_layout.addWidget(self.ui_icon_group) self.ui_layout.addWidget(self.ui_options_group) self.ui_layout.addStretch() # 创建性能设置页 self.performance_widget = QtWidgets.QWidget() self.performance_layout = QtWidgets.QVBoxLayout(self.performance_widget) # 撤销队列大小设置 self.performance_undo_group = QtWidgets.QGroupBox("撤销队列大小") self.performance_undo_layout = QtWidgets.QVBoxLayout(self.performance_undo_group) self.performance_undo_spin = QtWidgets.QSpinBox() self.performance_undo_spin.setMinimum(10) self.performance_undo_spin.setMaximum(100) self.performance_undo_layout.addWidget(self.performance_undo_spin) # 视口质量设置 self.performance_viewport_group = QtWidgets.QGroupBox("视口质量") self.performance_viewport_layout = QtWidgets.QVBoxLayout(self.performance_viewport_group) self.performance_viewport_combo = QtWidgets.QComboBox() self.performance_viewport_combo.addItem("低", "low") self.performance_viewport_combo.addItem("中", "medium") self.performance_viewport_combo.addItem("高", "high") self.performance_viewport_layout.addWidget(self.performance_viewport_combo) # 性能选项设置 self.performance_options_group = QtWidgets.QGroupBox("性能选项") self.performance_options_layout = QtWidgets.QVBoxLayout(self.performance_options_group) self.performance_gpu_check = QtWidgets.QCheckBox("使用GPU加速") self.performance_options_layout.addWidget(self.performance_gpu_check) # 添加控件到性能设置页 self.performance_layout.addWidget(self.performance_undo_group) self.performance_layout.addWidget(self.performance_viewport_group) self.performance_layout.addWidget(self.performance_options_group) self.performance_layout.addStretch() # 添加标签页 self.tab_widget.addTab(self.general_widget, "常规") self.tab_widget.addTab(self.dna_widget, "DNA") self.tab_widget.addTab(self.calibration_widget, "校准") self.tab_widget.addTab(self.binding_widget, "绑定") self.tab_widget.addTab(self.blendshape_widget, "BlendShape") self.tab_widget.addTab(self.ui_widget, "UI") self.tab_widget.addTab(self.performance_widget, "性能") # 创建按钮 self.button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Apply | QtWidgets.QDialogButtonBox.Reset ) # 添加导入/导出按钮 self.import_button = QtWidgets.QPushButton("导入设置...") self.export_button = QtWidgets.QPushButton("导出设置...") self.button_box.addButton(self.import_button, QtWidgets.QDialogButtonBox.ActionRole) self.button_box.addButton(self.export_button, QtWidgets.QDialogButtonBox.ActionRole) def _create_layouts(self): """Create dialog layouts""" # Create main layout main_layout = QtWidgets.QVBoxLayout(self) main_layout.setContentsMargins(10, 10, 10, 10) main_layout.setSpacing(10) # 添加控件到布局 main_layout.addWidget(self.tab_widget) main_layout.addWidget(self.button_box) def _create_connections(self): """Create signal/slot connections""" # Button connections self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) self.button_box.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self._apply_settings) self.button_box.button(QtWidgets.QDialogButtonBox.Reset).clicked.connect(self._reset_settings) # 导入/导出按钮连接 self.import_button.clicked.connect(self._import_settings) self.export_button.clicked.connect(self._export_settings) # 控件连接 self.ui_font_slider.valueChanged.connect(self._update_font_label) self.dna_path_button.clicked.connect(self._browse_dna_path) # 自动保存连接 self.autosave_check.toggled.connect(self.autosave_interval_spin.setEnabled) def _load_settings(self): """Load settings to dialog widgets""" try: # 常规设置 language = self.settings["general"]["language"] index = self.language_combo.findData(language) if index >= 0: self.language_combo.setCurrentIndex(index) theme = self.settings["general"]["theme"] index = self.theme_combo.findData(theme) if index >= 0: self.theme_combo.setCurrentIndex(index) self.autosave_check.setChecked(self.settings["general"]["auto_save"]) self.autosave_interval_spin.setValue(self.settings["general"]["save_interval"]) self.autosave_interval_spin.setEnabled(self.settings["general"]["auto_save"]) self.welcome_check.setChecked(self.settings["general"]["show_welcome"]) # DNA设置 self.dna_path_edit.setText(self.settings["dna"]["default_dna_path"]) self.dna_autoload_check.setChecked(self.settings["dna"]["auto_load_last"]) self.dna_backup_check.setChecked(self.settings["dna"]["backup_before_edit"]) # 校准设置 self.calibration_auto_check.setChecked(self.settings["calibration"]["auto_calibrate"]) self.calibration_reference_check.setChecked(self.settings["calibration"]["show_reference"]) self.calibration_diff_check.setChecked(self.settings["calibration"]["show_differences"]) # 绑定设置 method = self.settings["binding"]["default_method"] index = self.binding_method_combo.findData(method) if index >= 0: self.binding_method_combo.setCurrentIndex(index) self.binding_mirror_check.setChecked(self.settings["binding"]["mirror_weights"]) self.binding_normalize_check.setChecked(self.settings["binding"]["normalize_weights"]) # BlendShape设置 format = self.settings["blendshape"]["default_export_format"] index = self.blendshape_format_combo.findData(format) if index >= 0: self.blendshape_format_combo.setCurrentIndex(index) self.blendshape_connect_check.setChecked(self.settings["blendshape"]["auto_connect_controllers"]) self.blendshape_corrective_check.setChecked(self.settings["blendshape"]["create_corrective_shapes"]) # UI设置 self.ui_font_slider.setValue(self.settings["ui"]["font_size"]) self._update_font_label(self.settings["ui"]["font_size"]) icon_size = self.settings["ui"]["icon_size"] index = self.ui_icon_combo.findData(icon_size) if index >= 0: self.ui_icon_combo.setCurrentIndex(index) self.ui_tooltips_check.setChecked(self.settings["ui"]["show_tooltips"]) self.ui_confirm_check.setChecked(self.settings["ui"]["confirm_on_exit"]) # 性能设置 self.performance_undo_spin.setValue(self.settings["performance"]["undo_queue_size"]) viewport_quality = self.settings["performance"]["viewport_quality"] index = self.performance_viewport_combo.findData(viewport_quality) if index >= 0: self.performance_viewport_combo.setCurrentIndex(index) self.performance_gpu_check.setChecked(self.settings["performance"]["use_gpu_acceleration"]) except Exception as e: cmds.warning(f"Error loading settings to dialog: {str(e)}") def _save_settings(self): """Save settings from dialog widgets""" try: # 常规设置 self.settings["general"]["language"] = self.language_combo.currentData() self.settings["general"]["theme"] = self.theme_combo.currentData() self.settings["general"]["auto_save"] = self.autosave_check.isChecked() self.settings["general"]["save_interval"] = self.autosave_interval_spin.value() self.settings["general"]["show_welcome"] = self.welcome_check.isChecked() # DNA设置 self.settings["dna"]["default_dna_path"] = self.dna_path_edit.text() self.settings["dna"]["auto_load_last"] = self.dna_autoload_check.isChecked() self.settings["dna"]["backup_before_edit"] = self.dna_backup_check.isChecked() # 校准设置 self.settings["calibration"]["auto_calibrate"] = self.calibration_auto_check.isChecked() self.settings["calibration"]["show_reference"] = self.calibration_reference_check.isChecked() self.settings["calibration"]["show_differences"] = self.calibration_diff_check.isChecked() # 绑定设置 self.settings["binding"]["default_method"] = self.binding_method_combo.currentData() self.settings["binding"]["mirror_weights"] = self.binding_mirror_check.isChecked() self.settings["binding"]["normalize_weights"] = self.binding_normalize_check.isChecked() # BlendShape设置 self.settings["blendshape"]["default_export_format"] = self.blendshape_format_combo.currentData() self.settings["blendshape"]["auto_connect_controllers"] = self.blendshape_connect_check.isChecked() self.settings["blendshape"]["create_corrective_shapes"] = self.blendshape_corrective_check.isChecked() # UI设置 self.settings["ui"]["font_size"] = self.ui_font_slider.value() self.settings["ui"]["icon_size"] = self.ui_icon_combo.currentData() self.settings["ui"]["show_tooltips"] = self.ui_tooltips_check.isChecked() self.settings["ui"]["confirm_on_exit"] = self.ui_confirm_check.isChecked() # 性能设置 self.settings["performance"]["undo_queue_size"] = self.performance_undo_spin.value() self.settings["performance"]["viewport_quality"] = self.performance_viewport_combo.currentData() self.settings["performance"]["use_gpu_acceleration"] = self.performance_gpu_check.isChecked() # 保存设置 self.settings_utils.save_settings(self.settings) return True except Exception as e: cmds.warning(f"Error saving settings from dialog: {str(e)}") return False def _apply_settings(self): """Apply settings""" if self._save_settings(): # 通知主窗口应用设置 self.parent().apply_settings(self.settings) def _reset_settings(self): """Reset settings""" reply = QtWidgets.QMessageBox.question( self, "Reset Settings", "Are you sure you want to reset all settings to default values?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No ) if reply == QtWidgets.QMessageBox.Yes: # Reset settings self.settings_utils.reset_settings() self.settings = self.settings_utils.get_all_settings() # 重新加载设置到对话框 self._load_settings() def _update_font_label(self, value): """Update font size label""" self.ui_font_label.setText(str(value)) def _browse_dna_path(self): """Browse DNA path""" dir_path = QtWidgets.QFileDialog.getExistingDirectory( self, "Select DNA File Directory", self.dna_path_edit.text() ) if dir_path: self.dna_path_edit.setText(dir_path) def _import_settings(self): """Import settings""" file_path, _ = QtWidgets.QFileDialog.getOpenFileName( self, "导入设置", "", "JSON文件 (*.json);;所有文件 (*.*)" ) if file_path: if self.settings_utils.import_settings(file_path): self.settings = self.settings_utils.get_all_settings() self._load_settings() QtWidgets.QMessageBox.information( self, "导入设置", f"Successfully imported settings: {file_path}" ) def _export_settings(self): """Export settings""" file_path, _ = QtWidgets.QFileDialog.getSaveFileName( self, "导出设置", "", "JSON文件 (*.json);;所有文件 (*.*)" ) if file_path: # 先保存当前设置 self._save_settings() if self.settings_utils.export_settings(file_path): QtWidgets.QMessageBox.information( self, "导出设置", f"Successfully exported settings: {file_path}" ) def accept(self): """Accept dialog""" if self._save_settings(): # 通知主窗口应用设置 self.parent().apply_settings(self.settings) super(SettingsDialog, self).accept() def reject(self): """Reject dialog""" reply = QtWidgets.QMessageBox.question( self, "Cancel Settings", "Are you sure you want to cancel all setting changes?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No ) if reply == QtWidgets.QMessageBox.Yes: super(SettingsDialog, self).reject()