diff options
author | Nat <natcl@hotmail.com> | 2007-09-13 15:55:52 (GMT) |
---|---|---|
committer | Nat <natcl@hotmail.com> | 2007-09-13 15:55:52 (GMT) |
commit | e12dbff4dda5aafbaac98f75f0467ef00dc06c32 (patch) | |
tree | 52f74f5a699ca1a2827b333e76a7225b7d768256 /TamTamEdit.activity/Edit/rm | |
parent | b94ccdfd2329ed2d1128a4392e2f67b1e6b704da (diff) |
Activity split
Diffstat (limited to 'TamTamEdit.activity/Edit/rm')
-rw-r--r-- | TamTamEdit.activity/Edit/rm/BackgroundView.py | 501 | ||||
-rw-r--r-- | TamTamEdit.activity/Edit/rm/NoteView.py | 253 | ||||
-rw-r--r-- | TamTamEdit.activity/Edit/rm/PageBankView.py | 85 | ||||
-rw-r--r-- | TamTamEdit.activity/Edit/rm/PageView.py | 65 | ||||
-rw-r--r-- | TamTamEdit.activity/Edit/rm/PositionIndicator.py | 47 | ||||
-rw-r--r-- | TamTamEdit.activity/Edit/rm/TrackView.py | 263 | ||||
-rw-r--r-- | TamTamEdit.activity/Edit/rm/TunePageView.py | 17 | ||||
-rw-r--r-- | TamTamEdit.activity/Edit/rm/TuneView.py | 123 |
8 files changed, 1354 insertions, 0 deletions
diff --git a/TamTamEdit.activity/Edit/rm/BackgroundView.py b/TamTamEdit.activity/Edit/rm/BackgroundView.py new file mode 100644 index 0000000..ff6e75f --- /dev/null +++ b/TamTamEdit.activity/Edit/rm/BackgroundView.py @@ -0,0 +1,501 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +from math import floor + +from Framework.Constants import Constants +from GUI.GUIConstants import GUIConstants +from GUI.Core.NoteParametersWindow import NoteParametersWindow + +from Framework.Core.Profiler import TP + +class SELECTNOTES: + ALL = -1 + NONE = 0 + ADD = 1 + REMOVE = 2 + EXCLUSIVE = 3 + +#------------------------------------------------------------- +# This is a TEMPORARY implementaion of the BackgroundView, +# it was written quickly to get track selections working +#------------------------------------------------------------- + +# TODO: Do I really have to subclass gtk.EventBox to get the button-press-event? +# (I wasn't getting it subclassing directly from DrawingArea) +class BackgroundView( gtk.EventBox ): + #----------------------------------- + # initialization + #----------------------------------- + def __init__( self, trackIDs, selectedTrackIDs, selectionChangedCallback, mutedTrackIDs, beatsPerPageAdjustment, trackDictionary, selectedPageIDs, updatePageCallback ): + gtk.EventBox.__init__( self ) + + self.drawingArea = gtk.DrawingArea() + self.add( self.drawingArea ) + + self.sizeInitialized = False + + self.trackViews = {} + self.trackIDs = trackIDs + self.selectedTrackIDs = selectedTrackIDs + self.selectionChangedCallback = selectionChangedCallback + self.mutedTrackIDs = mutedTrackIDs + self.beatsPerPageAdjustment = beatsPerPageAdjustment + self.trackDictionary = trackDictionary + self.selectedPageIDs = selectedPageIDs + self.updatePageCallback = updatePageCallback + + self.curAction = False # stores the current mouse action + self.curActionObject = False # stores the object that in handling the action + + self.buttonPressCount = 1 # used on release events to indicate double/triple releases + self.clickLoc = [0,0] # location of the last click + self.marqueeLoc = False # current drag location of the marquee + + self.drawingArea.connect( "expose-event", self.draw ) + self.connect( "button-press-event", self.handleButtonPress ) + self.connect( "button-release-event", self.handleButtonRelease ) + self.connect( "motion-notify-event", self.handleMotion ) + + #----------------------------------- + # access methods + #----------------------------------- + def getTrackRect( self, trackID ): + return gtk.gdk.Rectangle( GUIConstants.BORDER_SIZE, + self.getTrackYLocation( trackID ), + self.getTrackWidth(), + self.getTrackHeight() ) + + def getTrackWidth( self ): + return self.get_allocation().width - 2 * ( GUIConstants.BORDER_SIZE + 2 ) + + def getFullHeight( self ): + return int( floor( self.get_allocation().height / len( self.trackIDs ) ) ) + + def getTrackHeight( self ): + return int( self.getFullHeight() - 2 * self.getTrackSpacing() ) + + #TODO-> trackIDs should probably be ordered! + # we're just using trackID as an index here (this will only work until you can remove tracks) + def getTrackYLocation( self, trackID ): + if self.getTrackHeight() < 0: + return 0 + else: + trackIndex = trackID + + trackHeight = int( floor( self.get_allocation().height / len( self.trackIDs ) ) ) + trackBackgroundYValue = trackHeight * trackIndex + return trackBackgroundYValue + GUIConstants.BORDER_SIZE + + def getTrackSpacing( self ): + return GUIConstants.TRACK_SPACING + + #----------------------------------- + # callback methods + #----------------------------------- + def set_size_request( self, width, height ): + self.sizeInitialized = True + self.drawingArea.set_size_request( width, height ) + self.height = height + self.width = width + + numTracks = len(self.trackIDs) + trackSpacing = self.getTrackSpacing() + if numTracks: self.trackHeight = int( floor( (height - trackSpacing*(numTracks-1)) / numTracks ) ) + else: self.trackHeight = 1 + self.trackWidth = width + + trackCount = 0 + for trackID in self.trackIDs: + self.trackViews[trackID].set_size_request( self.trackWidth, self.trackHeight ) + self.trackViews[trackID].setPositionOffset( (0, trackCount*(self.trackHeight+trackSpacing)) ) + trackCount += 1 + + def setCurrentTracks( self, trackViews ): + + oldLen = len(self.trackViews) + + if oldLen and trackViews != self.trackViews: self.clearSelectedNotes() # clear all the currently selected notes + + self.trackViews = trackViews + + numTracks = len(self.trackViews) + if oldLen != numTracks and self.sizeInitialized: + trackSpacing = self.getTrackSpacing() + if numTracks: self.trackHeight = int( floor( (self.height - trackSpacing*(numTracks-1)) / numTracks ) ) + else: self.trackHeight = 1 + trackCount = 0 + for trackID in self.trackIDs: + self.trackViews[trackID].set_size_request( self.trackWidth, self.trackHeight ) + self.trackViews[trackID].setPositionOffset( (0, trackCount*(self.trackHeight+trackSpacing)) ) + trackCount += 1 + + self.dirty() + + + def getNoteParameters( self ): + for trackID in self.selectedTrackIDs: + for pageID in self.selectedPageIDs: + for note in self.trackDictionary[ trackID ][ pageID ]: + newPitch = note.pitch + self.noteParameters.pitchAdjust.value + newAmplitude = note.amplitude * self.noteParameters.amplitudeAdjust.value + newPan = self.noteParameters.panAdjust.value + newReverbSend = note.reverbSend * self.noteParameters.reverbSendAdjust.value + newAttack = self.noteParameters.attackAdjust.value + newDecay = self.noteParameters.decayAdjust.value + newFilterType = self.noteParameters.filterType + newFilterCutoff = self.noteParameters.filterCutoff + newTied = self.noteParameters.tied + newOverlap = self.noteParameters.overlap + + note.pitch = self.noteParametersBoundaries( newPitch, note.pitch, Constants.MINIMUM_PITCH, Constants.MAXIMUM_PITCH ) + note.amplitude = self.noteParametersBoundaries( newAmplitude, note.amplitude, Constants.MINIMUM_AMPLITUDE, Constants.MAXIMUM_AMPLITUDE ) + note.reverbSend = self.noteParametersBoundaries( newReverbSend, note.reverbSend, Constants.MINIMUM_AMPLITUDE, + Constants.MAXIMUM_AMPLITUDE ) + if newPan != note.pan: + note.pan = newPan + + if newAttack != note.attack: + note.attack = newAttack + + if newDecay != note.decay: + note.decay = newDecay + + if newFilterType != note.filterType: + note.filterType = newFilterType + + if newFilterCutoff != note.filterCutoff: + note.filterCutoff = newFilterCutoff + + if newTied != note.tied: + note.tied = newTied + + if newOverlap != note.overlap: + note.overlap = newOverlap + + self.updatePageCallback() + + def noteParametersBoundaries( self, newValue, noteValue, minBoundary, maxBoundary ): + if newValue != noteValue: + if newValue >= minBoundary and newValue <= maxBoundary: + return newValue + elif newValue < minBoundary: + return minBoundary + elif newValue > maxBoundary: + return maxBoundary + else: + return noteValue + + #----------------------------------- + # action and event methods + #----------------------------------- + def setCurrentAction( self, action, obj ): + if self.curAction: + print "BackgroundView - Action already in progress!" + + self.curAction = action + self.curActionObject = obj + + if action == "note-drag-onset": self.updateDragLimits() + elif action == "note-drag-duration": self.updateDragLimits() + elif action == "note-drag-pitch": self.updateDragLimits() + + def doneCurrentAction( self ): + if self.curAction == "note-drag-onset": self.doneNoteDrag() + elif self.curAction == "note-drag-duration": self.doneNoteDrag() + elif self.curAction == "note-drag-pitch": self.doneNoteDrag() + + self.curAction = False + self.curActionObject = False + + def toggleTrack( self, trackID, exclusive ): + if exclusive: + self.selectedTrackIDs.clear() + self.selectedTrackIDs.add( trackID ) + else: + if trackID in self.selectedTrackIDs: + self.selectedTrackIDs.discard( trackID ) + else: + self.selectedTrackIDs.add( trackID ) + + def selectionChanged( self ): + if self.curAction == "note-drag-onset": self.updateDragLimits() + elif self.curAction == "note-drag-duration": self.updateDragLimits() + elif self.curAction == "note-drag-pitch": self.updateDragLimits() + self.dirty() + + def selectNotesByBar( self, selID, startX, stopX ): + beatCount = int(round( self.beatsPerPageAdjustment.value, 0 )) + for trackID in self.trackIDs: + if trackID == selID: + notes = self.trackViews[trackID].getNotesByBar( beatCount, startX, stopX ) + self.trackViews[trackID].selectNotes( SELECTNOTES.EXCLUSIVE, notes ) + else: + self.trackViews[trackID].selectNotes( SELECTNOTES.NONE, [] ) + self.selectionChanged() + + def selectNotesByTrack( self, selID ): + for trackID in self.trackIDs: + if trackID == selID: self.trackViews[trackID].selectNotes( SELECTNOTES.ALL, [] ) + else: self.trackViews[trackID].selectNotes( SELECTNOTES.NONE, [] ) + self.selectionChanged() + + def selectNotes( self, noteDic ): + for trackID in self.trackIDs: + if trackID in noteDic: self.trackViews[trackID].selectNotes( SELECTNOTES.EXCLUSIVE, noteDic[trackID] ) + else: self.trackViews[trackID].selectNotes( SELECTNOTES.NONE, [] ) + self.selectionChanged() + + def addNotesToSelection( self, noteDic ): + for trackID in self.trackIDs: + if trackID in noteDic: self.trackViews[trackID].selectNotes( SELECTNOTES.ADD, noteDic[trackID] ) + self.selectionChanged() + + def deselectNotes( self, noteDic ): + for trackID in self.trackIDs: + if trackID in noteDic: self.trackViews[trackID].selectNotes( SELECTNOTES.REMOVE, noteDic[trackID] ) + self.selectionChanged() + + def clearSelectedNotes( self ): + for trackID in self.trackIDs: + self.trackViews[trackID].selectNotes( SELECTNOTES.NONE, [] ) + self.selectionChanged() + + def updateDragLimits( self ): + self.dragLimits = [ [-9999,9999], [-9999,9999], [-9999,9999] ] # initialize to big numbers! + for trackID in self.trackIDs: + self.trackViews[trackID].updateDragLimits( self.dragLimits ) + + def noteDragOnset( self, event ): + dx = event.x - self.clickLoc[0] + dx = min( self.dragLimits[0][1], max( self.dragLimits[0][0], dx ) ) + dy = 0 + dw = 0 + + for trackID in self.trackIDs: + self.trackViews[trackID].noteDrag( self, dx, dy, dw ) + self.dirty() + + def noteDragDuration( self, event ): + dx = 0 + dy = 0 + dw = event.x - self.clickLoc[0] + dw = min( self.dragLimits[2][1], max( self.dragLimits[2][0], dw ) ) + + for trackID in self.trackIDs: + self.trackViews[trackID].noteDrag( self, dx, dy, dw ) + self.dirty() + + def noteDragPitch( self, event ): + dx = 0 + dy = event.y - self.clickLoc[1] + dy = min( self.dragLimits[1][1], max( self.dragLimits[1][0], dy ) ) + dw = 0 + + for trackID in self.trackIDs: + self.trackViews[trackID].noteDrag( self, dx, dy, dw ) + self.dirty() + + def doneNoteDrag( self ): + for trackID in self.trackIDs: + self.trackViews[trackID].doneNoteDrag( self ) + + def updateMarquee( self, event ): + self.marqueeLoc = [ event.x, event.y ] + parentRect = self.get_allocation() + if self.marqueeLoc[0] < 0: self.marqueeLoc[0] = 0 + elif self.marqueeLoc[0] > parentRect.width: self.marqueeLoc[0] = parentRect.width + if self.marqueeLoc[1] < 0: self.marqueeLoc[1] = 0 + elif self.marqueeLoc[1] > parentRect.height: self.marqueeLoc[1] = parentRect.height + + self.dirty() + + def doneMarquee( self, event ): + if self.marqueeLoc: + start = [ min(self.clickLoc[0],self.marqueeLoc[0]), \ + min(self.clickLoc[1],self.marqueeLoc[1]) ] + stop = [ max(self.clickLoc[0],self.marqueeLoc[0]), \ + max(self.clickLoc[1],self.marqueeLoc[1]) ] + + select = {} + + trackSpacing = self.getTrackSpacing() + trackTop = 0 + for trackID in self.trackIDs: + notes = self.trackViews[trackID].handleMarqueeSelect( self, start, stop ) + if notes: select[trackID] = notes + trackTop += self.trackHeight + trackSpacing + if trackTop > stop[1]: break + + self.selectNotes( select ) + + self.marqueeLoc = False + self.doneCurrentAction() + + self.dirty() + + def handleButtonPress( self, drawingArea, event ): + + TP.ProfileBegin( "BV::handleButtonPress" ) + + if event.type == gtk.gdk._2BUTTON_PRESS: self.buttonPressCount = 2 + elif event.type == gtk.gdk._3BUTTON_PRESS: self.buttonPressCount = 3 + else: self.buttonPressCount = 1 + + self.clickLoc = [ event.x, event.y ] + + trackSpacing = self.getTrackSpacing() + trackTop = 0 + for trackID in self.trackIDs: + handled = self.trackViews[trackID].handleButtonPress( self, event ) + trackTop += self.trackHeight + trackSpacing + if handled or trackTop > event.y: break + + if handled: + if not self.curAction: self.curAction = True # it was handled maybe no action was declared, set curAction to True anyway + TP.ProfileEnd( "BV::handleButtonPress" ) + return + + if event.button == 3: + self.noteParameters = NoteParametersWindow( self.trackDictionary, self.getNoteParameters ) + self.setCurrentAction( "noteParameters", False ) + + TP.ProfileEnd( "BV::handleButtonPress" ) + + + def handleButtonRelease( self, drawingArea, event ): + TP.ProfileBegin( "BV::handleButtonRelease" ) + + if not self.curAction: #do track selection stuff here so that we can also handle marquee selection + trackSpacing = self.getTrackSpacing() + trackTop = 0 + for trackID in self.trackIDs: + handled = self.trackViews[trackID].handleButtonRelease( self, event, self.buttonPressCount ) + trackTop += self.trackHeight + trackSpacing + if handled or trackTop > event.y: break + + if handled: self.dirty() + + TP.ProfileEnd( "BV::handleButtonRelease" ) + return + + if not self.curActionObject: # there was no real action to carry out + self.curAction = False + TP.ProfileEnd( "BV::handleButtonRelease" ) + return + + if self.curActionObject != self: + if self.curActionObject.handleButtonRelease( self, event, self.buttonPressCount ): + self.dirty() + TP.ProfileEnd( "BV::handleButtonRelease" ) + return + + + # we're doing the action ourselves + + if self.curAction == "marquee": self.doneMarquee( event ) + + TP.ProfileEnd( "BV::handleButtonRelease" ) + return + + def handleMotion( self, drawingArea, event ): + TP.ProfileBegin( "BV::handleMotion" ) + + if not self.curAction: # no action is in progress yet we're dragging, start a marquee + self.setCurrentAction( "marquee", self ) + + if self.curAction == "note-drag-onset": + self.noteDragOnset( event ) + TP.ProfileEnd( "BV::handleMotion" ) + return + + if self.curAction == "note-drag-duration": + self.noteDragDuration( event ) + TP.ProfileEnd( "BV::handleMotion" ) + return + + if self.curAction == "note-drag-pitch": + self.noteDragPitch( event ) + TP.ProfileEnd( "BV::handleMotion" ) + return + + # we're doing the action ourselves + + if self.curAction == "marquee": self.updateMarquee( event ) + + TP.ProfileEnd( "BV::handleMotion" ) + return + + def TEMPOLDSTUFF(self): + + #TODO change this to accomodate the space between tracks + trackHeight = ( drawingArea.get_allocation().height - 1 ) / len( self.trackIDs ) + trackID = int( floor( event.y / trackHeight ) ) + + if event.type == gtk.gdk.BUTTON_PRESS: + #single click toggles track selection + if trackID in self.selectedTrackIDs: + self.selectedTrackIDs.discard( trackID ) + else: + self.selectedTrackIDs.add( trackID ) + elif event.type == gtk.gdk._2BUTTON_PRESS: + #double click selects a single track + self.selectedTrackIDs.clear() + self.selectedTrackIDs.add( trackID ) + + self.drawingArea.queue_draw() + self.selectionChangedCallback() + if event.button == 3: + self.noteParameters = NoteParametersWindow( self.trackDictionary, self.getNoteParameters ) + + #----------------------------------- + # drawing methods + #----------------------------------- + def draw( self, drawingArea, event ): + TP.ProfileBegin( "BackgroundView::draw" ) + + context = drawingArea.window.cairo_create() + context.set_antialias(0) # I don't know what to set this to to turn it off, and it doesn't seem to work anyway!? + + #parentRect = self.get_allocation() + + beatCount = int(round( self.beatsPerPageAdjustment.value, 0 )) + + for trackID in self.trackIDs: + self.trackViews[trackID].draw( context, + beatCount, + trackID in self.selectedTrackIDs ) + + # if self.curAction == "note-drag": # draw a cross at clickLoc + # lineW = 1 + # context.set_line_width( lineW ) + # lineWDIV2 = lineW/2.0 + # context.set_source_rgb( 1, 1, 1 ) + + # context.move_to( self.clickLoc[0] + lineWDIV2 - 3, self.clickLoc[1] + lineWDIV2 ) + # context.rel_line_to( 6, 0 ) + # context.stroke() + # context.move_to( self.clickLoc[0] + lineWDIV2, self.clickLoc[1] + lineWDIV2 - 3) + # context.rel_line_to( 0, 6 ) + # context.stroke() + + if self.marqueeLoc: # draw the selection rect + lineW = 1 + context.set_line_width( lineW ) + lineWDIV2 = lineW/2.0 + + context.move_to( self.clickLoc[0] + lineWDIV2, self.clickLoc[1] + lineWDIV2 ) + context.line_to( self.marqueeLoc[0] + lineWDIV2, self.clickLoc[1] + lineWDIV2 ) + context.line_to( self.marqueeLoc[0] + lineWDIV2, self.marqueeLoc[1] + lineWDIV2 ) + context.line_to( self.clickLoc[0] + lineWDIV2, self.marqueeLoc[1] + lineWDIV2 ) + context.close_path() + context.set_source_rgb( 1, 1, 1 ) + context.stroke() + + TP.ProfileEnd( "BackgroundView::draw" ) + + def dirty( self ): + self.queue_draw() + + diff --git a/TamTamEdit.activity/Edit/rm/NoteView.py b/TamTamEdit.activity/Edit/rm/NoteView.py new file mode 100644 index 0000000..ac139a1 --- /dev/null +++ b/TamTamEdit.activity/Edit/rm/NoteView.py @@ -0,0 +1,253 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +from Framework.Constants import Constants +from Framework.CSound.CSoundConstants import CSoundConstants +from GUI.GUIConstants import GUIConstants +from GUI.Core.NoteParametersWindow import NoteParametersWindow + +from BackgroundView import SELECTNOTES + +#---------------------------------------------------------------------- +# TODO: currently we are only using CSoundNotes, +# - this should updated to handle generic Note objects +#---------------------------------------------------------------------- + +#---------------------------------------------------------------------- +# A view for the (CSound)Note class +#---------------------------------------------------------------------- +class NoteView: + #----------------------------------- + # initialization + # TODO: not sure if passing in beatsPerPageAdjustment is the best way to go about it + #----------------------------------- + def __init__( self, note, track, beatsPerPageAdjustment ): + self.note = note + + self.track = track + self.beatsPerPageAdjustment = beatsPerPageAdjustment + self.posOffset = (0,0) + + self.baseOnset = self.basePitch = self.baseDuration = self.lastDragX = self.lastDragY = self.lastDragW = 0 # note dragging properties + + self.sampleNote = None + + self.parentSize = False + + self.selected = False + self.potentialDeselect = False + + + def getNoteParameters( self ): + self.note.pitch = self.noteParameters.pitchAdjust.value + self.note.amplitude = self.noteParameters.amplitudeAdjust.value + self.note.pan = self.noteParameters.panAdjust.value + self.note.attack = self.noteParameters.attackAdjust.value + self.note.decay = self.noteParameters.decayAdjust.value + self.note.reverbSend = self.noteParameters.reverbSendAdjust.value + self.note.filterType = self.noteParameters.filterType + self.note.filterCutoff = self.noteParameters.filterCutoff + self.note.tied = self.noteParameters.tied + self.note.overlap = self.noteParameters.overlap + + def handleButtonPress( self, emitter, event ): + eX = event.x - self.x + eY = event.y - self.y + + if eX < 0 or eX > self.width \ + or eY < 0 or eY > self.height: + return False + + if event.button == 3: + self.noteParameters = NoteParametersWindow( self.note, self.getNoteParameters ) + return True + + if event.type == gtk.gdk._2BUTTON_PRESS: # select bar + self.potentialDeselect = False + emitter.selectNotesByBar( self.track.getID(), self.x, self.x+self.width ) + elif event.type == gtk.gdk._3BUTTON_PRESS: # select track + self.potentialDeselect = False + emitter.selectNotesByTrack( self.track.getID() ) + else: + if self.getSelected(): # we already selected, might want to delected + self.potentialDeselect = True + else: + emitter.selectNotes( { self.track.getID(): [ self ] } ) + self.updateSampleNote( self.note.pitch ) + + percent = eX/self.width + if percent < 0.3: emitter.setCurrentAction( "note-drag-onset", self ) + elif percent > 0.7: emitter.setCurrentAction( "note-drag-duration", self ) + else: emitter.setCurrentAction( "note-drag-pitch", self ) + + + emitter.dirty() + + return True + + def handleButtonRelease( self, emitter, event, buttonPressCount ): + + if self.potentialDeselect: + self.potentialDeselect = False + emitter.deselectNotes( { self.track.getID(): [ self ] } ) + + self.clearSampleNote() + + emitter.doneCurrentAction() + + return True + + def noteDrag( self, emitter, dx, dy, dw ): + self.potentialDeselect = False + + ticksPerPixel = (round( self.beatsPerPageAdjustment.value, 0 ) * Constants.TICKS_PER_BEAT) / self.parentSize[0] + stepPerPixel = (Constants.NUMBER_OF_POSSIBLE_PITCHES-1) / (self.parentSize[1] - self.height) + pitchPerStep = (Constants.MAXIMUM_PITCH-Constants.MINIMUM_PITCH)/(Constants.NUMBER_OF_POSSIBLE_PITCHES-1) + + if dx != self.lastDragX: + self.lastDragX = dx + self.note.onset = self.baseOnset + int(dx*ticksPerPixel) + + if dy != self.lastDragY: + self.lastDragY = dy + newPitch = self.basePitch + round(-dy*stepPerPixel)*pitchPerStep + self.note.pitch = newPitch + self.updateSampleNote( newPitch ) + + if dw != self.lastDragW: + self.lastDragW = dw + self.note.duration = self.baseDuration + int(dw*ticksPerPixel) + + self.updateTransform( False ) + + def doneNoteDrag( self, emitter ): + self.baseOnset = self.note.onset + self.basePitch = self.note.pitch + self.baseDuration = self.note.duration + + self.lastDragX = 0 + self.lastDragY = 0 + self.lastDragW = 0 + + self.clearSampleNote() + + + def handleMarqueeSelect( self, emitter, start, stop ): + intersectionY = [ max(start[1],self.y), min(stop[1],self.y+self.height) ] + if intersectionY[0] > intersectionY[1]: + return False + + intersectionX = [ max(start[0],self.x), min(stop[0],self.x+self.width) ] + if intersectionX[0] > intersectionX[1]: + return False + + return True + + #----------------------------------- + # draw + #----------------------------------- + + def setPositionOffset( self, offset ): + self.posOffset = offset + if self.parentSize: self.updateTransform( False ) + + def draw( self, context ): + lineW = GUIConstants.NOTE_BORDER_SIZE + lineWDIV2 = lineW/2.0 + context.set_line_width( lineW ) + + context.move_to( self.x + lineWDIV2, self.y + lineWDIV2 ) + context.rel_line_to( self.width - lineW, 0 ) + context.rel_line_to( 0, self.height - lineW ) + context.rel_line_to( -self.width + lineW, 0 ) + context.close_path() + + #background + colour = 1 - ( ( self.note.amplitude * 0.7 ) + 0.3 ) + context.set_source_rgb( colour, colour, colour ) + context.fill_preserve() + + #border + if self.selected: context.set_source_rgb( 1, 1, 1 ) + else: context.set_source_rgb( 0, 0, 0 ) + context.stroke() + + #----------------------------------- + # update + #----------------------------------- + + def updateTransform( self, parentSize ): + if parentSize: self.parentSize = parentSize + self.width = int( self.parentSize[0] * self.note.duration / (round( self.beatsPerPageAdjustment.value, 0 ) * Constants.TICKS_PER_BEAT) ) + self.height = round( max( GUIConstants.MINIMUM_NOTE_HEIGHT, self.parentSize[1] / (Constants.NUMBER_OF_POSSIBLE_PITCHES-1) ) ) + self.x = int( self.parentSize[0] * self.note.onset / (round( self.beatsPerPageAdjustment.value, 0 ) * Constants.TICKS_PER_BEAT) ) \ + + self.posOffset[0] + self.y = round( (self.parentSize[1]-self.height) * ( Constants.MAXIMUM_PITCH - self.note.pitch ) / (Constants.NUMBER_OF_POSSIBLE_PITCHES-1) ) \ + + self.posOffset[1] + + def checkX( self, startx, stopx ): + if self.x >= startx and self.x < stopx: return True + else: return False + + def getStartTick( self ): + return self.note.onset + + def getEndTick( self ): + return self.note.onset + self.note.duration + + def updateDragLimits( self, dragLimits, leftBound, rightBound, widthBound ): + pixelsPerTick = self.parentSize[0] / (round( self.beatsPerPageAdjustment.value, 0 ) * Constants.TICKS_PER_BEAT) + pixelsPerPitch = (self.parentSize[1] - self.height) / (Constants.MAXIMUM_PITCH - Constants.MINIMUM_PITCH) + left = (leftBound - self.note.onset) * pixelsPerTick + right = (rightBound - self.note.duration - self.note.onset) * pixelsPerTick + up = (self.note.pitch - Constants.MAXIMUM_PITCH) * pixelsPerPitch + down = (self.note.pitch - Constants.MINIMUM_PITCH) * pixelsPerPitch + short = (Constants.MINIMUM_NOTE_DURATION - self.note.duration) * pixelsPerTick + long = (widthBound - self.note.duration - self.note.onset) * pixelsPerTick + + if dragLimits[0][0] < left: dragLimits[0][0] = left + if dragLimits[0][1] > right: dragLimits[0][1] = right + if dragLimits[1][0] < up: dragLimits[1][0] = up + if dragLimits[1][1] > down: dragLimits[1][1] = down + if dragLimits[2][0] < short: dragLimits[2][0] = short + if dragLimits[2][1] > long: dragLimits[2][1] = long + + # store the current loc as a reference point + self.baseOnset = self.note.onset + self.basePitch = self.note.pitch + self.baseDuration = self.note.duration + + def updateSampleNote( self, pitch ): + if self.sampleNote == None: + self.sampleNote = self.note.clone() + #TODO clean this up: + if CSoundConstants.INSTRUMENTS[ self.sampleNote.instrumentFlag ].csoundInstrumentID == 103: + self.sampleNote.duration = 100 + else: + self.sampleNote.duration = -1 + self.sampleNote.play() + + elif self.sampleNote.pitch != pitch: + self.sampleNote.pitch = pitch + self.sampleNote.play() + + def clearSampleNote( self ): + if self.sampleNote != None: + self.sampleNote.duration = 0 + self.sampleNote.play() + del self.sampleNote + self.sampleNote = None + + #----------------------------------- + # Selection + #----------------------------------- + + def setSelected( self, state ): + if self.selected != state: + self.selected = state + return True # state changed + return False # state is the same + + def getSelected( self ): + return self.selected diff --git a/TamTamEdit.activity/Edit/rm/PageBankView.py b/TamTamEdit.activity/Edit/rm/PageBankView.py new file mode 100644 index 0000000..fedadef --- /dev/null +++ b/TamTamEdit.activity/Edit/rm/PageBankView.py @@ -0,0 +1,85 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +from GUI.GUIConstants import GUIConstants +from GUI.Core.PageView import PageView + +class PageBankView( gtk.Frame ): + + NO_PAGE = -1 + + def __init__( self, selectPageCallback, pageDropCallback ): + gtk.Frame.__init__( self ) + self.table = gtk.Table( 1, GUIConstants.NUMBER_OF_PAGE_BANK_COLUMNS ) + self.add( self.table ) + self.drag_dest_set( gtk.DEST_DEFAULT_ALL, [ ( "tune page", gtk.TARGET_SAME_APP, 11 )], gtk.gdk.ACTION_COPY|gtk.gdk.ACTION_MOVE ) + self.connect( "drag_data_received", self.dragDataReceived ) + self.selectPageCallback = selectPageCallback + self.pageDropCallback = pageDropCallback + self.selectedPageIds = set([]) + self.pageIndexDictionary = {} + self.pageViews = {} + + def dragDataReceived( self, widget, context, x, y, selectionData, info, time): + self.pageDropCallback( selectionData.data ) + + def addPage( self, pageId, invokeCallback = True ): + pageIndex = len( self.pageViews.keys() ) + self.pageIndexDictionary[ pageIndex ] = pageId + + #TODO: resize table to suit number of pages? + #if pageIndex > ( self.table.n-rows * self.table.n_columns ): + # self.table.resize( self.table.n_rows + 1, self.table.n_columns ) + + pageView = PageView( pageIndex, self.selectPage, True ) + self.pageViews[ pageIndex ] = pageView + + columnIndex = pageIndex % GUIConstants.NUMBER_OF_PAGE_BANK_COLUMNS + rowIndex = int( pageIndex / GUIConstants.NUMBER_OF_PAGE_BANK_COLUMNS ) + self.table.attach( pageView, columnIndex, columnIndex + 1, rowIndex, rowIndex + 1, gtk.SHRINK, gtk.SHRINK ) + + self.updateSize( pageView ) + + pageView.drag_source_set( gtk.gdk.BUTTON1_MASK, + [ ( "bank page", gtk.TARGET_SAME_APP, 10 ) ], + gtk.gdk.ACTION_COPY ) + + self.selectPage( pageId, True, invokeCallback ) + + pageView.show() + + def set_size_request( self, width, height ): + gtk.Frame.set_size_request( self, width, height ) + self.table.set_size_request( width, height ) + for pageId in self.pageViews.keys(): + self.updateSize( self.pageViews[ pageId ] ) + + def updateSize( self, pageView ): + pageView.set_size_request( self.get_allocation().width / GUIConstants.NUMBER_OF_PAGE_BANK_COLUMNS, + GUIConstants.PAGE_HEIGHT - 1 ) + + def selectPage( self, selectedPageId, invokeCallback = True, deselectOthers = True ): + if deselectOthers: + for pageId in self.pageViews.keys(): + self.pageViews[ pageId ].setSelected( pageId == selectedPageId ) + if pageId != selectedPageId: + self.selectedPageIds.discard( pageId ) + else: + self.selectedPageIds.add( pageId ) + #nb: pageId might be NO_PAGE, and selectedPageIds can be empty here + + else: + self.pageViews[ selectedPageId ].toggleSelected() + if self.pageViews[ selectedPageId ].selected: + self.selectedPageIds.add( selectedPageId ) + else: + self.selectedPageIds.discard( selectedPageId ) + + if invokeCallback: + self.selectPageCallback( selectedPageId ) + + def getSelectedPageIds( self ): + rval = filter( lambda id: self.pageViews[id].selected == True, self.pageViews.keys()) + return rval + diff --git a/TamTamEdit.activity/Edit/rm/PageView.py b/TamTamEdit.activity/Edit/rm/PageView.py new file mode 100644 index 0000000..00b650b --- /dev/null +++ b/TamTamEdit.activity/Edit/rm/PageView.py @@ -0,0 +1,65 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +import pango + +from GUI.GUIConstants import GUIConstants + +class PageView( gtk.DrawingArea ): + def __init__( self, pageID, selectPageCallback, selected = False ): + gtk.DrawingArea.__init__( self ) + + self.pageID = pageID + self.selectPageCallback = selectPageCallback + self.selected = selected + + self.add_events( gtk.gdk.BUTTON_PRESS_MASK ) + + self.connect( "expose-event", self.handleExposeEvent ) + self.connect( "button-press-event", self.handleButtonPress ) + self.connect( "drag_data_get", self.getData ) + + def handleButtonPress( self, widget, event ): + if event.button == 1 or event.button == 3: + self.selectPageCallback( self.pageID, event.button == 1 ) + + def getData( self, widget, context, selection, targetType, eventTime ): + return selection.set( gtk.gdk.SELECTION_PRIMARY, 32, "p %d" % self.pageID ) + + def toggleSelected( self ): + self.selected = not self.selected + self.queue_draw() + + def setSelected( self, selected ): + if self.selected != selected: + self.selected = selected + self.queue_draw() + + # TODO: this is temporary: replace with a visual representation of the page + def handleExposeEvent( self, drawingArea, event ): + size = self.get_allocation() + context = self.window.cairo_create() + + if self.selected: + context.set_line_width( GUIConstants.PAGE_SELECTED_BORDER_SIZE ) + else: + context.set_line_width( GUIConstants.PAGE_BORDER_SIZE ) + context.move_to( 0, 0 ) + context.rel_line_to( size.width, 0 ) + context.rel_line_to( 0, size.height ) + context.rel_line_to( -size.width, 0 ) + context.close_path() + + #blue background + context.set_source_rgb( 0.75, 0.75, 0.75 ) + context.fill_preserve() + + #black border + context.set_source_rgb( 0, 0, 0 ) + context.stroke() + + #text + layout = self.create_pango_layout( "%d" % ( self.pageID + 1 ) ) + layout.set_font_description( pango.FontDescription( 'Sans 10' ) ) + self.window.draw_layout( self.window.new_gc(), 5, 5, layout ) diff --git a/TamTamEdit.activity/Edit/rm/PositionIndicator.py b/TamTamEdit.activity/Edit/rm/PositionIndicator.py new file mode 100644 index 0000000..aadc4f4 --- /dev/null +++ b/TamTamEdit.activity/Edit/rm/PositionIndicator.py @@ -0,0 +1,47 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +#---------------------------------------------------------------------- +# A verical bar used to show the current point in time on a page +# TODO: modify this class to change the current point in time +# on click and drag +#---------------------------------------------------------------------- +class PositionIndicator( gtk.DrawingArea ): + #----------------------------------- + # initialization + #----------------------------------- + def __init__( self, trackIDs, selectedTrackIDs, mutedTrackIDs ): + gtk.DrawingArea.__init__( self ) + + self.trackIDs = trackIDs + self.selectedTrackIDs = selectedTrackIDs + self.mutedTrackIDs = mutedTrackIDs + + self.connect( "expose-event", self.draw ) + + def draw( self, drawingArea, event ): + indicatorSize = self.get_allocation() + trackHeight = indicatorSize.height / len( self.trackIDs ) + + context = drawingArea.window.cairo_create() + + trackIndex = 0 + for trackID in self.trackIDs: + height = trackIndex * trackHeight + + context.move_to( 0, height ) + context.rel_line_to( indicatorSize.width, 0 ) + context.rel_line_to( 0, height + trackHeight ) + context.rel_line_to( -indicatorSize.width, 0 ) + context.close_path() + + if trackID not in self.mutedTrackIDs: + context.set_source_rgb( 0, 0, 0 ) #black + else: + context.set_source_rgb( 0.6, 0.6, 0.6 ) #grey + + context.fill_preserve() + context.stroke() + + trackIndex += 1
\ No newline at end of file diff --git a/TamTamEdit.activity/Edit/rm/TrackView.py b/TamTamEdit.activity/Edit/rm/TrackView.py new file mode 100644 index 0000000..0b66abd --- /dev/null +++ b/TamTamEdit.activity/Edit/rm/TrackView.py @@ -0,0 +1,263 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +from Framework.Constants import Constants +from GUI.GUIConstants import GUIConstants + +from BackgroundView import SELECTNOTES +from NoteView import NoteView + + +#---------------------------------------------------------------------- +# This view class is used to show the contents of a NoteTrack +# i.e. a Collection of Note objects +#---------------------------------------------------------------------- +class TrackView: + #----------------------------------- + # initialization functions + #----------------------------------- + def __init__( self, trackID, beatsPerPageAdjustment ): + self.trackID = trackID + self.beatsPerPageAdjustment = beatsPerPageAdjustment + self.noteViews = [] + self.posOffset = (0,0) + self.selectedNotes = [] + + def getID( self ): + return self.trackID + + #----------------------------------- + # modification methods + #----------------------------------- + def setNotes( self, notes ): + self.clearNotes() + + lineW = self.getBorderWidth() + + for note in notes: + noteView = NoteView( note, self, self.beatsPerPageAdjustment ) + self.noteViews.append( noteView ) + noteView.setPositionOffset( (self.posOffset[0]+lineW, self.posOffset[1]+lineW ) ) + + self.updateNoteTransforms() + + def clearNotes( self ): + del self.noteViews + self.noteViews = [] + self.selectedNotes = [] + + def selectNotes( self, mode, which ): + if mode == SELECTNOTES.ALL: + for note in self.noteViews: note.setSelected( True ) + self.selectedNotes = self.noteViews[:] + elif mode == SELECTNOTES.NONE: + for note in self.noteViews: note.setSelected( False ) + self.selectedNotes = [] + elif mode == SELECTNOTES.ADD: + for note in which: + if note.setSelected( True ): + self.selectedNotes.insert( 0, note ) + elif mode == SELECTNOTES.REMOVE: + for note in which: + if note.setSelected( False ): + self.selectedNotes.remove( note ) + elif mode == SELECTNOTES.EXCLUSIVE: + for note in self.noteViews: + if note in which: + if note.setSelected( True ): + self.selectedNotes.insert( 0, note ) + else: + if note.setSelected( False ): + self.selectedNotes.remove( note ) + + def updateDragLimits( self, dragLimits ): + if not len(self.selectedNotes): return # no selected notes here + + leftBound = 0 + maxRightBound = round( self.beatsPerPageAdjustment.value, 0 ) * Constants.TICKS_PER_BEAT + last = len(self.noteViews)-1 + for i in range(0,last): + if not self.noteViews[i].getSelected(): + leftBound = self.noteViews[i].getEndTick() + else: + if not self.noteViews[i+1].getSelected(): + rightBound = min( self.noteViews[i+1].getStartTick(), maxRightBound ) + widthBound = rightBound + else: + rightBound = maxRightBound + widthBound = min( self.noteViews[i+1].getStartTick(), maxRightBound ) + self.noteViews[i].updateDragLimits( dragLimits, leftBound, rightBound, widthBound ) + if self.noteViews[last].getSelected(): + self.noteViews[last].updateDragLimits( dragLimits, leftBound, maxRightBound, maxRightBound ) + + def getNotesByBar( self, beatCount, startX, stopX ): + beatWidth = self.getBeatLineSpacing( beatCount ) + beatStart = self.getBeatLineStart() + while beatStart+beatWidth <= startX: + beatStart += beatWidth + beatStop = beatStart + beatWidth + while beatStop+beatWidth < stopX: + beatStop += beatWidth + + notes = [] + for note in self.noteViews: + if note.checkX( beatStart, beatStop ): + notes.insert(0,note) + return notes + + #----------------------------------- + # event methods + #----------------------------------- + + def handleButtonPress( self, emitter, event ): + eX = event.x - self.posOffset[0] + eY = event.y - self.posOffset[1] + if eX < 0 or eX > self.width or eY < 0 or eY > self.height: + return False + + for note in self.noteViews: + handled = note.handleButtonPress( emitter, event ) + if handled: return handled + + return False + + def handleButtonRelease( self, emitter, event, buttonPressCount ): + eX = event.x - self.posOffset[0] + eY = event.y - self.posOffset[1] + + if eX < 0 or eX > self.width or eY < 0 or eY > self.height: + return False + + if event.button == 1: + if buttonPressCount == 1: emitter.toggleTrack( self.trackID, False ) + else: emitter.toggleTrack( self.trackID, True ) + + return True + + def handleMarqueeSelect( self, emitter, start, stop ): + intersectionY = [ max(start[1],self.posOffset[1]), min(stop[1],self.posOffset[1]+self.height) ] + if intersectionY[0] > intersectionY[1]: + return False + + intersectionX = [ max(start[0],self.posOffset[0]), min(stop[0],self.posOffset[0]+self.width) ] + if intersectionX[0] > intersectionX[1]: + return False + + + hits = [] + for note in self.noteViews: + hit = note.handleMarqueeSelect( emitter, + [ intersectionX[0], intersectionY[0] ], \ + [ intersectionX[1], intersectionY[1] ] ) + if hit: hits.insert(0,note) + + if len(hits): return hits + + return False + + def noteDrag( self, emitter, dx, dy, dw ): + for note in self.selectedNotes: + note.noteDrag( emitter, dx, dy, dw ) + + def doneNoteDrag( self, emitter ): + for note in self.selectedNotes: + note.doneNoteDrag( emitter ) + + #----------------------------------- + # drawing methods + #----------------------------------- + + def getBorderWidth( self ): #should return a constant value, otherwise we have to recalculate sizing and positioning everyframe! + return GUIConstants.BORDER_SIZE + + def getBeatLineWidth( self ): + return GUIConstants.BEAT_LINE_SIZE #should return a constant value, otherwise we have to recalculate sizing and positioning everyframe! + + def getBeatLineSpacing( self, beatCount ): + return (self.width - 2*self.getBorderWidth() + self.getBeatLineWidth())/beatCount + + def getBeatLineStart( self ): + return self.posOffset[0] + self.getBorderWidth() - self.getBeatLineWidth()/2.0 + + def setPositionOffset( self, offset ): + self.posOffset = offset + + lineW = self.getBorderWidth() + for note in self.noteViews: + note.setPositionOffset( ( self.posOffset[0]+lineW, self.posOffset[1]+lineW ) ) + + def draw( self, context, beatCount, selected ): + #if selected: lineW = GUIConstants.SELECTED_BORDER_SIZE + #else: lineW = GUIConstants.BORDER_SIZE + lineW = self.getBorderWidth() + context.set_line_width( lineW ) + lineWDIV2 = lineW/2.0 + + context.move_to( self.posOffset[0] + lineWDIV2, self.posOffset[1] + lineWDIV2 ) + context.rel_line_to( self.width - lineW, 0 ) + context.rel_line_to( 0, self.height - lineW ) + context.rel_line_to( -self.width + lineW, 0 ) + context.close_path() + + #draw the background + context.set_source_rgb( 0.75, 0.75, 0.75 ) + context.fill_preserve() + + #draw the border + if selected: context.set_source_rgb( 1, 1, 1 ) + else: context.set_source_rgb( 0, 0, 0 ) + context.stroke() + + #draw the beat lines + beatLineWidth = self.getBeatLineWidth() + context.set_line_width( beatLineWidth ) + beatWidth = self.getBeatLineSpacing( beatCount ) + beatStart = self.getBeatLineStart() + context.set_source_rgb( 0, 0, 0 ) + for i in range(1,beatCount): + context.move_to( beatStart + i*beatWidth, self.posOffset[1] + lineW ) + context.rel_line_to( 0, self.height - 2*lineW ) + context.stroke() + + #draw the notes + for note in self.noteViews: + note.draw( context ) + + #----------------------------------- + # sizing methods + #----------------------------------- + + def updateNoteTransforms( self ): + width = self.width - 2*self.getBorderWidth() + height = self.height - 2*self.getBorderWidth() # adjust for actual note drawing area + for noteView in self.noteViews: + noteView.updateTransform( (width, height) ) + + def set_size_request( self, width, height ): + self.width = width + self.height = height + self.updateNoteTransforms() + + +#unused for now... +class NoteViewPool: + def __init__( self, parentContainer, beatsPerPageAdjustment ): + self.parentContainer = parentContainer + self.beatsPerPageAdjustment = beatsPerPageAdjustment + self.pool = [] + + def addNoteView( self, noteView ): + #noteView.hide() + self.pool.append( noteView ) + + def addNoteViews( self, noteViews ): + for noteView in noteViews: + self.addNoteView( noteView ) + + def getNoteView( self ): + poolSize = len( pool ) + if poolSize != 0: + return pool.pop( poolSize ) + + return NoteView( None, self.parentContainer, self.beatsPerPageAdjustment ) diff --git a/TamTamEdit.activity/Edit/rm/TunePageView.py b/TamTamEdit.activity/Edit/rm/TunePageView.py new file mode 100644 index 0000000..501504f --- /dev/null +++ b/TamTamEdit.activity/Edit/rm/TunePageView.py @@ -0,0 +1,17 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +from PageView import PageView + +class TunePageView( PageView ): + def __init__( self, pageID, tuneIndex, selectPageCallback, selected = False ): + PageView.__init__( self, pageID, selectPageCallback, selected ) + + self.pageIndex = tuneIndex + + def handleButtonPress( self, widget, data ): + self.selectPageCallback( self.tuneIndex ) + + def getData( self, widget, context, selection, targetType, eventTime ): + return selection.set( gtk.gdk.SELECTION_PRIMARY, 32, "t %d %d" % (self.pageID,self.pageIndex) ) diff --git a/TamTamEdit.activity/Edit/rm/TuneView.py b/TamTamEdit.activity/Edit/rm/TuneView.py new file mode 100644 index 0000000..63cf468 --- /dev/null +++ b/TamTamEdit.activity/Edit/rm/TuneView.py @@ -0,0 +1,123 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +from GUI.GUIConstants import GUIConstants +from GUI.Core.TunePageView import TunePageView + +def swap(l,i,j): + e = l[i] + l[i] = l[j] + l[j] = e + +class TuneView( gtk.ScrolledWindow ): + + NO_PAGE = -1 + + def _page_width(self): + return self.pageContainer.get_allocation().width / GUIConstants.NUMBER_OF_PAGE_BANK_COLUMNS + + def __init__( self, selectPageCallback ): + gtk.ScrolledWindow.__init__( self ) + + #selectPageCallback(): currently connected to pagePlayer.setPlayTune, which skips to a given page of the tune. + self.selectPageCallback = selectPageCallback + self.selectedPageIndex = self.NO_PAGE + + self.set_policy( gtk.POLICY_ALWAYS, gtk.POLICY_AUTOMATIC ) + self.set_placement( gtk.CORNER_TOP_LEFT ) + + #self.pageViews: list of our custom PageView widgets + self.pageViews = [] + self.pageContainer = gtk.HBox( False ) + self.add_with_viewport( self.pageContainer ) + + #the old part + self.pageContainer.drag_dest_set( gtk.DEST_DEFAULT_ALL, + [ ( "bank page", gtk.TARGET_SAME_APP, 10 ), + ( "tune page", gtk.TARGET_SAME_APP, 11 )], + gtk.gdk.ACTION_COPY|gtk.gdk.ACTION_MOVE ) + + self.pageContainer.connect( "drag_data_received", self.dragDataReceived ) + + #private method: called by gtk when pages get dragged onto the tune-view + def dragDataReceived( self, widget, context, x, y, selectionData, info, time ): + print 'dragDataReceived: ', selectionData.data, info, selectionData.data + recv = selectionData.data.split() + if recv[0] == 'p': + pageId = int( recv[1] ) + self.addPage( pageId, min( x / self._page_width(), len( self.pageViews )) ) + elif recv[0] == 't': + self.moveSelectedPage( min( x / self._page_width(), len( self.pageViews ) -1)) + else: + raise 'ERROR' + + #public method: called by MainWindow on file load + def syncFromPagePlayer(self): + raise 'never call this' + map( lambda pv:pv.destroy(), self.pageViews ) + self.pageViews = [] + tunePages = self.tunePagesCallback() + for i in range( len(tunePages)): + self.addPage( tunePages[i], i, False) + + + def addPage( self, pageID, position ): + #create a new widget + pageView = TunePageView( pageID, position, self.selectPage ) + self.pageViews.insert( position, pageView ) + self.pageContainer.pack_start( pageView, False ) + self.pageContainer.reorder_child( pageView, position ) + + pageView.set_size_request( self.pageContainer.get_allocation().width / GUIConstants.NUMBER_OF_PAGE_BANK_COLUMNS, + GUIConstants.PAGE_HEIGHT ) + pageView.show() + + for i in range( len(self.pageViews)) : + self.pageViews[i].tuneIndex = i + self.pageViews[i].setSelected( i == position) + self.selectPageCallback( pageID, position ) + pageView.drag_source_set( + gtk.gdk.BUTTON1_MASK, + [ ( "tune page", gtk.TARGET_SAME_APP, 11 ) ], + gtk.gdk.ACTION_COPY|gtk.gdk.ACTION_MOVE ) + + def moveSelectedPage( self, position): + self.pageContainer.reorder_child( self.pageViews[self.selectedPageIndex], position ) + swap( self.pageViews, self.selectedPageIndex, position ) + self.selectedPageIndex = position + for i in range( len(self.pageViews) ) : + self.pageViews[i].tuneIndex = i + self.pageViews[i].setSelected( i == position) + + def removePage( self, position ): + pv = self.pageViews[position] + self.pageViews[position:position+1] = [] + if self.selectedPageIndex >= position : self.selectedPageIndex -= 1 + for i in range( len(self.pageViews)) : + self.pageViews[i].tuneIndex = i + self.pageViews[i].setSelected( i == position) + self.pageContainer.remove(pv) + del pv + + def selectPage( self, selectedPageIndex, invokeCallback = True ): + if selectedPageIndex >= len( self.pageViews ): selectedPageIndex = self.NO_PAGE + self.selectedPageIndex = selectedPageIndex + if selectedPageIndex == self.NO_PAGE: + for pv in self.pageViews: pv.setSelected(False) + if invokeCallback: self.selectPageCallback( -1, -1 ) + else: + if not self.pageViews[ selectedPageIndex ].selected: + map( lambda pv: pv.setSelected( pv.tuneIndex == selectedPageIndex), self.pageViews) + if invokeCallback: self.selectPageCallback( self.pageViews[selectedPageIndex].pageID, selectedPageIndex ) + + def set_size_request( self, width, height ): + gtk.ScrolledWindow.set_size_request( self, width, height ) + map( lambda pv: pv.set_size_request( width / GUIConstants.NUMBER_OF_PAGE_BANK_COLUMNS, GUIConstants.PAGE_HEIGHT ), self.pageViews) + + def getPageId( self, idx): + return self.pageViews[idx].pageID + + def getTune( self ): + return [ p.pageID for p in self.pageViews ] + |