forked from Rowland/EG
1.整合菜单栏(2D图片、3D图片、地形)
This commit is contained in:
parent
c39ebeb345
commit
95395bdb05
@ -13,6 +13,15 @@ class TerrainManager:
|
|||||||
self.terrains = []
|
self.terrains = []
|
||||||
|
|
||||||
# core/terrain_manager.py
|
# core/terrain_manager.py
|
||||||
|
def _get_tree_widget(self):
|
||||||
|
"""安全获取树形控件"""
|
||||||
|
try:
|
||||||
|
if (hasattr(self.world, 'interface_manager') and
|
||||||
|
hasattr(self.world.interface_manager, 'treeWidget')):
|
||||||
|
return self.world.interface_manager.treeWidget
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
def createTerrainFromHeightMap(self, heightmap_path, scale=(1, 1, 1)):
|
def createTerrainFromHeightMap(self, heightmap_path, scale=(1, 1, 1)):
|
||||||
"""从高度图创建地形"""
|
"""从高度图创建地形"""
|
||||||
|
|||||||
@ -272,211 +272,6 @@ class GUIManager:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def createGUIEntry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08):
|
def createGUIEntry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08):
|
||||||
"""创建2D GUI文本输入框"""
|
|
||||||
from direct.gui.DirectGui import DirectEntry
|
|
||||||
|
|
||||||
# 将3D坐标转换为2D屏幕坐标
|
|
||||||
gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1)
|
|
||||||
|
|
||||||
entry = DirectEntry(
|
|
||||||
text="",
|
|
||||||
pos=gui_pos,
|
|
||||||
scale=size,
|
|
||||||
command=self.onGUIEntrySubmit,
|
|
||||||
extraArgs=[f"entry_{len(self.gui_elements)}"],
|
|
||||||
initialText=placeholder,
|
|
||||||
numLines=1,
|
|
||||||
width=12,
|
|
||||||
focus=0
|
|
||||||
)
|
|
||||||
|
|
||||||
# 为GUI元素添加标识
|
|
||||||
entry.setTag("gui_type", "entry")
|
|
||||||
entry.setTag("gui_id", f"entry_{len(self.gui_elements)}")
|
|
||||||
entry.setTag("gui_placeholder", placeholder)
|
|
||||||
entry.setTag("is_gui_element", "1")
|
|
||||||
|
|
||||||
self.gui_elements.append(entry)
|
|
||||||
# 安全地调用updateSceneTree
|
|
||||||
if hasattr(self.world, 'updateSceneTree'):
|
|
||||||
self.world.updateSceneTree()
|
|
||||||
|
|
||||||
print(f"✓ 创建GUI输入框: {placeholder} (逻辑位置: {pos}, 屏幕位置: {gui_pos})")
|
|
||||||
return entry
|
|
||||||
def createGUI2DImage(self, pos=(0, 0, 0), image_path=None, size=0.2):
|
|
||||||
"""创建2D GUI图片"""
|
|
||||||
from direct.gui.DirectGui import DirectFrame
|
|
||||||
from panda3d.core import TransparencyAttrib,Texture,CardMaker,CardMaker,Vec3
|
|
||||||
|
|
||||||
# 将3D坐标转换为2D屏幕坐标
|
|
||||||
gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1)
|
|
||||||
|
|
||||||
#使用CardMaker创建一个更可靠的图片框架
|
|
||||||
cm = CardMaker('gui-2d-image')
|
|
||||||
cm.setFrame(-size,size,-size,size)
|
|
||||||
|
|
||||||
image_node = self.world.aspect2d.attachNewNode(cm.generate())
|
|
||||||
image_node.setPos(gui_pos)
|
|
||||||
image_node.setBin('fixed',0)
|
|
||||||
image_node.setDepthWrite(False)
|
|
||||||
image_node.setDepthTest(False)
|
|
||||||
image_node.setColor(1,1,1,1)
|
|
||||||
|
|
||||||
# 设置透明度支持
|
|
||||||
image_node.setTransparency(TransparencyAttrib.MAlpha)
|
|
||||||
|
|
||||||
# 如果提供了图像路径,则加载纹理
|
|
||||||
if image_path:
|
|
||||||
try:
|
|
||||||
texture = self.world.loader.loadTexture(image_path)
|
|
||||||
if texture:
|
|
||||||
image_node.setTexture(texture,1)
|
|
||||||
texture.setWrapU(Texture.WM_clamp)
|
|
||||||
texture.setWrapV(Texture.WM_clamp)
|
|
||||||
texture.setMinfilter(Texture.FT_linear)
|
|
||||||
texture.setMagfilter(Texture.FT_linear)
|
|
||||||
image_node.setColor(1,1,1,1)
|
|
||||||
else:
|
|
||||||
print(f"⚠️ 无法加载2D图片纹理: {image_path}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ 加载2D图片纹理失败: {e}")
|
|
||||||
|
|
||||||
# 为GUI元素添加标识
|
|
||||||
image_node.setTag("gui_type", "2d_image")
|
|
||||||
image_node.setTag("gui_id", f"2d_image_{len(self.gui_elements)}")
|
|
||||||
image_node.setTag("gui_text", f"2D图片_{len(self.gui_elements)}")
|
|
||||||
if image_path:
|
|
||||||
image_node.setTag("image_path", image_path)
|
|
||||||
image_node.setTag("is_gui_element", "1")
|
|
||||||
|
|
||||||
self.gui_elements.append(image_node)
|
|
||||||
|
|
||||||
# 安全地调用updateSceneTree
|
|
||||||
if hasattr(self.world, 'updateSceneTree'):
|
|
||||||
self.world.updateSceneTree()
|
|
||||||
|
|
||||||
print(f"✓ 创建2D GUI图片 (逻辑位置: {pos}, 屏幕位置: {gui_pos})")
|
|
||||||
return image_node
|
|
||||||
|
|
||||||
def constrain2DPosition(self,gui_element,new_x=None,new_z=None):
|
|
||||||
"""限制2dGUI元素位置在屏幕范围内"""
|
|
||||||
try:
|
|
||||||
from panda3d.core import Vec3
|
|
||||||
|
|
||||||
bounds = gui_element.getTightBounds()
|
|
||||||
element_width=0
|
|
||||||
element_height=0
|
|
||||||
|
|
||||||
if bounds:
|
|
||||||
min_point,max_point = bounds
|
|
||||||
element_width = (max_point.getX() - min_point.getX())/2
|
|
||||||
element_height = (max_point.getZ()-min_point.getZ())/2
|
|
||||||
|
|
||||||
#获取当前缩放
|
|
||||||
scale = gui_element.getScale()
|
|
||||||
if hasattr(scale,'getX'):
|
|
||||||
scale_x = scale.getX()
|
|
||||||
scale_z = scale.getZ() if hasattr(scale,'getZ') else scale_x
|
|
||||||
else:
|
|
||||||
scale_x = scale_z = scale if isinstance(scale,(int,float)) else 1.0
|
|
||||||
|
|
||||||
actual_width = element_width * scale_x
|
|
||||||
actual_height = element_height * scale_z
|
|
||||||
|
|
||||||
screen_width = 1.9
|
|
||||||
screen_height = 0.9
|
|
||||||
|
|
||||||
min_x = -screen_width + actual_width
|
|
||||||
max_x = screen_width - actual_width
|
|
||||||
min_z = -screen_height + actual_height
|
|
||||||
max_z = screen_height - actual_height
|
|
||||||
|
|
||||||
#获取当前位置
|
|
||||||
current_pos = gui_element.getPos()
|
|
||||||
x = new_x if new_x is not None else current_pos.getX()
|
|
||||||
z = new_z if new_z is not None else current_pos.getZ()
|
|
||||||
|
|
||||||
#应用边界限制
|
|
||||||
x = max(min_x,min(max_x,x))
|
|
||||||
z = max(min_z,min(max_z,z))
|
|
||||||
|
|
||||||
return Vec3(x,current_pos.getY(),z)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"约束2D位置时出错: {e}")
|
|
||||||
# 出错时返回原始值
|
|
||||||
current_pos = gui_element.getPos()
|
|
||||||
x = new_x if new_x is not None else current_pos.getX()
|
|
||||||
z = new_z if new_z is not None else current_pos.getZ()
|
|
||||||
return Vec3(x, current_pos.getY(), z)
|
|
||||||
|
|
||||||
|
|
||||||
def createGUI3DText(self, pos=(0, 0, 0), text="3D文本", size=1):
|
|
||||||
"""创建3D空间文本"""
|
|
||||||
from panda3d.core import TextNode,Material,Vec4,ColorAttrib,TransparencyAttrib
|
|
||||||
|
|
||||||
textNode = TextNode(f'3d-text-{len(self.gui_elements)}')
|
|
||||||
textNode.setText(text)
|
|
||||||
textNode.setAlign(TextNode.ACenter)
|
|
||||||
if self.world.getChineseFont():
|
|
||||||
textNode.setFont(self.world.getChineseFont())
|
|
||||||
|
|
||||||
textNode.setTextColor(Vec4(1,1,1,1))
|
|
||||||
|
|
||||||
textNodePath = self.world.render.attachNewNode(textNode)
|
|
||||||
textNodePath.setPos(*pos)
|
|
||||||
textNodePath.setScale(size,size,size)
|
|
||||||
#textNodePath.setBillboardAxis() # 让文本总是面向相机
|
|
||||||
|
|
||||||
# 为3D文本创建默认材质
|
|
||||||
material = Material(f"text-material-{len(self.gui_elements)}")
|
|
||||||
material.setBaseColor(Vec4(1, 1, 1, 1)) # 白色
|
|
||||||
material.setDiffuse(Vec4(1, 1, 1, 1))
|
|
||||||
material.setAmbient(Vec4(0.5, 0.5, 0.5, 1))
|
|
||||||
material.setSpecular(Vec4(0.1, 0.1, 0.1, 1.0))
|
|
||||||
material.setShininess(10.0)
|
|
||||||
#material.setEmission(0,0,0,1)
|
|
||||||
|
|
||||||
textNodePath.setMaterial(material, 1)
|
|
||||||
|
|
||||||
textNodePath.setTransparency(TransparencyAttrib.MAlpha)
|
|
||||||
textNodePath.setAttrib(ColorAttrib.makeFlat(Vec4(1, 1, 1, 1)))
|
|
||||||
textNodePath.setLightOff()
|
|
||||||
|
|
||||||
# 为GUI元素添加标识
|
|
||||||
textNodePath.setTag("gui_type", "3d_text")
|
|
||||||
textNodePath.setTag("gui_id", f"3d_text_{len(self.gui_elements)}")
|
|
||||||
textNodePath.setTag("gui_text", text)
|
|
||||||
textNodePath.setTag("is_gui_element", "1")
|
|
||||||
|
|
||||||
textNodePath.setDepthWrite(True) # 确保深度写入
|
|
||||||
textNodePath.setDepthTest(True) # 启用深度测试
|
|
||||||
textNodePath.setBin("fixed", 0) # 设置渲染层级,避免被遮挡
|
|
||||||
|
|
||||||
# if hasattr(self, 'render_pipeline') and self.render_pipeline:
|
|
||||||
# try:
|
|
||||||
# self.render_pipeline.set_effect(
|
|
||||||
# textNodePath,
|
|
||||||
# "effects/default.yaml",
|
|
||||||
# {
|
|
||||||
# "normal_mapping": False,
|
|
||||||
# "render_gbuffer": False,
|
|
||||||
# "alpha_testing": True,
|
|
||||||
# "parallax_mapping": False,
|
|
||||||
# "render_shadow": False,
|
|
||||||
# "render_envmap": False
|
|
||||||
# },
|
|
||||||
# 50
|
|
||||||
# )
|
|
||||||
# except Exception as e:
|
|
||||||
# print(f"⚠️ PBR效果应用失败: {e}")
|
|
||||||
|
|
||||||
self.gui_elements.append(textNodePath)
|
|
||||||
# 安全地调用updateSceneTree
|
|
||||||
if hasattr(self.world, 'updateSceneTree'):
|
|
||||||
self.world.updateSceneTree()
|
|
||||||
|
|
||||||
print(f"✓ 创建3D文本: {text} (世界位置: {pos})")
|
|
||||||
return textNodePath
|
|
||||||
"""创建2D GUI文本输入框 - 支持多选创建和GUI父子关系,优化版本"""
|
"""创建2D GUI文本输入框 - 支持多选创建和GUI父子关系,优化版本"""
|
||||||
try:
|
try:
|
||||||
from direct.gui.DirectGui import DirectEntry
|
from direct.gui.DirectGui import DirectEntry
|
||||||
@ -587,6 +382,185 @@ class GUIManager:
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def createGUI2DImage(self, pos=(0, 0, 0), image_path=None, size=0.2):
|
||||||
|
"""创建2D GUI图片"""
|
||||||
|
try:
|
||||||
|
from direct.gui.DirectGui import DirectButton
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
|
print(f"🔘 开始创建GUI按钮,位置: {pos}, 图片路径: {image_path}, 尺寸: {size}")
|
||||||
|
|
||||||
|
# 获取树形控件
|
||||||
|
tree_widget = self._get_tree_widget()
|
||||||
|
if not tree_widget:
|
||||||
|
print("❌ 无法访问树形控件")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 使用CustomTreeWidget的方法获取目标父节点列表
|
||||||
|
target_parents = tree_widget.get_target_parents_for_gui_creation()
|
||||||
|
if not target_parents:
|
||||||
|
print("❌ 没有找到有效的父节点")
|
||||||
|
return None
|
||||||
|
|
||||||
|
created_2dimage = []
|
||||||
|
|
||||||
|
# 为每个有效的父节点创建GUI按钮
|
||||||
|
for parent_item, parent_node in target_parents:
|
||||||
|
try:
|
||||||
|
# 生成唯一名称
|
||||||
|
image_name = f"GUIImage_{len(self.gui_elements)}"
|
||||||
|
|
||||||
|
# 使用CustomTreeWidget的方法判断父节点类型并设置相应的挂载方式
|
||||||
|
if tree_widget.is_gui_element(parent_node):
|
||||||
|
# 父节点是GUI元素 - 作为子GUI挂载
|
||||||
|
gui_pos = tree_widget.calculate_relative_gui_position(pos, parent_node)
|
||||||
|
parent_gui_node = parent_node # 直接挂载到GUI元素
|
||||||
|
print(f"📎 挂载到GUI父节点: {parent_node.getName()}")
|
||||||
|
else:
|
||||||
|
# 父节点是普通3D节点 - 使用屏幕坐标
|
||||||
|
gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1)
|
||||||
|
parent_gui_node = None # 使用默认的aspect2d
|
||||||
|
print(f"📎 挂载到3D父节点: {parent_item.text(0)}")
|
||||||
|
|
||||||
|
# 使用CardMaker创建一个更可靠的图片框架
|
||||||
|
cm = CardMaker('gui-2d-image')
|
||||||
|
cm.setFrame(-size, size, -size, size)
|
||||||
|
|
||||||
|
image_node = self.world.aspect2d.attachNewNode(cm.generate())
|
||||||
|
image_node.setPos(gui_pos)
|
||||||
|
image_node.setBin('fixed', 0)
|
||||||
|
image_node.setDepthWrite(False)
|
||||||
|
image_node.setDepthTest(False)
|
||||||
|
image_node.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
# 设置透明度支持
|
||||||
|
image_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
|
|
||||||
|
# 如果提供了图像路径,则加载纹理
|
||||||
|
if image_path:
|
||||||
|
try:
|
||||||
|
texture = self.world.loader.loadTexture(image_path)
|
||||||
|
if texture:
|
||||||
|
image_node.setTexture(texture, 1)
|
||||||
|
texture.setWrapU(Texture.WM_clamp)
|
||||||
|
texture.setWrapV(Texture.WM_clamp)
|
||||||
|
texture.setMinfilter(Texture.FT_linear)
|
||||||
|
texture.setMagfilter(Texture.FT_linear)
|
||||||
|
image_node.setColor(1, 1, 1, 1)
|
||||||
|
else:
|
||||||
|
print(f"⚠️ 无法加载2D图片纹理: {image_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 加载2D图片纹理失败: {e}")
|
||||||
|
|
||||||
|
# 设置节点标签
|
||||||
|
image_node.setTag("gui_type", "2d_image")
|
||||||
|
image_node.setTag("gui_id", f"2d_image_{len(self.gui_elements)}")
|
||||||
|
image_node.setTag("gui_text", f"2D图片_{len(self.gui_elements)}")
|
||||||
|
image_node.setTag("is_gui_element", "1")
|
||||||
|
image_node.setTag("is_scene_element", "1")
|
||||||
|
image_node.setTag("created_by_user", "1")
|
||||||
|
image_node.setTag("gui_parent_type", "gui" if parent_gui_node else "3d")
|
||||||
|
image_node.setName(image_name)
|
||||||
|
|
||||||
|
# 如果有GUI父节点,建立引用关系
|
||||||
|
if parent_gui_node:
|
||||||
|
parent_id = parent_gui_node.getTag("gui_id") if hasattr(parent_gui_node, 'getTag') else ""
|
||||||
|
image_node.setTag("gui_parent_id", parent_id)
|
||||||
|
|
||||||
|
# 添加到GUI元素列表
|
||||||
|
self.gui_elements.append(image_node)
|
||||||
|
|
||||||
|
print(f"✅ 为 {parent_item.text(0)} 创建GUI按钮成功: {image_name}")
|
||||||
|
|
||||||
|
# 使用CustomTreeWidget的方法在Qt树形控件中添加对应节点
|
||||||
|
qt_item = tree_widget.add_node_to_tree_widget(image_node, parent_item, "GUI_IMAGE")
|
||||||
|
if qt_item:
|
||||||
|
created_2dimage.append((image_node, qt_item))
|
||||||
|
else:
|
||||||
|
created_2dimage.append((image_node, None))
|
||||||
|
print("⚠️ Qt树节点添加失败,但GUI对象已创建")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 为 {parent_item.text(0)} 创建GUI按钮失败: {str(e)}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 处理创建结果
|
||||||
|
if not created_2dimage:
|
||||||
|
print("❌ 没有成功创建任何GUI按钮")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 选中最后创建的按钮并更新场景树
|
||||||
|
if created_2dimage:
|
||||||
|
last_button, last_qt_item = created_2dimage[-1]
|
||||||
|
if last_qt_item:
|
||||||
|
tree_widget.setCurrentItem(last_qt_item)
|
||||||
|
tree_widget.update_selection_and_properties(last_button, last_qt_item)
|
||||||
|
|
||||||
|
print(f"🎉 总共创建了 {len(created_2dimage)} 个GUI按钮")
|
||||||
|
|
||||||
|
# 返回值处理
|
||||||
|
if len(created_2dimage) == 1:
|
||||||
|
return created_2dimage[0][0]
|
||||||
|
else:
|
||||||
|
return [button for button, _ in created_2dimage]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 创建GUI按钮过程失败: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def constrain2DPosition(self,gui_element,new_x=None,new_z=None):
|
||||||
|
"""限制2dGUI元素位置在屏幕范围内"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import Vec3
|
||||||
|
|
||||||
|
bounds = gui_element.getTightBounds()
|
||||||
|
element_width=0
|
||||||
|
element_height=0
|
||||||
|
|
||||||
|
if bounds:
|
||||||
|
min_point,max_point = bounds
|
||||||
|
element_width = (max_point.getX() - min_point.getX())/2
|
||||||
|
element_height = (max_point.getZ()-min_point.getZ())/2
|
||||||
|
|
||||||
|
#获取当前缩放
|
||||||
|
scale = gui_element.getScale()
|
||||||
|
if hasattr(scale,'getX'):
|
||||||
|
scale_x = scale.getX()
|
||||||
|
scale_z = scale.getZ() if hasattr(scale,'getZ') else scale_x
|
||||||
|
else:
|
||||||
|
scale_x = scale_z = scale if isinstance(scale,(int,float)) else 1.0
|
||||||
|
|
||||||
|
actual_width = element_width * scale_x
|
||||||
|
actual_height = element_height * scale_z
|
||||||
|
|
||||||
|
screen_width = 1.9
|
||||||
|
screen_height = 0.9
|
||||||
|
|
||||||
|
min_x = -screen_width + actual_width
|
||||||
|
max_x = screen_width - actual_width
|
||||||
|
min_z = -screen_height + actual_height
|
||||||
|
max_z = screen_height - actual_height
|
||||||
|
|
||||||
|
#获取当前位置
|
||||||
|
current_pos = gui_element.getPos()
|
||||||
|
x = new_x if new_x is not None else current_pos.getX()
|
||||||
|
z = new_z if new_z is not None else current_pos.getZ()
|
||||||
|
|
||||||
|
#应用边界限制
|
||||||
|
x = max(min_x,min(max_x,x))
|
||||||
|
z = max(min_z,min(max_z,z))
|
||||||
|
|
||||||
|
return Vec3(x,current_pos.getY(),z)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"约束2D位置时出错: {e}")
|
||||||
|
# 出错时返回原始值
|
||||||
|
current_pos = gui_element.getPos()
|
||||||
|
x = new_x if new_x is not None else current_pos.getX()
|
||||||
|
z = new_z if new_z is not None else current_pos.getZ()
|
||||||
|
return Vec3(x, current_pos.getY(), z)
|
||||||
|
|
||||||
def createGUI3DText(self, pos=(0, 0, 0), text="3D文本", size=0.5):
|
def createGUI3DText(self, pos=(0, 0, 0), text="3D文本", size=0.5):
|
||||||
"""创建3D空间文本 - 支持多选创建,优化版本"""
|
"""创建3D空间文本 - 支持多选创建,优化版本"""
|
||||||
try:
|
try:
|
||||||
@ -680,6 +654,141 @@ class GUIManager:
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def createGUI3DImage(self, pos=(0, 0, 0), image_path=None, size=1.0):
|
||||||
|
"""创建3D空间图片"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import TextNode
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
|
print(f"📄 开始创建3D文本,位置: {pos}, 3D图片位置: {image_path}, 尺寸: {size}")
|
||||||
|
|
||||||
|
# 获取树形控件
|
||||||
|
tree_widget = self._get_tree_widget()
|
||||||
|
if not tree_widget:
|
||||||
|
print("❌ 无法访问树形控件")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 获取目标父节点列表
|
||||||
|
target_parents = tree_widget.get_target_parents_for_creation()
|
||||||
|
if not target_parents:
|
||||||
|
print("❌ 没有找到有效的父节点")
|
||||||
|
return None
|
||||||
|
|
||||||
|
created_3dimage = []
|
||||||
|
|
||||||
|
# 为每个有效的父节点创建3D文本
|
||||||
|
for parent_item, parent_node in target_parents:
|
||||||
|
try:
|
||||||
|
# 生成唯一名称
|
||||||
|
image_name = f"GUI3DImage_{len(self.gui_elements)}"
|
||||||
|
|
||||||
|
# 参数类型检查和转换
|
||||||
|
if isinstance(size, (list, tuple)):
|
||||||
|
if len(size) >= 2:
|
||||||
|
x_size, y_size = float(size[0]), float(size[1])
|
||||||
|
else:
|
||||||
|
x_size = y_size = float(size[0]) if size else 1.0
|
||||||
|
else:
|
||||||
|
x_size = y_size = float(size)
|
||||||
|
|
||||||
|
# 创建卡片
|
||||||
|
cm = CardMaker('gui_3d_image')
|
||||||
|
cm.setFrame(-x_size / 2, x_size / 2, -y_size / 2, y_size / 2)
|
||||||
|
|
||||||
|
# 创建3D图像节点
|
||||||
|
image_node = self.world.render.attachNewNode(cm.generate())
|
||||||
|
image_node.setPos(*pos)
|
||||||
|
|
||||||
|
# 为3D图像创建独立的材质
|
||||||
|
material = Material(f"image-material-{len(self.gui_elements)}")
|
||||||
|
material.setBaseColor(LColor(1, 1, 1, 1))
|
||||||
|
material.setDiffuse(LColor(1, 1, 1, 1))
|
||||||
|
material.setAmbient(LColor(0.5, 0.5, 0.5, 1))
|
||||||
|
material.setSpecular(LColor(0.1, 0.1, 0.1, 1.0))
|
||||||
|
material.setShininess(10.0)
|
||||||
|
material.setEmission(LColor(0, 0, 0, 1)) # 无自发光
|
||||||
|
image_node.setMaterial(material, 1)
|
||||||
|
|
||||||
|
image_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
|
|
||||||
|
# 如果提供了图像路径,则加载纹理
|
||||||
|
if image_path:
|
||||||
|
self.update3DImageTexture(image_node, image_path)
|
||||||
|
|
||||||
|
# 应用PBR效果(如果可用)
|
||||||
|
try:
|
||||||
|
if hasattr(self, 'render_pipeline') and self.render_pipeline:
|
||||||
|
self.render_pipeline.set_effect(
|
||||||
|
image_node,
|
||||||
|
"effects/default.yaml",
|
||||||
|
{
|
||||||
|
"normal_mapping": True,
|
||||||
|
"render_gbuffer": True,
|
||||||
|
"alpha_testing": False,
|
||||||
|
"parallax_mapping": False,
|
||||||
|
"render_shadow": False,
|
||||||
|
"render_envmap": True,
|
||||||
|
"disable_children_effects": True
|
||||||
|
},
|
||||||
|
50
|
||||||
|
)
|
||||||
|
print("✓ GUI 3D图像PBR效果已应用")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ GUI 3D图像PBR效果应用失败: {e}")
|
||||||
|
image_node.setName(image_name)
|
||||||
|
|
||||||
|
# 设置节点标签
|
||||||
|
image_node.setTag("gui_type", "3d_image")
|
||||||
|
image_node.setTag("gui_id", f"3d_image_{len(self.gui_elements)}")
|
||||||
|
if image_path:
|
||||||
|
image_node.setTag("gui_image_path", image_path)
|
||||||
|
image_node.setTag("is_gui_element", "1")
|
||||||
|
image_node.setTag("is_scene_element", "1")
|
||||||
|
image_node.setTag("created_by_user", "1")
|
||||||
|
|
||||||
|
# 添加到GUI元素列表
|
||||||
|
self.gui_elements.append(image_node)
|
||||||
|
|
||||||
|
print(f"✅ 为 {parent_item.text(0)} 创建3D文本成功: {image_name}")
|
||||||
|
|
||||||
|
# 在Qt树形控件中添加对应节点
|
||||||
|
qt_item = tree_widget.add_node_to_tree_widget(image_node, parent_item, "GUI_3DIMAGE")
|
||||||
|
if qt_item:
|
||||||
|
created_3dimage.append((image_node, qt_item))
|
||||||
|
else:
|
||||||
|
created_3dimage.append((image_node, None))
|
||||||
|
print("⚠️ Qt树节点添加失败,但GUI对象已创建")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 为 {parent_item.text(0)} 创建3D文本失败: {str(e)}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 处理创建结果
|
||||||
|
if not created_3dimage:
|
||||||
|
print("❌ 没有成功创建任何3D文本")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 选中最后创建的文本并更新场景树
|
||||||
|
if created_3dimage:
|
||||||
|
last_image, last_qt_item = created_3dimage[-1]
|
||||||
|
if last_qt_item:
|
||||||
|
tree_widget.setCurrentItem(last_qt_item)
|
||||||
|
tree_widget.update_selection_and_properties(last_image, last_qt_item)
|
||||||
|
|
||||||
|
print(f"🎉 总共创建了 {len(created_3dimage)} 个3D文本")
|
||||||
|
|
||||||
|
# 返回值处理
|
||||||
|
if len(created_3dimage) == 1:
|
||||||
|
return created_3dimage[0][0]
|
||||||
|
else:
|
||||||
|
return [text_np for text_np, _ in created_3dimage]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 创建3D文本过程失败: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
def createGUIVirtualScreen(self, pos=(0, 0, 0), size=(2, 1), text="虚拟屏幕"):
|
def createGUIVirtualScreen(self, pos=(0, 0, 0), size=(2, 1), text="虚拟屏幕"):
|
||||||
"""创建3D虚拟屏幕 - 支持多选创建,优化版本"""
|
"""创建3D虚拟屏幕 - 支持多选创建,优化版本"""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -282,9 +282,6 @@ class InterfaceManager:
|
|||||||
terrain_item.setData(0,Qt.UserRole+1,"terrain") # 标记为地形节点
|
terrain_item.setData(0,Qt.UserRole+1,"terrain") # 标记为地形节点
|
||||||
addNodeToTree(terrain_node,terrain_item,force=True)
|
addNodeToTree(terrain_node,terrain_item,force=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 展开所有节点
|
# 展开所有节点
|
||||||
#self.treeWidget.expandAll()
|
#self.treeWidget.expandAll()
|
||||||
self._restore_expanded()
|
self._restore_expanded()
|
||||||
|
|||||||
@ -41,6 +41,11 @@ class MainWindow(QMainWindow):
|
|||||||
self.updateTimer.timeout.connect(self.updateScriptPanel)
|
self.updateTimer.timeout.connect(self.updateScriptPanel)
|
||||||
self.updateTimer.start(500) # 每500毫秒更新一次
|
self.updateTimer.start(500) # 每500毫秒更新一次
|
||||||
|
|
||||||
|
self.toolbarDragging = False
|
||||||
|
self.dragStartPos = QPoint(0, 0)
|
||||||
|
self.toolbarStartPos = QPoint(0, 0)
|
||||||
|
|
||||||
|
|
||||||
def setupCenterWidget(self):
|
def setupCenterWidget(self):
|
||||||
"""设置窗口基本属性"""
|
"""设置窗口基本属性"""
|
||||||
self.setWindowTitle("引擎编辑器")
|
self.setWindowTitle("引擎编辑器")
|
||||||
@ -178,21 +183,27 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def toolbarMouseMoveEvent(self, event):
|
def toolbarMouseMoveEvent(self, event):
|
||||||
"""工具栏鼠标移动事件"""
|
"""工具栏鼠标移动事件"""
|
||||||
if self.toolbarDragging and event.buttons() == Qt.LeftButton:
|
try:
|
||||||
# 计算新位置
|
if self.toolbarDragging and event.buttons() == Qt.LeftButton:
|
||||||
delta = event.globalPos() - self.dragStartPos
|
# 计算新位置
|
||||||
new_pos = self.toolbarStartPos + delta
|
delta = event.globalPos() - self.dragStartPos
|
||||||
|
new_pos = self.toolbarStartPos + delta
|
||||||
|
|
||||||
# 边界检测
|
# 边界检测
|
||||||
panda_rect = self.pandaWidget.geometry()
|
panda_rect = self.pandaWidget.geometry()
|
||||||
toolbar_size = self.embeddedToolbar.size()
|
toolbar_size = self.embeddedToolbar.size()
|
||||||
|
|
||||||
# 限制在Panda3D区域内
|
# 限制在Panda3D区域内
|
||||||
new_pos.setX(max(0, min(new_pos.x(), panda_rect.width() - toolbar_size.width())))
|
new_pos.setX(max(0, min(new_pos.x(), panda_rect.width() - toolbar_size.width())))
|
||||||
new_pos.setY(max(0, min(new_pos.y(), panda_rect.height() - toolbar_size.height())))
|
new_pos.setY(max(0, min(new_pos.y(), panda_rect.height() - toolbar_size.height())))
|
||||||
|
|
||||||
|
self.embeddedToolbar.move(new_pos)
|
||||||
|
event.accept()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"工具栏鼠标移动事件出错")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
self.embeddedToolbar.move(new_pos)
|
|
||||||
event.accept()
|
|
||||||
|
|
||||||
def toolbarMouseReleaseEvent(self, event):
|
def toolbarMouseReleaseEvent(self, event):
|
||||||
"""工具栏鼠标释放事件"""
|
"""工具栏鼠标释放事件"""
|
||||||
@ -303,26 +314,12 @@ class MainWindow(QMainWindow):
|
|||||||
self.createMenu = menubar.addMenu('创建')
|
self.createMenu = menubar.addMenu('创建')
|
||||||
self.setupCreateMenuActions() # 统一创建菜单动作
|
self.setupCreateMenuActions() # 统一创建菜单动作
|
||||||
|
|
||||||
self.createGUIaddMenu = self.createMenu.addMenu('GUI')
|
|
||||||
self.createButtonAction = self.createGUIaddMenu.addAction('创建按钮')
|
|
||||||
self.createLabelAction = self.createGUIaddMenu.addAction('创建标签')
|
|
||||||
self.createEntryAction = self.createGUIaddMenu.addAction('创建输入框')
|
|
||||||
self.createGUIaddMenu.addSeparator()
|
|
||||||
self.createVirtualScreenAction = self.createGUIaddMenu.addAction('创建虚拟屏幕')
|
|
||||||
self.createCesiumViewAction = self.createGUIaddMenu.addAction('创建Cesium地图')
|
|
||||||
self.toggleCesiumViewAction = self.createGUIaddMenu.addAction('开关地图')
|
|
||||||
self.refreshCesiumViewAction = self.createGUIaddMenu.addAction('刷新地图')
|
|
||||||
|
|
||||||
self.createLightaddMenu = self.createMenu.addMenu('光源')
|
|
||||||
self.createSpotLightAction = self.createLightaddMenu.addAction('聚光灯')
|
|
||||||
self.createPointLightAction = self.createLightaddMenu.addAction('点光源')
|
|
||||||
|
|
||||||
#添加地形菜单
|
#添加地形菜单
|
||||||
self.createTerrainMenu = self.createMenu.addMenu('地形')
|
self.createTerrainMenu = self.createMenu.addMenu('地形')
|
||||||
self.createFlatTerrainAction = self.createTerrainMenu.addAction('创建平面地形')
|
self.createFlatTerrainAction = self.createTerrainMenu.addAction('创建平面地形')
|
||||||
self.createHeightmapTerrainAction = self.createTerrainMenu.addAction('从高度图创建地形')
|
self.createHeightmapTerrainAction = self.createTerrainMenu.addAction('从高度图创建地形')
|
||||||
self.createTerrainMenu.addSeparator()
|
self.createTerrainMenu.addSeparator()
|
||||||
self.terrainEditModeAction = self.createTerrainMenu.addAction('地形编辑模式')
|
# self.terrainEditModeAction = self.createTerrainMenu.addAction('地形编辑模式')
|
||||||
|
|
||||||
# GUI菜单
|
# GUI菜单
|
||||||
# GUI菜单 - 复用创建菜单的动作
|
# GUI菜单 - 复用创建菜单的动作
|
||||||
@ -383,12 +380,14 @@ class MainWindow(QMainWindow):
|
|||||||
# 3D GUI子菜单
|
# 3D GUI子菜单
|
||||||
self.create3dGUIaddMenu = self.createMenu.addMenu('3D GUI')
|
self.create3dGUIaddMenu = self.createMenu.addMenu('3D GUI')
|
||||||
self.create3DTextAction = self.create3dGUIaddMenu.addAction('3D文本')
|
self.create3DTextAction = self.create3dGUIaddMenu.addAction('3D文本')
|
||||||
|
self.create3DImageAction = self.create3dGUIaddMenu.addAction('3D图片')
|
||||||
|
|
||||||
# GUI子菜单
|
# GUI子菜单
|
||||||
self.createGUIaddMenu = self.createMenu.addMenu('GUI')
|
self.createGUIaddMenu = self.createMenu.addMenu('GUI')
|
||||||
self.createButtonAction = self.createGUIaddMenu.addAction('创建按钮')
|
self.createButtonAction = self.createGUIaddMenu.addAction('创建按钮')
|
||||||
self.createLabelAction = self.createGUIaddMenu.addAction('创建标签')
|
self.createLabelAction = self.createGUIaddMenu.addAction('创建标签')
|
||||||
self.createEntryAction = self.createGUIaddMenu.addAction('创建输入框')
|
self.createEntryAction = self.createGUIaddMenu.addAction('创建输入框')
|
||||||
|
self.createImageAction = self.createGUIaddMenu.addAction('创建图片')
|
||||||
self.createGUIaddMenu.addSeparator()
|
self.createGUIaddMenu.addSeparator()
|
||||||
self.createVideoScreen = self.createGUIaddMenu.addAction('创建视频屏幕')
|
self.createVideoScreen = self.createGUIaddMenu.addAction('创建视频屏幕')
|
||||||
self.createSphericalVideo = self.createGUIaddMenu.addAction('创建球形视频')
|
self.createSphericalVideo = self.createGUIaddMenu.addAction('创建球形视频')
|
||||||
@ -408,12 +407,14 @@ class MainWindow(QMainWindow):
|
|||||||
# 连接到world对象的创建方法
|
# 连接到world对象的创建方法
|
||||||
# self.createEnptyaddAction.triggered.connect(self.world.createEmptyObject)
|
# self.createEnptyaddAction.triggered.connect(self.world.createEmptyObject)
|
||||||
self.create3DTextAction.triggered.connect(lambda: self.world.createGUI3DText())
|
self.create3DTextAction.triggered.connect(lambda: self.world.createGUI3DText())
|
||||||
|
self.create3DImageAction.triggered.connect(lambda: self.world.createGUI3DImage())
|
||||||
self.createButtonAction.triggered.connect(lambda: self.world.createGUIButton())
|
self.createButtonAction.triggered.connect(lambda: self.world.createGUIButton())
|
||||||
self.createLabelAction.triggered.connect(lambda: self.world.createGUILabel())
|
self.createLabelAction.triggered.connect(lambda: self.world.createGUILabel())
|
||||||
self.createEntryAction.triggered.connect(lambda: self.world.createGUIEntry())
|
self.createEntryAction.triggered.connect(lambda: self.world.createGUIEntry())
|
||||||
|
self.createImageAction.triggered.connect(lambda: self.world.createGUI2DImage())
|
||||||
# self.createVideoScreen.triggered.connect(self.world.createVideoScreen)
|
# self.createVideoScreen.triggered.connect(self.world.createVideoScreen)
|
||||||
# self.createSphericalVideo.triggered.connect(self.world.createSphericalVideo)
|
# self.createSphericalVideo.triggered.connect(self.world.createSphericalVideo)
|
||||||
# self.createVirtualScreenAction.triggered.connect(self.world.createVirtualScreen)
|
self.createVirtualScreenAction.triggered.connect(lambda: self.world.createGUIVirtualScreen())
|
||||||
self.createSpotLightAction.triggered.connect(lambda :self.world.createSpotLight())
|
self.createSpotLightAction.triggered.connect(lambda :self.world.createSpotLight())
|
||||||
self.createPointLightAction.triggered.connect(lambda :self.world.createPointLight())
|
self.createPointLightAction.triggered.connect(lambda :self.world.createPointLight())
|
||||||
|
|
||||||
@ -430,9 +431,11 @@ class MainWindow(QMainWindow):
|
|||||||
return {
|
return {
|
||||||
'createEmpty': self.createEnptyaddAction,
|
'createEmpty': self.createEnptyaddAction,
|
||||||
'create3DText': self.create3DTextAction,
|
'create3DText': self.create3DTextAction,
|
||||||
|
'create3DImage': self.create3DImageAction,
|
||||||
'createButton': self.createButtonAction,
|
'createButton': self.createButtonAction,
|
||||||
'createLabel': self.createLabelAction,
|
'createLabel': self.createLabelAction,
|
||||||
'createEntry': self.createEntryAction,
|
'createEntry': self.createEntryAction,
|
||||||
|
'createImage': self.createImageAction,
|
||||||
'createVideoScreen': self.createVideoScreen,
|
'createVideoScreen': self.createVideoScreen,
|
||||||
'createSphericalVideo': self.createSphericalVideo,
|
'createSphericalVideo': self.createSphericalVideo,
|
||||||
'createVirtualScreen': self.createVirtualScreenAction,
|
'createVirtualScreen': self.createVirtualScreenAction,
|
||||||
@ -785,13 +788,13 @@ class MainWindow(QMainWindow):
|
|||||||
self.guiEditModeAction.triggered.connect(lambda: self.world.toggleGUIEditMode())
|
self.guiEditModeAction.triggered.connect(lambda: self.world.toggleGUIEditMode())
|
||||||
|
|
||||||
# 连接创建事件 - 使用菜单动作而不是不存在的工具栏按钮
|
# 连接创建事件 - 使用菜单动作而不是不存在的工具栏按钮
|
||||||
self.createSpotLightAction.triggered.connect(lambda: self.world.createSpotLight())
|
# self.createSpotLightAction.triggered.connect(lambda: self.world.createSpotLight())
|
||||||
self.createPointLightAction.triggered.connect(lambda: self.world.createPointLight())
|
# self.createPointLightAction.triggered.connect(lambda: self.world.createPointLight())
|
||||||
self.createButtonAction.triggered.connect(lambda: self.world.createGUIButton())
|
# self.createButtonAction.triggered.connect(lambda: self.world.createGUIButton())
|
||||||
self.createLabelAction.triggered.connect(lambda: self.world.createGUILabel())
|
# self.createLabelAction.triggered.connect(lambda: self.world.createGUILabel())
|
||||||
self.createEntryAction.triggered.connect(lambda: self.world.createGUIEntry())
|
# self.createEntryAction.triggered.connect(lambda: self.world.createGUIEntry())
|
||||||
self.create3DTextAction.triggered.connect(lambda: self.world.createGUI3DText())
|
# self.create3DTextAction.triggered.connect(lambda: self.world.createGUI3DText())
|
||||||
self.createVirtualScreenAction.triggered.connect(lambda: self.world.createGUIVirtualScreen())
|
# self.createVirtualScreenAction.triggered.connect(lambda: self.world.createGUIVirtualScreen())
|
||||||
self.createCesiumViewAction.triggered.connect(self.onCreateCesiumView)
|
self.createCesiumViewAction.triggered.connect(self.onCreateCesiumView)
|
||||||
self.toggleCesiumViewAction.triggered.connect(self.onToggleCesiumView)
|
self.toggleCesiumViewAction.triggered.connect(self.onToggleCesiumView)
|
||||||
self.refreshCesiumViewAction.triggered.connect(self.onRefreshCesiumView)
|
self.refreshCesiumViewAction.triggered.connect(self.onRefreshCesiumView)
|
||||||
@ -799,7 +802,7 @@ class MainWindow(QMainWindow):
|
|||||||
# 连接地形创建事件
|
# 连接地形创建事件
|
||||||
self.createFlatTerrainAction.triggered.connect(self.onCreateFlatTerrain)
|
self.createFlatTerrainAction.triggered.connect(self.onCreateFlatTerrain)
|
||||||
self.createHeightmapTerrainAction.triggered.connect(self.onCreateHeightmapTerrain)
|
self.createHeightmapTerrainAction.triggered.connect(self.onCreateHeightmapTerrain)
|
||||||
self.terrainEditModeAction.triggered.connect(self.onTerrainEditMode)
|
# self.terrainEditModeAction.triggered.connect(self.onTerrainEditMode)
|
||||||
|
|
||||||
# 连接树节点点击信号
|
# 连接树节点点击信号
|
||||||
self.treeWidget.itemSelectionChanged.connect(
|
self.treeWidget.itemSelectionChanged.connect(
|
||||||
|
|||||||
@ -1553,6 +1553,7 @@ class PropertyPanelManager:
|
|||||||
)
|
)
|
||||||
if file_path:
|
if file_path:
|
||||||
# 应用新纹理到 3D Image
|
# 应用新纹理到 3D Image
|
||||||
|
file_path = util.normalize_model_path(file_path)
|
||||||
success = self.world.gui_manager.update3DImageTexture(gui_element, file_path)
|
success = self.world.gui_manager.update3DImageTexture(gui_element, file_path)
|
||||||
if success:
|
if success:
|
||||||
# 保存路径到 Tag
|
# 保存路径到 Tag
|
||||||
@ -1560,7 +1561,7 @@ class PropertyPanelManager:
|
|||||||
# 更新显示
|
# 更新显示
|
||||||
texture_label.setText(file_path)
|
texture_label.setText(file_path)
|
||||||
# 可选:刷新场景树或其他 UI
|
# 可选:刷新场景树或其他 UI
|
||||||
self.world.scene_manager.updateSceneTree()
|
# self.world.scene_manager.updateSceneTree()
|
||||||
|
|
||||||
select_texture_button.clicked.connect(onSelectTexture)
|
select_texture_button.clicked.connect(onSelectTexture)
|
||||||
|
|
||||||
@ -1595,6 +1596,7 @@ class PropertyPanelManager:
|
|||||||
)
|
)
|
||||||
if file_path:
|
if file_path:
|
||||||
# 应用新纹理到 2D Image
|
# 应用新纹理到 2D Image
|
||||||
|
file_path = util.normalize_model_path(file_path)
|
||||||
success = self.update2DImageTexture(gui_element, file_path)
|
success = self.update2DImageTexture(gui_element, file_path)
|
||||||
if success:
|
if success:
|
||||||
# 保存路径到 Tag
|
# 保存路径到 Tag
|
||||||
@ -1603,7 +1605,7 @@ class PropertyPanelManager:
|
|||||||
# 更新显示
|
# 更新显示
|
||||||
#texture_label.setText(file_path)
|
#texture_label.setText(file_path)
|
||||||
# 可选:刷新场景树或其他 UI
|
# 可选:刷新场景树或其他 UI
|
||||||
self.world.scene_manager.updateSceneTree()
|
# self.world.scene_manager.updateSceneTree()
|
||||||
|
|
||||||
select_texture_button.clicked.connect(onSelect2DTexture)
|
select_texture_button.clicked.connect(onSelect2DTexture)
|
||||||
|
|
||||||
|
|||||||
@ -1302,11 +1302,40 @@ class CustomTreeWidget(QTreeWidget):
|
|||||||
parent = wrapinstance(0, QWidget)
|
parent = wrapinstance(0, QWidget)
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.world = world
|
self.world = world
|
||||||
|
self.initData()
|
||||||
self.setupUI() # 初始化界面
|
self.setupUI() # 初始化界面
|
||||||
self.setupContextMenu() # 初始化右键菜单
|
self.setupContextMenu() # 初始化右键菜单
|
||||||
|
|
||||||
self.setupDragDrop() # 设置拖拽功能
|
self.setupDragDrop() # 设置拖拽功能
|
||||||
|
|
||||||
|
def initData(self):
|
||||||
|
"""初始化变量"""
|
||||||
|
# 定义2D GUI元素类型
|
||||||
|
self.gui_2d_types = {
|
||||||
|
"GUI_BUTTON", # DirectButton
|
||||||
|
"GUI_LABEL", # DirectLabel
|
||||||
|
"GUI_ENTRY", # DirectEntry
|
||||||
|
"GUI_IMAGE",
|
||||||
|
"GUI_NODE" # 其他2D GUI容器
|
||||||
|
}
|
||||||
|
|
||||||
|
# 定义3D GUI元素类型
|
||||||
|
self.gui_3d_types = {
|
||||||
|
"GUI_3DTEXT", # 3D TextNode
|
||||||
|
"GUI_3DIMAGE",
|
||||||
|
"GUI_VIRTUAL_SCREEN" # Virtual Screen
|
||||||
|
}
|
||||||
|
|
||||||
|
# 定义3D场景节点类型(可以接受3D GUI元素和其他3D场景元素)
|
||||||
|
self.scene_3d_types = {
|
||||||
|
"SCENE_ROOT",
|
||||||
|
"SCENE_NODE",
|
||||||
|
"LIGHT_NODE",
|
||||||
|
"CAMERA_NODE",
|
||||||
|
"IMPORTED_MODEL_NODE",
|
||||||
|
"MODEL_NODE"
|
||||||
|
}
|
||||||
|
|
||||||
def setupUI(self):
|
def setupUI(self):
|
||||||
"""初始化UI设置"""
|
"""初始化UI设置"""
|
||||||
self.setHeaderHidden(True)
|
self.setHeaderHidden(True)
|
||||||
@ -1356,12 +1385,14 @@ class CustomTreeWidget(QTreeWidget):
|
|||||||
# 3D GUI菜单
|
# 3D GUI菜单
|
||||||
create3dGUIMenu = createMenu.addMenu('3D GUI')
|
create3dGUIMenu = createMenu.addMenu('3D GUI')
|
||||||
create3dGUIMenu.addAction(create_actions['create3DText'])
|
create3dGUIMenu.addAction(create_actions['create3DText'])
|
||||||
|
create3dGUIMenu.addAction(create_actions['create3DImage'])
|
||||||
|
|
||||||
# GUI菜单
|
# GUI菜单
|
||||||
createGUIMenu = createMenu.addMenu('GUI')
|
createGUIMenu = createMenu.addMenu('GUI')
|
||||||
createGUIMenu.addAction(create_actions['createButton'])
|
createGUIMenu.addAction(create_actions['createButton'])
|
||||||
createGUIMenu.addAction(create_actions['createLabel'])
|
createGUIMenu.addAction(create_actions['createLabel'])
|
||||||
createGUIMenu.addAction(create_actions['createEntry'])
|
createGUIMenu.addAction(create_actions['createEntry'])
|
||||||
|
createGUIMenu.addAction(create_actions['createImage'])
|
||||||
createGUIMenu.addSeparator()
|
createGUIMenu.addSeparator()
|
||||||
createGUIMenu.addAction(create_actions['createVideoScreen'])
|
createGUIMenu.addAction(create_actions['createVideoScreen'])
|
||||||
createGUIMenu.addAction(create_actions['createSphericalVideo'])
|
createGUIMenu.addAction(create_actions['createSphericalVideo'])
|
||||||
@ -1455,7 +1486,7 @@ class CustomTreeWidget(QTreeWidget):
|
|||||||
|
|
||||||
# 检查是否是2D GUI元素
|
# 检查是否是2D GUI元素
|
||||||
dragged_type = dragged_item.data(0, Qt.UserRole + 1)
|
dragged_type = dragged_item.data(0, Qt.UserRole + 1)
|
||||||
is_2d_gui = dragged_type in {"GUI_BUTTON", "GUI_LABEL", "GUI_ENTRY", "GUI_NODE"}
|
is_2d_gui = dragged_type in self.gui_2d_types
|
||||||
|
|
||||||
# 重新父化到新的父节点
|
# 重新父化到新的父节点
|
||||||
if new_parent_node:
|
if new_parent_node:
|
||||||
@ -1595,28 +1626,13 @@ class CustomTreeWidget(QTreeWidget):
|
|||||||
target_type = target_item.data(0, Qt.UserRole + 1)
|
target_type = target_item.data(0, Qt.UserRole + 1)
|
||||||
|
|
||||||
# 定义2D GUI元素类型
|
# 定义2D GUI元素类型
|
||||||
gui_2d_types = {
|
gui_2d_types = self.gui_2d_types
|
||||||
"GUI_BUTTON", # DirectButton
|
|
||||||
"GUI_LABEL", # DirectLabel
|
|
||||||
"GUI_ENTRY", # DirectEntry
|
|
||||||
"GUI_NODE" # 其他2D GUI容器
|
|
||||||
}
|
|
||||||
|
|
||||||
# 定义3D GUI元素类型
|
# 定义3D GUI元素类型
|
||||||
gui_3d_types = {
|
gui_3d_types = self.gui_3d_types
|
||||||
"GUI_3DTEXT", # 3D TextNode
|
|
||||||
"GUI_VIRTUAL_SCREEN" # Virtual Screen
|
|
||||||
}
|
|
||||||
|
|
||||||
# 定义3D场景节点类型(可以接受3D GUI元素和其他3D场景元素)
|
# 定义3D场景节点类型(可以接受3D GUI元素和其他3D场景元素)
|
||||||
scene_3d_types = {
|
scene_3d_types = self.scene_3d_types
|
||||||
"SCENE_ROOT",
|
|
||||||
"SCENE_NODE",
|
|
||||||
"LIGHT_NODE",
|
|
||||||
"CAMERA_NODE",
|
|
||||||
"IMPORTED_MODEL_NODE",
|
|
||||||
"MODEL_NODE"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 检查拖拽元素的类型
|
# 检查拖拽元素的类型
|
||||||
is_dragged_2d_gui = dragged_type in gui_2d_types
|
is_dragged_2d_gui = dragged_type in gui_2d_types
|
||||||
@ -1704,24 +1720,6 @@ class CustomTreeWidget(QTreeWidget):
|
|||||||
# 出错时采用保守策略,禁止拖拽
|
# 出错时采用保守策略,禁止拖拽
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _getNodeTypeDescription(self, node_type):
|
|
||||||
"""获取节点类型的描述文本(用于错误提示)"""
|
|
||||||
type_descriptions = {
|
|
||||||
"GUI_BUTTON": "2D按钮",
|
|
||||||
"GUI_LABEL": "2D标签",
|
|
||||||
"GUI_ENTRY": "2D输入框",
|
|
||||||
"GUI_NODE": "2D GUI容器",
|
|
||||||
"GUI_3DTEXT": "3D文本",
|
|
||||||
"GUI_VIRTUAL_SCREEN": "虚拟屏幕",
|
|
||||||
"SCENE_ROOT": "场景根节点",
|
|
||||||
"SCENE_NODE": "场景节点",
|
|
||||||
"LIGHT_NODE": "灯光节点",
|
|
||||||
"CAMERA_NODE": "相机节点",
|
|
||||||
"IMPORTED_MODEL_NODE": "导入模型",
|
|
||||||
"MODEL_NODE": "模型节点"
|
|
||||||
}
|
|
||||||
return type_descriptions.get(node_type, f"未知类型({node_type})")
|
|
||||||
|
|
||||||
def _getRootNode(self, item):
|
def _getRootNode(self, item):
|
||||||
"""获取树中节点的根节点项"""
|
"""获取树中节点的根节点项"""
|
||||||
if not item:
|
if not item:
|
||||||
@ -2018,10 +2016,7 @@ class CustomTreeWidget(QTreeWidget):
|
|||||||
node_type = item.data(0, Qt.UserRole + 1)
|
node_type = item.data(0, Qt.UserRole + 1)
|
||||||
|
|
||||||
# 场景根节点和普通场景节点可以作为父节点
|
# 场景根节点和普通场景节点可以作为父节点
|
||||||
if node_type in ["SCENE_ROOT",
|
if node_type in self.gui_3d_types and self.scene_3d_types:
|
||||||
"SCENE_NODE", "LIGHT_NODE", "CAMERA_NODE",
|
|
||||||
"IMPORTED_MODEL_NODE",
|
|
||||||
"GUI_3DTEXT"]:
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# # 模型节点也可以作为父节点
|
# # 模型节点也可以作为父节点
|
||||||
@ -2095,7 +2090,7 @@ class CustomTreeWidget(QTreeWidget):
|
|||||||
node_type = item.data(0, Qt.UserRole + 1)
|
node_type = item.data(0, Qt.UserRole + 1)
|
||||||
|
|
||||||
# GUI元素可以作为其他GUI元素的父节点
|
# GUI元素可以作为其他GUI元素的父节点
|
||||||
if node_type in ["GUI_BUTTON", "GUI_LABEL", "GUI_ENTRY", "GUI_NODE"]:
|
if node_type in self.gui_2d_types:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 场景根节点和普通场景节点也可以作为父节点
|
# 场景根节点和普通场景节点也可以作为父节点
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user