# Change the selected parameter(s) via the mouse wheel v3.4
# and much more see http://neocron.lunarpages.com/alforum/index.php?topic=1511.0
# - poor 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):
	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={}
	ComponentSize={}
	SavePath=os.path.join(poser.PrefsLocation(), "acb", "multiactor")
		
	def __init__(self,parent,title, pane):
		wx.Panel.__init__(self, parent, -1, wx.Point(-1, -1), wx.DefaultSize, wx.WANTS_CHARS)
		
		self.ComponentSizeFile=os.path.join(self.SavePath, "component_size.config")
		if os.path.exists(self.ComponentSizeFile):
			fd=open(self.ComponentSizeFile)
			self.ComponentSize=pickle.load(fd)
			fd.close()
			if self.ComponentSize.has_key("Pane"):
				pane.FloatingSize(self.ComponentSize["Pane"]).BestSize(self.ComponentSize["Pane"])
		
		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)
		list=self.GetActorParamList()
		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.cbCameras = wx.CheckBox(self, 21, "Cameras")
		self.cbCameras.Bind(wx.EVT_CHECKBOX, self.EvtChkboxActorType)
		self.szActorType.Add(self.cbCameras)
		self.cbLights = wx.CheckBox(self, 22, "Lights")
		self.cbLights.Bind(wx.EVT_CHECKBOX, self.EvtChkboxActorType)
		self.szActorType.Add(self.cbLights)
		self.cbMagnets = wx.CheckBox(self, 23, "Magnets")
		self.cbMagnets.Bind(wx.EVT_CHECKBOX, self.EvtChkboxActorType)
		self.szActorType.Add(self.cbMagnets)
		self.cbProps = wx.CheckBox(self, 23, "Props")
		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.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)), list, 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.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, "Mat", 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)

		
		
		
		# layout
		self.tab3 = wx.Panel(self.tabs, -1, wx.Point(-1, -1), wx.DefaultSize, wx.WANTS_CHARS)
		self.tabs.AddPage(self.tab3, "Layout", False)
		self.sizerTab3= wx.BoxSizer(wx.VERTICAL)
		self.tab3.SetSizer(self.sizerTab3)
		fgsLayout=wx.FlexGridSizer(2,3,2,1)
		self.tab3.SetSizer(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)
				
		#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.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.EvtResize)
				
		if not os.path.exists(self.SavePath):
			os.makedirs(self.SavePath)

		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.ComponentSizeFile, "w")
			pickle.dump(self.ComponentSize,fd)
			fd.close()
		except:
			pass
		
#		poser.Scene().ClearEventCallback()
	def EvtResize(self, event):
		self.ComponentSize["Pane"]=poser.WxAuiManager().GetPane(self).floating_size
			
	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.ComponentSize["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.ComponentSize["lbActors"]=(x,y)
		self.sizer.SetItemMinSize(self.lbActors, (x,y))
		self.Layout()
	def GetSize(self, component, defaultSize):
		if self.ComponentSize.has_key(component): 
			return self.ComponentSize[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 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'):
			self.UpdateParams(self.GetActorParamList())
			self.sizer2.Hide(self.szActorType)
			self.lbActors.Show(0)
			self.rbTransType.Show(0)
		elif (self.rbType.GetSelection()==1):
			self.UpdateActors(self.GetFigureActors())
			self.UpdateParams(self.RotTransString[:3])
			self.sizer2.Show(self.szActorType)
			self.lbActors.Show(1)
			self.rbTransType.Show(0)
		elif (self.rbType.GetSelection()==2):
			self.UpdateActors(self.GetUniverseActors())
			self.UpdateParams(self.RotTransString)
			self.sizer2.Show(self.szActorType)
			self.lbActors.Show(1)
			self.rbTransType.Show(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
	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):
		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)
		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])
				self.value=str(poser.Scene().CurrentActor().Parameter(self.selectedParamName).Value())
			else:
				self.selectedParamName=""
				self.value=0
			self.txtValue.SetValue(str(self.value))
		elif (self.rbType.GetSelection()==1):
			self.value=0
			self.txtValue.SetValue(str(self.value))
		elif (self.rbType.GetSelection()==2):
			self.value=0
			self.txtValue.SetValue(str(self.value))
	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
			if (
				self.ActorIsBody(actor) 
				or (actor.InternalName()==actor.ItsFigure().InternalName())
				or (actor.IsCamera() and self.cbCameras.GetValue()) 
				or (actor.IsLight() and self.cbLights.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):
		list=([],[])
		for actor in poser.Scene().Actor("UNIVERSE").Children():
			#print actor.Name(), actor.IsBodyPart(), actor.OnOff()
			if self.IsInternalItem(actor.InternalName()):
				continue
			if (
				(actor.IsCamera() and self.cbCameras.GetValue()) 
				or (actor.IsLight() and self.cbLights.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(actor.Name())
			elif actor.IsBodyPart():
				if actor.ItsFigure().ConformTarget()!=None:
					continue
				if self.IsFigurePartVisible(actor.ItsFigure())==1:
					list[0].append(actor.InternalName())
					list[1].append(actor.ItsFigure().Name() + " -> " +actor.Name())
				else:
					continue
		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):
		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
		for ix in self.lbParams.GetSelections():
			param=actor.Parameter(self.lbParams.GetString(ix))
			UndoFrameActor[self.lbParams.GetString(ix)]=param.Value()
			if type==0:
				value=amout
			elif type==1:
				value=-1*param.Value()
			elif type==2:
				value=param.Value()+amount
			param.SetValue(value)

		if len(l)==1:
			self.txtValue.SetValue(str(param.Value()))
		else:
			if type==0:
				self.value=value
			elif type==1:
				self.value=0
			elif type==2:
				self.value=self.value+amount
			self.txtValue.SetValue(str(self.value))
		poser.Scene().Draw()
		self.SetUndo(Undo)
	def SetActorProperties(self, type):
		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
		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.Name()]=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.txtValue.SetValue(str(self.value))
	def SetFigureProperties(self, type):
		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):
		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)
		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.Name()]=parm.Value()
						val=parm.Value()
						if type==0:
							val=amount
						elif type==1:
							val=-1*val
						elif type==2:
							if param[1]==1:
								if transtype==1:
									val=val+ixAct*amount
								if transtype==2:
									val=val+random.random()*amount
							else:
								val=val+amount
						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.txtValue.SetValue(str(self.value))
	def SetUniverseProperties(self, type):
		selectedActors=self.lbActors.GetSelections()
		if len(selectedActors)==0:
			return
		for actor in poser.Scene().Actor("UNIVERSE").Children():
			for ix in selectedActors:
				if actor.InternalName()==self.Actors[ix]:
					self.SetProperty(type, actor)
		poser.Scene().Draw()
		poser.Scene().CurrentMaterial().ShaderTree().UpdatePreview()
	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==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)
		
	def SetMaterialProperties(self, actor, nodeMethod, value):
		if (actor.Materials()):
			for material in actor.Materials():
				tree = material.ShaderTree()
				for node in tree.Nodes():
					nodeMethod(node, value)

	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 SetNormalsForward(self, node, value):
		if node.Type() ==  poser.kNodeTypeCodePOSERSURFACE:
			inp = node.Input(25)
			if inp!=None:
				inp.SetFloat(value)
				
	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 (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=actor.Parameter(kv[0])
							if param==None:
								continue
							NextFrameActor[kv[0]]=param.Value()
							param.SetValue(kv[1])
		Nexts.append(Next)
		del Prevs[-1]
		self.SetUndoRedoButtons()
		self.txtValue.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.split(":")[0] in self.InternalItems
	def ActorIsBody(self, actor):
		return actor.InternalName().split(":")[0]=="BODY"
name = "Wheel Posing"
man = poser.WxAuiManager()
root = man.GetManagedWindow()

pane = wx.aui.AuiPaneInfo()
pane.Caption(name).CaptionVisible().CloseButton().Resizable().DestroyOnClose()
pane.Float().Right().PinButton().Dock()
win = WheelPosing(root, name, pane)
man.AddPane(win, pane)
pane.Show()
man.Update()


