254 lines
9.2 KiB
Python
254 lines
9.2 KiB
Python
import os
|
||
from imgui_bundle import imgui, imgui_ctx
|
||
|
||
|
||
class InteractionPanels:
|
||
"""Drag-and-drop and context menu interaction panels."""
|
||
|
||
def __init__(self, app):
|
||
self.app = app
|
||
|
||
def __getattr__(self, name):
|
||
return getattr(self.app, name)
|
||
|
||
def __setattr__(self, name, value):
|
||
if name == "app" or name in self.__dict__ or hasattr(type(self), name):
|
||
object.__setattr__(self, name, value)
|
||
else:
|
||
setattr(self.app, name, value)
|
||
|
||
|
||
def _draw_drag_drop_interface(self):
|
||
"""绘制拖拽界面"""
|
||
# 检查资源管理器的拖拽状态
|
||
if self.resource_manager.is_dragging():
|
||
self.is_dragging = True
|
||
self.dragged_files = self.resource_manager.get_dragged_files()
|
||
self.show_drag_overlay = True
|
||
|
||
# 绘制拖拽覆盖层
|
||
if self.show_drag_overlay:
|
||
self._draw_drag_overlay()
|
||
|
||
# 检查是否有拖拽的文件需要处理
|
||
if self.is_dragging and self.dragged_files:
|
||
# 显示拖拽状态
|
||
self._draw_drag_status()
|
||
|
||
# 检查是否释放鼠标(结束拖拽)
|
||
if imgui.is_mouse_released(0):
|
||
self._handle_drag_drop_completion()
|
||
|
||
|
||
def _handle_drag_drop_completion(self):
|
||
"""处理拖拽完成"""
|
||
# 检查是否在3D视图中释放
|
||
mouse_pos = imgui.get_mouse_pos()
|
||
viewport = imgui.get_main_viewport()
|
||
|
||
# 简单检查:如果不在任何ImGui窗口上,则认为是在3D视图中
|
||
if not imgui.is_any_window_hovered():
|
||
# 导入支持的3D模型文件
|
||
imported_count = 0
|
||
for file_path in self.dragged_files:
|
||
if file_path.suffix.lower() in ['.gltf', '.glb', '.fbx', '.bam', '.egg', '.obj']:
|
||
try:
|
||
self._import_model_for_runtime(str(file_path))
|
||
self.add_success_message(f"成功导入模型: {file_path.name}")
|
||
imported_count += 1
|
||
except Exception as e:
|
||
self.add_error_message(f"导入模型失败 {file_path.name}: {e}")
|
||
|
||
if imported_count > 0:
|
||
self.add_success_message(f"共导入 {imported_count} 个模型")
|
||
|
||
# 清除拖拽状态
|
||
self.is_dragging = False
|
||
self.dragged_files.clear()
|
||
self.show_drag_overlay = False
|
||
self.resource_manager.clear_drag()
|
||
|
||
|
||
def _draw_drag_overlay(self):
|
||
"""绘制拖拽覆盖层"""
|
||
viewport = imgui.get_main_viewport()
|
||
imgui.set_next_window_pos((0, 0))
|
||
imgui.set_next_window_size(viewport.work_size)
|
||
|
||
flags = (
|
||
imgui.WindowFlags_.no_title_bar |
|
||
imgui.WindowFlags_.no_resize |
|
||
imgui.WindowFlags_.no_move |
|
||
imgui.WindowFlags_.no_scrollbar |
|
||
imgui.WindowFlags_.no_saved_settings |
|
||
imgui.WindowFlags_.no_background |
|
||
imgui.WindowFlags_.no_focus_on_appearing
|
||
)
|
||
|
||
imgui.begin("##DragOverlay", True, flags)
|
||
|
||
# 绘制半透明背景
|
||
draw_list = imgui.get_window_draw_list()
|
||
draw_list.add_rect_filled(
|
||
(0, 0), viewport.work_size,
|
||
imgui.get_color_u32((0, 0, 0, 0.1))
|
||
)
|
||
|
||
# 绘制提示文本
|
||
text_size = imgui.calc_text_size("释放以导入文件")
|
||
text_pos = (
|
||
(viewport.work_size.x - text_size.x) / 2,
|
||
(viewport.work_size.y - text_size.y) / 2
|
||
)
|
||
|
||
draw_list.add_text(
|
||
text_pos,
|
||
imgui.get_color_u32((1, 1, 1, 1)),
|
||
"释放以导入文件"
|
||
)
|
||
|
||
imgui.end()
|
||
|
||
|
||
def _draw_drag_status(self):
|
||
"""绘制拖拽状态"""
|
||
viewport = imgui.get_main_viewport()
|
||
|
||
# 在右下角显示拖拽状态
|
||
imgui.set_next_window_pos(
|
||
(viewport.work_size.x - 300, viewport.work_size.y - 150),
|
||
imgui.Cond_.first_use_ever
|
||
)
|
||
|
||
flags = (
|
||
imgui.WindowFlags_.no_title_bar |
|
||
imgui.WindowFlags_.no_resize |
|
||
imgui.WindowFlags_.no_move |
|
||
imgui.WindowFlags_.no_scrollbar |
|
||
imgui.WindowFlags_.no_saved_settings
|
||
)
|
||
|
||
with imgui_ctx.begin("拖拽状态", True, flags):
|
||
imgui.text("拖拽的文件:")
|
||
for file_path in self.dragged_files:
|
||
filename = os.path.basename(file_path)
|
||
imgui.text(f" • {filename}")
|
||
|
||
imgui.separator()
|
||
|
||
if imgui.button("导入所有文件"):
|
||
self.process_dragged_files()
|
||
|
||
imgui.same_line()
|
||
if imgui.button("取消"):
|
||
self.clear_dragged_files()
|
||
|
||
|
||
def _draw_context_menus(self):
|
||
"""绘制右键菜单"""
|
||
# 节点右键菜单
|
||
if hasattr(self, '_context_menu_node') and self._context_menu_node:
|
||
imgui.open_popup("节点右键菜单")
|
||
self._context_menu_node = None
|
||
|
||
if imgui.begin_popup("节点右键菜单"):
|
||
if imgui.menu_item("删除节点", "", False, True)[1]:
|
||
if hasattr(self, '_context_menu_target') and self._context_menu_target:
|
||
self._delete_node(self._context_menu_target)
|
||
imgui.close_current_popup()
|
||
|
||
if imgui.menu_item("重命名", "", False, True)[1]:
|
||
self._renaming_node = True
|
||
imgui.close_current_popup()
|
||
|
||
imgui.separator()
|
||
|
||
if imgui.menu_item("复制", "", False, True)[1]:
|
||
if hasattr(self, '_context_menu_target') and self._context_menu_target:
|
||
self._copy_node(self._context_menu_target)
|
||
imgui.close_current_popup()
|
||
|
||
if imgui.menu_item("聚焦", "", False, True)[1]:
|
||
if hasattr(self, '_context_menu_target') and self._context_menu_target:
|
||
if hasattr(self, 'selection') and self.selection:
|
||
self.selection.updateSelection(self._context_menu_target)
|
||
self.selection.focusCameraOnSelectedNodeAdvanced()
|
||
imgui.close_current_popup()
|
||
|
||
imgui.end_popup()
|
||
|
||
# 重命名对话框
|
||
if hasattr(self, '_renaming_node') and self._renaming_node:
|
||
imgui.open_popup("重命名节点")
|
||
if not hasattr(self, '_rename_buffer'):
|
||
self._rename_buffer = ""
|
||
if hasattr(self, '_context_menu_target') and self._context_menu_target:
|
||
self._rename_buffer = self._context_menu_target.getName() or ""
|
||
|
||
if imgui.begin_popup("重命名节点"):
|
||
changed, new_name = imgui.input_text("新名称", self._rename_buffer, 256)
|
||
if changed:
|
||
self._rename_buffer = new_name
|
||
|
||
if imgui.button("确定"):
|
||
if hasattr(self, '_context_menu_target') and self._context_menu_target:
|
||
self._context_menu_target.setName(self._rename_buffer)
|
||
self._renaming_node = False
|
||
imgui.close_current_popup()
|
||
|
||
imgui.same_line()
|
||
if imgui.button("取消"):
|
||
self._renaming_node = False
|
||
imgui.close_current_popup()
|
||
|
||
imgui.end_popup()
|
||
|
||
|
||
def _delete_node_simple(self, node):
|
||
"""删除节点 - 简化版本"""
|
||
if not node or node.isEmpty():
|
||
return
|
||
|
||
# 从场景管理器中删除
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
if hasattr(self.scene_manager, 'models') and node in self.scene_manager.models:
|
||
self.scene_manager.models.remove(node)
|
||
|
||
# 从GUI管理器中删除
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
gui_element = None
|
||
if hasattr(node, 'getPythonTag'):
|
||
gui_element = node.getPythonTag('gui_element')
|
||
if gui_element and hasattr(self.gui_manager, 'gui_elements'):
|
||
if gui_element in self.gui_manager.gui_elements:
|
||
self.gui_manager.gui_elements.remove(gui_element)
|
||
|
||
# 使用主删除方法
|
||
self._delete_node(node)
|
||
|
||
# 获取节点名称(在删除之前)
|
||
node_name = node.getName() if not node.isEmpty() else '未命名节点'
|
||
|
||
# 删除节点本身
|
||
node.removeNode()
|
||
|
||
# 清除选择
|
||
if hasattr(self, 'selection') and self.selection:
|
||
if self.selection.selectedNode == node:
|
||
self.selection.clearSelection()
|
||
|
||
# 添加成功消息
|
||
self.add_success_message(f"已删除节点: {node_name}")
|
||
|
||
|
||
def _copy_node(self, node):
|
||
"""复制节点"""
|
||
if not node or node.isEmpty():
|
||
return
|
||
|
||
# 这里可以实现节点复制逻辑
|
||
# 暂时只显示消息
|
||
self.add_info_message(f"复制功能暂未实现: {node.getName() or '未命名节点'}")
|
||
|
||
# ==================== 创建功能实现 ====================
|