Browse Source

Added support for multiple windows

Gyedo Jeon 16 years ago
parent
commit
0ad1e310d3

+ 2 - 1
direct/src/directtools/DirectGlobals.py

@@ -30,7 +30,8 @@ SKIP_HIDDEN = 1
 SKIP_BACKFACE = 2
 SKIP_BACKFACE = 2
 SKIP_CAMERA = 4
 SKIP_CAMERA = 4
 SKIP_UNPICKABLE = 8
 SKIP_UNPICKABLE = 8
-SKIP_ALL = SKIP_HIDDEN | SKIP_BACKFACE | SKIP_CAMERA | SKIP_UNPICKABLE
+SKIP_WIDGET = 16
+SKIP_ALL = SKIP_HIDDEN | SKIP_BACKFACE | SKIP_CAMERA | SKIP_UNPICKABLE | SKIP_WIDGET
 
 
 # bit flags for indicating how editable an object is
 # bit flags for indicating how editable an object is
 EDIT_TYPE_UNMOVABLE = 1
 EDIT_TYPE_UNMOVABLE = 1

+ 364 - 68
direct/src/directtools/DirectManipulation.py

@@ -30,10 +30,12 @@ class DirectManipulationControl(DirectObject):
             ['DIRECT-mouse1', self.manipulationStart],
             ['DIRECT-mouse1', self.manipulationStart],
             ['DIRECT-mouse1Up', self.manipulationStop],
             ['DIRECT-mouse1Up', self.manipulationStop],
             ['tab', self.toggleObjectHandlesMode],
             ['tab', self.toggleObjectHandlesMode],
-            ['.', self.objectHandles.multiplyScalingFactorBy, 2.0],
-            ['>', self.objectHandles.multiplyScalingFactorBy, 2.0],
-            [',', self.objectHandles.multiplyScalingFactorBy, 0.5],
-            ['<', self.objectHandles.multiplyScalingFactorBy, 0.5],
+##             ['.', self.objectHandles.multiplyScalingFactorBy, 2.0],
+##             ['>', self.objectHandles.multiplyScalingFactorBy, 2.0],
+##             [',', self.objectHandles.multiplyScalingFactorBy, 0.5],
+##             ['<', self.objectHandles.multiplyScalingFactorBy, 0.5],
+            ['DIRECT-widgetScaleUp', self.scaleWidget, 2.0],
+            ['DIRECT-widgetScaleDown', self.scaleWidget, 0.5],
             ['shift-f', self.objectHandles.growToFit],
             ['shift-f', self.objectHandles.growToFit],
             ['i', self.plantSelectedNodePath],
             ['i', self.plantSelectedNodePath],
             ]
             ]
@@ -41,8 +43,48 @@ class DirectManipulationControl(DirectObject):
         self.optionalSkipFlags = 0
         self.optionalSkipFlags = 0
         self.unmovableTagList = []
         self.unmovableTagList = []
 
 
-        # [gjeon] to enable selection while other manipulation is disabled
+        # [gjeon] flag to enable selection while other manipulation is disabled
         self.fAllowSelectionOnly = 0
         self.fAllowSelectionOnly = 0
+
+        # [gjeon] flag to enable marquee selection feature
+        self.fAllowMarquee = 0
+        self.marquee = None
+
+        # [gjeon] for new LE's multi-view support
+        self.fMultiView = 0
+
+    def scaleWidget(self, factor):
+        if hasattr(base.direct, 'widget'):
+            base.direct.widget.multiplyScalingFactorBy(factor)
+        else:
+            self.objectHandles.multiplyScalingFactorBy(factor)
+        
+    def supportMultiView(self):
+        if self.fMultiView:
+            return
+        
+        self.objectHandles.hide(BitMask32.bit(0))
+        self.objectHandles.hide(BitMask32.bit(1))
+        self.objectHandles.hide(BitMask32.bit(2))
+
+        self.topViewWidget = ObjectHandles('topViewWidget')
+        self.frontViewWidget = ObjectHandles('frontViewWidget')
+        self.leftViewWidget = ObjectHandles('leftViewWidget')
+        self.widgetList = [self.topViewWidget, self.frontViewWidget, self.leftViewWidget, self.objectHandles]
+
+        self.topViewWidget.hide(BitMask32.bit(1))
+        self.topViewWidget.hide(BitMask32.bit(2))
+        self.topViewWidget.hide(BitMask32.bit(3))
+
+        self.frontViewWidget.hide(BitMask32.bit(0))
+        self.frontViewWidget.hide(BitMask32.bit(2))
+        self.frontViewWidget.hide(BitMask32.bit(3))
+
+        self.leftViewWidget.hide(BitMask32.bit(0))
+        self.leftViewWidget.hide(BitMask32.bit(1))
+        self.leftViewWidget.hide(BitMask32.bit(3))
+
+        self.fMultiView = 1
         
         
     def manipulationStart(self, modifiers):
     def manipulationStart(self, modifiers):
         # Start out in select mode
         # Start out in select mode
@@ -55,7 +97,7 @@ class DirectManipulationControl(DirectObject):
             return
             return
 
 
         # Check for a widget hit point
         # Check for a widget hit point
-        entry = base.direct.iRay.pickWidget()
+        entry = base.direct.iRay.pickWidget(skipFlags = SKIP_WIDGET)
         # Did we hit a widget?
         # Did we hit a widget?
         if entry:
         if entry:
             # Yes!
             # Yes!
@@ -67,21 +109,33 @@ class DirectManipulationControl(DirectObject):
             # Nope, off the widget, no constraint
             # Nope, off the widget, no constraint
             self.constraint = None
             self.constraint = None
             # [gjeon] to prohibit unwanted object movement while direct window doesn't have focus
             # [gjeon] to prohibit unwanted object movement while direct window doesn't have focus
-            if base.direct.cameraControl.useMayaCamControls and not base.direct.gotControl(modifiers):
+            if base.direct.cameraControl.useMayaCamControls and not base.direct.gotControl(modifiers) \
+               and not self.fAllowMarquee:
                 return
                 return
         
         
         if not base.direct.gotAlt(modifiers):
         if not base.direct.gotAlt(modifiers):
-            # Check to see if we are moving the object
-            # We are moving the object if we either wait long enough
-            taskMgr.doMethodLater(MANIPULATION_MOVE_DELAY,
-                                  self.switchToMoveMode,
-                                  'manip-move-wait')
-            # Or we move far enough
-            self.moveDir = None
-            watchMouseTask = Task.Task(self.watchMouseTask)
-            watchMouseTask.initX = base.direct.dr.mouseX
-            watchMouseTask.initY = base.direct.dr.mouseY
-            taskMgr.add(watchMouseTask, 'manip-watch-mouse')
+            if entry:
+                # Check to see if we are moving the object
+                # We are moving the object if we either wait long enough
+                taskMgr.doMethodLater(MANIPULATION_MOVE_DELAY,
+                                      self.switchToMoveMode,
+                                      'manip-move-wait')
+                # Or we move far enough
+                self.moveDir = None
+                watchMouseTask = Task.Task(self.watchMouseTask)
+                watchMouseTask.initX = base.direct.dr.mouseX
+                watchMouseTask.initY = base.direct.dr.mouseY
+                taskMgr.add(watchMouseTask, 'manip-watch-mouse')
+            else:
+                if base.direct.fControl:
+                    self.mode = 'move'
+                    self.manipulateObject()
+                elif not base.direct.fAlt and self.fAllowMarquee:
+                    self.moveDir = None
+                    watchMarqueeTask = Task.Task(self.watchMarqueeTask)
+                    watchMarqueeTask.initX = base.direct.dr.mouseX
+                    watchMarqueeTask.initY = base.direct.dr.mouseY
+                    taskMgr.add(watchMarqueeTask, 'manip-marquee-mouse')
 
 
     def switchToMoveMode(self, state):
     def switchToMoveMode(self, state):
         taskMgr.remove('manip-watch-mouse')
         taskMgr.remove('manip-watch-mouse')
@@ -99,10 +153,47 @@ class DirectManipulationControl(DirectObject):
         else:
         else:
             return Task.cont
             return Task.cont
 
 
+    def watchMarqueeTask(self, state):
+        taskMgr.remove('manip-watch-mouse')
+        taskMgr.remove('manip-move-wait')  
+        self.mode = 'select'
+        self.drawMarquee(state.initX, state.initY)
+        return Task.cont
+
+    def drawMarquee(self, startX, startY):
+        if self.marquee:
+            self.marquee.remove()
+            self.marquee = None
+
+        if base.direct.cameraControl.useMayaCamControls and base.direct.fAlt:
+            return
+
+        endX = base.direct.dr.mouseX
+        endY = base.direct.dr.mouseY
+
+        if (((abs (endX - startX)) < 0.01) and
+            ((abs (endY - startY)) < 0.01)):
+            return
+
+        self.marquee = LineNodePath(render2d, 'marquee', 0.5, VBase4(.8, .6, .6, 1))
+        self.marqueeInfo = (startX, startY, endX, endY)
+        self.marquee.drawLines([
+            [(startX, 0, startY), (startX, 0, endY)],
+            [(startX, 0, endY), (endX, 0, endY)],
+            [(endX, 0, endY), (endX, 0, startY)],
+            [(endX, 0, startY), (startX, 0, startY)]])
+        self.marquee.create()
+
+        if self.fMultiView:
+            for i in range(4):
+                if i != base.camList.index(NodePath(base.direct.camNode)):
+                    self.marquee.hide(BitMask32.bit(i))
+        
     def manipulationStop(self):
     def manipulationStop(self):
         taskMgr.remove('manipulateObject')
         taskMgr.remove('manipulateObject')
         taskMgr.remove('manip-move-wait')
         taskMgr.remove('manip-move-wait')
         taskMgr.remove('manip-watch-mouse')
         taskMgr.remove('manip-watch-mouse')
+        taskMgr.remove('manip-marquee-mouse')
         # depending on flag.....
         # depending on flag.....
         if self.mode == 'select':
         if self.mode == 'select':
             # Check for object under mouse
             # Check for object under mouse
@@ -111,17 +202,123 @@ class DirectManipulationControl(DirectObject):
             skipFlags = self.defaultSkipFlags | self.optionalSkipFlags
             skipFlags = self.defaultSkipFlags | self.optionalSkipFlags
             # Skip camera (and its children), unless control key is pressed
             # Skip camera (and its children), unless control key is pressed
             skipFlags |= SKIP_CAMERA * (1 - base.getControl())
             skipFlags |= SKIP_CAMERA * (1 - base.getControl())
-            entry = base.direct.iRay.pickGeom(skipFlags = skipFlags)
-            if entry:
-                # Record hit point information
-                self.hitPt.assign(entry.getSurfacePoint(entry.getFromNodePath()))
-                self.hitPtDist = Vec3(self.hitPt).length()
-                # Select it
-                base.direct.select(entry.getIntoNodePath(), base.direct.fShift)
-            else:
+
+            if self.marquee:
+                self.marquee.remove()
+                self.marquee = None
                 base.direct.deselectAll()
                 base.direct.deselectAll()
+
+                startX = self.marqueeInfo[0]
+                startY = self.marqueeInfo[1]
+                endX = self.marqueeInfo[2]
+                endY = self.marqueeInfo[3]
+
+                fll = Point3(0, 0, 0)
+                flr = Point3(0, 0, 0)
+                fur = Point3(0, 0, 0)
+                ful = Point3(0, 0, 0)
+                nll = Point3(0, 0, 0)
+                nlr = Point3(0, 0, 0)
+                nur = Point3(0, 0, 0)
+                nul = Point3(0, 0, 0)
+
+                lens = base.direct.cam.node().getLens()
+                lens.extrude((startX, startY), nul, ful)
+                lens.extrude((endX, startY), nur, fur)
+                lens.extrude((endX, endY), nlr, flr)
+                lens.extrude((startX, endY), nll, fll)
+
+                marqueeFrustum = BoundingHexahedron(fll, flr, fur, ful, nll, nlr, nur, nul);
+                marqueeFrustum.xform(base.direct.cam.getNetTransform().getMat())
+
+                base.marqueeFrustum = marqueeFrustum
+
+                def findTaggedNodePath(nodePath):
+                    # Select tagged object if present
+                    for tag in base.direct.selected.tagList:
+                        if nodePath.hasNetTag(tag):
+                            nodePath = nodePath.findNetTag(tag)
+                            return nodePath
+                    return None
+
+                selectionList = []
+                for geom in render.findAllMatches("**/+GeomNode"):
+                    if (skipFlags & SKIP_HIDDEN) and geom.isHidden():
+                        # Skip if hidden node
+                        continue
+##                     elif (skipFlags & SKIP_BACKFACE) and base.direct.iRay.isEntryBackfacing():
+##                         # Skip, if backfacing poly
+##                         pass
+                    elif ((skipFlags & SKIP_CAMERA) and
+                          (camera in geom.getAncestors())):
+                        # Skip if parented to a camera.
+                        continue
+                    # Can pick unpickable, use the first visible node
+                    elif ((skipFlags & SKIP_UNPICKABLE) and
+                          (geom.getName() in base.direct.iRay.unpickable)):
+                        # Skip if in unpickable list
+                        continue
+
+                    nodePath = findTaggedNodePath(geom)
+                    if nodePath in selectionList:
+                        continue
+    
+                    bb = geom.getBounds()
+                    bbc = bb.makeCopy()
+                    bbc.xform(geom.getParent().getNetTransform().getMat())
+
+                    boundingSphereTest = marqueeFrustum.contains(bbc)
+                    if boundingSphereTest > 1:
+                        if boundingSphereTest == 7:
+                            print "boundingSphere is all in, selecting ", geom
+
+                            if nodePath not in selectionList:
+                                selectionList.append(nodePath)
+                        else:
+                            tMat = Mat4(geom.getMat())
+                            geom.clearMat()
+                            # Get bounds
+                            min = Point3(0)
+                            max = Point3(0)
+                            geom.calcTightBounds(min, max)
+                            # Restore transform
+                            geom.setMat(tMat)                                
+
+                            fll = Point3(min[0], max[1], min[2])
+                            flr = Point3(max[0], max[1], min[2])
+                            fur = max
+                            ful = Point3(min[0], max[1], max[2])
+                            nll = min
+                            nlr = Point3(max[0], min[1], min[2])
+                            nur = Point3(max[0], min[1], max[2])
+                            nul = Point3(min[0], min[1], max[2])
+
+                            tbb = BoundingHexahedron(fll, flr, fur, ful, nll, nlr, nur, nul)
+
+                            tbb.xform(geom.getNetTransform().getMat())
+
+                            tightBoundTest = marqueeFrustum.contains(tbb)
+
+                            if tightBoundTest > 1:
+                                if nodePath not in selectionList:
+                                    selectionList.append(nodePath)
+
+                for nodePath in selectionList:
+                    base.direct.select(nodePath, 1)
+
+            else:
+                entry = base.direct.iRay.pickGeom(skipFlags = skipFlags)
+                if entry:
+                    # Record hit point information
+                    self.hitPt.assign(entry.getSurfacePoint(entry.getFromNodePath()))
+                    self.hitPtDist = Vec3(self.hitPt).length()
+                    # Select it
+                    base.direct.select(entry.getIntoNodePath(), base.direct.fShift)
+                else:
+                    base.direct.deselectAll()
         elif self.mode == 'move':
         elif self.mode == 'move':
             self.manipulateObjectCleanup()
             self.manipulateObjectCleanup()
+            
         self.mode = None
         self.mode = None
 
 
     def manipulateObjectCleanup(self):
     def manipulateObjectCleanup(self):
@@ -161,7 +358,11 @@ class DirectManipulationControl(DirectObject):
         taskMgr.add(t, 'followSelectedNodePath')
         taskMgr.add(t, 'followSelectedNodePath')
 
 
     def followSelectedNodePathTask(self, state):
     def followSelectedNodePathTask(self, state):
-        base.direct.widget.setPosHpr(state.base, state.pos, state.hpr)
+        if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
+            for widget in base.direct.manipulationControl.widgetList:
+                widget.setPosHpr(state.base, state.pos, state.hpr)
+        else:
+            base.direct.widget.setPosHpr(state.base, state.pos, state.hpr)            
         return Task.cont
         return Task.cont
 
 
     def enableManipulation(self):
     def enableManipulation(self):
@@ -293,17 +494,22 @@ class DirectManipulationControl(DirectObject):
         # Widget takes precedence
         # Widget takes precedence
         if self.constraint:
         if self.constraint:
             type = self.constraint[2:]
             type = self.constraint[2:]
-            if type == 'post' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
-                # [gjeon] to enable non-uniform scaling
-                if base.direct.fControl and not self.currEditTypes & EDIT_TYPE_UNSCALABLE:
+            if base.direct.fControl and not self.currEditTypes & EDIT_TYPE_UNSCALABLE:
+                if type == 'post':
+                    # [gjeon] non-uniform scaling
                     self.fScaling = 1
                     self.fScaling = 1
                     self.scale1D(state)
                     self.scale1D(state)
                 else:
                 else:
+                    # [gjeon] uniform scaling
+                    self.fScaling = 1
+                    self.scale3D(state)                    
+            else:
+                if type == 'post' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
                     self.xlate1D(state)
                     self.xlate1D(state)
-            elif type == 'disc' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
-                self.xlate2D(state)
-            elif type == 'ring' and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
-                self.rotate1D(state)
+                elif type == 'disc' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
+                    self.xlate2D(state)
+                elif type == 'ring' and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
+                    self.rotate1D(state)
         # No widget interaction, determine free manip mode
         # No widget interaction, determine free manip mode
         elif self.fFreeManip:
         elif self.fFreeManip:
             # If we've been scaling and changed modes, reset object handles
             # If we've been scaling and changed modes, reset object handles
@@ -362,7 +568,11 @@ class DirectManipulationControl(DirectObject):
         else:
         else:
             # Move widget to keep hit point as close to mouse as possible
             # Move widget to keep hit point as close to mouse as possible
             offset = self.hitPt - self.prevHit
             offset = self.hitPt - self.prevHit
-            base.direct.widget.setPos(base.direct.widget, offset)
+            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
+                for widget in base.direct.manipulationControl.widgetList:
+                    widget.setPos(widget, offset)
+            else:
+                base.direct.widget.setPos(base.direct.widget, offset)                
 
 
     def xlate2D(self, state):
     def xlate2D(self, state):
         # Constrained 2D (planar) translation
         # Constrained 2D (planar) translation
@@ -378,7 +588,11 @@ class DirectManipulationControl(DirectObject):
             self.prevHit.assign(self.hitPt)
             self.prevHit.assign(self.hitPt)
         else:
         else:
             offset = self.hitPt - self.prevHit
             offset = self.hitPt - self.prevHit
-            base.direct.widget.setPos(base.direct.widget, offset)
+            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
+                for widget in base.direct.manipulationControl.widgetList:
+                    widget.setPos(widget, offset)
+            else:
+                base.direct.widget.setPos(base.direct.widget, offset)
 
 
     def rotate1D(self, state):
     def rotate1D(self, state):
         # Constrained 1D rotation about the widget's main axis (X, Y, or Z)
         # Constrained 1D rotation about the widget's main axis (X, Y, or Z)
@@ -401,11 +615,23 @@ class DirectManipulationControl(DirectObject):
         if self.fWidgetTop:
         if self.fWidgetTop:
             deltaAngle = -1 * deltaAngle
             deltaAngle = -1 * deltaAngle
         if self.rotateAxis == 'x':
         if self.rotateAxis == 'x':
-            base.direct.widget.setP(base.direct.widget, deltaAngle)
+            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
+                for widget in base.direct.manipulationControl.widgetList:
+                    widget.setP(widget, deltaAngle)
+            else:
+                base.direct.widget.setP(base.direct.widget, deltaAngle)
         elif self.rotateAxis == 'y':
         elif self.rotateAxis == 'y':
-            base.direct.widget.setR(base.direct.widget, deltaAngle)
+            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
+                for widget in base.direct.manipulationControl.widgetList:
+                    widget.setR(widget, deltaAngle)
+            else:
+                base.direct.widget.setR(base.direct.widget, deltaAngle)
         elif self.rotateAxis == 'z':
         elif self.rotateAxis == 'z':
-            base.direct.widget.setH(base.direct.widget, deltaAngle)
+            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
+                for widget in base.direct.manipulationControl.widgetList:
+                    widget.setH(widget, deltaAngle)
+            else:
+                base.direct.widget.setH(base.direct.widget, deltaAngle)
         # Record crank angle for next time around
         # Record crank angle for next time around
         self.lastCrankAngle = newAngle
         self.lastCrankAngle = newAngle
 
 
@@ -611,13 +837,13 @@ class DirectManipulationControl(DirectObject):
                            [base.direct.selected.getSelectedAsList()])
                            [base.direct.selected.getSelectedAsList()])
 
 
 class ObjectHandles(NodePath, DirectObject):
 class ObjectHandles(NodePath, DirectObject):
-    def __init__(self):
+    def __init__(self, name='objectHandles'):
         # Initialize the superclass
         # Initialize the superclass
         NodePath.__init__(self)
         NodePath.__init__(self)
 
 
         # Load up object handles model and assign it to self
         # Load up object handles model and assign it to self
         self.assign(loader.loadModel('models/misc/objectHandles'))
         self.assign(loader.loadModel('models/misc/objectHandles'))
-        self.setName('objectHandles')
+        self.setName(name)
         self.scalingNode = self.getChild(0)
         self.scalingNode = self.getChild(0)
         self.scalingNode.setName('ohScalingNode')
         self.scalingNode.setName('ohScalingNode')
         self.ohScalingFactor = 1.0
         self.ohScalingFactor = 1.0
@@ -668,6 +894,24 @@ class ObjectHandles(NodePath, DirectObject):
         self.createGuideLines()
         self.createGuideLines()
         self.hideGuides()
         self.hideGuides()
 
 
+        # tag with name so they can skipped during iRay selection
+        self.xPostCollision.setTag('WidgetName',name)
+        self.yPostCollision.setTag('WidgetName',name)        
+        self.zPostCollision.setTag('WidgetName',name)
+
+        self.xRingCollision.setTag('WidgetName',name)
+        self.yRingCollision.setTag('WidgetName',name)        
+        self.zRingCollision.setTag('WidgetName',name)
+
+        self.xDiscCollision.setTag('WidgetName',name)
+        self.yDiscCollision.setTag('WidgetName',name)        
+        self.zDiscCollision.setTag('WidgetName',name)
+
+        # name disc geoms so they can be added to unpickables
+        self.xDisc.find("**/+GeomNode").setName('x-disc-geom')
+        self.yDisc.find("**/+GeomNode").setName('y-disc-geom')
+        self.zDisc.find("**/+GeomNode").setName('z-disc-geom')        
+
         # Start with widget handles hidden
         # Start with widget handles hidden
         self.fActive = 1
         self.fActive = 1
         self.toggleWidget()
         self.toggleWidget()
@@ -686,10 +930,19 @@ class ObjectHandles(NodePath, DirectObject):
             
             
     def toggleWidget(self):
     def toggleWidget(self):
         if self.fActive:
         if self.fActive:
-            self.deactivate()
+            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
+                for widget in base.direct.manipulationControl.widgetList:
+                    widget.deactivate()
+            else:
+                self.deactivate()
         else:
         else:
-            self.activate()
-
+            if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
+                for widget in base.direct.manipulationControl.widgetList:
+                    widget.activate()
+                    widget.showWidgetIfActive()
+            else:
+                self.activate()
+                    
     def activate(self):
     def activate(self):
         self.scalingNode.reparentTo(self)
         self.scalingNode.reparentTo(self)
         self.fActive = 1
         self.fActive = 1
@@ -697,7 +950,7 @@ class ObjectHandles(NodePath, DirectObject):
     def deactivate(self):
     def deactivate(self):
         self.scalingNode.reparentTo(hidden)
         self.scalingNode.reparentTo(hidden)
         self.fActive = 0
         self.fActive = 0
-
+                
     def showWidgetIfActive(self):
     def showWidgetIfActive(self):
         if self.fActive:
         if self.fActive:
             self.reparentTo(base.direct.group)
             self.reparentTo(base.direct.group)
@@ -707,7 +960,7 @@ class ObjectHandles(NodePath, DirectObject):
 
 
     def hideWidget(self):
     def hideWidget(self):
         self.reparentTo(hidden)
         self.reparentTo(hidden)
-
+                
     def enableHandles(self, handles):
     def enableHandles(self, handles):
         if type(handles) == types.ListType:
         if type(handles) == types.ListType:
             for handle in handles:
             for handle in handles:
@@ -886,15 +1139,30 @@ class ObjectHandles(NodePath, DirectObject):
         lines = LineNodePath(self.xPost)
         lines = LineNodePath(self.xPost)
         lines.setColor(VBase4(1, 0, 0, 1))
         lines.setColor(VBase4(1, 0, 0, 1))
         lines.setThickness(5)
         lines.setThickness(5)
-        lines.moveTo(0, 0, 0)
-        lines.drawTo(1.5, 0, 0)
-        lines.create()
-        lines = LineNodePath(self.xPost)
-        lines.setColor(VBase4(1, 0, 0, 1))
-        lines.setThickness(1.5)
-        lines.moveTo(0, 0, 0)
+        #lines.moveTo(0, 0, 0)
+        #lines.drawTo(1.5, 0, 0)
+        lines.moveTo(1.5, 0, 0)
+        #lines.create()
+        #lines = LineNodePath(self.xPost)
+        #lines.setColor(VBase4(1, 0, 0, 1))
+        #lines.setThickness(1.5)
+        #lines.moveTo(0, 0, 0)
         lines.drawTo(-1.5, 0, 0)
         lines.drawTo(-1.5, 0, 0)
+
+        arrowInfo0 = 1.3
+        arrowInfo1 = 0.1
+        #lines.setThickness(5)
+        lines.moveTo(1.5, 0, 0)
+        lines.drawTo(arrowInfo0, arrowInfo1, arrowInfo1)
+        lines.moveTo(1.5, 0, 0)
+        lines.drawTo(arrowInfo0, arrowInfo1, -1 * arrowInfo1)
+        lines.moveTo(1.5, 0, 0)
+        lines.drawTo(arrowInfo0, -1 * arrowInfo1, arrowInfo1)
+        lines.moveTo(1.5, 0, 0)
+        lines.drawTo(arrowInfo0, -1 * arrowInfo1, -1 * arrowInfo1)
+
         lines.create()
         lines.create()
+        lines.setName('x-post-line')
 
 
         # X ring
         # X ring
         self.xRing = self.xRingGroup.attachNewNode('x-ring-visible')
         self.xRing = self.xRingGroup.attachNewNode('x-ring-visible')
@@ -907,21 +1175,34 @@ class ObjectHandles(NodePath, DirectObject):
                           math.cos(deg2Rad(ang)),
                           math.cos(deg2Rad(ang)),
                           math.sin(deg2Rad(ang)))
                           math.sin(deg2Rad(ang)))
         lines.create()
         lines.create()
+        lines.setName('x-ring-line')
 
 
         # Y post
         # Y post
         self.yPost = self.yPostGroup.attachNewNode('y-post-visible')
         self.yPost = self.yPostGroup.attachNewNode('y-post-visible')
         lines = LineNodePath(self.yPost)
         lines = LineNodePath(self.yPost)
         lines.setColor(VBase4(0, 1, 0, 1))
         lines.setColor(VBase4(0, 1, 0, 1))
         lines.setThickness(5)
         lines.setThickness(5)
-        lines.moveTo(0, 0, 0)
-        lines.drawTo(0, 1.5, 0)
-        lines.create()
-        lines = LineNodePath(self.yPost)
-        lines.setColor(VBase4(0, 1, 0, 1))
-        lines.setThickness(1.5)
-        lines.moveTo(0, 0, 0)
+        #lines.moveTo(0, 0, 0)
+        #lines.drawTo(0, 1.5, 0)
+        lines.moveTo(0, 1.5, 0)
+        #lines.create()
+        #lines = LineNodePath(self.yPost)
+        #lines.setColor(VBase4(0, 1, 0, 1))
+        #lines.setThickness(1.5)
+        #lines.moveTo(0, 0, 0)
         lines.drawTo(0, -1.5, 0)
         lines.drawTo(0, -1.5, 0)
+
+        #lines.setThickness(5)
+        lines.moveTo(0, 1.5, 0)
+        lines.drawTo(arrowInfo1, arrowInfo0, arrowInfo1)
+        lines.moveTo(0, 1.5, 0)
+        lines.drawTo(arrowInfo1, arrowInfo0, -1 * arrowInfo1)
+        lines.moveTo(0, 1.5, 0)
+        lines.drawTo(-1 * arrowInfo1, arrowInfo0, arrowInfo1)
+        lines.moveTo(0, 1.5, 0)
+        lines.drawTo(-1 * arrowInfo1, arrowInfo0, -1 * arrowInfo1)
         lines.create()
         lines.create()
+        lines.setName('y-post-line')
 
 
         # Y ring
         # Y ring
         self.yRing = self.yRingGroup.attachNewNode('y-ring-visible')
         self.yRing = self.yRingGroup.attachNewNode('y-ring-visible')
@@ -934,21 +1215,35 @@ class ObjectHandles(NodePath, DirectObject):
                           0,
                           0,
                           math.sin(deg2Rad(ang)))
                           math.sin(deg2Rad(ang)))
         lines.create()
         lines.create()
-
+        lines.setName('y-ring-line')
+        
         # Z post
         # Z post
         self.zPost = self.zPostGroup.attachNewNode('z-post-visible')
         self.zPost = self.zPostGroup.attachNewNode('z-post-visible')
         lines = LineNodePath(self.zPost)
         lines = LineNodePath(self.zPost)
         lines.setColor(VBase4(0, 0, 1, 1))
         lines.setColor(VBase4(0, 0, 1, 1))
         lines.setThickness(5)
         lines.setThickness(5)
-        lines.moveTo(0, 0, 0)
-        lines.drawTo(0, 0, 1.5)
-        lines.create()
-        lines = LineNodePath(self.zPost)
-        lines.setColor(VBase4(0, 0, 1, 1))
-        lines.setThickness(1.5)
-        lines.moveTo(0, 0, 0)
+        #lines.moveTo(0, 0, 0)
+        #lines.drawTo(0, 0, 1.5)
+        lines.moveTo(0, 0, 1.5)
+        #lines.create()
+        #lines = LineNodePath(self.zPost)
+        #lines.setColor(VBase4(0, 0, 1, 1))
+        #lines.setThickness(1.5)
+        #lines.moveTo(0, 0, 0)
         lines.drawTo(0, 0, -1.5)
         lines.drawTo(0, 0, -1.5)
+
+        #lines.setThickness(5)
+        lines.moveTo(0, 0, 1.5)
+        lines.drawTo(arrowInfo1, arrowInfo1, arrowInfo0)
+        lines.moveTo(0, 0, 1.5)
+        lines.drawTo(arrowInfo1, -1 * arrowInfo1, arrowInfo0)
+        lines.moveTo(0, 0, 1.5)
+        lines.drawTo(-1 * arrowInfo1, arrowInfo1,  arrowInfo0)
+        lines.moveTo(0, 0, 1.5)
+        lines.drawTo(-1 * arrowInfo1, -1 * arrowInfo1, arrowInfo0)
+
         lines.create()
         lines.create()
+        lines.setName('z-post-line')
 
 
         # Z ring
         # Z ring
         self.zRing = self.zRingGroup.attachNewNode('z-ring-visible')
         self.zRing = self.zRingGroup.attachNewNode('z-ring-visible')
@@ -961,6 +1256,7 @@ class ObjectHandles(NodePath, DirectObject):
                           math.sin(deg2Rad(ang)),
                           math.sin(deg2Rad(ang)),
                           0)
                           0)
         lines.create()
         lines.create()
+        lines.setName('z-ring-line')
 
 
     def createGuideLines(self):
     def createGuideLines(self):
         self.guideLines = self.attachNewNode('guideLines')
         self.guideLines = self.attachNewNode('guideLines')

+ 8 - 0
direct/src/directtools/DirectSelection.py

@@ -560,6 +560,14 @@ class SelectionQueue(CollisionHandlerQueue):
                   (nodePath.getName() in self.unpickable)):
                   (nodePath.getName() in self.unpickable)):
                 # Skip if in unpickable list
                 # Skip if in unpickable list
                 pass
                 pass
+            elif ((skipFlags & SKIP_WIDGET) and
+                (nodePath.getTag('WidgetName') != base.direct.widget.getName())):
+                # Skip if this widget part is not belong to current widget
+                pass
+            elif ((skipFlags & SKIP_WIDGET) and base.direct.fControl and
+                (nodePath.getName()[2:] == 'ring')):
+                # Skip when ununiformly scale in ortho view
+                pass
             else:
             else:
                 self.setCurrentIndex(i)
                 self.setCurrentIndex(i)
                 self.setCurrentEntry(entry)
                 self.setCurrentEntry(entry)

+ 54 - 21
direct/src/directtools/DirectSession.py

@@ -156,6 +156,7 @@ class DirectSession(DirectObject):
             ['SGE_Fit', self.fitOnNodePath],
             ['SGE_Fit', self.fitOnNodePath],
             ['SGE_Delete', self.removeNodePath],
             ['SGE_Delete', self.removeNodePath],
             ['SGE_Set Name', self.getAndSetName],
             ['SGE_Set Name', self.getAndSetName],
+            ['DIRECT-delete', self.removeAllSelected],
             ]
             ]
 
 
         if base.wantTk:
         if base.wantTk:
@@ -175,18 +176,22 @@ class DirectSession(DirectObject):
         keyList.extend(map(chr, range(48, 58)))
         keyList.extend(map(chr, range(48, 58)))
         keyList.extend(["`", "-", "=", "[", "]", ";", "'", ",", ".", "/", "\\"])
         keyList.extend(["`", "-", "=", "[", "]", ";", "'", ",", ".", "/", "\\"])
 
 
+        def addCtrl(a):
+            return "control-%s"%a
+
         def addShift(a):
         def addShift(a):
             return "shift-%s"%a
             return "shift-%s"%a
 
 
-        self.keyList = keyList[:]
-        self.keyList.extend(map(addShift, keyList))
-        self.keyList.extend(['escape', 'delete', 'page_up', 'page_down'])
+        self.keyEvents = keyList[:]
+        self.keyEvents.extend(map(addCtrl, keyList))
+        self.keyEvents.extend(map(addShift, keyList))        
+        self.keyEvents.extend(['escape', 'delete', 'page_up', 'page_down'])
 
 
-        self.keyEvents = ['escape', 'delete', 'page_up', 'page_down',
-                          '[', '{', ']', '}',
-                          'shift-a', 'b', 'control-f',
-                          'l', 'shift-l', 'o', 'p', 'r',
-                          'shift-r', 's', 't', 'v', 'w']
+##         self.keyEvents = ['escape', 'delete', 'page_up', 'page_down',
+##                           '[', '{', ']', '}',
+##                           'shift-a', 'b', 'control-f',
+##                           'l', 'shift-l', 'o', 'p', 'r',
+##                           'shift-r', 's', 't', 'v', 'w']
         self.mouseEvents = ['mouse1', 'mouse1-up',
         self.mouseEvents = ['mouse1', 'mouse1-up',
                             'shift-mouse1', 'shift-mouse1-up',
                             'shift-mouse1', 'shift-mouse1-up',
                             'control-mouse1', 'control-mouse1-up',
                             'control-mouse1', 'control-mouse1-up',
@@ -225,6 +230,9 @@ class DirectSession(DirectObject):
             '+': 'DIRECT-zoomInCam',
             '+': 'DIRECT-zoomInCam',
             '_': 'DIRECT-zoomOutCam',
             '_': 'DIRECT-zoomOutCam',
             '-': 'DIRECT-zoomOutCam',
             '-': 'DIRECT-zoomOutCam',
+            'delete': 'DIRECT-delete',
+            '.': 'DIRECT-widgetScaleUp',
+            ',': 'DIRECT-widgetScaleDown',
             }
             }
 
 
         self.passThroughKeys = ['v','b','l','p', 'r', 'shift-r', 's', 't','shift-a', 'w'] 
         self.passThroughKeys = ['v','b','l','p', 'r', 'shift-r', 's', 't','shift-a', 'w'] 
@@ -404,9 +412,6 @@ class DirectSession(DirectObject):
         for event in self.keyEvents:
         for event in self.keyEvents:
             self.accept(event, self.inputHandler, [event])
             self.accept(event, self.inputHandler, [event])
 
 
-        for event in self.keyList:
-            self.accept(event, self.inputHandler, [event])
-
     def enableMouseEvents(self):
     def enableMouseEvents(self):
         for event in self.mouseEvents:
         for event in self.mouseEvents:
             self.accept(event, self.inputHandler, [event])
             self.accept(event, self.inputHandler, [event])
@@ -441,6 +446,8 @@ class DirectSession(DirectObject):
                     base.direct.iRay = base.direct.dr.iRay
                     base.direct.iRay = base.direct.dr.iRay
                     base.mouseWatcher = winCtrl.mouseWatcher
                     base.mouseWatcher = winCtrl.mouseWatcher
                     base.mouseWatcherNode = winCtrl.mouseWatcher.node()
                     base.mouseWatcherNode = winCtrl.mouseWatcher.node()
+                    if base.direct.manipulationControl.fMultiView:
+                        base.direct.widget = base.direct.manipulationControl.widgetList[base.camList.index(NodePath(winCtrl.camNode))]
                     break
                     break
 
 
         # Deal with keyboard and mouse input
         # Deal with keyboard and mouse input
@@ -491,8 +498,8 @@ class DirectSession(DirectObject):
             self.downAncestry()
             self.downAncestry()
         elif input == 'escape':
         elif input == 'escape':
             self.deselectAll()
             self.deselectAll()
-        elif input == 'delete':
-            self.removeAllSelected()
+##         elif input == 'delete':
+##             self.removeAllSelected()
         elif input == 'v':
         elif input == 'v':
             self.toggleWidgetVis()
             self.toggleWidgetVis()
         elif input == 'b':
         elif input == 'b':
@@ -566,9 +573,19 @@ class DirectSession(DirectObject):
         if not taskMgr.hasTaskNamed('resizeObjectHandles'):
         if not taskMgr.hasTaskNamed('resizeObjectHandles'):
             dnp = self.selected.last
             dnp = self.selected.last
             if dnp:
             if dnp:
-                nodeCamDist = Vec3(dnp.getPos(direct.camera)).length()
-                sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList.getCurrentDr().fovV))
-                self.widget.setDirectScalingFactor(sf)
+                if self.manipulationControl.fMultiView:
+                    for i in range(3):
+                        sf = 30.0 * direct.drList[i].orthoFactor
+                        self.manipulationControl.widgetList[i].setDirectScalingFactor(sf)
+
+                    nodeCamDist = Vec3(dnp.getPos(base.camList[3])).length()
+                    sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList[3].fovV))
+                    self.manipulationControl.widgetList[3].setDirectScalingFactor(sf)
+                        
+                else:
+                    nodeCamDist = Vec3(dnp.getPos(direct.camera)).length()
+                    sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList.getCurrentDr().fovV))
+                    self.widget.setDirectScalingFactor(sf)
         return Task.cont
         return Task.cont
     
     
     def select(self, nodePath, fMultiSelect = 0,
     def select(self, nodePath, fMultiSelect = 0,
@@ -585,7 +602,11 @@ class DirectSession(DirectObject):
             self.selectedNPReadout.setText(
             self.selectedNPReadout.setText(
                 'Selected:' + dnp.getName())
                 'Selected:' + dnp.getName())
             # Show the manipulation widget
             # Show the manipulation widget
-            self.widget.showWidget()
+            if self.manipulationControl.fMultiView:
+                for widget in self.manipulationControl.widgetList:
+                    widget.showWidget()
+            else:
+                self.widget.showWidget()
             editTypes = self.manipulationControl.getEditTypes([dnp])
             editTypes = self.manipulationControl.getEditTypes([dnp])
             if (editTypes & EDIT_TYPE_UNEDITABLE == EDIT_TYPE_UNEDITABLE):
             if (editTypes & EDIT_TYPE_UNEDITABLE == EDIT_TYPE_UNEDITABLE):
                 self.manipulationControl.disableWidgetMove()
                 self.manipulationControl.disableWidgetMove()
@@ -601,8 +622,12 @@ class DirectSession(DirectObject):
             # This uses the additional scaling factor used to grow and
             # This uses the additional scaling factor used to grow and
             # shrink the widget
             # shrink the widget
             if not self.fScaleWidgetByCam: # [gjeon] for not scaling widget by distance from camera
             if not self.fScaleWidgetByCam: # [gjeon] for not scaling widget by distance from camera
-                self.widget.setScalingFactor(dnp.getRadius())
-            
+                if self.manipulationControl.fMultiView:
+                    for widget in self.manipulationControl.widgetList:
+                        widget.setScalingFactor(dnp.getRadius())
+                else:
+                    self.widget.setScalingFactor(dnp.getRadius())
+                
             # Spawn task to have object handles follow the selected object
             # Spawn task to have object handles follow the selected object
             taskMgr.remove('followSelectedNodePath')
             taskMgr.remove('followSelectedNodePath')
             t = Task.Task(self.followSelectedNodePathTask)
             t = Task.Task(self.followSelectedNodePathTask)
@@ -624,7 +649,11 @@ class DirectSession(DirectObject):
         dnp = self.selected.deselect(nodePath)
         dnp = self.selected.deselect(nodePath)
         if dnp:
         if dnp:
             # Hide the manipulation widget
             # Hide the manipulation widget
-            self.widget.hideWidget()
+            if self.manipulationControl.fMultiView:
+                for widget in self.manipulationControl.widgetList:
+                    widget.hideWidget()
+            else:
+                self.widget.hideWidget()                
             self.selectedNPReadout.reparentTo(hidden)
             self.selectedNPReadout.reparentTo(hidden)
             self.selectedNPReadout.setText(' ')
             self.selectedNPReadout.setText(' ')
             taskMgr.remove('followSelectedNodePath')
             taskMgr.remove('followSelectedNodePath')
@@ -635,7 +664,11 @@ class DirectSession(DirectObject):
     def deselectAll(self):
     def deselectAll(self):
         self.selected.deselectAll()
         self.selected.deselectAll()
         # Hide the manipulation widget
         # Hide the manipulation widget
-        self.widget.hideWidget()
+        if self.manipulationControl.fMultiView:
+            for widget in self.manipulationControl.widgetList:
+                widget.hideWidget()
+        else:
+            self.widget.hideWidget()
         self.selectedNPReadout.reparentTo(hidden)
         self.selectedNPReadout.reparentTo(hidden)
         self.selectedNPReadout.setText(' ')
         self.selectedNPReadout.setText(' ')
         taskMgr.remove('followSelectedNodePath')
         taskMgr.remove('followSelectedNodePath')