
#   Copyright (C) 2002-2003 Yannick Gingras <ygingras@ygingras.net>
#   Copyright (C) 2002-2003 Vincent Barbin <vbarbin@openbeatbox.org>

#   This file is part of Open Beat Box.

#   Open Beat Box is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.

#   Open Beat Box is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with Open Beat Box; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

from qt import *
from SimpleApp import SimpleApp

from OBBGui.Splash       import Splash
from OBBGui.OBBSkin      import OBBSkin
from OBBGui.PatEditorGui import PatEditorGui

from OBBUtils.OBBTimer   import OBBTimer

from OBBSound.SoundDevice    import SoundDevice
from OBBSound.OBBSongCreator import OBBSongCreator

from OBBFuncts   import *
from OBBDebugger import *

import OBBUtils.OBBSignals as sigs

import config

MAX_ALT_GUI    =   0
SCROLL_TIMEOUT =  80

class PatEditor(SimpleApp):
    def __init__( self, demoDelay = 0, Verbose = 0):
        SimpleApp.__init__(self)
        self.demoDelay = demoDelay
        self._lambdas = []
        self._altGuis = []
        self.debugger = OBBDebugger(Verbose)


    def exec_loop(self):
        self.app = QApplication([])
        # kick the double click
        self.app.setDoubleClickInterval(0)
        
        self.quitTimer = QTimer(self)

        if self.demoDelay: # auto-kick gui (probably in a unittest)
            self.quitTimer.singleShot( self.demoDelay * 1000,
                                       self.quit )

        # The GUI is a bit slow to load and the term is too ugly and 
        # too rectangular to be enjoyable... 
        #                                            -- YGingras
        self.splash = Splash(os.path.join(getImgDir(), "splash.png"),
                             config.SPLASH_DELAY)
        self.splash.show()

        self.initSound()
        self.initGui()
        self.creator.newSongDocument()
        self.showGui()
        self.app.exec_loop()
        

    def play(self):
        self.stop()
        self.hitTimer.changeBpm(self.creator.getTempo())
        self.hitTimer.start()


    def stop(self):
        self.hitTimer.stop()
        self.emit(sigs.stop, ())


    def quit(self):
        self.stop()
        self.app.closeAllWindows()
        self.creator.cleanUpTemporaryFiles()


    def initGui(self):
        skin = OBBSkin()
        skin.load(os.path.join(getSkinDir(), config.DEF_SKIN))
        self.gui = PatEditorGui(skin)
        self.connectGuiSignals(self.gui)

        # it's perfect when 2 (or more) guis can work in synch
        for i in range(MAX_ALT_GUI):
            altGui = PatEditorGui(skin)
            altGui.show()
            self.connectGuiSignals(altGui)
            self._altGuis.append(altGui)
            
        qApp.setMainWidget(self.gui.beMainWidget())
        self.scrollTimer = QTimer(self)
        self.connect(self.scrollTimer, SIGNAL("timeout()"), self.scroll)
        self.scrollTimer.start(SCROLL_TIMEOUT)
        

    def showGui(self):
        self.splash.raiseW()
        self.gui.show()
        map(lambda gui:gui.show(), self._altGuis)
        qApp.processEvents()


    def initSound(self):
        self.hitTimer = OBBTimer(config.DEF_BPM)
        self.creator  = OBBSongCreator()
        self.sndDev   = SoundDevice()
        self.connectSndSignals()


    def connectSndSignals(self):
        self.connect(self.creator, sigs.tempoChanged, self.hitTimer.changeBpm)
        self.connect(self.hitTimer, sigs.hitPlayed, self.sndDev.handleHit)
        self.connect(self.hitTimer, sigs.hitPlayed, self.creator.handleHit)
        self.connect(self.creator,
                     sigs.sampleCreated,
                     self.sndDev.handleLoadSample)


    def connectGuiSignals(self, gui):
        self.connect(gui, sigs.newTempo, self.creator.setTempo)
        self.connect(self.creator, sigs.tempoChanged, gui.setTempo)

        self.connect(gui, sigs.newPatVolume, self.sndDev.setVolume)
        self.connect(self.sndDev, sigs.volumeChanged, gui.setPatVolume)

        self.connect(gui, sigs.previewInstr, self.previewInstr)

        self.connect(gui, sigs.newInstrBal, self.creator.setPanning)
        self.connect(self.creator, sigs.instrBalChanged, gui.setInstrBalance)

        self.connect(gui, sigs.newInstrFile, self.creator.setInstrument)
        self.connect(self.creator, sigs.instrFileChanged, gui.setInstrFilename)
        self.connect(self.creator, sigs.patFileChanged, gui.setPatFile)

        self.connect(self, sigs.scroll, gui.scroll)

        self.connect(gui,  sigs.play, self.play)
        self.connect(gui,  sigs.stop, self.stop)
        self.connect(self, sigs.stop, gui.resetHitProgress)
        self.connect(gui,  sigs.quit, self.quit)
        
        self.connect(self.creator, sigs.clearHits, gui.clearHits)
        
        self.connect(gui, sigs.newFile, self.newFile)
        self.connect(gui, sigs.loadPattern, self.creator.loadFile)

        self.connect(gui, sigs.hitToggled, self.creator.toggleHit)
        self.connect(self.creator, sigs.hitToggled, gui.toggleHit)
        self.connect(self.hitTimer, sigs.hitPlayed, gui.showHitPos)
        
        self.connect(gui, sigs.savePattern, self.savePattern)
   

    def previewInstr(self, instrId):
        self.sndDev.play(self.creator.getInstrument(instrId))


    def scroll(self):
        self.emit(sigs.scroll, ())


    def newFile(self):
        self.creator.newSongDocument()


    def savePattern(self, filename):
        self.creator.setFileName(filename, 1)
        self.creator.save()

