mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 01:07:51 -04:00
Added generic wx panda frame
This commit is contained in:
parent
d08be0d404
commit
3b7c98a5e1
243
direct/src/wxwidgets/ViewPort.py
Executable file
243
direct/src/wxwidgets/ViewPort.py
Executable file
@ -0,0 +1,243 @@
|
||||
"""
|
||||
Contains classes useful for 3D viewports.
|
||||
|
||||
Originally written by pro-rsoft,
|
||||
Modified by gjeon.
|
||||
"""
|
||||
|
||||
__all__ = ["Viewport", "ViewportManager"]
|
||||
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.directtools.DirectGrid import DirectGrid
|
||||
from direct.showbase.ShowBase import WindowControls
|
||||
from direct.directtools.DirectGlobals import *
|
||||
from pandac.PandaModules import WindowProperties, OrthographicLens, Point3, Plane, CollisionPlane, CollisionNode, NodePath
|
||||
import wx
|
||||
|
||||
HORIZONTAL = wx.SPLIT_HORIZONTAL
|
||||
VERTICAL = wx.SPLIT_VERTICAL
|
||||
CREATENEW = 99
|
||||
VPLEFT = 10
|
||||
VPFRONT = 11
|
||||
VPTOP = 12
|
||||
VPPERSPECTIVE = 13
|
||||
|
||||
class ViewportManager:
|
||||
"""Manages the global viewport stuff."""
|
||||
viewports = []
|
||||
gsg = None
|
||||
|
||||
@staticmethod
|
||||
def initializeAll(*args, **kwargs):
|
||||
"""Calls initialize() on all the viewports."""
|
||||
for v in ViewportManager.viewports:
|
||||
v.initialize(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def updateAll(*args, **kwargs):
|
||||
"""Calls Update() on all the viewports."""
|
||||
for v in ViewportManager.viewports:
|
||||
v.Update(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def layoutAll(*args, **kwargs):
|
||||
"""Calls Layout() on all the viewports."""
|
||||
for v in ViewportManager.viewports:
|
||||
v.Layout(*args, **kwargs)
|
||||
|
||||
class Viewport(wx.Panel, DirectObject):
|
||||
"""Class representing a 3D Viewport."""
|
||||
CREATENEW = CREATENEW
|
||||
VPLEFT = VPLEFT
|
||||
VPFRONT = VPFRONT
|
||||
VPTOP = VPTOP
|
||||
VPPERSPECTIVE = VPPERSPECTIVE
|
||||
def __init__(self, name, *args, **kwargs):
|
||||
self.name = name
|
||||
DirectObject.__init__(self)
|
||||
wx.Panel.__init__(self, *args, **kwargs)
|
||||
|
||||
ViewportManager.viewports.append(self)
|
||||
self.win = None
|
||||
self.camera = None
|
||||
self.lens = None
|
||||
self.camPos = None
|
||||
self.camLookAt = None
|
||||
self.initialized = False
|
||||
self.grid = None
|
||||
self.collPlane = None
|
||||
|
||||
def initialize(self):
|
||||
self.Update()
|
||||
wp = WindowProperties()
|
||||
wp.setOrigin(0, 0)
|
||||
wp.setSize(self.ClientSize.GetWidth(), self.ClientSize.GetHeight())
|
||||
assert self.GetHandle() != 0
|
||||
wp.setParentWindow(self.GetHandle())
|
||||
|
||||
# initializing panda window
|
||||
base.windowType = "onscreen"
|
||||
props = WindowProperties.getDefault()
|
||||
props.addProperties(wp)
|
||||
self.win = base.openWindow(props = props, gsg = ViewportManager.gsg)
|
||||
if self.win:
|
||||
self.cam2d = base.makeCamera2d(self.win)
|
||||
self.cam2d.node().setCameraMask(LE_CAM_MASKS[self.name])
|
||||
|
||||
if ViewportManager.gsg == None:
|
||||
ViewportManager.gsg = self.win.getGsg()
|
||||
self.cam = base.camList[-1]
|
||||
self.camera = render.attachNewNode(self.name)
|
||||
#self.camera.setName(self.name)
|
||||
#self.camera.reparentTo(render)
|
||||
self.cam.reparentTo(self.camera)
|
||||
self.camNode = self.cam.node()
|
||||
|
||||
self.camNode.setCameraMask(LE_CAM_MASKS[self.name])
|
||||
|
||||
self.bt = base.setupMouse(self.win, True)
|
||||
self.bt.node().setPrefix('_le_%s_'%self.name[:3])
|
||||
mw = self.bt.getParent()
|
||||
mk = mw.getParent()
|
||||
winCtrl = WindowControls(
|
||||
self.win, mouseWatcher=mw,
|
||||
cam=self.camera,
|
||||
camNode = self.camNode,
|
||||
cam2d=None,
|
||||
mouseKeyboard =mk,
|
||||
grid = self.grid)
|
||||
base.setupWindowControls(winCtrl)
|
||||
|
||||
self.initialized = True
|
||||
if self.lens != None: self.cam.node().setLens(self.lens)
|
||||
if self.camPos != None: self.camera.setPos(self.camPos)
|
||||
if self.camLookAt != None: self.camera.lookAt(self.camLookAt)
|
||||
|
||||
self.camLens = self.camNode.getLens()
|
||||
|
||||
if self.name in ['top', 'front', 'left']:
|
||||
x = self.ClientSize.GetWidth() * 0.1
|
||||
y = self.ClientSize.GetHeight() * 0.1
|
||||
self.camLens.setFilmSize(x, y)
|
||||
|
||||
self.Bind(wx.EVT_SIZE, self.onSize)
|
||||
|
||||
## self.accept("wheel_down", self.zoomOut)
|
||||
## self.accept("wheel_up", self.zoomIn)
|
||||
## self.accept("page_down", self.zoomOut)
|
||||
## self.accept("page_down-repeat", self.zoomOut)
|
||||
## self.accept("page_up", self.zoomIn)
|
||||
## self.accept("page_up-repeat", self.zoomIn)
|
||||
#self.accept("mouse3", self.onRightDown)
|
||||
|
||||
def close(self):
|
||||
"""Closes the viewport."""
|
||||
if self.initialized:
|
||||
Window.close(self)
|
||||
ViewportManager.viewports.remove(self)
|
||||
|
||||
def onSize(self, evt):
|
||||
"""Invoked when the viewport is resized."""
|
||||
if self.win != None:
|
||||
wp = WindowProperties()
|
||||
wp.setOrigin(0, 0)
|
||||
newWidth = self.ClientSize.GetWidth()
|
||||
newHeight = self.ClientSize.GetHeight()
|
||||
wp.setSize(newWidth, newHeight)
|
||||
self.win.requestProperties(wp)
|
||||
|
||||
if hasattr(base, "direct") and base.direct:
|
||||
for dr in base.direct.drList:
|
||||
if dr.camNode == self.camNode:
|
||||
dr.updateFilmSize(newWidth, newHeight)
|
||||
break
|
||||
|
||||
def onRightDown(self, evt = None):
|
||||
"""Invoked when the viewport is right-clicked."""
|
||||
if evt == None:
|
||||
mpos = wx.GetMouseState()
|
||||
mpos = self.ScreenToClient((mpos.x, mpos.y))
|
||||
else:
|
||||
mpos = evt.GetPosition()
|
||||
self.Update()
|
||||
#self.PopupMenu(self.menu, mpos)
|
||||
#self.menu.Destroy()
|
||||
|
||||
def zoomOut(self):
|
||||
self.camera.setY(self.camera, -MOUSE_ZOO_SPEED)
|
||||
|
||||
def zoomIn(self):
|
||||
self.camera.setY(self.camera, MOUSE_ZOOM_SPEED)
|
||||
|
||||
@staticmethod
|
||||
def make(parent, vpType = None):
|
||||
"""Safe constructor that also takes CREATENEW, VPLEFT, VPTOP, etc."""
|
||||
if vpType == None or vpType == CREATENEW:
|
||||
return Viewport(parent)
|
||||
if isinstance(vpType, Viewport): return vpType
|
||||
if vpType == VPLEFT: return Viewport.makeLeft(parent)
|
||||
if vpType == VPFRONT: return Viewport.makeFront(parent)
|
||||
if vpType == VPTOP: return Viewport.makeTop(parent)
|
||||
if vpType == VPPERSPECTIVE: return Viewport.makePerspective(parent)
|
||||
raise TypeError, "Unknown viewport type: %s" % vpType
|
||||
|
||||
@staticmethod
|
||||
def makeOrthographic(parent, name, campos):
|
||||
v = Viewport(name, parent)
|
||||
v.lens = OrthographicLens()
|
||||
v.lens.setFilmSize(30)
|
||||
v.camPos = campos
|
||||
v.camLookAt = Point3(0, 0, 0)
|
||||
v.grid = DirectGrid(parent=render)
|
||||
if name == 'left':
|
||||
v.grid.setHpr(0, 0, 90)
|
||||
collPlane = CollisionNode('LeftGridCol')
|
||||
collPlane.addSolid(CollisionPlane(Plane(1, 0, 0, 0)))
|
||||
collPlane.setIntoCollideMask(BitMask32.bit(21))
|
||||
v.collPlane = NodePath(collPlane)
|
||||
v.collPlane.wrtReparentTo(v.grid)
|
||||
#v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_leftViewGridBack")
|
||||
LE_showInOneCam(v.grid, name)
|
||||
elif name == 'front':
|
||||
v.grid.setHpr(90, 0, 90)
|
||||
collPlane = CollisionNode('FrontGridCol')
|
||||
collPlane.addSolid(CollisionPlane(Plane(0, -1, 0, 0)))
|
||||
collPlane.setIntoCollideMask(BitMask32.bit(21))
|
||||
v.collPlane = NodePath(collPlane)
|
||||
v.collPlane.wrtReparentTo(v.grid)
|
||||
#v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_frontViewGridBack")
|
||||
LE_showInOneCam(v.grid, name)
|
||||
else:
|
||||
collPlane = CollisionNode('TopGridCol')
|
||||
collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0)))
|
||||
collPlane.setIntoCollideMask(BitMask32.bit(21))
|
||||
v.collPlane = NodePath(collPlane)
|
||||
v.collPlane.reparentTo(v.grid)
|
||||
#v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_topViewGridBack")
|
||||
LE_showInOneCam(v.grid, name)
|
||||
return v
|
||||
|
||||
@staticmethod
|
||||
def makePerspective(parent):
|
||||
v = Viewport('persp', parent)
|
||||
v.camPos = Point3(-19, -19, 19)
|
||||
v.camLookAt = Point3(0, 0, 0)
|
||||
|
||||
v.grid = DirectGrid(parent=render)
|
||||
collPlane = CollisionNode('PerspGridCol')
|
||||
collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0)))
|
||||
oldBitmask = collPlane.getIntoCollideMask()
|
||||
collPlane.setIntoCollideMask(BitMask32.bit(21)|oldBitmask)
|
||||
v.collPlane = NodePath(collPlane)
|
||||
v.collPlane.reparentTo(v.grid)
|
||||
#v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_perspViewGridBack")
|
||||
LE_showInOneCam(v.grid, 'persp')
|
||||
return v
|
||||
|
||||
@staticmethod
|
||||
def makeLeft(parent): return Viewport.makeOrthographic(parent, 'left', Point3(600, 0, 0))
|
||||
@staticmethod
|
||||
def makeFront(parent): return Viewport.makeOrthographic(parent, 'front', Point3(0, -600, 0))
|
||||
@staticmethod
|
||||
def makeTop(parent): return Viewport.makeOrthographic(parent, 'top', Point3(0, 0, 600))
|
||||
|
216
direct/src/wxwidgets/WxPandaShell.py
Executable file
216
direct/src/wxwidgets/WxPandaShell.py
Executable file
@ -0,0 +1,216 @@
|
||||
import wx
|
||||
import os
|
||||
from wx.lib.agw import fourwaysplitter as FWS
|
||||
|
||||
from pandac.PandaModules import *
|
||||
from direct.showbase.ShowBase import *
|
||||
from direct.directtools.DirectGlobals import *
|
||||
|
||||
base = ShowBase(False)
|
||||
|
||||
from WxAppShell import *
|
||||
from ViewPort import *
|
||||
|
||||
ID_FOUR_VIEW = 401
|
||||
ID_TOP_VIEW = 402
|
||||
ID_FRONT_VIEW = 403
|
||||
ID_LEFT_VIEW = 404
|
||||
ID_PERSP_VIEW = 405
|
||||
|
||||
class WxPandaShell(WxAppShell):
|
||||
""" Class for Panda3D LevelEditor """
|
||||
frameWidth = 800
|
||||
frameHeight = 600
|
||||
appversion = '1.0'
|
||||
appname = 'Panda3D Generic WX Frame'
|
||||
copyright = ('Copyright 2010 Disney Online Studios.' +
|
||||
'\nAll Rights Reserved.')
|
||||
|
||||
MENU_TEXTS = {
|
||||
ID_FOUR_VIEW : ("Four Views", None),
|
||||
ID_TOP_VIEW : ("Top View", None),
|
||||
ID_FRONT_VIEW : ("Front View", None),
|
||||
ID_LEFT_VIEW : ("Left View", None),
|
||||
ID_PERSP_VIEW : ("Persp View", None),
|
||||
}
|
||||
|
||||
def __init__(self, fStartDirect = False):
|
||||
fDirect = (base.config.GetBool('want-directtools', 0) or
|
||||
(base.config.GetString("cluster-mode", '') != ''))
|
||||
|
||||
self.fStartDirect = fStartDirect or fDirect
|
||||
|
||||
# Create the Wx app
|
||||
self.wxApp = wx.App(redirect = False)
|
||||
self.wxApp.SetAppName(self.appname)
|
||||
WxAppShell.__init__(self, size=wx.Size(self.frameWidth, self.frameHeight))
|
||||
self.initialize()
|
||||
|
||||
def createMenu(self):
|
||||
self.menuView = wx.Menu()
|
||||
self.menuBar.Insert(self.menuBar.GetMenuCount() - 1, self.menuView, "&View")
|
||||
|
||||
menuItem = self.menuView.AppendRadioItem(ID_FOUR_VIEW, self.MENU_TEXTS[ID_FOUR_VIEW][0])
|
||||
self.Bind(wx.EVT_MENU, lambda p0=None, p1=-1:self.onViewChange(p0, p1), menuItem)
|
||||
|
||||
menuItem = self.menuView.AppendRadioItem(ID_TOP_VIEW, self.MENU_TEXTS[ID_TOP_VIEW][0])
|
||||
self.Bind(wx.EVT_MENU, lambda p0=None, p1=0:self.onViewChange(p0, p1), menuItem)
|
||||
|
||||
menuItem = self.menuView.AppendRadioItem(ID_FRONT_VIEW, self.MENU_TEXTS[ID_FRONT_VIEW][0])
|
||||
self.Bind(wx.EVT_MENU, lambda p0=None, p1=1:self.onViewChange(p0, p1), menuItem)
|
||||
|
||||
menuItem = self.menuView.AppendRadioItem(ID_LEFT_VIEW, self.MENU_TEXTS[ID_LEFT_VIEW][0])
|
||||
self.Bind(wx.EVT_MENU, lambda p0=None, p1=2:self.onViewChange(p0, p1), menuItem)
|
||||
|
||||
menuItem = self.menuView.AppendRadioItem(ID_PERSP_VIEW, self.MENU_TEXTS[ID_PERSP_VIEW][0])
|
||||
self.Bind(wx.EVT_MENU, lambda p0=None, p1=3:self.onViewChange(p0, p1), menuItem)
|
||||
|
||||
def createInterface(self):
|
||||
self.createMenu()
|
||||
self.mainFrame = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_BORDER)
|
||||
self.leftFrame = wx.SplitterWindow(self.mainFrame, style = wx.SP_3D | wx.SP_BORDER)
|
||||
self.baseFrame = wx.SplitterWindow(self.mainFrame, style = wx.SP_3D | wx.SP_BORDER)
|
||||
self.viewFrame = FWS.FourWaySplitter(self.baseFrame, style=wx.SP_LIVE_UPDATE)
|
||||
self.rightFrame = wx.SplitterWindow(self.baseFrame, style = wx.SP_3D | wx.SP_BORDER)
|
||||
|
||||
self.topView = Viewport.makeTop(self.viewFrame)
|
||||
self.viewFrame.AppendWindow(self.topView)
|
||||
|
||||
self.frontView = Viewport.makeFront(self.viewFrame)
|
||||
self.viewFrame.AppendWindow(self.frontView)
|
||||
|
||||
self.leftView = Viewport.makeLeft(self.viewFrame)
|
||||
self.viewFrame.AppendWindow(self.leftView)
|
||||
|
||||
self.perspView = Viewport.makePerspective(self.viewFrame)
|
||||
self.viewFrame.AppendWindow(self.perspView)
|
||||
|
||||
self.leftBarUpPane = wx.Panel(self.leftFrame)
|
||||
self.leftBarDownPane = wx.Panel(self.leftFrame)
|
||||
self.rightBarUpPane = wx.Panel(self.rightFrame)
|
||||
self.rightBarDownPane = wx.Panel(self.rightFrame)
|
||||
|
||||
self.leftFrame.SplitHorizontally(self.leftBarUpPane, self.leftBarDownPane)
|
||||
self.rightFrame.SplitHorizontally(self.rightBarUpPane, self.rightBarDownPane)
|
||||
self.mainFrame.SplitVertically(self.leftFrame, self.baseFrame, 200)
|
||||
self.baseFrame.SplitVertically(self.viewFrame, self.rightFrame, 600)
|
||||
|
||||
self.leftFrame.SetSashGravity(0.5)
|
||||
self.rightFrame.SetSashGravity(0.5)
|
||||
self.baseFrame.SetSashGravity(1.0)
|
||||
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(self.mainFrame, 1, wx.EXPAND, 0)
|
||||
self.SetSizer(sizer); self.Layout()
|
||||
|
||||
def initialize(self):
|
||||
"""Initializes the viewports and editor."""
|
||||
self.Update()
|
||||
ViewportManager.updateAll()
|
||||
self.wxStep()
|
||||
ViewportManager.initializeAll()
|
||||
# Position the camera
|
||||
if base.trackball != None:
|
||||
base.trackball.node().setPos(0, 30, 0)
|
||||
base.trackball.node().setHpr(0, 15, 0)
|
||||
|
||||
# initializing direct
|
||||
if self.fStartDirect:
|
||||
base.startDirect(fWantTk = 0, fWantWx = 0)
|
||||
|
||||
base.direct.disableMouseEvents()
|
||||
newMouseEvents = map(lambda x: "_le_per_%s"%x, base.direct.mouseEvents) +\
|
||||
map(lambda x: "_le_fro_%s"%x, base.direct.mouseEvents) +\
|
||||
map(lambda x: "_le_lef_%s"%x, base.direct.mouseEvents) +\
|
||||
map(lambda x: "_le_top_%s"%x, base.direct.mouseEvents)
|
||||
base.direct.mouseEvents = newMouseEvents
|
||||
base.direct.enableMouseEvents()
|
||||
|
||||
base.direct.disableKeyEvents()
|
||||
keyEvents = map(lambda x: "_le_per_%s"%x, base.direct.keyEvents) +\
|
||||
map(lambda x: "_le_fro_%s"%x, base.direct.keyEvents) +\
|
||||
map(lambda x: "_le_lef_%s"%x, base.direct.keyEvents) +\
|
||||
map(lambda x: "_le_top_%s"%x, base.direct.keyEvents)
|
||||
base.direct.keyEvents = keyEvents
|
||||
base.direct.enableKeyEvents()
|
||||
|
||||
base.direct.disableModifierEvents()
|
||||
modifierEvents = map(lambda x: "_le_per_%s"%x, base.direct.modifierEvents) +\
|
||||
map(lambda x: "_le_fro_%s"%x, base.direct.modifierEvents) +\
|
||||
map(lambda x: "_le_lef_%s"%x, base.direct.modifierEvents) +\
|
||||
map(lambda x: "_le_top_%s"%x, base.direct.modifierEvents)
|
||||
base.direct.modifierEvents = modifierEvents
|
||||
base.direct.enableModifierEvents()
|
||||
|
||||
base.direct.cameraControl.lockRoll = True
|
||||
base.direct.setFScaleWidgetByCam(1)
|
||||
|
||||
unpickables = [
|
||||
"z-guide",
|
||||
"y-guide",
|
||||
"x-guide",
|
||||
"x-disc-geom",
|
||||
"x-ring-line",
|
||||
"x-post-line",
|
||||
"y-disc-geom",
|
||||
"y-ring-line",
|
||||
"y-post-line",
|
||||
"z-disc-geom",
|
||||
"z-ring-line",
|
||||
"z-post-line",
|
||||
"centerLines",
|
||||
"majorLines",
|
||||
"minorLines",
|
||||
"Sphere",]
|
||||
|
||||
for unpickable in unpickables:
|
||||
base.direct.addUnpickable(unpickable)
|
||||
|
||||
base.direct.manipulationControl.optionalSkipFlags |= SKIP_UNPICKABLE
|
||||
base.direct.manipulationControl.fAllowMarquee = 1
|
||||
base.direct.manipulationControl.supportMultiView()
|
||||
base.direct.cameraControl.useMayaCamControls = 1
|
||||
base.direct.cameraControl.perspCollPlane = self.perspView.collPlane
|
||||
for widget in base.direct.manipulationControl.widgetList:
|
||||
widget.setBin('gui-popup', 0)
|
||||
widget.setDepthTest(0)
|
||||
|
||||
# [gjeon] to intercept messages here
|
||||
base.direct.ignore('DIRECT-delete')
|
||||
base.direct.ignore('DIRECT-select')
|
||||
base.direct.ignore('DIRECT-preDeselectAll')
|
||||
base.direct.ignore('DIRECT-toggleWidgetVis')
|
||||
base.direct.fIgnoreDirectOnlyKeyMap = 1
|
||||
|
||||
# [gjeon] do not use the old way of finding current DR
|
||||
base.direct.drList.tryToGetCurrentDr = False
|
||||
|
||||
else:
|
||||
base.direct=None
|
||||
base.closeWindow(base.win)
|
||||
base.win = base.winList[3]
|
||||
|
||||
def wxStep(self, task = None):
|
||||
"""A step in the WX event loop. You can either call this yourself or use as task."""
|
||||
while self.evtLoop.Pending():
|
||||
self.evtLoop.Dispatch()
|
||||
self.wxApp.ProcessIdle()
|
||||
if task != None: return task.cont
|
||||
|
||||
def appInit(self):
|
||||
"""Overridden from WxAppShell.py."""
|
||||
# Create a new event loop (to overide default wxEventLoop)
|
||||
self.evtLoop = wx.EventLoop()
|
||||
self.oldLoop = wx.EventLoop.GetActive()
|
||||
wx.EventLoop.SetActive(self.evtLoop)
|
||||
taskMgr.add(self.wxStep, "evtLoopTask")
|
||||
|
||||
def onViewChange(self, evt, viewIdx):
|
||||
for i in range(4):
|
||||
if viewIdx >=0 and\
|
||||
i != viewIdx:
|
||||
base.winList[i].setActive(0)
|
||||
else:
|
||||
base.winList[i].setActive(1)
|
||||
|
||||
self.viewFrame.SetExpanded(viewIdx)
|
3
direct/src/wxwidgets/WxPandaStart.py
Executable file
3
direct/src/wxwidgets/WxPandaStart.py
Executable file
@ -0,0 +1,3 @@
|
||||
from WxPandaShell import *
|
||||
base.app = WxPandaShell()
|
||||
|
Loading…
x
Reference in New Issue
Block a user