diff --git a/check_docking.py b/check_docking.py deleted file mode 100644 index 3078b445..00000000 --- a/check_docking.py +++ /dev/null @@ -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 可用!") \ No newline at end of file diff --git a/core/imgui_style_manager.py b/core/imgui_style_manager.py index ed1b643e..e9aee657 100644 --- a/core/imgui_style_manager.py +++ b/core/imgui_style_manager.py @@ -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 diff --git a/core/resource_manager.py b/core/resource_manager.py index 46931884..f6c4c32b 100644 --- a/core/resource_manager.py +++ b/core/resource_manager.py @@ -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'] diff --git a/demo.py b/demo.py index afad7a74..17ce5ed1 100644 --- a/demo.py +++ b/demo.py @@ -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(): diff --git a/icons/file_types/archive.png b/icons/file_types/archive.png new file mode 100644 index 00000000..2371475f Binary files /dev/null and b/icons/file_types/archive.png differ diff --git a/icons/file_types/audio.png b/icons/file_types/audio.png new file mode 100644 index 00000000..3f74196b Binary files /dev/null and b/icons/file_types/audio.png differ diff --git a/icons/file_types/code.png b/icons/file_types/code.png new file mode 100644 index 00000000..eee951ae Binary files /dev/null and b/icons/file_types/code.png differ diff --git a/icons/file_types/config.png b/icons/file_types/config.png new file mode 100644 index 00000000..45d7c2d3 Binary files /dev/null and b/icons/file_types/config.png differ diff --git a/icons/file_types/document.png b/icons/file_types/document.png new file mode 100644 index 00000000..8fc8fff7 Binary files /dev/null and b/icons/file_types/document.png differ diff --git a/icons/file_types/file.png b/icons/file_types/file.png new file mode 100644 index 00000000..00ceb8ac Binary files /dev/null and b/icons/file_types/file.png differ diff --git a/icons/file_types/folder.png b/icons/file_types/folder.png new file mode 100644 index 00000000..b732e244 Binary files /dev/null and b/icons/file_types/folder.png differ diff --git a/icons/file_types/font.png b/icons/file_types/font.png new file mode 100644 index 00000000..8cd03ec9 Binary files /dev/null and b/icons/file_types/font.png differ diff --git a/icons/file_types/image.png b/icons/file_types/image.png new file mode 100644 index 00000000..455a25e5 Binary files /dev/null and b/icons/file_types/image.png differ diff --git a/icons/file_types/model.png b/icons/file_types/model.png new file mode 100644 index 00000000..aceafb5c Binary files /dev/null and b/icons/file_types/model.png differ diff --git a/icons/file_types/python.png b/icons/file_types/python.png new file mode 100644 index 00000000..2b6d8348 Binary files /dev/null and b/icons/file_types/python.png differ diff --git a/icons/file_types/video.png b/icons/file_types/video.png new file mode 100644 index 00000000..386c419b Binary files /dev/null and b/icons/file_types/video.png differ diff --git a/imgui.ini b/imgui.ini index 0b653654..8c491380 100644 --- a/imgui.ini +++ b/imgui.ini @@ -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 diff --git a/simple_drag_drop.py b/simple_drag_drop.py deleted file mode 100644 index 848279eb..00000000 --- a/simple_drag_drop.py +++ /dev/null @@ -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('<>', self.on_drop) - self.drop_area.dnd_bind('<>', self.on_drag_enter) - self.drop_area.dnd_bind('<>', 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() \ No newline at end of file