#!BPY
"""
Name: 'Bone Tools'
Blender: 248
Group: 'Animation'
Tooltip: 'Four useful buttons for pose and constraints'
"""
__author__ = ["Emilio Le Roux (elerouxx)"]
__url__ = ("http://wiki.blender.org/index.php/Scripts/Manual/Animation/Bone_Tools_v02". "http://www.moscafilms.com.br/emilioleroux/blender/bone_tools_v02.py")
__version__ = "0.2 - 03.07.2007"

__bpydoc__ = """\
This is a very simple collection of tools to help in some animation tasks.
The layout is minimal so the user can access the buttons all the time
from a small script window.

The scripts should only be used with an armature in Pose mode.

I wrote these two scripts as a substitute for shortcuts I miss in Blender:
	
SELECT CHILDREN:
Just select one or more bones and click on this button to have all their children selected.

SELECT SIBLINGS:
Select one or more bones and click on this button to have all the other children of the same
parent selected.


I wrote these other two scripts to help with constraints:
	
NEW ALIGNED EMPTY:
Creates a new Empty object and aligns it to the bone's visual location, rotation and scale.
Just select one or more bones and hit the button.
Several Empties can be created at once if more than one bone is selected.

ALIGN TO BONE:
Aligns the selected objects to the selected bone. 
Select the object(s) first and the bone in pose mode last.
(Only one bone should be selected)
"""


# --------------------------------------------------------------------------
# Bone Tools v0.2 by Emilio Le Roux (elerouxx)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------


import Blender
from Blender import Window, sys
from Blender import Armature
from Blender import Object



from Blender.BGL import *
from Blender.Draw import *
import bpy





########################################
# selects all children of selected bones

def selectchildren():
	print ''
	print '###### select children #####'
	
	sce = bpy.data.scenes.active
	arm_ob = sce.objects.active
	
	if not arm_ob or arm_ob.getType() != 'Armature':
		PupMenu('Please select an armature bone')
		return
		
	arm_data = arm_ob.getData()

	bones = arm_data.bones.values()
	
	selectlist = []
	
	print '#bonelist#'
	print bones
		
	#List bones to select (only works from pose mode - not edit mode)

	for bone in bones:
				
		if (Armature.BONE_SELECTED in bone.options):
			selectlist += bone.getAllChildren()

	#Flag bones SELECTED
	
	arm_data.makeEditable()
			
	for selectbone in selectlist:
			arm_data.bones[selectbone.name].options += [Armature.BONE_SELECTED]
		
	arm_data.update()
					
	Blender.Redraw()

					
		
########################################
# selects all siblings of selected bones

def selectsiblings():
	print ''
	print '###### select siblings #####'
	
	sce = bpy.data.scenes.active
	arm_ob = sce.objects.active
	
	if not arm_ob or arm_ob.getType() != 'Armature':
		PupMenu('Please select an armature bone')
		return
		
	arm_data = arm_ob.getData()
	
	bones = arm_data.bones.values()
	
	selectlist = []

	print '#bonelist#'
	print bones
		
	#List bones to select (only works from pose mode - not edit mode)

	for bone in bones:
				
		if (Armature.BONE_SELECTED in bone.options):
			selectlist += bone.parent.children
		
		
	#Flag bones SELECTED
	
	arm_data.makeEditable()
	
	for selectbone in selectlist:
		arm_data.bones[selectbone.name].options += [Armature.BONE_SELECTED]
		
		
	arm_data.update()
					
	Blender.Redraw()



###############################
# Create Empty aligned to bone

def createempty():
	sce = bpy.data.scenes.active
	arm_ob = sce.objects.active
	
	if not arm_ob or arm_ob.getType() != 'Armature':
		PupMenu('Please select an armature bone')
		return
	
	arm_data = arm_ob.getData()
	bones = arm_data.bones.values()
	
	pose = arm_ob.getPose()
	
	for bone in bones:
		
		if (Armature.BONE_SELECTED in bone.options):
			bonematrix=bone.matrix['ARMATURESPACE']
			posebone=pose.bones[bone.name]
			posematrix = posebone.poseMatrix
			bonematrix_world = posematrix*arm_ob.matrixWorld
			ob_empty = Object.New('Empty',bone.name)
			sce.link(ob_empty)
			ob_empty.setMatrix(bonematrix_world)
			
	Blender.Redraw()
	
	
	
###################################
# Align object to bone

def aligntobone():
	sce = bpy.data.scenes.active
	obs=sce.objects.context
	arm_ob=sce.objects.active
	
	if not arm_ob or arm_ob.getType() != 'Armature':
		PupMenu('Please select an armature bone')
		return
	
	#count of objects must be >1
	
	arm_data=arm_ob.getData()
	bones = arm_data.bones.values()
		
	pose = arm_ob.getPose()
	
	for ob in obs:
		if ob != arm_ob:
			for bone in bones:
				if Armature.BONE_SELECTED in bone.options:
					bonematrix=bone.matrix['ARMATURESPACE']
					posebone=pose.bones[bone.name]
					posematrix = posebone.poseMatrix
					bonematrix_world = posematrix*arm_ob.matrixWorld
					ob.setMatrix(bonematrix_world)
			
	Blender.Redraw()
			




#########################
# Interface


global dist

dist = Create(0.2)
left = Create (0.0)
right = Create (1.0)
num = Create(2)

#Events
EVENT_NOEVENT = 1
EVENT_SELECTCHILDREN = 2
EVENT_SELECTSIBLINGS = 3
EVENT_CREATEEMPTYFORBONE = 4
EVENT_ALIGNTOBONE = 5

EVENT_TOGGLELAYOUT = 6

#Other constants
LAYOUT_VERTICAL = 0
LAYOUT_HORIZONTAL = 1



def draw():
	global dist, left, right, num, old_dist
	global EVENT_NOEVENT, EVENT_SELECTCHILDREN, EVENT_SELECTSIBLINGS, EVENT_CREATEEMPTYFORBONE,EVENT_ALIGNTOBONE,EVENT_TOGGLELAYOUT
	
	glClear(GL_COLOR_BUFFER_BIT)
	
	Button("Select Children",EVENT_SELECTCHILDREN,0,0,100,20)
	Button("Select Siblings",EVENT_SELECTSIBLINGS,100,0,100,20)
	Button("New Aligned Empty",EVENT_CREATEEMPTYFORBONE,200,0,140,20)
	Button("Align to Bone",EVENT_ALIGNTOBONE,340,0,100,20)

def event(evt,val):
	if(evt ==QKEY and not val):Exit()
		
def btevent(evt):
	if evt ==EVENT_SELECTCHILDREN	:selectchildren()
	if evt ==EVENT_SELECTSIBLINGS	:selectsiblings()
	if evt ==EVENT_CREATEEMPTYFORBONE	:createempty()
	if evt ==EVENT_ALIGNTOBONE	:aligntobone()
	
Register(draw,event,btevent)
	
	
	