import posixpath import tkinter as tk import tkinter.ttk as ttk from source.packages import PackageManager from direct.showbase.ShowBase import ShowBase from panda3d.core import VirtualFileSystem, Material, WindowProperties from direct.stdpy.file import walk import simplepbr import gltf def get_icons(): return type('', (object,), { 'app': tk.PhotoImage(file="icons/application.png"), 'brick': tk.PhotoImage(file="icons/brick.png"), 'bricks': tk.PhotoImage(file="icons/bricks.png"), 'computer': tk.PhotoImage(file="icons/computer.png"), 'folder': tk.PhotoImage(file="icons/folder.png"), 'shape_group': tk.PhotoImage(file="icons/shape_group.png"), 'pictures': tk.PhotoImage(file="icons/pictures.png"), 'picture': tk.PhotoImage(file='icons/picture.png'), "page_red": tk.PhotoImage(file='icons/page_red.png'), 'shape_square': tk.PhotoImage(file='icons/shape_square.png'), 'color_wheel': tk.PhotoImage(file='icons/color_wheel.png'), 'color_swatch': tk.PhotoImage(file='icons/color_swatch.png') })() def add_package_contents_to_tree(tree, package, type, name, extensions, icon_folder, icon_group, icon_item): data_path = posixpath.join(package.mount_dir, type) tree.insert(package.mount_dir, 'end', data_path, text=f' {name}', image=icon_group) file_count = 0 for root, paths, files in walk(data_path): for path in paths: tree.insert(root, 'end', posixpath.join(root, path), text=f' {path}', image=icon_folder) for file in files: if file.lower().endswith(extensions): file_count += 1 tree.insert(root, 'end', posixpath.join(root, file), text=f' {file}', image=icon_item) tree.item(data_path, text=f' {name} ({file_count})') def add_package_models_to_tree(tree, package, icons): add_package_contents_to_tree(tree, package, 'models/', '3D Models', ('.glb', '.gltf', '.obj', '.egg'), icons.folder, icons.shape_group, icons.shape_square) def add_package_textures_to_tree(tree, package, icons): add_package_contents_to_tree(tree, package, 'textures/', 'Image Textures', ('.png', '.jpg', '.bmp'), icons.folder, icons.pictures, icons.picture) def add_package_materials_to_tree(tree, package, icons): add_package_contents_to_tree(tree, package, 'materials/', 'Materials', ('.json'), icons.folder, icons.color_wheel, icons.color_swatch) def add_package_to_tree(tree, package, icons): add_package_models_to_tree(tree, package, icons) add_package_textures_to_tree(tree, package, icons) add_package_materials_to_tree(tree, package, icons) def init_packages_tree(tree, packages, icons): tree.insert('', 'end', '/', text=' /', open=True, image=icons.app) tree.insert('/', 'end', '/main/', text=f' Main Package "{packages.main_package.meta.name}" - {packages.main_package.meta.version}', image=icons.computer) tree.insert('/', 'end', '/include/', text=f' Included Packages ({len(packages.package_list)})', image=icons.bricks) add_package_to_tree(tree, packages.main_package, icons) for package in packages.package_list: tree.insert('/include/', 'end', package.mount_dir, text=f' "{package.meta.name}" - {package.meta.version}', image=icons.brick) add_package_to_tree(tree, package, icons) return tree def init_gui(app, args): app.gui.geometry("700x500") app.gui.grid_rowconfigure(0, weight=10) app.gui.grid_rowconfigure(0, weight=1) app.gui.grid_columnconfigure(0, weight=1) package_frame = tk.Frame(app.gui, padx=4, pady=4) package_frame.grid(column=0, row=0, sticky="news") package_frame.grid_columnconfigure(0, weight=1) package_frame.grid_rowconfigure(0, weight=1) package_frame.grid_rowconfigure(1, weight=1000) packages_label = tk.Label(package_frame, text="Packages") packages_label.grid(column=0, row=0, sticky="w") packagetree_frame = tk.Frame(package_frame) packagetree_frame.grid(column=0, row=1, sticky="news") packagetree_frame.grid_columnconfigure(0, weight=1000) packagetree_frame.grid_columnconfigure(1, weight=1) packagetree_frame.grid_rowconfigure(0, weight=1) app.tree_packages = ttk.Treeview(packagetree_frame, show="tree") app.tree_packages.grid(column=0, row=0, sticky="news") packagetree_scrollbar = ttk.Scrollbar(packagetree_frame, orient="vertical", command=app.tree_packages.yview) packagetree_scrollbar.grid(column=1, row=0) app.tree_packages.bind('', app.on_packagetree_doubleclick) scene_frame = tk.Frame(app.gui, padx=4, pady=4) scene_frame.grid(column=0, row=1, sticky="news") scene_frame.grid_columnconfigure(0, weight=1) scene_frame.grid_rowconfigure(0, weight=1) scene_frame.grid_rowconfigure(1, weight=1000) scene_label = tk.Label(scene_frame, text="Scene Graph") scene_label.grid(column=0, row=0, sticky="w") scenetree_frame = tk.Frame(scene_frame) scenetree_frame.grid(column=0, row=1, sticky="news") scenetree_frame.grid_columnconfigure(0, weight=10000) scenetree_frame.grid_columnconfigure(1, weight=1) scenetree_frame.grid_rowconfigure(0, weight=1) app.tree_scene = ttk.Treeview(scenetree_frame, show="tree") app.tree_scene.grid(column=0, row=0, sticky="news") scenetree_scrollbar = ttk.Scrollbar(scenetree_frame, orient="vertical", command=app.tree_scene.yview) scenetree_scrollbar.grid(column=1, row=0) class PackageExplorer: def __init__(self, args): self.gui = tk.Tk() self.panda = ShowBase() self.package_manager = PackageManager(VirtualFileSystem.getGlobalPtr()) self.package_manager.set_main_package(args.main) if args.package: for include in args.package: self.package_manager.include_package(include) self.tree_packages = None self.tree_scene = None self.running = True simplepbr.init() gltf.patch_loader(self.panda.loader) init_gui(self, args) init_packages_tree(self.tree_packages, self.package_manager, get_icons()) self.gui.protocol("WM_DELETE_WINDOW", self.on_tk_close) def on_tk_close(self): self.running = False def on_packagetree_doubleclick(self, event): item = self.tree_packages.selection()[0] if item.lower().endswith(('.glb', '.gltf', '.obj', '.egg')): mat = Material() mat.setAmbient((1, 0, 0, 1)) node = self.panda.loader.loadModel(item) node.reparentTo(self.panda.render) node.setMaterial(mat) def loop(self): try: while self.running: self.panda.taskMgr.step() self.gui.update_idletasks() self.gui.update() except KeyboardInterrupt: return def start_explorer(args): app = PackageExplorer(args) app.loop()