forked from Rowland/EG
1.UI更新
This commit is contained in:
parent
64c7a30bc2
commit
b386818f76
@ -49,6 +49,8 @@ from rplibs.pyqt_imports import * #noqa
|
||||
# Load the generated UI Layout
|
||||
from ui.main_window_generated import Ui_MainWindow # noqa
|
||||
|
||||
from ui.widgets import UniversalMessageDialog
|
||||
|
||||
from rpcore.pluginbase.manager import PluginManager # noqa
|
||||
from rpcore.util.network_communication import NetworkCommunication # noqa
|
||||
from rpcore.mount_manager import MountManager # noqa
|
||||
@ -119,9 +121,13 @@ class PluginConfigurator(QMainWindow, Ui_MainWindow):
|
||||
self, "Warning", msg, QMessageBox.Yes, QMessageBox.No)
|
||||
if reply == QMessageBox.Yes:
|
||||
|
||||
QMessageBox.information(
|
||||
self, "Success",
|
||||
"Settings have been reset! You may have to restart the pipeline.")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"Success",
|
||||
"Settings have been reset! You may have to restart the pipeline.",
|
||||
show_cancel=False,
|
||||
confirm_text="OK"
|
||||
)
|
||||
self._plugin_mgr.reset_plugin_settings(self._current_plugin)
|
||||
|
||||
# Save config
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 546 B |
Binary file not shown.
|
Before Width: | Height: | Size: 482 B |
@ -19,7 +19,7 @@ from PyQt5.QtWidgets import (
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
# 导入自定义对话框
|
||||
from ui.widgets import NewProjectDialog
|
||||
from ui.widgets import NewProjectDialog, UniversalMessageDialog
|
||||
|
||||
class ProjectManager:
|
||||
"""项目管理器 - 统一管理项目的生命周期"""
|
||||
@ -103,11 +103,23 @@ class ProjectManager:
|
||||
parent_window.current_project_path = full_project_path
|
||||
|
||||
# 显示成功消息
|
||||
QMessageBox.information(parent_window, "成功", f"项目 '{project_name}' 创建成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
parent_window,
|
||||
"成功",
|
||||
f"项目 '{project_name}' 创建成功!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(parent_window, "错误", f"创建项目失败: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
parent_window,
|
||||
"错误",
|
||||
f"创建项目失败: {str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return False
|
||||
|
||||
def openProject(self, parent_window):
|
||||
@ -127,7 +139,13 @@ class ProjectManager:
|
||||
# 检查是否是有效的项目文件夹
|
||||
config_file = os.path.join(project_path, "project.json")
|
||||
if not os.path.exists(config_file):
|
||||
QMessageBox.warning(parent_window, "警告", "选择的不是有效的项目文件夹!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
parent_window,
|
||||
"警告",
|
||||
"选择的不是有效的项目文件夹!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return False
|
||||
|
||||
# 读取项目配置
|
||||
@ -161,7 +179,13 @@ class ProjectManager:
|
||||
if hasattr(parent_window, 'fileView') and hasattr(parent_window, 'fileModel'):
|
||||
parent_window.fileView.setRootIndex(parent_window.fileModel.index(project_path))
|
||||
|
||||
QMessageBox.information(parent_window, "成功", "项目加载成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
parent_window,
|
||||
"成功",
|
||||
"项目加载成功!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return True
|
||||
# 检查场景文件
|
||||
# scene_file = os.path.join(project_path, "scenes", "scene.bam")
|
||||
@ -200,7 +224,13 @@ class ProjectManager:
|
||||
# return False
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(parent_window, "错误", f"加载项目时发生错误:{str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
parent_window,
|
||||
"错误",
|
||||
f"加载项目时发生错误:{str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return False
|
||||
|
||||
def openProjectForPath(self, project_path, parent_window=None):
|
||||
@ -217,7 +247,13 @@ class ProjectManager:
|
||||
config_file = os.path.join(project_path, "project.json")
|
||||
if not os.path.exists(config_file):
|
||||
if parent_window:
|
||||
QMessageBox.warning(parent_window, "警告", f"选择的不是有效的项目文件夹!{project_path}")
|
||||
UniversalMessageDialog.show_warning(
|
||||
parent_window,
|
||||
"警告",
|
||||
f"选择的不是有效的项目文件夹!{project_path}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
print("警告: 选择的不是有效的项目文件夹!")
|
||||
return False
|
||||
@ -255,13 +291,25 @@ class ProjectManager:
|
||||
if hasattr(parent_window, 'fileView') and hasattr(parent_window, 'fileModel'):
|
||||
parent_window.fileView.setRootIndex(parent_window.fileModel.index(project_path))
|
||||
|
||||
QMessageBox.information(parent_window, "成功", "项目加载成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
parent_window,
|
||||
"成功",
|
||||
"项目加载成功!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
print(f"项目 '{project_path}' 加载成功!")
|
||||
return True
|
||||
else:
|
||||
if parent_window:
|
||||
QMessageBox.warning(parent_window, "错误", "加载场景失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
parent_window,
|
||||
"错误",
|
||||
"加载场景失败!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
print("错误: 加载场景失败!")
|
||||
return False
|
||||
@ -269,7 +317,13 @@ class ProjectManager:
|
||||
except Exception as e:
|
||||
error_msg = f"加载项目时发生错误:{str(e)}"
|
||||
if parent_window:
|
||||
QMessageBox.critical(parent_window, "错误", error_msg)
|
||||
UniversalMessageDialog.show_error(
|
||||
parent_window,
|
||||
"错误",
|
||||
error_msg,
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
print(error_msg)
|
||||
return False
|
||||
@ -283,7 +337,13 @@ class ProjectManager:
|
||||
if hasattr(parent_window, 'current_project_path'):
|
||||
self.current_project_path = parent_window.current_project_path
|
||||
else:
|
||||
QMessageBox.warning(parent_window, "警告", "请先创建或打开一个项目!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
parent_window,
|
||||
"警告",
|
||||
"请先创建或打开一个项目!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return False
|
||||
|
||||
project_path = self.current_project_path
|
||||
@ -324,14 +384,32 @@ class ProjectManager:
|
||||
project_name = os.path.basename(project_path)
|
||||
self.updateWindowTitle(parent_window, project_name)
|
||||
|
||||
QMessageBox.information(parent_window, "成功", "项目保存成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
parent_window,
|
||||
"成功",
|
||||
"项目保存成功!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return True
|
||||
else:
|
||||
QMessageBox.warning(parent_window, "错误", "保存场景失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
parent_window,
|
||||
"错误",
|
||||
"保存场景失败!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(parent_window, "错误", f"保存项目时发生错误:{str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
parent_window,
|
||||
"错误",
|
||||
f"保存项目时发生错误:{str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return False
|
||||
|
||||
# ==================== 项目打包功能 ====================
|
||||
@ -1099,4 +1177,4 @@ def updateWindowTitle(window, project_name=None):
|
||||
if project_name:
|
||||
window.setWindowTitle(f"{base_title} - {project_name}")
|
||||
else:
|
||||
window.setWindowTitle(base_title)
|
||||
window.setWindowTitle(base_title)
|
||||
|
||||
@ -64,6 +64,11 @@ class IconManager:
|
||||
'minimize_icon': 'minimize_icon.png',
|
||||
'windowing_icon': 'windowing_icon.png',
|
||||
'close_icon': 'close_icon.png',
|
||||
|
||||
# 弹窗图标
|
||||
'success_icon': 'success_icon.png',
|
||||
'warning_icon': 'warning_icon.png',
|
||||
'fail_icon': 'delete_fail_icon.png',
|
||||
}
|
||||
|
||||
# 初始化默认图标
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""
|
||||
"""
|
||||
主窗口设置模块
|
||||
|
||||
负责主窗口的界面构建和事件绑定:
|
||||
@ -21,7 +21,9 @@ from PyQt5.QtCore import Qt, QDir, QTimer, QSize, QPoint, QUrl, QRect
|
||||
from direct.showbase.ShowBaseGlobal import aspect2d
|
||||
from panda3d.core import OrthographicLens
|
||||
|
||||
from ui.widgets import CustomPanda3DWidget, CustomFileView, CustomTreeWidget,CustomAssetsTreeWidget, CustomConsoleDockWidget
|
||||
from ui.widgets import (CustomPanda3DWidget, CustomFileView, CustomTreeWidget,
|
||||
CustomAssetsTreeWidget, CustomConsoleDockWidget,
|
||||
UniversalMessageDialog)
|
||||
from ui.icon_manager import get_icon_manager, get_icon
|
||||
|
||||
|
||||
@ -226,6 +228,12 @@ class StyledTerrainDialog(QDialog):
|
||||
widget.setRange(field.get("min", 0), field.get("max", 1000))
|
||||
widget.setSingleStep(field.get("step", 1))
|
||||
widget.setValue(field.get("value", field.get("default", 0)))
|
||||
elif widget_type == "text":
|
||||
widget = QLineEdit()
|
||||
widget.setText(field.get("value", field.get("default", "")))
|
||||
if field.get("placeholder"):
|
||||
widget.setPlaceholderText(field.get("placeholder"))
|
||||
widget.setClearButtonEnabled(True)
|
||||
else:
|
||||
widget = QDoubleSpinBox()
|
||||
widget.setRange(field.get("min", 0.0), field.get("max", 1000.0))
|
||||
@ -345,6 +353,8 @@ class StyledTerrainDialog(QDialog):
|
||||
widget = self.field_widgets.get(name)
|
||||
if isinstance(widget, (QDoubleSpinBox, QSpinBox)):
|
||||
return widget.value()
|
||||
if isinstance(widget, QLineEdit):
|
||||
return widget.text()
|
||||
return None
|
||||
try:
|
||||
from PyQt5.QtWebEngineWidgets import QWebEngineView
|
||||
@ -3052,7 +3062,13 @@ class MainWindow(QMainWindow):
|
||||
try:
|
||||
selected_item = self.treeWidget.currentItem()
|
||||
if not selected_item:
|
||||
QMessageBox.information(self, "提示", "请先选择要复制的节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"请先选择要复制的节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 获取选中的节点
|
||||
@ -3064,35 +3080,71 @@ class MainWindow(QMainWindow):
|
||||
selected_node = getattr(self.world.selection, 'selectedNode', None)
|
||||
|
||||
if not selected_node or selected_node.isEmpty():
|
||||
QMessageBox.warning(self, "错误", "无法获取选中节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
"无法获取选中节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 检查是否是根节点
|
||||
if selected_node.getName() == "render":
|
||||
QMessageBox.warning(self, "错误", "不能复制根节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
"不能复制根节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 序列化节点数据
|
||||
node_data = self.world.scene_manager.serializeNodeForCopy(selected_node)
|
||||
if not node_data:
|
||||
QMessageBox.warning(self, "错误", "无法序列化选中节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
"无法序列化选中节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 存储到剪切板
|
||||
self.clipboard = [node_data]
|
||||
self.clipboard_mode = "copy"
|
||||
|
||||
QMessageBox.information(self, "成功", "节点已复制到剪切板")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
"节点已复制到剪切板",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"复制操作失败: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"复制操作失败: {str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onCut(self):
|
||||
"""剪切操作"""
|
||||
try:
|
||||
selected_item = self.treeWidget.currentItem()
|
||||
if not selected_item:
|
||||
QMessageBox.information(self, "提示", "请先选择要剪切的节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"请先选择要剪切的节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 获取选中的节点
|
||||
@ -3104,18 +3156,36 @@ class MainWindow(QMainWindow):
|
||||
selected_node = getattr(self.world.selection, 'selectedNode', None)
|
||||
|
||||
if not selected_node or selected_node.isEmpty():
|
||||
QMessageBox.warning(self, "错误", "无法获取选中节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
"无法获取选中节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 检查是否是根节点或特殊节点
|
||||
if selected_node.getName() in ["render", "camera", "ambientLight", "directionalLight"]:
|
||||
QMessageBox.warning(self, "错误", "不能剪切根节点或系统节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
"不能剪切根节点或系统节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 序列化节点数据
|
||||
node_data = self.world.scene_manager.serializeNodeForCopy(selected_node)
|
||||
if not node_data:
|
||||
QMessageBox.warning(self, "错误", "无法序列化选中节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
"无法序列化选中节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 存储到剪切板
|
||||
@ -3125,16 +3195,34 @@ class MainWindow(QMainWindow):
|
||||
# 删除原节点
|
||||
self.treeWidget.delete_items([selected_item])
|
||||
|
||||
QMessageBox.information(self, "成功", "节点已剪切到剪切板")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
"节点已剪切到剪切板",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"剪切操作失败: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"剪切操作失败: {str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onPaste(self):
|
||||
"""粘贴操作"""
|
||||
try:
|
||||
if not self.clipboard:
|
||||
QMessageBox.information(self, "提示", "剪切板为空")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"剪切板为空",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 获取粘贴目标节点
|
||||
@ -3175,13 +3263,25 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# 检查父节点有效性
|
||||
if not parent_node or parent_node.isEmpty():
|
||||
QMessageBox.warning(self, "错误", "无法获取有效的父节点")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
"无法获取有效的父节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 检查目标节点是否为允许的父节点类型
|
||||
parent_name = parent_node.getName()
|
||||
if parent_name in ["camera", "ambientLight", "directionalLight"]:
|
||||
QMessageBox.warning(self, "错误", "不能粘贴到该类型节点下")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
"不能粘贴到该类型节点下",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 粘贴节点
|
||||
@ -3200,10 +3300,22 @@ class MainWindow(QMainWindow):
|
||||
self.clipboard.clear()
|
||||
self.clipboard_mode = None
|
||||
|
||||
QMessageBox.information(self, "成功", f"已粘贴 {len(pasted_nodes)} 个节点")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
f"已粘贴 {len(pasted_nodes)} 个节点",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"粘贴操作失败: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"粘贴操作失败: {str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def _serializeNode(self, node):
|
||||
"""序列化节点数据"""
|
||||
@ -3330,13 +3442,31 @@ class MainWindow(QMainWindow):
|
||||
print("成功操作")
|
||||
else:
|
||||
print("撤销失败")
|
||||
QMessageBox.information(self,"提示","撤销操作失败")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"撤销操作失败",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
print("没有可撤销的操作")
|
||||
QMessageBox.information(self,"提示","没有可撤销的操作")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"没有可撤销的操作",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
print("命令管理器未初始化")
|
||||
QMessageBox.information(self,"提示","命令系统未初始化")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"命令系统未初始化",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onRedo(self):
|
||||
"""重做操作"""
|
||||
@ -3347,13 +3477,31 @@ class MainWindow(QMainWindow):
|
||||
print("成功重做")
|
||||
else:
|
||||
print("重做失败")
|
||||
QMessageBox.information(self,"提示","重做操作失败")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"重做操作失败",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
print("没有可重做的操作")
|
||||
QMessageBox.information(self,"提示","没有可重做的操作")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"没有可重做的操作",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
print("命令管理器未初始化")
|
||||
QMessageBox.information(self,"提示","命令系统未初始化")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"命令系统未初始化",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onCreateCesiumView(self):
|
||||
if hasattr(self.world,'gui_manager') and self.world.gui_manager:
|
||||
@ -3404,15 +3552,16 @@ class MainWindow(QMainWindow):
|
||||
break
|
||||
|
||||
if not cesium_view_exists:
|
||||
reply = QMessageBox.question(
|
||||
result = UniversalMessageDialog.show_info(
|
||||
self,
|
||||
'提示',
|
||||
'Cesium 地图视图尚未打开,是否先打开地图视图?',
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.Yes
|
||||
"提示",
|
||||
"Cesium 地图视图尚未打开,是否先打开地图视图?",
|
||||
show_cancel=True,
|
||||
confirm_text="打开视图",
|
||||
cancel_text="取消"
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
if result == QDialog.Accepted:
|
||||
self.onCreateCesiumView()
|
||||
# 给一点时间让 Cesium 视图加载
|
||||
QTimer.singleShot(1000, self.showAddModelDialog)
|
||||
@ -3457,22 +3606,28 @@ class MainWindow(QMainWindow):
|
||||
)
|
||||
|
||||
if success:
|
||||
QMessageBox.information(
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
f"模型已成功添加到地图!\n模型ID: {model_id}"
|
||||
f"模型已成功添加到地图!\n模型ID: {model_id}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
QMessageBox.warning(
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"失败",
|
||||
"添加模型失败,请检查控制台输出"
|
||||
"添加模型失败,请检查控制台输出",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"添加模型时发生错误:\n{str(e)}"
|
||||
f"添加模型时发生错误:\n{str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
|
||||
@ -3547,43 +3702,103 @@ class MainWindow(QMainWindow):
|
||||
return None, False
|
||||
|
||||
def onLoadCesiumTileset(self):
|
||||
dialog = self.createStyledInputDialog(
|
||||
self,
|
||||
"加载 Cesium 3D Tiles",
|
||||
"输入 tileset.json URL:",
|
||||
QLineEdit.Normal,
|
||||
"https://assets.ion.cesium.com/96128/tileset.json"
|
||||
)
|
||||
"""加载 Cesium 3D Tiles"""
|
||||
fields = [
|
||||
{
|
||||
"name": "url",
|
||||
"label": "Tileset URL",
|
||||
"type": "text",
|
||||
"value": "https://assets.ion.cesium.com/96128/tileset.json",
|
||||
"placeholder": "输入 tileset.json 地址",
|
||||
"label_width": 110
|
||||
},
|
||||
{
|
||||
"name": "longitude",
|
||||
"label": "经度(°)",
|
||||
"type": "double",
|
||||
"min": -180.0,
|
||||
"max": 180.0,
|
||||
"step": 0.1,
|
||||
"decimals": 6,
|
||||
"value": 0.0,
|
||||
"label_width": 110
|
||||
},
|
||||
{
|
||||
"name": "latitude",
|
||||
"label": "纬度(°)",
|
||||
"type": "double",
|
||||
"min": -90.0,
|
||||
"max": 90.0,
|
||||
"step": 0.1,
|
||||
"decimals": 6,
|
||||
"value": 0.0,
|
||||
"label_width": 110
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"label": "高度(米)",
|
||||
"type": "double",
|
||||
"min": -10000.0,
|
||||
"max": 10000.0,
|
||||
"step": 1.0,
|
||||
"decimals": 2,
|
||||
"value": 0.0,
|
||||
"label_width": 110
|
||||
}
|
||||
]
|
||||
|
||||
dialog = StyledTerrainDialog(self, "加载 Cesium 3D Tiles", fields, primary_text="加载", secondary_text="取消")
|
||||
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
url = dialog.textValue()
|
||||
if url:
|
||||
try:
|
||||
# 生成唯一的 tileset 名称
|
||||
import uuid
|
||||
tileset_name = f"tileset_{uuid.uuid4().hex[:8]}"
|
||||
url = dialog.get_value("url")
|
||||
if not url or not url.strip():
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"提示",
|
||||
"请输入有效的 tileset URL",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 加载 tileset
|
||||
if hasattr(self.world, 'addCesiumTileset'):
|
||||
success = self.world.addCesiumTileset(tileset_name, url, (0, 0, 0))
|
||||
if success:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"成功",
|
||||
f"Cesium 3D Tiles 已加载到场景中!\n名称: {tileset_name}"
|
||||
)
|
||||
else:
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"失败",
|
||||
"加载 Cesium 3D Tiles 失败"
|
||||
)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
"错误",
|
||||
f"加载 Cesium 3D Tiles 时发生错误:\n{str(e)}"
|
||||
longitude = dialog.get_value("longitude")
|
||||
latitude = dialog.get_value("latitude")
|
||||
height = dialog.get_value("height")
|
||||
|
||||
try:
|
||||
import uuid
|
||||
tileset_name = f"tileset_{uuid.uuid4().hex[:8]}"
|
||||
|
||||
if hasattr(self.world, 'addCesiumTileset'):
|
||||
success = self.world.addCesiumTileset(
|
||||
tileset_name,
|
||||
url.strip(),
|
||||
(longitude, latitude, height)
|
||||
)
|
||||
if success:
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
f"Cesium 3D Tiles 已加载到场景中!\n名称: {tileset_name}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"失败",
|
||||
"加载 Cesium 3D Tiles 失败",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
except Exception as e:
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"加载 Cesium 3D Tiles 时发生错误:\n{str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onToolChanged(self, button):
|
||||
"""工具切换事件处理"""
|
||||
@ -4310,7 +4525,9 @@ class MainWindow(QMainWindow):
|
||||
"""创建脚本按钮事件"""
|
||||
script_name = self.scriptNameEdit.text().strip()
|
||||
if not script_name:
|
||||
QMessageBox.warning(self, "错误", "请输入脚本名称!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self, "警告", "请输入脚本名称!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
template = self.templateCombo.currentText()
|
||||
@ -4318,17 +4535,35 @@ class MainWindow(QMainWindow):
|
||||
try:
|
||||
success = self.world.createScript(script_name, template)
|
||||
if success:
|
||||
QMessageBox.information(self, "成功", f"脚本 '{script_name}' 创建成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
f"脚本 '{script_name}' 创建成功!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
self.scriptNameEdit.clear()
|
||||
self.refreshScriptsList()
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", f"脚本 '{script_name}' 创建失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"警告",
|
||||
f"脚本 '{script_name}' 创建失败!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"创建脚本时出错: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"创建脚本时发生错误: {str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onCreateScriptDialog(self):
|
||||
"""菜单创建脚本事件"""
|
||||
dialog = self.createStyledInputDialog(self, "创建脚本", "输入脚本名称:")
|
||||
dialog = self.createStyledInputDialog(self, "创建脚本", "请输入脚本名称:")
|
||||
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
script_name = dialog.textValue()
|
||||
@ -4336,30 +4571,55 @@ class MainWindow(QMainWindow):
|
||||
try:
|
||||
success = self.world.createScript(script_name.strip(), "basic")
|
||||
if success:
|
||||
QMessageBox.information(self, "成功", f"脚本 '{script_name}' 创建成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
f"脚本 '{script_name}' 创建成功!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
self.refreshScriptsList()
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", f"脚本 '{script_name}' 创建失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"警告",
|
||||
f"脚本 '{script_name}' 创建失败!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"创建脚本时出错: {str(e)}")
|
||||
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"创建脚本时发生错误: {str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onLoadScript(self):
|
||||
"""加载脚本按钮事件"""
|
||||
current_item = self.scriptsList.currentItem()
|
||||
if not current_item:
|
||||
QMessageBox.warning(self, "错误", "请选择要加载的脚本!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self, "警告", "请选择要加载的脚本!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
script_name = current_item.text()
|
||||
try:
|
||||
success = self.world.reloadScript(script_name)
|
||||
if success:
|
||||
QMessageBox.information(self, "成功", f"脚本 '{script_name}' 重载成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self, "成功", f"脚本 '{script_name}' 加载成功!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", f"脚本 '{script_name}' 重载失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self, "警告", f"脚本 '{script_name}' 加载失败!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"重载脚本时出错: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self, "错误", f"加载脚本时发生错误: {str(e)}", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
|
||||
def onLoadScriptFile(self):
|
||||
"""加载脚本文件菜单事件"""
|
||||
@ -4376,29 +4636,52 @@ class MainWindow(QMainWindow):
|
||||
try:
|
||||
success = self.world.loadScript(file_path)
|
||||
if success:
|
||||
QMessageBox.information(self, "成功", "脚本文件加载成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self, "成功", "脚本文件加载成功!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
self.refreshScriptsList()
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", "脚本文件加载失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self, "警告", "脚本文件加载失败!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"加载脚本文件时出错: {str(e)}")
|
||||
|
||||
UniversalMessageDialog.show_error(
|
||||
self, "错误", f"加载脚本文件时发生错误: {str(e)}", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
|
||||
def onReloadAllScripts(self):
|
||||
"""重载所有脚本事件"""
|
||||
"""重新加载所有脚本事件"""
|
||||
try:
|
||||
scripts_loaded = self.world.loadAllScripts()
|
||||
QMessageBox.information(self, "成功", f"重载完成,共加载 {len(scripts_loaded)} 个脚本!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
f"更新完成,共加载 {len(scripts_loaded)} 个脚本!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
self.refreshScriptsList()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"重载脚本时出错: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"加载脚本时发生错误: {str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onToggleHotReload(self):
|
||||
"""切换热重载状态"""
|
||||
"""切换热更新状态"""
|
||||
enabled = self.toggleHotReloadAction.isChecked()
|
||||
self.world.enableHotReload(enabled)
|
||||
status = "启用" if enabled else "禁用"
|
||||
QMessageBox.information(self, "热重载", f"热重载已{status}")
|
||||
status = "已开启" if enabled else "已关闭"
|
||||
UniversalMessageDialog.show_info(
|
||||
self,
|
||||
"脚本热更",
|
||||
f"脚本热更{status}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onOpenScriptsManager(self):
|
||||
"""打开脚本管理器"""
|
||||
@ -4408,65 +4691,107 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def onScriptDoubleClick(self, item):
|
||||
"""脚本列表双击事件"""
|
||||
# 可以在这里添加打开外部编辑器的功能
|
||||
script_name = item.text()
|
||||
QMessageBox.information(self, "提示", f"双击了脚本: {script_name}\n\n可以使用外部编辑器编辑脚本文件。")
|
||||
UniversalMessageDialog.show_info(
|
||||
self,
|
||||
"提示",
|
||||
f"双击脚本: {script_name}\n\n请使用外部编辑器编辑脚本文件。",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onMountScript(self):
|
||||
"""挂载脚本事件"""
|
||||
selected_object = getattr(self.world.selection, 'selectedObject', None)
|
||||
if not selected_object:
|
||||
QMessageBox.warning(self, "错误", "请先选择一个对象!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self, "警告", "请选择一个对象!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
script_name = self.mountScriptCombo.currentText()
|
||||
if not script_name:
|
||||
QMessageBox.warning(self, "错误", "请选择要挂载的脚本!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self, "警告", "请选择要挂载的脚本!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
success = self.world.addScript(selected_object, script_name)
|
||||
if success:
|
||||
QMessageBox.information(self, "成功", f"脚本 '{script_name}' 已挂载到对象!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self, "成功", f"脚本 '{script_name}' 已挂载到对象!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
self.updateMountedScriptsList(selected_object)
|
||||
|
||||
# 同时更新属性面板
|
||||
if self.treeWidget and self.treeWidget.currentItem():
|
||||
self.world.updatePropertyPanel(self.treeWidget.currentItem())
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", f"挂载脚本失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self, "警告", "挂载脚本失败!", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"挂载脚本时出错: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self, "错误", f"挂载脚本时发生错误: {str(e)}", show_cancel=False, confirm_text="确认"
|
||||
)
|
||||
|
||||
def onUnmountScript(self):
|
||||
"""卸载脚本事件"""
|
||||
selected_object = getattr(self.world.selection, 'selectedObject', None)
|
||||
if not selected_object:
|
||||
QMessageBox.warning(self, "错误", "请先选择一个对象!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"警告",
|
||||
"请选择一个对象!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
current_item = self.mountedScriptsList.currentItem()
|
||||
if not current_item:
|
||||
QMessageBox.warning(self, "错误", "请选择要卸载的脚本!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"警告",
|
||||
"请选择要卸载的脚本!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
return
|
||||
|
||||
# 解析脚本名称(移除状态标记)
|
||||
item_text = current_item.text()
|
||||
script_name = item_text[2:] # 移除 "✓ " 或 "✗ " 前缀
|
||||
script_name = item_text[2:]
|
||||
|
||||
try:
|
||||
success = self.world.removeScript(selected_object, script_name)
|
||||
if success:
|
||||
QMessageBox.information(self, "成功", f"脚本 '{script_name}' 已从对象卸载!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
f"脚本 '{script_name}' 已从对象卸载!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
self.updateMountedScriptsList(selected_object)
|
||||
|
||||
# 同时更新属性面板
|
||||
if self.treeWidget and self.treeWidget.currentItem():
|
||||
self.world.updatePropertyPanel(self.treeWidget.currentItem())
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", f"卸载脚本失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"警告",
|
||||
"卸载脚本失败!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"卸载脚本时出错: {str(e)}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"卸载脚本时发生错误: {str(e)}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onOpenIconManager(self):
|
||||
"""打开图标管理器"""
|
||||
@ -4560,9 +4885,21 @@ class MainWindow(QMainWindow):
|
||||
|
||||
terrain_info = self.world.createFlatTerrain((width, height), resolution)
|
||||
if terrain_info:
|
||||
QMessageBox.information(self, "成功", "平面地形创建成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
"平面地形创建成功!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "平面地形创建失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"警告",
|
||||
"平面地形创建失败!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onCreateHeightmapTerrain(self):
|
||||
"""从高度图创建地形"""
|
||||
@ -4624,9 +4961,21 @@ class MainWindow(QMainWindow):
|
||||
(x_scale, y_scale, z_scale)
|
||||
)
|
||||
if terrain_info:
|
||||
QMessageBox.information(self, "成功", "高度图地形创建成功!")
|
||||
UniversalMessageDialog.show_success(
|
||||
self,
|
||||
"成功",
|
||||
"高度图地形创建成功!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "高度图地形创建失败!")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"警告",
|
||||
"高度图地形创建失败!",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def onOpenAssemblyDisassemblyConfig(self):
|
||||
"""打开拆装配置界面"""
|
||||
|
||||
@ -241,6 +241,41 @@ class PropertyPanelManager:
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
"""
|
||||
|
||||
# 固定宽度的徽章样式(用于碰撞检测状态)
|
||||
self.badge_style_green_fixed = """
|
||||
QLabel {
|
||||
background-color: rgba(45, 255, 196, 0.15);
|
||||
border: 1px solid rgba(45, 255, 196, 0.6);
|
||||
color: #2dffc4;
|
||||
border-radius: 6px;
|
||||
padding: 4px 10px;
|
||||
font-family: 'Microsoft YaHei', 'Inter', sans-serif;
|
||||
font-size: 9px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.5px;
|
||||
min-width: 50px;
|
||||
max-width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
"""
|
||||
|
||||
self.badge_style_red_fixed = """
|
||||
QLabel {
|
||||
background-color: rgba(255, 99, 99, 0.15);
|
||||
border: 1px solid rgba(255, 99, 99, 0.6);
|
||||
color: #ff6363;
|
||||
border-radius: 6px;
|
||||
padding: 4px 10px;
|
||||
font-family: 'Microsoft YaHei', 'Inter', sans-serif;
|
||||
font-size: 9px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.5px;
|
||||
min-width: 50px;
|
||||
max-width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
"""
|
||||
|
||||
def createStatusBadge(self, text, badge_type="green"):
|
||||
"""创建现代化状态徽章
|
||||
@ -265,6 +300,28 @@ class PropertyPanelManager:
|
||||
badge.setStyleSheet(self.badge_style_blue) # 默认蓝色
|
||||
return badge
|
||||
|
||||
def createFixedStatusBadge(self, text, badge_type="green"):
|
||||
"""创建固定宽度的状态徽章(用于碰撞检测等需要保持一致宽度的场景)
|
||||
|
||||
Args:
|
||||
text: 徽章文字
|
||||
badge_type: 徽章类型,支持 "green", "red"
|
||||
|
||||
Returns:
|
||||
QLabel: 配置好固定宽度样式的标签
|
||||
"""
|
||||
badge = QLabel(text)
|
||||
badge.setAlignment(Qt.AlignCenter) # 确保文字居中
|
||||
|
||||
if badge_type == "green":
|
||||
badge.setStyleSheet(self.badge_style_green_fixed)
|
||||
elif badge_type == "red":
|
||||
badge.setStyleSheet(self.badge_style_red_fixed)
|
||||
else:
|
||||
badge.setStyleSheet(self.badge_style_green_fixed) # 默认绿色
|
||||
|
||||
return badge
|
||||
|
||||
def createModernButton(self, text, button_type="default"):
|
||||
"""创建现代化按钮
|
||||
|
||||
@ -1012,7 +1069,7 @@ class PropertyPanelManager:
|
||||
|
||||
# 清理碰撞相关控件引用
|
||||
collision_controls = [
|
||||
'collision_status_text', 'collision_shape_combo', 'collision_shape_label',
|
||||
'collision_status_badge', 'collision_shape_combo', 'collision_shape_label',
|
||||
'collision_visibility_button', 'collision_button', 'collision_layout', 'collision_group',
|
||||
'collision_pos_x', 'collision_pos_y', 'collision_pos_z',
|
||||
'collision_radius', 'collision_width', 'collision_length', 'collision_height',
|
||||
@ -9300,14 +9357,28 @@ except Exception as e:
|
||||
# 检查模型是否已有碰撞
|
||||
has_collision = self._hasCollision(model)
|
||||
|
||||
# 碰撞状态标签
|
||||
# 创建主容器
|
||||
main_container = QWidget()
|
||||
main_layout = QVBoxLayout(main_container)
|
||||
main_layout.setContentsMargins(8, 8, 8, 8)
|
||||
main_layout.setSpacing(12)
|
||||
|
||||
# 状态和形状选择区域
|
||||
header_container = QWidget()
|
||||
header_layout = QGridLayout(header_container)
|
||||
header_layout.setContentsMargins(0, 0, 0, 0)
|
||||
header_layout.setSpacing(8)
|
||||
|
||||
# 碰撞状态行
|
||||
status_label = QLabel("状态:")
|
||||
collision_layout.addWidget(status_label, 0, 0)
|
||||
|
||||
# 状态文本(需要保存引用以便更新)
|
||||
self.collision_status_text = QLabel("已启用" if has_collision else "未启用")
|
||||
self.collision_status_text.setStyleSheet("color: green;" if has_collision else "color: red;")
|
||||
collision_layout.addWidget(self.collision_status_text, 0, 1)
|
||||
# 状态徽章(使用固定宽度样式)
|
||||
if has_collision:
|
||||
self.collision_status_badge = self.createFixedStatusBadge("已启用", "green")
|
||||
else:
|
||||
self.collision_status_badge = self.createFixedStatusBadge("未启用", "red")
|
||||
collision_layout.addWidget(self.collision_status_badge, 0, 1)
|
||||
|
||||
# 形状选择标签(始终显示)
|
||||
self.collision_shape_label = QLabel("碰撞形状:")
|
||||
@ -9343,14 +9414,15 @@ except Exception as e:
|
||||
# 添加碰撞参数调整控件
|
||||
current_row = self._addCollisionParameterControls(model, collision_layout, current_row, current_shape)
|
||||
|
||||
# 显示/隐藏切换按钮
|
||||
self.collision_visibility_button = QPushButton("隐藏碰撞" if is_collision_visible else "显示碰撞")
|
||||
# 显示/隐藏切换按钮(使用现代化样式)
|
||||
visibility_text = "隐藏碰撞" if is_collision_visible else "显示碰撞"
|
||||
self.collision_visibility_button = self.createModernButton(visibility_text, "primary")
|
||||
self.collision_visibility_button.clicked.connect(lambda: self._toggleCollisionVisibility(model))
|
||||
collision_layout.addWidget(self.collision_visibility_button, current_row, 0, 1, 2)
|
||||
current_row += 1
|
||||
|
||||
# 移除碰撞按钮
|
||||
self.collision_button = QPushButton("移除碰撞")
|
||||
# 移除碰撞按钮(使用现代化样式)
|
||||
self.collision_button = self.createModernButton("移除碰撞", "danger")
|
||||
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
|
||||
collision_layout.addWidget(self.collision_button, current_row, 0, 1, 2)
|
||||
else:
|
||||
@ -9365,8 +9437,8 @@ except Exception as e:
|
||||
if hasattr(self, 'collision_visibility_button'):
|
||||
self.collision_visibility_button.setVisible(False)
|
||||
|
||||
# 添加碰撞按钮
|
||||
self.collision_button = QPushButton("添加碰撞")
|
||||
# 添加碰撞按钮(使用现代化样式)
|
||||
self.collision_button = self.createModernButton("添加碰撞", "success")
|
||||
self.collision_button.clicked.connect(lambda: self._addCollisionAndUpdate(model))
|
||||
collision_layout.addWidget(self.collision_button, current_row, 0, 1, 2)
|
||||
collision_group.setLayout(collision_layout)
|
||||
@ -9677,7 +9749,32 @@ except Exception as e:
|
||||
try:
|
||||
if hasattr(self, 'collision_visibility_button'):
|
||||
is_visible = self._isCollisionVisible(model)
|
||||
self.collision_visibility_button.setText("隐藏碰撞" if is_visible else "显示碰撞")
|
||||
button_text = "隐藏碰撞" if is_visible else "显示碰撞"
|
||||
self.collision_visibility_button.setText(button_text)
|
||||
|
||||
# 应用主要按钮样式
|
||||
self.collision_visibility_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: rgba(77, 116, 189, 0.8);
|
||||
color: #ffffff;
|
||||
border: 1px solid #4d74bd;
|
||||
border-radius: 4px;
|
||||
padding: 8px 12px;
|
||||
font-family: 'Microsoft YaHei', 'Inter', sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
min-height: 16px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(77, 116, 189, 1.0);
|
||||
border: 1px solid rgba(77, 116, 189, 1.0);
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: rgba(61, 96, 169, 1.0);
|
||||
border: 1px solid rgba(61, 96, 169, 1.0);
|
||||
}
|
||||
""")
|
||||
|
||||
print(f"更新可见性按钮:{model.getName()} - {'可见' if is_visible else '隐藏'}")
|
||||
except Exception as e:
|
||||
print(f"更新碰撞可见性按钮失败: {e}")
|
||||
@ -9845,6 +9942,17 @@ except Exception as e:
|
||||
except Exception as e:
|
||||
print(f"移除碰撞失败: {e}")
|
||||
|
||||
def _findButtonRow(self, layout):
|
||||
"""查找按钮应该在的行数"""
|
||||
# 简单返回一个合适的行数,基于布局中现有的项目数
|
||||
row_count = 0
|
||||
for i in range(layout.count()):
|
||||
item = layout.itemAt(i)
|
||||
if item and item.widget():
|
||||
row, col, rowspan, colspan = layout.getItemPosition(i)
|
||||
row_count = max(row_count, row + 1)
|
||||
return row_count
|
||||
|
||||
def _updateCollisionPanelState(self, model):
|
||||
"""更新碰撞面板状态"""
|
||||
try:
|
||||
@ -9854,24 +9962,65 @@ except Exception as e:
|
||||
|
||||
self._updating_collision_panel = True
|
||||
|
||||
if hasattr(self, 'collision_button') and hasattr(self, 'collision_status_text') and hasattr(self,
|
||||
if hasattr(self, 'collision_button') and hasattr(self, 'collision_status_badge') and hasattr(self,
|
||||
'collision_shape_combo'):
|
||||
has_collision = self._hasCollision(model)
|
||||
|
||||
# 更新状态文本和颜色
|
||||
self.collision_status_text.setText("已启用" if has_collision else "未启用")
|
||||
self.collision_status_text.setStyleSheet("color: green;" if has_collision else "color: red;")
|
||||
# 更新状态徽章(使用固定宽度)
|
||||
if has_collision:
|
||||
new_badge = self.createFixedStatusBadge("已启用", "green")
|
||||
else:
|
||||
new_badge = self.createFixedStatusBadge("未启用", "red")
|
||||
|
||||
# 替换旧的徽章
|
||||
old_badge = self.collision_status_badge
|
||||
parent_layout = old_badge.parent().layout()
|
||||
if parent_layout:
|
||||
# 找到旧徽章在布局中的位置
|
||||
for i in range(parent_layout.count()):
|
||||
item = parent_layout.itemAt(i)
|
||||
if item and item.widget() == old_badge:
|
||||
# 移除旧徽章并添加新徽章
|
||||
parent_layout.removeWidget(old_badge)
|
||||
old_badge.deleteLater()
|
||||
parent_layout.addWidget(new_badge, 0, 1) # 状态徽章在第0行第1列
|
||||
self.collision_status_badge = new_badge
|
||||
break
|
||||
|
||||
if has_collision:
|
||||
# 有碰撞:显示移除按钮,下拉框变为只读并显示当前类型
|
||||
self.collision_button.setText("移除碰撞")
|
||||
|
||||
# 先断开所有连接,再重新连接
|
||||
try:
|
||||
self.collision_button.clicked.disconnect()
|
||||
except:
|
||||
pass
|
||||
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
|
||||
if hasattr(self, 'collision_button'):
|
||||
# 更新按钮文本和样式(简单方法:直接设置文本和样式)
|
||||
self.collision_button.setText("移除碰撞")
|
||||
# 应用危险按钮样式
|
||||
self.collision_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: rgba(255, 99, 99, 0.15);
|
||||
color: #ff6363;
|
||||
border: 1px solid rgba(255, 99, 99, 0.6);
|
||||
border-radius: 4px;
|
||||
padding: 8px 12px;
|
||||
font-family: 'Microsoft YaHei', 'Inter', sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: 400;
|
||||
min-height: 16px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(255, 99, 99, 0.25);
|
||||
border: 1px solid #ff6363;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: rgba(255, 99, 99, 0.4);
|
||||
color: #ffffff;
|
||||
}
|
||||
""")
|
||||
|
||||
# 重新连接信号
|
||||
try:
|
||||
self.collision_button.clicked.disconnect()
|
||||
except:
|
||||
pass
|
||||
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
|
||||
|
||||
# 获取并显示当前碰撞类型,设置为只读
|
||||
current_shape = self._getCurrentCollisionShape(model)
|
||||
@ -9895,14 +10044,37 @@ except Exception as e:
|
||||
|
||||
else:
|
||||
# 无碰撞:显示添加按钮,下拉框变为可编辑
|
||||
self.collision_button.setText("添加碰撞")
|
||||
if hasattr(self, 'collision_button'):
|
||||
self.collision_button.setText("添加碰撞")
|
||||
# 应用成功按钮样式
|
||||
self.collision_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: rgba(45, 255, 196, 0.15);
|
||||
color: #2dffc4;
|
||||
border: 1px solid rgba(45, 255, 196, 0.6);
|
||||
border-radius: 4px;
|
||||
padding: 8px 12px;
|
||||
font-family: 'Microsoft YaHei', 'Inter', sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: 400;
|
||||
min-height: 16px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(45, 255, 196, 0.25);
|
||||
border: 1px solid #2dffc4;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: rgba(45, 255, 196, 0.4);
|
||||
color: #ffffff;
|
||||
}
|
||||
""")
|
||||
|
||||
# 先断开所有连接,再重新连接
|
||||
try:
|
||||
self.collision_button.clicked.disconnect()
|
||||
except:
|
||||
pass
|
||||
self.collision_button.clicked.connect(lambda: self._addCollisionAndUpdate(model))
|
||||
# 先断开所有连接,再重新连接
|
||||
try:
|
||||
self.collision_button.clicked.disconnect()
|
||||
except:
|
||||
pass
|
||||
self.collision_button.clicked.connect(lambda: self._addCollisionAndUpdate(model))
|
||||
|
||||
# 恢复为可编辑状态
|
||||
self.collision_shape_combo.setEnabled(True)
|
||||
|
||||
462
ui/widgets.py
462
ui/widgets.py
@ -43,7 +43,7 @@ class NewProjectDialog(QDialog):
|
||||
self.dragging = False
|
||||
self.drag_position = QPoint()
|
||||
self.icon_manager = get_icon_manager()
|
||||
self._title_icon_size = QSize(14, 14)
|
||||
self._title_icon_size = QSize(18, 18)
|
||||
self._icon_close = self.icon_manager.get_icon('close_icon', self._title_icon_size)
|
||||
|
||||
# 设置严格按照Figma设计的样式
|
||||
@ -81,10 +81,12 @@ class NewProjectDialog(QDialog):
|
||||
border: none;
|
||||
color: #EBEBEB;
|
||||
font-size: 14px;
|
||||
min-width: 32px;
|
||||
max-width: 32px;
|
||||
min-height: 32px;
|
||||
max-height: 32px;
|
||||
min-width: 18px;
|
||||
max-width: 18px;
|
||||
min-height: 18px;
|
||||
max-height: 18px;
|
||||
padding: 0px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
QWidget#controlButtons QPushButton:hover {
|
||||
background-color: #2A2D2E;
|
||||
@ -94,7 +96,7 @@ class NewProjectDialog(QDialog):
|
||||
border-radius: 0px 5px 0px 0px;
|
||||
}
|
||||
QPushButton#closeButton:hover {
|
||||
background-color: #E74C3C;
|
||||
background-color: #2A2D2E;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QWidget#contentWidget {
|
||||
@ -431,25 +433,25 @@ class NewProjectDialog(QDialog):
|
||||
# 获取并验证路径
|
||||
self.projectPath = self.pathEdit.text()
|
||||
if not self.projectPath:
|
||||
StyledMessageBox.warning(self, "错误", "请选择项目路径!")
|
||||
UniversalMessageDialog.show_warning(self, "错误", "请选择项目路径!", show_cancel=False, confirm_text="确认")
|
||||
return
|
||||
|
||||
# 获取并验证项目名称
|
||||
self.projectName = self.nameEdit.text().strip()
|
||||
if not self.projectName:
|
||||
StyledMessageBox.warning(self, "错误", "请输入项目名称!")
|
||||
UniversalMessageDialog.show_warning(self, "错误", "请输入项目名称!", show_cancel=False, confirm_text="确认")
|
||||
return
|
||||
|
||||
# 验证项目名称格式
|
||||
if not re.match(r'^[a-zA-Z0-9_\-\u4e00-\u9fa5]+$', self.projectName):
|
||||
StyledMessageBox.warning(self, "错误",
|
||||
"项目名称只能包含字母、数字、下划线、中划线和中文!")
|
||||
UniversalMessageDialog.show_warning(self, "错误",
|
||||
"项目名称只能包含字母、数字、下划线、中划线和中文!", show_cancel=False, confirm_text="确认")
|
||||
return
|
||||
|
||||
# 检查项目是否已存在
|
||||
full_path = os.path.join(self.projectPath, self.projectName)
|
||||
if os.path.exists(full_path):
|
||||
StyledMessageBox.warning(self, "错误", "项目已存在!")
|
||||
UniversalMessageDialog.show_warning(self, "错误", "项目已存在!", show_cancel=False, confirm_text="确认")
|
||||
return
|
||||
|
||||
self.accept()
|
||||
@ -849,21 +851,21 @@ class CustomAssetsTreeWidget(QTreeWidget):
|
||||
"""删除文件或文件夹"""
|
||||
import os
|
||||
import shutil
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
filepath = item.data(0, Qt.UserRole)
|
||||
is_folder = item.data(0, Qt.UserRole + 1)
|
||||
|
||||
item_type = "文件夹" if is_folder else "文件"
|
||||
reply = StyledMessageBox.question(
|
||||
self,
|
||||
"确认删除",
|
||||
result = UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"确认删除",
|
||||
f"确定要删除这个{item_type}吗?\n{filepath}",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.No
|
||||
show_cancel=True,
|
||||
confirm_text="删除",
|
||||
cancel_text="取消"
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
if result == QDialog.Accepted:
|
||||
try:
|
||||
if is_folder:
|
||||
shutil.rmtree(filepath)
|
||||
@ -873,6 +875,13 @@ class CustomAssetsTreeWidget(QTreeWidget):
|
||||
print(f"删除{item_type}: {filepath}")
|
||||
except OSError as e:
|
||||
print(f"删除{item_type}失败: {e}")
|
||||
UniversalMessageDialog.show_error(
|
||||
self,
|
||||
"错误",
|
||||
f"删除{item_type}失败: {e}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
def copyPath(self, filepath):
|
||||
"""复制路径到剪贴板"""
|
||||
@ -903,7 +912,6 @@ class CustomAssetsTreeWidget(QTreeWidget):
|
||||
def showProperties(self, item):
|
||||
"""显示属性面板"""
|
||||
import os
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
filepath = item.data(0, Qt.UserRole)
|
||||
is_folder = item.data(0, Qt.UserRole + 1)
|
||||
@ -926,10 +934,23 @@ class CustomAssetsTreeWidget(QTreeWidget):
|
||||
修改时间: {modified_str}
|
||||
"""
|
||||
|
||||
StyledMessageBox.information(self, "属性", properties.strip())
|
||||
UniversalMessageDialog.show_info(
|
||||
self,
|
||||
"属性",
|
||||
properties.strip(),
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
except OSError as e:
|
||||
StyledMessageBox.warning(self, "错误", f"无法获取属性: {e}")
|
||||
UniversalMessageDialog.show_warning(
|
||||
self,
|
||||
"错误",
|
||||
f"无法获取属性: {e}",
|
||||
show_cancel=False,
|
||||
confirm_text="确认"
|
||||
)
|
||||
|
||||
|
||||
# def mouseDoubleClickEvent(self, event):
|
||||
# """处理双击事件"""
|
||||
@ -2105,6 +2126,392 @@ class StyledMessageBox:
|
||||
ok = dialog.exec_()
|
||||
return dialog.textValue(), ok
|
||||
|
||||
class UniversalMessageDialog(QDialog):
|
||||
"""通用消息对话框类 - 支持不同图标和按钮配置"""
|
||||
|
||||
# 消息类型枚举
|
||||
SUCCESS = "success_icon"
|
||||
WARNING = "warning_icon"
|
||||
ERROR = "fail_icon"
|
||||
INFO = "info"
|
||||
|
||||
def __init__(self, parent, title, message, message_type=INFO, show_cancel=True,
|
||||
confirm_text="确认", cancel_text="取消", icon_size=QSize(48, 48)):
|
||||
"""
|
||||
初始化通用消息对话框
|
||||
|
||||
Args:
|
||||
parent: 父窗口
|
||||
title: 对话框标题
|
||||
message: 消息内容
|
||||
message_type: 消息类型 (SUCCESS, WARNING, ERROR, INFO)
|
||||
show_cancel: 是否显示取消按钮
|
||||
confirm_text: 确认按钮文字
|
||||
cancel_text: 取消按钮文字
|
||||
icon_size: 图标尺寸
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle(title)
|
||||
self.setObjectName("universalMessageDialog")
|
||||
self.setModal(True)
|
||||
self.resize(508, 134)
|
||||
self.setMinimumSize(508, 134)
|
||||
self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint)
|
||||
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
||||
|
||||
# 对话框配置
|
||||
self.message_type = message_type
|
||||
self.show_cancel = show_cancel
|
||||
self.confirm_text = confirm_text
|
||||
self.cancel_text = cancel_text
|
||||
self.icon_size = icon_size
|
||||
|
||||
# 拖拽相关
|
||||
self.dragging = False
|
||||
self.drag_position = QPoint()
|
||||
|
||||
# 图标管理
|
||||
self.icon_manager = get_icon_manager()
|
||||
self._title_icon_size = QSize(18, 18)
|
||||
self._icon_close = self.icon_manager.get_icon('close_icon', self._title_icon_size)
|
||||
|
||||
# 根据消息类型获取对应图标
|
||||
self._message_icon = self._get_message_icon()
|
||||
|
||||
# 设置样式
|
||||
self._setup_styles()
|
||||
|
||||
# 创建UI
|
||||
self._create_ui(message)
|
||||
|
||||
def _get_message_icon(self):
|
||||
"""根据消息类型获取对应图标"""
|
||||
icon_map = {
|
||||
self.SUCCESS: 'success_icon',
|
||||
self.WARNING: 'warning_icon',
|
||||
self.ERROR: 'fail_icon',
|
||||
self.INFO: 'success_icon' # 默认使用成功图标
|
||||
}
|
||||
|
||||
icon_name = icon_map.get(self.message_type, 'success_icon')
|
||||
return self.icon_manager.get_icon(icon_name, self.icon_size)
|
||||
|
||||
def _setup_styles(self):
|
||||
"""设置对话框样式"""
|
||||
self.setStyleSheet("""
|
||||
QDialog#universalMessageDialog {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
QFrame#baseFrame {
|
||||
background-color: #19191B;
|
||||
border: 1px solid #3E3E42;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QWidget#titleBar {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 5px 5px 0px 0px;
|
||||
min-height: 32px;
|
||||
max-height: 32px;
|
||||
}
|
||||
QWidget#titleBar QWidget {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
QLabel#titleLabel {
|
||||
color: #FFFFFF;
|
||||
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.7px;
|
||||
}
|
||||
QWidget#controlButtons QPushButton {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: #EBEBEB;
|
||||
font-size: 14px;
|
||||
min-width: 18px;
|
||||
max-width: 18px;
|
||||
min-height: 18px;
|
||||
max-height: 18px;
|
||||
padding: 0px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
QWidget#controlButtons QPushButton:hover {
|
||||
background-color: #2A2D2E;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QPushButton#closeButton {
|
||||
border-radius: 0px 5px 0px 0px;
|
||||
}
|
||||
QPushButton#closeButton:hover {
|
||||
background-color: #2A2D2E;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QFrame#titleSeparator {
|
||||
background-color: #3E3E42;
|
||||
border: none;
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
}
|
||||
QWidget#contentWidget {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
QLabel#messageLabel {
|
||||
color: #EBEBEB;
|
||||
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.6px;
|
||||
line-height: 1.4;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
QPushButton {
|
||||
background-color: rgba(89, 98, 118, 0.5);
|
||||
color: #EBEBEB;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
padding: 0px 12px;
|
||||
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
|
||||
font-weight: 300;
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.5px;
|
||||
min-width: 90px;
|
||||
max-width: 90px;
|
||||
min-height: 28px;
|
||||
max-height: 28px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #3067C0;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #2556A0;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QPushButton#primaryButton {
|
||||
background-color: rgba(89, 98, 118, 0.5);
|
||||
border: none;
|
||||
color: #EBEBEB;
|
||||
font-weight: 300;
|
||||
}
|
||||
QPushButton#primaryButton:hover {
|
||||
background-color: #2556A0;
|
||||
}
|
||||
QPushButton#primaryButton:pressed {
|
||||
background-color: #1E4A8C;
|
||||
}
|
||||
QPushButton#secondaryButton {
|
||||
background-color: rgba(89, 98, 118, 0.5);
|
||||
border: none;
|
||||
color: #EBEBEB;
|
||||
}
|
||||
QPushButton#secondaryButton:hover {
|
||||
background-color: #3067C0;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
QPushButton#secondaryButton:pressed {
|
||||
background-color: #2556A0;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
""")
|
||||
|
||||
def _create_ui(self, message):
|
||||
"""构建用户界面"""
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||||
main_layout.setSpacing(0)
|
||||
|
||||
base_frame = QFrame()
|
||||
base_frame.setObjectName('baseFrame')
|
||||
base_frame.setFrameShape(QFrame.NoFrame)
|
||||
base_frame.setAttribute(Qt.WA_StyledBackground, True)
|
||||
|
||||
base_layout = QVBoxLayout(base_frame)
|
||||
base_layout.setContentsMargins(25, 14, 25, 14)
|
||||
base_layout.setSpacing(0)
|
||||
|
||||
self._create_title_bar()
|
||||
base_layout.addWidget(self.title_bar)
|
||||
base_layout.addSpacing(4)
|
||||
|
||||
title_separator = QFrame()
|
||||
title_separator.setObjectName('titleSeparator')
|
||||
title_separator.setFrameShape(QFrame.HLine)
|
||||
title_separator.setFrameShadow(QFrame.Plain)
|
||||
base_layout.addWidget(title_separator)
|
||||
base_layout.addSpacing(10)
|
||||
|
||||
content_widget = QWidget()
|
||||
content_widget.setObjectName('contentWidget')
|
||||
content_layout = QVBoxLayout(content_widget)
|
||||
content_layout.setContentsMargins(0, 0, 0, 0)
|
||||
content_layout.setSpacing(10)
|
||||
|
||||
message_area = QHBoxLayout()
|
||||
message_area.setContentsMargins(0, 0, 0, 0)
|
||||
message_area.setSpacing(15)
|
||||
|
||||
icon_label = QLabel()
|
||||
if self._message_icon and not self._message_icon.isNull():
|
||||
icon_label.setPixmap(self._message_icon.pixmap(self.icon_size))
|
||||
icon_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
icon_label.setFixedSize(self.icon_size)
|
||||
message_area.addWidget(icon_label)
|
||||
|
||||
self.message_label = QLabel(message)
|
||||
self.message_label.setObjectName('messageLabel')
|
||||
self.message_label.setWordWrap(True)
|
||||
self.message_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
self.message_label.setMinimumHeight(self.icon_size.height())
|
||||
self.message_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
message_area.addWidget(self.message_label, 1)
|
||||
message_area.addStretch()
|
||||
|
||||
content_layout.addLayout(message_area)
|
||||
base_layout.addWidget(content_widget)
|
||||
base_layout.addSpacing(10)
|
||||
|
||||
button_widget = QWidget()
|
||||
button_layout = QHBoxLayout(button_widget)
|
||||
button_layout.setContentsMargins(0, 0, 0, 0)
|
||||
button_layout.setSpacing(10)
|
||||
button_layout.addStretch()
|
||||
|
||||
if self.show_cancel:
|
||||
self.cancel_button = QPushButton(self.cancel_text)
|
||||
self.cancel_button.setObjectName("secondaryButton")
|
||||
self.cancel_button.clicked.connect(self.reject)
|
||||
self.cancel_button.setFixedSize(90, 28)
|
||||
button_layout.addWidget(self.cancel_button)
|
||||
|
||||
self.confirm_button = QPushButton(self.confirm_text)
|
||||
self.confirm_button.setObjectName("primaryButton")
|
||||
self.confirm_button.clicked.connect(self.accept)
|
||||
self.confirm_button.setFixedSize(90, 28)
|
||||
button_layout.addWidget(self.confirm_button)
|
||||
|
||||
self.confirm_button.setDefault(True)
|
||||
self.confirm_button.setAutoDefault(True)
|
||||
if self.show_cancel:
|
||||
self.cancel_button.setAutoDefault(False)
|
||||
|
||||
base_layout.addWidget(button_widget)
|
||||
|
||||
main_layout.addWidget(base_frame)
|
||||
|
||||
def _create_title_bar(self):
|
||||
"""创建自定义标题栏"""
|
||||
self.title_bar = QFrame()
|
||||
self.title_bar.setObjectName("titleBar")
|
||||
|
||||
title_layout = QHBoxLayout(self.title_bar)
|
||||
title_layout.setContentsMargins(0, 0, 0, 0)
|
||||
title_layout.setSpacing(0)
|
||||
|
||||
self.title_label = QLabel(self.windowTitle())
|
||||
self.title_label.setObjectName("titleLabel")
|
||||
self.title_label.setAlignment(Qt.AlignVCenter | Qt.AlignLeft)
|
||||
title_layout.addWidget(self.title_label, 1)
|
||||
|
||||
title_layout.addStretch()
|
||||
|
||||
controls = QWidget()
|
||||
controls.setObjectName("controlButtons")
|
||||
controls_layout = QHBoxLayout(controls)
|
||||
controls_layout.setContentsMargins(0, 0, 0, 0)
|
||||
controls_layout.setSpacing(0)
|
||||
|
||||
self.close_button = QPushButton()
|
||||
self.close_button.setObjectName("closeButton")
|
||||
self.close_button.clicked.connect(self.reject)
|
||||
self.close_button.setFocusPolicy(Qt.NoFocus)
|
||||
controls_layout.addWidget(self.close_button)
|
||||
|
||||
self._apply_title_bar_icons()
|
||||
|
||||
title_layout.addWidget(controls)
|
||||
|
||||
|
||||
def _apply_title_bar_icons(self):
|
||||
"""应用标题栏图标"""
|
||||
if self._icon_close:
|
||||
self.close_button.setIcon(self._icon_close)
|
||||
self.close_button.setIconSize(self._title_icon_size)
|
||||
self.close_button.setText("")
|
||||
self.close_button.setToolTip("关闭")
|
||||
|
||||
def setWindowTitle(self, title):
|
||||
"""设置窗口标题"""
|
||||
super().setWindowTitle(title)
|
||||
if hasattr(self, "title_label"):
|
||||
self.title_label.setText(title)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""鼠标按下事件 - 用于拖拽窗口"""
|
||||
if event.button() == Qt.LeftButton and self.title_bar.geometry().contains(event.pos()):
|
||||
self.dragging = True
|
||||
self.drag_position = event.globalPos() - self.frameGeometry().topLeft()
|
||||
event.accept()
|
||||
super().mousePressEvent(event)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""鼠标移动事件 - 用于拖拽窗口"""
|
||||
if event.buttons() == Qt.LeftButton and self.dragging:
|
||||
self.move(event.globalPos() - self.drag_position)
|
||||
event.accept()
|
||||
super().mouseMoveEvent(event)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
"""鼠标释放事件 - 停止拖拽"""
|
||||
if event.button() == Qt.LeftButton:
|
||||
self.dragging = False
|
||||
super().mouseReleaseEvent(event)
|
||||
|
||||
@staticmethod
|
||||
def show_success(parent, title, message, show_cancel=False, confirm_text="确认"):
|
||||
"""显示成功消息对话框"""
|
||||
dialog = UniversalMessageDialog(
|
||||
parent, title, message,
|
||||
UniversalMessageDialog.SUCCESS,
|
||||
show_cancel, confirm_text
|
||||
)
|
||||
return dialog.exec_()
|
||||
|
||||
@staticmethod
|
||||
def show_warning(parent, title, message, show_cancel=True, confirm_text="确认", cancel_text="取消"):
|
||||
"""显示警告消息对话框"""
|
||||
dialog = UniversalMessageDialog(
|
||||
parent, title, message,
|
||||
UniversalMessageDialog.WARNING,
|
||||
show_cancel, confirm_text, cancel_text
|
||||
)
|
||||
return dialog.exec_()
|
||||
|
||||
@staticmethod
|
||||
def show_error(parent, title, message, show_cancel=False, confirm_text="确认"):
|
||||
"""显示错误消息对话框"""
|
||||
dialog = UniversalMessageDialog(
|
||||
parent, title, message,
|
||||
UniversalMessageDialog.ERROR,
|
||||
show_cancel, confirm_text
|
||||
)
|
||||
return dialog.exec_()
|
||||
|
||||
@staticmethod
|
||||
def show_info(parent, title, message, show_cancel=True, confirm_text="确认", cancel_text="取消"):
|
||||
"""显示信息消息对话框"""
|
||||
dialog = UniversalMessageDialog(
|
||||
parent, title, message,
|
||||
UniversalMessageDialog.INFO,
|
||||
show_cancel, confirm_text, cancel_text
|
||||
)
|
||||
return dialog.exec_()
|
||||
|
||||
|
||||
class StyledTextInputDialog(QDialog):
|
||||
"""与新建项目样式一致的文本输入对话框"""
|
||||
|
||||
@ -2937,12 +3344,17 @@ class CustomTreeWidget(QTreeWidget):
|
||||
else:
|
||||
message = f"确定要删除 {item_count} 个节点吗?"
|
||||
|
||||
reply = StyledMessageBox.question(
|
||||
self, "确认删除", message,
|
||||
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
|
||||
dialog = UniversalMessageDialog(
|
||||
self,
|
||||
"确认删除",
|
||||
message,
|
||||
message_type=UniversalMessageDialog.WARNING,
|
||||
show_cancel=True,
|
||||
confirm_text="确认",
|
||||
cancel_text="取消"
|
||||
)
|
||||
|
||||
if reply != QMessageBox.Yes:
|
||||
if dialog.exec_() != QDialog.Accepted:
|
||||
return
|
||||
|
||||
# 默认选中场景根节点,通常是第一个顶级节点
|
||||
|
||||
Loading…
Reference in New Issue
Block a user