コード例 #1
0
    def __init__(self, parent, pos=(0,0), size=wx.DefaultSize):
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size, style = wx.EXPAND)
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.SetBackgroundColour(BACKGROUND_COLOUR)
        self.parent = parent
        dt = MyFileDropTarget(self)
        self.SetDropTarget(dt)
        self.useMario = False
        self.backBitmap = None
        self.needBitmap = True
        self.onMotion = False
        self.marios = [wx.Bitmap(os.path.join(IMAGES_PATH, 'Mario%d.png' % i), wx.BITMAP_TYPE_PNG) for i in [1,2,3,2,4,5,6,5]]
        if PLATFORM == "darwin":
            fontsize = 10
        else:
            fontsize = 8
        self.font = wx.Font(fontsize, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
        self.font_pos = wx.Font(fontsize, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
        self.trajectories = [Trajectory(self, i+1) for i in range(MAX_STREAMS)]
        self.memorizedTrajectory = Trajectory(self, -1)
        self.memorizedId = {}
        self.midiTranspose = True
        self.midiXposition = 0
        self.midiOctaveSpread = 2
        self.fxballs = {}
        if len(self.fxballs) != 0:
            self.fxball = self.fxballs[0]
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.screenOffset = 2
        self.sndBitmap = None
        self.selected = self.trajectories[0]
        self.bitmapDict = {}
        self.closed = 0
        self.oscilPeriod = 2
        self.oscilScaling = 1
        self.mode = TRAJTYPES[0]
        self.pointerPos = None
        self.SetColors(outline=(255,255,255), bg=(30,30,30), fill=(184,32,32), rect=(0,255,0), losa=(0,0,255), wave=(70,70,70))
        self.currentSize = tuple(self.GetSize())

        self.Bind(wx.EVT_KEY_DOWN, self.KeyDown)
        self.Bind(wx.EVT_KEY_UP, self.KeyUp)
        self.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
        self.Bind(wx.EVT_LEFT_DCLICK, self.MouseDoubleClick)
        self.Bind(wx.EVT_LEFT_UP, self.MouseUp)
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.Bind(wx.EVT_MOTION, self.MouseMotion)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnResize)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)

        if sys.platform == "win32":
            self.dcref = wx.BufferedPaintDC
        else:
            self.dcref = wx.PaintDC
コード例 #2
0
ファイル: DrawingSurface.py プロジェクト: belangeo/soundgrain
    def __init__(self, parent, pos=(0,0), size=wx.DefaultSize):
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size, style = wx.EXPAND)
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.SetBackgroundColour(BACKGROUND_COLOUR)
        self.parent = parent
        dt = MyFileDropTarget(self)
        self.SetDropTarget(dt)
        self.useMario = False
        self.backBitmap = None
        self.needBitmap = True
        self.onMotion = False
        self.marios = [wx.Bitmap(os.path.join(IMAGES_PATH, 'Mario%d.png' % i), wx.BITMAP_TYPE_PNG) for i in [1,2,3,2,4,5,6,5]]
        if PLATFORM == 'linux2':
            self.font = wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, face="Monospace")
            self.font_pos = wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL)
        elif PLATFORM == 'win32':
            self.font = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL, face="Monospace")
            self.font_pos = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL)
        else:
            self.font = wx.Font(10, wx.NORMAL, wx.NORMAL, wx.NORMAL, face="Monospace")
            self.font_pos = wx.Font(10, wx.NORMAL, wx.NORMAL, wx.NORMAL)
        self.trajectories = [Trajectory(self, i+1) for i in range(MAX_STREAMS)]
        self.memorizedTrajectory = Trajectory(self, -1)
        self.memorizedId = {}
        self.midiTranspose = True
        self.midiXposition = 0
        self.midiOctaveSpread = 2
        self.fxballs = {}
        if len(self.fxballs) != 0:
            self.fxball = self.fxballs[0]
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.screenOffset = 2
        self.sndBitmap = None
        self.selected = self.trajectories[0]
        self.bitmapDict = {}
        self.closed = 0
        self.oscilPeriod = 2
        self.oscilScaling = 1
        self.mode = TRAJTYPES[0]
        self.pointerPos = None
        self.SetColors(outline=(255,255,255), bg=(30,30,30), fill=(184,32,32), rect=(0,255,0), losa=(0,0,255), wave=(70,70,70))
        self.currentSize = self.GetSizeTuple()

        self.Bind(wx.EVT_KEY_DOWN, self.KeyDown)
        self.Bind(wx.EVT_KEY_UP, self.KeyUp)
        self.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
        self.Bind(wx.EVT_LEFT_DCLICK, self.MouseDoubleClick)
        self.Bind(wx.EVT_LEFT_UP, self.MouseUp)
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.Bind(wx.EVT_MOTION, self.MouseMotion)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnResize)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)

        if sys.platform == "win32":
            self.dcref = wx.BufferedPaintDC
        else:
            self.dcref = wx.PaintDC
コード例 #3
0
ファイル: MainFrame.py プロジェクト: skwrlion/soundgrain
 def loadFile(self, path):
     if self.midiSettings.IsShown():
         self.midiSettings.Hide()
     self.panel.removeAllFxBalls()
     f = open(path, 'r')
     msg = f.read()
     f.close()
     result, method = xmlrpclib.loads(msg)
     dict = result[0]
     if 'new_soundgrain_file.sg' in path:
         self.currentFile = None
         self.currentPath = None
         title = '%s %s - ' % (NAME, SG_VERSION)
         self.status.SetStatusText("")
     else:
         self.currentFile = path
         self.currentPath = os.path.split(path)[0]
         title = '%s %s - %s' % (NAME, SG_VERSION,
                                 os.path.split(self.currentFile)[1])
     self.panel.trajectories = [
         Trajectory(self.panel, i + 1) for i in range(MAX_STREAMS)
     ]
     self.panel.memorizedTrajectory = Trajectory(self.panel, -1)
     self.panel.memorizedId = {}
     self.controls.setSelected(0)
     self.setState(dict)
     self.SetTitle(title)
     self.panel.needBitmap = True
     size = self.GetSize()
     if size[0] > self.screen_size[0]:
         x = self.screen_size[0] - 50
     else:
         x = size[0]
     if size[1] > self.screen_size[1]:
         y = self.screen_size[1] - 50
     else:
         y = size[1]
     size = (x, y)
     wx.CallAfter(self.panel.Refresh)
     wx.CallLater(100, self.SetSize, size)
コード例 #4
0
ファイル: DrawingSurface.py プロジェクト: belangeo/soundgrain
class DrawingSurface(wx.Panel):
    def __init__(self, parent, pos=(0,0), size=wx.DefaultSize):
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size, style = wx.EXPAND)
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.SetBackgroundColour(BACKGROUND_COLOUR)
        self.parent = parent
        dt = MyFileDropTarget(self)
        self.SetDropTarget(dt)
        self.useMario = False
        self.backBitmap = None
        self.needBitmap = True
        self.onMotion = False
        self.marios = [wx.Bitmap(os.path.join(IMAGES_PATH, 'Mario%d.png' % i), wx.BITMAP_TYPE_PNG) for i in [1,2,3,2,4,5,6,5]]
        if PLATFORM == 'linux2':
            self.font = wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, face="Monospace")
            self.font_pos = wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL)
        elif PLATFORM == 'win32':
            self.font = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL, face="Monospace")
            self.font_pos = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL)
        else:
            self.font = wx.Font(10, wx.NORMAL, wx.NORMAL, wx.NORMAL, face="Monospace")
            self.font_pos = wx.Font(10, wx.NORMAL, wx.NORMAL, wx.NORMAL)
        self.trajectories = [Trajectory(self, i+1) for i in range(MAX_STREAMS)]
        self.memorizedTrajectory = Trajectory(self, -1)
        self.memorizedId = {}
        self.midiTranspose = True
        self.midiXposition = 0
        self.midiOctaveSpread = 2
        self.fxballs = {}
        if len(self.fxballs) != 0:
            self.fxball = self.fxballs[0]
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.screenOffset = 2
        self.sndBitmap = None
        self.selected = self.trajectories[0]
        self.bitmapDict = {}
        self.closed = 0
        self.oscilPeriod = 2
        self.oscilScaling = 1
        self.mode = TRAJTYPES[0]
        self.pointerPos = None
        self.SetColors(outline=(255,255,255), bg=(30,30,30), fill=(184,32,32), rect=(0,255,0), losa=(0,0,255), wave=(70,70,70))
        self.currentSize = self.GetSizeTuple()

        self.Bind(wx.EVT_KEY_DOWN, self.KeyDown)
        self.Bind(wx.EVT_KEY_UP, self.KeyUp)
        self.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
        self.Bind(wx.EVT_LEFT_DCLICK, self.MouseDoubleClick)
        self.Bind(wx.EVT_LEFT_UP, self.MouseUp)
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.Bind(wx.EVT_MOTION, self.MouseMotion)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnResize)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)

        if sys.platform == "win32":
            self.dcref = wx.BufferedPaintDC
        else:
            self.dcref = wx.PaintDC

    def setCurrentSize(self, size):
        self.currentSize = size
        self.needBitmap = True
        self.Refresh()

    def OnLeave(self, evt):
        self.pointerPos = None
        self.Refresh()
        evt.Skip()

    def OnResize(self, evt):
        w,h = self.GetSizeTuple()
        cX, cY = self.currentSize[0], self.currentSize[1]
        for t in self.getActiveTrajectories():
            for i, p in enumerate(t.getPoints()):
                xscl = p[0] / float(cX)
                yscl = p[1] / float(cY)
                t.points[i] = (w * xscl, h * yscl)
            t.setPointPos(t.getFirstPoint())
            if t.getType() in ['circle', 'oscil']:
                center = t.getCenter()
                xscl = center[0] / float(cX)
                yscl = center[1] / float(cY)
                t.setCenter((w * xscl, h * yscl))
                t.setRadius(t.getCenter()[0] - t.getFirstPoint()[0])
            t.setInitPoints()
        for fxball in self.fxballs.values():
            center = fxball.getCenter()
            size = fxball.getSize()
            scl = (w / (float(cX)) + (h / float(cY))) * 0.5
            fxball.setSize(int(size * scl))
            xscl = center[0] / float(cX)
            yscl = center[1] / float(cY)
            fxball.setCenter((w * xscl, h * yscl))

        self.currentSize = (w,h)
        self.needBitmap = True
        self.parent.controls.drawWaveform()
        wx.CallAfter(self.Refresh)

    def restoreFxBall(self, dict):
        self.fxballs[dict["id"]] = FxBall(dict["fx"], dict["id"], self.parent.sg_audio, dict["pos"], dict["size"], dict["gradient"], dict["fader"])
        self.parent.sg_audio.addFx(dict["fx"], dict["id"])
        self.fxballs[dict["id"]].load(dict["controls"])
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.needBitmap = True
        self.Refresh()

    def restoreFxBalls(self, dict, xfac=1.0, yfac=1.0):
        if dict != {}:
            for dic in dict.values():
                self.fxballs[dic["id"]] = FxBall(dic["fx"], dic["id"], self.parent.sg_audio, dic["pos"], 
                                            dic["size"], dic["gradient"], dic["fader"], xfac, yfac)
                self.parent.sg_audio.addFx(dic["fx"], dic["id"])
                self.fxballs[dic["id"]].load(dic["controls"])
            self.fxballValues = [fx for fx in self.fxballs.values()]
            self.needBitmap = True
            self.Refresh()

    def addFxBall(self, fx):
        key = -1
        fxkeys = self.fxballs.keys()
        for i in range(10):
            if i not in fxkeys:
                key = i
                break
        if key != -1:
            self.fxballs[key] = FxBall(fx, key, self.parent.sg_audio, (100,100))
            self.parent.sg_audio.addFx(fx, key)
            self.fxballValues = [fx for fx in self.fxballs.values()]
            self.needBitmap = True
            self.Refresh()

    def removeAllFxBalls(self):
        for key in self.fxballs.keys():
            self.fxballs[key].hideControls()
            del self.fxballs[key]
            self.parent.sg_audio.removeFx(key)
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.needBitmap = True
        self.Refresh()

    def removeFxBall(self, key):
        self.fxballs[key].hideControls()
        del self.fxballs[key]
        self.parent.sg_audio.removeFx(key)
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.needBitmap = True
        self.Refresh()

    def clock(self, which):
        t = self.trajectories[which]
        t.clock()
        if t.getActive():
            w,h = self.GetSizeTuple()
            w,h = float(w), float(h)
            if t.getPointPos() != None:
                x = t.getPointPos()[0]/w
                y = 1 - t.getPointPos()[1]/h
                self.parent.sg_audio.setXposition(which, x)
                self.parent.sg_audio.setYposition(which, y)

    def setMidiTranspose(self, value):
        self.midiTranspose = value

    def setMidiXposition(self, value):
        self.midiXposition = value

    def setMidiOctaveSpread(self, value):
        self.midiOctaveSpread = value

    def setOscilPeriod(self, period):
        self.oscilPeriod = period

    def getOscilPeriod(self):
        return self.oscilPeriod

    def setOscilScaling(self, scaling):
        self.oscilScaling = scaling

    def getOscilScaling(self):
        return self.oscilScaling

    def SetColors(self, outline, bg, fill, rect, losa, wave):
        self.outlinecolor = wx.Colour(*outline)
        self.backgroundcolor = wx.Colour(*bg)
        self.fillcolor = wx.Colour(*fill)
        self.rectcolor = wx.Colour(*rect)
        self.losacolor = wx.Colour(*losa)
        self.wavecolor = wx.Colour(*wave)
        self.losaBrush = wx.Brush(self.losacolor, wx.SOLID)
        self.losaPen = wx.Pen(self.losacolor, width=1, style=wx.SOLID)

    def getValues(self):
        w,h = self.GetSizeTuple()
        w,h = float(w), float(h)
        vals = []
        for t in self.trajectories:
            if t.getPointPos() != None:
                x = t.getPointPos()[0]/w
                y = 1 - t.getPointPos()[1]/h
                vals.append([x,y])
            else:
                vals.append([])
        return vals

    def setMode(self, mode):
        self.mode = TRAJTYPES[mode]

    def setClosed(self, closed):
        self.closed = closed

    def getTrajectory(self, which):
        return self.trajectories[which]

    def getAllTrajectories(self):
        return self.trajectories

    def getActiveTrajectories(self):
        return [t for t in self.trajectories if t.getActive()]

    def OnRightDown(self, evt):
        self.SetFocus()
        for t in self.getActiveTrajectories():
            if t.getInsideRect(evt.GetPosition()):
                t.clear()
                if len(self.getActiveTrajectories()) > 0:
                    self.setSelected(self.getActiveTrajectories()[0])
                else:
                    self.setSelected(self.getTrajectory(0))
                self.needBitmap = True
                self.Refresh()
                return
        mouseState = wx.GetMouseState()
        mousePos = (mouseState.GetX(), mouseState.GetY())
        for fxball in self.fxballs.values():
            if fxball.getInside(evt.GetPosition(), small=True):
                fxball.openControls(mousePos)
                return

    def setSelectedById(self, id):
        self.selected = self.trajectories[id]

    def setSelected(self, traj):
        self.selected = traj
        self.parent.controls.setSelected(self.selected.getId())

    def Memorize(self):
        w,h = self.GetSize()
        t = self.selected
        self.memorizedTrajectory.setType(t.getType())
        self.memorizedTrajectory.setTimeSpeed(t.getTimeSpeed())
        self.memorizedTrajectory.setStep(t.getStep())
        self.memorizedTrajectory.activateLp(self.parent.lowpass)
        self.memorizedTrajectory.setEditionLevel(self.parent.editionLevel)
        self.memorizedTrajectory.setPoints(t.getPoints())
        self.memorizedTrajectory.setInitPoints()
        if self.memorizedTrajectory.getType() not in  ['free', 'line']:
            self.memorizedTrajectory.setRadius(t.getRadius())
            self.memorizedTrajectory.setCenter(t.getCenter())
        if self.midiXposition:
            off = (w/2) - self.memorizedTrajectory.getFirstPoint()[0]
            self.memorizedTrajectory.move((off, 0))
            self.memorizedTrajectory.setInitPoints()

    def addTrajFromMemory(self, index, pitch, normy, midinote):
        t = self.memorizedTrajectory
        for new_t in self.trajectories:
            if not new_t.getActive():
                self.memorizedId[index] = new_t.getId()
                new_t.setTimeSpeed(t.getTimeSpeed())
                if self.midiTranspose:
                    new_t.setTranspo(pitch)
                else:
                    new_t.setTranspo(1.0)
                new_t.setStep(t.getStep())
                new_t.setActive(True)
                new_t.setType(self.mode)
                new_t.lpx.reinit()
                new_t.lpy.reinit()
                new_t.activateLp(self.parent.lowpass)
                new_t.setEditionLevel(self.parent.editionLevel)
                new_t.setPoints(t.getPoints())
                new_t.setInitPoints()
                if new_t.getType() == 'free':
                    pass
                else:
                    new_t.setCenter(t.getCenter())
                    new_t.setRadius(t.getRadius())
                break
        Xs = [p[0] for p in new_t.getPoints()]
        extremeXs = (min(Xs), max(Xs))
        Ys = [p[1] for p in new_t.getPoints()]
        extremeYs = (min(Ys), max(Ys))
        if new_t.getType() not in  ['free', 'line']:
            curCenter = new_t.getCenter()
        downPos = new_t.getFirstPoint()
        w,h = self.GetSize()
        if not self.midiXposition:
            x, y = downPos[0], int((1.-normy)*h)
        else:
            if pitch <= 1:
                normx = int((w/2) - (w * (60 - midinote) / 12. / self.midiOctaveSpread))
            else:
                normx = int((w/2) + (w * (midinote - 60) / 12. / self.midiOctaveSpread))
            x,y = normx, int((1.-normy)*h)
        if new_t.getType() in ['free', 'line']:
            offset = (downPos[0] - x, downPos[1] - y)
            clipedOffset = self.clip(offset, extremeXs, extremeYs)
            new_t.move(clipedOffset)
        else:
            offset = (downPos[0] - x, downPos[1] - y)
            center, clipedOffset = self.clipCircleMove(new_t.getRadius(), curCenter, offset)
            new_t.setCenter(center)
            new_t.move(clipedOffset)
        self.needBitmap = True
        self.Refresh()

    def deleteMemorizedTraj(self, index):
        id = self.memorizedId[index]
        t = self.trajectories[id]
        t.clear()
        if len(self.getActiveTrajectories()) > 0:
            self.setSelected(self.getActiveTrajectories()[0])
        else:
            self.setSelected(self.getTrajectory(0))
        self.needBitmap = True
        self.Refresh()

    def KeyDown(self, evt):
        if evt.GetKeyCode() in [wx.WXK_BACK, wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE]:
            if self.selected != None:
                self.selected.clear()
                if len(self.getActiveTrajectories()) > 0:
                    self.setSelected(self.getActiveTrajectories()[0])
                else:
                    self.setSelected(self.getTrajectory(0))
            evt.StopPropagation()
            return

        off = {wx.WXK_UP: [0,1], wx.WXK_DOWN: [0,-1], wx.WXK_LEFT: [1,0], wx.WXK_RIGHT: [-1,0]}.get(evt.GetKeyCode(), [0,0])
        # Move selected trajectory
        if evt.ShiftDown() and off != [0,0]:
            traj = self.trajectories[self.parent.controls.getSelected()]
            if traj.getType() in ['circle', 'oscil']:
                center = traj.getCenter()
                traj.setCenter((center[0]-off[0], center[1]-off[1]))
            traj.move(off)
            traj.setInitPoints()
            self.onMotion = True
            evt.StopPropagation()
            return
        # Move all trajectories
        elif off != [0,0]:
            for traj in self.getActiveTrajectories():
                if traj.getType() in ['circle', 'oscil']:
                    center = traj.getCenter()
                    traj.setCenter((center[0]-off[0], center[1]-off[1]))
                traj.move(off)
                traj.setInitPoints()
            self.onMotion = True
            evt.StopPropagation()
            return
        # Set freeze mode
        if evt.GetKeyCode() < 256:
            c = chr(evt.GetKeyCode())
            if c in ['1', '2', '3', '4', '5', '6', '7', '8']:
                if self.trajectories[int(c)-1].getFreeze():
                    self.trajectories[int(c)-1].setFreeze(False)
                else:
                    self.trajectories[int(c)-1].setFreeze(True)
            elif c == '0':
                for i in range(8):
                    if self.trajectories[i].getFreeze():
                        self.trajectories[i].setFreeze(False)
                    else:
                        self.trajectories[i].setFreeze(True)
            elif c == '9':
                if not self.useMario:
                    self.useMario = True
                else:
                    self.useMario = False
        evt.Skip()

    def KeyUp(self, evt):
        self.onMotion = False
        if evt.GetKeyCode() in [wx.WXK_BACK, wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE, wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT]:
            self.needBitmap = True
            self.Refresh()

    def MouseDoubleClick(self, evt):
        self.SetFocus()
        self.downPos = evt.GetPositionTuple()
        for t in self.getActiveTrajectories():
            # Select or duplicate trajectory
            if t.getInsideRect(self.downPos):
                for new_t in self.trajectories:
                    if not new_t.getActive():
                        self.setSelected(new_t)
                        self.selected.setActive(True)
                        self.selected.setType(t.getType())
                        self.selected.lpx.reinit()
                        self.selected.lpy.reinit()
                        self.selected.activateLp(self.parent.lowpass)
                        self.selected.setEditionLevel(self.parent.editionLevel)
                        self.selected.setPoints(t.getPoints())
                        self.selected.setInitPoints()
                        if self.selected.getType() not in  ['free', 'line']:
                            self.selected.setRadius(t.getRadius())
                            self.selected.setCenter(t.getCenter())
                        break
                else:
                    self.setSelected(t)
                Xs = [p[0] for p in self.selected.getPoints()]
                self.extremeXs = (min(Xs), max(Xs))
                Ys = [p[1] for p in self.selected.getPoints()]
                self.extremeYs = (min(Ys), max(Ys))
                self.action = 'drag'
                if self.selected.getType() not in  ['free', 'line']:
                    self.curCenter = self.selected.getCenter()
                self.CaptureMouse()
                return

        for key, fxball in self.fxballs.items():
            if fxball.getInside(self.downPos, small=True):
                self.removeFxBall(key)
                break

        evt.Skip()

    def MouseDown(self, evt):
        self.SetFocus()
        self.downPos = evt.GetPositionTuple()
        for t in self.getActiveTrajectories():
            # Select or duplicate trajectory
            if t.getInsideRect(self.downPos):
                if evt.AltDown():
                    for new_t in self.trajectories:
                        if not new_t.getActive():
                            self.setSelected(new_t)
                            self.selected.setActive(True)
                            self.selected.setType(t.getType())
                            self.selected.lpx.reinit()
                            self.selected.lpy.reinit()
                            self.selected.activateLp(self.parent.lowpass)
                            self.selected.setEditionLevel(self.parent.editionLevel)
                            self.selected.setPoints(t.getPoints())
                            self.selected.setInitPoints()
                            if self.selected.getType() not in  ['free', 'line']:
                                self.selected.setRadius(t.getRadius())
                                self.selected.setCenter(t.getCenter())
                            break
                else:
                    self.setSelected(t)
                Xs = [p[0] for p in self.selected.getPoints()]
                self.extremeXs = (min(Xs), max(Xs))
                Ys = [p[1] for p in self.selected.getPoints()]
                self.extremeYs = (min(Ys), max(Ys))
                self.curCenters = [traj.getCenter() for traj in self.getActiveTrajectories()]
                self.action = 'drag'
                if self.selected.getType() not in  ['free', 'line']:
                    self.curCenter = self.selected.getCenter()
                self.CaptureMouse()
                return
            # Rescale circle or oscil trajectory
            if t.getInsideLosange(self.downPos):
                self.setSelected(t)
                self.action = 'rescale'
                self.CaptureMouse()
                return
            # Check for trajectory transformation
            for p in t.getPoints():
                if wx.Rect(p[0]-5, p[1]-5, 10, 10).Contains(self.downPos):
                    self.pindex = t.getPoints().index(p)
                    self.setSelected(t)
                    self.action = 'edit'
                    self.CaptureMouse()
                    return
        # Check if inside an FxBall
        for key, fxball in self.fxballs.items():
            if fxball.getInside(self.downPos, small=True):
                if evt.AltDown():
                    self.removeFxBall(key)
                else:
                    self.fxball = fxball
                    self.action = 'drag_ball'
                    self.CaptureMouse()
                return
            elif fxball.getInside(self.downPos, small=False):
                if evt.AltDown():
                    self.removeFxBall(key)
                    self.Refresh()
                else:
                    self.fxball = fxball
                    self.action = 'rescale_ball'
                    self.CaptureMouse()
                return

        # Click in an empty space, draw a new trajectory
        self.action = 'draw'
        for t in self.trajectories:
            if not t.getActive():
                self.traj = t
                self.traj.setActive(True)
                self.traj.setType(self.mode)
                self.traj.lpx.reinit()
                self.traj.lpy.reinit()
                self.traj.activateLp(self.parent.lowpass)
                self.traj.setEditionLevel(self.parent.editionLevel)
                if self.traj.getType() == 'free':
                    self.traj.addPoint(self.clipPos(self.downPos))
                else:
                    self.traj.setCenter(self.downPos)
                    self.traj.setRadius(0)
                self.CaptureMouse()
                self.Refresh()
                break
            else:
                self.traj = None
        evt.Skip()

    def MouseUp(self, evt):
        if self.HasCapture():
            if self.action == 'draw' and self.traj:
                if len(self.traj.getPoints()) <= 1:
                    self.traj.clear()
                    self.ReleaseMouse()
                    return
                if self.traj.getType() == 'free':
                    self.traj.addFinalPoint(self.clipPos(evt.GetPositionTuple()), self.closed)
                    if self.parent.fillPoints:
                        self.traj.fillPoints(self.closed)
                    self.traj.setInitPoints()
                elif self.traj.getType() in ['circle', 'oscil']:
                    if self.parent.fillPoints:
                        self.traj.fillPoints(False)
                    self.traj.setInitPoints()
                else:
                    if self.parent.fillPoints:
                        self.traj.fillPoints(False)
                    self.traj.setInitPoints()
            elif self.action == 'drag':
                self.selected.setInitPoints()
            elif self.action == 'rescale':
                if self.selected.getType() == 'circle':
                    if self.parent.fillPoints:
                        self.selected.fillPoints(True)
                else:
                    if self.parent.fillPoints:
                        self.selected.fillPoints(False)
                self.selected.setInitPoints()
            elif self.action == 'edit':
                if self.parent.fillPoints:
                    self.selected.fillPoints(False)
                self.selected.setInitPoints()
                self.selected.setType('free')
            elif self.action in ['drag_ball', 'rescale_ball']:
                self.fxball.restoreGradient()
                self.fxball.restoreCenter()

            self.Refresh()
            self.ReleaseMouse()
            if self.action not in ['drag_ball', 'rescale_ball']:
                self.parent.createTempFile()
            self.onMotion = False
            self.needBitmap = True
        evt.Skip()

    def MouseMotion(self, evt):
        self.pointerPos = evt.GetPositionTuple()
        if self.HasCapture() and evt.Dragging() and evt.LeftIsDown():
            if self.action == 'draw' and self.traj:
                if self.traj.getType() == 'free':
                    self.traj.addPoint(self.clipPos(evt.GetPositionTuple()))
                elif self.traj.getType() == 'line':
                    self.traj.points = []
                    self.traj.lpx.reinit()
                    self.traj.lpy.reinit()
                    x,y = self.clipPos(evt.GetPositionTuple())

                    x2 = abs(x-self.downPos[0])
                    y2 = abs(y-self.downPos[1])
                    maxstep = int(math.sqrt(x2*x2+y2*y2))

                    if self.downPos[0] == x: xdir = 0
                    elif self.downPos[0] < x: xdir = 1
                    else: xdir = -1
                    if self.downPos[1] == y: ydir = 0
                    elif self.downPos[1] < y: ydir = 1
                    else: ydir = -1

                    for i in range(0, maxstep, 2):
                        xpt = self.downPos[0] + xdir * int(x2 * i / float(maxstep))
                        ypt = self.downPos[1] + ydir * int(y2 * i / float(maxstep))
                        self.traj.addPoint((int(round(xpt)),int(round(ypt))))
                else:
                    Xlen = abs(self.downPos[0] - evt.GetPosition()[0])
                    Ylen = abs(self.downPos[1] - evt.GetPosition()[1])
                    self.traj.setRadius(self.clipCirclePos(math.sqrt( Xlen**2 + Ylen**2 ), self.traj.getCenter(), self.traj.getRadius()))
                    r = self.traj.getRadius()
                    halfR = int(round(r/2.))
                    if halfR <= 1: scaleR = 1
                    else: scaleR = 1./(halfR-1)
                    self.traj.points = []
                    self.traj.lpx.reinit()
                    self.traj.lpy.reinit()
                    if self.traj.getType() == 'circle':
                        for i in range(-halfR,halfR+1):
                            a = i * scaleR * r
                            x = math.cos(math.pi * i * scaleR) * r
                            y = math.sin(math.pi * i * scaleR) * r
                            self.traj.addCirclePoint((int(round(x + self.downPos[0])), int(round(y + self.downPos[1]))))
                    else:
                        for i in range(int(-halfR * self.oscilScaling), int(halfR * self.oscilScaling + 1)):
                            a = i * scaleR * r
                            x = math.cos(math.pi * i * scaleR) * r
                            y = math.sin(math.pi * self.oscilPeriod * i * scaleR) * r
                            self.traj.addCirclePoint((int(round(x + self.downPos[0])), int(round(y + self.downPos[1]))))

            elif self.action == 'drag':
                if self.selected.getType() in ['free', 'line']:
                    x,y = evt.GetPositionTuple()
                    offset = (self.downPos[0] - x, self.downPos[1] - y)
                    clipedOffset = self.clip(offset, self.extremeXs, self.extremeYs)
                    self.selected.move(clipedOffset)
                else:
                    x,y = self.clipPos(evt.GetPositionTuple())
                    offset = (self.downPos[0] - x, self.downPos[1] - y)
                    center, clipedOffset = self.clipCircleMove(self.selected.getRadius(), self.curCenter, offset)
                    self.selected.setCenter(center)
                    self.selected.move(clipedOffset)
                if evt.ShiftDown():
                    for traj in self.getActiveTrajectories():
                        if traj != self.selected:
                            if traj.getType() in ['free', 'line']:
                                clipedOffset = self.clip(offset, self.extremeXs, self.extremeYs)
                                traj.move(clipedOffset)
                            else:
                                center, clipedOffset = self.clipCircleMove(traj.getRadius(), self.curCenters[traj.getId()], offset)
                                traj.setCenter(center)
                                traj.move(clipedOffset)

            elif self.action == 'rescale':
                Xlen = abs(self.selected.getCenter()[0] - evt.GetPosition()[0])
                Ylen = abs(self.selected.getCenter()[1] - evt.GetPosition()[1])
                self.selected.setRadius(self.clipCirclePos(math.sqrt( Xlen**2 + Ylen**2 ), self.selected.getCenter(), self.selected.getRadius()))
                r = self.selected.getRadius()
                halfR = int(round(r/2.))
                if halfR <= 1: scaleR = 1
                else: scaleR = 1./(halfR-1)
                self.selected.points = []
                self.selected.lpx.reinit()
                self.selected.lpy.reinit()
                if self.selected.getType() == 'circle':
                    for i in range(-halfR,halfR+1):
                        a = i * scaleR * r
                        x = math.cos(math.pi * i * scaleR) * r
                        y = math.sin(math.pi * i * scaleR) * r
                        self.selected.addCirclePoint((int(round(x + self.selected.getCenter()[0])), int(round(y + self.selected.getCenter()[1]))))
                else:
                    for i in range(int(-halfR * self.oscilScaling), int(halfR * self.oscilScaling + 1)):
                        a = i * scaleR * r
                        x = math.cos(math.pi * i * scaleR) * r
                        y = math.sin(math.pi * self.oscilPeriod * i * scaleR) * r
                        self.selected.addCirclePoint((int(round(x + self.selected.getCenter()[0])), int(round(y + self.selected.getCenter()[1]))))
            elif self.action == 'edit':
                x,y = evt.GetPositionTuple()
                offset = (self.downPos[0] - x, self.downPos[1] - y)
                self.selected.editTraj(self.pindex, offset)
            elif self.action == 'drag_ball':
                pos = evt.GetPositionTuple()
                if evt.ShiftDown():
                    off = (self.downPos[1] - pos[1])
                    self.fxball.setGradient(off)
                else:
                    self.fxball.move(pos)
            elif self.action == 'rescale_ball':
                pos = evt.GetPositionTuple()
                x = self.fxball.center[0] - pos[0]
                y = self.fxball.center[1] - pos[1]
                hyp = math.sqrt(x*x+y*y)
                if hyp < 5: hyp = 5
                self.fxball.resize(hyp*2)

            self.onMotion = True
            self.Refresh()
        evt.Skip()

    def draw(self, dc):
        gc = wx.GraphicsContext_Create(dc)
        dc.BeginDrawing()
        dc.SetTextForeground("#000000")
        dc.SetFont(self.font)
        if not self.sndBitmap:
            w,h = self.GetSizeTuple()
            dc.SetBrush(wx.Brush(self.backgroundcolor, wx.SOLID))
            dc.Clear()
            dc.SetPen(wx.Pen(self.outlinecolor, width=1, style=wx.SOLID))
            dc.DrawRectangle(0, 0, w, h)
        else:
            dc.DrawBitmap(self.sndBitmap,0,0)

        [dc.DrawBitmap(fx.bit, fx.pos[0], fx.pos[1], True) for fx in self.fxballValues]

        selectedTraj = self.parent.controls.getSelected()
        activeTrajs = [t for t in self.getActiveTrajectories() if len(t.getPoints()) > 1]
        for t in activeTrajs:
            recsize = 14
            s2 = recsize / 2
            gc.SetBrush(t.getBrush(trans=True))
            gc.SetPen(t.getPen(big=True))
            if len(t.getPoints()) >= 2:
                gc.DrawLines(t.getPoints())
            if t.getId() == selectedTraj:
                recsize = 14
                s2 = recsize / 2
                self.selected = t
                gc.SetPen(wx.Pen("#EEEEEE", width=2, style=wx.SOLID))
            if t.getFirstPoint() != None:
                gc.SetBrush(t.getBrush())
                gc.DrawRoundedRectangle(t.getFirstPoint()[0]-s2, t.getFirstPoint()[1]-s2, recsize, recsize, 2)
                dc.DrawLabel(str(t.getLabel()), wx.Rect(t.getFirstPoint()[0]-s2,t.getFirstPoint()[1]-s2, recsize, recsize), wx.ALIGN_CENTER)
                if t.getType() in ['circle', 'oscil']:
                    gc.SetBrush(self.losaBrush)
                    gc.SetPen(self.losaPen)
                    gc.DrawRoundedRectangle(t.getLosangePoint()[0]-5, t.getLosangePoint()[1]-5, 10, 10, 2)
        dc.EndDrawing()

    def drawBackBitmap(self):
        w,h = self.currentSize
        if self.backBitmap == None or self.backBitmap.GetSize() != self.currentSize:
            self.backBitmap = wx.EmptyBitmap(w,h)
        dc = wx.MemoryDC(self.backBitmap)
        self.draw(dc)
        dc.SelectObject(wx.NullBitmap)
        self.needBitmap = False

    def OnPaint(self, evt):
        dc = self.dcref(self)
        gc = wx.GraphicsContext_Create(dc)
        dc.BeginDrawing()

        if self.onMotion or self.needBitmap:
            self.drawBackBitmap()
        dc.DrawBitmap(self.backBitmap,0,0)

        activeTrajs = [t for t in self.getActiveTrajectories() if len(t.getPoints()) > 1 and t.circlePos]
        self.parent.sg_audio.setMixerChannelAmps(activeTrajs, self.fxballValues)

        if not self.useMario:
            for t in activeTrajs:
                if t.circlePos != None:
                    gc.SetPen(t.getPen())
                    gc.SetBrush(t.getBrush())
                    gc.DrawEllipse(t.circlePos[0]-5, t.circlePos[1]-5, 10, 10)
                    gc.SetPen(t.getBorderPen())
                    gc.SetBrush(t.getBorderBrush())
                    gc.DrawEllipse(t.circlePos[0]-2, t.circlePos[1]-2, 4, 4)
        else:
            for t in activeTrajs:
                if t.lastCirclePos[0] < t.circlePos[0]: marioff = 0
                else: marioff = 4
                bitmario = self.marios[t.mario + marioff]
                dc.DrawBitmap(bitmario, t.circlePos[0]-8, t.circlePos[1]-8, True)

        if self.pointerPos != None:
            w,h = self.GetSizeTuple()
            dc.SetTextForeground("#FFFFFF")
            dc.SetFont(self.font_pos)
            xvalue = self.pointerPos[0] / float(w) * self.parent.controls.sndDur
            yvalue = (h - self.pointerPos[1]) / float(h)
            dc.DrawText("X: %.3f   Y: %.3f" % (xvalue, yvalue), w-100, h-13)
        dc.EndDrawing()

    def clip(self, off, exXs, exYs):
        Xs = [p[0] for p in self.selected.getPoints()]
        minX, maxX = min(Xs), max(Xs)
        Ys = [p[1] for p in self.selected.getPoints()]
        minY, maxY = min(Ys), max(Ys)
        x,y = off
        sizex, sizey = self.GetSizeTuple()
        offset = self.screenOffset
        if exXs[0] - off[0] >= offset and exXs[1] - off[0] <= sizex - offset:
            x = x
        elif exXs[1] - off[0] >= sizex - offset:
            x = exXs[1] - sizex + offset
        else:
            x = exXs[0] - offset - 1
        if exYs[0] - off[1] >= offset and exYs[1] - off[1] <= sizey - offset:
            y = y
        elif exYs[1] - off[1] >= sizey - offset:
            y = exYs[1] - sizey + offset
        else:
            y = exYs[0] - offset - 1
        return (x,y)

    def clipPos(self, pos):
        x,y = pos
        sizex, sizey = self.GetSizeTuple()
        offset = self.screenOffset
        if x < offset: x = offset
        elif x > (sizex-offset): x = sizex - offset
        else: x = x
        if y < offset: y = offset
        elif y > (sizey-offset): y = sizey - offset
        else: y = y
        return (x,y)

    def clipCirclePos(self, rad, center, lastRad):
        sizex, sizey = self.GetSizeTuple()
        offset = self.screenOffset
        flag = True
        radius1 = radius2 = radius3 = radius4 = 1000000
        if center[0] - rad <= 0 + offset:
            radius1 = center[0] - offset
            flag = False
        if center[1] - rad <= 0 + offset:
            radius2 = center[1] - offset
            flag = False
        if center[0] + rad >= sizex - offset:
            radius3 = sizex - offset - center[0]
            flag = False
        if center[1] + rad >= sizey - offset:
            radius4 = sizey - offset - center[1]
            flag = False
        if flag:
            return rad
        else:
            return min(radius1, radius2, radius3, radius4)

    def clipCircleMove(self, rad, center, offset):
        sizex, sizey = self.GetSizeTuple()
        off = self.screenOffset
        if center[0] - offset[0] - rad >= 0 + off and center[0] - offset[0] + rad <= sizex - off:
            cx = center[0] - offset[0]
            offx = offset[0]
        elif center[0] - offset[0] + rad >= sizex - off:
            cx = sizex - off - rad
            offx = center[0] - cx
        else:
            cx = 0 + off + rad
            offx = center[0] - cx
        if center[1] - offset[1] - rad >= 0 + off and center[1] - offset[1] + rad <= sizey - off:
            cy = center[1] - offset[1]
            offy = offset[1]
        elif center[1] - offset[1] + rad >= sizey - off:
            cy = sizey - off - rad
            offy = center[1] - cy
        else:
            cy = 0 + off + rad
            offy = center[1] - cy
        return [cx, cy], [offx, offy]

    def analyse(self, file):
        self.file = file
        self.list = self.parent.sg_audio.getViewTable(self.GetSizeTuple())
        self.bitmapDict[self.file] = self.list
        self.create_bitmap()

    def create_bitmap(self):
        size = self.GetSizeTuple()
        self.sndBitmap = wx.EmptyBitmap(size[0], size[1])
        memory = wx.MemoryDC()
        memory.SelectObject(self.sndBitmap)
        gc = wx.GraphicsContext_Create(memory)
        gc.SetPen(wx.Pen("#3F3F44"))
        gc.SetBrush(wx.Brush("#3F3F44", style=wx.TRANSPARENT))
        memory.SetBrush(wx.Brush(self.backgroundcolor))
        memory.DrawRectangle(0,0,size[0],size[1])
        for samples in self.list:
            if len(samples):
                gc.DrawLines(samples)
        memory.SelectObject(wx.NullBitmap)
        self.needBitmap = True
        self.Refresh()
コード例 #5
0
class DrawingSurface(wx.Panel):
    def __init__(self, parent, pos=(0,0), size=wx.DefaultSize):
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size, style = wx.EXPAND)
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.SetBackgroundColour(BACKGROUND_COLOUR)
        self.parent = parent
        dt = MyFileDropTarget(self)
        self.SetDropTarget(dt)
        self.useMario = False
        self.backBitmap = None
        self.needBitmap = True
        self.onMotion = False
        self.marios = [wx.Bitmap(os.path.join(IMAGES_PATH, 'Mario%d.png' % i), wx.BITMAP_TYPE_PNG) for i in [1,2,3,2,4,5,6,5]]
        if PLATFORM == "darwin":
            fontsize = 10
        else:
            fontsize = 8
        self.font = wx.Font(fontsize, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
        self.font_pos = wx.Font(fontsize, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
        self.trajectories = [Trajectory(self, i+1) for i in range(MAX_STREAMS)]
        self.memorizedTrajectory = Trajectory(self, -1)
        self.memorizedId = {}
        self.midiTranspose = True
        self.midiXposition = 0
        self.midiOctaveSpread = 2
        self.fxballs = {}
        if len(self.fxballs) != 0:
            self.fxball = self.fxballs[0]
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.screenOffset = 2
        self.sndBitmap = None
        self.selected = self.trajectories[0]
        self.bitmapDict = {}
        self.closed = 0
        self.oscilPeriod = 2
        self.oscilScaling = 1
        self.mode = TRAJTYPES[0]
        self.pointerPos = None
        self.SetColors(outline=(255,255,255), bg=(30,30,30), fill=(184,32,32), rect=(0,255,0), losa=(0,0,255), wave=(70,70,70))
        self.currentSize = tuple(self.GetSize())

        self.Bind(wx.EVT_KEY_DOWN, self.KeyDown)
        self.Bind(wx.EVT_KEY_UP, self.KeyUp)
        self.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
        self.Bind(wx.EVT_LEFT_DCLICK, self.MouseDoubleClick)
        self.Bind(wx.EVT_LEFT_UP, self.MouseUp)
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.Bind(wx.EVT_MOTION, self.MouseMotion)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnResize)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)

        if sys.platform == "win32":
            self.dcref = wx.BufferedPaintDC
        else:
            self.dcref = wx.PaintDC

    def setCurrentSize(self, size):
        self.currentSize = size
        self.needBitmap = True
        self.Refresh()

    def OnLeave(self, evt):
        self.pointerPos = None
        self.Refresh()
        evt.Skip()

    def OnResize(self, evt):
        w,h = self.GetSize()
        cX, cY = self.currentSize[0], self.currentSize[1]
        for t in self.getActiveTrajectories():
            for i, p in enumerate(t.getPoints()):
                xscl = p[0] / float(cX)
                yscl = p[1] / float(cY)
                t.points[i] = (w * xscl, h * yscl)
            t.setPointPos(t.getFirstPoint())
            if t.getType() in ['circle', 'oscil']:
                center = t.getCenter()
                xscl = center[0] / float(cX)
                yscl = center[1] / float(cY)
                t.setCenter((w * xscl, h * yscl))
                t.setRadius(t.getCenter()[0] - t.getFirstPoint()[0])
            t.setInitPoints()
        for fxball in self.fxballs.values():
            center = fxball.getCenter()
            size = fxball.getSize()
            scl = (w / (float(cX)) + (h / float(cY))) * 0.5
            fxball.setSize(int(size * scl))
            xscl = center[0] / float(cX)
            yscl = center[1] / float(cY)
            fxball.setCenter((w * xscl, h * yscl))

        self.currentSize = (w,h)
        self.needBitmap = True
        self.parent.controls.drawWaveform()
        wx.CallAfter(self.Refresh)

    def restoreFxBall(self, dict):
        self.fxballs[dict["id"]] = FxBall(dict["fx"], dict["id"], self.parent.sg_audio, dict["pos"], dict["size"], dict["gradient"], dict["fader"])
        self.parent.sg_audio.addFx(dict["fx"], dict["id"])
        self.fxballs[dict["id"]].load(dict["controls"])
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.needBitmap = True
        self.Refresh()

    def restoreFxBalls(self, dict, xfac=1.0, yfac=1.0):
        if dict != {}:
            for dic in dict.values():
                self.fxballs[dic["id"]] = FxBall(dic["fx"], dic["id"], self.parent.sg_audio, dic["pos"], 
                                            dic["size"], dic["gradient"], dic["fader"], xfac, yfac)
                self.parent.sg_audio.addFx(dic["fx"], dic["id"])
                self.fxballs[dic["id"]].load(dic["controls"])
            self.fxballValues = [fx for fx in self.fxballs.values()]
            self.needBitmap = True
            self.Refresh()

    def addFxBall(self, fx):
        key = -1
        fxkeys = self.fxballs.keys()
        for i in range(10):
            if i not in fxkeys:
                key = i
                break
        if key != -1:
            self.fxballs[key] = FxBall(fx, key, self.parent.sg_audio, (100,100))
            self.parent.sg_audio.addFx(fx, key)
            self.fxballValues = [fx for fx in self.fxballs.values()]
            self.needBitmap = True
            self.Refresh()

    def removeAllFxBalls(self):
        for key in list(self.fxballs.keys()):
            self.fxballs[key].hideControls()
            del self.fxballs[key]
            self.parent.sg_audio.removeFx(key)
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.needBitmap = True
        self.Refresh()

    def removeFxBall(self, key):
        self.fxballs[key].hideControls()
        del self.fxballs[key]
        self.parent.sg_audio.removeFx(key)
        self.fxballValues = [fx for fx in self.fxballs.values()]
        self.needBitmap = True
        self.Refresh()

    def clock(self, which):
        t = self.trajectories[which]
        t.clock()
        if t.getActive():
            w,h = self.GetSize()
            w,h = float(w), float(h)
            if t.getPointPos() != None:
                x = t.getPointPos()[0]/w
                y = 1 - t.getPointPos()[1]/h
                self.parent.sg_audio.setXposition(which, x)
                self.parent.sg_audio.setYposition(which, y)

    def setMidiTranspose(self, value):
        self.midiTranspose = value

    def setMidiXposition(self, value):
        self.midiXposition = value

    def setMidiOctaveSpread(self, value):
        self.midiOctaveSpread = value

    def setOscilPeriod(self, period):
        self.oscilPeriod = period

    def getOscilPeriod(self):
        return self.oscilPeriod

    def setOscilScaling(self, scaling):
        self.oscilScaling = scaling

    def getOscilScaling(self):
        return self.oscilScaling

    def SetColors(self, outline, bg, fill, rect, losa, wave):
        self.outlinecolor = wx.Colour(*outline)
        self.backgroundcolor = wx.Colour(*bg)
        self.fillcolor = wx.Colour(*fill)
        self.rectcolor = wx.Colour(*rect)
        self.losacolor = wx.Colour(*losa)
        self.wavecolor = wx.Colour(*wave)
        self.losaBrush = wx.Brush(self.losacolor, wx.SOLID)
        self.losaPen = wx.Pen(self.losacolor, width=1, style=wx.SOLID)

    def getValues(self):
        w,h = self.GetSize()
        w,h = float(w), float(h)
        vals = []
        for t in self.trajectories:
            if t.getPointPos() != None:
                x = t.getPointPos()[0]/w
                y = 1 - t.getPointPos()[1]/h
                vals.append([x,y])
            else:
                vals.append([])
        return vals

    def setMode(self, mode):
        self.mode = TRAJTYPES[mode]

    def setClosed(self, closed):
        self.closed = closed

    def getTrajectory(self, which):
        return self.trajectories[which]

    def getAllTrajectories(self):
        return self.trajectories

    def getActiveTrajectories(self):
        return [t for t in self.trajectories if t.getActive()]

    def OnRightDown(self, evt):
        self.SetFocus()
        for t in self.getActiveTrajectories():
            if t.getInsideRect(evt.GetPosition()):
                t.clear()
                if len(self.getActiveTrajectories()) > 0:
                    self.setSelected(self.getActiveTrajectories()[0])
                else:
                    self.setSelected(self.getTrajectory(0))
                self.needBitmap = True
                self.Refresh()
                return
        mouseState = wx.GetMouseState()
        mousePos = (mouseState.GetX(), mouseState.GetY())
        for fxball in self.fxballs.values():
            if fxball.getInside(evt.GetPosition(), small=True):
                fxball.openControls(mousePos)
                return

    def setSelectedById(self, id):
        self.selected = self.trajectories[id]

    def setSelected(self, traj):
        self.selected = traj
        self.parent.controls.setSelected(self.selected.getId())

    def Memorize(self):
        w,h = self.GetSize()
        t = self.selected
        self.memorizedTrajectory.setType(t.getType())
        self.memorizedTrajectory.setTimeSpeed(t.getTimeSpeed())
        self.memorizedTrajectory.setStep(t.getStep())
        self.memorizedTrajectory.activateLp(self.parent.lowpass)
        self.memorizedTrajectory.setEditionLevel(self.parent.editionLevel)
        self.memorizedTrajectory.setPoints(t.getPoints())
        self.memorizedTrajectory.setInitPoints()
        if self.memorizedTrajectory.getType() not in  ['free', 'line']:
            self.memorizedTrajectory.setRadius(t.getRadius())
            self.memorizedTrajectory.setCenter(t.getCenter())
        if self.midiXposition:
            off = (w/2) - self.memorizedTrajectory.getFirstPoint()[0]
            self.memorizedTrajectory.move((off, 0))
            self.memorizedTrajectory.setInitPoints()

    def addTrajFromMemory(self, index, pitch, normy, midinote):
        t = self.memorizedTrajectory
        for new_t in self.trajectories:
            if not new_t.getActive():
                self.memorizedId[index] = new_t.getId()
                new_t.setTimeSpeed(t.getTimeSpeed())
                if self.midiTranspose:
                    new_t.setTranspo(pitch)
                else:
                    new_t.setTranspo(1.0)
                new_t.setStep(t.getStep())
                new_t.setActive(True)
                new_t.setType(self.mode)
                new_t.lpx.reinit()
                new_t.lpy.reinit()
                new_t.activateLp(self.parent.lowpass)
                new_t.setEditionLevel(self.parent.editionLevel)
                new_t.setPoints(t.getPoints())
                new_t.setInitPoints()
                if new_t.getType() == 'free':
                    pass
                else:
                    new_t.setCenter(t.getCenter())
                    new_t.setRadius(t.getRadius())
                break
        Xs = [p[0] for p in new_t.getPoints()]
        extremeXs = (min(Xs), max(Xs))
        Ys = [p[1] for p in new_t.getPoints()]
        extremeYs = (min(Ys), max(Ys))
        if new_t.getType() not in  ['free', 'line']:
            curCenter = new_t.getCenter()
        downPos = new_t.getFirstPoint()
        w,h = self.GetSize()
        if not self.midiXposition:
            x, y = downPos[0], int((1.-normy)*h)
        else:
            if pitch <= 1:
                normx = int((w/2) - (w * (60 - midinote) / 12. / self.midiOctaveSpread))
            else:
                normx = int((w/2) + (w * (midinote - 60) / 12. / self.midiOctaveSpread))
            x,y = normx, int((1.-normy)*h)
        if new_t.getType() in ['free', 'line']:
            offset = (downPos[0] - x, downPos[1] - y)
            clipedOffset = self.clip(offset, extremeXs, extremeYs)
            new_t.move(clipedOffset)
        else:
            offset = (downPos[0] - x, downPos[1] - y)
            center, clipedOffset = self.clipCircleMove(new_t.getRadius(), curCenter, offset)
            new_t.setCenter(center)
            new_t.move(clipedOffset)
        self.needBitmap = True
        self.Refresh()

    def deleteMemorizedTraj(self, index):
        id = self.memorizedId[index]
        t = self.trajectories[id]
        t.clear()
        if len(self.getActiveTrajectories()) > 0:
            self.setSelected(self.getActiveTrajectories()[0])
        else:
            self.setSelected(self.getTrajectory(0))
        self.needBitmap = True
        self.Refresh()

    def KeyDown(self, evt):
        if evt.GetKeyCode() in [wx.WXK_BACK, wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE]:
            if self.selected != None:
                self.selected.clear()
                if len(self.getActiveTrajectories()) > 0:
                    self.setSelected(self.getActiveTrajectories()[0])
                else:
                    self.setSelected(self.getTrajectory(0))
            evt.StopPropagation()
            return

        level = self.parent.arrowSpeedLevel
        off = {wx.WXK_UP: [0,level], wx.WXK_DOWN: [0,-level], wx.WXK_LEFT: [level,0], wx.WXK_RIGHT: [-level,0]}.get(evt.GetKeyCode(), [0,0])
        # Move selected trajectory
        if evt.ShiftDown() and off != [0,0]:
            traj = self.trajectories[self.parent.controls.getSelected()]
            if traj.getType() in ['circle', 'oscil']:
                center = traj.getCenter()
                traj.setCenter((center[0]-off[0], center[1]-off[1]))
            traj.move(off)
            traj.setInitPoints()
            self.onMotion = True
            evt.StopPropagation()
            return
        # Move all trajectories
        elif off != [0,0]:
            for traj in self.getActiveTrajectories():
                if traj.getType() in ['circle', 'oscil']:
                    center = traj.getCenter()
                    traj.setCenter((center[0]-off[0], center[1]-off[1]))
                traj.move(off)
                traj.setInitPoints()
            self.onMotion = True
            evt.StopPropagation()
            return
        # Set freeze mode
        if evt.GetKeyCode() < 256:
            c = chr(evt.GetKeyCode())
            if c in ['1', '2', '3', '4', '5', '6', '7', '8']:
                if self.trajectories[int(c)-1].getFreeze():
                    self.trajectories[int(c)-1].setFreeze(False)
                else:
                    self.trajectories[int(c)-1].setFreeze(True)
            elif c == '0':
                for i in range(8):
                    if self.trajectories[i].getFreeze():
                        self.trajectories[i].setFreeze(False)
                    else:
                        self.trajectories[i].setFreeze(True)
            elif c == '9':
                if not self.useMario:
                    self.useMario = True
                else:
                    self.useMario = False
        evt.Skip()

    def KeyUp(self, evt):
        self.onMotion = False
        if evt.GetKeyCode() in [wx.WXK_BACK, wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE, wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT]:
            self.needBitmap = True
            self.Refresh()

    def MouseDoubleClick(self, evt):
        self.SetFocus()
        self.downPos = evt.GetPosition()
        for t in self.getActiveTrajectories():
            # Select or duplicate trajectory
            if t.getInsideRect(self.downPos):
                for new_t in self.trajectories:
                    if not new_t.getActive():
                        self.setSelected(new_t)
                        self.selected.setActive(True)
                        self.selected.setType(t.getType())
                        self.selected.lpx.reinit()
                        self.selected.lpy.reinit()
                        self.selected.activateLp(self.parent.lowpass)
                        self.selected.setEditionLevel(self.parent.editionLevel)
                        self.selected.setPoints(t.getPoints())
                        self.selected.setInitPoints()
                        if self.selected.getType() not in  ['free', 'line']:
                            self.selected.setRadius(t.getRadius())
                            self.selected.setCenter(t.getCenter())
                        break
                else:
                    self.setSelected(t)
                Xs = [p[0] for p in self.selected.getPoints()]
                self.extremeXs = (min(Xs), max(Xs))
                Ys = [p[1] for p in self.selected.getPoints()]
                self.extremeYs = (min(Ys), max(Ys))
                self.action = 'drag'
                if self.selected.getType() not in  ['free', 'line']:
                    self.curCenter = self.selected.getCenter()
                self.CaptureMouse()
                return

        for key, fxball in self.fxballs.items():
            if fxball.getInside(self.downPos, small=True):
                self.removeFxBall(key)
                break

        evt.Skip()

    def MouseDown(self, evt):
        self.SetFocus()
        self.downPos = evt.GetPosition()
        for t in self.getActiveTrajectories():
            # Select or duplicate trajectory
            if t.getInsideRect(self.downPos):
                if evt.AltDown():
                    for new_t in self.trajectories:
                        if not new_t.getActive():
                            self.setSelected(new_t)
                            self.selected.setActive(True)
                            self.selected.setType(t.getType())
                            self.selected.lpx.reinit()
                            self.selected.lpy.reinit()
                            self.selected.activateLp(self.parent.lowpass)
                            self.selected.setEditionLevel(self.parent.editionLevel)
                            self.selected.setPoints(t.getPoints())
                            self.selected.setInitPoints()
                            if self.selected.getType() not in  ['free', 'line']:
                                self.selected.setRadius(t.getRadius())
                                self.selected.setCenter(t.getCenter())
                            break
                else:
                    self.setSelected(t)
                Xs = [p[0] for p in self.selected.getPoints()]
                self.extremeXs = (min(Xs), max(Xs))
                Ys = [p[1] for p in self.selected.getPoints()]
                self.extremeYs = (min(Ys), max(Ys))
                self.curCenters = [traj.getCenter() for traj in self.getActiveTrajectories()]
                self.action = 'drag'
                if self.selected.getType() not in  ['free', 'line']:
                    self.curCenter = self.selected.getCenter()
                self.CaptureMouse()
                return
            # Rescale circle or oscil trajectory
            if t.getInsideLosange(self.downPos):
                self.setSelected(t)
                self.action = 'rescale'
                self.CaptureMouse()
                return
            # Check for trajectory transformation
            for p in t.getPoints():
                if wx.Rect(p[0]-5, p[1]-5, 10, 10).Contains(self.downPos):
                    self.pindex = t.getPoints().index(p)
                    self.setSelected(t)
                    self.action = 'edit'
                    self.CaptureMouse()
                    return
        # Check if inside an FxBall
        for key, fxball in self.fxballs.items():
            if fxball.getInside(self.downPos, small=True):
                if evt.AltDown():
                    self.removeFxBall(key)
                else:
                    self.fxball = fxball
                    self.action = 'drag_ball'
                    self.CaptureMouse()
                return
            elif fxball.getInside(self.downPos, small=False):
                if evt.AltDown():
                    self.removeFxBall(key)
                    self.Refresh()
                else:
                    self.fxball = fxball
                    self.action = 'rescale_ball'
                    self.CaptureMouse()
                return

        # Click in an empty space, draw a new trajectory
        self.action = 'draw'
        for t in self.trajectories:
            if not t.getActive():
                self.traj = t
                self.traj.setActive(True)
                self.traj.setType(self.mode)
                self.traj.lpx.reinit()
                self.traj.lpy.reinit()
                self.traj.activateLp(self.parent.lowpass)
                self.traj.setEditionLevel(self.parent.editionLevel)
                if self.traj.getType() == 'free':
                    self.traj.addPoint(self.clipPos(self.downPos))
                elif self.traj.getType() in ['circle', 'oscil']:
                    self.traj.setCenter(self.downPos)
                    self.traj.setRadius(0)
                self.CaptureMouse()
                self.Refresh()
                break
            else:
                self.traj = None
        evt.Skip()

    def MouseUp(self, evt):
        if self.HasCapture():
            if self.action == 'draw' and self.traj:
                if len(self.traj.getPoints()) <= 1:
                    self.traj.clear()
                    self.ReleaseMouse()
                    return
                if self.traj.getType() == 'free':
                    self.traj.addFinalPoint(self.clipPos(evt.GetPosition()), self.closed)
                    if self.parent.fillPoints:
                        self.traj.fillPoints(self.closed)
                    self.traj.setInitPoints()
                elif self.traj.getType() in ['circle', 'oscil']:
                    if self.parent.fillPoints:
                        self.traj.fillPoints(False)
                    self.traj.setInitPoints()
                else:
                    if self.parent.fillPoints:
                        self.traj.fillPoints(False)
                    self.traj.setInitPoints()
            elif self.action == 'drag':
                self.selected.setInitPoints()
            elif self.action == 'rescale':
                if self.selected.getType() == 'circle':
                    if self.parent.fillPoints:
                        self.selected.fillPoints(True)
                else:
                    if self.parent.fillPoints:
                        self.selected.fillPoints(False)
                self.selected.setInitPoints()
            elif self.action == 'edit':
                if self.parent.fillPoints:
                    self.selected.fillPoints(False)
                self.selected.setInitPoints()
                self.selected.setType('free')
            elif self.action in ['drag_ball', 'rescale_ball']:
                self.fxball.restoreGradient()
                self.fxball.restoreCenter()

            self.Refresh()
            self.ReleaseMouse()
            if self.action not in ['drag_ball', 'rescale_ball']:
                self.parent.createTempFile()
            self.onMotion = False
            self.needBitmap = True
        evt.Skip()

    def MouseMotion(self, evt):
        self.pointerPos = evt.GetPosition()
        if self.HasCapture() and evt.Dragging() and evt.LeftIsDown():
            if self.action == 'draw' and self.traj:
                if self.traj.getType() == 'free':
                    self.traj.addPoint(self.clipPos(evt.GetPosition()))
                elif self.traj.getType() == 'line':
                    self.traj.points = []
                    self.traj.lpx.reinit()
                    self.traj.lpy.reinit()
                    x,y = self.clipPos(evt.GetPosition())

                    x2 = abs(x-self.downPos[0])
                    y2 = abs(y-self.downPos[1])
                    maxstep = int(math.sqrt(x2*x2+y2*y2))

                    if self.downPos[0] == x: xdir = 0
                    elif self.downPos[0] < x: xdir = 1
                    else: xdir = -1
                    if self.downPos[1] == y: ydir = 0
                    elif self.downPos[1] < y: ydir = 1
                    else: ydir = -1

                    for i in range(0, maxstep, 2):
                        xpt = self.downPos[0] + xdir * int(x2 * i / float(maxstep))
                        ypt = self.downPos[1] + ydir * int(y2 * i / float(maxstep))
                        self.traj.addPoint((int(round(xpt)),int(round(ypt))))
                else:
                    Xlen = abs(self.downPos[0] - evt.GetPosition()[0])
                    Ylen = abs(self.downPos[1] - evt.GetPosition()[1])
                    self.traj.setRadius(self.clipCirclePos(math.sqrt( Xlen**2 + Ylen**2 ), self.traj.getCenter(), self.traj.getRadius()))
                    r = self.traj.getRadius()
                    halfR = int(round(r/2.))
                    if halfR <= 1: scaleR = 1
                    else: scaleR = 1./(halfR-1)
                    self.traj.points = []
                    self.traj.lpx.reinit()
                    self.traj.lpy.reinit()
                    if self.traj.getType() == 'circle':
                        for i in range(-halfR,halfR+1):
                            a = i * scaleR * r
                            x = math.cos(math.pi * i * scaleR) * r
                            y = math.sin(math.pi * i * scaleR) * r
                            self.traj.addCirclePoint((int(round(x + self.downPos[0])), int(round(y + self.downPos[1]))))
                    else:
                        for i in range(int(-halfR * self.oscilScaling), int(halfR * self.oscilScaling + 1)):
                            a = i * scaleR * r
                            x = math.cos(math.pi * i * scaleR) * r
                            y = math.sin(math.pi * self.oscilPeriod * i * scaleR) * r
                            self.traj.addCirclePoint((int(round(x + self.downPos[0])), int(round(y + self.downPos[1]))))

            elif self.action == 'drag':
                if self.selected.getType() in ['free', 'line']:
                    x,y = evt.GetPosition()
                    offset = (self.downPos[0] - x, self.downPos[1] - y)
                    clipedOffset = self.clip(offset, self.extremeXs, self.extremeYs)
                    self.selected.move(clipedOffset)
                else:
                    x,y = self.clipPos(evt.GetPosition())
                    offset = (self.downPos[0] - x, self.downPos[1] - y)
                    center, clipedOffset = self.clipCircleMove(self.selected.getRadius(), self.curCenter, offset)
                    self.selected.setCenter(center)
                    self.selected.move(clipedOffset)
                if evt.ShiftDown():
                    for traj in self.getActiveTrajectories():
                        if traj != self.selected:
                            if traj.getType() in ['free', 'line']:
                                clipedOffset = self.clip(offset, self.extremeXs, self.extremeYs)
                                traj.move(clipedOffset)
                            else:
                                center, clipedOffset = self.clipCircleMove(traj.getRadius(), self.curCenters[traj.getId()], offset)
                                traj.setCenter(center)
                                traj.move(clipedOffset)

            elif self.action == 'rescale':
                Xlen = abs(self.selected.getCenter()[0] - evt.GetPosition()[0])
                Ylen = abs(self.selected.getCenter()[1] - evt.GetPosition()[1])
                self.selected.setRadius(self.clipCirclePos(math.sqrt( Xlen**2 + Ylen**2 ), self.selected.getCenter(), self.selected.getRadius()))
                r = self.selected.getRadius()
                halfR = int(round(r/2.))
                if halfR <= 1: scaleR = 1
                else: scaleR = 1./(halfR-1)
                self.selected.points = []
                self.selected.lpx.reinit()
                self.selected.lpy.reinit()
                if self.selected.getType() == 'circle':
                    for i in range(-halfR,halfR+1):
                        a = i * scaleR * r
                        x = math.cos(math.pi * i * scaleR) * r
                        y = math.sin(math.pi * i * scaleR) * r
                        self.selected.addCirclePoint((int(round(x + self.selected.getCenter()[0])), int(round(y + self.selected.getCenter()[1]))))
                else:
                    for i in range(int(-halfR * self.oscilScaling), int(halfR * self.oscilScaling + 1)):
                        a = i * scaleR * r
                        x = math.cos(math.pi * i * scaleR) * r
                        y = math.sin(math.pi * self.oscilPeriod * i * scaleR) * r
                        self.selected.addCirclePoint((int(round(x + self.selected.getCenter()[0])), int(round(y + self.selected.getCenter()[1]))))
            elif self.action == 'edit':
                x,y = evt.GetPosition()
                offset = (self.downPos[0] - x, self.downPos[1] - y)
                self.selected.editTraj(self.pindex, offset)
            elif self.action == 'drag_ball':
                pos = evt.GetPosition()
                if evt.ShiftDown():
                    off = (self.downPos[1] - pos[1])
                    self.fxball.setGradient(off)
                else:
                    self.fxball.move(pos)
            elif self.action == 'rescale_ball':
                pos = evt.GetPosition()
                x = self.fxball.center[0] - pos[0]
                y = self.fxball.center[1] - pos[1]
                hyp = math.sqrt(x*x+y*y)
                if hyp < 5: hyp = 5
                self.fxball.resize(hyp*2)

            self.onMotion = True
            self.Refresh()
        evt.Skip()

    def draw(self, dc):
        gc = wx.GraphicsContext_Create(dc)
        dc.SetTextForeground("#000000")
        dc.SetFont(self.font)
        if not self.sndBitmap:
            w,h = self.GetSize()
            dc.SetBrush(wx.Brush(self.backgroundcolor, wx.SOLID))
            dc.Clear()
            dc.SetPen(wx.Pen(self.outlinecolor, width=1, style=wx.SOLID))
            dc.DrawRectangle(0, 0, w, h)
        else:
            dc.DrawBitmap(self.sndBitmap,0,0)

        [dc.DrawBitmap(fx.bit, fx.pos[0], fx.pos[1], True) for fx in self.fxballValues]

        selectedTraj = self.parent.controls.getSelected()
        activeTrajs = [t for t in self.getActiveTrajectories() if len(t.getPoints()) > 1]
        for t in activeTrajs:
            recsize = 14
            s2 = recsize / 2
            gc.SetBrush(t.getBrush(trans=True))
            gc.SetPen(t.getPen(big=True))
            if len(t.getPoints()) >= 2:
                gc.DrawLines(t.getPoints())
            if t.getId() == selectedTraj:
                recsize = 14
                s2 = recsize / 2
                self.selected = t
                gc.SetPen(wx.Pen("#EEEEEE", width=2, style=wx.SOLID))
            if t.getFirstPoint() != None:
                # With midi triggering, it's possible to delete a trajectory in the
                # middle of this block. That raises an error: NoneType (t.circlePos)
                # object is not subscriptable.
                try:
                    gc.SetBrush(t.getBrush())
                    gc.DrawRoundedRectangle(t.getFirstPoint()[0]-s2, t.getFirstPoint()[1]-s2, recsize, recsize, 2)
                    dc.DrawLabel(str(t.getLabel()), wx.Rect(t.getFirstPoint()[0]-s2,t.getFirstPoint()[1]-s2, recsize, recsize), wx.ALIGN_CENTER)
                    if t.getType() in ['circle', 'oscil']:
                        gc.SetBrush(self.losaBrush)
                        gc.SetPen(self.losaPen)
                        gc.DrawRoundedRectangle(t.getLosangePoint()[0]-5, t.getLosangePoint()[1]-5, 10, 10, 2)
                except:
                    pass

    def drawBackBitmap(self):
        w,h = self.currentSize
        if self.backBitmap == None or self.backBitmap.GetSize() != self.currentSize:
            self.backBitmap = wx.EmptyBitmap(w,h)
        dc = wx.MemoryDC(self.backBitmap)
        self.draw(dc)
        dc.SelectObject(wx.NullBitmap)
        self.needBitmap = False

    def OnPaint(self, evt):
        dc = self.dcref(self)
        gc = wx.GraphicsContext_Create(dc)

        if self.onMotion or self.needBitmap:
            self.drawBackBitmap()
        dc.DrawBitmap(self.backBitmap,0,0)

        activeTrajs = [t for t in self.getActiveTrajectories() if len(t.getPoints()) > 1 and t.circlePos]
        self.parent.sg_audio.setMixerChannelAmps(activeTrajs, self.fxballValues)

        if not self.useMario:
            for t in activeTrajs:
                if t.circlePos != None:
                    # With midi triggering, it's possible to delete a trajectory in the
                    # middle of this block. That raises an error: NoneType (t.circlePos)
                    # object is not subscriptable.
                    try:
                        gc.SetPen(t.getPen())
                        gc.SetBrush(t.getBrush())
                        gc.DrawEllipse(t.circlePos[0]-5, t.circlePos[1]-5, 10, 10)
                        gc.SetPen(t.getBorderPen())
                        gc.SetBrush(t.getBorderBrush())
                        gc.DrawEllipse(t.circlePos[0]-2, t.circlePos[1]-2, 4, 4)
                    except:
                        pass
        else:
            for t in activeTrajs:
                if t.lastCirclePos[0] < t.circlePos[0]: marioff = 0
                else: marioff = 4
                bitmario = self.marios[t.mario + marioff]
                dc.DrawBitmap(bitmario, t.circlePos[0]-8, t.circlePos[1]-8, True)

        if self.pointerPos != None:
            w,h = self.GetSize()
            dc.SetTextForeground("#FFFFFF")
            dc.SetFont(self.font_pos)
            xvalue = self.pointerPos[0] / float(w) * self.parent.controls.sndDur
            yvalue = (h - self.pointerPos[1]) / float(h)
            dc.DrawText("X: %.3f  Y: %.3f" % (xvalue, yvalue), w-110, h-13)

    def clip(self, off, exXs, exYs):
        Xs = [p[0] for p in self.selected.getPoints()]
        minX, maxX = min(Xs), max(Xs)
        Ys = [p[1] for p in self.selected.getPoints()]
        minY, maxY = min(Ys), max(Ys)
        x,y = off
        sizex, sizey = self.GetSize()
        offset = self.screenOffset
        if exXs[0] - off[0] >= offset and exXs[1] - off[0] <= sizex - offset:
            x = x
        elif exXs[1] - off[0] >= sizex - offset:
            x = exXs[1] - sizex + offset
        else:
            x = exXs[0] - offset - 1
        if exYs[0] - off[1] >= offset and exYs[1] - off[1] <= sizey - offset:
            y = y
        elif exYs[1] - off[1] >= sizey - offset:
            y = exYs[1] - sizey + offset
        else:
            y = exYs[0] - offset - 1
        return (x,y)

    def clipPos(self, pos):
        x,y = pos
        sizex, sizey = self.GetSize()
        offset = self.screenOffset
        if x < offset: x = offset
        elif x > (sizex-offset): x = sizex - offset
        else: x = x
        if y < offset: y = offset
        elif y > (sizey-offset): y = sizey - offset
        else: y = y
        return (x,y)

    def clipCirclePos(self, rad, center, lastRad):
        sizex, sizey = self.GetSize()
        offset = self.screenOffset
        flag = True
        radius1 = radius2 = radius3 = radius4 = 1000000
        if center[0] - rad <= 0 + offset:
            radius1 = center[0] - offset
            flag = False
        if center[1] - rad <= 0 + offset:
            radius2 = center[1] - offset
            flag = False
        if center[0] + rad >= sizex - offset:
            radius3 = sizex - offset - center[0]
            flag = False
        if center[1] + rad >= sizey - offset:
            radius4 = sizey - offset - center[1]
            flag = False
        if flag:
            return rad
        else:
            return min(radius1, radius2, radius3, radius4)

    def clipCircleMove(self, rad, center, offset):
        sizex, sizey = self.GetSize()
        off = self.screenOffset
        if center[0] - offset[0] - rad >= 0 + off and center[0] - offset[0] + rad <= sizex - off:
            cx = center[0] - offset[0]
            offx = offset[0]
        elif center[0] - offset[0] + rad >= sizex - off:
            cx = sizex - off - rad
            offx = center[0] - cx
        else:
            cx = 0 + off + rad
            offx = center[0] - cx
        if center[1] - offset[1] - rad >= 0 + off and center[1] - offset[1] + rad <= sizey - off:
            cy = center[1] - offset[1]
            offy = offset[1]
        elif center[1] - offset[1] + rad >= sizey - off:
            cy = sizey - off - rad
            offy = center[1] - cy
        else:
            cy = 0 + off + rad
            offy = center[1] - cy
        return [cx, cy], [offx, offy]

    def analyse(self, file):
        self.file = file
        self.list = self.parent.sg_audio.getViewTable(self.GetSize())
        self.bitmapDict[self.file] = self.list
        self.create_bitmap()

    def create_bitmap(self):
        size = tuple(self.GetSize())
        self.sndBitmap = wx.EmptyBitmap(size[0], size[1])
        memory = wx.MemoryDC()
        memory.SelectObject(self.sndBitmap)
        gc = wx.GraphicsContext_Create(memory)
        gc.SetPen(wx.Pen("#3F3F44"))
        gc.SetBrush(wx.Brush("#3F3F44", style=wx.TRANSPARENT))
        memory.SetBrush(wx.Brush(self.backgroundcolor))
        memory.DrawRectangle(0,0,size[0],size[1])
        for samples in self.list:
            if len(samples):
                gc.DrawLines(samples)
        memory.SelectObject(wx.NullBitmap)
        self.needBitmap = True
        self.Refresh()