1
0
forked from Rowland/EG
EG/core/event_handler.py
2025-07-02 09:49:59 +08:00

231 lines
9.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from panda3d.core import (Point3, Point2, CollisionTraverser, CollisionHandlerQueue,
CollisionNode, CollisionRay, GeomNode)
class EventHandler:
"""事件处理器 - 处理鼠标和键盘输入事件"""
def __init__(self, world):
"""初始化事件处理器"""
self.world = world
def mousePressEventLeft(self, evt):
"""处理鼠标左键按下事件"""
print("\n=== 开始处理鼠标左键事件 ===")
print(f"当前工具: {self.world.currentTool}")
if not evt:
print("事件为空")
return
# 获取鼠标点击的位置
x = evt.get('x', 0)
y = evt.get('y', 0)
print(f"鼠标点击位置: ({x}, {y})")
# 获取准确的窗口尺寸
winWidth, winHeight = self.world.getWindowSize()
# 直接使用 x, y 创建鼠标位置
mx = 2.0 * x / float(winWidth) - 1.0
my = 1.0 - 2.0 * y / float(winHeight)
print(f"转换后的坐标: ({mx}, {my})")
# 创建射线
nearPoint = Point3()
farPoint = Point3()
self.world.cam.node().getLens().extrude(Point2(mx, my), nearPoint, farPoint)
print(f"射线起点: {nearPoint}")
print(f"射线终点: {farPoint}")
# 进行射线检测
picker = CollisionTraverser()
queue = CollisionHandlerQueue()
pickerNode = CollisionNode('mouseRay')
pickerNP = self.world.cam.attachNewNode(pickerNode)
pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
# 使用 nearPoint 和 farPoint 创建射线
direction = farPoint - nearPoint
direction.normalize()
pickerNode.addSolid(CollisionRay(nearPoint, direction))
picker.addCollider(pickerNP, queue)
picker.traverse(self.world.render)
print(f"碰撞检测结果数量: {queue.getNumEntries()}")
if queue.getNumEntries() > 0:
# 获取最近的碰撞点
entry = queue.getEntry(0)
hitPos = entry.getSurfacePoint(self.world.render)
hitNode = entry.getIntoNodePath()
print(f"碰撞到节点: {hitNode.getName()}")
# 优先检查是否点击了坐标轴
print(f"检查坐标轴点击: 坐标轴存在={bool(self.world.selection.gizmo)}")
if self.world.selection.gizmo:
print("准备检查坐标轴点击...")
gizmoAxis = self.world.selection.checkGizmoClick(x, y)
if gizmoAxis:
print(f"✓ 检测到坐标轴点击: {gizmoAxis}")
# 开始坐标轴拖拽
self.world.selection.startGizmoDrag(gizmoAxis, x, y)
return
else:
print("× 没有点击到坐标轴")
# 处理GUI编辑模式
if self.world.guiEditMode:
# 检查是否点击了GUI元素
clickedGUI = self.world.gui_manager.findClickedGUI(hitNode)
if clickedGUI:
# 选中GUI元素
self.world.selection.updateSelection(clickedGUI)
self.world.gui_manager.selectGUIInTree(clickedGUI)
print(f"选中GUI元素: {clickedGUI.getTag('gui_text')}")
elif hasattr(self.world, 'currentGUITool') and self.world.currentGUITool:
# 在点击位置创建新GUI元素
self.world.gui_manager.createGUIAtPosition(hitPos, self.world.currentGUITool)
return
# 根据当前工具处理点击事件
if self.world.currentTool == "选择":
print("使用选择工具处理点击")
self._handleSelectionClick(hitNode)
else:
print("没有检测到碰撞")
# 如果不在GUI编辑模式清除选择
if not self.world.guiEditMode:
self.world.selection.updateSelection(None)
# 在GUI编辑模式下即使没有碰撞也可以在空白区域创建GUI
if (self.world.guiEditMode and
hasattr(self.world, 'currentGUITool') and
self.world.currentGUITool):
# 使用默认的地面高度创建GUI
default_height = 0.0
world_pos = Point3(mx * 10, 0, my * 10) # 简单的屏幕到世界坐标转换
world_pos.setZ(default_height)
self.world.gui_manager.createGUIAtPosition(world_pos, self.world.currentGUITool)
pickerNP.removeNode()
print("=== 鼠标左键事件处理结束 ===\n")
def _handleSelectionClick(self, hitNode):
"""处理选择工具的点击事件"""
# 查找可选择的节点(模型或其子节点)
while hitNode != self.world.render:
# 检查是否是模型或模型的子节点
isModel = hitNode in self.world.models
isChildOfModel = False
for model in self.world.models:
# 检查是否是模型的子节点
current = hitNode
while current != self.world.render:
if current == model:
isChildOfModel = True
break
current = current.getParent()
if isChildOfModel:
break
print(f"检查节点 {hitNode.getName()}: isModel={isModel}, isChildOfModel={isChildOfModel}")
if isModel or isChildOfModel:
print(f"选中节点: {hitNode.getName()}")
# 在树形控件中查找并选中对应的项
if self.world.interface_manager.treeWidget:
root = self.world.interface_manager.treeWidget.invisibleRootItem()
for i in range(root.childCount()):
sceneItem = root.child(i)
if sceneItem.text(0) == "场景":
foundItem = self.world.interface_manager.findTreeItem(hitNode, sceneItem)
if foundItem:
self.world.interface_manager.treeWidget.setCurrentItem(foundItem)
self.world.property_panel.updatePropertyPanel(foundItem)
# 更新选择状态并显示选择框
self.world.selection.updateSelection(hitNode)
break
break
hitNode = hitNode.getParent()
def mouseReleaseEventLeft(self, evt):
"""处理鼠标左键释放事件"""
# 处理坐标轴拖拽结束
if self.world.selection.isDraggingGizmo:
self.world.selection.stopGizmoDrag()
return
def wheelForward(self, data=None):
"""处理滚轮向前滚动(前进)"""
# 调用CoreWorld的父类方法
super(type(self.world), self.world).wheelForward(data)
# 更新属性面板
if (self.world.interface_manager.treeWidget and
self.world.interface_manager.treeWidget.currentItem() and
self.world.interface_manager.treeWidget.currentItem().text(0) == "相机"):
self.world.property_panel.updatePropertyPanel(
self.world.interface_manager.treeWidget.currentItem())
def wheelBackward(self, data=None):
"""处理滚轮向后滚动(后退)"""
# 调用CoreWorld的父类方法
super(type(self.world), self.world).wheelBackward(data)
# 更新属性面板
if (self.world.interface_manager.treeWidget and
self.world.interface_manager.treeWidget.currentItem() and
self.world.interface_manager.treeWidget.currentItem().text(0) == "相机"):
self.world.property_panel.updatePropertyPanel(
self.world.interface_manager.treeWidget.currentItem())
def mousePressEventMiddle(self, evt):
"""处理鼠标中键按下事件"""
# 已移除原有的Z轴拖拽功能
pass
def mouseReleaseEventMiddle(self, evt):
"""处理鼠标中键释放事件"""
# 已移除原有的Z轴拖拽功能
pass
def mouseMoveEvent(self, evt):
"""处理鼠标移动事件"""
if not evt:
return
# 处理坐标轴拖拽
if self.world.selection.isDraggingGizmo:
x = evt.get('x', 0)
y = evt.get('y', 0)
# 获取准确的窗口尺寸
winWidth, winHeight = self.world.getWindowSize()
# 将屏幕坐标转换为世界坐标
mx = 2.0 * x / float(winWidth) - 1.0
my = 1.0 - 2.0 * y / float(winHeight)
# 更新坐标轴拖拽
self.world.selection.updateGizmoDrag(x, y)
return
# 更新坐标轴高亮(鼠标悬停效果)
if self.world.selection.gizmo and not self.world.selection.isDraggingGizmo:
x = evt.get('x', 0)
y = evt.get('y', 0)
# 只在前5次调用时输出调试信息避免刷屏
if not hasattr(self.world, '_highlight_debug_count'):
self.world._highlight_debug_count = 0
if self.world._highlight_debug_count < 5:
print(f"更新坐标轴高亮: 鼠标({x}, {y}), 坐标轴存在={bool(self.world.selection.gizmo)}")
self.world._highlight_debug_count += 1
self.world.selection.updateGizmoHighlight(x, y)
# 调用CoreWorld的父类方法处理基础的相机旋转
super(type(self.world), self.world).mouseMoveEvent(evt)