# Change the selected parameter(s) via the mouse wheel v3.7
# and much more see http://neocron.lunarpages.com/alforum/index.php?topic=1511.0
# changes: 
#	return/enter doesn't deactivate panel, layout and position saved by room (if it can be guessed), 
#	LightAttenuation can be set, Undo/Redo and Value changes work for V4's chest rotation that cannot be called by it's Parameter name (Twist)
#	normals forwards not only for root node, 
#	decrease/increase Diffuse-Value by multiplier value diffuseMulti
#	SetGamma for Poser Pro
#	Checkbox to modify parented and conformed items, too (useful for changing properties/mats), Camera/Lighs checkboxes combined to one checkbox to save space
#	no more errors with multiple GoalCenterOfMass etc. props
#	added context menu for actor list: allows duplicating selected actors (will use Poser's duplicate feature) and if wished to select all duplicated actors
#	set the units used to display translation values to inches, foot, millimeter, centimeter, meter or a custom value ;-) (see setup tab)
# - Python coding by Dizzi
import poser
import wx
import wx.aui
import os.path
import random
import wx.lib.masked.numctrl
import math
import pickle

class WheelPosing(wx.Panel):
	diffuseMulti=0.9 #set to the value you like...
	CustomUnit=1 # custom display unit for translations
	
	SavePath=os.path.join(poser.PrefsLocation(), "acb", "multiactor")
	PanelLayout={}
	selectedParamName=""
#	multi=1
	value=1.0
	Amount="1"
	Digit=1
	Exponent=0
	Actors=[]
	RotTrans=[poser.kParmCodeXROT, poser.kParmCodeYROT, poser.kParmCodeZROT, poser.kParmCodeXTRAN, poser.kParmCodeYTRAN, poser.kParmCodeZTRAN]
	RotTransString=["Rotate X", "Rotate Y", "Rotate Z", "Translate X", "Translate Y", "Translate Z"]
	InternalItems=["GoalCenterOfMass","CenterOfMass", "faceRoomActor", "faceRoomTexActor"]
	Undos=[]
	Redos=[]
	LastActor=None
	KeyActors={}
	changedMats=[]
	UnitDivisor=[]
	
	def __init__(self,parent,title, pane):
		wx.Panel.__init__(self, parent, -1, wx.Point(-1, -1), wx.DefaultSize, wx.WANTS_CHARS)
		self.dlgGamma=None
		self.dlgDuplicate=wx.NumberEntryDialog(self, "Please enter how often to duplicate the selected actors", "Amount: ", "Duplicatie actors", 1, 1, 100)
	
		self.man=poser.WxAuiManager()
		
		if not os.path.exists(self.SavePath):
			os.mkdir(self.SavePath)
		
		self.PanelLayoutFile=os.path.join(self.SavePath, "PanelLayout_"+self.TryFindRoom()+".config")
		if os.path.exists(self.PanelLayoutFile):
			fd=open(self.PanelLayoutFile)
			self.PanelLayout=pickle.load(fd)
			fd.close()
			if self.PanelLayout.has_key("PanelLayout"):
				self.man.LoadPaneInfo(self.PanelLayout["PanelLayout"], pane)
		self.settingsFile=os.path.join(self.SavePath, "Settings.config")
		
		DefaultUnit=0
		self.settings={}
		if os.path.exists(self.settingsFile):
			fd=open(self.settingsFile)
			self.settings=pickle.load(fd)
			fd.close()
			if self.settings.has_key("diffuseMulti"):
				self.diffuseMulti=self.settings["diffuseMulti"]
			if self.settings.has_key("CustomUnit"):
				self.CustomUnit=self.settings["CustomUnit"]
			if self.settings.has_key("DefaultUnit"):
				DefaultUnit=self.settings["DefaultUnit"]
		
		self.sizer = wx.BoxSizer(wx.VERTICAL)
		self.SetSizer(self.sizer)
		self.SetAutoLayout(1)
		#self.sizer.SetSizeHints(self)
		self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
		self.sizer.Add(self.sizer2)
		l=self.GetActorParamList()
		list=self.GetActorParamList()[0]
		self.Params=l[1]
		radioList = ['Actor', 'Figure', 'All']
		self.rbType = wx.RadioBox(self, 40, "Type", wx.Point(-1, -1), wx.DefaultSize, radioList, 1, wx.RA_SPECIFY_COLS)
		self.Bind(wx.EVT_RADIOBOX, self.EvtRbType, self.rbType)
		self.sizer2.Add(self.rbType)
		
		staticBox = wx.StaticBox(self, -1, "Actors")
		self.szActorType = wx.StaticBoxSizer(staticBox, wx.VERTICAL)
		self.cbCamLights = wx.CheckBox(self, 21, "Cam/Light")
		self.cbCamLights.Bind(wx.EVT_CHECKBOX, self.EvtChkboxActorType)
		self.szActorType.Add(self.cbCamLights)
		self.cbMagnets = wx.CheckBox(self, 23, "Magnet")
		self.cbMagnets.Bind(wx.EVT_CHECKBOX, self.EvtChkboxActorType)
		self.szActorType.Add(self.cbMagnets)
		self.cbProps = wx.CheckBox(self, 23, "Prop")
		self.cbProps.Bind(wx.EVT_CHECKBOX, self.EvtChkboxActorType)
		self.cbProps.SetValue(True)
		self.szActorType.Add(self.cbProps)
		self.cbHidden = wx.CheckBox(self, 24, "Hidden")
		self.cbHidden.Bind(wx.EVT_CHECKBOX, self.EvtChkboxActorType)
		#self.cbHidden.SetValue(True)
		self.szActorType.Add(self.cbHidden)
		self.cbParented = wx.CheckBox(self, 25, "Parented")
		self.cbParented.Bind(wx.EVT_CHECKBOX, self.EvtChkboxActorType)
		self.cbParented.Enable(False)
		self.szActorType.Add(self.cbParented)
		self.sizer2.Add(self.szActorType)
		self.sizer2.Hide(self.szActorType)
		
		self.rbTransType = wx.RadioBox(self, 44, "Translate", wx.Point(-1, -1), wx.DefaultSize, ["Equally", "N*A", "Random"], 1, wx.RA_SPECIFY_COLS)
		self.Bind(wx.EVT_RADIOBOX, self.EvtRbTransType, self.rbTransType)
		self.rbTransType.Show(0)
		self.sizer2.Add(self.rbTransType)

		self.lbActors = wx.ListBox(self, 50, (-1, -1), self.GetSize("lbActors", (175, 100)), [], wx.LB_EXTENDED|wx.LB_NEEDED_SB)
		self.lbActors.Multiselect=1
		self.sizer.Add(self.lbActors)
		self.lbActors.Show(0);
		
		self.tabs = wx.Notebook(self, -1, wx.DefaultPosition, wx.DefaultSize)
		self.sizer.Add(self.tabs)
		self.tabs.SetAutoLayout(True)
		
		self.tab1 = wx.Panel(self.tabs, -1, wx.Point(-1, -1), wx.DefaultSize, wx.WANTS_CHARS)
		self.tabs.AddPage(self.tab1, "Param", True)
		self.sizerTab1= wx.BoxSizer(wx.VERTICAL)
		self.tab1.SetSizer(self.sizerTab1)
		
		self.lbParams = wx.ListBox(self.tab1, 60, (-1, -1), self.GetSize("lbParams", (175, 100)), list, wx.LB_EXTENDED|wx.LB_NEEDED_SB)
		self.tab1.Bind(wx.EVT_LISTBOX, self.EvtListBoxClick, self.lbParams)
		self.sizerTab1.Add(self.lbParams)
		
		
		fgsGridInputs=wx.FlexGridSizer(2,3,2,1)
		self.sizerTab1.Add(fgsGridInputs)
		# input value
		lblValue = wx.StaticText(self.tab1, -1, "Value: ", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_RIGHT)
		self.txtValue = wx.lib.masked.NumCtrl(self.tab1, 0, "0.0")
		self.txtValue.SetFractionWidth(6)
		self.txtValue.SetIntegerWidth(6)
		self.txtValue.SetAllowNone(False)
		self.txtValue.SetAllowNegative(True)
		self.txtValue.SetGroupDigits(False)
		self.txtValue.SetEditable(False)
		fgsGridInputs.Add(lblValue, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
		fgsGridInputs.Add(self.txtValue)
		fgsGridInputs.Add(wx.StaticText(self.tab1, -1, ""))
		
		# amount label and input
		lblAmount = wx.StaticText(self.tab1, -1, "Amount: ", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_RIGHT)
		self.txtAmount = wx.lib.masked.NumCtrl(self.tab1, 0)
		self.txtAmount.SetFractionWidth(6)
		self.txtAmount.SetIntegerWidth(6)
		self.txtAmount.SetAllowNone(True)
		self.txtAmount.SetAllowNegative(True)
		self.txtAmount.SetGroupDigits(False)
		self.txtAmount.SetEditable(False)
		self.txtAmount.SetLimited(True)
		self.txtAmount.SetLimitOnFieldChange(True)
		self.txtAmount.SetMax("999999.999999")
		self.txtAmount.SetValue(self.Amount)
		self.lblDigit = wx.StaticText(self.tab1, -1, "+1", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_LEFT)
		fgsGridInputs.Add(lblAmount, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
		fgsGridInputs.Add(self.txtAmount)
		fgsGridInputs.Add(self.lblDigit, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
		
		#undo
		self.sizer3 = wx.BoxSizer(wx.HORIZONTAL)
		self.sizerTab1.Add(self.sizer3)
		self.btnInvert = wx.Button(self.tab1, 61, "Invert")
		self.sizer3.Add(self.btnInvert)
		self.btnSet = wx.Button(self.tab1, 62, "Set")
		self.sizer3.Add(self.btnSet)
		
		#undo
		self.sizerUndo = wx.BoxSizer(wx.HORIZONTAL)
		self.sizerTab1.Add(self.sizerUndo)
		self.btnUndo = wx.Button(self.tab1, 71, "Undo")
		self.btnUndo.Enable(False)
		self.sizerUndo.Add(self.btnUndo)
		self.btnRedo = wx.Button(self.tab1, 72, "Redo")
		self.btnRedo.Enable(False)
		self.sizerUndo.Add(self.btnRedo)
		
		
		#
		self.tab2 = wx.Panel(self.tabs, -1, wx.Point(-1, -1), wx.DefaultSize, wx.WANTS_CHARS)
		self.tabs.AddPage(self.tab2, "Prop", False)
		self.sizerTab2= wx.BoxSizer(wx.HORIZONTAL)
		self.tab2.SetSizer(self.sizerTab2)
		
		staticBoxGeneral = wx.StaticBox(self.tab2, -1, "General")
		szGeneral = wx.StaticBoxSizer(staticBoxGeneral, wx.VERTICAL)
		self.btnShow = wx.Button(self.tab2, 101, "Show")
		szGeneral.Add(self.btnShow)
		self.btnHide = wx.Button(self.tab2, 102, "Hide")
		szGeneral.Add(self.btnHide)
		self.sizerTab2.Add(szGeneral)
		
		staticBoxLight = wx.StaticBox(self.tab2, -1, "Light")
		szLight = wx.StaticBoxSizer(staticBoxLight, wx.VERTICAL)
		self.btnOn = wx.Button(self.tab2, 111, "On")
		szLight.Add(self.btnOn)
		self.btnOff = wx.Button(self.tab2, 112, "Off")
		szLight.Add(self.btnOff)
		self.btnRayTrace = wx.Button(self.tab2, 121, "Ray Trace")
		szLight.Add(self.btnRayTrace)
		self.btnDepthMap = wx.Button(self.tab2, 122, "Depth Map")
		szLight.Add(self.btnDepthMap)
		self.btnAttenConst = wx.Button(self.tab2, 123, "Constant")
		szLight.Add(self.btnAttenConst)
		self.btnAttenSqu = wx.Button(self.tab2, 124, "Inv Linear")
		szLight.Add(self.btnAttenSqu)
		self.btnAttenLin = wx.Button(self.tab2, 125, "Inv Square")
		szLight.Add(self.btnAttenLin)
		
		self.sizerTab2.Add(szLight)
		
		#Materials
		self.tab4 = wx.Panel(self.tabs, -1, wx.Point(-1, -1), wx.DefaultSize, wx.WANTS_CHARS)
		self.tabs.AddPage(self.tab4, "Mats", False)
		self.sizerTab4= wx.GridBagSizer(2,2)
		self.tab4.SetSizer(self.sizerTab4)
		
		staticBoxTexFilter = wx.StaticBox(self.tab4, -1, "Filtering")
		szTexFilter = wx.StaticBoxSizer(staticBoxTexFilter, wx.VERTICAL)
		self.sizerTab4.Add(szTexFilter, wx.GBPosition(0,0))
		self.btnMatFilterOff = wx.Button(self.tab4, 131, "Quality")
		szTexFilter.Add(self.btnMatFilterOff)
		self.btnMatFilterFast = wx.Button(self.tab4, 132, "Fast")
		szTexFilter.Add(self.btnMatFilterFast)
		self.btnMatFilterQuality = wx.Button(self.tab4, 133, "None")
		szTexFilter.Add(self.btnMatFilterQuality)
		
		staticBoxNForward = wx.StaticBox(self.tab4, -1, "N-Forward")
		szNForward = wx.StaticBoxSizer(staticBoxNForward, wx.VERTICAL)
		self.sizerTab4.Add(szNForward, wx.GBPosition(0,1))
		self.btnNForwardOn = wx.Button(self.tab4, 141, "On")
		szNForward.Add(self.btnNForwardOn)
		self.btnNForwardOff = wx.Button(self.tab4, 142, "Off")
		szNForward.Add(self.btnNForwardOff)

		staticBoxReflMult = wx.StaticBox(self.tab4, -1, "Refl_x_Mult")
		szReflMult = wx.StaticBoxSizer(staticBoxReflMult, wx.VERTICAL)
		self.sizerTab4.Add(szReflMult, wx.GBPosition(1,0))
		self.btnReflOn = wx.Button(self.tab4, 151, "On")
		szReflMult.Add(self.btnReflOn)
		self.btnReflOff = wx.Button(self.tab4, 152, "Off")
		szReflMult.Add(self.btnReflOff)

		staticBox = wx.StaticBox(self.tab4, -1, "Diffuse-Value")
		sz = wx.StaticBoxSizer(staticBox, wx.VERTICAL)
		self.sizerTab4.Add(sz, wx.GBPosition(1,1))
		self.btnDiffuseDec = wx.Button(self.tab4, 161, "Decrease")
		sz.Add(self.btnDiffuseDec)
		self.btnDiffuseInc = wx.Button(self.tab4, 162, "Increase")
		sz.Add(self.btnDiffuseInc)
		self.SetDiffuseToolTips()
		
		if poser.IsPro():
			self.sizerTab4.Add(wx.Button(self.tab4, 990, "Set Gamma"), wx.GBPosition(2,0))
		
		# layout
		self.tab3 = wx.Panel(self.tabs, -1, wx.Point(-1, -1), wx.DefaultSize, wx.WANTS_CHARS)
		p=self.tab3
		self.tabs.AddPage(self.tab3, "Setup", False)
		self.sizerTab3= wx.BoxSizer(wx.VERTICAL)
		self.tab3.SetSizer(self.sizerTab3)
		fgsLayout=wx.FlexGridSizer(2,3,2,1)
		self.sizerTab3.Add(fgsLayout)
		
		# input value
		lbl = wx.StaticText(self.tab3, -1, "Object", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_CENTER)
		fgsLayout.Add(lbl, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL)
		lbl = wx.StaticText(self.tab3, -1, "Width", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_CENTER)
		fgsLayout.Add(lbl, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL)
		lbl = wx.StaticText(self.tab3, -1, "Height", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_CENTER)
		fgsLayout.Add(lbl, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL)
		
		lbl = wx.StaticText(self.tab3, -1, "Parameters", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_RIGHT)
		self.spLoPX  = wx.SpinCtrl(id=1, initial=self.lbParams.GetSizeTuple()[0], max=999, min=50, parent=self.tab3, pos=wx.Point(-1, -1), size=(60,-1), style=wx.SP_ARROW_KEYS)
		self.spLoPY  = wx.SpinCtrl(id=1, initial=self.lbParams.GetSizeTuple()[1], max=999, min=50, parent=self.tab3, pos=wx.Point(-1, -1), size=(60,-1), style=wx.SP_ARROW_KEYS)
		fgsLayout.Add(lbl, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
		fgsLayout.Add(self.spLoPX, 0, wx.ALIGN_CENTER)
		fgsLayout.Add(self.spLoPY, 0, wx.ALIGN_CENTER)

		lbl = wx.StaticText(self.tab3, -1, "Actors", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_RIGHT)
		self.spLoAX  = wx.SpinCtrl(id=2, initial=self.lbActors.GetSizeTuple()[0], max=999, min=50, parent=self.tab3, pos=wx.Point(-1, -1), size=(60,-1), style=wx.SP_ARROW_KEYS)
		self.spLoAY  = wx.SpinCtrl(id=2, initial=self.lbActors.GetSizeTuple()[1], max=999, min=50, parent=self.tab3, pos=wx.Point(-1, -1), size=(60,-1), style=wx.SP_ARROW_KEYS)
		fgsLayout.Add(lbl, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
		fgsLayout.Add(self.spLoAX, 0, wx.ALIGN_CENTER)
		fgsLayout.Add(self.spLoAY, 0, wx.ALIGN_CENTER)
		self.tab3.Bind(wx.EVT_SPINCTRL, self.EvtSpin)
		
		self.sizerTab3.AddSpacer(10)
		s=wx.BoxSizer(wx.HORIZONTAL)
		self.sizerTab3.Add(s)
		s.Add(wx.StaticText(p, -1, "Diffuse Multi: "))
		self.ncDiffuse=wx.lib.masked.numctrl.NumCtrl(parent=p, value=self.diffuseMulti, id=1000, integerWidth=1, fractionWidth=3,allowNegative=False, min=0.1, max=0.999, limitOnFieldChange=True)
		self.ncDiffuse.Bind(wx.EVT_TEXT, self.EvtText)
		s.Add(self.ncDiffuse)
		
		self.sizerTab3.AddSpacer(10)
		radioList = ['Poser native units', 'Inches', 'Feet', 'Millimeter', 'Centimeter', 'Meter', 'Custom (1 PNU=X Custom)']
		self.UnitMultiplier=[1.0, 0.009689922332760, 0.116279064941000, 0.000381492993164000, 0.00381492993164000, 0.381492993164000, self.CustomUnit]
		self.rbUnit = wx.RadioBox(p, 70, "Units used for Translations", wx.Point(-1, -1), wx.DefaultSize, radioList, 1, wx.RA_SPECIFY_COLS)
		self.rbUnit.SetSelection(DefaultUnit)
		self.sizerTab3.Add(self.rbUnit)
		self.Bind(wx.EVT_RADIOBOX, self.EvtUnit, self.rbUnit)
		s=wx.BoxSizer(wx.HORIZONTAL)
		self.sizerTab3.Add(s)
		s.Add(wx.StaticText(p, -1, "1 PNU=X Custom: "))
		self.ncCustomUnit=wx.lib.masked.numctrl.NumCtrl(parent=p, value=self.CustomUnit, id=1001, integerWidth=5, fractionWidth=10,allowNegative=False)
		self.ncCustomUnit.Bind(wx.EVT_TEXT, self.EvtText)
		s.Add(self.ncCustomUnit)
		
		#bind mousewheel on listboxes so moving the wheel without pressing will work
		self.Bind(wx.EVT_BUTTON, self.EvtButton)
		self.tab1.Bind(wx.EVT_BUTTON, self.EvtButton)
		self.tab2.Bind(wx.EVT_BUTTON, self.EvtButton)
		self.Bind(wx.EVT_MOUSEWHEEL, self.EvtWheel)
		self.lbParams.Bind(wx.EVT_MOUSEWHEEL, self.EvtWheel)
		self.lbActors.Bind(wx.EVT_MOUSEWHEEL, self.EvtWheel)

		#bind keyevents so Poser doesn't get them. Ha!
		self.Bind(wx.EVT_CHAR, self.EvtKey)
		self.lbParams.Bind(wx.EVT_CHAR, self.EvtKey)
		self.lbActors.Bind(wx.EVT_CHAR, self.EvtKey)
		self.rbType.Bind(wx.EVT_CHAR, self.EvtKey)
		self.rbTransType.Bind(wx.EVT_CHAR, self.EvtKey)
		self.txtValue.Bind(wx.EVT_CHAR, self.EvtKey)
		self.txtAmount.Bind(wx.EVT_CHAR, self.EvtKey)
		
#		self.Layout()
#		poser.Scene().SetEventCallback(self.EvcbParam)
		self.timer = wx.Timer(self)
		self.Bind(wx.EVT_TIMER, self.EvtTimer, self.timer)
		self.timer.Start(100)  # x100 milliseconds
		
		self.Bind(wx.EVT_SIZE,self.EvtChildFocus)
		self.Bind(wx.EVT_CHILD_FOCUS, self.EvtChildFocus)
		self.Bind(wx.EVT_RIGHT_DOWN, self.ShowContextMenu)
		self.lbActors.Bind(wx.EVT_RIGHT_DOWN, self.ShowActorContextMenu)
		self.Bind(wx.EVT_MENU, self.ExecuteMenuCommand)
		self.lbActors.Bind(wx.EVT_MENU, self.ExecuteMenuCommand)

		self.Bind(wx.EVT_NAVIGATION_KEY, self.EvtDoNothing)
		
		self.KeyActorsFile=os.path.join(self.SavePath, "key_actor.config")
		if os.path.exists(self.KeyActorsFile):
			fd=open(self.KeyActorsFile)
			self.KeyActors=pickle.load(fd)
			fd.close()
	def __del__(self):
		try:
			fd=open(self.KeyActorsFile, "w")
			pickle.dump(self.KeyActors,fd)
			fd.close()
		except:
			pass
		try:
			fd=open(self.PanelLayoutFile, "w")
			pickle.dump(self.PanelLayout,fd)
			fd.close()
		except:
			pass
	def EvtDoNothing(self, event):
		print event
		return
#		poser.Scene().ClearEventCallback()
	def EvtChildFocus(self, event):
		self.SaveLayout()
		event.Skip()
	def SaveLayout(self):
		pane=self.man.GetPane(self)
		pane.BestSize(pane.floating_size)
		self.PanelLayout["PanelLayout"]=self.man.SavePaneInfo(pane)
	def TryFindRoom(self):
		for pane in self.man.GetAllPanes():
			if pane.name.startswith("Hair") and pane.IsShown():
				return "Hair"
			elif pane.name.startswith("Cloth") and pane.IsShown():
				return "Cloth"
			elif pane.name.startswith("Material") and pane.IsShown():
				return "Material"
		return "Default"

	def EvtText(self, event):
		if event.Id==1000:
			val=self.ncDiffuse.GetValue()
			if val>=1 or val<0.1:return
			self.diffuseMulti=val
			self.SetDiffuseToolTips()
			self.settings["diffuseMulti"]=val
			fd=open(self.settingsFile, "w")
			pickle.dump(self.settings,fd)
			fd.close()
		if event.Id==1001:
			val=self.ncCustomUnit.GetValue()
			self.CustomUnit=val
			self.settings["CustomUnit"]=val
			fd=open(self.settingsFile, "w")
			pickle.dump(self.settings,fd)
			fd.close()
	def SetDiffuseToolTips(self):
		self.btnDiffuseDec.SetToolTip(wx.ToolTip("Increase or decrease the Diffuse-Value\nValue will be multiplied/divided by "+str(self.diffuseMulti)))
		self.btnDiffuseInc.SetToolTip(wx.ToolTip("Increase or decrease the Diffuse-Value\nValue will be multiplied/divided by "+str(self.diffuseMulti)))
	
	def EvtKey(self,event):
		event.StopPropagation()
		code=event.GetKeyCode()
		if code==wx.WXK_F1:
			self.SetDigit(5)
		elif code==wx.WXK_F2:
			self.SetDigit(4)
		elif code==wx.WXK_F3:
			self.SetDigit(3)
		elif code==wx.WXK_F4:
			self.SetDigit(2)
		elif code==wx.WXK_F5:
			self.SetDigit(1)
		elif code==wx.WXK_F6:
			self.SetDigit(0)
		elif code==wx.WXK_F7:
			self.SetDigit(-1)
		elif code==wx.WXK_F8:
			self.SetDigit(-2)
		elif code==wx.WXK_F9:
			self.SetDigit(-3)
		elif code==wx.WXK_F10:
			self.SetDigit(-4)
		elif code==wx.WXK_F11:
			self.SetDigit(-5)
		elif code==wx.WXK_F12:
			self.SetDigit(-6)
		elif code==wx.WXK_LEFT:
			self.SetDigit(min(self.Exponent+1, 5))
		elif code==wx.WXK_RIGHT:
			self.SetDigit(max(self.Exponent-1, -6))
		elif code==wx.WXK_UP:
			self.SetAmount(self.txtAmount.GetValue()+self.Digit)
		elif code==wx.WXK_DOWN:
			val=self.txtAmount.GetValue()-self.Digit
			if (val>=0):
				self.SetAmount(val)
		elif code==wx.WXK_BACK:
			val=self.Amount
			if (len(val)>0):
				val=val[0:len(val)-1]
				self.SetAmount(val)
		elif code==wx.WXK_SPACE:
			self.SetAmount("")
		elif code==wx.WXK_RETURN:
			print 'x'
		elif code>255:
			return
		else:
			char=chr(code)
			if char.isdigit() or char==',' or char=='.':
				if char==',':
					char="."
				val=self.Amount
				if val=='' and char=='.':
					val="0.";
				else:
					val=val+char
				if self.IsNumber(val):
					self.SetAmount(val)
			elif char.isalpha():
				if char.isupper():
					l=[]
					for ix in self.lbActors.GetSelections():
						l.append(self.lbActors.GetString(ix))
					self.KeyActors[char.lower()]=l
				else:
					self.lbActors.DeselectAll()
					if self.KeyActors.has_key(char.lower()):
						for s in self.KeyActors[char.lower()]:
							i=self.lbActors.FindString(s)
							if i!=wx.NOT_FOUND:
								self.lbActors.Select(i)
	def EvtSpin(self, event):
		if event.Id==1:
			self.SetSizeParams(self.spLoPX.GetValue(), self.spLoPY.GetValue())
		elif event.Id==2:
			self.SetSizeActors(self.spLoAX.GetValue(), self.spLoAY.GetValue())
	def SetSizeParams(self, x, y):
		self.lbParams.SetSize((x,y))
		self.PanelLayout["lbParams"]=(x,y)
		self.sizerTab1.SetItemMinSize(self.lbParams, (x,y))
		self.tab1.Layout()
		self.tab1.Fit()
	def SetSizeActors(self, x, y):
		self.lbActors.SetSize((x,y))
		self.PanelLayout["lbActors"]=(x,y)
		self.sizer.SetItemMinSize(self.lbActors, (x,y))
		self.PanelLayout()
	def GetSize(self, component, defaultSize):
		if self.PanelLayout.has_key(component): 
			return self.PanelLayout[component]
		return defaultSize
#	def EvtEnter(self,event):
#		event.StopPropagation()
#		self.UpdateAmount()
#	def UpdateAmount(self):
#		val=self.txtNewAmount.GetValue()
#		if (self.IsNumber(val)):
#			self.txtAmount.SetValue(str(float(val)))
#		self.txtNewAmount.SetValue("")
	def SetAmount(self, val):
		val=str(val)
		self.Amount=val
		if len(val)==0:
			self.txtAmount.SetValue(None)
		else:
			if self.txtAmount.IsInBounds(val):
				self.txtAmount.SetValue(val)
	def SetDigit(self, exponent):
		self.Exponent=exponent
		self.Digit=math.pow(10, exponent)
		if (exponent>=0):
			self.lblDigit.SetLabel("+"+str(exponent+1))
		else:
			self.lblDigit.SetLabel(str(exponent))
	def SetValue(self, value):
		if value<0 and value>-0.000001: value=0.0
		self.txtValue.SetValue(value)
	def IsNumber(self, s):
		try:
			float(s)
			return True
		except ValueError:
			return False
	def EvtRbType(self, event):
		self.CheckList('T')
		self.lbParams.SetFocus()
	def EvtRbTransType(self, event):
		self.lbParams.SetFocus()
	def EvtListBoxClick(self, event):
		self.SelectedParametersChanged()
	def EvtChkboxActorType(self, event):
		self.CheckList('A')
	def CheckList(self, type):
		if self.rbType.GetSelection()==0 and (type=='C' or type=='T'):
			l=self.GetActorParamList()
			self.UpdateParams(l[0])
			self.Param=l[1]
			self.sizer2.Hide(self.szActorType)
			self.lbActors.Show(0)
			self.rbTransType.Show(0)
			self.cbParented.Enable(0)
		elif (self.rbType.GetSelection()==1):
			self.UpdateActors(self.GetFigureActors())
			self.UpdateParams(self.RotTransString[:3])
			self.Param=self.RotTrans[:3]
			self.sizer2.Show(self.szActorType)
			self.lbActors.Show(1)
			self.rbTransType.Show(0)
			self.cbParented.Enable(0)
		elif (self.rbType.GetSelection()==2):
			self.UpdateActors(self.GetUniverseActors())
			self.UpdateParams(self.RotTransString)
			self.Param=self.RotTrans
			self.sizer2.Show(self.szActorType)
			self.lbActors.Show(1)
			self.rbTransType.Show(1)
			self.cbParented.Enable(1)
		else:
			return
		self.sizer.Layout()
		self.Layout()
	def GetActorParamList(self):
		list=[]
		Param=[]
		for parm in poser.Scene().CurrentActor().Parameters():
			if not parm.Hidden():
			   list = list + [parm.Name()]
			   Param = Param + [parm.InternalName()]
		return [list, Param]
	def UpdateParams(self, lNewNames):
		lCurrentNames=self.lbParams.GetItems()
		bSame=True #old==new actors?
		for param in lCurrentNames:
			if not param in lNewNames:
				bSame=False
				break
		for param in lNewNames:
			if not param in lCurrentNames:
				bSame=False
				break
		if bSame:
			return
		lSelectedIx=self.lbParams.GetSelections()
		self.lbParams.Set(lNewNames)
		for i in range(len(lSelectedIx)): #select the previous selected actors
			try:
				ix=lNewNames.index(lCurrentNames[lSelectedIx[i]])
			except ValueError:
				continue
			self.lbParams.Select(ix)
	def UpdateActors(self, lNewActors, lNewActorsToSelect=()):
		bSame=True #old==new actors?
		for actor in self.Actors:
			if not actor in lNewActors[0]:
				bSame=False
				break
		for actor in lNewActors[0]:
			if not actor in self.Actors:
				bSame=False
				break
		if bSame:
			return
		lSelectedIx=self.lbActors.GetSelections()
		self.lbActors.Clear() #clear list
		self.lbActors.AppendItems(lNewActors[1]) #add all new actors
		for i in range(len(lSelectedIx)): #select the previous selected actors
			try:
				ix=lNewActors[0].index(self.Actors[lSelectedIx[i]])
			except ValueError:
				continue
			self.lbActors.Select(ix)
		for sa in lNewActorsToSelect:
			self.lbActors.Select(lNewActors[0].index(sa))
		self.Actors=lNewActors[0]
		
	def SelectedParametersChanged(self):
		if (self.rbType.GetSelection()==0):
			list=self.lbParams.GetSelections()
#			for ix in self.lbParams.GetSelections():
#				list = list + [self.lbParams.GetString(ix)]
			if len(list)==1:
				self.selectedParamName=self.lbParams.GetString(list[0])
				#check by internal name, because V4's chest rotation parameter 'twist' cannot be called by its name
				try:
					param=self.GetParamByInternalName(poser.Scene().CurrentActor(), self.Params[list[0]])
					if (param.TypeCode() in self.RotTrans[3:]): #is translation type... adjust amount
						self.value=param.Value()/self.UnitMultiplier[self.rbUnit.GetSelection()]
					else:
						self.value=param.Value()
				except:
					self.value=0
			else:
				self.selectedParamName=""
				self.value=0
		elif (self.rbType.GetSelection()==1):
			self.value=0
		elif (self.rbType.GetSelection()==2):
			self.value=0
		self.SetValue(self.value)
	def GetParamByInternalName(self, actor, name):
		for param in actor.Parameters():
			if param.InternalName()==name:
				return param
		return None
	def GetFigureActors(self):
		list=([],[])
#		try:
		fig=poser.Scene().CurrentFigure()
		if fig==None:
			return list
		name=fig.Name()
		for actor in fig.Actors():
			if self.IsInternalItem(actor.InternalName()):
				continue
			#print actor.InternalName()
			if (
				self.ActorIsBody(actor) 
				or (actor.InternalName()==actor.ItsFigure().InternalName())
				or (actor.IsCamera() and self.cbCamLights.GetValue()) 
				or (actor.IsLight() and self.cbCamLights.GetValue()) 
				or actor.IsBodyPart() 
				or ((actor.IsProp() or actor.IsHairProp()) and self.cbProps.GetValue()) 
				or ((actor.IsBase() or actor.IsDeformer() or actor.IsZone()) and self.cbMagnets.GetValue())
			) and (self.cbHidden.GetValue() or actor.OnOff()==1):
				list[0].append(actor.InternalName())
				list[1].append(actor.Name())
#		except:
#			pass
		return list
	def GetUniverseActors(self):
		l=self.GetAllChildActors(poser.Scene().Actor("UNIVERSE"))
		#print l
		return l
	def GetAllChildActors(self, parent, prefix=""):
		list=([],[])
		for actor in parent.Children():
			name=actor.Name()
			newprefix=prefix
			#print actor.Name(), actor.IsBodyPart(), actor.OnOff()
			if self.IsInternalItem(actor.InternalName()):
				continue
			if (
				(actor.IsCamera() and self.cbCamLights.GetValue()) 
				or (actor.IsLight() and self.cbCamLights.GetValue())
				or (actor.IsProp() and self.cbProps.GetValue())
				or ((actor.IsBase() or actor.IsDeformer() or actor.IsZone()) and self.cbMagnets.GetValue())
			) and (self.cbHidden.GetValue() or actor.OnOff()==1):
				list[0].append(actor.InternalName())
				list[1].append(prefix + name)
			elif actor.IsBodyPart():
				if actor.ItsFigure().ConformTarget()!=None and self.cbParented.GetValue()==False:
					continue
				parentBelongsToSameFigure=parent.IsBodyPart() and (parent.ItsFigure()!=None and parent.ItsFigure().InternalName()==actor.ItsFigure().InternalName())
				if not parentBelongsToSameFigure and self.IsFigurePartVisible(actor.ItsFigure())==1:
					name=actor.ItsFigure().Name()# + ">" +actor.Name()
					list[0].append(actor.InternalName())
					list[1].append(prefix + name)
					newprefix=prefix+name+" > "
			if self.cbParented.GetValue():
				l=self.GetAllChildActors(actor, newprefix)
				list[0].extend(l[0])
				list[1].extend(l[1])
		return list
	def IsFigurePartVisible(self, figure):
		for actor in figure.Actors():
			if (self.cbHidden.GetValue() or actor.OnOff()==1):
				return 1
		return 0
	def EvtWheel(self, event):
#		delta = event.GetWheelDelta()
		rotation = event.GetWheelRotation()
		
#		print 'delta: ' + repr(delta) + ' rotation:' + repr(rotation)
		if (event.ShiftDown() and not event.CmdDown()):
			if rotation>0:
				self.lbParams.ScrollLines(-1*event.GetLinesPerAction())
			else:
				self.lbParams.ScrollLines(event.GetLinesPerAction())
		elif (event.CmdDown() and not event.ShiftDown()):
			val=self.txtAmount.GetValue()
			if rotation>0:
				self.SetAmount(val+self.Digit)
			else:
				val=val-self.Digit
				if (val>=0):
					self.SetAmount(val)
		elif (event.CmdDown() and event.ShiftDown()):
			if not self.IsNumber(self.Amount):
				return
			if rotation>0:
				self.SetAmount(float(self.Amount)*10)
			else:
				self.SetAmount(float(self.Amount)/10)
		else:
			if not self.IsNumber(self.Amount):
				return
			amount=float(self.Amount)
			if rotation<0:
				amount=-1.0*amount
			if (self.rbType.GetSelection()==0):
				self.ChangeActorParams(2, amount)
			elif (self.rbType.GetSelection()==1):
				self.ChangeFigureRotations(2, amount)
			elif (self.rbType.GetSelection()==2):
				self.ChangeUniverseRotTrans(2, amount)
	def ChangeActorParams(self, type, amount):
		unitAmount=amount*self.UnitMultiplier[self.rbUnit.GetSelection()]
		l = self.lbParams.GetSelections()
		if len(l)==0:
			return
		Undo={}
		actor = poser.Scene().CurrentActor()
		frame = poser.Scene().Frame()
		UndoFrame={}
		Undo[frame]=UndoFrame
		UndoFrameActor={}
		UndoFrame[actor.InternalName()]=UndoFrameActor
		param = None
		value = 0
		amt=0.0
		for ix in self.lbParams.GetSelections():
			param=self.GetParamByInternalName(actor, self.Params[ix])
			UndoFrameActor[param.InternalName()]=param.Value()
			if (param.TypeCode() in self.RotTrans[3:]): #is translation type... adjust amount
				amt=unitAmount
			else:
				amt=amount
			if type==0:
				value=amt
			elif type==1:
				value=-1*param.Value()
			elif type==2:
				value=param.Value()+amt
			param.SetValue(value)

		if len(l)==1:
			if amt==unitAmount:
				self.value=param.Value()/self.UnitMultiplier[self.rbUnit.GetSelection()]
			else:
				self.value=param.Value()
		else:
			if type==0:
				self.value=value
			elif type==1:
				self.value=0
			elif type==2:
				self.value=self.value+amount
		self.SetValue(self.value)
		poser.Scene().Draw()
		self.SetUndo(Undo)
	def SetActorProperties(self, type):
		if len(self.changedMats)>0:
			self.changedMats=[]
		actor = poser.Scene().CurrentActor()
		self.SetProperty(type, actor)
		poser.Scene().Draw()
		poser.Scene().CurrentMaterial().ShaderTree().UpdatePreview()

	def ChangeFigureRotations(self, type, amount):
		selectedParams=self.lbParams.GetSelections()
		if (len(selectedParams)==0):
			return
		fig=poser.Scene().CurrentFigure()
		if fig==None:
			return
		frame = poser.Scene().Frame()
		Undo={}
		UndoFrame={}
		Undo[frame]=UndoFrame
		params=[]
		for ix in selectedParams:
			params = params + [self.RotTrans[ix]]
		value=0
		amount
		for actor in fig.Actors():
			if actor.IsCamera() or actor.IsLight() or actor.IsBodyPart() or actor.IsProp() or actor.IsHairProp():
				for ix in self.lbActors.GetSelections():
					if actor.InternalName()==self.Actors[ix]:
						UndoFrameActor={}
						UndoFrame[actor.InternalName()]=UndoFrameActor
						for param in params:
							parm=actor.ParameterByCode(param)
							UndoFrameActor[parm.InternalName()]=parm.Value()
							if type==0:
								value=amount
							elif type==1:
								value=-1*parm.Value()
							elif type==2:
								value=parm.Value()+amount
							parm.SetValue(value)
		poser.Scene().Draw()
		self.SetUndo(Undo)
		if type==0:
			self.value=value
		elif type==1:
			self.value=0
		elif type==2:
			self.value=self.value+amount
		self.SetValue(self.value)
	def SetFigureProperties(self, type):
		if len(self.changedMats)>0:
			self.changedMats=[]
		fig=poser.Scene().CurrentFigure()
		if fig==None:
			return
		for actor in fig.Actors():
			if actor.IsCamera() or actor.IsLight() or actor.IsBodyPart() or actor.IsProp() or actor.IsHairProp():
				for ix in self.lbActors.GetSelections():
					if actor.InternalName()==self.Actors[ix]:
						self.SetProperty(type, actor)
		poser.Scene().Draw()
		poser.Scene().CurrentMaterial().ShaderTree().UpdatePreview()
	def ChangeUniverseRotTrans(self, type, amount):
		unitAmount=amount*self.UnitMultiplier[self.rbUnit.GetSelection()]
		selectedParams=self.lbParams.GetSelections()
		if (len(selectedParams)==0):
			return
		frame = poser.Scene().Frame()
		Undo={}
		UndoFrame={}
		Undo[frame]=UndoFrame
		params=[]
		transtype=self.rbTransType.GetSelection()
		for ix in selectedParams:
			followTransType = 0
			if transtype==1 or transtype==2:
				followTransType = 1
			params = params + [[self.RotTrans[ix],followTransType]]
		selectedActors=self.lbActors.GetSelections()
		cntAct=len(selectedActors)
		amt=0.0
		for actor in poser.Scene().Actor("UNIVERSE").Children():
			ixAct=0
			for ix in selectedActors:
				if actor.InternalName()==self.Actors[ix]:
					UndoFrameActor={}
					UndoFrame[actor.InternalName()]=UndoFrameActor
					for param in params:
						parm=actor.ParameterByCode(param[0])
						if parm==None:
							continue
						UndoFrameActor[parm.InternalName()]=parm.Value()
						val=parm.Value()
						if (parm.TypeCode() in self.RotTrans[3:]): #is translation type... adjust amount
							amt=unitAmount
						else:
							amt=amount
						if type==0:
							val=amt
						elif type==1:
							val=-1*val
						elif type==2:
							if param[1]==1:
								if transtype==1:
									val=val+ixAct*amt
								if transtype==2:
									val=val+random.random()*amt
							else:
								val=val+amt
						parm.SetValue(val)
				ixAct=ixAct+1
		poser.Scene().Draw()
		self.SetUndo(Undo)
		if type==0:
			self.value=val
		elif type==1:
			self.value=0
		elif type==2:
			self.value=self.value+amount
		self.SetValue(self.value)
	def SetUniverseProperties(self, type):
		if len(self.changedMats)>0:
			self.changedMats=[]
		selectedActors=self.lbActors.GetSelections()
		if len(selectedActors)==0:
			return
		self.SetUniversePropertiesRec(type, poser.Scene().Actor("UNIVERSE"), selectedActors)
		poser.Scene().Draw()
		poser.Scene().CurrentMaterial().ShaderTree().UpdatePreview()
	def SetUniversePropertiesRec(self, type, parent, selectedActors):
		for actor in parent.Children():
			for ix in selectedActors:
				if actor.InternalName()==self.Actors[ix]:
					self.SetProperty(type, actor)
			self.SetUniversePropertiesRec(type, actor, selectedActors)
	def SetProperty(self, type, actor):
		if type==101:
			actor.SetOnOff(1)
		elif type==102:
			actor.SetOnOff(0)
		elif type==111:
			if (actor.IsLight()):
				actor.SetLightOn(1)
		elif type==112:
			if (actor.IsLight()):
				actor.SetLightOn(0)
		elif type==121:
			if (actor.IsLight()):
				actor.SetRayTraceShadows(1)
		elif type==122:
			if (actor.IsLight()):
				actor.SetRayTraceShadows(0)
		elif type==123:
			if (actor.IsLight()):
				actor.SetLightAttenType(0)
		elif type==124:
			if (actor.IsLight()):
				actor.SetLightAttenType(poser.kLightCodeINVLINEARATTEN)
		elif type==125:
			if (actor.IsLight()):
				actor.SetLightAttenType(poser.kLightCodeINVSQUAREATTEN)
		elif type==131: #Quality
			self.SetMaterialProperties(actor, self.SetMaterialFilter, 3)
		elif type==132: #Fast
			self.SetMaterialProperties(actor, self.SetMaterialFilter, 2)
		elif type==133: #None
			self.SetMaterialProperties(actor, self.SetMaterialFilter, 1)
		elif type==141: #N-Forward on
			self.SetMaterialProperties(actor, self.SetNormalsForward, 1)
		elif type==142: #N-Forward off
			self.SetMaterialProperties(actor, self.SetNormalsForward, 0)
		elif type==151: #Refl-x-Mult on
			self.SetMaterialProperties(actor, self.SetReflXMult, 1)
		elif type==152: #Refl-x-Mult off
			self.SetMaterialProperties(actor, self.SetReflXMult, 0)
		elif type==161: #Diffuse-Multi
			self.SetMaterialProperties(actor, self.MultiDiffuse, self.diffuseMulti)
		elif type==162: #Diffuse-Divide
			self.SetMaterialProperties(actor, self.MultiDiffuse, 1/self.diffuseMulti)
		elif type==990: 
			self.SetMaterialProperties(actor, self.SetGammaValue, None)
		
	def SetMaterialProperties(self, actor, nodeMethod, value):
		if (actor.Materials()):
			for material in actor.Materials():
				id=self.GetMaterialId(actor, material)
				if id in self.changedMats:
					continue
				else:
					tree = material.ShaderTree()
					for node in tree.Nodes():
						nodeMethod(node, value)
					self.changedMats.append(id)
	def GetMaterialId(self, actor, material):
		fig=actor.ItsFigure()
		if fig==None:
			return actor.InternalName()+":"+material.Name()
		else:
			return fig.InternalName()+":"+material.Name()
	def SetGammaValue(self, node, value):
		self.dlgGamma.SetGamma(node)
	def SetMaterialFilter(self, node, value):
		if node.Type() == poser.kNodeTypeCodeIMAGEMAP:
			inp = node.Input(13)
			if inp!=None:
				inp.SetFloat(value)
	def SetReflXMult(self, node, value):
		if node.Type() ==  poser.kNodeTypeCodePOSERSURFACE:
			inp = node.Input(20)
			if inp!=None:
				inp.SetFloat(value)
			inp = node.Input(21)
			if inp!=None:
				inp.SetFloat(value)
	def MultiDiffuse(self, node, value):
		if node.Type() ==  poser.kNodeTypeCodePOSERSURFACE:
			inp = node.Input(1)
			if inp!=None:
				inp.SetFloat(inp.Value()*value)
		elif node.Type() == poser.kNodeTypeCodeDIFFUSE:
			inp = node.Input(1)
			if inp!=None:
				inp.SetFloat(inp.Value()*value)
	
	def SetNormalsForward(self, node, value):
		if node.Type() ==  poser.kNodeTypeCodePOSERSURFACE:
			inp = node.Input(25)
			if inp!=None:
				inp.SetFloat(value)
		elif node.Type() in [poser.kNodeTypeCodeVELVET, poser.kNodeTypeCodeTOON, poser.kNodeTypeCodeSPECULAR, poser.kNodeTypeCodePHONG, poser.kNodeTypeCodeGLOSSY, poser.kNodeTypeCodeDIFFUSE, poser.kNodeTypeCodeBLINN, poser.kNodeTypeCodeANISOTROPIC]:
			inp=node.InputByInternalName("Normals_Forward")
			if inp!=None:
				inp.SetFloat(value)
		
	def EvtUnit(self, event):
		try:
			self.settings["DefaultUnit"]=self.rbUnit.GetSelection()
			fd=open(self.settingsFile, "w")
			pickle.dump(self.settings,fd)
			fd.close()
		except:
			pass
	def EvtButton(self, event):
		if (event.Id==62):
			val=self.txtAmount.GetValue()
			if (self.rbType.GetSelection()==0):
				self.ChangeActorParams(0,val)
			elif (self.rbType.GetSelection()==1):
				self.ChangeFigureRotations(0,val)
			elif (self.rbType.GetSelection()==2):
				self.ChangeUniverseRotTrans(0,val)
		elif (event.Id==61):
			if (self.rbType.GetSelection()==0):
				self.ChangeActorParams(1,0)
			elif (self.rbType.GetSelection()==1):
				self.ChangeFigureRotations(1,0)
			elif (self.rbType.GetSelection()==2):
				self.ChangeUniverseRotTrans(1,0)
		elif (event.Id==71):
			if wx.GetKeyState(wx.WXK_ALT):
				self.Undos=[]
				self.SetUndoRedoButtons()
			else:
				self.Undo()
		elif (event.Id==72):
			self.Redo()
		elif (event.Id>100):
			if (event.Id==990):
				if (self.dlgGamma==None):
					self.dlgGamma=self.SetGamma(self)
				res=self.dlgGamma.ShowModal()
				if res==wx.ID_CANCEL:
					return
			if (self.rbType.GetSelection()==0):
				self.SetActorProperties(event.Id)
			elif (self.rbType.GetSelection()==1):
				self.SetFigureProperties(event.Id)
			elif (self.rbType.GetSelection()==2):
				self.SetUniverseProperties(event.Id)
		else:
			return
	def SetUndo(self, Undo):
		self.Redos=[]
		self.Undos.append(Undo)
		self.SetUndoRedoButtons()
	def Undo(self):
		self.UndoOrRedo(self.Undos, self.Redos)
	def Redo(self):
		self.UndoOrRedo(self.Redos, self.Undos)
	def UndoOrRedo(self, Prevs, Nexts):
		Prev=Prevs[-1]
		Next={}
		currentFrame=poser.Scene().Frame()
		frames=poser.Scene().NumFrames()
		for PrevFrame in Prev.items():
			if PrevFrame[0]<=frames:
				poser.Scene().SetFrame(PrevFrame[0])
				NextFrame={}
				Next[PrevFrame[0]]=NextFrame
				PrevFrameActor=PrevFrame[1]
				for actor in poser.Scene().Actors():
					if actor.InternalName() in PrevFrameActor:
						NextFrameActor={}
						NextFrame[actor.InternalName()]=NextFrameActor
						for kv in PrevFrameActor[actor.InternalName()].items():
							param=self.GetParamByInternalName(actor, kv[0])
							if param==None:
								continue
							NextFrameActor[kv[0]]=param.Value()
							param.SetValue(kv[1])
		Nexts.append(Next)
		del Prevs[-1]
		self.SetUndoRedoButtons()
		self.SetValue(0.0)
		poser.Scene().SetFrame(currentFrame)
		poser.Scene().Draw()
	def SetUndoRedoButtons(self):
		self.btnUndo.Enable(len(self.Undos)>0)
		self.btnUndo.SetLabel("Undo "+str(len(self.Undos)))
		self.btnRedo.Enable(len(self.Redos)>0)
		self.btnRedo.SetLabel("Redo "+str(len(self.Redos)))
#	def EvcbParam(self, iScene, iEventType):
#		if (iEventType & poser.kEventCodeACTORSELECTIONCHANGED):
#			self.CheckList('C')
#		if (iEventType & poser.kEventCodeACTORDELETED):
#			self.CheckList('D')
#		if (iEventType & poser.kEventCodeITEMRENAMED):
#			self.CheckList('R')
	def EvtTimer(self, id):
		try:
			lastAct=poser.Scene().CurrentActor().InternalName()
			if (self.LastActor != lastAct):
				self.LastActor = lastAct
				self.CheckList('C')
		except:
			self.LastActor=None
	def IsInternalItem(self, internalName):
		return internalName.replace(" ",":").split(":")[0] in self.InternalItems # replace(" ", ":") to catch CenterOfMass 2:x objects...
	def ActorIsBody(self, actor):
		return actor.InternalName().split(":")[0]=="BODY"
	def Duplicate(self, bSelectDuplicates):
		res=self.dlgDuplicate.ShowModal()
		if res==wx.ID_CANCEL:
			return
		duplicateCnt=self.dlgDuplicate.GetValue()
		selectedActors=self.lbActors.GetSelections()
		newActors=[]
		for actor in poser.Scene().Actor("UNIVERSE").Children():
			for ix in selectedActors:
				if actor.InternalName()==self.Actors[ix]:
					for i in range(duplicateCnt):
						poser.Scene().SelectActor(actor)
						poser.ProcessCommand(1568)
						a=poser.Scene().CurrentActor()
						if (a.IsBodyPart()):
							a=a.ItsFigure()
						newActors.append(a.InternalName())
		if not bSelectDuplicates:
			newActors=[]
		self.UpdateActors(self.GetUniverseActors(), newActors)
	
	
	def ShowActorContextMenu(self, event):
		if (self.rbType.GetSelection()!=2):	return
		pane = self.man.GetPane(self)
		menu = wx.Menu()
		menu.Append(11, "Duplicate Selected")
		menu.Append(12, "Duplicate && Select Selected")
		self.PopupMenu(menu)
		menu.Destroy()
		
	def ShowContextMenu(self, event):
		pane = self.man.GetPane(self)
		menu = wx.Menu()
				
		dock = menu.Append(1, "Docked", kind=wx.ITEM_CHECK)
		float = menu.Append(2, "Floating", kind=wx.ITEM_CHECK)
		if pane.IsDocked():
			dock.Check()
		else: 
			float.Check()
		menu.AppendSeparator()
		drag = menu.Append(3, "Drag-Docking Enabled", kind=wx.ITEM_CHECK)
		if pane.IsLeftDockable():
			drag.Check()
		self.PopupMenu(menu)
		menu.Destroy()

	def ExecuteMenuCommand(self, e):
		pane = self.man.GetPane(self)
		id = e.GetId()
		if id == 1:
			if pane.IsDocked():
				return
			pane.Dock()
			self.man.Update()
		elif id == 2:
			if pane.IsFloating():
				return
			pane.Float()
			self.man.Update()
		elif id == 3:
			pane.Dockable(e.IsChecked())
		elif id == 11:
			self.Duplicate(False)
		elif id == 12:
			self.Duplicate(True)
	
	class SetGamma(wx.Dialog):
		SavePath=os.path.join(poser.PrefsLocation(), "acb", "gamma")
		DicSelection={}
		
		def __init__(self,parent):
			wx.Dialog.__init__(self, parent, -1, "Set Gamma", wx.Point(-1, -1), wx.DefaultSize)
			
			self.sizer = wx.BoxSizer(wx.VERTICAL)
			self.SetSizer(self.sizer)
			
			staticBox = wx.StaticBox(self, -1, "Inputs")
			self.szInput = wx.StaticBoxSizer(staticBox, wx.VERTICAL)
			self.sizer.Add(self.szInput)
			self.cbDisplacement = wx.CheckBox(self, -1, "Displacement")
			self.szInput.Add(self.cbDisplacement)
			self.cbBump = wx.CheckBox(self, -1, "Bump")
			self.szInput.Add(self.cbBump)
			self.cbGradient = wx.CheckBox(self, -1, "Gradient_Bump")
			self.szInput.Add(self.cbGradient)
			self.cbTransparency = wx.CheckBox(self, -1, "Transparency")
			self.szInput.Add(self.cbTransparency)
			self.cbOther = wx.CheckBox(self, -1, "Other")
			self.szInput.Add(self.cbOther)
			
			fgsGridInputs=wx.FlexGridSizer(2,2,2,1)
			self.sizer.Add(fgsGridInputs)
			lblGamma = wx.StaticText(self, -1, "Value: ", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_RIGHT)
			self.txtGamma = wx.lib.masked.NumCtrl(self, 20)
			self.txtGamma.SetFractionWidth(2)
			self.txtGamma.SetIntegerWidth(1)
			self.txtGamma.SetValue(2.2)
			self.txtGamma.SetMax(5.0)
			self.txtGamma.SetMin(0.2)
			self.txtGamma.SetAllowNone(False)
			self.txtGamma.SetAllowNegative(False)
			self.txtGamma.SetGroupDigits(False)
			
			fgsGridInputs.Add(lblGamma, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
			fgsGridInputs.Add(self.txtGamma)
			
			self.btnReset = wx.Button(self, 1, "Reset", wx.Point(-1,-1), (50,-1))
			self.btnReset.SetToolTip(wx.ToolTip("use global gamma setting"))
			fgsGridInputs.Add(self.btnReset)
			self.btnSet = wx.Button(self, 2, "Set", wx.Point(-1,-1), (50,-1))
			self.btnSet.SetToolTip(wx.ToolTip("use entered gamma value"))
			fgsGridInputs.Add(self.btnSet)
			
			self.sizer.Add(self.CreateStdDialogButtonSizer(wx.CANCEL))
			
			self.Layout()
			
			self.Bind(wx.EVT_BUTTON, self.EvtButton)
			
			if not os.path.exists(self.SavePath):
				os.makedirs(self.SavePath)

			self.MemoryFile=os.path.join(self.SavePath, "memory.config")
			if os.path.exists(self.MemoryFile):
				fd=open(self.MemoryFile)
				dic=pickle.load(fd)
				self.DicSelection=dic
				if (dic.has_key("inputs_d")):
					self.cbDisplacement.SetValue(dic["inputs_d"])
				if (dic.has_key("inputs_b")):
					self.cbBump.SetValue(dic["inputs_b"])
				if (dic.has_key("inputs_g")):
					self.cbGradient.SetValue(dic["inputs_g"])
				if (dic.has_key("inputs_t")):
					self.cbTransparency.SetValue(dic["inputs_t"])
				if (dic.has_key("inputs_o")):
					self.cbOther.SetValue(dic["inputs_o"])
				if (dic.has_key("gamma")):
					self.txtGamma.SetValue(dic["gamma"])
				fd.close()
			
		def __del__(self):
			try:
				fd=open(self.MemoryFile, "w")
				pickle.dump(self.DicSelection,fd)
				fd.close()
			except:
				pass

		def EvtButton(self, event):
			dic=self.DicSelection
			dic["inputs_d"]=self.cbDisplacement.GetValue()
			dic["inputs_b"]=self.cbBump.GetValue()
			dic["inputs_g"]=self.cbGradient.GetValue()
			dic["inputs_t"]=self.cbTransparency.GetValue()
			dic["inputs_o"]=self.cbOther.GetValue()
			dic["gamma"]=self.txtGamma.GetValue()
			
			self.EndModal(event.Id)
			return
			
		def SetGamma(self, node):
			code=self.GetReturnCode()
			if code==1:
				self.SetGammaStart(node, 0, True)
			elif code==2:
				self.SetGammaStart(node, self.txtGamma.GetValue(), False)
					
		def SetGammaStart(self, node, value, useGlobalGamma):
			for input in node.Inputs():
				name = input.InternalName()
				if input.InNode():
					if name == "Transparency_Max":
						if self.cbTransparency.GetValue():
							self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
					elif name == "Displacement":
						if self.cbDisplacement.GetValue():
							self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
					elif name == "Bump":
						if self.cbBump.GetValue():
							self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
					elif name == "Gradient_Bump":
						if self.cbGradient.GetValue():
							self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
					else:
						if self.cbOther.GetValue():
							self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
		def SetGammaPerNode(self, node, value, useGlobalGamma):
			if node!=None:
				for input in node.Inputs():
					if input.InternalName() == "Image_Source":
						texture = input.Texture()
						if texture!=None:
							if useGlobalGamma==True:
								texture.SetUseSceneGamma(1)
							else:
								texture.SetGamma(value)
					self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)

		

name = "Wheel Posing & Tools"
man = poser.WxAuiManager()
root = man.GetManagedWindow()

pane = wx.aui.AuiPaneInfo()
pane.Caption(name).CaptionVisible().CloseButton().Resizable().DestroyOnClose()
pane.BestSize(wx.Size(50, 50)).Right().PinButton().Dock()
win = WheelPosing(root, name, pane)
man.AddPane(win, pane)
pane.Show()
man.Update()


