open_toontown_panda3d/direct/src/leveleditor/LevelEditorUIBase.py

696 lines
28 KiB
Python
Executable File

import wx
import os
## from wx.lib.agw import fourwaysplitter as FWS
from panda3d.core import BitMask32, Mat4, NodePath, Vec3
from direct.wxwidgets.WxPandaShell import WxPandaShell
from direct.wxwidgets.WxSlider import WxSlider
from direct.directtools.DirectSelection import SelectionRay
from direct.showbase.MessengerGlobal import messenger
#from ViewPort import *
from . import ObjectGlobals as OG
from .ObjectPaletteUI import ObjectPaletteUI
from .ObjectPropertyUI import ObjectPropertyUI
from .SceneGraphUI import SceneGraphUI
from .LayerEditorUI import LayerEditorUI
from .HotKeyUI import HotKeyUI
from .ProtoPaletteUI import ProtoPaletteUI
from .ActionMgr import ActionAddNewObj, ActionTransformObj
from .AnimControlUI import AnimControlUI
from .CurveAnimUI import CurveAnimUI
from .GraphEditorUI import GraphEditorUI
class PandaTextDropTarget(wx.TextDropTarget):
def __init__(self, editor, view):
wx.TextDropTarget.__init__(self)
self.editor = editor
self.view = view
def OnDropText(self, x, y, text):
# create new object
parentNPRef = [None]
if not self.editor.propMeetsReq(text, parentNPRef):
return
action = ActionAddNewObj(self.editor, text, parent=parentNPRef[0])
self.editor.actionMgr.push(action)
newobj = action()
print(newobj)
if newobj is None:
return
# change window coordinate to mouse coordinate
mx = 2 * (x/float(self.view.ClientSize.GetWidth()) - 0.5)
my = -2 * (y/float(self.view.ClientSize.GetHeight()) - 0.5)
# create ray from the camera to detect 3d position
iRay = SelectionRay(self.view.camera)
iRay.collider.setFromLens(self.view.camNode, mx, my)
hitPt = None
if self.editor.objectMgr.currLiveNP:
iRay.collideWithGeom()
iRay.ct.traverse(self.editor.objectMgr.currLiveNP)
def isEntryBackfacing(iRay, entry):
if not entry.hasSurfaceNormal():
# Well, no way to tell. Assume we're not backfacing.
return 0
fromNodePath = entry.getFromNodePath()
v = Vec3(entry.getSurfacePoint(fromNodePath))
n = entry.getSurfaceNormal(fromNodePath)
# Convert to camera space for backfacing test
p2cam = iRay.collisionNodePath.getParent().getMat(self.view.camera)
v = Vec3(p2cam.xformPoint(v))
n = p2cam.xformVec(n)
# Normalize and check angle between to vectors
v.normalize()
return v.dot(n) >= 0
iRay.sortEntries()
for entry in iRay.getEntries():
if isEntryBackfacing(iRay, entry):
pass
else:
hitPt = entry.getSurfacePoint(entry.getFromNodePath())
break
if hitPt is None:
iRay.collideWithBitMask(BitMask32.bit(21))
iRay.ct.traverse(self.view.collPlane)
if iRay.getNumEntries() > 0:
entry = iRay.getEntry(0)
hitPt = entry.getSurfacePoint(entry.getFromNodePath())
if hitPt:
# create a temp nodePath to get the position
np = NodePath('temp')
np.setPos(self.view.camera, hitPt)
if base.direct.manipulationControl.fGridSnap:
snappedPos = self.view.grid.computeSnapPoint(np.getPos())
np.setPos(snappedPos)
# update temp nodePath's HPR and scale with newobj's
np.setHpr(newobj.getHpr())
np.setScale(newobj.getScale())
# transform newobj to cursor position
obj = self.editor.objectMgr.findObjectByNodePath(newobj)
action = ActionTransformObj(self.editor, obj[OG.OBJ_UID], Mat4(np.getMat()))
self.editor.actionMgr.push(action)
np.remove()
action()
iRay.collisionNodePath.removeNode()
del iRay
ID_NEW = 101
ID_OPEN = 102
ID_SAVE = 103
ID_SAVE_AS = 104
ID_EXPORT_TO_MAYA = 105
ID_DUPLICATE = 201
ID_MAKE_LIVE = 202
ID_UNDO = 203
ID_REDO = 204
ID_SHOW_GRID = 301
ID_GRID_SIZE = 302
ID_GRID_SNAP = 303
ID_SHOW_PANDA_OBJECT = 304
ID_HOT_KEYS = 305
ID_PARENT_TO_SELECTED = 306
ID_CREATE_CURVE = 601
ID_EDIT_CURVE = 602
ID_CURVE_ANIM = 603
ID_ANIM = 701
ID_GRAPH = 702
class LevelEditorUIBase(WxPandaShell):
""" Class for Panda3D LevelEditor """
def __init__(self, editor):
self.MENU_TEXTS.update({
ID_NEW : ("&New", "LE-NewScene"),
ID_OPEN : ("&Open", "LE-OpenScene"),
ID_SAVE : ("&Save", "LE-SaveScene"),
ID_SAVE_AS : ("Save &As", None),
ID_EXPORT_TO_MAYA : ("Export to Maya", None),
wx.ID_EXIT : ("&Quit", "LE-Quit"),
ID_DUPLICATE : ("&Duplicate", "LE-Duplicate"),
ID_MAKE_LIVE : ("Make &Live", "LE-MakeLive"),
ID_UNDO : ("&Undo", "LE-Undo"),
ID_REDO : ("&Redo", "LE-Redo"),
ID_SHOW_GRID : ("&Show Grid", None),
ID_GRID_SIZE : ("&Grid Size", None),
ID_GRID_SNAP : ("Grid S&nap", None),
ID_SHOW_PANDA_OBJECT : ("Show &Panda Objects", None),
ID_HOT_KEYS : ("&Hot Keys", None),
ID_PARENT_TO_SELECTED : ("&Parent To Selected", None),
ID_CREATE_CURVE : ("&Create Curve", None),
ID_EDIT_CURVE : ("&Edit Curve", None),
ID_CURVE_ANIM : ("&Curve Animation", None),
ID_ANIM : ("&Edit Animation", None),
ID_GRAPH : ("&Graph Editor", None)
})
self.editor = editor
WxPandaShell.__init__(self, fStartDirect=True)
self.contextMenu = ViewportMenu()
self.bindKeyEvents(True)
def bindKeyEvents(self, toBind=True):
if toBind:
self.wxApp.Bind(wx.EVT_CHAR, self.onKeyEvent)
self.wxApp.Bind(wx.EVT_KEY_DOWN, self.onKeyDownEvent)
self.wxApp.Bind(wx.EVT_KEY_UP, self.onKeyUpEvent)
else:
self.wxApp.Unbind(wx.EVT_CHAR)
self.wxApp.Unbind(wx.EVT_KEY_DOWN)
self.wxApp.Unbind(wx.EVT_KEY_UP)
def createMenu(self):
menuItem = self.menuFile.Insert(0, ID_NEW, self.MENU_TEXTS[ID_NEW][0])
self.Bind(wx.EVT_MENU, self.onNew, menuItem)
menuItem = self.menuFile.Insert(1, ID_OPEN, self.MENU_TEXTS[ID_OPEN][0])
self.Bind(wx.EVT_MENU, self.onOpen, menuItem)
menuItem = self.menuFile.Insert(2, ID_SAVE, self.MENU_TEXTS[ID_SAVE][0])
self.Bind(wx.EVT_MENU, self.onSave, menuItem)
menuItem = self.menuFile.Insert(3, ID_SAVE_AS, self.MENU_TEXTS[ID_SAVE_AS][0])
self.Bind(wx.EVT_MENU, self.onSaveAs, menuItem)
menuItem = self.menuFile.Insert(4, ID_EXPORT_TO_MAYA, self.MENU_TEXTS[ID_EXPORT_TO_MAYA][0])
self.Bind(wx.EVT_MENU, self.onExportToMaya, menuItem)
self.menuEdit = wx.Menu()
self.menuBar.Insert(1, self.menuEdit, "&Edit")
menuItem = self.menuEdit.Append(ID_DUPLICATE, self.MENU_TEXTS[ID_DUPLICATE][0])
self.Bind(wx.EVT_MENU, self.onDuplicate, menuItem)
menuItem = self.menuEdit.Append(ID_MAKE_LIVE, self.MENU_TEXTS[ID_MAKE_LIVE][0])
self.Bind(wx.EVT_MENU, self.onMakeLive, menuItem)
menuItem = self.menuEdit.Append(ID_UNDO, self.MENU_TEXTS[ID_UNDO][0])
self.Bind(wx.EVT_MENU, self.editor.actionMgr.undo, menuItem)
menuItem = self.menuEdit.Append(ID_REDO, self.MENU_TEXTS[ID_REDO][0])
self.Bind(wx.EVT_MENU, self.editor.actionMgr.redo, menuItem)
self.menuOptions = wx.Menu()
self.menuBar.Insert(2, self.menuOptions, "&Options")
self.showGridMenuItem = self.menuOptions.Append(ID_SHOW_GRID, self.MENU_TEXTS[ID_SHOW_GRID][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.toggleGrid, self.showGridMenuItem)
self.gridSizeMenuItem = self.menuOptions.Append(ID_GRID_SIZE, self.MENU_TEXTS[ID_GRID_SIZE][0])
self.Bind(wx.EVT_MENU, self.onGridSize, self.gridSizeMenuItem)
self.gridSnapMenuItem = self.menuOptions.Append(ID_GRID_SNAP, self.MENU_TEXTS[ID_GRID_SNAP][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.toggleGridSnap, self.gridSnapMenuItem)
self.showPandaObjectsMenuItem = self.menuOptions.Append(ID_SHOW_PANDA_OBJECT, self.MENU_TEXTS[ID_SHOW_PANDA_OBJECT][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.onShowPandaObjects, self.showPandaObjectsMenuItem)
self.parentToSelectedMenuItem = self.menuOptions.Append(ID_PARENT_TO_SELECTED, self.MENU_TEXTS[ID_PARENT_TO_SELECTED][0], kind = wx.ITEM_CHECK)
self.hotKeysMenuItem = self.menuOptions.Append(ID_HOT_KEYS, self.MENU_TEXTS[ID_HOT_KEYS][0])
self.Bind(wx.EVT_MENU, self.onHotKeys, self.hotKeysMenuItem)
self.menuCurve = wx.Menu()
self.menuBar.Insert(3, self.menuCurve, "&CurveMode")
self.createCurveMenuItem = self.menuCurve.Append(ID_CREATE_CURVE, self.MENU_TEXTS[ID_CREATE_CURVE][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.onCreateCurve, self.createCurveMenuItem)
self.editCurveMenuItem = self.menuCurve.Append(ID_EDIT_CURVE, self.MENU_TEXTS[ID_EDIT_CURVE][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.onEditCurve, self.editCurveMenuItem)
self.curveAnimMenuItem = self.menuCurve.Append(ID_CURVE_ANIM, self.MENU_TEXTS[ID_CURVE_ANIM][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.onCurveAnim, self.curveAnimMenuItem)
self.menuAnim = wx.Menu()
self.menuBar.Insert(4, self.menuAnim, "&AnimationMode")
self.editAnimMenuItem = self.menuAnim.Append(ID_ANIM, self.MENU_TEXTS[ID_ANIM][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.onAnimation, self.editAnimMenuItem)
self.graphEditorMenuItem = self.menuAnim.Append(ID_GRAPH, self.MENU_TEXTS[ID_GRAPH][0], kind = wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU, self.onGraphEditor, self.graphEditorMenuItem)
WxPandaShell.createMenu(self)
def onGraphEditor(self,e):
if base.direct.selected.last is None:
dlg = wx.MessageDialog(None, 'Please select a object first.', 'NOTICE', wx.OK )
dlg.ShowModal()
dlg.Destroy()
self.graphEditorMenuItem.Check(False)
else:
currentObj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
self.graphEditorUI = GraphEditorUI(self, self.editor, currentObj)
self.graphEditorUI.Show()
self.graphEditorMenuItem.Check(True)
def onAnimation(self,e):
if self.editor.mode != self.editor.ANIM_MODE:
self.animUI = AnimControlUI(self, self.editor)
self.animUI.Show()
self.editor.mode = self.editor.ANIM_MODE
if self.editor.mode == self.editor.ANIM_MODE:
self.editAnimMenuItem.Check(True)
def onCurveAnim(self,e):
self.curveAnimUI = CurveAnimUI(self, self.editor)
self.curveAnimUI.Show()
self.curveAnimMenuItem.Check(True)
def onCreateCurve(self,e):
"""Function to invoke curve creating, need to check previous mode"""
if self.editor.mode == self.editor.CREATE_CURVE_MODE:
self.createCurveMenuItem.Check(False)
self.editor.curveEditor.onBaseMode()
else:
if self.editor.mode == self.editor.EDIT_CURVE_MODE:
self.editor.curveEditor.onBaseMode()
self.editCurveMenuItem.Check(False)
self.createCurveMenuItem.Check(True)
self.onCreateCurve(None)
else:
self.currentView = self.getCurrentView()
if self.currentView is None:
dlg = wx.MessageDialog(None, 'Please select a viewport first.Do not support curve creation under four viewports.', 'NOTICE', wx.OK )
dlg.ShowModal()
dlg.Destroy()
self.createCurveMenuItem.Check(False)
else:
self.editor.mode = self.editor.CREATE_CURVE_MODE
self.editor.updateStatusReadout('Please press ENTER to end the curve creation.')
degreeUI = CurveDegreeUI(self, -1, 'Curve Degree')
degreeUI.ShowModal()
degreeUI.Destroy()
base.direct.manipulationControl.disableManipulation()
self.editCurveMenuItem.Check(False)
def onEditCurve(self,e):
"""Function to invoke curve editing and translate global information to local information. Need to check previous mode"""
if self.editor.mode == self.editor.EDIT_CURVE_MODE:
self.editCurveMenuItem.Check(False)
self.editor.curveEditor.onBaseMode()
else:
if self.editor.mode == self.editor.CREATE_CURVE_MODE:
self.editor.curveEditor.onBaseMode()
self.editCurveMenuItem.Check(True)
self.createCurveMenuItem.Check(False)
self.onEditCurve(None)
else:
if base.direct.selected.last is None:
dlg = wx.MessageDialog(None, 'Please select a curve first.', 'NOTICE', wx.OK )
dlg.ShowModal()
dlg.Destroy()
self.editCurveMenuItem.Check(False)
if base.direct.selected.last is not None :
base.direct.manipulationControl.enableManipulation()
self.createCurveMenuItem.Check(False)
self.curveObj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
if self.curveObj[OG.OBJ_DEF].name == '__Curve__':
self.editor.mode = self.editor.EDIT_CURVE_MODE
self.editor.updateStatusReadout('Please press ENTER to end the curve editing.')
self.editor.curveEditor.currentRope = self.curveObj[OG.OBJ_NP]
self.editor.curveEditor.curveControl = self.curveObj[OG.OBJ_PROP]['curveInfo']
self.editor.curveEditor.degree = self.curveObj[OG.OBJ_PROP]['Degree']
for item in self.editor.curveEditor.curveControl:
item[1].show()
self.editor.curveEditor.curve.append((None, item[1].getPos()))
else:
dlg = wx.MessageDialog(None, 'Please select a curve first.', 'NOTICE', wx.OK )
dlg.ShowModal()
dlg.Destroy()
self.editCurveMenuItem.Check(False)
def updateMenu(self):
hotKeyDict = {}
for hotKey in base.direct.hotKeyMap.keys():
desc = base.direct.hotKeyMap[hotKey]
hotKeyDict[desc[1]] = hotKey
for id in self.MENU_TEXTS.keys():
desc = self.MENU_TEXTS[id]
if desc[1]:
menuItem = self.menuBar.FindItemById(id)
hotKey = hotKeyDict.get(desc[1])
if hotKey:
menuItem.SetText(desc[0] + "\t%s"%hotKey)
def createInterface(self):
WxPandaShell.createInterface(self)
self.leftBarUpNB = wx.Notebook(self.leftBarUpPane, style=wx.NB_BOTTOM)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.leftBarUpNB, 1, wx.EXPAND)
self.leftBarUpPane.SetSizer(sizer)
self.leftBarUpPane0 = wx.Panel(self.leftBarUpNB, -1)
self.leftBarUpNB.AddPage(self.leftBarUpPane0, 'Object Palette')
self.leftBarUpPane1 = wx.Panel(self.leftBarUpNB, -1)
self.leftBarUpNB.AddPage(self.leftBarUpPane1, 'Proto Palette')
self.leftBarDownNB = wx.Notebook(self.leftBarDownPane)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.leftBarDownNB, 1, wx.EXPAND)
self.leftBarDownPane.SetSizer(sizer)
self.leftBarDownPane0 = wx.Panel(self.leftBarDownNB, -1)
self.leftBarDownNB.AddPage(self.leftBarDownPane0, 'Scene Graph')
self.rightBarDownNB = wx.Notebook(self.rightBarDownPane)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.rightBarDownNB, 1, wx.EXPAND)
self.rightBarDownPane.SetSizer(sizer)
self.rightBarDownPane0 = wx.Panel(self.rightBarDownNB, -1)
self.rightBarDownNB.AddPage(self.rightBarDownPane0, 'Layers')
self.topView.SetDropTarget(PandaTextDropTarget(self.editor, self.topView))
self.frontView.SetDropTarget(PandaTextDropTarget(self.editor, self.frontView))
self.leftView.SetDropTarget(PandaTextDropTarget(self.editor, self.leftView))
self.perspView.SetDropTarget(PandaTextDropTarget(self.editor, self.perspView))
self.rightBarDownPane.Layout()
self.Layout()
self.objectPaletteUI = ObjectPaletteUI(self.leftBarUpPane0, self.editor)
self.protoPaletteUI = ProtoPaletteUI(self.leftBarUpPane1, self.editor)
self.objectPropertyUI = ObjectPropertyUI(self.rightBarUpPane, self.editor)
self.sceneGraphUI = SceneGraphUI(self.leftBarDownPane0, self.editor)
self.layerEditorUI = LayerEditorUI(self.rightBarDownPane0, self.editor)
self.showGridMenuItem.Check(True)
def onRightDown(self, evt=None):
"""Invoked when the viewport is right-clicked."""
if evt is None:
mpos = wx.GetMouseState()
mpos = self.ScreenToClient((mpos.x, mpos.y))
else:
mpos = evt.GetPosition()
base.direct.fMouse3 = 0
self.PopupMenu(self.contextMenu, mpos)
def onKeyDownEvent(self, evt):
if evt.GetKeyCode() == wx.WXK_ALT:
base.direct.fAlt = 1
elif evt.GetKeyCode() == wx.WXK_CONTROL:
base.direct.fControl = 1
elif evt.GetKeyCode() == wx.WXK_SHIFT:
base.direct.fShift = 1
elif evt.GetKeyCode() == wx.WXK_UP:
messenger.send('arrow_up')
elif evt.GetKeyCode() == wx.WXK_DOWN:
messenger.send('arrow_down')
elif evt.GetKeyCode() == wx.WXK_LEFT:
messenger.send('arrow_left')
elif evt.GetKeyCode() == wx.WXK_RIGHT:
messenger.send('arrow_right')
elif evt.GetKeyCode() == wx.WXK_PAGEUP:
messenger.send('page_up')
elif evt.GetKeyCode() == wx.WXK_PAGEDOWN:
messenger.send('page_down')
else:
evt.Skip()
def onKeyUpEvent(self, evt):
if evt.GetKeyCode() == wx.WXK_ALT:
base.direct.fAlt = 0
elif evt.GetKeyCode() == wx.WXK_CONTROL:
base.direct.fControl = 0
elif evt.GetKeyCode() == wx.WXK_SHIFT:
base.direct.fShift = 0
elif evt.GetKeyCode() == wx.WXK_UP:
messenger.send('arrow_up-up')
elif evt.GetKeyCode() == wx.WXK_DOWN:
messenger.send('arrow_down-up')
elif evt.GetKeyCode() == wx.WXK_LEFT:
messenger.send('arrow_left-up')
elif evt.GetKeyCode() == wx.WXK_RIGHT:
messenger.send('arrow_right-up')
elif evt.GetKeyCode() == wx.WXK_PAGEUP:
messenger.send('page_up-up')
elif evt.GetKeyCode() == wx.WXK_PAGEDOWN:
messenger.send('page_down-up')
else:
evt.Skip()
def onKeyEvent(self, evt):
input = ''
if evt.GetKeyCode() in range(97, 123): # for keys from a to z
if evt.GetModifiers() == 4: # when shift is pressed while caps lock is on
input = 'shift-%s'%chr(evt.GetKeyCode())
else:
input = chr(evt.GetKeyCode())
elif evt.GetKeyCode() in range(65, 91):
if evt.GetModifiers() == 4: # when shift is pressed
input = 'shift-%s'%chr(evt.GetKeyCode() + 32)
else:
input = chr(evt.GetKeyCode() + 32)
elif evt.GetKeyCode() in range(1, 27): # for keys from a to z with control
input = 'control-%s'%chr(evt.GetKeyCode()+96)
elif evt.GetKeyCode() == wx.WXK_DELETE:
input = 'delete'
elif evt.GetKeyCode() == wx.WXK_ESCAPE:
input = 'escape'
else:
if evt.GetModifiers() == 4:
input = 'shift-%s'%chr(evt.GetKeyCode())
elif evt.GetModifiers() == 2:
input = 'control-%s'%chr(evt.GetKeyCode())
elif evt.GetKeyCode() < 256:
input = chr(evt.GetKeyCode())
if input in base.direct.hotKeyMap.keys():
keyDesc = base.direct.hotKeyMap[input]
messenger.send(keyDesc[1])
def reset(self):
self.sceneGraphUI.reset()
self.layerEditorUI.reset()
def onNew(self, evt=None):
self.editor.reset()
def onOpen(self, evt=None):
dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.py", style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
if dialog.ShowModal() == wx.ID_OK:
self.editor.load(dialog.GetPath())
self.editor.setTitleWithFilename(dialog.GetPath())
dialog.Destroy()
def onSave(self, evt=None):
if self.editor.currentFile is None or\
not self.editor.currentFile.endswith('.py'):
return self.onSaveAs(evt)
else:
self.editor.save()
def onSaveAs(self, evt):
dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.py", style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
result = True
if dialog.ShowModal() == wx.ID_OK:
self.editor.saveAs(dialog.GetPath())
self.editor.setTitleWithFilename(dialog.GetPath())
else:
result = False
dialog.Destroy()
return result
def onExportToMaya(self, evt):
dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.mb", style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
if dialog.ShowModal() == wx.ID_OK:
self.editor.exportToMaya(dialog.GetPath())
dialog.Destroy()
def onDuplicate(self, evt):
self.editor.objectMgr.duplicateSelected()
def onMakeLive(self, evt):
self.editor.objectMgr.makeSelectedLive()
def toggleGrid(self, evt):
if self.showGridMenuItem.IsChecked():
for grid in [self.perspView.grid, self.topView.grid, self.frontView.grid, self.leftView.grid]:
if grid.isHidden():
grid.show()
else:
for grid in [self.perspView.grid, self.topView.grid, self.frontView.grid, self.leftView.grid]:
if not grid.isHidden():
grid.hide()
def toggleGridSnap(self, evt):
if self.gridSnapMenuItem.IsChecked():
base.direct.manipulationControl.fGridSnap = 1
for grid in [self.perspView.grid, self.topView.grid, self.frontView.grid, self.leftView.grid]:
grid.fXyzSnap = 1
else:
base.direct.manipulationControl.fGridSnap = 0
for grid in [self.perspView.grid, self.topView.grid, self.frontView.grid, self.leftView.grid]:
grid.fXyzSnap = 0
def onGridSize(self, evt):
gridSizeUI = GridSizeUI(self, -1, 'Change Grid Size', self.perspView.grid.gridSize, self.perspView.grid.gridSpacing)
gridSizeUI.ShowModal()
gridSizeUI.Destroy()
def onShowPandaObjects(self, evt):
self.sceneGraphUI.showPandaObjectChildren()
def onDestroy(self, evt):
self.editor.protoPalette.saveToFile()
self.editor.saveSettings()
self.editor.reset()
def updateGrids(self, newSize, newSpacing):
self.perspView.grid.gridSize = newSize
self.perspView.grid.gridSpacing = newSpacing
self.perspView.grid.updateGrid()
self.topView.grid.gridSize = newSize
self.topView.grid.gridSpacing = newSpacing
self.topView.grid.updateGrid()
self.frontView.grid.gridSize = newSize
self.frontView.grid.gridSpacing = newSpacing
self.frontView.grid.updateGrid()
self.leftView.grid.gridSize = newSize
self.leftView.grid.gridSpacing = newSpacing
self.leftView.grid.updateGrid()
def onHotKeys(self, evt):
hotKeyUI = HotKeyUI(self, -1, 'Hot Key List')
hotKeyUI.ShowModal()
hotKeyUI.Destroy()
def buildContextMenu(self, nodePath):
for menuItem in self.contextMenu.GetMenuItems():
self.contextMenu.RemoveItem(menuItem)
self.contextMenu.addItem('Replace This', call=lambda\
p0=None, p1=False:self.replaceObject(p0, p1))
self.contextMenu.addItem('Replace All', call=lambda\
p0=None, p1=True:self.replaceObject(p0, p1))
self.contextMenu.AppendSeparator()
def replaceObject(self, evt, all=False):
currObj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
if currObj is None:
print('No valid object is selected for replacement')
return
targetType = self.editor.ui.objectPaletteUI.getSelected()
if targetType is None:
print('No valid target type is selected for replacement')
return
if all:
typeName = currObj[OG.OBJ_DEF].name
objs = self.editor.objectMgr.findObjectsByTypeName(typeName)
for obj in objs:
self.editor.objectMgr.replaceObjectWithTypeName(obj, targetType)
else:
self.editor.objectMgr.replaceObjectWithTypeName(currObj, targetType)
class GridSizeUI(wx.Dialog):
def __init__(self, parent, id, title, gridSize, gridSpacing):
wx.Dialog.__init__(self, parent, id, title, size=(250, 240))
self.parent = parent
panel = wx.Panel(self, -1)
vbox = wx.BoxSizer(wx.VERTICAL)
wx.StaticBox(panel, -1, 'Grid Size', (5, 5), (235, 80))
self.gridSizeSlider = WxSlider(panel, -1, float(gridSize), 10.0, 100000.0,
pos = (10, 25), size=(220, -1),
style=wx.SL_HORIZONTAL | wx.SL_LABELS, textSize=(80,20))
self.gridSizeSlider.Enable()
wx.StaticBox(panel, -1, 'Grid Space', (5, 90), (235, 80))
self.gridSpacingSlider = WxSlider(panel, -1, float(gridSpacing), 0.01, 2000.0,
pos = (10, 115), size=(220, -1),
style=wx.SL_HORIZONTAL | wx.SL_LABELS)
self.gridSpacingSlider.Enable()
okButton = wx.Button(self, -1, 'Apply', size=(70, 20))
okButton.Bind(wx.EVT_BUTTON, self.onApply)
vbox.Add(panel)
vbox.Add(okButton, 1, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 5)
self.SetSizer(vbox)
base.le.ui.bindKeyEvents(False)
def onApply(self, evt):
newSize = self.gridSizeSlider.GetValue()
newSpacing = self.gridSpacingSlider.GetValue()
self.parent.updateGrids(newSize, newSpacing)
base.le.ui.bindKeyEvents(True)
self.Destroy()
class ViewportMenu(wx.Menu):
"""Represents a menu that appears when right-clicking a viewport."""
def __init__(self):
wx.Menu.__init__(self)
def addItem(self, name, parent = None, call = None, id = None):
if id is None:
id = wx.NewId()
if parent is None:
parent = self
item = wx.MenuItem(parent, id, name)
parent.AppendItem(item)
if call is not None:
self.Bind(wx.EVT_MENU, call, item)
def addMenu(self, name, parent = None, id = None):
if id is None:
id = wx.NewId()
subMenu = wx.Menu()
if parent is None:
parent = self
parent.AppendMenu(id, name, subMenu)
return subMenu
class CurveDegreeUI(wx.Dialog):
def __init__(self, parent, id, title):
wx.Dialog.__init__(self, parent, id, title, size=(150, 120))
self.parent = parent
panel = wx.Panel(self, -1)
degreeBox = wx.BoxSizer(wx.VERTICAL)
degreeList = ['2','3','4']
self.degree = wx.RadioBox(panel, -1, 'Curve Degree', (5, 5), wx.DefaultSize, degreeList, 3, wx.RA_SPECIFY_COLS)
self.degree.SetToolTipString("Select the degree of the curve.")
self.degree.SetSelection(1)
okButton = wx.Button(self, -1, 'Apply', size=(70, 20))
okButton.Bind(wx.EVT_BUTTON, self.onApply)
degreeBox.Add(panel, 1, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 5)
degreeBox.Add(okButton, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 5)
self.SetSizer(degreeBox)
def onApply(self, evt):
if str(self.degree.GetSelection()) == '0':
self.parent.editor.curveEditor.degree = 2
if str(self.degree.GetSelection()) == '1':
self.parent.editor.curveEditor.degree = 3
if str(self.degree.GetSelection()) == '2':
self.parent.editor.curveEditor.degree = 4
self.Destroy()