172 lines
5.9 KiB
Python
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)
|
|
|
|
|
|
|
|
|
|
|
|
|