""" Defines Graph Editor """ import os,wx import math import cPickle as pickle from PaletteTreeCtrl import * import ObjectGlobals as OG import AnimGlobals as AG from wx.lib.embeddedimage import PyEmbeddedImage property = [ "translateX", "translateY", "translateZ" ] #---------------------------------------------------------------------- ZoomIn = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAIAAAD9b0jDAAAAA3NCSVQICAjb4U/gAAACgklE" "QVRIid3VW0vjQBQA4DlJMziZlCKCSB/9Bf4a3wRtNU6SHyXK6pay2nVbQbasskXFO15SqmwL" "LtYnn7Zg20zSyT50wZikXsCHxXk9Z74ZZuacgebtLXrvIb27+PFQjDEADIoqiiLL8htQAMAY" "Hx4dPTw8SHEuIaRWqzWbzUQi8SoUAIaGhgqFgn15SSn1Iwmqqh4fH5c2NpLJpO8/xhORzEeR" "EJLL5VqtViaT8TxPCBFMoJTu7e1tb28zxpLJpOu6L6D9PS6vrHQ6nWw267puVNzZ2alUKqZh" "UE0LivFoX/y0vOxynpmZ4ZxHxZ+Vyu7urmmaqqqGxBhUkiSM8eLiIgDMTE87EVHTtB9bW4cH" "B5ZpEkKiYhjt3/XCwoKiKFNTU47jRPf4vVw+PTmxLAtjHCs+QQEAAJaWljRNm5yc7Ha7wQtF" "CGGMy+WybduWZSmK4nlerIiCTwoAOOfX19cTExMSgPDDT0iSJNu2x8fHU6nUM+ITVAhBCLFM" "83MuV63VKCGhVM65ruv1RqNYLFJKX4UihFzXTafTc7Oz+XzerlZVVQ1GhRCyLJuGcXV1VSqV" "QtGBKEKo6zhjY2Pzur66tnZxcRGa2ev1AMA0zXqj8W3wfmPK1HGc0dFRNj//dX397Ows6iKE" "DMZ+39wUCgVKabTXxNe+4zgjIyMGY8VS6eT0NOr6vs8Yu7u7+7K6SggJuQMbCud8eHjYYGxz" "c3N/f19RlJDb6/V0Xb+/v8/n829ofZzzVCqlz82dn5//abUk6UmyEEIIkc1k2u32r3o9uCq8" "+PHJsuz7vud5IfTffABZljnnwejLnb9/grEiQih2vVd9J36kup4fH+w3/S/QvwejQg8ibHgo" "AAAAAElFTkSuQmCC") #---------------------------------------------------------------------- ZoomOut = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAIAAAD9b0jDAAAAA3NCSVQICAjb4U/gAAACmUlE" "QVRIieXVz0sbQRQH8NmdH8smh3jwEIIlB+tNEW1NVps0WxPBv0BQXKQx4N2/xR2xTYQ9iIHc" "/A+shyqevHiQVBGLeqgoxM1kNjHTQ8DayWb14KX0Hfe9+fDd4bGr/Ly4AK9d6quL/y6qKIqm" "aQHThBBVfT7HnwlFUTjn3/f3MUKKoviMqurh4WG9XkcIvRQVQoRCodPT0+1yWdO0bhchxD2v" "WCxyzjHGL0IBAA8PD9biIgDAcRxN06Q39Tzvk2kahmHbNmMswP3rmBCi0WhYlkUI2dzcxBhL" "ruu6mUwmnU6v2bbrur1c+dY77sLCQjgcLpVKGKFuN5VKmaZpU1qr1Qghz6OP7vz8fF9f39di" "Efq5H6amcrkcpfTu7q7b9d8PIQRjbG5urr+//8vGBoSw200mErOzs3R9/fb2VnLh6uqqrwsA" "aLVao6OjV9fX3/b2RkZGJLfZbMbj8UgkUqlU3g4NhcNhIURQ0k612+12u/1ufPxHtcoY6157" "z/OGh4fv7++vLi8hhI/Pg9ZY1/Xz83PHcVZWViKRSLPZfNpFCHmeRynNZrNjY2ONRuOx1TOp" "rutnZ2eO41iWNTg4KIkYY875mm2/n5iYnp5+KvZMqut6tVrd2tpaWlqKx+OMMUmsM0YpnZqc" "NE3TdV3puA+q6/rJycl2ufw5n38zMCClwBjXXdem9GMmk06lukUfNBQKHR8fVyqVwvJyLBaT" "REJIrVbr3KNhGL6ijGKMj46OdnZ2CoVCNBqVRAjhr5ubUqmUm5kxksleIpA+fYyxg4ODfD4f" "jUY559IohHB3dzebzSYTiQARAKA8/fEJIVRVhRC2Wi3faSEEIUTahKCknbAAgF4iAEBV1WdF" "Ge1kCZgO7vZEX6X+c/Q3Qy8zmmCLWqIAAAAASUVORK5CYII=") #---------------------------------------------------------------------- OneTangent = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAIAAAD9b0jDAAAAA3NCSVQICAjb4U/gAAACKUlE" "QVRIia2Wz2saURDH5/3Yt6aVsE3SomArGO0phxCSU6A2EFgSklP+qPwrXkOQkBCoaG8eQrBQ" "KRYVU1tabUij3V1337weAtZI1FX3e9qF2c/OzJv9zpKbRgMGRAhRSsF8oo9uOCeUMk0LDEo1" "rVUuF46Pv2SzhDEgJBhoLZer5/OViwu32yWUjnlsvHj/SrluPJ222m3GORMC5ugsGTwoyjkT" "4nuxeFetvj06ko4zG/RRjeh5rmVFNjeZrt8UCnxhIQAoAIBSnm0n9vb+1Gq/y2Wm60FAAUAp" "UGr18LCRz9vtNuH8iZipoQAopW4Yb3Z2vmazgDjtJIyMlo7zIpUyksnq2RkTIhgoAHiWFdve" "RsTmx4IuNP/ZToiUvV7CNNt3natb61b57cKEMIXIOeu+N0uof5IaEl8f7+R3K1SG8sKc0FqF" "oPTjCZOhEiDF0Vyk8da3+occC4UCgAKAAhBe73X6Xa/T+VEs8klcv0eKCtD1kgcHP6+v7xsN" "OtZzp5hqhUh1PbG/Xz0/l5ZFGAsACgDous+j0cjWVuX0lI428qmdWNr2q/X10NJS/fJyVHNn" "sXfPtuO7u39brV+lkgiHmRBDKZOhbepThDHpOJ8zmZ7jLMZiq6YJhPSXxYyLSEkZMgx9ebl8" "clLKZO6bTTbgkFN7ZV+e47xcW4tubIQjkWcrKyjl/zpmK/9BlDH0vIfZUogBZAoAKCWhVCk1" "tHrnggLAk/9I/wC0eekA1bLbIQAAAABJRU5ErkJggg==") #---------------------------------------------------------------------- TwoTangents = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAIAAAD9b0jDAAAAA3NCSVQICAjb4U/gAAACL0lE" "QVRIie3UzU8TQRQA8DczO1vatRgh1YhWD/WD+kG91FgOXLhx4+CpiYnE9L8g/gVwJHhp4lUP" "pPHgQRMOGiEaDabV1LRAtdjUAG23m3W/Znc8YEo/trRNOGjCO+7M++3MezODdopFOO7Axy6e" "oC0oAqAEY4QGyCcE4faVtaII7dQUy7b7dDEheq3GdB0R4o76KH2+kZ158uzxyzcO56iXS0Rx" "N5tdnZ9fW1w0FaXZPUQxRl/Le7+q8mruh2paQsem2kLweCq5XGVrq7K5adTruGk+ahx+AeOS" "rLz4ktctdtYvPYje0i3Gu22cUr1a3VheHg6FhoPBC9EoBwDO21EOQDH2igIALL39NOrz3r8z" "rppWp3jQmQ8LC5enp4NTU0zTmGG0/PJwKgBzHEU3VcN6eHfie7X++ltBEmknSoaG0snkSDg8" "Njmp12ptIrieU4dzAEjEIu8KPz8Wy14qNI9SScqvrHCA67Ozlqq6F8f1K3McL6WPYpFUOre9" "L3uEv50VfL7S+vpuJjMxN8cMo1HEvlAAMG37nF+KR28+fZ/e/62JBAuiWC8U8qlUJJFAhHDH" "6ZZ71LnRLXY1MDJzI5Rc+6wwR5PlTDIZjsd9gYBjuTSwEajneypR4dV2qXxq1F/dG5fLodg9" "U9OOThGOHgYAg7FrF8fKKqjng/4rl+xeYl+ozeEMsNsiwmCftnnXQg6EcgABICxyAGAcut2x" "wdADt+uFdYv/9OU/Qf9d9A9dhOgRU8MmewAAAABJRU5ErkJggg==") #---------------------------------------------------------------------- class GraphEditorWindow(wx.Window): """ This is the main graph editor window. """ def __init__(self, parent, windowSize, property, xRange, yRange, curFrame, object): wx.Window.__init__(self, parent, size = windowSize, style = wx.SUNKEN_BORDER) self._mainDialog = wx.GetTopLevelParent(self) self.w,self.h = self.GetClientSize() self.zoom = float(2) self._mouseIn = False self._selectRec = False self._selectHandler = False self._OneTangent = True self.object = object self.curFrame = curFrame self.property = property self.zeroPos = (float(0), self.h/float(2)) self.zero = 0 self.unitWidth = self.w/float(xRange) self.unitHeight = self.h/float(yRange) self.generateInfo() self.InitBuffer() self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown) self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp) self.Bind(wx.EVT_MOTION, self.OnMotion) def refresh(self): self._mouseIn = False self._selectRec = False self._selectHandler = False self.generateInfo() def generateInfo(self): #generate the information for animation curve generation self.X = [] self.Y = [] self.Z = [] if self._mainDialog.editor.animMgr.keyFramesInfo != {}: self.keyFramesInfo = self._mainDialog.editor.animMgr.keyFramesInfo for key in self.keyFramesInfo.keys(): if key == (self.object[OG.OBJ_UID], 'X'): for i in range(len(self.keyFramesInfo[key])): item = self.keyFramesInfo[key][i] handler = self.generateHandler(item) self.X.append([key, i, handler[0], handler[1], handler[2], handler[3], handler[4]]) if key == (self.object[OG.OBJ_UID], 'Y'): for i in range(len(self.keyFramesInfo[key])): item = self.keyFramesInfo[key][i] handler = self.generateHandler(item) self.Y.append([key, i, handler[0], handler[1], handler[2], handler[3], handler[4]]) if key == (self.object[OG.OBJ_UID], 'Z'): for i in range(len(self.keyFramesInfo[key])): item = self.keyFramesInfo[key][i] handler = self.generateHandler(item) self.Z.append([key, i, handler[0], handler[1], handler[2], handler[3], handler[4]]) def generateHandler(self, item): #generate the position for the control handler x1 = self.zeroPos[0] + float(item[AG.FRAME])*self.unitWidth y1 = self.zeroPos[1] - float(item[AG.VALUE])*self.unitHeight t1x = item[AG.INSLOPE][0]*self.unitWidth t1y = item[AG.INSLOPE][1]*self.unitHeight t2x = item[AG.OUTSLOPE][0]*self.unitWidth t2y = item[AG.OUTSLOPE][1]*self.unitHeight tanA = t1y/t1x temp1 = float(1)/(tanA**2+1) if t1x <0 : cosA = -math.sqrt(abs(temp1)) if t1x >=0: cosA = math.sqrt(abs(temp1)) temp2 = (tanA**2)*temp1 if t1y <0 : sinA = -math.sqrt(abs(temp2)) if t1y >=0: sinA = math.sqrt(abs(temp2)) x2 = x1-float(self.unitWidth*self.zoom)*cosA y2 = y1+float(self.unitWidth*self.zoom)*sinA tanA = t2y/t2x temp1 = float(1)/(tanA**2+1) if t2x <0 : cosA = -math.sqrt(abs(temp1)) if t2x >=0: cosA = math.sqrt(abs(temp1)) temp2 = (tanA**2)*temp1 if t2y <0 : sinA = -math.sqrt(abs(temp2)) if t2y >=0: sinA = math.sqrt(abs(temp2)) x3 = x1+float(self.unitWidth*self.zoom)*cosA y3 = y1-float(self.unitWidth*self.zoom)*sinA return [[(x1,y1),0],[(x2,y2),0],[(x3,y3),0],[t1x,t1y],[t2x,t2y]] def InitBuffer(self): self.buffer = wx.EmptyBitmap(self.w, self.h) dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) self.DrawXCoord(dc) self.DrawYCoord(dc) self.DrawFrame(dc) self.DrawCurve(dc) self.DrawSelectRec(dc) def SetGraphEditorData(self, property, curFrame = 1): self.curFrame = curFrame self.property = property self.InitBuffer() def OnPaint(self, evt): dc = wx.BufferedPaintDC(self, self.buffer) def DrawXCoord(self,dc): dc.SetBackground(wx.Brush(wx.Colour(200, 200, 200))) dc.Clear() dc.SetPen(wx.BLACK_PEN) dc.SetBrush(wx.BLACK_BRUSH) dc.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL)) dc.DrawLine(self.zeroPos[0], float(0), self.zeroPos[0], self.h) st = str(self.zero) self.tw,self.th = dc.GetTextExtent(st) dc.DrawText(st, self.zeroPos[0]+1.0, self.h-self.th-0.5) dc.SetPen(wx.Pen(wx.Colour(150, 150, 150))) dc.SetBrush(wx.Brush(wx.Colour(150, 150, 150))) if self.unitWidth >= 25: posPos = self.zeroPos[0]+self.unitWidth posNum = self.zero + 1 while posPos <= self.w: dc.DrawLine(posPos, float(0), posPos, self.h) st = str(posNum) self.drawXNumber(dc, st, posPos) posPos += self.unitWidth posNum += 1 negPos = self.zeroPos[0]-self.unitWidth negNum = self.zero - 1 while negPos >= float(0): dc.DrawLine(negPos, float(0), negPos, self.h) st = str(negNum) self.drawXNumber(dc, st, negPos) negPos -= self.unitWidth posNum -= 1 elif self.unitWidth >= 10 and self.unitWidth <= 25: posPos = self.zeroPos[0]+self.unitWidth*float(2) posNum = self.zero + 2 while posPos <= self.w: dc.DrawLine(posPos, float(0), posPos, self.h) st = str(posNum) self.drawXNumber(dc, st, posPos) posPos += self.unitWidth*float(2) posNum += 2 negPos = self.zeroPos[0]-self.unitWidth*float(2) negNum = self.zero - 2 while negPos >= float(0): dc.DrawLine(negPos, float(0), negPos, self.h) st = str(negNum) self.drawXNumber(dc, st, negPos) negPos -= self.unitWidth*float(2) posNum -= 2 elif self.unitWidth >= 2 and self.unitWidth <= 10: posPos = self.zeroPos[0]+self.unitWidth*float(5) posNum = self.zero + 5 while posPos <= self.w: dc.DrawLine(posPos, float(0), posPos, self.h) st = str(posNum) self.drawXNumber(dc, st, posPos) posPos += self.unitWidth*float(5) posNum += 5 negPos = self.zeroPos[0]-self.unitWidth*float(5) negNum = self.zero - 5 while negPos >= float(0): dc.DrawLine(negPos, float(0), negPos, self.h) st = str(negNum) self.drawXNumber(dc, st, negPos) negPos -= self.unitWidth*float(5) posNum -= 5 def DrawYCoord(self,dc): dc.SetPen(wx.BLACK_PEN) dc.SetBrush(wx.BLACK_BRUSH) dc.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL)) dc.DrawLine(float(0), self.zeroPos[1], self.w, self.zeroPos[1]) st = str(self.zero) dc.DrawText(st, 5.0, self.zeroPos[1]-1.0) dc.SetPen(wx.Pen(wx.Colour(150, 150, 150))) dc.SetBrush(wx.Brush(wx.Colour(150, 150, 150))) dc.SetLogicalFunction(wx.AND) posPos = self.zeroPos[1]-self.unitHeight*float(5) posNum = self.zero + 5 while posPos >= float(0): dc.DrawLine(float(0), posPos, self.w, posPos) st = str(posNum) self.drawYNumber(dc, st, posPos) posPos -= self.unitHeight*float(5) posNum += 5 negPos = self.zeroPos[1]+self.unitHeight*float(5) negNum = self.zero - 5 while negPos <= self.h: dc.DrawLine(float(0), negPos, self.w, negPos) st = str(negNum) self.drawYNumber(dc, st, negPos) negPos += self.unitHeight*float(5) negNum -= 5 def drawXNumber(self, dc, st, pos): oldPen, oldBrush, oldMode = dc.GetPen(), dc.GetBrush(), dc.GetLogicalFunction() dc.SetPen(wx.BLACK_PEN) dc.SetBrush(wx.BLACK_BRUSH) dc.DrawText(st, pos+1.0, self.h-self.th-0.5) dc.SetPen(oldPen) dc.SetBrush(oldBrush) dc.SetLogicalFunction(oldMode) def drawYNumber(self, dc, st, pos): oldPen, oldBrush, oldMode = dc.GetPen(), dc.GetBrush(), dc.GetLogicalFunction() dc.SetPen(wx.BLACK_PEN) dc.SetBrush(wx.BLACK_BRUSH) dc.DrawText(st, 5.0, pos-1.0) dc.SetPen(oldPen) dc.SetBrush(oldBrush) dc.SetLogicalFunction(oldMode) def DrawFrame(self, dc): if self._mainDialog.editor.mode == self._mainDialog.editor.ANIM_MODE: curFramePos = self.zeroPos[0]+self.curFrame*self.unitWidth dc.SetPen(wx.Pen("red")) dc.SetBrush(wx.Brush("red")) dc.DrawLine(curFramePos, float(0), curFramePos, self.h) else: pass def drawX(self, dc): dc.SetPen(wx.Pen("red")) dc.SetBrush(wx.Brush("red")) self.drawSingleCurve(self.X, dc) self.drawKeys(self.X, dc) self.drawHandler(self.X, dc) def drawY(self, dc): dc.SetPen(wx.Pen("green")) dc.SetBrush(wx.Brush("green")) self.drawSingleCurve(self.Y, dc) self.drawKeys(self.Y, dc) self.drawHandler(self.Y, dc) def drawZ(self, dc): dc.SetPen(wx.Pen("blue")) dc.SetBrush(wx.Brush("blue")) self.drawSingleCurve(self.Z, dc) self.drawKeys(self.Z, dc) self.drawHandler(self.Z, dc) def DrawCurve(self, dc): if self.property == self._mainDialog.namestr: self.drawX(dc) self.drawY(dc) self.drawZ(dc) return if self.property == property[AG.X]: self.drawX(dc) return if self.property == property[AG.Y]: self.drawY(dc) return if self.property == property[AG.Z]: self.drawZ(dc) return def drawSingleCurve(self, list, dc): if len(list) == 1: dc.DrawPoint(list[0][AG.KEYFRAME][AG.LOCAL_VALUE][0], list[0][AG.KEYFRAME][AG.LOCAL_VALUE][1]) return if len(list) == 2: dc.DrawLine(list[0][AG.KEYFRAME][AG.LOCAL_VALUE][0], list[0][AG.KEYFRAME][AG.LOCAL_VALUE][1], list[1][AG.KEYFRAME][AG.LOCAL_VALUE][0], list[1][AG.KEYFRAME][AG.LOCAL_VALUE][1]) return if len(list)>=3 : for i in range(len(list)-1): x1 = list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0] y1 = list[i][AG.KEYFRAME][AG.LOCAL_VALUE][1] x4 = list[i+1][AG.KEYFRAME][AG.LOCAL_VALUE][0] y4 = list[i+1][AG.KEYFRAME][AG.LOCAL_VALUE][1] t1x = list[i][AG.OUT_SLOPE][0] t1y = list[i][AG.OUT_SLOPE][1] t2x = list[i+1][AG.IN_SLOPE][0] t2y = list[i+1][AG.IN_SLOPE][1] x2 = x1 + (x4 - x1) / float(3); scale1 = (x2 - x1) / t1x; y2 = y1 - t1y * scale1; x3 = x4 - (x4 - x1) / float(3); scale2 = (x4 - x3) / t2x; y3 = y4 + t2y * scale2; ax = - float(1) * x1 + float(3) * x2 - float(3) * x3 + float(1) * x4; bx = float(3) * x1 - float(6) * x2 + float(3) * x3 + float(0) * x4; cx = - float(3) * x1 + float(3) * x2 + float(0) * x3 + float(0) * x4; dx = float(1) * x1 + float(0) * x2 - float(0) * x3 + float(0) * x4; ay = - float(1) * y1 + float(3) * y2 - float(3) * y3 + float(1) * y4; by = float(3) * y1 - float(6) * y2 + float(3) * y3 + float(0) * y4; cy = - float(3) * y1 + float(3) * y2 + float(0) * y3 + float(0) * y4; dy = float(1) * y1 + float(0) * y2 - float(0) * y3 + float(0) * y4; preX = x1 preY = y1 t = 0.001 while t<=float(1): x = ax * t*t*t + bx * t*t + cx * t + dx; y = ay * t*t*t + by * t*t + cy * t + dy; curX = x curY = y dc.DrawLine(preX, preY, curX, curY) preX = curX preY = curY t += 0.001 def drawKeys(self, list, dc): for i in range(len(list)): pointX = list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0] pointY = list[i][AG.KEYFRAME][AG.LOCAL_VALUE][1] if list[i][AG.KEYFRAME][AG.SELECT] == 0: dc.SetPen(wx.Pen("black",3)) dc.SetBrush(wx.Brush("black")) dc.DrawCircle(pointX, pointY, 2) if list[i][AG.KEYFRAME][AG.SELECT] == 1: dc.SetPen(wx.Pen("cyan",3)) dc.SetBrush(wx.Brush("cyan")) dc.DrawCircle(pointX, pointY, 2) def drawHandler(self, list, dc): for i in range(len(list)): if list[i][AG.KEYFRAME][AG.SELECT] == 1: X1 = list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0] Y1 = list[i][AG.KEYFRAME][AG.LOCAL_VALUE][1] if self._OneTangent == True: for j in range(3,5): X = list[i][j][AG.LOCAL_VALUE][0] Y = list[i][j][AG.LOCAL_VALUE][1] if list[i][j][AG.SELECT] == 1: dc.SetPen(wx.Pen("cyan",3)) dc.SetBrush(wx.Brush("cyan")) dc.DrawCircle(X, Y, 2) dc.SetPen(wx.Pen("cyan",1)) dc.DrawLine(X1, Y1, X, Y) if list[i][j][AG.SELECT] == 0: dc.SetPen(wx.Pen("brown",3)) dc.SetBrush(wx.Brush("brown")) dc.DrawCircle(X, Y, 2) dc.SetPen(wx.Pen("brown",1)) dc.DrawLine(X1, Y1, X, Y) if self._OneTangent == False: if list[i][AG.IN_TANGENT][AG.SELECT] == 1: X = list[i][AG.IN_TANGENT][AG.LOCAL_VALUE][0] Y = list[i][AG.IN_TANGENT][AG.LOCAL_VALUE][1] dc.SetPen(wx.Pen("cyan",3)) dc.SetBrush(wx.Brush("cyan")) dc.DrawCircle(X, Y, 2) dc.SetPen(wx.Pen("cyan",1)) dc.DrawLine(X1, Y1, X, Y) if list[i][AG.IN_TANGENT][AG.SELECT] == 0: X = list[i][AG.IN_TANGENT][AG.LOCAL_VALUE][0] Y = list[i][AG.IN_TANGENT][AG.LOCAL_VALUE][1] dc.SetPen(wx.Pen("navy",3)) dc.SetBrush(wx.Brush("navy")) dc.DrawCircle(X, Y, 2) dc.SetPen(wx.Pen("navy",1)) dc.DrawLine(X1, Y1, X, Y) if list[i][AG.OUT_TANGENT][AG.SELECT] == 1: X = list[i][AG.OUT_TANGENT][AG.LOCAL_VALUE][0] Y = list[i][AG.OUT_TANGENT][AG.LOCAL_VALUE][1] dc.SetPen(wx.Pen("cyan",3)) dc.SetBrush(wx.Brush("cyan")) dc.DrawCircle(X, Y, 2) dc.SetPen(wx.Pen("cyan",1)) dc.DrawLine(X1, Y1, X, Y) if list[i][AG.OUT_TANGENT][AG.SELECT] == 0: X = list[i][AG.OUT_TANGENT][AG.LOCAL_VALUE][0] Y = list[i][AG.OUT_TANGENT][AG.LOCAL_VALUE][1] dc.SetPen(wx.Pen("brown",3)) dc.SetBrush(wx.Brush("brown")) dc.DrawCircle(X, Y, 2) dc.SetPen(wx.Pen("brown",1)) dc.DrawLine(X1, Y1, X, Y) def DrawSelectRec(self, dc): if self._selectRec == True: dc.SetPen(wx.Pen("navy", 1)) dc.SetBrush(wx.Brush("navy")) ## dc.SetLogicalFunction(wx.AND) dc.DrawLine(self.pos[0], self.pos[1], self.pos[0], self.newPos[1]) dc.DrawLine(self.pos[0], self.pos[1], self.newPos[0], self.pos[1]) dc.DrawLine(self.newPos[0], self.newPos[1], self.pos[0], self.newPos[1]) dc.DrawLine(self.newPos[0], self.newPos[1], self.newPos[0], self.pos[1]) def OnSize(self,evt): self.InitBuffer() def OnLeftDown(self,evt): point = (evt.GetX(), evt.GetY()) if point[1]>= float(0) and point[1]<= float(self.h): if point[0]>= float(0) and point[0]<= float(self.w): self._mouseIn = True if self._mouseIn: self.CaptureMouse() self.pos = point def OnLeftUp(self,evt): if self.GetCapture(): self.ReleaseMouse() self._mouseIn = False self._selectRec = False self.setSelection() self.SetGraphEditorData(self.property, self.curFrame) def OnMiddleDown(self,evt): point = (evt.GetX(), evt.GetY()) if point[1]>= float(0) and point[1]<= float(self.h): if point[0]>= float(0) and point[0]<= float(self.w): self._mouseIn = True if self._mouseIn: self.CaptureMouse() self.midPos = point def OnMiddleUp(self, evt): if self.GetCapture(): self.ReleaseMouse() def OnMotion(self,evt): self._mouseIn = False if evt.Dragging() and evt.LeftIsDown(): self.newPos = (evt.GetX(), evt.GetY()) if self.newPos[1]>= float(0) and self.newPos[1]<= float(self.h): if self.newPos[0]>= float(0) and self.newPos[0]<= float(self.w): self._mouseIn = True if self._mouseIn: if self.newPos == self.pos: evt.Skip() self._mouseIn = False else: self._selectRec = True self.SetGraphEditorData(self.property, self.curFrame) if evt.Dragging() and evt.MiddleIsDown(): self.newMidPos = (evt.GetX(), evt.GetY()) if self.newMidPos[1]>= float(0) and self.newMidPos[1]<= float(self.h): if self.newMidPos[0]>= float(0) and self.newMidPos[0]<= float(self.w): self._mouseIn = True if self._mouseIn: if self.newMidPos == self.midPos: evt.Skip() self._mouseIn = False else: self.recalculateSlope() self.onAnimation() self.midPos = self.newMidPos evt.Skip() self._mouseIn = False self._selectRec = False def setExistKey(self, list): flag = False for i in range(len(list)): if list[i][AG.KEYFRAME][AG.SELECT] == 1: inside = self.inside(self.pos, self.newPos, (list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0], list[i][AG.KEYFRAME][AG.LOCAL_VALUE][1])) if inside == True: list[i][AG.KEYFRAME][AG.SELECT] = 0 if inside == False: find = False for j in range(3,5): inside = self.inside(self.pos, self.newPos, (list[i][j][AG.LOCAL_VALUE][0], list[i][j][AG.LOCAL_VALUE][1])) if inside == False: list[i][j][AG.SELECT] = 0 if inside == True: list[i][j][AG.SELECT] = 1 find = True flag = True if find == False: list[i][AG.KEYFRAME][AG.SELECT] == 0 return flag def setNewKey(self, list): for i in range(len(list)): inside = self.inside(self.pos, self.newPos, (list[i][2][0][0], list[i][2][0][1])) if inside == True: list[i][AG.KEYFRAME][AG.SELECT] = 1 if inside == False: list[i][AG.KEYFRAME][AG.SELECT] = 0 def setSelection(self): if self.property == self._mainDialog.namestr: self.setSelectionBase(self.X) self.setSelectionBase(self.Y) self.setSelectionBase(self.Z) return if self.property == property[AG.X]: self.setSelectionBase(self.X) return if self.property == property[AG.Y]: self.setSelectionBase(self.Y) return if self.property == property[AG.Z]: self.setSelectionBase(self.Z) return def setSelectionBase(self, list): self.setExistKey(list) if self.setExistKey(list) == True: return else: self.setNewKey(list) def inside(self, point0, point1, point): if point0[0]<=point1[0] and point0[1]<=point1[1]: if point0[0]= list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0]: self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.INSLOPE][0] = temp0 self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.INSLOPE][1] = temp1 return if handler[1][0][0] < list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0]: if self._OneTangent == False: list[i][AG.IN_TANGENT][0] = handler[1][0] list[i][AG.IN_SLOPE][0] = handler[3][0] list[i][AG.IN_SLOPE][1] = handler[3][1] if self._OneTangent == True: self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.OUTSLOPE][0] = newSlope[0]/self.unitWidth self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.OUTSLOPE][1] = newSlope[1]/self.unitHeight handler = self.generateHandler(self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]]) list[i][AG.IN_TANGENT][0] = handler[1][0] list[i][AG.OUT_TANGENT][0] = handler[2][0] list[i][AG.IN_SLOPE][0] = handler[3][0] list[i][AG.IN_SLOPE][1] = handler[3][1] list[i][AG.OUT_SLOPE][0] = handler[4][0] list[i][AG.OUT_SLOPE][1] = handler[4][1] self.SetGraphEditorData(self.property, self.curFrame) if list[i][AG.OUT_TANGENT][AG.SELECT] == 1: newPointX = list[i][AG.OUT_TANGENT][AG.LOCAL_VALUE][0] + moveX newPointY = list[i][AG.OUT_TANGENT][AG.LOCAL_VALUE][1] + moveY newSlope = [newPointX - list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0] , list[i][AG.KEYFRAME][AG.LOCAL_VALUE][1] - newPointY] temp0 = self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.OUTSLOPE][0] temp1 = self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.OUTSLOPE][1] self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.OUTSLOPE][0] = newSlope[0]/self.unitWidth self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.OUTSLOPE][1] = newSlope[1]/self.unitHeight handler = self.generateHandler(self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]]) if handler[2][0][0] <= list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0]: self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.OUTSLOPE][0] = temp0 self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.OUTSLOPE][1] = temp1 return if handler[2][0][0] > list[i][AG.KEYFRAME][AG.LOCAL_VALUE][0]: if self._OneTangent == False: list[i][AG.OUT_TANGENT][0] = handler[2][0] list[i][AG.OUT_SLOPE][0] = handler[4][0] list[i][AG.OUT_SLOPE][1] = handler[4][1] if self._OneTangent == True: self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.INSLOPE][0] = newSlope[0]/self.unitWidth self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]][AG.INSLOPE][1] = newSlope[1]/self.unitHeight handler = self.generateHandler(self._mainDialog.editor.animMgr.keyFramesInfo[list[i][AG.KEY]][list[i][AG.I]]) list[i][AG.IN_TANGENT][0] = handler[1][0] list[i][AG.OUT_TANGENT][0] = handler[2][0] list[i][AG.IN_SLOPE][0] = handler[3][0] list[i][AG.IN_SLOPE][1] = handler[3][1] list[i][AG.OUT_SLOPE][0] = handler[4][0] list[i][AG.OUT_SLOPE][1] = handler[4][1] self.SetGraphEditorData(self.property, self.curFrame) def selectHandler(self): self._selectHandler = False def onAnimation(self): if self._mainDialog.editor.mode == self._mainDialog.editor.ANIM_MODE: self._mainDialog.editor.ui.animUI.OnAnimation(self._mainDialog.editor.ui.animUI.curFrame) else: pass class GraphEditorUI(wx.Dialog): """ This is the graph editor main class implementation. """ def __init__(self, parent, editor, object): wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Graph Editor", pos=wx.DefaultPosition, size=(735, 535)) self.editor = editor self.editor.GRAPH_EDITOR = True self.object = object self.xRange = 24+1 self.yRange = 50 if self.editor.mode == self.editor.ANIM_MODE: self.curFrame = self.editor.ui.animUI.curFrame self.curFrame = 1 self.mainPanel1 = wx.Panel(self, -1) bmpZoomIn = ZoomIn.GetBitmap() bmpZoomOut = ZoomOut.GetBitmap() bmpOneTangent = OneTangent.GetBitmap() bmpTwoTangents = TwoTangents.GetBitmap() self.buttonZoomIn = wx.BitmapButton(self.mainPanel1, -1, bmpZoomIn, size = (30,30),style = wx.BU_AUTODRAW) self.buttonZoomOut = wx.BitmapButton(self.mainPanel1, -1, bmpZoomOut, size = (30,30),style = wx.BU_AUTODRAW) self.buttonOneTangent = wx.BitmapButton(self.mainPanel1, -1, bmpOneTangent, size = (30,30),style = wx.BU_AUTODRAW) self.buttonTwoTangents = wx.BitmapButton(self.mainPanel1, -1, bmpTwoTangents, size = (30,30),style = wx.BU_AUTODRAW) self.mainPanel2 = wx.Panel(self, -1) self.tree = self.tree = wx.TreeCtrl(self.mainPanel2, id=-1, pos=wx.DefaultPosition,size=wx.Size(200, 450), style=wx.TR_MULTIPLE|wx.TR_DEFAULT_STYLE,validator=wx.DefaultValidator, name="treeCtrl") self.namestr = "%s"%(object[OG.OBJ_DEF].name) self.root = self.tree.AddRoot(self.namestr) self.AddTreeNodes(self.root, property) self.tree.Expand(self.root) self.tree.SelectItem(self.root,select=True) self.str = self.tree.GetItemText(self.root) self.graphEditorWindow =GraphEditorWindow(self.mainPanel2, wx.Size(500, 450), str(object[OG.OBJ_DEF].name), self.xRange, self.yRange, self.curFrame, self.object) self.SetProperties() self.DoLayout() self.Bind(wx.EVT_BUTTON, self.OnZoomIn, self.buttonZoomIn) self.Bind(wx.EVT_BUTTON, self.OnZoomOut, self.buttonZoomOut) self.Bind(wx.EVT_BUTTON, self.OnOneTangent, self.buttonOneTangent) self.Bind(wx.EVT_BUTTON, self.OnTwoTangents, self.buttonTwoTangents) self.Bind(wx.EVT_CLOSE, self.OnExit) self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged) def SetProperties(self): pass def DoLayout(self): dialogSizer = wx.BoxSizer(wx.VERTICAL) mainSizer1 = wx.FlexGridSizer(1, 4, 0, 0) mainSizer2 = wx.FlexGridSizer(1, 2, 0, 0) mainSizer1.Add(self.buttonOneTangent, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 570) mainSizer1.Add(self.buttonTwoTangents, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 10) mainSizer1.Add(self.buttonZoomIn, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 10) mainSizer1.Add(self.buttonZoomOut, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 10) mainSizer2.Add(self.tree, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 10) mainSizer2.Add(self.graphEditorWindow, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 10) self.mainPanel1.SetSizerAndFit(mainSizer1) self.mainPanel2.SetSizer(mainSizer2) dialogSizer.Add(self.mainPanel2, 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP, 10) dialogSizer.Add(self.mainPanel1, 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP, 5) self.SetSizer(dialogSizer) self.Layout() self.dialogSizer = dialogSizer def AddTreeNodes(self, parentItem, items): for item in items: if type(item) == str: self.tree.AppendItem(parentItem, item) def OnSelChanged(self, evt): item = evt.GetItem() if item: self.str = self.tree.GetItemText(item) self.graphEditorWindow.refresh() self.graphEditorWindow.SetGraphEditorData(self.str, self.curFrame) def OnZoomIn(self,evt): self.graphEditorWindow.zoom = self.graphEditorWindow.zoom/float(1.2) self.graphEditorWindow.unitWidth = self.graphEditorWindow.unitWidth*float(1.2) self.graphEditorWindow.unitHeight = self.graphEditorWindow.unitHeight*float(1.2) self.graphEditorWindow.generateInfo() self.graphEditorWindow.SetGraphEditorData(self.str, self.curFrame) def OnZoomOut(self,evt): self.graphEditorWindow.zoom = self.graphEditorWindow.zoom*float(1.2) self.graphEditorWindow.unitWidth = self.graphEditorWindow.unitWidth/float(1.2) self.graphEditorWindow.unitHeight = self.graphEditorWindow.unitHeight/float(1.2) self.graphEditorWindow.generateInfo() self.graphEditorWindow.SetGraphEditorData(self.str, self.curFrame) def OnOneTangent(self,evt): self.graphEditorWindow._OneTangent = True self.graphEditorWindow.SetGraphEditorData(self.str, self.curFrame) def OnTwoTangents(self,evt): self.graphEditorWindow._OneTangent = False self.graphEditorWindow.SetGraphEditorData(self.str, self.curFrame) def curFrameChange(self): if self.editor.mode == self.editor.ANIM_MODE: self.curFrame = self.editor.ui.animUI.curFrame self.graphEditorWindow.SetGraphEditorData(self.str, self.curFrame) else: pass def OnExit(self,evt): self.Destroy() self.editor.ui.graphEditorMenuItem.Check(False) self.object = None self.editor.GRAPH_EDITOR = False