mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 19:08:55 -04:00
Added ability to set color of selection box (if needed to be different than the default red).
This commit is contained in:
parent
e4c5381877
commit
12c5c4e0f3
@ -31,3 +31,10 @@ 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_ALL = SKIP_HIDDEN | SKIP_BACKFACE | SKIP_CAMERA | SKIP_UNPICKABLE
|
||||||
|
|
||||||
|
# bit flags for indicating how editable an object is
|
||||||
|
EDIT_TYPE_UNMOVABLE = 1
|
||||||
|
EDIT_TYPE_UNSCALABLE = 2
|
||||||
|
EDIT_TYPE_UNROTATABLE = 4
|
||||||
|
EDIT_TYPE_UNEDITABLE = EDIT_TYPE_UNMOVABLE | EDIT_TYPE_UNSCALABLE | EDIT_TYPE_UNROTATABLE
|
||||||
|
|
||||||
|
@ -175,14 +175,34 @@ class DirectManipulationControl(PandaObject):
|
|||||||
def removeManipulateObjectTask(self):
|
def removeManipulateObjectTask(self):
|
||||||
taskMgr.remove('manipulateObject')
|
taskMgr.remove('manipulateObject')
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
# Function: get edit types list for specified objects which indicate
|
||||||
|
# how editable the objects are
|
||||||
|
# Parameters: object, list of object to get edit types for
|
||||||
|
# Changes: none
|
||||||
|
# Returns: list of edit types
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
def getEditTypes(self,objects):
|
||||||
|
# See if any of the selected in the don't manipulate tag list
|
||||||
|
editTypes = 0
|
||||||
|
for tag in self.unmovableTagList:
|
||||||
|
for selected in objects:
|
||||||
|
unmovableTag = selected.getTag(tag)
|
||||||
|
if (unmovableTag):
|
||||||
|
# check value of unmovableTag to see if it is
|
||||||
|
# completely uneditable or if it allows only certain
|
||||||
|
# types of editing
|
||||||
|
editTypes |= int(unmovableTag)
|
||||||
|
return editTypes
|
||||||
|
|
||||||
def manipulateObject(self):
|
def manipulateObject(self):
|
||||||
# Only do this if something is selected
|
# Only do this if something is selected
|
||||||
selectedList = direct.selected.getSelectedAsList()
|
selectedList = direct.selected.getSelectedAsList()
|
||||||
# See if any of the selected in the don't manipulate tag list
|
# See if any of the selected are completely uneditable
|
||||||
for tag in self.unmovableTagList:
|
editTypes = self.getEditTypes(selectedList)
|
||||||
for selected in selectedList:
|
if (editTypes & EDIT_TYPE_UNEDITABLE == EDIT_TYPE_UNEDITABLE):
|
||||||
if selected.hasTag(tag):
|
return
|
||||||
return
|
self.currEditTypes = editTypes
|
||||||
if selectedList:
|
if selectedList:
|
||||||
# Remove the task to keep the widget attached to the object
|
# Remove the task to keep the widget attached to the object
|
||||||
taskMgr.remove('followSelectedNodePath')
|
taskMgr.remove('followSelectedNodePath')
|
||||||
@ -234,11 +254,11 @@ class DirectManipulationControl(PandaObject):
|
|||||||
# Widget takes precedence
|
# Widget takes precedence
|
||||||
if self.constraint:
|
if self.constraint:
|
||||||
type = self.constraint[2:]
|
type = self.constraint[2:]
|
||||||
if type == 'post':
|
if type == 'post' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
|
||||||
self.xlate1D(state)
|
self.xlate1D(state)
|
||||||
elif type == 'disc':
|
elif type == 'disc' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
|
||||||
self.xlate2D(state)
|
self.xlate2D(state)
|
||||||
elif type == 'ring':
|
elif type == 'ring' and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
|
||||||
self.rotate1D(state)
|
self.rotate1D(state)
|
||||||
# No widget interaction, determine free manip mode
|
# No widget interaction, determine free manip mode
|
||||||
elif self.fFreeManip:
|
elif self.fFreeManip:
|
||||||
@ -247,17 +267,17 @@ class DirectManipulationControl(PandaObject):
|
|||||||
self.objectHandles.transferObjectHandlesScale()
|
self.objectHandles.transferObjectHandlesScale()
|
||||||
self.fScaling = 0
|
self.fScaling = 0
|
||||||
# Alt key switches to a scaling mode
|
# Alt key switches to a scaling mode
|
||||||
if direct.fControl:
|
if direct.fControl and not self.currEditTypes & EDIT_TYPE_UNSCALABLE:
|
||||||
self.fScaling = 1
|
self.fScaling = 1
|
||||||
self.scale3D(state)
|
self.scale3D(state)
|
||||||
# Otherwise, manip mode depends on where you started
|
# Otherwise, manip mode depends on where you started
|
||||||
elif state.fMouseX and state.fMouseY:
|
elif state.fMouseX and state.fMouseY and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
|
||||||
# In the corner, spin around camera's axis
|
# In the corner, spin around camera's axis
|
||||||
self.rotateAboutViewVector(state)
|
self.rotateAboutViewVector(state)
|
||||||
elif state.fMouseX or state.fMouseY:
|
elif state.fMouseX or state.fMouseY and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
|
||||||
# Mouse started elsewhere in the outer frame, rotate
|
# Mouse started elsewhere in the outer frame, rotate
|
||||||
self.rotate2D(state)
|
self.rotate2D(state)
|
||||||
else:
|
elif not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
|
||||||
# Mouse started in central region, xlate
|
# Mouse started in central region, xlate
|
||||||
# Mode depends on shift key
|
# Mode depends on shift key
|
||||||
if direct.fShift or direct.fControl:
|
if direct.fShift or direct.fControl:
|
||||||
@ -281,6 +301,7 @@ class DirectManipulationControl(PandaObject):
|
|||||||
def removeTag(self, tag):
|
def removeTag(self, tag):
|
||||||
self.unmovableTagList.remove(tag)
|
self.unmovableTagList.remove(tag)
|
||||||
|
|
||||||
|
|
||||||
### WIDGET MANIPULATION METHODS ###
|
### WIDGET MANIPULATION METHODS ###
|
||||||
def xlate1D(self, state):
|
def xlate1D(self, state):
|
||||||
# Constrained 1D Translation along widget axis
|
# Constrained 1D Translation along widget axis
|
||||||
@ -962,4 +983,3 @@ class ObjectHandles(NodePath,PandaObject):
|
|||||||
return self.hitPt
|
return self.hitPt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,12 +9,12 @@ COA_CENTER = 1
|
|||||||
# MRM: To do: handle broken node paths in selected and deselected dicts
|
# MRM: To do: handle broken node paths in selected and deselected dicts
|
||||||
class DirectNodePath(NodePath):
|
class DirectNodePath(NodePath):
|
||||||
# A node path augmented with info, bounding box, and utility methods
|
# A node path augmented with info, bounding box, and utility methods
|
||||||
def __init__(self, nodePath):
|
def __init__(self, nodePath, bboxColor=None):
|
||||||
# Initialize the superclass
|
# Initialize the superclass
|
||||||
NodePath.__init__(self)
|
NodePath.__init__(self)
|
||||||
self.assign(nodePath)
|
self.assign(nodePath)
|
||||||
# Create a bounding box
|
# Create a bounding box
|
||||||
self.bbox = DirectBoundingBox(self)
|
self.bbox = DirectBoundingBox(self, bboxColor)
|
||||||
center = self.bbox.getCenter()
|
center = self.bbox.getCenter()
|
||||||
# Create matrix to hold the offset between the nodepath
|
# Create matrix to hold the offset between the nodepath
|
||||||
# and its center of action (COA)
|
# and its center of action (COA)
|
||||||
@ -69,7 +69,7 @@ class SelectedNodePaths(PandaObject):
|
|||||||
if not nodePath:
|
if not nodePath:
|
||||||
print 'Nothing selected!!'
|
print 'Nothing selected!!'
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Reset selected objects and highlight if multiSelect is false
|
# Reset selected objects and highlight if multiSelect is false
|
||||||
if not fMultiSelect:
|
if not fMultiSelect:
|
||||||
self.deselectAll()
|
self.deselectAll()
|
||||||
@ -244,13 +244,13 @@ class SelectedNodePaths(PandaObject):
|
|||||||
|
|
||||||
|
|
||||||
class DirectBoundingBox:
|
class DirectBoundingBox:
|
||||||
def __init__(self, nodePath):
|
def __init__(self, nodePath, bboxColor=None):
|
||||||
# Record the node path
|
# Record the node path
|
||||||
self.nodePath = nodePath
|
self.nodePath = nodePath
|
||||||
# Compute bounds, min, max, etc.
|
# Compute bounds, min, max, etc.
|
||||||
self.computeTightBounds()
|
self.computeTightBounds()
|
||||||
# Generate the bounding box
|
# Generate the bounding box
|
||||||
self.lines = self.createBBoxLines()
|
self.lines = self.createBBoxLines(bboxColor)
|
||||||
|
|
||||||
def recompute(self):
|
def recompute(self):
|
||||||
# Compute bounds, min, max, etc.
|
# Compute bounds, min, max, etc.
|
||||||
@ -285,11 +285,14 @@ class DirectBoundingBox:
|
|||||||
self.min = Point3(self.center - Point3(self.radius))
|
self.min = Point3(self.center - Point3(self.radius))
|
||||||
self.max = Point3(self.center + Point3(self.radius))
|
self.max = Point3(self.center + Point3(self.radius))
|
||||||
|
|
||||||
def createBBoxLines(self):
|
def createBBoxLines(self, bboxColor=None):
|
||||||
# Create a line segments object for the bbox
|
# Create a line segments object for the bbox
|
||||||
lines = LineNodePath(hidden)
|
lines = LineNodePath(hidden)
|
||||||
lines.node().setName('bboxLines')
|
lines.node().setName('bboxLines')
|
||||||
lines.setColor(VBase4(1., 0., 0., 1.))
|
if (bboxColor):
|
||||||
|
lines.setColor(VBase4(*bboxColor))
|
||||||
|
else:
|
||||||
|
lines.setColor(VBase4(1., 0., 0., 1.))
|
||||||
lines.setThickness(0.5)
|
lines.setThickness(0.5)
|
||||||
|
|
||||||
minX = self.min[0]
|
minX = self.min[0]
|
||||||
@ -329,6 +332,13 @@ class DirectBoundingBox:
|
|||||||
|
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
def setBoxColorScale(self,r,g,b,a):
|
||||||
|
if (self.lines):
|
||||||
|
self.lines.reset()
|
||||||
|
self.lines = None
|
||||||
|
self.lines = self.createBBoxLines((r,g,b,a))
|
||||||
|
self.show()
|
||||||
|
|
||||||
def updateBBoxLines(self):
|
def updateBBoxLines(self):
|
||||||
ls = self.lines.lineSegs
|
ls = self.lines.lineSegs
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user