Browse Source

*** empty log message ***

Mark Mine 24 years ago
parent
commit
ebcd197ff5

+ 4 - 4
direct/src/directtools/DirectManipulation.py

@@ -302,12 +302,12 @@ class DirectManipulationControl(PandaObject):
         if self.rotateAxis == 'x':
         if self.rotateAxis == 'x':
             direct.widget.setP(direct.widget, deltaAngle)
             direct.widget.setP(direct.widget, deltaAngle)
         elif self.rotateAxis == 'y':
         elif self.rotateAxis == 'y':
-            direct.widget.setR(direct.widget, -deltaAngle)
-        elif self.rotateAxis == 'z':
             if base.config.GetBool('temp-hpr-fix',0):
             if base.config.GetBool('temp-hpr-fix',0):
-                direct.widget.setH(direct.widget, -deltaAngle)
+                direct.widget.setR(direct.widget, deltaAngle)
             else:
             else:
-                direct.widget.setH(direct.widget, deltaAngle)
+                direct.widget.setR(direct.widget, -deltaAngle)
+        elif self.rotateAxis == 'z':
+            direct.widget.setH(direct.widget, deltaAngle)
         # Record crank angle for next time around
         # Record crank angle for next time around
         self.lastCrankAngle = newAngle
         self.lastCrankAngle = newAngle
 
 

+ 13 - 1
direct/src/directtools/DirectSession.py

@@ -10,6 +10,7 @@ from DirectSessionPanel import *
 from tkSimpleDialog import askstring
 from tkSimpleDialog import askstring
 import Placer
 import Placer
 import EntryScale
 import EntryScale
+import SceneGraphExplorer
 import OnscreenText
 import OnscreenText
 import types
 import types
 import __builtin__
 import __builtin__
@@ -104,6 +105,7 @@ class DirectSession(PandaObject):
             ['SGE_Fit', self.fitOnNodePath],
             ['SGE_Fit', self.fitOnNodePath],
             ['SGE_Place', Placer.place],
             ['SGE_Place', Placer.place],
             ['SGE_Set Color', EntryScale.rgbPanel],
             ['SGE_Set Color', EntryScale.rgbPanel],
+            ['SGE_Explore', SceneGraphExplorer.explore],
             ['SGE_Delete', self.removeNodePath],
             ['SGE_Delete', self.removeNodePath],
             ['SGE_Set Name', self.getAndSetName],
             ['SGE_Set Name', self.getAndSetName],
             ]
             ]
@@ -320,12 +322,22 @@ class DirectSession(PandaObject):
         messenger.send('DIRECT_activeParent', [self.activeParent])
         messenger.send('DIRECT_activeParent', [self.activeParent])
         
         
     def reparent(self, nodePath = None):
     def reparent(self, nodePath = None):
-        if nodePath and self.activeParent:
+        if (nodePath and self.activeParent and
+            self.isNotCycle(nodePath, self.activeParent)):
             oldParent = nodePath.getParent()
             oldParent = nodePath.getParent()
             nodePath.reparentTo(self.activeParent)
             nodePath.reparentTo(self.activeParent)
             # Alert everyone else
             # Alert everyone else
             messenger.send('DIRECT_reparent',
             messenger.send('DIRECT_reparent',
                            [nodePath, oldParent, self.activeParent])
                            [nodePath, oldParent, self.activeParent])
+
+    def isNotCycle(self, nodePath, parent):
+        if nodePath.id() == parent.id():
+            print 'DIRECT.reparent: Invalid parent'
+            return 0
+        elif parent.hasParent():
+            return self.isNotCycle(nodePath, parent.getParent())
+        else:
+            return 1
         
         
     def flash(self, nodePath = 'None Given'):
     def flash(self, nodePath = 'None Given'):
         """ Highlight an object by setting it red for a few seconds """
         """ Highlight an object by setting it red for a few seconds """

+ 5 - 4
direct/src/extensions/NodePath-extensions.py

@@ -35,9 +35,10 @@
     # For iterating over children
     # For iterating over children
     def getChildrenAsList(self):
     def getChildrenAsList(self):
         """Converts a node path's child NodePathCollection into a list"""
         """Converts a node path's child NodePathCollection into a list"""
+        children = self.getChildren()
         childrenList = []
         childrenList = []
         for childNum in range(self.getNumChildren()):
         for childNum in range(self.getNumChildren()):
-            childrenList.append(self.getChild(childNum))
+            childrenList.append(children[childNum])
         return childrenList
         return childrenList
 
 
     def printChildren(self):
     def printChildren(self):
@@ -779,7 +780,7 @@
         from ShowBaseGlobal import *
         from ShowBaseGlobal import *
         import TkGlobal
         import TkGlobal
         import Placer
         import Placer
-        Placer.place(self)
+        return Placer.place(self)
 
 
     def explore(self):
     def explore(self):
         base.wantDIRECT = 1
         base.wantDIRECT = 1
@@ -787,7 +788,7 @@
         from ShowBaseGlobal import *
         from ShowBaseGlobal import *
         import TkGlobal
         import TkGlobal
         import SceneGraphExplorer
         import SceneGraphExplorer
-        SceneGraphExplorer.explore(self)
+        return SceneGraphExplorer.explore(self)
 
 
     def rgbPanel(self, cb = None):
     def rgbPanel(self, cb = None):
         base.wantDIRECT = 1
         base.wantDIRECT = 1
@@ -795,7 +796,7 @@
         from ShowBaseGlobal import *
         from ShowBaseGlobal import *
         import TkGlobal
         import TkGlobal
         import EntryScale
         import EntryScale
-        EntryScale.rgbPanel(self, cb)
+        return EntryScale.rgbPanel(self, cb)
 
 
     def select(self):
     def select(self):
         base.wantDIRECT = 1
         base.wantDIRECT = 1

+ 382 - 163
direct/src/leveleditor/LevelEditor.py

@@ -1,25 +1,3 @@
-
-import getopt
-import sys
-
-# If you run this from the command line you can pass in the hood codes
-# you want to load. For example:
-#    ppython LevelEditor.py DD TT BR
-#
-if sys.argv[1:]:
-    try:
-        opts, pargs = getopt.getopt(sys.argv[1:], '')
-        hoods = pargs
-    except Exception, e:
-        print e
-# If you do not run from the command line, we just load all of them
-# or you can hack this up for your own purposes.
-else:
-    # hoods = ['TT', 'DD', 'BR', 'DG', 'DL', 'MM']
-    hoods = ['TT' ]
-
-print "Loading LevelEditor for hoods: ", hoods
-
 from ShowBaseGlobal import *
 from ShowBaseGlobal import *
 from PandaObject import *
 from PandaObject import *
 from PieMenu import *
 from PieMenu import *
@@ -31,13 +9,15 @@ from tkMessageBox import showinfo
 from tkFileDialog import *
 from tkFileDialog import *
 from whrandom import *
 from whrandom import *
 import Pmw
 import Pmw
+import Floater
 import EntryScale
 import EntryScale
 import VectorWidgets
 import VectorWidgets
 import string
 import string
 import os
 import os
-import __builtin__
+import getopt
+import sys
 import whrandom
 import whrandom
-import Floater
+import __builtin__
 
 
 # Colors used by all color menus
 # Colors used by all color menus
 DEFAULT_COLORS = [
 DEFAULT_COLORS = [
@@ -58,24 +38,6 @@ BUILDING_TYPES = ['10_10', '20', '10_20', '20_10', '10_10_10',
                   '12_8', '13_9_8'
                   '12_8', '13_9_8'
                   ]
                   ]
 
 
-# The list of neighborhoods to edit
-hoodIds = {'TT' : 'toontown_central',
-           'DD' : 'donalds_dock',
-           'MM' : 'minnies_melody_land',
-           'BR' : 'the_burrrgh',
-           'DG' : 'daisys_garden',
-           'DL' : 'donalds_dreamland',
-           }
-NEIGHBORHOODS = []
-NEIGHBORHOOD_CODES = {}
-for hoodId in hoods:
-    if hoodIds.has_key(hoodId):
-        hoodName = hoodIds[hoodId]
-        NEIGHBORHOOD_CODES[hoodName] = hoodId
-        NEIGHBORHOODS.append(hoodName)
-    else:
-        print 'Error: no hood defined for: ', hoodId
-
 OBJECT_SNAP_POINTS = {
 OBJECT_SNAP_POINTS = {
     'street_5x20': [(Vec3(5.0,0,0), Vec3(0)),
     'street_5x20': [(Vec3(5.0,0,0), Vec3(0)),
                     (Vec3(0), Vec3(0))],
                     (Vec3(0), Vec3(0))],
@@ -190,27 +152,74 @@ OBJECT_SNAP_POINTS = {
     }
     }
 SNAP_ANGLE = 15.0
 SNAP_ANGLE = 15.0
 
 
+# NEIGHBORHOOD DATA
+# If you run this from the command line you can pass in the hood codes
+# you want to load. For example:
+#    ppython LevelEditor.py DD TT BR
+#
+if sys.argv[1:]:
+    try:
+        opts, pargs = getopt.getopt(sys.argv[1:], '')
+        hoods = pargs
+    except Exception, e:
+        print e
+# If you do not run from the command line, we just load all of them
+# or you can hack this up for your own purposes.
+else:
+    hoodString = base.config.GetString('level-editor-hoods',
+                                       'TT DD BR DG DL MM')
+    hoods = string.split(hoodString)
+
+# The list of neighborhoods to edit
+hoodIds = {'TT' : 'toontown_central',
+           'DD' : 'donalds_dock',
+           'MM' : 'minnies_melody_land',
+           'BR' : 'the_burrrgh',
+           'DG' : 'daisys_garden',
+           'DL' : 'donalds_dreamland',
+           }
+
+# Init neighborhood arrays
+NEIGHBORHOODS = []
+NEIGHBORHOOD_CODES = {}
+for hoodId in hoods:
+    if hoodIds.has_key(hoodId):
+        hoodName = hoodIds[hoodId]
+        NEIGHBORHOOD_CODES[hoodName] = hoodId
+        NEIGHBORHOODS.append(hoodName)
+    else:
+        print 'Error: no hood defined for: ', hoodId
+
+# Load DNA
 try:
 try:
     if dnaLoaded:
     if dnaLoaded:
         pass
         pass
 except NameError:
 except NameError:
+    print "Loading LevelEditor for hoods: ", hoods
     # DNAStorage instance for storing level DNA info
     # DNAStorage instance for storing level DNA info
     __builtin__.DNASTORE = DNASTORE = DNAStorage()
     __builtin__.DNASTORE = DNASTORE = DNAStorage()
     # Load the generic storage file
     # Load the generic storage file
-    loadDNAFile(DNASTORE, 'phase_4/dna/storage.dna', CSDefault, 1)
+    loadDNAFile(DNASTORE,
+                'phase_4/dna/storage.dna', CSDefault, 1)
     # Load all the neighborhood specific storage files
     # Load all the neighborhood specific storage files
     if 'TT' in hoods:
     if 'TT' in hoods:
-        loadDNAFile(DNASTORE, 'phase_4/dna/storage_TT.dna', CSDefault, 1)
+        loadDNAFile(DNASTORE,
+                    'phase_4/dna/storage_TT.dna', CSDefault, 1)
     if 'DD' in hoods:
     if 'DD' in hoods:
-        loadDNAFile(DNASTORE, 'phase_6/dna/storage_DD.dna', CSDefault, 1)
+        loadDNAFile(DNASTORE,
+                    'phase_6/dna/storage_DD.dna', CSDefault, 1)
     if 'MM' in hoods:
     if 'MM' in hoods:
-        loadDNAFile(DNASTORE, 'phase_6/dna/storage_MM.dna', CSDefault, 1)
+        loadDNAFile(DNASTORE,
+                    'phase_6/dna/storage_MM.dna', CSDefault, 1)
     if 'BR' in hoods:
     if 'BR' in hoods:
-        loadDNAFile(DNASTORE, 'phase_8/dna/storage_BR.dna', CSDefault, 1)
+        loadDNAFile(DNASTORE,
+                    'phase_8/dna/storage_BR.dna', CSDefault, 1)
     if 'DG' in hoods:
     if 'DG' in hoods:
-        loadDNAFile(DNASTORE, 'phase_8/dna/storage_DG.dna', CSDefault, 1)
+        loadDNAFile(DNASTORE,
+                    'phase_8/dna/storage_DG.dna', CSDefault, 1)
     if 'DL' in hoods:
     if 'DL' in hoods:
-        loadDNAFile(DNASTORE, 'phase_8/dna/storage_DL.dna', CSDefault, 1)
+        loadDNAFile(DNASTORE,
+                    'phase_8/dna/storage_DL.dna', CSDefault, 1)
     __builtin__.dnaLoaded = 1
     __builtin__.dnaLoaded = 1
 
 
 # Precompute class types for type comparisons
 # Precompute class types for type comparisons
@@ -376,14 +385,14 @@ class LevelEditor(NodePath, PandaObject):
     # selectedDNARoot: DNA Node of currently selected object
     # selectedDNARoot: DNA Node of currently selected object
     # selectedNPRoot: Corresponding Node Path
     # selectedNPRoot: Corresponding Node Path
     # DNATarget: Subcomponent being modified by Pie Menu
     # DNATarget: Subcomponent being modified by Pie Menu
-    def __init__(self):
+    def __init__(self, hoods = hoods):
         # Make the level editor a node path so that you can show/hide
         # Make the level editor a node path so that you can show/hide
         # The level editor separately from loading/saving the top level node
         # The level editor separately from loading/saving the top level node
         # Initialize superclass
         # Initialize superclass
         NodePath.__init__(self)
         NodePath.__init__(self)
         # Become the new node path
         # Become the new node path
         self.assign(hidden.attachNewNode('LevelEditor'))
         self.assign(hidden.attachNewNode('LevelEditor'))
-        
+
         # Enable replaceSelected by default:
         # Enable replaceSelected by default:
         self.replaceSelectedEnabled=1
         self.replaceSelectedEnabled=1
         
         
@@ -517,6 +526,9 @@ class LevelEditor(NodePath, PandaObject):
         self.battleCellMarker.setScale(1)
         self.battleCellMarker.setScale(1)
         self.currentBattleCellType = "20w 20l"
         self.currentBattleCellType = "20w 20l"
 
 
+        # Update scene graph explorer
+        self.panel.sceneGraphExplorer.update()
+
     # ENABLE/DISABLE
     # ENABLE/DISABLE
     def enable(self):
     def enable(self):
         """ Enable level editing and show level """
         """ Enable level editing and show level """
@@ -551,7 +563,8 @@ class LevelEditor(NodePath, PandaObject):
         # Remove insertion marker task
         # Remove insertion marker task
         taskMgr.removeTasksNamed('insertionMarkerTask')
         taskMgr.removeTasksNamed('insertionMarkerTask')
 
 
-    def reset(self, fDeleteToplevel = 1, fCreateToplevel = 1):
+    def reset(self, fDeleteToplevel = 1, fCreateToplevel = 1,
+              fUpdateExplorer = 1):
         """
         """
         Reset level and re-initialize main class variables
         Reset level and re-initialize main class variables
         Pass in the new top level group
         Pass in the new top level group
@@ -602,6 +615,9 @@ class LevelEditor(NodePath, PandaObject):
         self.snapList = []
         self.snapList = []
         # Last menu used
         # Last menu used
         self.activeMenu = None
         self.activeMenu = None
+        # Update scene graph explorer
+        if fUpdateExplorer:
+            self.panel.sceneGraphExplorer.update()
 
 
     def deleteToplevel(self):
     def deleteToplevel(self):
         # Destory old toplevel node path and DNA
         # Destory old toplevel node path and DNA
@@ -609,7 +625,7 @@ class LevelEditor(NodePath, PandaObject):
         self.DNAData.remove(self.DNAToplevel)
         self.DNAData.remove(self.DNAToplevel)
         # Then the toplevel Node Path
         # Then the toplevel Node Path
         self.NPToplevel.reparentTo(hidden)
         self.NPToplevel.reparentTo(hidden)
-        self.NPToplevel.remove()
+        self.NPToplevel.removeNode()
 
 
     def createToplevel(self, dnaNode, nodePath = None):
     def createToplevel(self, dnaNode, nodePath = None):
         # When you create a new level, data is added to this node
         # When you create a new level, data is added to this node
@@ -627,8 +643,8 @@ class LevelEditor(NodePath, PandaObject):
         self.DNAParent = self.DNAToplevel
         self.DNAParent = self.DNAToplevel
         self.NPParent = self.NPToplevel
         self.NPParent = self.NPToplevel
         self.VGParent = None
         self.VGParent = None
-        # Update scene graph explorer
-        # self.panel.sceneGraphExplorer.update()
+        # Add toplevel node path for suit points
+        self.suitPointToplevel = self.NPToplevel.attachNewNode('suitPoints')
 
 
     def destroy(self):
     def destroy(self):
         """ Disable level editor and destroy node path """
         """ Disable level editor and destroy node path """
@@ -740,8 +756,8 @@ class LevelEditor(NodePath, PandaObject):
         dnaNode = self.findDNANode(nodePath)
         dnaNode = self.findDNANode(nodePath)
         # Does the node path correspond to a DNA Object
         # Does the node path correspond to a DNA Object
         if dnaNode:
         if dnaNode:
-            for i in self.removeHookList:
-                i(dnaNode, nodePath)
+            for hook in self.removeHookList:
+                hook(dnaNode, nodePath)
             # Get DNANode's parent
             # Get DNANode's parent
             parentDNANode = dnaNode.getParent()
             parentDNANode = dnaNode.getParent()
             if parentDNANode:
             if parentDNANode:
@@ -749,6 +765,43 @@ class LevelEditor(NodePath, PandaObject):
                 parentDNANode.remove(dnaNode)
                 parentDNANode.remove(dnaNode)
             # Delete DNA and associated Node Relations from DNA Store
             # Delete DNA and associated Node Relations from DNA Store
             DNASTORE.removeDNAGroup(dnaNode)
             DNASTORE.removeDNAGroup(dnaNode)
+        else:
+            pointOrCell, type = self.findPointOrCell(nodePath)
+            if pointOrCell and type:
+                if (type == 'suitPointMarker'):
+                    print 'Suit Point:', pointOrCell
+                    if DNASTORE.removeSuitPoint(pointOrCell):
+                        print "Removed from DNASTORE"
+                        del(self.pointDict[pointOrCell])
+                        # Update edge dict
+                        for edge in self.point2edgeDict[pointOrCell]:
+                            # Is it still in edge dict?
+                            oldEdgeLine = self.edgeDict.get(edge, None)
+                            if oldEdgeLine:
+                                del self.edgeDict[edge]
+                                oldEdgeLine.reset()
+                                del oldEdgeLine
+                    else:
+                        print "Not found in DNASTORE"
+                elif (type == 'battleCellMarker'):
+                    # Get parent vis group
+                    visGroupNP, visGroupDNA = self.findParentVisGroup(nodePath)
+                    print 'Battle Cell:', pointOrCell
+                    # Remove cell from vis group
+                    if visGroupNP and visGroupDNA:
+                        if visGroupDNA.removeBattleCell(pointOrCell):
+                            print "Removed from Vis Group"
+                        else:
+                            print "Not found in Vis Group"
+                    else:
+                        print "Parent Vis Group not found"
+                    # Remove cell from DNASTORE
+                    if DNASTORE.removeBattleCell(pointOrCell):
+                        print "Removed from DNASTORE"
+                    else:
+                        print "Not found in DNASTORE"
+                    # Remove cell from cellDict
+                    del(self.cellDict[pointOrCell])
 
 
     def reparent(self, nodePath, oldParent, newParent):
     def reparent(self, nodePath, oldParent, newParent):
         """ Move node path (and its DNA) to active parent """
         """ Move node path (and its DNA) to active parent """
@@ -972,7 +1025,7 @@ class LevelEditor(NodePath, PandaObject):
             # mouse position
             # mouse position
             hitPt = self.getGridIntersectionPoint()
             hitPt = self.getGridIntersectionPoint()
             # Attach a node, so we can set pos with respect to:
             # Attach a node, so we can set pos with respect to:
-            tempNode=hidden.attachNewNode('tempNode')
+            tempNode = hidden.attachNewNode('tempNode')
             # Place it:
             # Place it:
             tempNode.setPos(direct.grid, hitPt)
             tempNode.setPos(direct.grid, hitPt)
             # Copy the pos to where we really want it:
             # Copy the pos to where we really want it:
@@ -1685,6 +1738,17 @@ class LevelEditor(NodePath, PandaObject):
         for child in children:
         for child in children:
             childVisGroups = (childVisGroups + self.getDNAVisGroups(child))
             childVisGroups = (childVisGroups + self.getDNAVisGroups(child))
         return childVisGroups
         return childVisGroups
+
+    def findParentVisGroup(self, nodePath):
+        """ Find the containing vis group """
+        dnaNode = self.findDNANode(nodePath)
+        if dnaNode:
+            if DNAClassEqual(dnaNode, DNA_VIS_GROUP):
+                return nodePath, dnaNode
+        elif nodePath.hasParent():
+            return self.findParentVisGroup(nodePath.getParent())
+        else:
+            return None
     
     
     def showGrid(self,flag):
     def showGrid(self,flag):
         """ toggle direct grid """
         """ toggle direct grid """
@@ -1702,8 +1766,10 @@ class LevelEditor(NodePath, PandaObject):
         self.levelMap = hidden.attachNewNode('level-map')
         self.levelMap = hidden.attachNewNode('level-map')
         self.activeMap = None
         self.activeMap = None
         self.mapDictionary = {}
         self.mapDictionary = {}
+        """
         for neighborhood in NEIGHBORHOODS:
         for neighborhood in NEIGHBORHOODS:
             self.createMap(neighborhood)
             self.createMap(neighborhood)
+        """
 
 
     def createMap(self, neighborhood):
     def createMap(self, neighborhood):
         map = loader.loadModel('models/level_editor/' + neighborhood +
         map = loader.loadModel('models/level_editor/' + neighborhood +
@@ -1949,7 +2015,8 @@ class LevelEditor(NodePath, PandaObject):
 
 
     def loadDNAFromFile(self, filename):
     def loadDNAFromFile(self, filename):
         # Reset level, destroying existing scene/DNA hierarcy
         # Reset level, destroying existing scene/DNA hierarcy
-        self.reset(fDeleteToplevel = 1, fCreateToplevel = 0)
+        self.reset(fDeleteToplevel = 1, fCreateToplevel = 0,
+                   fUpdateExplorer = 0)
         # Now load in new file
         # Now load in new file
         node = loadDNAFile(DNASTORE, filename, CSDefault, 1)
         node = loadDNAFile(DNASTORE, filename, CSDefault, 1)
 
 
@@ -1957,7 +2024,8 @@ class LevelEditor(NodePath, PandaObject):
             # If the node already has a parent arc when it's loaded, we must
             # If the node already has a parent arc when it's loaded, we must
             # be using the level editor and we want to preserve that arc.
             # be using the level editor and we want to preserve that arc.
             newNPToplevel = NodePath()
             newNPToplevel = NodePath()
-            newNPToplevel.extendBy(node.getParent(RenderRelation.getClassType(), 0))
+            newNPToplevel.extendBy(node.getParent(
+                RenderRelation.getClassType(), 0))
             newNPToplevel.reparentTo(hidden)
             newNPToplevel.reparentTo(hidden)
         else:
         else:
             # Otherwise, we should create a new arc for the node.
             # Otherwise, we should create a new arc for the node.
@@ -1983,7 +2051,8 @@ class LevelEditor(NodePath, PandaObject):
         self.hideBattleCells()
         self.hideBattleCells()
         # Set the title bar to have the filename to make it easier
         # Set the title bar to have the filename to make it easier
         # to remember what file you are working on
         # to remember what file you are working on
-        self.panel["title"] = filename
+        self.panel["title"] = 'Level Editor: ' + os.path.basename(filename)
+        self.panel.sceneGraphExplorer.update()
 
 
     def outputDNADefaultFile(self):
     def outputDNADefaultFile(self):
         f = Filename(self.styleManager.stylePathPrefix +
         f = Filename(self.styleManager.stylePathPrefix +
@@ -2233,11 +2302,26 @@ class LevelEditor(NodePath, PandaObject):
         mat = self.NPToplevel.getMat(parent)
         mat = self.NPToplevel.getMat(parent)
         relStartPos = Point3(mat.xformPoint(edge.getStartPoint().getPos()))
         relStartPos = Point3(mat.xformPoint(edge.getStartPoint().getPos()))
         relEndPos = Point3(mat.xformPoint(edge.getEndPoint().getPos()))
         relEndPos = Point3(mat.xformPoint(edge.getEndPoint().getPos()))
+        # Compute offset: a vector rotated 90 degrees clockwise
+        offset = Vec3(relEndPos - relStartPos)
+        offset.normalize()
+        offset *= 0.1
+        a = offset[0]
+        offset.setX(offset[1])
+        offset.setY(-1 * a)
+        # Just to get it above the street
+        offset.setZ(0.05)
+        # Add offset to start and end to help differentiate lines
+        relStartPos += offset
+        relEndPos += offset
+        # Draw arrow
         edgeLine.drawArrow(relStartPos,
         edgeLine.drawArrow(relStartPos,
                            relEndPos,
                            relEndPos,
                            15, # arrow angle
                            15, # arrow angle
                            1) # arrow length
                            1) # arrow length
         edgeLine.create()
         edgeLine.create()
+        # Clean up:
+        tempNode.removeNode()
         return edgeLine
         return edgeLine
 
 
     def drawSuitPoint(self, pos, type, parent):
     def drawSuitPoint(self, pos, type, parent):
@@ -2268,7 +2352,8 @@ class LevelEditor(NodePath, PandaObject):
         suitPoint = DNASTORE.storeSuitPoint(self.currentSuitPointType, absPos)
         suitPoint = DNASTORE.storeSuitPoint(self.currentSuitPointType, absPos)
         if not self.pointDict.has_key(suitPoint):
         if not self.pointDict.has_key(suitPoint):
             marker = self.drawSuitPoint(
             marker = self.drawSuitPoint(
-                absPos, self.currentSuitPointType, self.NPToplevel)
+                absPos, self.currentSuitPointType,
+                self.suitPointToplevel)
             self.pointDict[suitPoint] = marker
             self.pointDict[suitPoint] = marker
         self.currentSuitPointIndex = suitPoint.getIndex()
         self.currentSuitPointIndex = suitPoint.getIndex()
 
 
@@ -2305,6 +2390,57 @@ class LevelEditor(NodePath, PandaObject):
             # First point, store it
             # First point, store it
             self.startSuitPoint = suitPoint
             self.startSuitPoint = suitPoint
 
 
+    def highlightConnected(self, nodePath = None, fReversePath = 0):
+        if nodePath == None:
+            nodePath = direct.selected.last
+        if nodePath:
+            suitPoint = self.findPointOrCell(nodePath)[0]
+            if suitPoint:
+                self.clearPathHighlights()
+                self.highlightConnectedRec(suitPoint, fReversePath)
+
+    def highlightConnectedRec(self, suitPoint, fReversePath):
+        nodePath = self.pointDict.get(suitPoint, None)
+        if nodePath:
+            # highlight marker
+            nodePath.setColor(1,0,0,1)
+            # Add point to visited points
+            self.visitedPoints.append(suitPoint)
+            # highlight connected edges
+            for edge in self.point2edgeDict[suitPoint]:
+                if ((fReversePath or (suitPoint == edge.getStartPoint())) and
+                    (edge not in self.visitedEdges)):
+                    edgeLine = self.edgeDict[edge]
+                    # Call node path not LineNodePath setColor
+                    NodePath.setColor(edgeLine,1,0,0,1)
+                    # Add edge to visited edges
+                    self.visitedEdges.append(edge)
+                    # Color components connected to the edge
+                    if fReversePath:
+                        startPoint = edge.getStartPoint()
+                        if startPoint not in self.visitedPoints:
+                            self.highlightConnectedRec(startPoint,
+                                                       fReversePath)
+                    endPoint = edge.getEndPoint()
+                    if endPoint not in self.visitedPoints:
+                        self.highlightConnectedRec(endPoint,
+                                                   fReversePath)
+
+    def clearPathHighlights(self):
+        for point in self.pointDict.keys():
+            type = point.getPointType()
+            marker = self.pointDict[point]
+            if (type == DNASuitPoint.STREETPOINT):
+                marker.setColor(0,0,0.6)
+            elif (type == DNASuitPoint.FRONTDOORPOINT):
+                marker.setColor(0,0,1)
+            elif (type == DNASuitPoint.SIDEDOORPOINT):
+                marker.setColor(0,0.2,0.4)
+        for edge in self.edgeDict.values():
+            edge.clearColor()
+        self.visitedPoints = []
+        self.visitedEdges = []
+
     def drawBattleCell(self, cell, parent):
     def drawBattleCell(self, cell, parent):
         marker = self.battleCellMarker.copyTo(parent)
         marker = self.battleCellMarker.copyTo(parent)
         # Greenish
         # Greenish
@@ -2349,7 +2485,8 @@ class LevelEditor(NodePath, PandaObject):
         for i in range(numPoints):
         for i in range(numPoints):
             point = DNASTORE.getSuitPointAtIndex(i)
             point = DNASTORE.getSuitPointAtIndex(i)
             marker = self.drawSuitPoint(
             marker = self.drawSuitPoint(
-                point.getPos(), point.getPointType(), self.NPToplevel)
+                point.getPos(), point.getPointType(),
+                self.suitPointToplevel)
             self.pointDict[point] = marker
             self.pointDict[point] = marker
 
 
         # Edges
         # Edges
@@ -2443,6 +2580,12 @@ class LevelEditor(NodePath, PandaObject):
                 return cell
                 return cell
         return None
         return None
 
 
+    def toggleZoneColors(self):
+        if self.panel.zoneColor.get():
+            self.colorZones()
+        else:
+            self.clearZoneColors()
+
     def colorZones(self):
     def colorZones(self):
         # Give each zone a random color to see them better
         # Give each zone a random color to see them better
         visGroups = self.getDNAVisGroups(self.NPToplevel)
         visGroups = self.getDNAVisGroups(self.NPToplevel)
@@ -2451,6 +2594,13 @@ class LevelEditor(NodePath, PandaObject):
             np.setColor(0.5 + random()/2.0,
             np.setColor(0.5 + random()/2.0,
                         0.5 + random()/2.0,
                         0.5 + random()/2.0,
                         0.5 + random()/2.0)
                         0.5 + random()/2.0)
+
+    def clearZoneColors(self):
+        # Clear random colors
+        visGroups = self.getDNAVisGroups(self.NPToplevel)
+        for visGroup in visGroups:
+            np = visGroup[0]
+            np.clearColor()
     
     
     def getBlockFromName(self, name):
     def getBlockFromName(self, name):
         block=name[2:name.find(':')]
         block=name[2:name.find(':')]
@@ -3225,7 +3375,7 @@ class LevelStyleManager:
                                                          sf = 0.25))
                                                          sf = 0.25))
             elif (dnaType == 'sign'):
             elif (dnaType == 'sign'):
                 attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
                 attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
-                                                         sf = 0.1))
+                                                         sf = 0.05))
             elif (dnaType == 'door'):
             elif (dnaType == 'door'):
                 attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
                 attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
                                                          sf = 0.035))
                                                          sf = 0.035))
@@ -3750,7 +3900,7 @@ class LevelEditorPanel(Pmw.MegaToplevel):
         self.fUpdateSelected = 1
         self.fUpdateSelected = 1
         # Handle to the toplevels hull
         # Handle to the toplevels hull
         hull = self.component('hull')
         hull = self.component('hull')
-        hull.geometry('400x680')
+        hull.geometry('400x550')
         
         
         balloon = self.balloon = Pmw.Balloon(hull)
         balloon = self.balloon = Pmw.Balloon(hull)
         # Start with balloon help disabled
         # Start with balloon help disabled
@@ -3836,7 +3986,7 @@ class LevelEditorPanel(Pmw.MegaToplevel):
             selectioncommand = self.levelEditor.setEditMode, history = 0,
             selectioncommand = self.levelEditor.setEditMode, history = 0,
             scrolledlist_items = NEIGHBORHOODS)
             scrolledlist_items = NEIGHBORHOODS)
         self.editMenu.selectitem(NEIGHBORHOODS[0])
         self.editMenu.selectitem(NEIGHBORHOODS[0])
-        self.editMenu.pack(side = 'left', expand = 0)
+        self.editMenu.pack(side = LEFT, expand = 0)
                                      
                                      
 
 
         # Create the notebook pages
         # Create the notebook pages
@@ -3845,72 +3995,22 @@ class LevelEditorPanel(Pmw.MegaToplevel):
         streetsPage = self.notebook.add('Streets')
         streetsPage = self.notebook.add('Streets')
         toonBuildingsPage = self.notebook.add('Toon Bldgs')
         toonBuildingsPage = self.notebook.add('Toon Bldgs')
         landmarkBuildingsPage = self.notebook.add('Landmark Bldgs')
         landmarkBuildingsPage = self.notebook.add('Landmark Bldgs')
-        suitPathPage = self.notebook.add('Paths')
-        battleCellPage = self.notebook.add('Cells')
         # suitBuildingsPage = self.notebook.add('Suit Buildings')
         # suitBuildingsPage = self.notebook.add('Suit Buildings')
         propsPage = self.notebook.add('Props')
         propsPage = self.notebook.add('Props')
         signPage = self.notebook.add('Signs')
         signPage = self.notebook.add('Signs')
+        suitPathPage = self.notebook.add('Paths')
+        battleCellPage = self.notebook.add('Cells')
         sceneGraphPage = self.notebook.add('SceneGraph')
         sceneGraphPage = self.notebook.add('SceneGraph')
         self.notebook['raisecommand'] = self.updateInfo
         self.notebook['raisecommand'] = self.updateInfo
 
 
-
-        self.fPaths = IntVar()
-        self.fPaths.set(0)
-        self.pathButton = Checkbutton(suitPathPage,
-                                      text = 'Show Paths',
-                                      width = 6,
-                                      variable = self.fPaths,
-                                      command = self.toggleSuitPaths)
-        self.pathButton.pack(side = 'top', expand = 1, fill = 'x')
-        self.suitPointSelector = Pmw.ComboBox(
-            suitPathPage,
-            dropdown = 0,
-            listheight = 200,
-            labelpos = W,
-            label_text = 'Point type:',
-            label_width = 12,
-            label_anchor = W,
-            entry_width = 30,
-            selectioncommand = self.setSuitPointType,
-            scrolledlist_items = ['street', 'front door', 'side door']
-            )
-        self.suitPointSelector.selectitem('street')
-        self.suitPointSelector.pack(expand = 1, fill = 'both')
-
-        self.fCells = IntVar()
-        self.fCells.set(0)
-        self.cellButton = Checkbutton(battleCellPage,
-                                      text = 'Show Cells',
-                                      width = 6,
-                                      variable = self.fCells,
-                                      command = self.toggleBattleCells)
-        self.cellButton.pack(side = 'top', expand = 1, fill = 'x')
-
-        self.colorZoneButton = Button(battleCellPage,
-                                      text = 'Color Zones',
-                                      command = self.levelEditor.colorZones)
-        self.colorZoneButton.pack(side = 'top', expand = 1, fill = 'x')
-
-        self.battleCellSelector = Pmw.ComboBox(
-            battleCellPage,
-            dropdown = 0,
-            listheight = 200,
-            labelpos = W,
-            label_text = 'Cell type:',
-            label_width = 12,
-            label_anchor = W,
-            entry_width = 30,
-            selectioncommand = self.setBattleCellType,
-            scrolledlist_items = ['20w 20l', '20w 30l', '30w 20l', '30w 30l']
-            )
-        self.battleCellSelector.selectitem('20w 20l')
-        self.battleCellSelector.pack(expand = 1, fill = 'both')
-
+        # STREETS
+        Label(streetsPage, text = 'Streets',
+              font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
         self.addStreetButton = Button(
         self.addStreetButton = Button(
             streetsPage,
             streetsPage,
             text = 'ADD STREET',
             text = 'ADD STREET',
             command = self.addStreet)
             command = self.addStreet)
-        self.addStreetButton.pack(fill = 'x')
+        self.addStreetButton.pack(fill = X, padx = 20, pady = 10)
         self.streetSelector = Pmw.ComboBox(
         self.streetSelector = Pmw.ComboBox(
             streetsPage,
             streetsPage,
             dropdown = 0,
             dropdown = 0,
@@ -3927,13 +4027,16 @@ class LevelEditorPanel(Pmw.MegaToplevel):
             )
             )
         self.streetModuleType = self.styleManager.getCatalogCode('street',0)
         self.streetModuleType = self.styleManager.getCatalogCode('street',0)
         self.streetSelector.selectitem(self.streetModuleType[7:])
         self.streetSelector.selectitem(self.streetModuleType[7:])
-        self.streetSelector.pack(expand = 1, fill = 'both')
+        self.streetSelector.pack(expand = 1, fill = BOTH)
 
 
+        # TOON BUILDINGS
+        Label(toonBuildingsPage, text = 'Toon Buildings',
+              font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
         self.addToonBuildingButton = Button(
         self.addToonBuildingButton = Button(
             toonBuildingsPage,
             toonBuildingsPage,
             text = 'ADD TOON BUILDING',
             text = 'ADD TOON BUILDING',
             command = self.addFlatBuilding)
             command = self.addFlatBuilding)
-        self.addToonBuildingButton.pack(fill = 'x')
+        self.addToonBuildingButton.pack(fill = X, padx = 20, pady = 10)
         self.toonBuildingSelector = Pmw.ComboBox(
         self.toonBuildingSelector = Pmw.ComboBox(
             toonBuildingsPage,
             toonBuildingsPage,
             dropdown = 0,
             dropdown = 0,
@@ -3948,19 +4051,22 @@ class LevelEditorPanel(Pmw.MegaToplevel):
             )
             )
         self.toonBuildingType = 'random20'
         self.toonBuildingType = 'random20'
         self.toonBuildingSelector.selectitem(self.toonBuildingType)
         self.toonBuildingSelector.selectitem(self.toonBuildingType)
-        self.toonBuildingSelector.pack(expand = 1, fill = 'both')
+        self.toonBuildingSelector.pack(expand = 1, fill = BOTH)
         
         
         #self.toonBuildingWidthScale = EntryScale.EntryScale(
         #self.toonBuildingWidthScale = EntryScale.EntryScale(
         #toonBuildingsPage, min = 1.0, max = 30.0,
         #toonBuildingsPage, min = 1.0, max = 30.0,
         #   resolution = 0.01, text = 'Wall Width',
         #   resolution = 0.01, text = 'Wall Width',
         #   command = self.updateSelectedWallWidth)
         #   command = self.updateSelectedWallWidth)
-        #self.toonBuildingWidthScale.pack(fill = 'x')
-        
+        #self.toonBuildingWidthScale.pack(fill = X)
+
+        # LANDMARK BUILDINGS
+        Label(landmarkBuildingsPage, text = 'Landmark Buildings',
+              font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
         self.addLandmarkBuildingButton = Button(
         self.addLandmarkBuildingButton = Button(
             landmarkBuildingsPage,
             landmarkBuildingsPage,
             text = 'ADD LANDMARK BUILDING',
             text = 'ADD LANDMARK BUILDING',
             command = self.addLandmark)
             command = self.addLandmark)
-        self.addLandmarkBuildingButton.pack(fill = 'x')
+        self.addLandmarkBuildingButton.pack(fill = X, padx = 20, pady = 10)
         self.landmarkBuildingSelector = Pmw.ComboBox(
         self.landmarkBuildingSelector = Pmw.ComboBox(
             landmarkBuildingsPage,
             landmarkBuildingsPage,
             dropdown = 0,
             dropdown = 0,
@@ -3979,14 +4085,16 @@ class LevelEditorPanel(Pmw.MegaToplevel):
             'toon_landmark',0)
             'toon_landmark',0)
         self.landmarkBuildingSelector.selectitem(
         self.landmarkBuildingSelector.selectitem(
             self.styleManager.getCatalogCode('toon_landmark',0)[14:])
             self.styleManager.getCatalogCode('toon_landmark',0)[14:])
-        self.landmarkBuildingSelector.pack(expand = 1, fill = 'both')
+        self.landmarkBuildingSelector.pack(expand = 1, fill = BOTH)
         
         
-        # Signs:
+        # SIGNS
+        Label(signPage, text = 'Signs',
+              font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
         self.currentSignDNA=None
         self.currentSignDNA=None
         self.currentBaselineDNA=None
         self.currentBaselineDNA=None
         self.levelEditor.selectedNodePathHookHooks.append(self.updateSignPage)
         self.levelEditor.selectedNodePathHookHooks.append(self.updateSignPage)
-        gridFrame = Frame(signPage)
 
 
+        gridFrame = Frame(signPage)
         signSelectedFrame = Frame(gridFrame)
         signSelectedFrame = Frame(gridFrame)
 
 
         self.currentBaselineIndex=0
         self.currentBaselineIndex=0
@@ -3998,17 +4106,17 @@ class LevelEditorPanel(Pmw.MegaToplevel):
             history = 0, # unique = 0,
             history = 0, # unique = 0,
             scrolledlist_items = ['<the sign>'])
             scrolledlist_items = ['<the sign>'])
         self.baselineMenu.selectitem(self.currentBaselineIndex)
         self.baselineMenu.selectitem(self.currentBaselineIndex)
-        self.baselineMenu.pack(side = 'left', expand = 1, fill = 'x')
+        self.baselineMenu.pack(side = LEFT, expand = 1, fill = X)
 
 
         self.baselineAddButton = Button(
         self.baselineAddButton = Button(
             signSelectedFrame, 
             signSelectedFrame, 
             text="Add Baseline", command=self.addBaseline)
             text="Add Baseline", command=self.addBaseline)
-        self.baselineAddButton.pack(side = 'left', expand = 1, fill = 'x')
+        self.baselineAddButton.pack(side = LEFT, expand = 1, fill = X)
 
 
         self.baselineDeleteButton = Button(
         self.baselineDeleteButton = Button(
             signSelectedFrame, 
             signSelectedFrame, 
             text="Del", command=self.deleteSignItem)
             text="Del", command=self.deleteSignItem)
-        self.baselineDeleteButton.pack(side = 'left', expand = 1, fill = 'x')
+        self.baselineDeleteButton.pack(side = LEFT, expand = 1, fill = X)
 
 
         signSelectedFrame.grid(row=0, column=0, columnspan=6)
         signSelectedFrame.grid(row=0, column=0, columnspan=6)
 
 
@@ -4044,21 +4152,22 @@ class LevelEditorPanel(Pmw.MegaToplevel):
             signButtonFrame,
             signButtonFrame,
             text = 'Big First Letter',
             text = 'Big First Letter',
             variable=self.bigFirstLetterIntVar, command=self.setBigFirstLetter)
             variable=self.bigFirstLetterIntVar, command=self.setBigFirstLetter)
-        self.bigFirstLetterCheckbutton.pack(side = 'left', expand = 1, fill = 'x')
+        self.bigFirstLetterCheckbutton.pack(
+            side = LEFT, expand = 1, fill = X)
 
 
         self.allCapsIntVar = IntVar()
         self.allCapsIntVar = IntVar()
         self.allCapsCheckbutton = Checkbutton(
         self.allCapsCheckbutton = Checkbutton(
             signButtonFrame,
             signButtonFrame,
             text = 'All Caps',
             text = 'All Caps',
             variable=self.allCapsIntVar, command=self.setAllCaps)
             variable=self.allCapsIntVar, command=self.setAllCaps)
-        self.allCapsCheckbutton.pack(side = 'left', expand = 1, fill = 'x')
+        self.allCapsCheckbutton.pack(side = LEFT, expand = 1, fill = X)
 
 
         self.dropShadowIntVar = IntVar()
         self.dropShadowIntVar = IntVar()
         self.dropShadowCheckbutton = Checkbutton(
         self.dropShadowCheckbutton = Checkbutton(
             signButtonFrame,
             signButtonFrame,
             text = 'Drop Shadow',
             text = 'Drop Shadow',
             variable=self.dropShadowIntVar, command=self.setDropShadow)
             variable=self.dropShadowIntVar, command=self.setDropShadow)
-        self.dropShadowCheckbutton.pack(side = 'left', expand = 1, fill = 'x')
+        self.dropShadowCheckbutton.pack(side = LEFT, expand = 1, fill = X)
         
         
         signButtonFrame.grid(row=3, column=0, columnspan=6)
         signButtonFrame.grid(row=3, column=0, columnspan=6)
 
 
@@ -4123,14 +4232,16 @@ class LevelEditorPanel(Pmw.MegaToplevel):
             command=self.setDNATargetRoll)
             command=self.setDNATargetRoll)
         self.addRollFloater.grid(row=12, column=3, rowspan=2, columnspan=3)
         self.addRollFloater.grid(row=12, column=3, rowspan=2, columnspan=3)
 
 
-        gridFrame.pack(fill='both')
+        gridFrame.pack(fill=BOTH)
 
 
-        # Props:
+        # PROPS
+        Label(propsPage, text = 'Props',
+              font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
         self.addPropsButton = Button(
         self.addPropsButton = Button(
             propsPage,
             propsPage,
             text = 'ADD PROP',
             text = 'ADD PROP',
             command = self.addProp)
             command = self.addProp)
-        self.addPropsButton.pack(fill = 'x')
+        self.addPropsButton.pack(fill = X, padx = 20, pady = 10)
         self.propSelector = Pmw.ComboBox(
         self.propSelector = Pmw.ComboBox(
             propsPage,
             propsPage,
             dropdown = 0,
             dropdown = 0,
@@ -4146,19 +4257,125 @@ class LevelEditorPanel(Pmw.MegaToplevel):
         self.propType = self.styleManager.getCatalogCode('prop',0)
         self.propType = self.styleManager.getCatalogCode('prop',0)
         self.propSelector.selectitem(
         self.propSelector.selectitem(
             self.styleManager.getCatalogCode('prop',0))
             self.styleManager.getCatalogCode('prop',0))
-        self.propSelector.pack(expand = 1, fill = 'both')
+        self.propSelector.pack(expand = 1, fill = BOTH)
 
 
+        # SUIT PATHS
+        Label(suitPathPage, text = 'Suit Paths',
+              font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
+
+        spButtons = Frame(suitPathPage)
+        self.fPaths = IntVar()
+        self.fPaths.set(0)
+        self.pathButton = Checkbutton(spButtons,
+                                      text = 'Show Paths',
+                                      width = 6,
+                                      variable = self.fPaths,
+                                      command = self.toggleSuitPaths)
+        self.pathButton.pack(side = LEFT, expand = 1, fill = X)
+
+        self.zoneColor = IntVar()
+        self.zoneColor.set(0)
+        self.colorZoneButton1 = Checkbutton(
+            spButtons,
+            text = 'Color Zones', width = 6,
+            variable = self.zoneColor,
+            command = self.levelEditor.toggleZoneColors)
+        self.colorZoneButton1.pack(side = LEFT, expand = 1, fill = X)
+        spButtons.pack(fill = X)
+
+        spButtons = Frame(suitPathPage)
+        Label(spButtons, text = 'Highlight:').pack(side = LEFT, fill = X)
+        self.highlightConnectedButton = Button(
+            spButtons,
+            text = 'Forward',
+            width = 6,
+            command = self.levelEditor.highlightConnected)
+        self.highlightConnectedButton.pack(side = LEFT, expand = 1, fill = X)
+
+        self.highlightConnectedButton2 = Button(
+            spButtons,
+            text = 'Connected',
+            width = 6,
+            command = lambda s = self: s.levelEditor.highlightConnected(fReversePath = 1))
+        self.highlightConnectedButton2.pack(side = LEFT, expand = 1, fill = X)
+
+        self.clearHighlightButton = Button(
+            spButtons,
+            text = 'Clear',
+            width = 6,
+            command = self.levelEditor.clearPathHighlights)
+        self.clearHighlightButton.pack(side = LEFT, expand = 1, fill = X)
+        spButtons.pack(fill = X, pady = 4)
+        
+        self.suitPointSelector = Pmw.ComboBox(
+            suitPathPage,
+            dropdown = 0,
+            listheight = 200,
+            labelpos = W,
+            label_text = 'Point type:',
+            label_width = 12,
+            label_anchor = W,
+            entry_width = 30,
+            selectioncommand = self.setSuitPointType,
+            scrolledlist_items = ['street', 'front door', 'side door']
+            )
+        self.suitPointSelector.selectitem('street')
+        self.suitPointSelector.pack(expand = 1, fill = BOTH)
+
+        # BATTLE CELLS
+        Label(battleCellPage, text = 'Battle Cells',
+              font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
+        bcButtons = Frame(battleCellPage)
+        self.fCells = IntVar()
+        self.fCells.set(0)
+        self.cellButton = Checkbutton(bcButtons,
+                                      text = 'Show Cells',
+                                      width = 6,
+                                      variable = self.fCells,
+                                      command = self.toggleBattleCells)
+        self.cellButton.pack(side = LEFT, expand = 1, fill = X)
+
+        self.colorZoneButton2 = Checkbutton(
+            bcButtons,
+            text = 'Color Zones', width = 6,
+            variable = self.zoneColor,
+            command = self.levelEditor.toggleZoneColors)
+        self.colorZoneButton2.pack(side = LEFT, expand = 1, fill = X)
+        bcButtons.pack(fill = X)
+
+        self.battleCellSelector = Pmw.ComboBox(
+            battleCellPage,
+            dropdown = 0,
+            listheight = 200,
+            labelpos = W,
+            label_text = 'Cell type:',
+            label_width = 12,
+            label_anchor = W,
+            entry_width = 30,
+            selectioncommand = self.setBattleCellType,
+            scrolledlist_items = ['20w 20l', '20w 30l', '30w 20l', '30w 30l']
+            )
+        self.battleCellSelector.selectitem('20w 20l')
+        self.battleCellSelector.pack(expand = 1, fill = BOTH)
+
+        # SCENE GRAPH EXPLORER
+        Label(sceneGraphPage, text = 'Level Scene Graph',
+              font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
+        self.sceneGraphExplorer = SceneGraphExplorer(
+            parent = sceneGraphPage,
+            nodePath = self.levelEditor,
+            menuItems = ['Add Group', 'Add Vis Group'])
+        self.sceneGraphExplorer.pack(expand = 1, fill = BOTH)
 
 
         # Compact down notebook
         # Compact down notebook
         self.notebook.setnaturalsize()
         self.notebook.setnaturalsize()
 
 
-
         self.colorEntry = VectorWidgets.ColorEntry(
         self.colorEntry = VectorWidgets.ColorEntry(
             hull, text = 'Select Color',
             hull, text = 'Select Color',
             command = self.updateSelectedObjColor)
             command = self.updateSelectedObjColor)
         self.colorEntry.menu.add_command(
         self.colorEntry.menu.add_command(
             label = 'Save Color', command = self.levelEditor.saveColor)
             label = 'Save Color', command = self.levelEditor.saveColor)
-        self.colorEntry.pack(fill = 'x')
+        self.colorEntry.pack(fill = X)
 
 
         buttonFrame = Frame(hull)
         buttonFrame = Frame(hull)
         self.fMapVis = IntVar()
         self.fMapVis = IntVar()
@@ -4168,7 +4385,7 @@ class LevelEditorPanel(Pmw.MegaToplevel):
                                       width = 6,
                                       width = 6,
                                       variable = self.fMapVis,
                                       variable = self.fMapVis,
                                       command = self.toggleMapVis)
                                       command = self.toggleMapVis)
-        self.mapSnapButton.pack(side = 'left', expand = 1, fill = 'x')
+        #self.mapSnapButton.pack(side = LEFT, expand = 1, fill = X)
 
 
         self.fXyzSnap = IntVar()
         self.fXyzSnap = IntVar()
         self.fXyzSnap.set(1)
         self.fXyzSnap.set(1)
@@ -4177,7 +4394,7 @@ class LevelEditorPanel(Pmw.MegaToplevel):
                                       width = 6,
                                       width = 6,
                                       variable = self.fXyzSnap,
                                       variable = self.fXyzSnap,
                                       command = self.toggleXyzSnap)
                                       command = self.toggleXyzSnap)
-        self.xyzSnapButton.pack(side = 'left', expand = 1, fill = 'x')
+        self.xyzSnapButton.pack(side = LEFT, expand = 1, fill = X)
 
 
         self.fHprSnap = IntVar()
         self.fHprSnap = IntVar()
         self.fHprSnap.set(1)
         self.fHprSnap.set(1)
@@ -4186,15 +4403,23 @@ class LevelEditorPanel(Pmw.MegaToplevel):
                                       width = 6,
                                       width = 6,
                                       variable = self.fHprSnap,
                                       variable = self.fHprSnap,
                                       command = self.toggleHprSnap)
                                       command = self.toggleHprSnap)
-        self.hprSnapButton.pack(side = 'left', expand = 1, fill = 'x')
+        self.hprSnapButton.pack(side = LEFT, expand = 1, fill = X)
 
 
+        def toggleWidgetHandles(s = self):
+            if s.fPlaneSnap.get():
+                direct.widget.disableHandles(['x-ring', 'x-disc',
+                                              'y-ring', 'y-disc',
+                                              'z-post'])
+            else:
+                direct.widget.enableHandles('all')
         self.fPlaneSnap = IntVar()
         self.fPlaneSnap = IntVar()
         self.fPlaneSnap.set(1)
         self.fPlaneSnap.set(1)
         self.planeSnapButton = Checkbutton(buttonFrame,
         self.planeSnapButton = Checkbutton(buttonFrame,
                                            text = 'PlaneSnap',
                                            text = 'PlaneSnap',
                                            width = 6,
                                            width = 6,
-                                           variable = self.fPlaneSnap)
-        self.planeSnapButton.pack(side = 'left', expand = 1, fill = 'x')
+                                           variable = self.fPlaneSnap,
+                                           command = toggleWidgetHandles)
+        self.planeSnapButton.pack(side = LEFT, expand = 1, fill = X)
 
 
         self.fGrid = IntVar()
         self.fGrid = IntVar()
         self.fGrid.set(0)
         self.fGrid.set(0)
@@ -4203,7 +4428,7 @@ class LevelEditorPanel(Pmw.MegaToplevel):
                                       width = 6,
                                       width = 6,
                                       variable = self.fGrid,
                                       variable = self.fGrid,
                                       command = self.toggleGrid)
                                       command = self.toggleGrid)
-        direct.gridButton.pack(side = 'left', expand = 1, fill = 'x')
+        direct.gridButton.pack(side = LEFT, expand = 1, fill = X)
         buttonFrame.pack(fill = X)
         buttonFrame.pack(fill = X)
 
 
         buttonFrame4 = Frame(hull)
         buttonFrame4 = Frame(hull)
@@ -4215,21 +4440,15 @@ class LevelEditorPanel(Pmw.MegaToplevel):
             value = 0,
             value = 0,
             variable = self.driveMode,
             variable = self.driveMode,
             command = self.levelEditor.useDriveMode)
             command = self.levelEditor.useDriveMode)
-        self.driveModeButton.pack(side = 'left', expand = 1, fill = 'x')
-        directModeButton = Radiobutton(
+        self.driveModeButton.pack(side = LEFT, fill = X, expand = 1)
+        self.directModeButton = Radiobutton(
             buttonFrame4,
             buttonFrame4,
             text = 'DIRECT Fly',
             text = 'DIRECT Fly',
             value = 1,
             value = 1,
             variable = self.driveMode,
             variable = self.driveMode,
             command = self.levelEditor.useDirectFly)
             command = self.levelEditor.useDirectFly)
-        directModeButton.pack(side = 'left', expand = 1, fill = 'x')
-        buttonFrame4.pack(fill = X)
-
-        self.sceneGraphExplorer = SceneGraphExplorer(
-            parent = sceneGraphPage,
-            nodePath = self.levelEditor,
-            menuItems = ['Add Group', 'Add Vis Group', 'Set Color'])
-        self.sceneGraphExplorer.pack(expand = 1, fill = BOTH)
+        self.directModeButton.pack(side = LEFT, fill = X, expand = 1)
+        buttonFrame4.pack(fill = X, padx = 60)
         
         
         # Make sure input variables processed 
         # Make sure input variables processed 
         self.initialiseoptions(LevelEditorPanel)
         self.initialiseoptions(LevelEditorPanel)
@@ -4755,7 +4974,7 @@ class VisGroupsEditor(Pmw.MegaToplevel):
                                usehullsize = 1, hull_width = 200,
                                usehullsize = 1, hull_width = 200,
                                hull_height = 400)
                                hull_height = 400)
         frame = sf.interior()
         frame = sf.interior()
-        sf.pack(padx=5, pady=3, fill = 'both', expand = 1)
+        sf.pack(padx=5, pady=3, fill = BOTH, expand = 1)
 
 
         # Add vis groups selector
         # Add vis groups selector
         self.selected = Pmw.RadioSelect(frame, selectmode=MULTIPLE,
         self.selected = Pmw.RadioSelect(frame, selectmode=MULTIPLE,
@@ -4779,7 +4998,7 @@ class VisGroupsEditor(Pmw.MegaToplevel):
         sf.reposition()
         sf.reposition()
 
 
         buttonFrame = Frame(hull)
         buttonFrame = Frame(hull)
-        buttonFrame.pack(fill='x', expand = 1)
+        buttonFrame.pack(fill=X, expand = 1)
 
 
         self.showMode = IntVar()
         self.showMode = IntVar()
         self.showMode.set(0)
         self.showMode.set(0)
@@ -4787,12 +5006,12 @@ class VisGroupsEditor(Pmw.MegaToplevel):
                                          value = 0, indicatoron = 1,
                                          value = 0, indicatoron = 1,
                                          variable = self.showMode,
                                          variable = self.showMode,
                                          command = self.refreshVisibility)
                                          command = self.refreshVisibility)
-        self.showAllButton.pack(side = LEFT, fill = 'x', expand = 1)
+        self.showAllButton.pack(side = LEFT, fill = X, expand = 1)
         self.showActiveButton = Radiobutton(buttonFrame, text = 'Show Target',
         self.showActiveButton = Radiobutton(buttonFrame, text = 'Show Target',
                                             value = 1, indicatoron = 1,
                                             value = 1, indicatoron = 1,
                                             variable = self.showMode,
                                             variable = self.showMode,
                                             command = self.refreshVisibility)
                                             command = self.refreshVisibility)
-        self.showActiveButton.pack(side = LEFT, fill = 'x', expand = 1)
+        self.showActiveButton.pack(side = LEFT, fill = X, expand = 1)
 
 
         # Make sure input variables processed 
         # Make sure input variables processed 
         self.initialiseoptions(VisGroupsEditor)
         self.initialiseoptions(VisGroupsEditor)

+ 10 - 5
direct/src/tkwidgets/SceneGraphExplorer.py

@@ -12,7 +12,7 @@ DEFAULT_MENU_ITEMS = [
     'Separator',
     'Separator',
     'Fit', 'Flash', 'Isolate', 'Toggle Vis', 'Show All',
     'Fit', 'Flash', 'Isolate', 'Toggle Vis', 'Show All',
     'Separator',
     'Separator',
-    'Place', 'Set Color',
+    'Place', 'Set Color', 'Explore',
     'Separator']
     'Separator']
 
 
 class SceneGraphExplorer(Pmw.MegaWidget, PandaObject):
 class SceneGraphExplorer(Pmw.MegaWidget, PandaObject):
@@ -41,7 +41,7 @@ class SceneGraphExplorer(Pmw.MegaWidget, PandaObject):
             'scrolledCanvas',
             'scrolledCanvas',
             (), None,
             (), None,
             Pmw.ScrolledCanvas, (interior,),
             Pmw.ScrolledCanvas, (interior,),
-            hull_width = 200, hull_height = 500,
+            hull_width = 200, hull_height = 300,
             usehullsize = 1)
             usehullsize = 1)
         self._canvas = self._scrolledCanvas.component('canvas')
         self._canvas = self._scrolledCanvas.component('canvas')
         self._canvas['scrollregion'] = ('0i', '0i', '2i', '4i')
         self._canvas['scrollregion'] = ('0i', '0i', '2i', '4i')
@@ -53,7 +53,8 @@ class SceneGraphExplorer(Pmw.MegaWidget, PandaObject):
         self._canvas.bind('<Configure>',
         self._canvas.bind('<Configure>',
                           lambda e, sc = self._scrolledCanvas:
                           lambda e, sc = self._scrolledCanvas:
                           sc.resizescrollregion())
                           sc.resizescrollregion())
-
+        self.interior().bind('<Destroy>', self.onDestroy)
+        
         # Create the contents
         # Create the contents
         self._treeItem = SceneGraphExplorerItem(self.nodePath)
         self._treeItem = SceneGraphExplorerItem(self.nodePath)
 
 
@@ -68,7 +69,7 @@ class SceneGraphExplorer(Pmw.MegaWidget, PandaObject):
             Label, (interior,),
             Label, (interior,),
             text = 'Active Parent: ',
             text = 'Active Parent: ',
             anchor = W, justify = LEFT)
             anchor = W, justify = LEFT)
-        self._label.pack(expand = 1, fill = X)
+        self._label.pack(fill = X)
 
 
         # Add update parent label
         # Add update parent label
         def updateLabel(nodePath = None, s = self):
         def updateLabel(nodePath = None, s = self):
@@ -108,6 +109,10 @@ class SceneGraphExplorer(Pmw.MegaWidget, PandaObject):
         self._left = self._canvas.xview()[0]
         self._left = self._canvas.xview()[0]
         self._top = self._canvas.yview()[0]
         self._top = self._canvas.yview()[0]
 
 
+    def onDestroy(self, event):
+        # Remove hooks
+        self.ignore('DIRECT_activeParent')
+        self.ignore('SGE_Update Explorer')
 
 
 class SceneGraphExplorerItem(TreeItem):
 class SceneGraphExplorerItem(TreeItem):
 
 
@@ -126,7 +131,7 @@ class SceneGraphExplorerItem(TreeItem):
 
 
     def SetText(self, text):
     def SetText(self, text):
         try:
         try:
-            self.nodePath.node().setName(text)
+            self.nodePath.setName(text)
         except AttributeError:
         except AttributeError:
             pass
             pass
 
 

+ 7 - 2
direct/src/tkwidgets/Tree.py

@@ -188,8 +188,6 @@ class TreeNode:
         if self.state != 'expanded':
         if self.state != 'expanded':
             return y+17
             return y+17
         # draw children
         # draw children
-        #if not self.children:
-        #self.children = []
         sublist = self.item._GetSubList()
         sublist = self.item._GetSubList()
         if not sublist:
         if not sublist:
             # IsExpandable() was mistaken; that's allowed
             # IsExpandable() was mistaken; that's allowed
@@ -203,6 +201,10 @@ class TreeNode:
                 child = TreeNode(self.canvas, self, item, self.menuList)
                 child = TreeNode(self.canvas, self, item, self.menuList)
             self.children[key] = child
             self.children[key] = child
             self.kidKeys.append(key)
             self.kidKeys.append(key)
+        # Remove unused children
+        for key in self.children.keys():
+            if key not in self.kidKeys:
+                del(self.children[key])
         cx = x+20
         cx = x+20
         cy = y+17
         cy = y+17
         cylast = 0
         cylast = 0
@@ -275,6 +277,9 @@ class TreeNode:
         self.label.bind("<1>", self.select_or_edit)
         self.label.bind("<1>", self.select_or_edit)
         self.label.bind("<Double-1>", self.flip)
         self.label.bind("<Double-1>", self.flip)
         self.label.bind("<3>", self.popupMenu)
         self.label.bind("<3>", self.popupMenu)
+        # Update text if necessary
+        if text != self.label['text']:
+            self.label['text'] = text
         self.text_id = id
         self.text_id = id
 
 
     def select_or_edit(self, event=None):
     def select_or_edit(self, event=None):