This commit is contained in:
Rowland 2026-01-21 14:14:23 +08:00
parent 52b07aa64f
commit ae6395b88e
18 changed files with 343 additions and 456 deletions

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python3
"""
验证ImGui docking功能是否启用
"""
from imgui_bundle import imgui
# 创建一个虚拟的IO对象来检查标志
import imgui_bundle
print("检查ImGui docking支持...")
print(f"ConfigFlags_.docking_enable 存在: {hasattr(imgui.ConfigFlags_, 'docking_enable')}")
print(f"dock_space_over_viewport 存在: {hasattr(imgui, 'dock_space_over_viewport')}")
# 检查docking标志值
docking_flag = imgui.ConfigFlags_.docking_enable
print(f"Docking标志值: {docking_flag}")
# 检查窗口标志
print(f"WindowFlags_.no_title_bar 存在: {hasattr(imgui.WindowFlags_, 'no_title_bar')}")
print(f"WindowFlags_.no_collapse 存在: {hasattr(imgui.WindowFlags_, 'no_collapse')}")
print("\n✓ ImGui docking API 可用!")

View File

@ -13,7 +13,7 @@ from panda3d.core import Filename
class ImGuiStyleManager:
"""ImGui样式管理器 - 负责UI样式的统一管理"""
def __init__(self, imgui_backend):
def __init__(self, imgui_backend, world=None):
"""
初始化样式管理器
@ -21,6 +21,7 @@ class ImGuiStyleManager:
imgui_backend: ImGui后端对象
"""
self.imgui_backend = imgui_backend
self.world = world
self.io = imgui_backend.io
self.style = None # 延迟初始化在apply_style中设置
@ -60,25 +61,22 @@ class ImGuiStyleManager:
# 字体设置在demo.py中直接处理这里不再初始化
def _setup_fonts(self):
"""设置字体,包括中文字体支持"""
"""设置字体,优先确保中文正常显示"""
try:
# 尝试加载中文字体
font_path = self._get_chinese_font_path()
if font_path:
# 使用p3dimgui的字体加载方法
self.imgui_backend.load_font(font_path, self.sizes['font_size'])
print(f"✓ ImGui中文字体加载成功: {font_path}")
# 获取中文字体路径
chinese_font_path = self._get_chinese_font_path()
if chinese_font_path:
# 使用原始的字体加载方式
self._load_chinese_font_simple(chinese_font_path)
else:
print("⚠ 无法加载中文字体,使用默认字体")
print("⚠ 未找到中文字体,使用默认字体")
self._load_default_font()
except Exception as e:
print(f"⚠ ImGui字体设置失败: {e}")
# 备用方案:尝试使用默认字体
try:
# 使用p3dimgui的默认字体
self.imgui_backend.load_font(None, self.sizes['font_size'])
except:
pass
# 备用方案:使用默认字体
self._load_default_font()
def _get_chinese_font_path(self):
"""获取中文字体路径"""
@ -112,6 +110,148 @@ class ImGuiStyleManager:
return None
def _get_emoji_font_path(self):
"""获取Emoji字体路径"""
system = platform.system().lower()
# 候选Emoji字体路径
if system == "windows":
win_dir = os.environ.get("WINDIR") or r"C:\Windows"
font_candidates = [
Path(win_dir) / "Fonts" / "seguiemj.ttf", # Segoe UI Emoji
Path(win_dir) / "Fonts" / "NotoColorEmoji.ttf",
]
elif system == "darwin":
font_candidates = [
Path("/System/Library/Fonts/Apple Color Emoji.ttc"),
Path("/System/Library/Fonts/AppleColorEmoji.ttf"),
]
else: # Linux
font_candidates = [
Path("/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf"),
Path("/usr/share/fonts/opentype/noto/NotoColorEmoji.ttf"),
Path("/usr/share/fonts/truetype/emoji/Emoji.ttf"),
]
# 尝试找到存在的字体文件
for font_path in font_candidates:
if font_path.exists():
return str(font_path)
return None
def _load_merged_fonts(self, chinese_font_path, emoji_font_path):
"""合并加载中文字体和Emoji字体"""
try:
# 简化的字体加载:先确保中文正常显示
font_config = self.imgui_backend.io.fonts
# 清除现有字体
font_config.clear()
# 添加中文字体(使用默认字符范围)
chinese_font = font_config.add_font_from_file_ttf(
chinese_font_path,
self.sizes['font_size']
)
# 尝试添加Emoji字体如果支持的话
try:
font_config.merge_mode = True
font_config.add_font_from_file_ttf(
emoji_font_path,
self.sizes['font_size']
)
font_config.merge_mode = False
print(f"✓ ImGui合并字体加载成功: 中文={chinese_font_path}, Emoji={emoji_font_path}")
except Exception as emoji_error:
print(f"⚠ Emoji字体合并失败仅使用中文字体: {emoji_error}")
print(f"✓ ImGui中文字体加载成功: {chinese_font_path}")
# 构建字体图集
font_config.build()
except Exception as e:
print(f"⚠ 字体加载失败,使用备用方案: {e}")
self._load_simple_chinese_font(chinese_font_path)
def _load_font_with_emoji_range(self, font_path):
"""加载单一字体但包含Emoji字符范围"""
# 简化实现,直接调用简单字体加载
self._load_simple_chinese_font(font_path)
def _load_chinese_font_simple(self, font_path):
"""简单加载中文字体"""
try:
# 清除现有字体
self.imgui_backend.io.fonts.clear()
# 使用标准的中文字符范围
glyph_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese_full()
# 添加中文字体
self.imgui_backend.io.fonts.add_font_from_file_ttf(
font_path,
self.sizes['font_size'],
None,
glyph_ranges
)
print(f"✓ ImGui中文字体加载成功: {font_path}")
except Exception as e:
print(f"⚠ 中文字体加载失败: {e}")
self._load_default_font()
def _load_default_font(self):
"""加载默认字体"""
try:
# 清除现有字体
self.imgui_backend.io.fonts.clear()
# 添加默认字体
self.imgui_backend.io.fonts.add_font_default()
print("✓ 使用默认字体")
except Exception as e:
print(f"⚠ 默认字体加载失败: {e}")
def _get_chinese_glyph_ranges(self):
"""获取中文字符范围"""
# 基本拉丁 + 中文扩展
ranges = [
0x0020, 0x00FF, # 基本拉丁
0x2000, 0x206F, # 标点符号
0x3000, 0x30FF, # 中文符号
0xFF00, 0xFFEF, # 半角/全角
0x4E00, 0x9FAF, # CJK统一汉字
]
return ranges
def _get_emoji_glyph_ranges(self):
"""获取Emoji字符范围"""
# Emoji字符范围
ranges = [
0x1F300, 0x1F5FF, # 杂项符号和象形文字
0x1F600, 0x1F64F, # 表情符号
0x1F680, 0x1F6FF, # 交通和地图符号
0x1F700, 0x1F77F, # 炼金术符号
0x1F780, 0x1F7FF, # 几何形状扩展
0x1F800, 0x1F8FF, # 补充箭头-C
0x1F900, 0x1F9FF, # 补充符号和象形文字
0x2600, 0x26FF, # 杂项符号
0x2700, 0x27BF, # 装饰符号
]
return ranges
def _get_combined_glyph_ranges(self):
"""获取合并的字符范围(中文+Emoji"""
# 合并所有字符范围
chinese_ranges = self._get_chinese_glyph_ranges()
emoji_ranges = self._get_emoji_glyph_ranges()
# 将两个范围合并
combined = chinese_ranges + emoji_ranges
return combined
def apply_style(self):
"""应用与Qt UI一致的样式"""
# 先应用深色主题作为基础
@ -253,14 +393,19 @@ class ImGuiStyleManager:
return changed, new_value
def load_icon(self, icon_name):
"""加载图标纹理"""
"""加载图标纹理为ImGui可用的格式"""
try:
# 构建图标路径
project_root = Path(__file__).resolve().parent.parent
icon_path = project_root / "icons" / f"{icon_name}.png"
if icon_path.exists():
return self.imgui_backend.loadTexture(str(icon_path))
# 使用base.imgui.loadTexture方法
if hasattr(base, 'imgui') and hasattr(base.imgui, 'loadTexture'):
return base.imgui.loadTexture(str(icon_path))
else:
print(f"⚠ ImGui后端未初始化")
return None
else:
print(f"⚠ 图标文件不存在: {icon_path}")
return None

View File

@ -54,99 +54,93 @@ class ResourceManager:
# 文件图标映射Unicode Emoji
self._init_icon_map()
def _init_icon_map(self):
"""初始化文件图标映射"""
"""初始化文件图标映射使用PNG图标文件"""
self.icon_map = {
# 编程语言文件
'.py': '🐍', # Python文件
'.js': '', # JavaScript文件
'.ts': '', # TypeScript文件
'.html': '🌐', # HTML文件
'.css': '🎨', # CSS文件
'.json': '📋', # JSON文件
'.xml': '📄', # XML文件
'.yaml': '📄', # YAML文件
'.yml': '📄', # YAML文件
'.md': '📝', # Markdown文档
# 3D模型文件
'.fbx': '🎭', # FBX模型文件
'.obj': '🎭', # OBJ模型文件
'.gltf': '🎭', # glTF模型
'.glb': '🎭', # glTF二进制模型
'.bam': '🎭', # BAM模型文件
'.egg': '🎭', # EGG模型文件
'.dae': '🎭', # Collada模型
'.3ds': '🎭', # 3DS模型
'.blend': '🎭', # Blender文件
'.fbx': 'model', # FBX模型文件
'.obj': 'model', # OBJ模型文件
'.gltf': 'model', # glTF模型
'.glb': 'model', # glTF二进制模型
'.bam': 'model', # BAM模型文件
# 图像文件
'.jpg': '🖼️', # JPEG图像
'.jpeg': '🖼️', # JPEG图像
'.png': '🖼️', # PNG图像
'.gif': '🖼️', # GIF图像
'.bmp': '🖼️', # BMP图像
'.tga': '🖼️', # TGA图像
'.tiff': '🖼️', # TIFF图像
'.webp': '🖼️', # WebP图像
'.svg': '🖼️', # SVG图像
'.ico': '🖼️', # ICO图标
'.jpg': 'image', # JPEG图像
'.jpeg': 'image', # JPEG图像
'.png': 'image', # PNG图像
'.bmp': 'image', # BMP图像
'.tga': 'image', # TGA图像
'.tif': 'image', # TIFF图像
'.tiff': 'image', # TIFF图像
'.hdr': 'image', # HDR图像
'.exr': 'image', # EXR图像
# 音频文件
'.mp3': '🎵', # MP3音频
'.wav': '🎵', # WAV音频
'.ogg': '🎵', # OGG音频
'.flac': '🎵', # FLAC音频
'.m4a': '🎵', # M4A音频
'.mp3': 'audio', # MP3音频
'.wav': 'audio', # WAV音频
'.ogg': 'audio', # OGG音频
'.flac': 'audio', # FLAC音频
# 视频文件
'.mp4': '🎬', # MP4视频
'.avi': '🎬', # AVI视频
'.mkv': '🎬', # MKV视频
'.mov': '🎬', # MOV视频
'.wmv': '🎬', # WMV视频
'.flv': '🎬', # FLV视频
'.mp4': 'video', # MP4视频
'.avi': 'video', # AVI视频
'.mov': 'video', # MOV视频
'.mkv': 'video', # MKV视频
# 文档文件
'.txt': '📄', # 纯文本文件
'.pdf': '📕', # PDF文档
'.doc': '📘', # Word文档
'.docx': '📘', # Word文档
'.xls': '📗', # Excel表格
'.xlsx': '📗', # Excel表格
'.ppt': '📙', # PowerPoint演示
'.pptx': '📙', # PowerPoint演示
'.txt': 'document', # 文本文件
'.md': 'document', # Markdown文件
'.pdf': 'document', # PDF文件
'.doc': 'document', # Word文档
'.docx': 'document', # Word文档
'.rtf': 'document', # RTF文档
# 压缩文件
'.zip': '📦', # ZIP压缩包
'.rar': '📦', # RAR压缩包
'.7z': '📦', # 7Z压缩包
'.tar': '📦', # TAR压缩包
'.gz': '📦', # GZ压缩包
# 代码文件
'.py': 'python', # Python文件
'.js': 'code', # JavaScript文件
'.ts': 'code', # TypeScript文件
'.cpp': 'code', # C++文件
'.c': 'code', # C文件
'.h': 'code', # 头文件
'.java': 'code', # Java文件
'.cs': 'code', # C#文件
'.html': 'code', # HTML文件
'.css': 'code', # CSS文件
'.xml': 'code', # XML文件
'.json': 'config', # JSON文件
'.yaml': 'config', # YAML文件
'.yml': 'config', # YAML文件
# 配置文件
'.ini': '⚙️', # INI配置文件
'.cfg': '⚙️', # CFG配置文件
'.conf': '⚙️', # CONF配置文件
'.toml': '⚙️', # TOML配置文件
'.ini': 'config', # 配置文件
'.cfg': 'config', # 配置文件
'.conf': 'config', # 配置文件
'.toml': 'config', # 配置文件
# 压缩文件
'.zip': 'archive', # ZIP压缩包
'.rar': 'archive', # RAR压缩包
'.7z': 'archive', # 7Z压缩包
'.tar': 'archive', # TAR压缩包
'.gz': 'archive', # GZ压缩包
# 字体文件
'.ttf': '🔤', # TrueType字体
'.otf': '🔤', # OpenType字体
'.woff': '🔤', # WOFF字体
'.woff2': '🔤', # WOFF2字体
'.ttf': 'font', # TrueType字体
'.otf': 'font', # OpenType字体
'.woff': 'font', # WOFF字体
'.woff2': 'font', # WOFF2字体
# 文件夹图标
'folder': 'folder', # 文件夹图标
'folder_open': 'folder', # 打开的文件夹图标
# 默认图标
'default': '📄', # 默认文件图标
'folder': '📁', # 文件夹图标
'folder_open': '📂', # 打开的文件夹图标
'drive': '💾', # 驱动器图标
'home': '🏠', # 主目录图标
'default': 'file', # 默认文件图标
}
def get_file_icon(self, filename: str, is_folder: bool = False) -> str:
"""根据文件名获取图标"""
"""根据文件名获取图标名称"""
if is_folder:
return self.icon_map['folder']

207
demo.py
View File

@ -15,6 +15,7 @@ import os
import warnings
import threading
import time
from pathlib import Path
# 导入MyWorld类和必要的模块
from core.world import CoreWorld
@ -192,66 +193,46 @@ class MyWorld(CoreWorld):
# 初始化样式管理器
from core.imgui_style_manager import ImGuiStyleManager
self.style_manager = ImGuiStyleManager(self.imgui)
self.style_manager = ImGuiStyleManager(self.imgui, self)
# 尝试直接设置中文字体
# 简化的初始化字体设置(只使用中文字体)
try:
# 先清除默认字体
self.imgui.io.fonts.clear()
# 尝试加载中文字体
import platform
from pathlib import Path
# 获取中文字体路径
system = platform.system().lower()
if system == "linux":
font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
font_path = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
elif system == "windows":
font_path = "C:/Windows/Fonts/msyh.ttc"
elif system == "darwin":
font_path = "/System/Library/Fonts/PingFang.ttc"
else:
font_path = None
if font_path and Path(font_path).exists():
# 先清除默认字体
self.imgui.io.fonts.clear()
# 创建中文字符范围(基本中文字符)
# 这个范围包含了常用中文字符的Unicode范围
chinese_ranges = []
# 基本拉丁字母
for i in range(0x0020, 0x00FF):
chinese_ranges.append(i)
# 中文字符范围
for i in range(0x4E00, 0x9FFF): # CJK统一汉字
chinese_ranges.append(i)
for i in range(0x3400, 0x4DBF): # CJK扩展A
chinese_ranges.append(i)
for i in range(0x20000, 0x2A6DF): # CJK扩展B
chinese_ranges.append(i)
for i in range(0x2A700, 0x2B73F): # CJK扩展C
chinese_ranges.append(i)
for i in range(0x2B740, 0x2B81F): # CJK扩展D
chinese_ranges.append(i)
for i in range(0x2B820, 0x2CEAF): # CJK扩展E
chinese_ranges.append(i)
for i in range(0x2CEB0, 0x2EBEF): # CJK扩展F
chinese_ranges.append(i)
for i in range(0x3000, 0x303F): # CJK符号和标点
chinese_ranges.append(i)
for i in range(0xFF00, 0xFFEF): # 全角字符
chinese_ranges.append(i)
# 添加中文字体不指定字符范围让ImGui自动处理
font = self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
print(f"✓ 直接设置中文字体成功: {font_path}")
print(f" 使用自动字符范围")
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
print(f"✓ 初始化中文字体成功: {font_path}")
else:
print("⚠ 中文字体文件不存在")
# 回退到原来的字体
fallback_font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
if fallback_font_path and Path(fallback_font_path).exists():
self.imgui.io.fonts.add_font_from_file_ttf(fallback_font_path, 14.0)
print(f"✓ 初始化回退字体成功: {fallback_font_path}")
else:
self.imgui.io.fonts.add_font_default()
print("✓ 初始化使用默认字体")
except Exception as e:
print(f"⚠ 直接设置中文字体失败: {e}")
print(f"⚠ 初始化字体系统失败: {e}")
# 备用方案:使用默认字体
try:
self.imgui.io.fonts.add_font_default()
print("✓ 使用默认字体")
print("✓ 使用备用默认字体")
except:
pass
@ -485,34 +466,45 @@ class MyWorld(CoreWorld):
'delete_fail_icon': self.style_manager.load_icon('delete_fail_icon'),
}
# 确保中文字体被正确应用
# 简化字体加载(只使用中文字体)
try:
# 强制刷新字体
# 清除现有字体
self.imgui.io.fonts.clear()
# 重新添加中文字体
# 尝试加载中文字体
import platform
from pathlib import Path
system = platform.system().lower()
if system == "linux":
font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
font_path = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
elif system == "windows":
font_path = "C:/Windows/Fonts/msyh.ttc"
elif system == "darwin":
font_path = "/System/Library/Fonts/PingFang.ttc"
else:
font_path = None
if font_path and Path(font_path).exists():
# 添加中文字体,包含中文字符集
try:
chinese_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese_full()
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0, None, chinese_ranges)
print("✓ 第一帧重新设置中文字体(包含中文字符集)")
except:
# 如果获取字符集失败,使用简单方式
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
print("✓ 第一帧重新设置中文字体(简单方式)")
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
print(f"✓ 中文字体加载成功: {font_path}")
else:
# 回退到原来的字体
fallback_font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
if fallback_font_path and Path(fallback_font_path).exists():
self.imgui.io.fonts.add_font_from_file_ttf(fallback_font_path, 14.0)
print(f"✓ 回退字体加载成功: {fallback_font_path}")
else:
self.imgui.io.fonts.add_font_default()
print("✓ 使用默认字体")
except Exception as e:
print(f"⚠ 第一帧设置中文字体失败: {e}")
print(f"⚠ 字体初始化失败: {e}")
try:
self.imgui.io.fonts.add_font_default()
print("✓ 使用备用默认字体")
except:
pass
# 获取窗口尺寸
display_size = imgui.get_io().display_size
@ -780,10 +772,10 @@ class MyWorld(CoreWorld):
if imgui.button(""):
rm.navigate_up()
imgui.same_line()
if imgui.button("🏠"):
if imgui.button("主页"):
rm.navigate_to(rm.project_root / "Resources")
imgui.same_line()
if imgui.button("🔄"):
if imgui.button("刷新"):
rm.force_refresh()
# 自动刷新开关
@ -823,7 +815,7 @@ class MyWorld(CoreWorld):
continue
# 目录图标和名称
icon = rm.get_file_icon(dir_path.name, is_folder=True)
icon_name = rm.get_file_icon(dir_path.name, is_folder=True)
node_open = False
# 检查是否被选中
@ -831,9 +823,24 @@ class MyWorld(CoreWorld):
# 使用TreeNode来显示目录
if is_selected:
imgui.push_style_color(imgui.Col_.header, imgui.get_style().colors[imgui.Col_.header_hovered])
imgui.push_style_color(imgui.Col_.header, imgui.IM_COL32(100, 150, 200, 255))
node_open = imgui.tree_node(f"{icon} {dir_path.name}")
# 尝试加载PNG图标
icon_texture = None
try:
# 直接使用图标名称load_icon会自动添加.png
icon_texture = self.style_manager.load_icon(f"file_types/{icon_name}")
except:
pass
if icon_texture:
# 使用PNG图标
imgui.image(icon_texture, (16, 16))
imgui.same_line()
node_open = imgui.tree_node(f"{dir_path.name}")
else:
# 回退到文本标识符
node_open = imgui.tree_node(f"[{icon_name.upper()}]{dir_path.name}")
if is_selected:
imgui.pop_style_color()
@ -872,13 +879,29 @@ class MyWorld(CoreWorld):
if not rm.should_show_file(subdir):
continue
subicon = rm.get_file_icon(subdir.name, is_folder=True)
# 初始化变量
subicon_name = "folder"
sub_is_selected = False
# 获取子目录图标名称
subicon_name = rm.get_file_icon(subdir.name, is_folder=True)
sub_is_selected = subdir in rm.selected_files
if sub_is_selected:
imgui.push_style_color(imgui.Col_.header, imgui.get_style().colors[imgui.Col_.header_hovered])
# 尝试加载PNG图标
subicon_texture = None
try:
subicon_texture = self.style_manager.load_icon(f"file_types/{subicon_name}")
except:
pass
sub_node_open = imgui.tree_node(f" {subicon} {subdir.name}")
if subicon_texture:
# 使用PNG图标
imgui.image(subicon_texture, (16, 16))
imgui.same_line()
sub_node_open = imgui.tree_node(f" {subdir.name}")
else:
# 回退到文本标识符
sub_node_open = imgui.tree_node(f" [{subicon_name.upper()}]{subdir.name}")
if sub_is_selected:
imgui.pop_style_color()
@ -913,10 +936,24 @@ class MyWorld(CoreWorld):
if not rm.should_show_file(subfile):
continue
subicon = rm.get_file_icon(subfile.name)
subicon_name = rm.get_file_icon(subfile.name)
sub_is_selected = subfile in rm.selected_files
selected = imgui.selectable(f" {subicon} {subfile.name}", sub_is_selected)
# 尝试加载PNG图标
subicon_texture = None
try:
subicon_texture = self.style_manager.load_icon(f"file_types/{subicon_name}")
except:
pass
if subicon_texture:
# 使用PNG图标
imgui.image(subicon_texture, (16, 16))
imgui.same_line()
selected = imgui.selectable(f" {subfile.name}", sub_is_selected)
else:
# 回退到文本标识符
selected = imgui.selectable(f" [{subicon_name.upper()}] {subfile.name}", sub_is_selected)
# 处理子文件的选择
if selected:
@ -944,41 +981,11 @@ class MyWorld(CoreWorld):
rm.context_menu_file = subfile
rm.context_menu_position = (imgui.get_mouse_pos().x, imgui.get_mouse_pos().y)
imgui.tree_pop()
# 只有在节点展开时才调用tree_pop
if node_open:
imgui.tree_pop()
# 显示文件
for file_path in files:
if not rm.should_show_file(file_path):
continue
# 文件图标和名称
icon = rm.get_file_icon(file_path.name)
file_size = rm.get_file_size_string(file_path)
# 检查是否被选中
is_selected = file_path in rm.selected_files
# 使用Selectable来显示文件
selected = imgui.selectable(f"{icon} {file_path.name}", is_selected)
# 显示文件大小
if file_size:
imgui.same_line()
imgui.text_disabled(file_size)
# 处理选择
if selected:
if imgui.get_io().key_ctrl:
# 多选模式
if is_selected:
rm.selected_files.discard(file_path)
else:
rm.selected_files.add(file_path)
else:
# 单选模式
rm.selected_files.clear()
rm.selected_files.add(file_path)
rm.focused_file = file_path
# 处理拖拽开始
if imgui.is_item_active() and imgui.is_item_hovered():

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

BIN
icons/file_types/audio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

BIN
icons/file_types/code.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

BIN
icons/file_types/config.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

BIN
icons/file_types/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

BIN
icons/file_types/folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

BIN
icons/file_types/font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

BIN
icons/file_types/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

BIN
icons/file_types/model.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

BIN
icons/file_types/python.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

BIN
icons/file_types/video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

View File

@ -31,7 +31,7 @@ DockId=0x00000007,0
[Window][场景树]
Pos=0,20
Size=285,753
Size=285,739
Collapsed=0
DockId=0x00000001,0
@ -42,8 +42,8 @@ Collapsed=0
DockId=0x00000005,0
[Window][控制台]
Pos=880,775
Size=644,241
Pos=880,761
Size=644,255
Collapsed=0
DockId=0x0000000C,0
@ -99,20 +99,20 @@ Size=600,500
Collapsed=0
[Window][资源管理器]
Pos=0,775
Size=878,241
Pos=0,761
Size=878,255
Collapsed=0
DockId=0x0000000B,0
[Docking][Data]
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1850,996 Split=X
DockNode ID=0x00000003 Parent=0x08BD597D SizeRef=1524,996 Split=Y
DockNode ID=0x00000009 Parent=0x00000003 SizeRef=1380,753 Split=X
DockNode ID=0x00000009 Parent=0x00000003 SizeRef=1380,739 Split=X
DockNode ID=0x00000001 Parent=0x00000009 SizeRef=285,730 HiddenTabBar=1 Selected=0xE0015051
DockNode ID=0x00000002 Parent=0x00000009 SizeRef=1237,730 Split=Y
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=1380,32 HiddenTabBar=1 Selected=0x43A39006
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=1380,719 CentralNode=1 Selected=0x5E5F7166
DockNode ID=0x0000000A Parent=0x00000003 SizeRef=1380,241 Split=X Selected=0x5428E753
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=1380,705 CentralNode=1 Selected=0x5E5F7166
DockNode ID=0x0000000A Parent=0x00000003 SizeRef=1380,255 Split=X Selected=0x5428E753
DockNode ID=0x0000000B Parent=0x0000000A SizeRef=878,111 HiddenTabBar=1 Selected=0x3A2E05C3
DockNode ID=0x0000000C Parent=0x0000000A SizeRef=644,111 HiddenTabBar=1 Selected=0x5428E753
DockNode ID=0x00000004 Parent=0x08BD597D SizeRef=324,996 Split=Y Selected=0x5DB6FF37

View File

@ -1,238 +0,0 @@
#!/usr/bin/env python3
"""
简单的拖拽导入工具
直接运行此工具然后将3D文件拖拽到窗口中
工具会生成可在demo.py中使用的导入命令
"""
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import os
import sys
class SimpleDragDrop:
def __init__(self):
self.root = tk.Tk()
self.root.title("3D模型拖拽导入工具")
self.root.geometry("600x400")
# 设置窗口始终在最前面
self.root.attributes('-topmost', True)
# 支持的文件格式
self.supported_formats = ['.gltf', '.glb', '.fbx', '.bam', '.egg', '.obj']
self.setup_ui()
self.setup_drag_drop()
def setup_ui(self):
"""设置用户界面"""
# 主框架
main_frame = tk.Frame(self.root)
main_frame.pack(fill='both', expand=True, padx=10, pady=10)
# 标题
title_label = tk.Label(
main_frame,
text="将3D模型文件拖拽到此处",
font=('Arial', 16, 'bold')
)
title_label.pack(pady=(0, 10))
# 拖拽区域
self.drop_area = tk.Frame(
main_frame,
bg='lightgray',
relief='sunken',
bd=2,
height=150
)
self.drop_area.pack(fill='both', expand=True, pady=(0, 10))
# 提示文本
hint_label = tk.Label(
self.drop_area,
text="支持格式: .gltf, .glb, .fbx, .bam, .egg, .obj\n\n拖拽文件到此处或点击下方按钮选择文件",
bg='lightgray',
font=('Arial', 11)
)
hint_label.pack(expand=True)
# 按钮框架
button_frame = tk.Frame(main_frame)
button_frame.pack(fill='x', pady=(0, 10))
# 选择文件按钮
select_btn = tk.Button(
button_frame,
text="选择文件",
command=self.select_files,
width=15
)
select_btn.pack(side='left', padx=5)
# 清空按钮
clear_btn = tk.Button(
button_frame,
text="清空",
command=self.clear_files,
width=15
)
clear_btn.pack(side='left', padx=5)
# 生成命令按钮
generate_btn = tk.Button(
button_frame,
text="生成导入命令",
command=self.generate_commands,
bg='lightblue',
font=('Arial', 10, 'bold'),
width=15
)
generate_btn.pack(side='right', padx=5)
# 文件列表
list_label = tk.Label(
main_frame,
text="文件列表:",
font=('Arial', 10, 'bold')
)
list_label.pack(anchor='w', pady=(0, 5))
# 文件列表框
self.file_listbox = tk.Listbox(
main_frame,
height=8,
selectmode=tk.MULTIPLE
)
self.file_listbox.pack(fill='both', expand=True, pady=(0, 10))
# 命令输出区域
output_label = tk.Label(
main_frame,
text="导入命令:",
font=('Arial', 10, 'bold')
)
output_label.pack(anchor='w', pady=(0, 5))
self.command_text = scrolledtext.ScrolledText(
main_frame,
height=6,
width=70
)
self.command_text.pack(fill='both', expand=True)
def setup_drag_drop(self):
"""设置拖拽功能"""
try:
# 设置拖拽目标
self.drop_area.drop_target_register('DND_Files')
self.drop_area.dnd_bind('<<Drop>>', self.on_drop)
self.drop_area.dnd_bind('<<DragEnter>>', self.on_drag_enter)
self.drop_area.dnd_bind('<<DragLeave>>', self.on_drag_leave)
except:
# 如果拖拽不支持,只使用文件选择器
print("拖拽功能不可用,请使用文件选择器")
def on_drag_enter(self, event):
"""拖拽进入事件"""
self.drop_area.configure(bg='lightblue')
def on_drag_leave(self, event):
"""拖拽离开事件"""
self.drop_area.configure(bg='lightgray')
def on_drop(self, event):
"""拖拽释放事件"""
try:
self.drop_area.configure(bg='lightgray')
# 获取拖拽的文件
files = self.root.tk.splitlist(event.data)
for file_path in files:
self.add_file(file_path)
except Exception as e:
messagebox.showerror("错误", f"拖拽处理失败: {e}")
def add_file(self, file_path):
"""添加文件到列表"""
if os.path.exists(file_path):
file_ext = os.path.splitext(file_path)[1].lower()
if file_ext in self.supported_formats:
if file_path not in self.file_listbox.get(0, tk.END):
self.file_listbox.insert(tk.END, file_path)
else:
messagebox.showwarning("格式错误", f"不支持的文件格式: {file_ext}")
else:
messagebox.showerror("文件错误", f"文件不存在: {file_path}")
def select_files(self):
"""选择文件"""
files = filedialog.askopenfilenames(
title="选择3D模型文件",
filetypes=[
("所有支持的格式", "*.gltf *.glb *.fbx *.bam *.egg *.obj"),
("glTF文件", "*.gltf *.glb"),
("FBX文件", "*.fbx"),
("BAM文件", "*.bam"),
("EGG文件", "*.egg"),
("OBJ文件", "*.obj"),
("所有文件", "*.*")
]
)
for file_path in files:
self.add_file(file_path)
def clear_files(self):
"""清空文件列表"""
self.file_listbox.delete(0, tk.END)
self.command_text.delete(1.0, tk.END)
def generate_commands(self):
"""生成导入命令"""
files = list(self.file_listbox.get(0, tk.END))
if not files:
messagebox.showwarning("没有文件", "请先选择或拖拽文件")
return
# 生成Python导入代码
commands = "# 在demo.py的控制台中执行以下命令来导入文件:\n\n"
for i, file_path in enumerate(files, 1):
filename = os.path.basename(file_path)
commands += f"# 导入文件 {i}: {filename}\n"
commands += f"world._import_model_from_path('{file_path}')\n\n"
commands += "# 或者使用批量导入:\n"
commands += "files = [\n"
for file_path in files:
commands += f" '{file_path}',\n"
commands += "]\n"
commands += "for file_path in files:\n"
commands += " world._import_model_from_path(file_path)\n"
# 显示命令
self.command_text.delete(1.0, tk.END)
self.command_text.insert(1.0, commands)
messagebox.showinfo("完成", "导入命令已生成请复制到demo.py控制台中执行")
def run(self):
"""运行应用"""
self.root.mainloop()
def main():
"""主函数"""
try:
app = SimpleDragDrop()
app.run()
except Exception as e:
print(f"启动拖拽工具失败: {e}")
input("按回车键退出...")
if __name__ == "__main__":
main()