From 3b7c98a5e1d3af4265dc7ca4d10dc4f8515634c1 Mon Sep 17 00:00:00 2001 From: Gyedo Jeon Date: Fri, 9 Apr 2010 23:27:04 +0000 Subject: [PATCH] Added generic wx panda frame --- direct/src/wxwidgets/ViewPort.py | 243 +++++++++++++++++++++++++++ direct/src/wxwidgets/WxPandaShell.py | 216 ++++++++++++++++++++++++ direct/src/wxwidgets/WxPandaStart.py | 3 + 3 files changed, 462 insertions(+) create mode 100755 direct/src/wxwidgets/ViewPort.py create mode 100755 direct/src/wxwidgets/WxPandaShell.py create mode 100755 direct/src/wxwidgets/WxPandaStart.py diff --git a/direct/src/wxwidgets/ViewPort.py b/direct/src/wxwidgets/ViewPort.py new file mode 100755 index 0000000000..94fd796b9f --- /dev/null +++ b/direct/src/wxwidgets/ViewPort.py @@ -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)) + diff --git a/direct/src/wxwidgets/WxPandaShell.py b/direct/src/wxwidgets/WxPandaShell.py new file mode 100755 index 0000000000..575dbf1420 --- /dev/null +++ b/direct/src/wxwidgets/WxPandaShell.py @@ -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) diff --git a/direct/src/wxwidgets/WxPandaStart.py b/direct/src/wxwidgets/WxPandaStart.py new file mode 100755 index 0000000000..015181144b --- /dev/null +++ b/direct/src/wxwidgets/WxPandaStart.py @@ -0,0 +1,3 @@ +from WxPandaShell import * +base.app = WxPandaShell() +