EG/third_party/p3dimgui/utilities/SceneGraphExplorer.py

172 lines
5.9 KiB
Python

from panda3d.core import NodePath
from direct.showbase.DirectObject import DirectObject
from direct.interval.IntervalGlobal import Sequence, Func, Wait
from imgui_bundle import imgui, imgui_ctx
class SceneGraphExplorer(DirectObject):
def __init__(self, nodePath = None, active = True):
DirectObject.__init__(self)
self.nodePath: NodePath = nodePath
self.active = active
if not nodePath:
self.nodePath = base.render
self.__currentNodePath = self.nodePath
self.windowPos = None
self.reparentTarget: NodePath | None = None
self.flashOnClick = False
self.highlightSeq: Sequence | None = None
self.rename = ''
self.focusSetNameInput = False
self.__firstDraw = True
self.accept('imgui-new-frame', self.__draw)
def flash(self, nodePath):
if self.highlightSeq:
self.highlightSeq.finish()
colorScale = nodePath.getColorScale()
self.highlightSeq = Sequence(
Func(nodePath.setColorScale, (1.0, 0.0, 0.0, 0.0)),
Wait(1),
Func(nodePath.setColorScale, colorScale)
)
self.highlightSeq.start()
def __del__(self):
self.ignoreAll()
def __draw(self):
if not self.active:
return
id = 0
def drawTreeForNode(nodePath):
nonlocal id
flags = 0
if nodePath.getNumChildren() == 0:
flags = imgui.TreeNodeFlags_.leaf.value
elif nodePath == self.nodePath:
flags = imgui.TreeNodeFlags_.default_open.value
typeName = nodePath.node().getType().getName()
name = nodePath.getName()
tree = imgui.tree_node_ex(f"{self.nodePath.getName()}-{id}", flags, f"{typeName} {name}")
if self.flashOnClick and imgui.is_item_clicked():
self.flash(nodePath)
namePopupId = imgui.get_id(f"{nodePath}-namePopup")
if imgui.begin_popup_context_item():
clickedFlash, _ = imgui.menu_item("Flash", "", False)
if clickedFlash:
self.flash(nodePath)
imgui.separator()
clickedSetName, _ = imgui.menu_item("Set Name", "", False)
if clickedSetName:
self.rename = nodePath.getName()
self.focusSetNameInput = True
imgui.open_popup(namePopupId)
imgui.separator()
clickedSetTarget, _ = imgui.menu_item("Set Reparent Target", "", False)
if clickedSetTarget:
self.reparentTarget = nodePath
clickedReparent, _ = imgui.menu_item("Reparent to Target", "", False, self.reparentTarget is not None)
if clickedReparent:
nodePath.reparentTo(self.reparentTarget)
clickedWrtReparent, _ = imgui.menu_item("WRT Reparent To Target", "", False, self.reparentTarget is not None)
if clickedWrtReparent:
nodePath.wrtReparentTo(self.reparentTarget)
imgui.separator()
clickedPlace, _ = imgui.menu_item("Place", "", False)
if clickedPlace:
nodePath.place()
if nodePath != self.nodePath:
clickedExplore, _ = imgui.menu_item("Explore Seperately", "", False)
if clickedExplore:
nodePath.explore()
clickedDelete, _ = imgui.menu_item("Delete", "", False)
if clickedDelete:
nodePath.removeNode()
imgui.end_popup()
with imgui_ctx.begin_popup(f"{nodePath}-namePopup") as namePopup:
if namePopup:
imgui.text("Set Name:")
imgui.same_line()
if self.focusSetNameInput:
imgui.set_keyboard_focus_here()
self.focusSetNameInput = False
nameChanged, newName = imgui.input_text("##input", self.rename, imgui.InputTextFlags_.chars_no_blank.value)
if nameChanged:
self.rename = newName
if imgui.button("OK") or imgui.is_key_pressed(imgui.Key.enter):
nodePath.setName(self.rename)
self.rename = ''
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Cancel") or imgui.is_key_pressed(imgui.Key.escape):
self.rename = ''
imgui.close_current_popup()
if tree:
for child in nodePath.children:
id += 1
drawTreeForNode(child)
imgui.tree_pop()
if self.__firstDraw:
imgui.set_next_window_size((410,761))
self.__firstDraw = False
if self.windowPos and (self.nodePath != self.__currentNodePath):
imgui.set_next_window_pos(self.windowPos)
self.__currentNodePath = self.nodePath
with imgui_ctx.begin(f"Explore: {self.nodePath.getName()}", True, imgui.WindowFlags_.menu_bar) as (_, windowOpen):
if not windowOpen or not self.nodePath:
self.active = False
return
self.windowPos = imgui.get_window_pos()
with imgui_ctx.begin_menu_bar() as menuBar:
if menuBar:
with imgui_ctx.begin_menu("Options") as optionsMenu:
if optionsMenu:
clickedFlashToggle, _ = imgui.menu_item("Flash on Click", "", self.flashOnClick)
if clickedFlashToggle:
self.flashOnClick = not self.flashOnClick
imgui.text(f"Active Reparent Target: {self.reparentTarget}")
drawTreeForNode(self.nodePath)