593 lines
25 KiB
Python
593 lines
25 KiB
Python
from panda3d.core import (Point3, Point2, CollisionTraverser, CollisionHandlerQueue,
|
||
CollisionNode, CollisionRay, GeomNode, LineSegs, RenderState,
|
||
DepthTestAttrib, ColorAttrib)
|
||
|
||
|
||
class EventHandler:
|
||
"""事件处理器 - 处理鼠标和键盘输入事件"""
|
||
|
||
def __init__(self, world):
|
||
"""初始化事件处理器"""
|
||
self.world = world
|
||
|
||
# 射线显示相关
|
||
self.showRay = False # 是否显示射线(默认关闭)
|
||
self.rayNode = None # 当前显示的射线节点
|
||
self.rayLifetime = 2.0 # 射线显示时间(秒)
|
||
|
||
def showClickRay(self, nearPoint, farPoint, hitPos=None):
|
||
"""显示鼠标点击的射线"""
|
||
if not self.showRay:
|
||
return
|
||
|
||
try:
|
||
# 清除之前的射线
|
||
self.clearRay()
|
||
|
||
# 创建射线几何体
|
||
lines = LineSegs()
|
||
lines.setThickness(3.0)
|
||
|
||
# 设置射线颜色
|
||
if hitPos:
|
||
# 有碰撞:射线分两段,起点到碰撞点为绿色,碰撞点到终点为红色
|
||
lines.setColor(0, 1, 0, 1) # 绿色
|
||
lines.moveTo(nearPoint)
|
||
lines.drawTo(hitPos)
|
||
|
||
lines.setColor(1, 0, 0, 1) # 红色
|
||
lines.moveTo(hitPos)
|
||
lines.drawTo(farPoint)
|
||
|
||
# 在碰撞点添加一个小球
|
||
lines.setColor(1, 1, 0, 1) # 黄色
|
||
self._addHitMarker(lines, hitPos)
|
||
else:
|
||
# 无碰撞:整条射线为蓝色
|
||
lines.setColor(0, 0, 1, 1) # 蓝色
|
||
lines.moveTo(nearPoint)
|
||
lines.drawTo(farPoint)
|
||
|
||
# 创建射线节点
|
||
geomNode = lines.create()
|
||
self.rayNode = self.world.render.attachNewNode(geomNode)
|
||
self.rayNode.setName("clickRay")
|
||
|
||
# 设置渲染状态,确保射线总是可见
|
||
state = RenderState.make(
|
||
DepthTestAttrib.make(DepthTestAttrib.MAlways), # 总是通过深度测试
|
||
ColorAttrib.makeFlat((1.0, 1.0, 1.0, 1.0))
|
||
)
|
||
self.rayNode.setState(state)
|
||
self.rayNode.setLightOff() # 不受光照影响
|
||
|
||
# 设置自动清除任务(先清除可能存在的旧任务)
|
||
from direct.task.TaskManagerGlobal import taskMgr
|
||
taskMgr.remove("clearRay") # 清除可能存在的旧任务
|
||
taskMgr.doMethodLater(self.rayLifetime, self.clearRayTask, "clearRay")
|
||
|
||
print(f"✓ 射线已显示,{self.rayLifetime}秒后自动清除")
|
||
|
||
except Exception as e:
|
||
print(f"显示射线失败: {str(e)}")
|
||
|
||
def _addHitMarker(self, lines, hitPos):
|
||
"""在碰撞点添加标记"""
|
||
# 创建一个小十字标记
|
||
marker_size = 0.5
|
||
|
||
# X方向线
|
||
lines.moveTo(hitPos.x - marker_size, hitPos.y, hitPos.z)
|
||
lines.drawTo(hitPos.x + marker_size, hitPos.y, hitPos.z)
|
||
|
||
# Y方向线
|
||
lines.moveTo(hitPos.x, hitPos.y - marker_size, hitPos.z)
|
||
lines.drawTo(hitPos.x, hitPos.y + marker_size, hitPos.z)
|
||
|
||
# Z方向线
|
||
lines.moveTo(hitPos.x, hitPos.y, hitPos.z - marker_size)
|
||
lines.drawTo(hitPos.x, hitPos.y, hitPos.z + marker_size)
|
||
|
||
def clearRay(self):
|
||
"""清除当前显示的射线"""
|
||
if self.rayNode:
|
||
self.rayNode.removeNode()
|
||
self.rayNode = None
|
||
|
||
# 同时清除可能存在的任务
|
||
from direct.task.TaskManagerGlobal import taskMgr
|
||
taskMgr.remove("clearRay")
|
||
|
||
def clearRayTask(self, task):
|
||
"""清除射线的任务回调"""
|
||
self.clearRay()
|
||
return task.done
|
||
|
||
def toggleRayDisplay(self):
|
||
"""切换射线显示状态"""
|
||
self.showRay = not self.showRay
|
||
if not self.showRay:
|
||
self.clearRay()
|
||
print(f"射线显示: {'开启' if self.showRay else '关闭'}")
|
||
return self.showRay
|
||
|
||
def mousePressEventLeft(self, evt):
|
||
"""处理鼠标左键按下事件"""
|
||
print("\n=== EventHandler开始处理鼠标左键事件 ===")
|
||
print(f"🔧 当前工具: {getattr(self.world, 'currentTool', '未知')}")
|
||
|
||
if not evt:
|
||
print("❌ 事件为空")
|
||
return
|
||
if self.world.currentTool == "地形编辑":
|
||
print("🔧 地形编辑模式,调用地形编辑处理")
|
||
self._handleTerrainEdit(evt,"add")
|
||
return
|
||
|
||
# 获取鼠标点击的位置
|
||
x = evt.get('x', 0)
|
||
y = evt.get('y', 0)
|
||
print(f"📍 EventHandler收到鼠标点击位置: ({x:.1f}, {y:.1f})")
|
||
|
||
# 获取准确的窗口尺寸
|
||
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}")
|
||
|
||
# 将相机坐标系的点转换到世界坐标系
|
||
worldNearPoint = self.world.render.getRelativePoint(self.world.cam, nearPoint)
|
||
worldFarPoint = self.world.render.getRelativePoint(self.world.cam, farPoint)
|
||
#print(f"世界坐标系射线起点: {worldNearPoint}")
|
||
#print(f"世界坐标系射线终点: {worldFarPoint}")
|
||
|
||
# 进行射线检测
|
||
picker = CollisionTraverser()
|
||
queue = CollisionHandlerQueue()
|
||
|
||
pickerNode = CollisionNode('mouseRay')
|
||
pickerNP = self.world.cam.attachNewNode(pickerNode)
|
||
# 设置射线的碰撞掩码,匹配模型的碰撞掩码(第2位)
|
||
from panda3d.core import BitMask32
|
||
pickerNode.setFromCollideMask(BitMask32.bit(2))
|
||
|
||
# 使用相机坐标系的点创建射线(因为pickerNP是相机的子节点)
|
||
direction = farPoint - nearPoint
|
||
direction.normalize()
|
||
pickerNode.addSolid(CollisionRay(nearPoint, direction))
|
||
|
||
picker.addCollider(pickerNP, queue)
|
||
picker.traverse(self.world.render)
|
||
|
||
#print(f"碰撞检测结果数量: {queue.getNumEntries()}")
|
||
|
||
# 射线检测结果处理
|
||
hitPos = None
|
||
hitNode = None
|
||
|
||
if queue.getNumEntries() > 0:
|
||
# 获取最近的碰撞点
|
||
entry = queue.getEntry(0)
|
||
hitPos = entry.getSurfacePoint(self.world.render)
|
||
hitNode = entry.getIntoNodePath()
|
||
print(f"碰撞到节点: {hitNode.getName()}")
|
||
|
||
# 显示射线(使用世界坐标系的点)
|
||
self.showClickRay(worldNearPoint, worldFarPoint, hitPos)
|
||
|
||
# 处理ImGui鼠标点击
|
||
if hasattr(self.world, 'processImGuiMouseClick'):
|
||
if self.world.processImGuiMouseClick(x, y):
|
||
# 如果ImGui处理了点击,不再进行其他处理
|
||
pickerNP.removeNode()
|
||
return
|
||
|
||
# 优先检查是否点击了坐标轴
|
||
#print(f"检查坐标轴点击: 坐标轴存在={bool(self.world.selection.gizmo)}")
|
||
if self.world.selection.gizmo:
|
||
#print("准备检查坐标轴点击...")
|
||
try:
|
||
highlighted_axis = self.world.selection.gizmoHighlightAxis
|
||
if highlighted_axis:
|
||
print(f"✓ 检测到高亮轴: {highlighted_axis},直接开始拖拽")
|
||
# 直接使用高亮轴开始拖拽
|
||
self.world.selection.startGizmoDrag(highlighted_axis, x, y)
|
||
pickerNP.removeNode()
|
||
return
|
||
|
||
# 如果没有高亮轴,再尝试检测点击
|
||
gizmoAxis = self.world.selection.checkGizmoClick(x, y)
|
||
if gizmoAxis:
|
||
print(f"✓ 检测到坐标轴点击: {gizmoAxis}")
|
||
# 开始坐标轴拖拽
|
||
self.world.selection.startGizmoDrag(gizmoAxis, x, y)
|
||
pickerNP.removeNode()
|
||
return
|
||
else:
|
||
print("× 没有点击到坐标轴")
|
||
|
||
# gizmoAxis = self.world.selection.checkGizmoClick(x, y)
|
||
# if gizmoAxis:
|
||
# #print(f"✓ 检测到坐标轴点击: {gizmoAxis}")
|
||
# # 开始坐标轴拖拽
|
||
# self.world.selection.startGizmoDrag(gizmoAxis, x, y)
|
||
# pickerNP.removeNode()
|
||
# return
|
||
# else:
|
||
# print("× 没有点击到坐标轴")
|
||
except Exception as e:
|
||
print(f"❌ 坐标轴点击检测出现异常: {str(e)}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
print("继续处理模型选择...")
|
||
|
||
#print("继续处理碰撞结果...")
|
||
|
||
if hitPos and hitNode:
|
||
#print(f"✓ 检测到碰撞,开始处理点击事件")
|
||
#print(f"GUI编辑模式: {self.world.guiEditMode}")
|
||
#print(f"当前工具: {self.world.currentTool}")
|
||
|
||
# 处理GUI编辑模式
|
||
if self.world.guiEditMode:
|
||
#print("处理GUI编辑模式点击")
|
||
# 检查是否点击了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)
|
||
pickerNP.removeNode()
|
||
return
|
||
|
||
# 根据当前工具处理点击事件
|
||
if self.world.currentTool in ("选择", "移动", "旋转", "缩放"):
|
||
print("✓ 使用选择工具处理点击")
|
||
try:
|
||
self._handleSelectionClick(hitNode)
|
||
print("✓ 选择处理完成")
|
||
except Exception as e:
|
||
print(f"❌ 选择处理出现异常: {str(e)}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
else:
|
||
print(f"当前工具不是'选择',无法处理: {self.world.currentTool}")
|
||
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)
|
||
|
||
# 确保总是清理碰撞检测节点
|
||
try:
|
||
pickerNP.removeNode()
|
||
print("✓ 碰撞检测节点已清理")
|
||
except Exception as e:
|
||
print(f"清理碰撞检测节点失败: {str(e)}")
|
||
|
||
print("=== 鼠标左键事件处理结束 ===\n")
|
||
|
||
def mousePressEventRight(self,evt):
|
||
"""处理鼠标右键按下事件"""
|
||
print(f"当前工具: {self.world.currentTool}")
|
||
|
||
# 检查是否是地形编辑模式
|
||
if self.world.currentTool == "地形编辑":
|
||
self._handleTerrainEdit(evt, "subtract") # 降低地形
|
||
return
|
||
|
||
# 其他右键处理逻辑可以在这里添加
|
||
print("鼠标右键事件处理")
|
||
|
||
def _handleTerrainEdit(self, evt, operation):
|
||
"""处理地形编辑"""
|
||
try:
|
||
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)
|
||
|
||
nearPoint = Point3()
|
||
farPoint = Point3()
|
||
self.world.cam.node().getLens().extrude(Point2(mx, my), nearPoint, farPoint)
|
||
|
||
worldNearPoint = self.world.render.getRelativePoint(self.world.cam, nearPoint)
|
||
worldFarPoint = self.world.render.getRelativePoint(self.world.cam, farPoint)
|
||
|
||
picker = CollisionTraverser()
|
||
queue = CollisionHandlerQueue()
|
||
|
||
pickerNode = CollisionNode('terrain_edit_ray')
|
||
pickerNP = self.world.cam.attachNewNode(pickerNode)
|
||
|
||
from panda3d.core import BitMask32
|
||
# 确保我们检测所有碰撞体
|
||
pickerNode.setFromCollideMask(BitMask32.bit(2))
|
||
|
||
# 使用相机坐标系的点创建射线
|
||
direction = farPoint - nearPoint
|
||
direction.normalize()
|
||
pickerNode.addSolid(CollisionRay(nearPoint, direction))
|
||
|
||
picker.addCollider(pickerNP, queue)
|
||
picker.traverse(self.world.render)
|
||
print(f"地形碰撞检测结果数量: {queue.getNumEntries()}")
|
||
|
||
# 添加调试信息,显示所有场景中的碰撞体
|
||
print("场景中的碰撞体:")
|
||
|
||
def show_colliders(node, level=0):
|
||
indent = " " * level
|
||
if not node.isEmpty():
|
||
if isinstance(node.node(), CollisionNode):
|
||
print(f"{indent}CollisionNode: {node.getName()}")
|
||
for child in node.getChildren():
|
||
show_colliders(child, level + 1)
|
||
|
||
show_colliders(self.world.render)
|
||
|
||
# 射线检测结果处理
|
||
hitPos = None
|
||
hitNode = None
|
||
hitTerrainInfo = None
|
||
|
||
if queue.getNumEntries() > 0:
|
||
queue.sortEntries()
|
||
# 遍历所有碰撞结果,找到地形节点
|
||
for i in range(queue.getNumEntries()):
|
||
entry = queue.getEntry(i)
|
||
collided_node = entry.getIntoNodePath()
|
||
print(f"碰撞到节点: {collided_node.getName()}")
|
||
|
||
# 检查是否是地形节点
|
||
for terrain_info in self.world.terrain_manager.terrains:
|
||
terrain_node = terrain_info['node']
|
||
if collided_node == terrain_node or terrain_node.isAncestorOf(collided_node):
|
||
hitPos = entry.getSurfacePoint(self.world.render)
|
||
hitNode = collided_node
|
||
hitTerrainInfo = terrain_info
|
||
print(f"找到地形节点: {terrain_node.getName()}")
|
||
break
|
||
|
||
if hitPos:
|
||
break
|
||
|
||
if hitPos and hitTerrainInfo:
|
||
# 修改地形高度
|
||
x_pos, y_pos = hitPos.getX(), hitPos.getY()
|
||
|
||
# 使用 getattr 获取地形编辑参数
|
||
radius = getattr(self.world, 'terrain_edit_radius', 3.0)
|
||
strength = getattr(self.world, 'terrain_edit_strength', 0.3)
|
||
|
||
print(f"准备编辑地形: 位置({x_pos:.2f}, {y_pos:.2f}), 半径{radius}, 强度{strength}, 操作{operation}")
|
||
|
||
# 添加更多调试信息
|
||
print(f"地形信息: {hitTerrainInfo}")
|
||
if 'heightmap' in hitTerrainInfo:
|
||
print(f"高度图路径: {hitTerrainInfo['heightmap']}")
|
||
|
||
try:
|
||
# 检查 terrain_manager 是否有 modifyTerrainHeight 方法
|
||
if not hasattr(self.world.terrain_manager, 'modifyTerrainHeight'):
|
||
print("✗ 错误: terrain_manager 没有 modifyTerrainHeight 方法")
|
||
self.showClickRay(worldNearPoint, worldFarPoint, hitPos)
|
||
return
|
||
|
||
# 调用地形编辑方法
|
||
success = self.world.terrain_manager.modifyTerrainHeight(
|
||
hitTerrainInfo, x_pos, y_pos, radius=radius, strength=strength, operation=operation)
|
||
|
||
if success:
|
||
print(f"✓ 地形编辑成功: {operation} at ({x_pos:.2f}, {y_pos:.2f})")
|
||
# 显示射线
|
||
self.showClickRay(worldNearPoint, worldFarPoint, hitPos)
|
||
|
||
# 强制刷新地形显示
|
||
if 'terrain' in hitTerrainInfo:
|
||
hitTerrainInfo['terrain'].generate()
|
||
print("✓ 地形已刷新")
|
||
else:
|
||
print("✗ 地形编辑失败")
|
||
# 即使编辑失败也显示射线
|
||
self.showClickRay(worldNearPoint, worldFarPoint, hitPos)
|
||
except Exception as e:
|
||
print(f"✗ 地形编辑过程中出现异常: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
# 即使编辑失败也显示射线
|
||
self.showClickRay(worldNearPoint, worldFarPoint, hitPos)
|
||
else:
|
||
print("没有检测到地形碰撞")
|
||
# 显示射线(无碰撞)
|
||
self.showClickRay(worldNearPoint, worldFarPoint)
|
||
|
||
# 清理碰撞检测节点
|
||
pickerNP.removeNode()
|
||
print("地形编辑处理完成")
|
||
|
||
except Exception as e:
|
||
print(f"地形编辑处理出错: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def _handleSelectionClick(self, hitNode):
|
||
"""处理选择工具的点击事件"""
|
||
print(f"开始处理选择点击,碰撞节点: {hitNode.getName()}")
|
||
|
||
# 查找对应的实际模型节点
|
||
selectedModel = None
|
||
|
||
# 如果点击的是碰撞节点,找到它的父模型
|
||
if isinstance(hitNode.node(), CollisionNode):
|
||
print(f"点击的是碰撞节点: {hitNode.getName()}")
|
||
# 碰撞节点的父节点应该是模型
|
||
parent = hitNode.getParent()
|
||
if parent in self.world.models:
|
||
selectedModel = parent
|
||
print(f"找到对应的模型: {selectedModel.getName()}")
|
||
else:
|
||
print(f"碰撞节点的父节点不是模型: {parent.getName()}")
|
||
else:
|
||
# 查找可选择的节点(模型或其子节点)
|
||
current = hitNode
|
||
while current != self.world.render:
|
||
# 检查是否是模型
|
||
if current in self.world.models:
|
||
selectedModel = current
|
||
print(f"找到模型节点: {selectedModel.getName()}")
|
||
break
|
||
|
||
# 检查是否是模型的子节点
|
||
for model in self.world.models:
|
||
if current.getParent() == model or current.isAncestorOf(model):
|
||
selectedModel = model
|
||
print(f"找到父模型: {selectedModel.getName()}")
|
||
break
|
||
|
||
if selectedModel:
|
||
break
|
||
|
||
current = current.getParent()
|
||
|
||
if selectedModel:
|
||
#print(f"✓ 最终选中模型: {selectedModel.getName()}")
|
||
self.world.selection.handleMouseClick(selectedModel)
|
||
|
||
# 更新选择状态并显示选择框和坐标轴
|
||
self.world.selection.updateSelection(selectedModel)
|
||
|
||
# 在树形控件中查找并选中对应的项
|
||
if hasattr(self.world, 'interface_manager') and self.world.interface_manager and hasattr(self.world.interface_manager, 'treeWidget') and self.world.interface_manager.treeWidget:
|
||
#print("查找树形控件中的对应项...")
|
||
root = self.world.interface_manager.treeWidget.invisibleRootItem()
|
||
foundItem = None
|
||
|
||
for i in range(root.childCount()):
|
||
sceneItem = root.child(i)
|
||
if sceneItem.text(0) == "场景":
|
||
#print(f"在场景节点下查找...")
|
||
foundItem = self.world.interface_manager.findTreeItem(selectedModel, sceneItem)
|
||
if foundItem:
|
||
print(f"✓ 在树形控件中找到对应项: {foundItem.text(0)}")
|
||
try:
|
||
self.world.interface_manager.treeWidget.itemClicked.disconnect()
|
||
except TypeError:
|
||
pass
|
||
|
||
self.world.interface_manager.treeWidget.setCurrentItem(foundItem)
|
||
|
||
self.world.interface_manager.treeWidget.itemClicked.connect(
|
||
self.world.interface_manager.onTreeItemClicked)
|
||
else:
|
||
print("× 在树形控件中没有找到对应项")
|
||
break
|
||
|
||
if not foundItem:
|
||
print("× 没有找到场景节点或对应的树形项")
|
||
else:
|
||
print("× 树形控件不存在")
|
||
else:
|
||
print("× 没有找到可选择的模型节点")
|
||
self.world.selection.updateSelection(None)
|
||
|
||
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)
|
||
# 减少高亮调试输出,只在需要时输出
|
||
# 已静默处理,避免控制台刷屏
|
||
self.world.selection.updateGizmoHighlight(x, y)
|
||
|
||
# 调用CoreWorld的父类方法处理基础的相机旋转
|
||
super(type(self.world), self.world).mouseMoveEvent(evt)
|