forked from Rowland/EG
944 lines
37 KiB
Python
944 lines
37 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
拆装交互配置界面
|
|
实现模型的分步拆装交互功能配置
|
|
"""
|
|
|
|
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QTabWidget,
|
|
QWidget, QLabel, QListWidget, QListWidgetItem,
|
|
QPushButton, QComboBox, QSpinBox, QLineEdit,
|
|
QTextEdit, QGroupBox, QGridLayout, QCheckBox,
|
|
QSplitter, QTreeWidget, QTreeWidgetItem,
|
|
QMessageBox, QFileDialog, QScrollArea,
|
|
QFrame, QDoubleSpinBox, QSlider, QProgressBar)
|
|
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
|
|
from PyQt5.QtGui import QIcon, QPixmap, QFont
|
|
import os
|
|
import json
|
|
|
|
|
|
class AssemblyDisassemblyConfigDialog(QDialog):
|
|
"""拆装配置主对话框"""
|
|
|
|
def __init__(self, parent=None, world=None):
|
|
super().__init__(parent)
|
|
self.world = world
|
|
self.config_data = {
|
|
'models': [], # 参与拆装的模型列表
|
|
'steps': [], # 拆装步骤配置
|
|
'tools': [], # 使用的工具列表
|
|
'settings': {} # 全局设置
|
|
}
|
|
|
|
self.setupUI()
|
|
self.loadSceneModels()
|
|
|
|
def setupUI(self):
|
|
"""设置界面"""
|
|
self.setWindowTitle("拆装交互配置")
|
|
self.setModal(False) # 设置为非模态对话框
|
|
self.resize(1200, 800)
|
|
|
|
# 主布局
|
|
main_layout = QVBoxLayout(self)
|
|
|
|
# 创建分割器
|
|
splitter = QSplitter(Qt.Horizontal)
|
|
main_layout.addWidget(splitter)
|
|
|
|
# 左侧面板 - 模型和工具选择
|
|
left_panel = self.createLeftPanel()
|
|
splitter.addWidget(left_panel)
|
|
|
|
# 右侧面板 - 步骤配置
|
|
right_panel = self.createRightPanel()
|
|
splitter.addWidget(right_panel)
|
|
|
|
# 设置分割器比例
|
|
splitter.setSizes([400, 800])
|
|
|
|
# 底部按钮
|
|
button_layout = QHBoxLayout()
|
|
|
|
self.save_button = QPushButton("保存配置")
|
|
self.load_button = QPushButton("加载配置")
|
|
self.preview_button = QPushButton("预览效果")
|
|
self.apply_button = QPushButton("应用配置")
|
|
|
|
button_layout.addWidget(self.save_button)
|
|
button_layout.addWidget(self.load_button)
|
|
button_layout.addStretch()
|
|
button_layout.addWidget(self.preview_button)
|
|
button_layout.addWidget(self.apply_button)
|
|
|
|
main_layout.addLayout(button_layout)
|
|
|
|
# 连接信号
|
|
self.connectSignals()
|
|
|
|
def createLeftPanel(self):
|
|
"""创建左侧面板"""
|
|
left_widget = QWidget()
|
|
left_layout = QVBoxLayout(left_widget)
|
|
|
|
# 场景模型选择区域
|
|
models_group = QGroupBox("场景模型")
|
|
models_layout = QVBoxLayout(models_group)
|
|
|
|
# 模型搜索框
|
|
search_layout = QHBoxLayout()
|
|
search_label = QLabel("搜索:")
|
|
self.model_search_edit = QLineEdit()
|
|
self.model_search_edit.setPlaceholderText("输入模型名称搜索...")
|
|
search_layout.addWidget(search_label)
|
|
search_layout.addWidget(self.model_search_edit)
|
|
models_layout.addLayout(search_layout)
|
|
|
|
# 场景模型列表
|
|
self.scene_models_list = QTreeWidget()
|
|
self.scene_models_list.setHeaderLabel("场景中的模型")
|
|
self.scene_models_list.setSelectionMode(QTreeWidget.ExtendedSelection)
|
|
models_layout.addWidget(self.scene_models_list)
|
|
|
|
# 选中模型操作按钮
|
|
model_buttons_layout = QHBoxLayout()
|
|
self.add_to_config_button = QPushButton("添加到配置")
|
|
self.remove_from_config_button = QPushButton("从配置移除")
|
|
model_buttons_layout.addWidget(self.add_to_config_button)
|
|
model_buttons_layout.addWidget(self.remove_from_config_button)
|
|
models_layout.addLayout(model_buttons_layout)
|
|
|
|
left_layout.addWidget(models_group)
|
|
|
|
# 已配置模型列表
|
|
config_models_group = QGroupBox("已配置模型")
|
|
config_models_layout = QVBoxLayout(config_models_group)
|
|
|
|
self.config_models_list = QListWidget()
|
|
config_models_layout.addWidget(self.config_models_list)
|
|
|
|
left_layout.addWidget(config_models_group)
|
|
|
|
# 工具配置区域
|
|
tools_group = QGroupBox("工具配置")
|
|
tools_layout = QVBoxLayout(tools_group)
|
|
|
|
# 工具添加
|
|
tool_add_layout = QHBoxLayout()
|
|
self.tool_name_edit = QLineEdit()
|
|
self.tool_name_edit.setPlaceholderText("工具名称")
|
|
self.add_tool_button = QPushButton("添加工具")
|
|
tool_add_layout.addWidget(self.tool_name_edit)
|
|
tool_add_layout.addWidget(self.add_tool_button)
|
|
tools_layout.addLayout(tool_add_layout)
|
|
|
|
# 工具列表
|
|
self.tools_list = QListWidget()
|
|
tools_layout.addWidget(self.tools_list)
|
|
|
|
# 工具操作按钮
|
|
tool_buttons_layout = QHBoxLayout()
|
|
self.edit_tool_button = QPushButton("编辑")
|
|
self.remove_tool_button = QPushButton("删除")
|
|
tool_buttons_layout.addWidget(self.edit_tool_button)
|
|
tool_buttons_layout.addWidget(self.remove_tool_button)
|
|
tools_layout.addLayout(tool_buttons_layout)
|
|
|
|
left_layout.addWidget(tools_group)
|
|
|
|
return left_widget
|
|
|
|
def createRightPanel(self):
|
|
"""创建右侧面板"""
|
|
right_widget = QWidget()
|
|
right_layout = QVBoxLayout(right_widget)
|
|
|
|
# 步骤配置标签页
|
|
self.tab_widget = QTabWidget()
|
|
|
|
# 步骤列表标签页
|
|
self.steps_tab = self.createStepsTab()
|
|
self.tab_widget.addTab(self.steps_tab, "步骤配置")
|
|
|
|
# 全局设置标签页
|
|
self.settings_tab = self.createSettingsTab()
|
|
self.tab_widget.addTab(self.settings_tab, "全局设置")
|
|
|
|
right_layout.addWidget(self.tab_widget)
|
|
|
|
return right_widget
|
|
|
|
def createStepsTab(self):
|
|
"""创建步骤配置标签页"""
|
|
steps_widget = QWidget()
|
|
steps_layout = QHBoxLayout(steps_widget)
|
|
|
|
# 左侧步骤列表
|
|
steps_list_layout = QVBoxLayout()
|
|
|
|
# 步骤列表标题和操作按钮
|
|
steps_header_layout = QHBoxLayout()
|
|
steps_label = QLabel("拆装步骤")
|
|
steps_label.setFont(QFont("", 12, QFont.Bold))
|
|
self.add_step_button = QPushButton("添加步骤")
|
|
self.remove_step_button = QPushButton("删除步骤")
|
|
steps_header_layout.addWidget(steps_label)
|
|
steps_header_layout.addStretch()
|
|
steps_header_layout.addWidget(self.add_step_button)
|
|
steps_header_layout.addWidget(self.remove_step_button)
|
|
steps_list_layout.addLayout(steps_header_layout)
|
|
|
|
# 步骤列表
|
|
self.steps_list = QListWidget()
|
|
steps_list_layout.addWidget(self.steps_list)
|
|
|
|
# 步骤顺序调整按钮
|
|
step_order_layout = QHBoxLayout()
|
|
self.move_step_up_button = QPushButton("上移")
|
|
self.move_step_down_button = QPushButton("下移")
|
|
step_order_layout.addWidget(self.move_step_up_button)
|
|
step_order_layout.addWidget(self.move_step_down_button)
|
|
steps_list_layout.addLayout(step_order_layout)
|
|
|
|
# 右侧步骤详细配置
|
|
self.step_config_widget = self.createStepConfigWidget()
|
|
|
|
# 添加到布局
|
|
steps_layout.addLayout(steps_list_layout, 1)
|
|
steps_layout.addWidget(self.step_config_widget, 2)
|
|
|
|
return steps_widget
|
|
|
|
def createStepConfigWidget(self):
|
|
"""创建步骤详细配置部件"""
|
|
config_widget = QWidget()
|
|
config_layout = QVBoxLayout(config_widget)
|
|
|
|
# 滚动区域
|
|
scroll_area = QScrollArea()
|
|
scroll_area.setWidgetResizable(True)
|
|
scroll_content = QWidget()
|
|
scroll_layout = QVBoxLayout(scroll_content)
|
|
|
|
# 步骤基本信息
|
|
basic_info_group = QGroupBox("基本信息")
|
|
basic_info_layout = QGridLayout(basic_info_group)
|
|
|
|
# 步骤名称
|
|
basic_info_layout.addWidget(QLabel("步骤名称:"), 0, 0)
|
|
self.step_name_edit = QLineEdit()
|
|
basic_info_layout.addWidget(self.step_name_edit, 0, 1)
|
|
|
|
# 步骤描述
|
|
basic_info_layout.addWidget(QLabel("步骤描述:"), 1, 0)
|
|
self.step_description_edit = QTextEdit()
|
|
self.step_description_edit.setMaximumHeight(80)
|
|
basic_info_layout.addWidget(self.step_description_edit, 1, 1)
|
|
|
|
# 步骤类型
|
|
basic_info_layout.addWidget(QLabel("步骤类型:"), 2, 0)
|
|
self.step_type_combo = QComboBox()
|
|
self.step_type_combo.addItems(["拆卸", "安装"])
|
|
basic_info_layout.addWidget(self.step_type_combo, 2, 1)
|
|
|
|
scroll_layout.addWidget(basic_info_group)
|
|
|
|
# 目标模型配置
|
|
target_model_group = QGroupBox("目标模型")
|
|
target_model_layout = QGridLayout(target_model_group)
|
|
|
|
# 目标模型选择
|
|
target_model_layout.addWidget(QLabel("目标模型:"), 0, 0)
|
|
self.target_model_combo = QComboBox()
|
|
target_model_layout.addWidget(self.target_model_combo, 0, 1)
|
|
|
|
# 交互方式
|
|
target_model_layout.addWidget(QLabel("交互方式:"), 1, 0)
|
|
self.interaction_type_combo = QComboBox()
|
|
self.interaction_type_combo.addItems(["鼠标拖拽", "点击触发"])
|
|
target_model_layout.addWidget(self.interaction_type_combo, 1, 1)
|
|
|
|
scroll_layout.addWidget(target_model_group)
|
|
|
|
# 拖拽交互配置
|
|
self.drag_config_group = QGroupBox("拖拽交互配置")
|
|
drag_config_layout = QGridLayout(self.drag_config_group)
|
|
|
|
# 目标位置
|
|
drag_config_layout.addWidget(QLabel("目标位置 X:"), 0, 0)
|
|
self.target_pos_x_spin = QDoubleSpinBox()
|
|
self.target_pos_x_spin.setRange(-1000, 1000)
|
|
self.target_pos_x_spin.setSingleStep(0.1)
|
|
drag_config_layout.addWidget(self.target_pos_x_spin, 0, 1)
|
|
|
|
drag_config_layout.addWidget(QLabel("目标位置 Y:"), 1, 0)
|
|
self.target_pos_y_spin = QDoubleSpinBox()
|
|
self.target_pos_y_spin.setRange(-1000, 1000)
|
|
self.target_pos_y_spin.setSingleStep(0.1)
|
|
drag_config_layout.addWidget(self.target_pos_y_spin, 1, 1)
|
|
|
|
drag_config_layout.addWidget(QLabel("目标位置 Z:"), 2, 0)
|
|
self.target_pos_z_spin = QDoubleSpinBox()
|
|
self.target_pos_z_spin.setRange(-1000, 1000)
|
|
self.target_pos_z_spin.setSingleStep(0.1)
|
|
drag_config_layout.addWidget(self.target_pos_z_spin, 2, 1)
|
|
|
|
# 拖拽约束
|
|
self.constrain_x_check = QCheckBox("约束X轴")
|
|
self.constrain_y_check = QCheckBox("约束Y轴")
|
|
self.constrain_z_check = QCheckBox("约束Z轴")
|
|
|
|
constraint_layout = QHBoxLayout()
|
|
constraint_layout.addWidget(self.constrain_x_check)
|
|
constraint_layout.addWidget(self.constrain_y_check)
|
|
constraint_layout.addWidget(self.constrain_z_check)
|
|
|
|
drag_config_layout.addWidget(QLabel("拖拽约束:"), 3, 0)
|
|
drag_config_layout.addLayout(constraint_layout, 3, 1)
|
|
|
|
scroll_layout.addWidget(self.drag_config_group)
|
|
|
|
# 点击触发配置
|
|
self.click_config_group = QGroupBox("点击触发配置")
|
|
click_config_layout = QGridLayout(self.click_config_group)
|
|
|
|
# 位移距离
|
|
click_config_layout.addWidget(QLabel("位移距离 X:"), 0, 0)
|
|
self.move_distance_x_spin = QDoubleSpinBox()
|
|
self.move_distance_x_spin.setRange(-100, 100)
|
|
self.move_distance_x_spin.setSingleStep(0.1)
|
|
click_config_layout.addWidget(self.move_distance_x_spin, 0, 1)
|
|
|
|
click_config_layout.addWidget(QLabel("位移距离 Y:"), 1, 0)
|
|
self.move_distance_y_spin = QDoubleSpinBox()
|
|
self.move_distance_y_spin.setRange(-100, 100)
|
|
self.move_distance_y_spin.setSingleStep(0.1)
|
|
click_config_layout.addWidget(self.move_distance_y_spin, 1, 1)
|
|
|
|
click_config_layout.addWidget(QLabel("位移距离 Z:"), 2, 0)
|
|
self.move_distance_z_spin = QDoubleSpinBox()
|
|
self.move_distance_z_spin.setRange(-100, 100)
|
|
self.move_distance_z_spin.setSingleStep(0.1)
|
|
click_config_layout.addWidget(self.move_distance_z_spin, 2, 1)
|
|
|
|
# 位移时间
|
|
click_config_layout.addWidget(QLabel("位移时间(秒):"), 3, 0)
|
|
self.move_duration_spin = QDoubleSpinBox()
|
|
self.move_duration_spin.setRange(0.1, 10.0)
|
|
self.move_duration_spin.setSingleStep(0.1)
|
|
self.move_duration_spin.setValue(1.0)
|
|
click_config_layout.addWidget(self.move_duration_spin, 3, 1)
|
|
|
|
# 完成后隐藏
|
|
self.hide_after_move_check = QCheckBox("位移完成后隐藏模型")
|
|
click_config_layout.addWidget(self.hide_after_move_check, 4, 0, 1, 2)
|
|
|
|
scroll_layout.addWidget(self.click_config_group)
|
|
|
|
# 提示音频配置
|
|
audio_config_group = QGroupBox("步骤提示")
|
|
audio_config_layout = QGridLayout(audio_config_group)
|
|
|
|
# 提示音频文件
|
|
audio_config_layout.addWidget(QLabel("提示音频:"), 0, 0)
|
|
audio_file_layout = QHBoxLayout()
|
|
self.audio_file_edit = QLineEdit()
|
|
self.browse_audio_button = QPushButton("浏览...")
|
|
audio_file_layout.addWidget(self.audio_file_edit)
|
|
audio_file_layout.addWidget(self.browse_audio_button)
|
|
audio_config_layout.addLayout(audio_file_layout, 0, 1)
|
|
|
|
# 提示文字
|
|
audio_config_layout.addWidget(QLabel("提示文字:"), 1, 0)
|
|
self.hint_text_edit = QTextEdit()
|
|
self.hint_text_edit.setMaximumHeight(60)
|
|
audio_config_layout.addWidget(self.hint_text_edit, 1, 1)
|
|
|
|
scroll_layout.addWidget(audio_config_group)
|
|
|
|
# 使用工具配置
|
|
tool_config_group = QGroupBox("使用工具")
|
|
tool_config_layout = QGridLayout(tool_config_group)
|
|
|
|
tool_config_layout.addWidget(QLabel("所需工具:"), 0, 0)
|
|
self.required_tool_combo = QComboBox()
|
|
self.required_tool_combo.addItem("无")
|
|
tool_config_layout.addWidget(self.required_tool_combo, 0, 1)
|
|
|
|
scroll_layout.addWidget(tool_config_group)
|
|
|
|
# 设置滚动区域
|
|
scroll_area.setWidget(scroll_content)
|
|
config_layout.addWidget(scroll_area)
|
|
|
|
# 默认隐藏点击配置
|
|
self.click_config_group.setVisible(False)
|
|
|
|
return config_widget
|
|
|
|
def createSettingsTab(self):
|
|
"""创建全局设置标签页"""
|
|
settings_widget = QWidget()
|
|
settings_layout = QVBoxLayout(settings_widget)
|
|
|
|
# 全局设置组
|
|
global_settings_group = QGroupBox("全局设置")
|
|
global_settings_layout = QGridLayout(global_settings_group)
|
|
|
|
# 自动播放提示音
|
|
self.auto_play_audio_check = QCheckBox("自动播放步骤提示音")
|
|
self.auto_play_audio_check.setChecked(True)
|
|
global_settings_layout.addWidget(self.auto_play_audio_check, 0, 0, 1, 2)
|
|
|
|
# 显示步骤提示文字
|
|
self.show_hint_text_check = QCheckBox("显示步骤提示文字")
|
|
self.show_hint_text_check.setChecked(True)
|
|
global_settings_layout.addWidget(self.show_hint_text_check, 1, 0, 1, 2)
|
|
|
|
# 步骤完成确认
|
|
self.require_confirmation_check = QCheckBox("步骤完成需要确认")
|
|
global_settings_layout.addWidget(self.require_confirmation_check, 2, 0, 1, 2)
|
|
|
|
# 拖拽灵敏度
|
|
global_settings_layout.addWidget(QLabel("拖拽灵敏度:"), 3, 0)
|
|
self.drag_sensitivity_slider = QSlider(Qt.Horizontal)
|
|
self.drag_sensitivity_slider.setRange(1, 10)
|
|
self.drag_sensitivity_slider.setValue(5)
|
|
global_settings_layout.addWidget(self.drag_sensitivity_slider, 3, 1)
|
|
|
|
# 动画速度
|
|
global_settings_layout.addWidget(QLabel("动画速度:"), 4, 0)
|
|
self.animation_speed_slider = QSlider(Qt.Horizontal)
|
|
self.animation_speed_slider.setRange(1, 10)
|
|
self.animation_speed_slider.setValue(5)
|
|
global_settings_layout.addWidget(self.animation_speed_slider, 4, 1)
|
|
|
|
settings_layout.addWidget(global_settings_group)
|
|
|
|
# 预设配置组
|
|
presets_group = QGroupBox("预设配置")
|
|
presets_layout = QVBoxLayout(presets_group)
|
|
|
|
# 预设列表
|
|
self.presets_list = QListWidget()
|
|
presets_layout.addWidget(self.presets_list)
|
|
|
|
# 预设操作按钮
|
|
preset_buttons_layout = QHBoxLayout()
|
|
self.save_preset_button = QPushButton("保存为预设")
|
|
self.load_preset_button = QPushButton("加载预设")
|
|
self.delete_preset_button = QPushButton("删除预设")
|
|
preset_buttons_layout.addWidget(self.save_preset_button)
|
|
preset_buttons_layout.addWidget(self.load_preset_button)
|
|
preset_buttons_layout.addWidget(self.delete_preset_button)
|
|
presets_layout.addLayout(preset_buttons_layout)
|
|
|
|
settings_layout.addWidget(presets_group)
|
|
|
|
# 添加弹性空间
|
|
settings_layout.addStretch()
|
|
|
|
return settings_widget
|
|
|
|
def connectSignals(self):
|
|
"""连接信号槽"""
|
|
# 模型搜索
|
|
self.model_search_edit.textChanged.connect(self.filterSceneModels)
|
|
|
|
# 模型操作
|
|
self.add_to_config_button.clicked.connect(self.addModelsToConfig)
|
|
self.remove_from_config_button.clicked.connect(self.removeModelsFromConfig)
|
|
|
|
# 工具操作
|
|
self.add_tool_button.clicked.connect(self.addTool)
|
|
self.edit_tool_button.clicked.connect(self.editTool)
|
|
self.remove_tool_button.clicked.connect(self.removeTool)
|
|
|
|
# 步骤操作
|
|
self.add_step_button.clicked.connect(self.addStep)
|
|
self.remove_step_button.clicked.connect(self.removeStep)
|
|
self.move_step_up_button.clicked.connect(self.moveStepUp)
|
|
self.move_step_down_button.clicked.connect(self.moveStepDown)
|
|
self.steps_list.itemSelectionChanged.connect(self.onStepSelectionChanged)
|
|
|
|
# 步骤配置变化
|
|
self.interaction_type_combo.currentTextChanged.connect(self.onInteractionTypeChanged)
|
|
self.browse_audio_button.clicked.connect(self.browseAudioFile)
|
|
|
|
# 步骤配置实时更新
|
|
self.step_name_edit.textChanged.connect(self.updateCurrentStep)
|
|
self.step_description_edit.textChanged.connect(self.updateCurrentStep)
|
|
self.step_type_combo.currentTextChanged.connect(self.updateCurrentStep)
|
|
self.target_model_combo.currentTextChanged.connect(self.updateCurrentStep)
|
|
|
|
# 按钮操作
|
|
self.save_button.clicked.connect(self.saveConfiguration)
|
|
self.load_button.clicked.connect(self.loadConfiguration)
|
|
self.preview_button.clicked.connect(self.previewConfiguration)
|
|
self.apply_button.clicked.connect(self.applyConfiguration)
|
|
|
|
def loadSceneModels(self):
|
|
"""加载场景中的模型"""
|
|
if not self.world:
|
|
return
|
|
|
|
# 清空现有列表
|
|
self.scene_models_list.clear()
|
|
|
|
# 遍历场景中的所有节点
|
|
self._addNodeToTree(self.world.render, self.scene_models_list)
|
|
|
|
# 展开根节点
|
|
self.scene_models_list.expandAll()
|
|
|
|
def _addNodeToTree(self, node, parent_item):
|
|
"""递归添加节点到树形控件"""
|
|
if node.getName() in ['render', 'camera', 'aspect2d', 'pixel2d']:
|
|
# 跳过系统节点
|
|
for child in node.getChildren():
|
|
self._addNodeToTree(child, parent_item)
|
|
return
|
|
|
|
# 创建树形项
|
|
if isinstance(parent_item, QTreeWidget):
|
|
item = QTreeWidgetItem(parent_item)
|
|
else:
|
|
item = QTreeWidgetItem(parent_item)
|
|
|
|
item.setText(0, node.getName())
|
|
item.setData(0, Qt.UserRole, node)
|
|
|
|
# 添加子节点
|
|
for child in node.getChildren():
|
|
self._addNodeToTree(child, item)
|
|
|
|
def filterSceneModels(self, text):
|
|
"""过滤场景模型列表"""
|
|
# 简单的文本过滤实现
|
|
def filterItems(item):
|
|
item_text = item.text(0).lower()
|
|
text_lower = text.lower()
|
|
|
|
# 检查当前项是否匹配
|
|
matches = text_lower in item_text
|
|
|
|
# 检查子项
|
|
child_matches = False
|
|
for i in range(item.childCount()):
|
|
child_item = item.child(i)
|
|
if filterItems(child_item):
|
|
child_matches = True
|
|
|
|
# 显示/隐藏项
|
|
item.setHidden(not (matches or child_matches))
|
|
|
|
return matches or child_matches
|
|
|
|
# 从根项开始过滤
|
|
for i in range(self.scene_models_list.topLevelItemCount()):
|
|
filterItems(self.scene_models_list.topLevelItem(i))
|
|
|
|
def addModelsToConfig(self):
|
|
"""添加选中的模型到配置"""
|
|
selected_items = self.scene_models_list.selectedItems()
|
|
|
|
for item in selected_items:
|
|
node = item.data(0, Qt.UserRole)
|
|
if node:
|
|
model_name = node.getName()
|
|
|
|
# 检查是否已经存在
|
|
existing_items = self.config_models_list.findItems(model_name, Qt.MatchExactly)
|
|
if not existing_items:
|
|
# 添加到配置模型列表
|
|
list_item = QListWidgetItem(model_name)
|
|
list_item.setData(Qt.UserRole, node)
|
|
self.config_models_list.addItem(list_item)
|
|
|
|
# 添加到配置数据
|
|
self.config_data['models'].append({
|
|
'name': model_name,
|
|
'node': node,
|
|
'original_pos': node.getPos(),
|
|
'original_hpr': node.getHpr()
|
|
})
|
|
|
|
# 更新目标模型下拉框
|
|
self.target_model_combo.addItem(model_name)
|
|
|
|
def removeModelsFromConfig(self):
|
|
"""从配置中移除选中的模型"""
|
|
selected_items = self.config_models_list.selectedItems()
|
|
|
|
for item in selected_items:
|
|
model_name = item.text()
|
|
|
|
# 从列表中移除
|
|
row = self.config_models_list.row(item)
|
|
self.config_models_list.takeItem(row)
|
|
|
|
# 从配置数据中移除
|
|
self.config_data['models'] = [
|
|
model for model in self.config_data['models']
|
|
if model['name'] != model_name
|
|
]
|
|
|
|
# 从目标模型下拉框中移除
|
|
index = self.target_model_combo.findText(model_name)
|
|
if index >= 0:
|
|
self.target_model_combo.removeItem(index)
|
|
|
|
def addTool(self):
|
|
"""添加工具"""
|
|
tool_name = self.tool_name_edit.text().strip()
|
|
if not tool_name:
|
|
QMessageBox.warning(self, "警告", "请输入工具名称")
|
|
return
|
|
|
|
# 检查是否已存在
|
|
existing_items = self.tools_list.findItems(tool_name, Qt.MatchExactly)
|
|
if existing_items:
|
|
QMessageBox.warning(self, "警告", "工具已存在")
|
|
return
|
|
|
|
# 添加到工具列表
|
|
self.tools_list.addItem(tool_name)
|
|
self.required_tool_combo.addItem(tool_name)
|
|
|
|
# 添加到配置数据
|
|
self.config_data['tools'].append({
|
|
'name': tool_name,
|
|
'description': '',
|
|
'icon': ''
|
|
})
|
|
|
|
# 清空输入框
|
|
self.tool_name_edit.clear()
|
|
|
|
def editTool(self):
|
|
"""编辑工具"""
|
|
current_item = self.tools_list.currentItem()
|
|
if not current_item:
|
|
QMessageBox.warning(self, "警告", "请选择要编辑的工具")
|
|
return
|
|
|
|
# 这里可以添加工具编辑对话框
|
|
QMessageBox.information(self, "提示", "工具编辑功能待实现")
|
|
|
|
def removeTool(self):
|
|
"""删除工具"""
|
|
current_item = self.tools_list.currentItem()
|
|
if not current_item:
|
|
QMessageBox.warning(self, "警告", "请选择要删除的工具")
|
|
return
|
|
|
|
tool_name = current_item.text()
|
|
|
|
# 从列表中移除
|
|
row = self.tools_list.row(current_item)
|
|
self.tools_list.takeItem(row)
|
|
|
|
# 从下拉框中移除
|
|
index = self.required_tool_combo.findText(tool_name)
|
|
if index >= 0:
|
|
self.required_tool_combo.removeItem(index)
|
|
|
|
# 从配置数据中移除
|
|
self.config_data['tools'] = [
|
|
tool for tool in self.config_data['tools']
|
|
if tool['name'] != tool_name
|
|
]
|
|
|
|
def addStep(self):
|
|
"""添加步骤"""
|
|
step_count = len(self.config_data['steps']) + 1
|
|
step_name = f"步骤 {step_count}"
|
|
|
|
# 创建新步骤数据
|
|
step_data = {
|
|
'name': step_name,
|
|
'description': '',
|
|
'type': '拆卸',
|
|
'target_model': '',
|
|
'interaction_type': '鼠标拖拽',
|
|
'target_position': [0, 0, 0],
|
|
'constraints': {'x': False, 'y': False, 'z': False},
|
|
'move_distance': [0, 0, 0],
|
|
'move_duration': 1.0,
|
|
'hide_after_move': False,
|
|
'audio_file': '',
|
|
'hint_text': '',
|
|
'required_tool': '无'
|
|
}
|
|
|
|
# 添加到配置数据
|
|
self.config_data['steps'].append(step_data)
|
|
|
|
# 添加到步骤列表
|
|
list_item = QListWidgetItem(step_name)
|
|
list_item.setData(Qt.UserRole, step_data)
|
|
self.steps_list.addItem(list_item)
|
|
|
|
# 选中新添加的步骤
|
|
self.steps_list.setCurrentItem(list_item)
|
|
|
|
def removeStep(self):
|
|
"""删除步骤"""
|
|
current_item = self.steps_list.currentItem()
|
|
if not current_item:
|
|
QMessageBox.warning(self, "警告", "请选择要删除的步骤")
|
|
return
|
|
|
|
# 从列表中移除
|
|
row = self.steps_list.row(current_item)
|
|
self.steps_list.takeItem(row)
|
|
|
|
# 从配置数据中移除
|
|
self.config_data['steps'].pop(row)
|
|
|
|
# 重新编号步骤
|
|
self.renumberSteps()
|
|
|
|
def moveStepUp(self):
|
|
"""上移步骤"""
|
|
current_row = self.steps_list.currentRow()
|
|
if current_row <= 0:
|
|
return
|
|
|
|
# 交换数据
|
|
self.config_data['steps'][current_row], self.config_data['steps'][current_row - 1] = \
|
|
self.config_data['steps'][current_row - 1], self.config_data['steps'][current_row]
|
|
|
|
# 交换列表项
|
|
current_item = self.steps_list.takeItem(current_row)
|
|
self.steps_list.insertItem(current_row - 1, current_item)
|
|
self.steps_list.setCurrentRow(current_row - 1)
|
|
|
|
# 重新编号
|
|
self.renumberSteps()
|
|
|
|
def moveStepDown(self):
|
|
"""下移步骤"""
|
|
current_row = self.steps_list.currentRow()
|
|
if current_row >= self.steps_list.count() - 1:
|
|
return
|
|
|
|
# 交换数据
|
|
self.config_data['steps'][current_row], self.config_data['steps'][current_row + 1] = \
|
|
self.config_data['steps'][current_row + 1], self.config_data['steps'][current_row]
|
|
|
|
# 交换列表项
|
|
current_item = self.steps_list.takeItem(current_row)
|
|
self.steps_list.insertItem(current_row + 1, current_item)
|
|
self.steps_list.setCurrentRow(current_row + 1)
|
|
|
|
# 重新编号
|
|
self.renumberSteps()
|
|
|
|
def renumberSteps(self):
|
|
"""重新编号步骤"""
|
|
for i in range(self.steps_list.count()):
|
|
item = self.steps_list.item(i)
|
|
step_data = item.data(Qt.UserRole)
|
|
new_name = f"步骤 {i + 1}"
|
|
step_data['name'] = new_name
|
|
item.setText(new_name)
|
|
|
|
def onStepSelectionChanged(self):
|
|
"""步骤选择改变"""
|
|
current_item = self.steps_list.currentItem()
|
|
if not current_item:
|
|
return
|
|
|
|
step_data = current_item.data(Qt.UserRole)
|
|
if not step_data:
|
|
return
|
|
|
|
# 更新步骤配置界面
|
|
self.loadStepConfiguration(step_data)
|
|
|
|
def loadStepConfiguration(self, step_data):
|
|
"""加载步骤配置到界面"""
|
|
# 基本信息
|
|
self.step_name_edit.setText(step_data.get('name', ''))
|
|
self.step_description_edit.setPlainText(step_data.get('description', ''))
|
|
self.step_type_combo.setCurrentText(step_data.get('type', '拆卸'))
|
|
|
|
# 目标模型
|
|
target_model = step_data.get('target_model', '')
|
|
index = self.target_model_combo.findText(target_model)
|
|
if index >= 0:
|
|
self.target_model_combo.setCurrentIndex(index)
|
|
|
|
# 交互方式
|
|
interaction_type = step_data.get('interaction_type', '鼠标拖拽')
|
|
self.interaction_type_combo.setCurrentText(interaction_type)
|
|
self.onInteractionTypeChanged(interaction_type)
|
|
|
|
# 拖拽配置
|
|
target_pos = step_data.get('target_position', [0, 0, 0])
|
|
self.target_pos_x_spin.setValue(target_pos[0])
|
|
self.target_pos_y_spin.setValue(target_pos[1])
|
|
self.target_pos_z_spin.setValue(target_pos[2])
|
|
|
|
constraints = step_data.get('constraints', {'x': False, 'y': False, 'z': False})
|
|
self.constrain_x_check.setChecked(constraints.get('x', False))
|
|
self.constrain_y_check.setChecked(constraints.get('y', False))
|
|
self.constrain_z_check.setChecked(constraints.get('z', False))
|
|
|
|
# 点击触发配置
|
|
move_distance = step_data.get('move_distance', [0, 0, 0])
|
|
self.move_distance_x_spin.setValue(move_distance[0])
|
|
self.move_distance_y_spin.setValue(move_distance[1])
|
|
self.move_distance_z_spin.setValue(move_distance[2])
|
|
|
|
self.move_duration_spin.setValue(step_data.get('move_duration', 1.0))
|
|
self.hide_after_move_check.setChecked(step_data.get('hide_after_move', False))
|
|
|
|
# 提示配置
|
|
self.audio_file_edit.setText(step_data.get('audio_file', ''))
|
|
self.hint_text_edit.setPlainText(step_data.get('hint_text', ''))
|
|
|
|
# 工具配置
|
|
required_tool = step_data.get('required_tool', '无')
|
|
index = self.required_tool_combo.findText(required_tool)
|
|
if index >= 0:
|
|
self.required_tool_combo.setCurrentIndex(index)
|
|
|
|
def onInteractionTypeChanged(self, interaction_type):
|
|
"""交互方式改变"""
|
|
if interaction_type == "鼠标拖拽":
|
|
self.drag_config_group.setVisible(True)
|
|
self.click_config_group.setVisible(False)
|
|
else: # 点击触发
|
|
self.drag_config_group.setVisible(False)
|
|
self.click_config_group.setVisible(True)
|
|
|
|
def updateCurrentStep(self):
|
|
"""更新当前步骤数据"""
|
|
current_item = self.steps_list.currentItem()
|
|
if not current_item:
|
|
return
|
|
|
|
step_data = current_item.data(Qt.UserRole)
|
|
if not step_data:
|
|
return
|
|
|
|
# 更新步骤数据
|
|
step_data['name'] = self.step_name_edit.text()
|
|
step_data['description'] = self.step_description_edit.toPlainText()
|
|
step_data['type'] = self.step_type_combo.currentText()
|
|
step_data['target_model'] = self.target_model_combo.currentText()
|
|
step_data['interaction_type'] = self.interaction_type_combo.currentText()
|
|
|
|
# 更新列表项显示
|
|
current_item.setText(step_data['name'])
|
|
|
|
def browseAudioFile(self):
|
|
"""浏览音频文件"""
|
|
file_path, _ = QFileDialog.getOpenFileName(
|
|
self, "选择音频文件", "",
|
|
"音频文件 (*.wav *.mp3 *.ogg *.flac);;所有文件 (*)"
|
|
)
|
|
|
|
if file_path:
|
|
self.audio_file_edit.setText(file_path)
|
|
|
|
def saveConfiguration(self):
|
|
"""保存配置"""
|
|
file_path, _ = QFileDialog.getSaveFileName(
|
|
self, "保存拆装配置", "",
|
|
"JSON文件 (*.json);;所有文件 (*)"
|
|
)
|
|
|
|
if file_path:
|
|
try:
|
|
# 准备保存的数据(去除不能序列化的对象)
|
|
save_data = {
|
|
'models': [
|
|
{
|
|
'name': model['name'],
|
|
'original_pos': list(model['original_pos']),
|
|
'original_hpr': list(model['original_hpr'])
|
|
} for model in self.config_data['models']
|
|
],
|
|
'steps': self.config_data['steps'],
|
|
'tools': self.config_data['tools'],
|
|
'settings': {
|
|
'auto_play_audio': self.auto_play_audio_check.isChecked(),
|
|
'show_hint_text': self.show_hint_text_check.isChecked(),
|
|
'require_confirmation': self.require_confirmation_check.isChecked(),
|
|
'drag_sensitivity': self.drag_sensitivity_slider.value(),
|
|
'animation_speed': self.animation_speed_slider.value()
|
|
}
|
|
}
|
|
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
json.dump(save_data, f, ensure_ascii=False, indent=2)
|
|
|
|
QMessageBox.information(self, "成功", "配置保存成功")
|
|
|
|
except Exception as e:
|
|
QMessageBox.critical(self, "错误", f"保存配置失败: {str(e)}")
|
|
|
|
def loadConfiguration(self):
|
|
"""加载配置"""
|
|
file_path, _ = QFileDialog.getOpenFileName(
|
|
self, "加载拆装配置", "",
|
|
"JSON文件 (*.json);;所有文件 (*)"
|
|
)
|
|
|
|
if file_path:
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
data = json.load(f)
|
|
|
|
# 加载配置数据
|
|
self.loadConfigurationData(data)
|
|
QMessageBox.information(self, "成功", "配置加载成功")
|
|
|
|
except Exception as e:
|
|
QMessageBox.critical(self, "错误", f"加载配置失败: {str(e)}")
|
|
|
|
def loadConfigurationData(self, data):
|
|
"""加载配置数据到界面"""
|
|
# 清空现有配置
|
|
self.config_models_list.clear()
|
|
self.target_model_combo.clear()
|
|
self.steps_list.clear()
|
|
|
|
# 加载模型配置
|
|
# 注意:这里需要重新匹配场景中的模型节点
|
|
|
|
# 加载步骤配置
|
|
self.config_data['steps'] = data.get('steps', [])
|
|
for step_data in self.config_data['steps']:
|
|
list_item = QListWidgetItem(step_data['name'])
|
|
list_item.setData(Qt.UserRole, step_data)
|
|
self.steps_list.addItem(list_item)
|
|
|
|
# 加载工具配置
|
|
self.tools_list.clear()
|
|
self.required_tool_combo.clear()
|
|
self.required_tool_combo.addItem("无")
|
|
|
|
self.config_data['tools'] = data.get('tools', [])
|
|
for tool in self.config_data['tools']:
|
|
self.tools_list.addItem(tool['name'])
|
|
self.required_tool_combo.addItem(tool['name'])
|
|
|
|
# 加载全局设置
|
|
settings = data.get('settings', {})
|
|
self.auto_play_audio_check.setChecked(settings.get('auto_play_audio', True))
|
|
self.show_hint_text_check.setChecked(settings.get('show_hint_text', True))
|
|
self.require_confirmation_check.setChecked(settings.get('require_confirmation', False))
|
|
self.drag_sensitivity_slider.setValue(settings.get('drag_sensitivity', 5))
|
|
self.animation_speed_slider.setValue(settings.get('animation_speed', 5))
|
|
|
|
def previewConfiguration(self):
|
|
"""预览配置效果"""
|
|
QMessageBox.information(self, "提示", "预览功能待实现")
|
|
|
|
def applyConfiguration(self):
|
|
"""应用配置"""
|
|
QMessageBox.information(self, "提示", "应用配置功能待实现") |