#!BPY

"""
Name: 'Layer Manager'
Blender: 248
Group: 'System'
Tooltip: 'Named layer management, organize multiple configurations by layer group, and more.'
"""

__author__ = "FourMadMen.com (FourMadMen)"
__url__ = [
	"FourMadMen.com, http://www.fourmadmen.com",
	"Scripts by FourMadMen, http://www.fourmadmen.com/blender/scripts/index.html",
	"Layer Manager Homepage, http://www.fourmadmen.com/blender/scripts/4mm_layer_manager/index.html",
	"http://wiki.blender.org/index.php/Extensions:Py/Scripts/Manual/System/4mm_layer_manager",
	"blenderartists"
]
__version__ = "1.3.1 2008/10/14"

__bpydoc__ = """\
This script (Layer Manager) is used to manage scene layers.

With Layer Manager you can name layers, create layer groups, and hide un-used layers in much the same as you can hide mesh geometry.

Terms:

Active Layer: The layer that new objects will be created in.<br>
Available Layer: An availalbe layer is show by Layer Manager and can be made Visible/Invisible and can be selected for purposes of hiding, adding to a layer group, etc.<br>
Selected Layer: An available layers whose selection box is turned on.  Selected layers can be hidden, added to a layer group, etc.<br>
Hidden Layer: A hidden layer is not show in the Layer Manager and can not be selected.  The option to show hidden layers is known as revealing.<br>

Shortcuts:

Q: Exit<br>
+: Add new layer group (and make active)<br>
X: Delete active layer group<br>
H: Hide selected layers<br>
R: Reveal hidden layers<br>
M: Move selected objects to selected layers<br>
Shift+M: Merge selected layers<br>
F: Flatten selected layers<br>
O: Object info popup (very crude right now, will make better and am open to suggestions)<br>
V: Invert visible layer selection<br>
S: Invert selected layers selection<br>
`: View All Layers
A: Select/Deselect All Layers
0-9, Shift 0-9: Toggle Layer Visibility

Button Modifier shortcuts:

<Layer Visible Button>  Click to toggle, CTRL+Click to view only that layer<br>
<Layer Selected Button> Click to toggle, CTRL+Click to select only that layer, SHIFT+Click to Lock/Unlock<br>
<Layer Name>            Click to change name<br>
<Layer Info>            Click to select objects in layer by type, SHIFT+Click to select object in layer not of type, CTRL+Click to select ONLY objects in layer

Known Issues:

Blender.Window.Redraw(), which should redraw all 3D Views does not seem to do so.  The 3D View that was most recently usde prior to running the script seems to be the only one redrawn.  To force a redraw click on the Layer lock button.  Upon activation of the lock the view is updated.  Perhaps someone can shed some light on this issue?<br>

"""

# --------------------------------------------------------------------------
# $Id: 4mm_layer_manager_13.py, v 1.3.1 2008/09/20 00:16:00
# --------------------------------------------------------------------------
#
# --------------------------------------------------------------------------
# Layer Manager v1.3.1
# by FourMadMen.com (FourMadMen), 2008
# This script is protected by the GPL: Gnu Public Licence
# GPL - http://www.gnu.org/copyleft/gpl.html
# --------------------------------------------------------------------------
# ***** 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 *****
# --------------------------------------------------------------------------

#Press Alt-P to run

import Blender
from Blender import World, NMesh, Window, Scene, Draw, Types, Object, Text, Material
from Blender.Draw import Register
from Blender.BGL import glClear, GL_COLOR_BUFFER_BIT
import marshal
import time
from collections import defaultdict
import math

######################################################################
# Globals
#

#######################################
#
# User Configuration
#

num_columns = 2

#
#
#######################################

# Events
EVENT_NOEVENT = 0
EVENT_EXIT = 1
EVENT_HELP = 2
EVENT_ABOUT = 3
EVENT_EXPORT = 4
EVENT_IMPORT = 5
EVENT_LOAD_SH = 6
EVENT_MAIN_MENU = 7

EVENT_LG_NEW = 20
EVENT_LG_DELETE = 21
EVENT_LG_BROWSE = 22
EVENT_LG_CHANGE = 23

EVENT_VISIBLE_TO_SELECTED = 30
EVENT_INVERT_VISIBLE = 31
EVENT_INVERT_SELECTED = 32

EVENT_SEL_HIDE = 40
EVENT_SEL_REVEAL = 41
EVENT_SEL_MERGE = 42
EVENT_SEL_FLATTEN = 43
EVENT_SEL_MOVE = 44

EVENT_OBJ_INFO = 50

EVENT_LAYER_VISIBLE_BASE = 1000
EVENT_LAYER_SELECTED_BASE = 2000
EVENT_LAYER_NAME_BASE = 3000
EVENT_LAYER_INFO_BASE = 4000

####################################################################################
# Constants
#

ROOT = "fourmadmen.com/layermanager" #32-Character limit
NS = "ns"
NSP = "layermanager"
VERSION = "version"
STRUCT_TYPE = "struct.type"
AUTHOR = "author"
URL = "url"
RELEASE_DATE = "release.date"
LAYERS = "layers"
GROUPS = "groups"
SCENES = "scenes"
ID = "id"
DATA = "data"
NAME = "name"
ACTIVE = "active"
ACTIVE_BY_SCENE = "active.by.scene"
LAYER_SETTINGS = "layer.settings"
GUI_SETTINGS = "gui.settings"
LAYOUT = "layout"
VISIBLE = "visible"
SELECTED = "seleced"
LOCKED = "locked"
HIDDEN = "hidden"
B_INDEX = "b.index"

MAIN_MENU_KEY = "main"
LAYER_GROUPS_KEY = "layer_groups"
LAYER_FUNCTIONS_KEY = "layer_functions"
LAYER_PROPERTIES_KEY = "layer_properties"
VISIBLE_KEY = "visible"
SELECTED_KEY = "selected"
NAMES_KEY = "names"
INFO_KEY = "info"
LAYER_MANAGER_FILE_EXTENSION = ".4mm.layers"

#
# Constants
####################################################################################

experimentalLocking = True

buttons = {
	MAIN_MENU_KEY:[
		Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create("")
	],
	LAYER_GROUPS_KEY:[
		Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create("")
	],
	LAYER_FUNCTIONS_KEY:[
		Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
		Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
		Draw.Create("")
	],
	LAYER_PROPERTIES_KEY:{
		VISIBLE_KEY: [
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create("")
		],
		SELECTED_KEY: [
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create("") 
		],
		NAMES_KEY:[
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create("")
		],
		INFO_KEY:[
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""),
			Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create(""), Draw.Create("")
		]
	}
}

#
# Globals
######################################################################

####################################################################################
# Classes
#

class LayerManager:
	
	def __init__(self, properties):
		#print "__init__ LayerManager"
		
		self.properties = properties
		
		self.layerList = []
		self.layerDict = {}
		
		self.layerGroupList = []
		self.layerGroupDict = {}
		
	#end __init__
	
	def newLayer(self, properties = None):
		layer = Layer(properties)
		self.addLayer(layer)
	#end newLayer
	
	def addLayer(self, layer):
		self.layerList.append(layer)
		self.layerDict[layer.getID()] = layer
	#end addLayer
	
	def getLayerByIndex(self, index):
		return self.layerList[index]
	#end getLayerByIndex
	
	def getLayerById(self, id):
		for layer in self.layerList:
			if layer.getID()==id:
				return layer
			#end if
		#end for
		
		return None
	#end getLayerByIds
	
	def newLayerGroup(self, properties = None):
		if not properties:
			properties = self.newLayerGroupProperties()
		#end if
		
		layerGroup = LayerGroup(properties)
		self.addLayerGroup(layerGroup)
		
		self.activeLayerGroup = layerGroup
	#end newLayerGroup
	
	def addLayerGroup(self, layerGroup):
		self.layerGroupList.append(layerGroup)		
		self.layerGroupDict[layerGroup.getID()] = layerGroup
	#end addLayerGroup
	
	def newLayerGroupProperties(self):
		#scan for available id
		id = 1
		while True:
			try:
				self.properties[GROUPS][DATA][str(id)]
			except KeyError:
				break
			#end try/except
			
			id+=1
		#end while
		
		properties = {
			ID: id,
			NAME: self.autoNameGroup(),
			SCENES: [],
			LAYER_SETTINGS: {
				VISIBLE: [1],
				SELECTED: [],
				LOCKED: []
			}
		}
		
		self.properties[GROUPS][DATA][str(id)] = properties
		
		#return properties		
		return self.properties[GROUPS][DATA][str(id)]
	#end newLayerGroupProperties
	
	def setActiveLayerGroup(self, layerGroupID = None):
		if not layerGroupID:
			layerGroupID = self.properties[GROUPS][ACTIVE]
		#end if
		
		try:
			self.activeLayerGroup = self.layerGroupDict[layerGroupID]
		except KeyError:
			layerGroupID = self.layerGroupList[0].getID()
			self.activeLayerGroup = self.layerGroupDict[layerGroupID]
		#end try/except
		
		self.properties[GROUPS][ACTIVE] = layerGroupID
		
		self.updateLayers()
		self.updateVisible()
	#end setActiveLayerGroup
	
	def deleteActiveLayerGroup(self):
		id = self.activeLayerGroup.getID()
		
		self.layerGroupList.remove(self.activeLayerGroup)
		del self.properties[GROUPS][DATA][str(id)]
		
		self.properties[GROUPS][ACTIVE] = self.layerGroupList[-1].getID()
		self.setActiveLayerGroup()
	#end deleteActiveLayerGroup
	
	def activeLayers(self):
		return [ layer for layer in self.layerList if not layer.isHidden() ]
	#end visibleLayers
	
	def visibleLayers(self):
		return [ layer for layer in self.layerList if layer.isVisible() ]
	#end selectedLayers
	
	def selectedLayers(self):
		return [ layer for layer in self.layerList if layer.isSelected() ]
	#end selectedLayers
	
	def visibleToSelected(self):
		for layer in self.activeLayers():
			layer.setSelected(layer.isVisible())
		#end for
		
		self.updateVisible()
		self.updateSelected()
	#end visibleToSelected
	
	def invertVisibleLayers(self):
		for layer in self.activeLayers():
			layer.toggleVisible()
		#end for
		
		self.updateVisible()
	#end invertVisible
	
	def viewOnlyThisLayer(self, layer):
		for aLayer in self.activeLayers():
			aLayer.setVisible(layer.getID()==aLayer.getID());
		#end for
		
		self.updateVisible()
	#end viewOnlyThisLayer
	
	def selectOnlyThisLayer(self, layer):
		for aLayer in self.activeLayers():
			aLayer.setSelected(layer.getID()==aLayer.getID());
		#end for
		
		self.updateSelected()
	#end viewOnlyThisLayer
	
	def invertSelectedLayers(self):
		for layer in self.activeLayers():
			layer.toggleSelected()
		#end for
		
		self.updateSelected()
	#end invertVisible
	
	def hideSelectedLayers(self):
		for layer in self.selectedLayers():
			layer.setHidden(True)
		#end for
		
		self.updateHidden()
		self.updateVisible()
	#end hideSelected
	
	def revealHiddenLayers(self):
		for layer in self.layerList:
			if layer.isHidden():
				layer.setSelected(True)
				layer.setHidden(False)
			#end if
		#end for
		
		self.updateSelected()
		self.updateHidden()
		self.updateVisible()
	#end hideSelected
	
	def updateLayers(self):
		for layer in self.layerList:
			layer.setVisible(False)
			layer.setSelected(False)
			layer.setHidden(False)
			layer.setLocked(False)
		#end for
		
		layerIDs = self.activeLayerGroup.properties[LAYER_SETTINGS][VISIBLE]
		for id in layerIDs:
			self.layerDict[id].setVisible(True)
		#end for
		
		layerIDs = self.activeLayerGroup.properties[LAYER_SETTINGS][SELECTED]
		for id in layerIDs:
			self.layerDict[id].setSelected(True)
		#end for
		
		layerIDs = self.properties[LAYERS][HIDDEN]
		for id in layerIDs:
			self.layerDict[id].setHidden(True)
		#end for
		
		layerIDs = self.activeLayerGroup.properties[LAYER_SETTINGS][LOCKED]
		for id in layerIDs:
			self.layerDict[id].setLocked(True)
		#end for
	#end updateLayers
	
	def updateVisible(self):
		layers = [ layer.getID() for layer in self.visibleLayers() ] # Test all even if hidden
		if len(layers)==0:
			(self.activeLayers())[0].setVisible(True)
			layers = [ layer.getID() for layer in self.visibleLayers() ] # Test all even if hidden
		#end if
		
		self.activeLayerGroup.properties[LAYER_SETTINGS][VISIBLE] = layers
		
		Window.ViewLayers(layers)
		##Scene.getCurrent().layers = layers
	#end updateVisible
	
	def updateSelected(self):
		layers = [ layer.getID() for layer in self.layerList if layer.isSelected() ] # Test all even if hidden
		self.activeLayerGroup.properties[LAYER_SETTINGS][SELECTED] = layers
	#end updateVisible
	
	def updateHidden(self):
		layers = [ layer.getID() for layer in self.layerList if layer.isHidden() ] # Test all even if hidden
		self.properties[LAYERS][HIDDEN] = layers
	#end updateVisible
	
	def updateLocked(self):
		layers = [ layer.getID() for layer in self.layerList if layer.isLocked() ] # Test all even if hidden
		self.activeLayerGroup.properties[LAYER_SETTINGS][LOCKED] = layers
	#end updateVisible
	
	def updateActiveLayer(self, layerGroup=None):
		if not layerGroup: layerGroup = self.activeLayerGroup
		self.properties[GROUPS][ACTIVE] = layerGroup.getID()
	#end updateActiveLayer
	
	def setActiveLayer(self, layer):
		#setting active layer bitmask from script does not appear to be working, so kill for now
		pass
		
		#bitmask = 2**(layer.getID()-1)
		#
		#print 'Set Active Layer', layer.getID()
		#print 'bitmask', bitmask
		#	
		#Window.SetActiveLayer(bitmask)
		#print 'window active layer bitmask', Window.GetActiveLayer()
	#end setActiveLayer
	
	def autoNameGroup(self):
		haveUniqueName = False
		name = "Group"
		idx = 0
		
		while not haveUniqueName:
			haveUniqueName = True
			
			for group in self.layerGroupList:
				if name==group.getName():
					haveUniqueName = False
				#end if
			#end for
			
			if not haveUniqueName:
				idx+=1
				name = "Group "+str(idx)
			#end if
		#end while
		
		return name
	#end autoNameGroup
	
	def objectCountByLayer(self):
		counts = defaultdict(int)
		
		for object in Scene.GetCurrent().objects:
			for layerId in object.layers:
				counts[layerId] += 1
		
		return counts
	#end objectCountByLayer
	
	def moveObjectToLayers(self, object, layers):
		object.layers = [layer.getID() for layer in layers]
	#end moveObjectToLayers
	
	def addObjectToLayers(self, object, layers):
		objLayers = object.layers
		
		for layer in layers:
			print 'add', layer.getID(), 'to', objLayers
			layerId = layer.getID()
			
			try:
				index = objLayers.index(layerId)
			except ValueError:
				objLayers.append(layerId)
			#end try/except
		#end for
		
		object.layers = objLayers
	#end addObjectToLayers
	
	def removeObjectFromLayers(self, object, layers):
		objLayers = object.layers
		
		for layer in layers:
			print 'remove', layer.getID(), 'from', objLayers
			try:
				objLayers.remove(layer.getID())
			except ValueError:
				pass
			#end try/except
		#end for
		
		object.layers = objLayers
	#end removeObjectFromLayers
	
	def moveObjectsToLayers(self, objects = None, layers = None, removeLayers = None):
		if not objects:
			objects = Object.GetSelected()
		#end if
		
		if not layers:
			layers = self.selectedLayers()
		#end if
		
		if len(layers)==0: return
		
		for object in objects:
			if removeLayers:
				self.removeObjectFromLayers(object, removeLayers)
				self.addObjectToLayers(object, layers)
			else:
				self.moveObjectToLayers(object, layers)
			#end if
		#end for
	#end moveObjectsToLayers
	
	def mergeLayers(self, layers = None):
		if not layers:
			layers = self.selectedLayers()
		#end if
		
		if len(layers)<=1: return
		
		targetLayer = layers.pop(0)
		objects = []
		
		selectedLayerIDs = [ layer.getID() for layer in layers ]
		
		for object in Scene.GetCurrent().objects:
			objectLayerIDs = object.layers
			isInLayer = False
			
			for selectedLayerId in selectedLayerIDs:
				for layerId in objectLayerIDs:
					if layerId==selectedLayerId:
						isInLayer = True
						break
					#end if
				#end for
				
				if isInLayer: break
			#end for
			
			if isInLayer: objects.append(object)
		#end for
				
		self.moveObjectsToLayers(objects, [targetLayer], layers)
	
	#end mergeLayers
	
	def flattenLayers(self, layers = None):
		if not layers:
			layers = self.selectedLayers()
		#end if
		
		if len(layers)<=1: return
		
		self.mergeLayers(layers)
		
		for layer in layers:
			layer.setHidden(True)
		#end for
		
	#end flattenSelectedLayers
	
	def selectObjectsByLayer(self, layer = None, onlyIn = False):
		if not layer:
			layer = self.getLayerById(Window.GetActiveLayer())
		#end if
		
		objects = []
		selectedLayerId = layer.getID()
		
		if onlyIn:
			for object in Scene.GetCurrent().objects:
				object.select(False)
			#end for
		#end if

		for object in layer.objects():
			if not object.restrictSelect: object.select(True)
		#end for
	#end selectObjectsByLayer
	
	def exportProperties(self):
		filename = getLayerFilename()
		
		Window.FileSelector(self.saveLayerPropertiesCallback, "Export Layer Info", filename)
	#end export
	
	def saveLayerPropertiesCallback(self, filename):
		if filename==None: return
		
		print "Exporting Layer Manager Settings: "+filename
		
		try:
			data = marshal.dumps(layerManager.properties.convert_to_pyobject())
			
			fh = open (filename, 'w')
			fh.write(data)
			fh.close()
		except IOError:
			print "IOError on export: "+str(IOError)
		#end try/except
		
	#end saveLayerPropertiesCallback
	
	def importProperties(self):
		filename = getLayerFilename()
		
		Window.FileSelector(self.loadLayerPropertiesCallback, "Import Layer Info", filename)
	#end import
	
	def loadLayerPropertiesCallback(self, filename):
		global layer_info
		
		if filename==None: return
		
		init(filename)
	#end loadLayerPropertiesCallback
	
#end LayerManager

class LayerGroup:
	
	def __init__(self, properties):
		#print "__init__ LayerGroup"
		
		self.properties = properties
	#end __init__
	
	def __cmp__(self, other):
		return cmp(self.properties[ID], other.properties[ID])
	#end __cmp__
	
	def getID(self):
		return self.properties[ID]
	#end getID
	
	def setName(self, name):
		self.properties[NAME] = name
	#end setName
	
	def getName(self):
		return self.properties[NAME]
	#end getName
	
#end LayerGroup

class Layer:
	
	def __init__(self, properties):
		#print "__init__ Layer"
		
		self.properties = properties
		self.visible = 0
		self.selected = 0
		self.hidden = 0
		self.locked = 0
	#end __init__
	
	def __cmp__(self, other):
		return cmp(self.properties[ID], other.properties[ID])
	#end __cmp__
	
	def getID(self):
		return self.properties[ID]
	#end getID
	
	def setName(self, name):
		self.properties[NAME] = name
	#end setName
	
	def getName(self):
		return self.properties[NAME]
	#end getName
	
	def setVisible(self, state):
		state = int(state)
		self.visible = state
		
		if state: layerManager.setActiveLayer(self)
	#end setVisible
	
	def toggleVisible(self):
		if Window.GetKeyQualifiers() & Window.Qual.CTRL:
			for layer in layerManager.visibleLayers():
				layer.setVisible(False)
			#end for
			
			self.setVisible(True)
		else:
			self.setVisible(1 - self.visible)
		#end if
	#end toggleVisible
	
	def isVisible(self):
		return bool(self.visible and not self.hidden)
	#end isVisible
	
	def setSelected(self, state):
		state = int(state)
		self.selected = state
	#end setSelected
	
	def toggleSelected(self):
		if Window.GetKeyQualifiers() & Window.Qual.CTRL:
			for layer in layerManager.selectedLayers():
				layer.setSelected(False)
			#end for
			
			self.setSelected(True)
		else:
			self.setSelected(1 - self.selected)
		#end if
	#end toggleSelected
	
	def isSelected(self):
		return bool(self.selected and not self.hidden)
	#end isSelected
	
	def setHidden(self, state):
		state = int(state)
		self.hidden = state
	#end setSelected
	
	def isHidden(self):
		return bool(self.hidden)
	#end isHidden
	
	def setLocked(self, state):
		state = int(state)
		self.locked = state
		
		global experimentalLocking
		if experimentalLocking:
			for object in Scene.GetCurrent().objects:
				if self.getID() in object.layers:
					if state: object.select(False)
					object.restrictSelect = state
					if Scene.GetCurrent().objects.active==object:
						Scene.GetCurrent().objects.active = None
					#end if
				#end if
			#end for
		#end if
	#end setLocked
	
	def toggleLocked(self):
		self.setLocked(1 - self.locked)
	#end toggleLocked
	
	def isLocked(self):
		return bool(self.locked)
	#end isLocked
	
	def objects(self, name_only=False):
		names = []
		self.objectClipboard = ObjectClipboard()
		
		for object in Scene.GetCurrent().objects:
			if self.getID() in object.layers:
				if name_only:
					names.append(object.getName())
				else:
					self.objectClipboard.addObject(object)
				#end if
			#end if
		#end for
		
		if name_only:
			return names
		else:
			return self.objectClipboard.objects
		#end if
	#end objects
	
	def objectsByMaterial(self, material):
		if self.objectClipboard==None: self.objects()
		self.objectClipboard.registerMaterials()
		
		return self.objectClipboard.getObjectsByMaterial(material)
	#end objectByMaterial
	
	def selectObjects(self, state=True, klass=None):
		
		def isObjectOfBlenderType(object, type):
			return object.type==type
		#end isObjectOfBlenderType
		
		def doesObjectUseMaterial(object, material):
			uses = False
			
			materialName = material.getName()
			
			for objectMaterial in object.getMaterials():
				if objectMaterial.getName()==materialName:
					return True
				#end if
			#end for
			
			if object.getType()=="Mesh":
				mesh = object.getData(mesh=True)
				
				for meshMaterial in mesh.materials:
					if meshMaterial.getName()==materialName:
						return True
					#end if
				#end for
			#end if
			
			return False
		#end doesObjectUseMaterial
		
		if self.objectClipboard==None:
			objects = self.objects()
		else:
			objects = self.objectClipboard.objects
		#end if
		
		if type(klass)==type(""): # Blender object type string
			selectionMethod = isObjectOfBlenderType
		else: # No need to type check yet, this is a Material object
			selectionMethod = doesObjectUseMaterial
		#end if
				
		for object in objects:
			if klass:
				if selectionMethod(object, klass):
					objState = state
				else:
					objState = not state
				#end if
			else:
				objState = state
			#end if
			
			object.select(objState)
		#end for
	#end selectObjects
	
#end Layer

class ObjectClipboard:
	
	def __init__(self):
		#print "__init__ ObjectClipboard"
		
		self.objects = []
		self.materials = {}
	#end __init__
	
	def addObject(self, object):
		self.objects.append(object)
	#end addObject
	
	def removeObject(self, object):
		self.objects.remove(object)
	#end removeObject
	
	def registerMaterials(self):
		for object in self.objects:
			for material in object.getMaterials():
				materialName = material.getName()
				if self.materials[materialName]==None: self.materials[materialName] = []
				self.materials[materialName].append(object)
			#end for
		#end for
	#end registerMaterials
	
	def getObjectsByMaterial(self, material):
		try:
			return self.materials[material.getName()]
		except KeyError:
			return []
		#end try/except
	#end getObjectsByMaterial
	
	##Testing only.  Remove for release.
	#def getObjects(self):
	#	print 'using object clipboard ', self, ' of size: ', len(self.objects)
	#	return self.objects
	##end objects
	
#end ObjectClipboard

#
# Classes
####################################################################################

####################################################################################
# Packaged Text Payload
#

layerManagerSettingsText = """Layer Manager Settings Wrapper

** DO NOT DELETE **

Deleting this Text Object will clear
all Layer Manager settings.

After deletion, exit the Layer Manager 
script.

Blender does not have a global properties
space, so Layer Manager settings are 
stored in the property space of this Text 
object.

Layer Manager version 1.3.1
FourMadMen.com"""


eventSpacehandlerText = """# SPACEHANDLER.VIEW3D.EVENT

import Blender
from Blender import Draw

evt = Blender.event

#print evt

if evt == Draw.ACCENTGRAVEKEY:
	scriptsDir = Blender.Get("uscriptsdir")
	if not scriptsDir: scriptsDir = Blender.Get("scriptsdir")
	filename = "4mm_layer_manager_13.py"
	
	script_to_run = scriptsDir + "/" + filename
	#print script_to_run
	Blender.Run(script_to_run)
	
	evt = None
#end if

if not evt: Blender.event = None
"""


drawSpacehandlerText = """# SPACEHANDLER.VIEW3D.DRAW

import Blender
from Blender import Object, Window, Scene, Text

ROOT = "fourmadmen.com/layermanager" #32-Character limit
GROUPS = "groups"
DATA = "data"
ACTIVE = "active"
LAYER_SETTINGS = "layer.settings"
LOCKED = "locked"

def isObjectLocked(object):
	global activeLayerGroupId, lockedLayerIds
	
	#print 'Selected object name', object.getName()
	
	objectLayerIds = object.layers
	for objectLayerId in objectLayerIds:
		for lockedLayerId in lockedLayerIds:
			#print 'object layer id', objectLayerId, 'locked layer id', lockedLayerId
			if objectLayerId == lockedLayerId:
				#print 'Object', object.getName(), 'is locked'
				return True
			#end if
		#end for
	#end for
	
	return False
#end isObjectLocked

object = Scene.GetCurrent().objects.active

if object and object.isSelected(): #active object can be un-selected
	settingsWrappName = "LayerManager Settings"
	settingsWrapper = Text.Get(settingsWrappName)
	properties = settingsWrapper.properties[ROOT]
	activeLayerGroupId = properties[GROUPS][ACTIVE]
	lockedLayerIds = properties[GROUPS][DATA][str(activeLayerGroupId)][LAYER_SETTINGS][LOCKED]
	
	if len(lockedLayerIds) > 0:
		isLocked = isObjectLocked(object)
		
		if isLocked: 
			#print 'Object', object.getName(), 'will be de-selected'
			object.select(False)
			object.restrictSelect = True
			Scene.GetCurrent().objects.active = None
			
			Window.RedrawAll()
		#end if
	#end if
#end if
"""

#
# Packaged Text Payload
####################################################################################

####################################################################################
# Functions
#

def init(filename=None):
	global layerManager
	global num_columns
	
	print "Layer Manager 1.3.1 Init"
	
	layerManager = LayerManager(initProperties(filename))
	
	layersData = layerManager.properties[LAYERS][DATA]
	for id in sorted([value[ID] for value in layersData.values()]):
		properties = layersData[str(id)]
		layerManager.newLayer(properties)
	#end
	
	layerGroupsDATA = layerManager.properties[GROUPS][DATA]
	for id in sorted([value[ID] for value in layerGroupsDATA.values()]):
		properties = layerGroupsDATA[str(id)]
		layerManager.newLayerGroup(properties)
	#end
	
	layerManager.setActiveLayerGroup()
	
	num_columns = layerManager.properties[GUI_SETTINGS][LAYOUT]
	
	layerManager.updateVisible()
	
	print "Layer Manager Init Complete."
#end init

def initProperties(filename=None):
	#world = World.GetCurrent()
	#propertySpace = world.properties
	
	settingsWrapper = None
	
	settingsWrappName = "LayerManager Settings"
	try:
		settingsWrapper = Text.Get(settingsWrappName)
	except NameError:
		settingsWrapper = Text.New(settingsWrappName)
		settingsWrapper.write(layerManagerSettingsText)
	#end try/except
	
	propertySpace = settingsWrapper.properties
	layerManagerProperties = None
	
	if not filename:	
		try:
			layerManagerProperties = propertySpace[ROOT]
			print "Using blend file Layer Manager settings."
		except KeyError:
			pass
		#ent try/except
	#end if
	
	if not layerManagerProperties:
		if not filename: filename = getLayerFilename()
		
		if filename:
			try:
				fh = open (filename)
				print "Loading layer file:", filename
				data = fh.read()
				fh.close()
				
				fileProperties = marshal.loads(data)
				
				#load properties file old or new structure
				try:
					fileProperties[NS+":"+NSP]
					fileProperties[STRUCT_TYPE]
					
					if(fileProperties[STRUCT_TYPE]=="2"):
						layerManagerProperties = {}
						layerManagerProperties[ROOT] = fileProperties
					#end if
				except KeyError:
					try:
						fileProperties['layer_properties']['names']
						fileProperties['layer_groups']['groups']
						
						print "Converting Layermanger Settings from old file structure."
						
						convertedProperties = defaultProperties()
						
						for id, name in enumerate(fileProperties['layer_properties']['names']):
							if id>0:
								print 'Layer:', id, 'Name:', name
								convertedProperties[ROOT][LAYERS][DATA][str(id)][NAME] = name
							#end if
						#end for
						
						for index, groupList in enumerate(fileProperties['layer_groups']['groups']):
							id = index+1
							name = groupList[0]
							viewLayers = groupList[1]
							
							print 'Group:', id, 'Name:', name, 'View Layers', viewLayers
							
							try:
								convertedProperties[ROOT][GROUPS][DATA][str(id)]
								convertedProperties[ROOT][GROUPS][DATA][str(id)][NAME] = name
								convertedProperties[ROOT][GROUPS][DATA][str(id)][LAYER_SETTINGS][VISIBLE] = viewLayers
							except KeyError:
								groupProperties = {
									ID: id,
									NAME: name,
									SCENES: [],
									LAYER_SETTINGS: {
										VISIBLE: viewLayers,
										SELECTED: [],
										LOCKED: []
									}
								}
								
								convertedProperties[ROOT][GROUPS][DATA][str(id)] = groupProperties
							#end try/except
						#end for
						
						layerManagerProperties = convertedProperties
					except KeyError:
						pass
					#end try/except
				#end try/except
				
				if layerManagerProperties:
					print "Using Layer Manager settings from files."
					propertySpace.update(layerManagerProperties)
				#end if
			except IOError:
				print "File not found or can't read file: "+filename
			except KeyError:
				print "File has improper format: "+filename
			#end try/except
		#end if
	#end if
	
	if not layerManagerProperties: 
		print "Using default Layer Manager settings."
		layerManagerProperties = defaultProperties()
		propertySpace.update(layerManagerProperties)
	#end if
	
	return propertySpace[ROOT]
	
#end initProperties

def getLayerFilename():
	filename = Blender.Get("filename")
	if not filename: return ""
	
	if filename.endswith(".blend"):
		filename = filename[0:len(filename)-len(".blend")] + LAYER_MANAGER_FILE_EXTENSION
	#end if
	
	return filename
#end getLayerFilename

def defaultProperties():
	defaultProperties = {
		ROOT: {
			NS: NSP,
			NS+":"+NSP: ROOT,
			STRUCT_TYPE: "2",
			VERSION: "1.3.1",
			AUTHOR: "FourMadMen.com",
			URL: "http://www.fourmadmen.com/blender/scripts/4mm_layer_manager/index.html",
			RELEASE_DATE: "2008-10-14",
			GUI_SETTINGS: {
				LAYOUT: 2
			},
			LAYERS: {
				HIDDEN: [],
				DATA: {
					"1": {
						ID: 1,
						NAME: "Layer 1",
						B_INDEX: 1
					},
					"2": {
						ID: 2,
						NAME: "Layer 2",
						B_INDEX: 2
					},
					"3": {
						ID: 3,
						NAME: "Layer 3",
						B_INDEX: 3
					},
					"4": {
						ID: 4,
						NAME: "Layer 4",
						B_INDEX: 4
					},
					"5": {
						ID: 5,
						NAME: "Layer 5",
						B_INDEX: 5
					},
					"6": {
						ID: 6,
						NAME: "Layer 6",
						LOCKED: 0,
						B_INDEX: 6
					},
					"7": {
						ID: 7,
						NAME: "Layer 7",
						B_INDEX: 7
					},
					"8": {
						ID: 8,
						NAME: "Layer 8",
						B_INDEX: 8
					},
					"9": {
						ID: 9,
						NAME: "Layer 9",
						B_INDEX: 9
					},
					"10": {
						ID: 10,
						NAME: "Layer 10",
						B_INDEX: 10
					},
					"11": {
						ID: 11,
						NAME: "Layer 11",
						B_INDEX: 11
					},
					"12": {
						ID: 12,
						NAME: "Layer 12",
						B_INDEX: 12
					},
					"13": {
							ID: 13,
						NAME: "Layer 13",
						B_INDEX: 13
					},
					"14": {
						ID: 14,
						NAME: "Layer 14",
						B_INDEX: 14
					},
					"15": {
						ID: 15,
						NAME: "Layer 15",
						B_INDEX: 15
					},
					"16": {
						ID: 16,
						NAME: "Layer 16",
						B_INDEX: 16
					},
					"17": {
						ID: 17,
						NAME: "Layer 17",
						B_INDEX: 17
					},
					"18": {
						ID: 18,
						NAME: "Layer 18",
						B_INDEX: 18
					},
					"19": {
						ID: 19,
						NAME: "Layer 19",
						B_INDEX: 19
					},
					"20": {
						ID: 20,
						NAME: "Layer 20",
						B_INDEX: 20
					}
				}
			},
			GROUPS: {
				ACTIVE: 1,
				ACTIVE_BY_SCENE: { 
					## Reserved for future use ##
				},
				DATA: {
					"1": {
						ID: 1,
						NAME: "Group",
						SCENES: [], ## Reserved for future use ##
						LAYER_SETTINGS: {
							VISIBLE: [1],
							SELECTED: [],
							LOCKED: []
						}
					}
				}
			}
		}
	}
	
	return defaultProperties
#end defaultProperties

def decode(*arguments):
	if len(arguments) < 3:
		raise TypeError, 'decode() takes at least 3 arguments (%d given)' % (len(arguments))
	#end if
	
	dict = list(arguments[1:])
	
	if arguments[0] in dict:
		index = dict.index(arguments[0]);
		if index % 2 == 0 and len(dict) > index+1:
			return dict[index+1]
		#end if
		
		return dict[-1]
	elif len(dict) % 2 != 0:
		return dict[-1]
	#end if
	
#def decode

def layerInfoBlock(layer=None):
	return ["Not yet implemented."]
#end layerInfoBlock

def objectInfoBlock(object=None):
	if not object:
		objects = Object.GetSelected()
		
		if len(objects) == 0:
			return ["No Object Selected"]
		else:
			object = objects[0]
		#end if
	#end if
	
	objectInfo = []
	
	objectType = object.getType()
	
	objectInfo.append("Name: "+object.getName())
	objectInfo.append("Type: "+objectType)
	if object.getParent(): objectInfo.append("Parent: "+object.getParent().getName())
	objectInfo.append("Num Layers: "+str(len(object.layers)))
	if objectType=="Mesh":
		mesh = object.getData(mesh=True)
		
		objectInfo.append("Mesh Name: "+mesh.name)
		objectInfo.append("Num. Vertices: "+str(len(mesh.verts)))
		objectInfo.append("Num. Edges: "+str(len(mesh.edges)))
		objectInfo.append("Num. Faces: "+str(len(mesh.faces)))
	#end if
	
	return objectInfo
#end objectInfoBlock

def changeLayout(evt, val):
	global num_columns
	
	num_columns = decode(val, 1, 1, 2, 2, 3, 4, 2)
	layerManager.properties[GUI_SETTINGS][LAYOUT] = num_columns
	
	if winIsScript:
		Draw.Redraw()
	else:
		pass #xxx
	#end if
#end changeLayout

#
# Functions
####################################################################################

####################################################################################
# Event and Draw Functions
#

def popupMenu(options, title=None, maxrow=None):
	menuStr = ""
	
	if title:
		menuStr+=str(title)
		menuStr+="%t"
		menuStr+="|"
	#end if
	
	for option in options:
		#if type(option)=='list':
		#	return Draw.PupTreeMenu(options)
		##end if
		
		if option:
			menuStr+=str(option[0])
			menuStr+="%x"
			menuStr+=str(option[1])
		else:
			menuStr+="%l"
		#end if
		
		menuStr+="|"
	#end for
	
	#Doesn't like it if you implicitly pass None into maxrow
	if maxrow==None:
		return Draw.PupMenu(menuStr[:-1])
	else:
		return Draw.PupMenu(menuStr[:-1], maxrow)
	#end if
#end popupMenu

def event(evt, val):	
	#print 'event', evt, val
	
	#if evt>0: # and not val:
	#	need_redraw = check_locked_objects()
	#	if need_redraw:
	#		Draw.Redraw(1)
	#	#end if
	##end if
	
	if ((evt == Draw.QKEY) and not val):
		if winIsScript:
			Draw.Exit()
			print "Layer Manager stop"
		else:
			global uiBlockExit
			uiBlockExit = True
		#end if
	elif evt == Draw.ONEKEY and val:
		id = 1
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.TWOKEY and val:
		id = 2
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.THREEKEY and val:
		id = 3
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.FOURKEY and val:
		id = 4
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.FIVEKEY and val:
		id = 5
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.SIXKEY and val:
		id = 6
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.SEVENKEY and val:
		id = 7
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.EIGHTKEY and val:
		id = 8
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.NINEKEY and val:
		id = 9
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.ZEROKEY and val:
		id = 10
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT: id+=10
		layerManager.getLayerById(id).toggleVisible()
		layerManager.updateVisible()
	elif evt == Draw.ACCENTGRAVEKEY and val:
		for layer in layerManager.activeLayers():
			layer.setVisible(True)
		#end for
		layerManager.updateVisible()
	elif evt == Draw.AKEY and val:
		state = True
		if len(layerManager.selectedLayers()) > 0:
			state = False
		#end if
		
		for layer in layerManager.activeLayers():
			layer.setSelected(state)
		#end for
		layerManager.updateSelected()
	elif evt == Draw.PADPLUSKEY and val:
		layerManager.newLayerGroup()
		layerManager.updateLayers()
		layerManager.updateVisible()
		layerManager.updateActiveLayer()
	elif evt == Draw.EQUALKEY and val:
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
			layerManager.newLayerGroup()
			layerManager.updateLayers()
			layerManager.updateVisible()
		#end if
	elif evt == Draw.XKEY and val:
		layerManager.deleteActiveLayerGroup()
	elif evt == Draw.VKEY and val:
		layerManager.invertVisibleLayers()
	elif evt == Draw.SKEY and val:
		layerManager.invertSelectedLayers()
	elif evt == Draw.HKEY and val:
		layerManager.hideSelectedLayers()
	elif evt == Draw.RKEY and val:
		layerManager.revealHiddenLayers()
	elif evt == Draw.MKEY and val:
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
			layerManager.mergeLayers()
		else:
			layerManager.moveObjectsToLayers()
		#end if
	elif evt == Draw.FKEY and val:
		layerManager.flattenLayers()
	elif evt == Draw.OKEY and val:
		retval = Blender.Draw.PupBlock("Object Info", objectInfoBlock())
	else:
		if not winIsScript:
			button_event(evt)
			return True
		#end if
		
		return
	#end if
	
	if winIsScript: Window.Redraw(Window.Types.SCRIPT)
	Window.Redraw()
	
#end event

def button_event(evt):
	#print 'button_event', evt
	global activeLayerGroup
	global uiBlockExit
	
	if evt == EVENT_EXIT:
		if winIsScript:
			Draw.Exit()
			print "Layer Manager stop"
		else:
			uiBlockExit = True
		#end if
	elif evt == EVENT_HELP:
		Blender.ShowHelp("4mm_layer_manager_13.py")
	elif evt == EVENT_MAIN_MENU:
		menuTitle = "Main Menu"
		menuItems=[]		
		
		menuItems.append(("Import", EVENT_IMPORT))
		menuItems.append(("Export", EVENT_EXPORT))
		menuItems.append(None)
		
		lgNames = []
		for layerGroup in layerManager.layerGroupList:
			lgName = layerGroup.getName()
			if lgName.startswith("Render"):
				menuItems.append((lgName, -(layerGroup.getID()+10)))
				lgNames.append(lgName)
			#end if
		#end for
		if len(lgNames)>0: menuItems.append(None)
		
		menuItems.append(("Load Spacehandlers", EVENT_LOAD_SH))
		menuItems.append(None)
		menuItems.append(("Help", EVENT_HELP))
		menuItems.append(("About", EVENT_ABOUT))
		menuItems.append(None)
		menuItems.append(("Exit", EVENT_EXIT))
		
		mmi = popupMenu(menuItems, menuTitle)
		
		if mmi <= -10:
			clgi = layerManager.activeLayerGroup.getID()
			lgi = -(mmi+10)
			layerManager.setActiveLayerGroup(lgi)
			layerManager.updateLayers()
			context = Scene.GetCurrent().getRenderingContext()
			context.render()
			layerManager.setActiveLayerGroup(clgi)
			layerManager.updateLayers()
		elif mmi == EVENT_IMPORT:
			layerManager.importProperties()
			if not winIsScript: uiBlockExit = True
		elif mmi == EVENT_EXPORT:
			layerManager.exportProperties()
			if not winIsScript: uiBlockExit = True
		elif mmi == EVENT_LOAD_SH:
			name = "LayerManager13 ev SH"
			try:
				spacehandler = Text.Get(name)
				Text.unlink(spacehandler)
			except NameError:
				pass
			#end try/except
			spacehandler = Text.New(name)
			spacehandler.write(eventSpacehandlerText)
			
			name = "LayerManager13 dw SH"
			try:
				spacehandler = Text.Get(name)
				Text.unlink(spacehandler)
			except NameError:
				pass
			#end try/except
			spacehandler = Text.New(name)
			spacehandler.write(drawSpacehandlerText)
			
			blockItems = [
				"Load Complete.", 
				"To enable, go to menu:", 
				"View->Spacehandler Scripts", 
				"", 
				"After activation, use the",
				"Accent-Grave/Backtick key", 
				"to open as popup in a", 
				"3D window."
			]
			
			Blender.Draw.PupBlock("Load Handlers", blockItems)
		elif mmi == EVENT_HELP:
			Blender.ShowHelp("4mm_layer_manager_13.py")
		elif mmi == EVENT_ABOUT:
			blockItems = [
				"Layer Manager", 
				"Version 1.3.1 Build 2", 
				"October 14, 2008"
				"", 
				"by",
				"Four Mad Men",
				"www.FourMadMen.com"
			]
			
			Blender.Draw.PupBlock("About", blockItems)
		elif mmi == EVENT_EXIT:
			if winIsScript:
				Draw.Exit()
				print "Layer Manager stop"
			else:
				uiBlockExit = True
			#end if
		#end if
	elif evt == EVENT_LG_BROWSE:
		menuTitle = "Select Group"
		menuItems = []
		
		activeGroupName = layerManager.activeLayerGroup.getName()
		
		for index, layerGroup in enumerate(layerManager.layerGroupList):
			menuDecoration = decode(activeGroupName, layerGroup.getName(), "*", " ")
			menuItems.append((menuDecoration+layerGroup.getName(), layerGroup.getID()))
		#end for
		
		lgi = popupMenu(menuItems, menuTitle)
	
		if lgi>=0:
			layerManager.setActiveLayerGroup(lgi)
			layerManager.updateLayers()
		#end if			
	elif evt == EVENT_LG_CHANGE:
		layer_group_buttons = buttons[LAYER_GROUPS_KEY]
		name = layer_group_buttons[1].val
		layerManager.activeLayerGroup.setName(name)
	elif evt == EVENT_LG_NEW:
		layerManager.newLayerGroup()
		layerManager.updateLayers()
		layerManager.updateVisible()
		layerManager.updateActiveLayer() ##4mm##
	elif evt == EVENT_LG_DELETE:
		layerManager.deleteActiveLayerGroup()
	elif evt == EVENT_VISIBLE_TO_SELECTED:
		layerManager.visibleToSelected()
	elif evt == EVENT_INVERT_VISIBLE:
		layerManager.invertVisibleLayers()
	elif evt == EVENT_INVERT_SELECTED:
		layerManager.invertSelectedLayers()
	elif evt == EVENT_SEL_HIDE:
		layerManager.hideSelectedLayers()
	elif evt == EVENT_SEL_REVEAL:
		layerManager.revealHiddenLayers()
	elif evt == EVENT_SEL_MERGE:
		layerManager.mergeLayers()
	elif evt == EVENT_SEL_FLATTEN:
		layerManager.flattenLayers()
	elif evt == EVENT_SEL_MOVE:
		layerManager.moveObjectsToLayers()
	elif evt == EVENT_OBJ_INFO:
		retval = Blender.Draw.PupBlock("Object Info", objectInfoBlock())
	elif evt>=EVENT_LAYER_VISIBLE_BASE and evt<EVENT_LAYER_VISIBLE_BASE+1000 :
		index = evt - EVENT_LAYER_VISIBLE_BASE
		layer = layerManager.getLayerByIndex(index)
		
		if Window.GetKeyQualifiers() & Window.Qual.CTRL:
			layerManager.viewOnlyThisLayer(layer)
		else:
			layerManager.getLayerByIndex(index).toggleVisible()
			layerManager.updateVisible()
		#end if
	elif evt>=EVENT_LAYER_SELECTED_BASE and evt<EVENT_LAYER_SELECTED_BASE+1000 :
		index = evt - EVENT_LAYER_SELECTED_BASE
		layer = layerManager.getLayerByIndex(index)
		
		if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
			layer.toggleLocked()
			layerManager.updateLocked()
		elif Window.GetKeyQualifiers() & Window.Qual.CTRL:
			layerManager.selectOnlyThisLayer(layer)
		else:
			layer.toggleSelected()
			layerManager.updateSelected()
		#end if
	elif evt>=EVENT_LAYER_NAME_BASE and evt<EVENT_LAYER_NAME_BASE+1000 :
		index = evt - EVENT_LAYER_NAME_BASE
		layer = layerManager.getLayerByIndex(index)
		layer.setName(buttons[LAYER_PROPERTIES_KEY][NAMES_KEY][index].val)
	elif evt>=EVENT_LAYER_INFO_BASE and evt<EVENT_LAYER_INFO_BASE+1000 :
		index = evt - EVENT_LAYER_INFO_BASE
		layer = layerManager.getLayerByIndex(index)
		
		if Window.GetKeyQualifiers() & Window.Qual.CTRL:
			layerManager.selectObjectsByLayer(layer, True)
		else:
			menuItems = []
			menuTitle = ""
				
			if layer.isLocked():
				menuTitle = "Select By Type"
				menuItems.append(("Cancel (Layer is Locked)", -1))
			else:
				stateForType = not bool(Window.GetKeyQualifiers() & Window.Qual.SHIFT)
				olTypes = defaultdict(int)
				olMaterials = defaultdict(int)
				
				for object in layer.objects():
					olTypes[object.type] += 1
					
					for material in object.getMaterials():
						olMaterials[material.getName()] += 1
					#end for
					
					if object.type=="Mesh":
						mesh = object.getData(mesh=True)
						
						for material in mesh.materials:
							if material!=None:
								olMaterials[material.getName()] += 1
							#end if
						#end for
					#end if
				#end for
				
				sortedKeys = sorted(olTypes.keys())
				
				if stateForType:
					menuTitle = "Select By Type"
				else:
					menuTitle = "Select Not Type"
				#end if
				
				idx = 0
				for objType in sortedKeys:
					menuDisplay = "%d - %s" % (olTypes[objType], objType)
					menuOpt = "%x"+str(idx)
					
					menuItems.append((menuDisplay, idx))
					idx+=1
				#end for
				
				if len(olMaterials) > 0:
					menuItems.append(None);
					menuItems.append(("By Material...", -777))
				#end if
				
				menuItems.append(None);
				
				menuItems.append(("Select All", -999))
				menuItems.append(("Clear All", -888))
				menuItems.append(None)
				menuItems.append(("Cancel", -1))
			#end if
			
			lio = popupMenu(menuItems, menuTitle)
			if lio!=-1:
				if not layer.isVisible():
					layer.setVisible(True)
					layerManager.updateVisible()
				#end if
				
				if lio==-999 or lio==-888:
					layer.selectObjects(lio==-999)
				elif lio==-777:
					mSortedKeys = sorted(olMaterials.keys())
					
					menuTitle = "Select By Material"
					menuItems = []
					
					idx = 0
					for materialName in mSortedKeys:
						menuDisplay = "%d - %s" % (olMaterials[materialName], materialName)
						menuOpt = "%x"+str(idx)
						
						menuItems.append((menuDisplay, idx))
						idx+=1
					#end for
					
					menuItems.append(None)
					menuItems.append(("Cancel", -1))
					
					lim = popupMenu(menuItems, menuTitle, 20)
					
					if lim!=-1:
						materialName = mSortedKeys[lim]
						layer.selectObjects(stateForType, Material.Get(materialName))
					#end if
				else:
					selectType = sortedKeys[lio]
					
					layer.selectObjects(stateForType, selectType)
				#end if
			#end if
		#end if
	else:
		return
	#end if
	
	if winIsScript: Window.Redraw(Window.Types.SCRIPT)	
	Window.Redraw()
	
#end button_event

def gui():
	#print "__gui__"
	
	global buttons
	global num_columns
	global winIsScript
	
	if winIsScript:
		cb = gndn
	else:
		cb = event
	#end if
	
	glClear(GL_COLOR_BUFFER_BIT)
	
	main_menu_buttons = buttons[MAIN_MENU_KEY]
	layer_group_buttons = buttons[LAYER_GROUPS_KEY]
	layer_functions_buttons = buttons[LAYER_FUNCTIONS_KEY]
	layer_visible_buttons = buttons[LAYER_PROPERTIES_KEY][VISIBLE_KEY]
	layer_selection_buttons = buttons[LAYER_PROPERTIES_KEY][SELECTED_KEY]
	layer_name_buttons = buttons[LAYER_PROPERTIES_KEY][NAMES_KEY]
	layer_info_buttons = buttons[LAYER_PROPERTIES_KEY][INFO_KEY]
	
	section_divider_height = 10
	section_divider_width = 10
	lnb_max_input_length = 20
	
	lvb_width = 20
	lsb_width = 20
	lnb_width = 146
	lib_width = 20
	b_height = 20
	
	column_width = lvb_width + lsb_width + lnb_width + lib_width + section_divider_width
	
	if winIsScript:
		start_x = 10
		
		#buff = Buffer(GL_INT, 4)
		#glGetIntegerv(GL_SCISSOR_BOX, buff) #[0] PosX, [1] PosY, [2] Width, [3] Height
		
		areaSize = Window.GetAreaSize()
		windowHeight = areaSize[1] # - 16
		
		numActive = len(layerManager.activeLayers())
		layerLines = numActive
		
		if num_columns==1:
			numLayerDividers = (layerLines-1)/5
		elif num_columns==2:
			if layerLines>10:
				layerLines = 10
			#end if
			numLayerDividers = (layerLines-1)/5
		elif num_columns==4:
			layerLines = 0
			numLayerDividers = 0
		#end if
		
		height = (4*b_height) + (2*section_divider_height) + 2 + (layerLines*b_height) + (numLayerDividers*section_divider_height)
		
		#print 'Window height', windowHeight, 'optimum gui height', height
		#print 'num Layer Dividers', numLayerDividers
		verticalAspect  = (windowHeight-12.0) / height
		
		#print 'raw verticalAspect', verticalAspect
		if verticalAspect > 1.0: verticalAspect = 1
		#print 'verticalAspect', verticalAspect
		
		b_height = int(b_height * verticalAspect)
		section_divider_height = int(section_divider_height * verticalAspect)
		
		start_y = windowHeight - section_divider_height - b_height #10
	else:
		global GLOBAL
		
		ui_width = column_width * num_columns + 10
		if num_columns==4: ui_width+= column_width
		
		start_x = GLOBAL['start_x']
		start_y = GLOBAL['start_y']
		
		GLOBAL['end_x'] = start_x + ui_width
	#end if
	
	ctr = 0
	pos_x = start_x
	pos_y = start_y
	
	main_menu_buttons[0] = Draw.Button("Menu", EVENT_MAIN_MENU, pos_x, pos_y, 50, b_height, "Main Menu", cb)
	main_menu_buttons[1] = Draw.Number("Layout", EVENT_NOEVENT, pos_x+57, pos_y, 80, b_height, decode(num_columns, 1, 1, 2, 2, 4, 3, 2), 1, 3, "Layout Type: 1 - Vertical, 2 - Square, 3 - Horizontal", changeLayout)
	main_menu_buttons[2] = Draw.Button("?",EVENT_HELP, pos_x+144, pos_y, 20, b_height, "View Layer Manager help documentation", cb)
	main_menu_buttons[3] = Draw.Button("Exit",EVENT_EXIT, pos_x+166, pos_y, 40, b_height, "Exit Mayer Manager", cb)
	
	#layer group controls
	
	pos_y = pos_y - b_height - section_divider_height
	
	layer_group_buttons[0] = Draw.Button("...", EVENT_LG_BROWSE, pos_x, pos_y,  15, b_height, "Select active layer group", cb)
	layer_group_buttons[1] = Draw.String("", EVENT_LG_CHANGE, pos_x+15, pos_y, 151, b_height, layerManager.activeLayerGroup.getName(), 25, "Displays current layer group name.  Click to change.", cb)
	layer_group_buttons[2] = Draw.PushButton("+", EVENT_LG_NEW, pos_x+166, pos_y, 20, b_height, "Creates a new layer group", cb)
	
	if len(layerManager.layerGroupList) > 1:
		layer_group_buttons[3] = Draw.PushButton("X", EVENT_LG_DELETE, pos_x+186, pos_y, 20, b_height, "Delete current layer group", cb)
	#end if
	
	#layer controls
	
	pos_y = pos_y - b_height - section_divider_height
	
	layer_functions_buttons[5] = Draw.PushButton("V->S", EVENT_VISIBLE_TO_SELECTED, pos_x, pos_y, 40, b_height, "Select only visible layers", cb)
	layer_functions_buttons[6] = Draw.PushButton("Hide", EVENT_SEL_HIDE, pos_x+42, pos_y, 50, b_height, "Hide selected layers", cb)
	layer_functions_buttons[7] = Draw.PushButton("Merge", EVENT_SEL_MERGE, pos_x+94, pos_y, 50, b_height, "Merge selected layers", cb)
	layer_functions_buttons[8] = Draw.PushButton("Move To", EVENT_SEL_MOVE, pos_x+146, pos_y, 60, b_height, "Move selected objects to selected layers", cb)
	
	pos_y = pos_y - b_height - 2
	
	layer_functions_buttons[0] = Draw.PushButton("-", EVENT_INVERT_VISIBLE, pos_x, pos_y, 20, b_height, "Invert visible layers", cb)
	layer_functions_buttons[1] = Draw.PushButton("-", EVENT_INVERT_SELECTED, pos_x+20, pos_y, 20, b_height, "Inver selected layers", cb)
	layer_functions_buttons[2] = Draw.PushButton("Reveal", EVENT_SEL_REVEAL,  pos_x+42, pos_y, 50, b_height, "Reveal hidden layers", cb)
	layer_functions_buttons[3] = Draw.PushButton("Flatten", EVENT_SEL_FLATTEN, pos_x+94, pos_y, 50, b_height, "Flatten selected layers", cb)
	layer_functions_buttons[4] = Draw.PushButton("Obj. Info.", EVENT_OBJ_INFO, pos_x+146, pos_y, 60, b_height, "Details of selected objects", cb)
	
	i = 0
	objCounts = layerManager.objectCountByLayer()
	layerInfoTips = {}
	
	if num_columns==4:
		pos_x = column_width + section_divider_width #225
		pos_y = start_y + b_height
	#end if
	
	pos_y = pos_y - b_height - 2
	start_y = pos_y
	
	for layer in layerManager.layerList:
		if not layer.isHidden():
			layerId = layer.getID()
			
			#try:
			objectCount = objCounts[layerId]
			#except IndexError:
			#	objectCount = 0
			##end try/except
			
			layer_visible_buttons[i] = Draw.Toggle(str(layerId), EVENT_LAYER_VISIBLE_BASE+i, pos_x, pos_y,  lvb_width, b_height, layer.isVisible(), "Click to "+decode(layer.isVisible(), True, "Not view", "View")+", Ctrl+Click to view only this layer", cb)
			pos_x = pos_x + lvb_width;
			
			layer_selection_buttons[i] = Draw.Toggle(decode(layer.isLocked(), True, "L", " "), EVENT_LAYER_SELECTED_BASE+i, pos_x, pos_y,  lsb_width, b_height, layer.isSelected(), "Click to "+decode(layer.isSelected(), True, "Unselect", "Select")+", Ctrl+Click to select only this layer, Shift+Click to "+decode(layer.isLocked(), True, "Unlock", "Lock"), cb)
			pos_x = pos_x + lsb_width;
			
			layer_name_buttons[i] = Draw.String("", EVENT_LAYER_NAME_BASE+i, pos_x, pos_y, lnb_width, b_height, layer.getName(), lnb_max_input_length, "Layer Name, Click to edit", cb)
			pos_x = pos_x + lnb_width;
			
			if objectCount==0:
				infoDecoration = ""
			elif objectCount>99:
				infoDecoration = "##"
			else:
				infoDecoration = str(objectCount)
			#end if
			
			layerInfoTips[layerId] = "Select %d objects by type, Shit+Click to select not of type, Ctrl+Click to select ONLY objects in this layer" % (objectCount)
			
			layer_info_buttons[i] = Draw.PushButton(infoDecoration, EVENT_LAYER_INFO_BASE+i, pos_x, pos_y,  lib_width, b_height, layerInfoTips[layerId], cb)
			pos_x = pos_x + lib_width;
			
			ctr = ctr + 1
			pos_y = pos_y - b_height
			
			if ctr%5==0:
				pos_y = pos_y - section_divider_height
			#end if
			
			if ctr%(20/num_columns)==0:
				pos_x = pos_x + section_divider_width
				pos_y = start_y
			else:
				pos_x = pos_x - column_width + 10
			#end if
		#end if
		
		i+=1
		
	#end for
	
	layerManager.updateVisible()
#end gui

def gndn(evt, val):
	pass
#end gndn

#
# Event and Draw Functions
####################################################################################

####################################################################################
#
# Main
#
####################################################################################

init()

global winIsScript
winIsScript = True

areaId = Window.GetAreaID()
print 'Run request from area id', areaId

for win in Window.GetScreenInfo(type=Window.Types.VIEW3D):
	winId = win['id']	
	
	if areaId==winId:
		print 'Area is 3D window'
		winIsScript = False
		break
	#end if	
#end for

Window.Redraw()

if winIsScript==True:
	print "Run from script/text window"
	Draw.Register(gui, event, button_event)
else:
	print "Run via UIBlock"
	uiBlockExit = False
	
	start_x, start_y = [i for i in Window.GetMouseCoords()]
	
	GLOBAL = {
		'start_x': start_x,
		'start_y': start_y
	}
	
	while not uiBlockExit:
		Draw.UIBlock(gui)
		
		mouse_x, mouse_y = [i for i in Window.GetMouseCoords()]
		
		if GLOBAL['start_x']-mouse_x > 10: break
		if mouse_x-GLOBAL['end_x'] > 10: break
	#end while
	
	Window.Redraw()
	
	print "Layer Manager stop"
#end if
