Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Edit
diff options
context:
space:
mode:
authorJames <olpc@localhost.localdomain>2007-02-17 03:45:23 (GMT)
committer James <olpc@localhost.localdomain>2007-02-17 03:45:23 (GMT)
commitee0904a24c1b7d6c2f66578607d5a4e7a8e81ab8 (patch)
tree810da49fc3c3c0fcce53de2547684ef4c1dcf45c /Edit
parent1bbaaac5b15bdf69e720e15930b3c8bff7d4f78a (diff)
parentd49ef42a259304a108957c103705d45c47d4956e (diff)
merging
Diffstat (limited to 'Edit')
-rw-r--r--Edit/HitInterface.py57
-rw-r--r--Edit/MainWindow.py350
-rw-r--r--Edit/NoteInterface.py97
-rw-r--r--Edit/TrackInterface.py420
-rw-r--r--Edit/TuneInterface.py89
5 files changed, 804 insertions, 209 deletions
diff --git a/Edit/HitInterface.py b/Edit/HitInterface.py
index 1301a33..1b12b1f 100644
--- a/Edit/HitInterface.py
+++ b/Edit/HitInterface.py
@@ -18,10 +18,14 @@ class HitInterface( NoteInterface ):
self.updateTransform()
def updateTransform( self ):
- if self.note.page == self.owner.curPage and not self.firstTransform:
- oldX = self.imgX
- oldY = self.imgY
- oldEndX = self.imgX + self.imgWidth
+ if self.note.page in self.owner.getActivePages():
+ if not self.firstTransform:
+ oldX = self.imgX
+ oldY = self.imgY
+ oldEndX = self.imgX + self.imgWidth
+ dirty = True
+ else:
+ dirty = False
if self.note.cs.onset != self.oldOnset:
self.x = self.owner.ticksToPixels( self.noteDB.getPage(self.note.page).beats, self.note.cs.onset )
@@ -33,7 +37,7 @@ class HitInterface( NoteInterface ):
self.imgY = self.y - Config.NOTE_IMAGE_PADDING
self.oldPitch = self.note.cs.pitch
- if self.note.page == self.owner.curPage:
+ if dirty:
if self.firstTransform:
self.owner.invalidate_rect( self.imgX, self.imgY, self.imgWidth, self.imgHeight, self.note.page )
self.firstTransform = False
@@ -107,19 +111,42 @@ class HitInterface( NoteInterface ):
return 1
- def noteDrag( self, emitter, do, dp, dd ):
+ def noteDragPitch( self, dp, stream ):
self.potentialDeselect = False
-
- if do != self.lastDragO:
- self.lastDragO = do
- self.noteDB.updateNote( self.note.page, self.note.track, self.note.id, PARAMETER.ONSET, self.baseOnset + do )
- self.end = self.note.cs.onset + self.note.cs.duration
-
if dp != self.lastDragP and not dp%2:
self.lastDragP = dp
- newPitch = self.basePitch + dp
- self.noteDB.updateNote( self.note.page, self.note.track, self.note.id, PARAMETER.PITCH, newPitch )
- self.updateSampleNote( newPitch )
+ stream += [ self.note.id, self.basePitch + dp ]
+
+ def noteDragDuration( self, dd, stream ):
+ return
+
+ def noteDecOnset( self, step, leftBound, stream ):
+ if self.selected:
+ if leftBound < self.note.cs.onset:
+ onset = max( self.note.cs.onset+step, leftBound )
+ stream += [ self.note.id, onset ]
+ return leftBound
+
+ def noteIncOnset( self, step, rightBound, stream ):
+ if self.selected:
+ if rightBound > self.end:
+ onset = min( self.end+step, rightBound ) - self.note.cs.duration
+ stream += [ self.note.id, onset ]
+ return rightBound
+
+ def noteDecPitch( self, step, stream ):
+ if self.note.cs.pitch > Config.MINIMUM_PITCH_DRUM:
+ stream += [ self.note.id, max( self.note.cs.pitch+2*step, Config.MINIMUM_PITCH_DRUM ) ]
+
+ def noteIncPitch( self, step, stream ):
+ if self.note.cs.pitch < Config.MAXIMUM_PITCH_DRUM:
+ stream += [ self.note.id, min( self.note.cs.pitch+2*step, Config.MAXIMUM_PITCH_DRUM ) ]
+
+ def noteDecDuration( self, step, stream ):
+ return
+
+ def noteIncDuration( self, step, rightBound, stream ):
+ return
# updateTooltip returns:
# -1, event occurs before us so don't bother checking any later notes
diff --git a/Edit/MainWindow.py b/Edit/MainWindow.py
index 2a8465b..4514f3e 100644
--- a/Edit/MainWindow.py
+++ b/Edit/MainWindow.py
@@ -207,17 +207,17 @@ class MainWindow( gtk.EventBox ):
self.GUI["2toolPanel"].set_size_request( -1, 75 )
# + + tool box
self.GUI["2toolBox"] = formatRoundBox( RoundHBox(), "#6C9790" )
- self.GUI["2toolBox"].set_size_request( 146, -1 )
+ self.GUI["2toolBox"].set_size_request( 154, -1 )
self.GUI["2toolPointerButton"] = ImageRadioButton( None, Config.IMAGE_ROOT+"pointer.png", Config.IMAGE_ROOT+"pointerDown.png", backgroundFill = "#6C9790" )
- self.GUI["2toolPointerButton"].connect( "clicked", self.handleToolClick , "Default" )
+ self.GUI["2toolPointerButton"].connect( "clicked", self.handleToolClick , "default" )
self.GUI["2toolBox"].pack_start( self.GUI["2toolPointerButton"] )
self.GUI["2toolPencilButton"] = ImageRadioButton( self.GUI["2toolPointerButton"], Config.IMAGE_ROOT+"pencil.png", Config.IMAGE_ROOT+"pencilDown.png", backgroundFill = "#6C9790" )
- self.GUI["2toolPencilButton"].connect( "clicked", self.handleToolClick , "Draw" )
+ self.GUI["2toolPencilButton"].connect( "clicked", self.handleToolClick , "draw" )
self.GUI["2toolBox"].pack_start( self.GUI["2toolPencilButton"] )
self.GUI["2toolPanel"].pack_start( self.GUI["2toolBox"], False, False )
self.GUI["2rightPanel"].pack_start( self.GUI["2toolPanel"], False )
# + + context box (for context sensitive buttons, nothing to do with CAIRO)
- contextWidth = 592
+ contextWidth = 674
self.GUI["2contextBox"] = formatRoundBox( RoundFixed(), "#6C9790" )
self.GUI["2contextBox"].set_size_request( contextWidth, -1 )
self.GUI["2contextPrevButton"] = gtk.Button("<")
@@ -229,48 +229,92 @@ class MainWindow( gtk.EventBox ):
# + + + page box
self.GUI["2pageBox"] = gtk.HBox()
self.GUI["2pageBox"].set_size_request( contextWidth-50, -1 )
+ self.GUI["2pageGenerateButton"] = gtk.Button("Gen")
+ self.GUI["2pageGenerateButton"].connect( "clicked", lambda a1:self.pageGenerate() )
+ self.GUI["2pageBox"].pack_start( self.GUI["2pageGenerateButton"] )
+ self.GUI["2pagePropertiesButton"] = gtk.Button("Prop")
+ self.GUI["2pagePropertiesButton"].connect( "clicked", lambda a1:self.pageProperties() )
+ self.GUI["2pageBox"].pack_start( self.GUI["2pagePropertiesButton"] )
self.GUI["2pageDeleteButton"] = gtk.Button("Delete")
- self.GUI["2pageDeleteButton"].connect( "clicked", lambda a1:self.removePages() )
+ self.GUI["2pageDeleteButton"].connect( "clicked", lambda a1:self.pageDelete() )
self.GUI["2pageBox"].pack_start( self.GUI["2pageDeleteButton"] )
- self.GUI["2pageNewButton"] = gtk.Button("New")
- self.GUI["2pageNewButton"].connect( "clicked", lambda a1:self.addPage() )
- self.GUI["2pageBox"].pack_start( self.GUI["2pageNewButton"] )
self.GUI["2pageDuplicateButton"] = gtk.Button("Duplicate")
- self.GUI["2pageDuplicateButton"].connect( "clicked", lambda a1:self.duplicatePages() )
+ self.GUI["2pageDuplicateButton"].connect( "clicked", lambda a1:self.pageDuplicate() )
self.GUI["2pageBox"].pack_start( self.GUI["2pageDuplicateButton"] )
+ self.GUI["2pageNewButton"] = gtk.Button("New")
+ self.GUI["2pageNewButton"].connect( "clicked", lambda a1:self.pageAdd() )
+ self.GUI["2pageBox"].pack_start( self.GUI["2pageNewButton"] )
+ self.GUI["2pageBeatsButton"] = gtk.Button("Beats")
+ self.GUI["2pageBeatsButton"].connect( "clicked", lambda a1:self.pageBeats() )
+ self.GUI["2pageBox"].pack_start( self.GUI["2pageBeatsButton"] )
self.GUI["2contextBox"].put( self.GUI["2pageBox"], 25, 0 )
# + + + track box
self.GUI["2trackBox"] = gtk.HBox()
self.GUI["2trackBox"].set_size_request( contextWidth-50, -1 )
+ self.GUI["2trackGenerateButton"] = gtk.Button("tGen")
+ self.GUI["2trackGenerateButton"].connect( "clicked", lambda a1:self.trackGenerate() )
+ self.GUI["2trackBox"].pack_start( self.GUI["2trackGenerateButton"] )
+ self.GUI["2trackPropertiesButton"] = gtk.Button("tProp")
+ self.GUI["2trackPropertiesButton"].connect( "clicked", lambda a1:self.trackProperties() )
+ self.GUI["2trackBox"].pack_start( self.GUI["2trackPropertiesButton"] )
self.GUI["2trackDeleteButton"] = gtk.Button("tDelete")
- self.GUI["2trackDeleteButton"].connect( "clicked", lambda a1:self.removePages() )
+ self.GUI["2trackDeleteButton"].connect( "clicked", lambda a1:self.trackDelete() )
self.GUI["2trackBox"].pack_start( self.GUI["2trackDeleteButton"] )
- self.GUI["2trackNewButton"] = gtk.Button("tNew")
- self.GUI["2trackNewButton"].connect( "clicked", lambda a1:self.addPage() )
- self.GUI["2trackBox"].pack_start( self.GUI["2trackNewButton"] )
- self.GUI["2trackDuplicateButton"] = gtk.Button("tDuplicate")
- self.GUI["2trackDuplicateButton"].connect( "clicked", lambda a1:self.duplicatePages() )
+ self.GUI["2trackDuplicateButton"] = gtk.ToggleButton("tDuplicate")
+ self.GUI["2trackDuplicateButton"].connect( "toggled", lambda a1:self.trackDuplicate() )
self.GUI["2trackBox"].pack_start( self.GUI["2trackDuplicateButton"] )
self.GUI["2contextBox"].put( self.GUI["2trackBox"], 25, 0 )
# + + + note box
self.GUI["2noteBox"] = gtk.HBox()
self.GUI["2noteBox"].set_size_request( contextWidth-50, -1 )
+ self.GUI["2noteGenerateButton"] = gtk.Button("nGen")
+ self.GUI["2noteGenerateButton"].connect( "clicked", lambda a1:self.noteGenerate() )
+ self.GUI["2noteBox"].pack_start( self.GUI["2noteGenerateButton"] )
+ self.GUI["2notePropertiesButton"] = gtk.Button("nProp")
+ self.GUI["2notePropertiesButton"].connect( "clicked", lambda a1:self.noteProperties() )
+ self.GUI["2noteBox"].pack_start( self.GUI["2notePropertiesButton"] )
self.GUI["2noteDeleteButton"] = gtk.Button("nDelete")
- self.GUI["2noteDeleteButton"].connect( "clicked", lambda a1:self.removePages() )
+ self.GUI["2noteDeleteButton"].connect( "clicked", lambda a1:self.noteDelete() )
self.GUI["2noteBox"].pack_start( self.GUI["2noteDeleteButton"] )
- self.GUI["2noteNewButton"] = gtk.Button("nNew")
- self.GUI["2noteNewButton"].connect( "clicked", lambda a1:self.addPage() )
- self.GUI["2noteBox"].pack_start( self.GUI["2noteNewButton"] )
- self.GUI["2noteDuplicateButton"] = gtk.Button("nDuplicate")
- self.GUI["2noteDuplicateButton"].connect( "clicked", lambda a1:self.duplicatePages() )
+ self.GUI["2noteDuplicateButton"] = gtk.ToggleButton("nDuplicate")
+ self.GUI["2noteDuplicateButton"].connect( "toggled", self.noteDuplicateWidget )
self.GUI["2noteBox"].pack_start( self.GUI["2noteDuplicateButton"] )
+ self.GUI["2noteOnsetBox"] = gtk.HBox()
+ self.GUI["2noteOnsetMinusButton"] = gtk.Button("<")
+ self.GUI["2noteOnsetMinusButton"].connect( "clicked", lambda a1:self.trackInterface.noteStepOnset(-1) )
+ self.GUI["2noteOnsetBox"].pack_start( self.GUI["2noteOnsetMinusButton"] )
+ self.GUI["2noteOnsetPlusButton"] = gtk.Button(">")
+ self.GUI["2noteOnsetPlusButton"].connect( "clicked", lambda a1:self.trackInterface.noteStepOnset(1) )
+ self.GUI["2noteOnsetBox"].pack_start( self.GUI["2noteOnsetPlusButton"] )
+ self.GUI["2noteBox"].pack_start( self.GUI["2noteOnsetBox"] )
+ self.GUI["2notePitchBox"] = gtk.VBox()
+ self.GUI["2notePitchPlusButton"] = gtk.Button("^")
+ self.GUI["2notePitchPlusButton"].connect( "clicked", lambda a1:self.trackInterface.noteStepPitch(1) )
+ self.GUI["2notePitchBox"].pack_start( self.GUI["2notePitchPlusButton"] )
+ self.GUI["2notePitchMinusButton"] = gtk.Button("v")
+ self.GUI["2notePitchMinusButton"].connect( "clicked", lambda a1:self.trackInterface.noteStepPitch(-1) )
+ self.GUI["2notePitchBox"].pack_start( self.GUI["2notePitchMinusButton"] )
+ self.GUI["2noteBox"].pack_start( self.GUI["2notePitchBox"] )
+ self.GUI["2noteDurationBox"] = gtk.HBox()
+ self.GUI["2noteDurationMinusButton"] = gtk.Button("<")
+ self.GUI["2noteDurationMinusButton"].connect( "clicked", lambda a1:self.trackInterface.noteStepDuration(-1) )
+ self.GUI["2noteDurationBox"].pack_start( self.GUI["2noteDurationMinusButton"] )
+ self.GUI["2noteDurationPlusButton"] = gtk.Button(">")
+ self.GUI["2noteDurationPlusButton"].connect( "clicked", lambda a1:self.trackInterface.noteStepDuration(1) )
+ self.GUI["2noteDurationBox"].pack_start( self.GUI["2noteDurationPlusButton"] )
+ self.GUI["2noteBox"].pack_start( self.GUI["2noteDurationBox"] )
+ self.GUI["2noteVolumeBox"] = gtk.VBox()
+ self.GUI["2noteVolumePlusButton"] = gtk.Button("^")
+ self.GUI["2noteVolumePlusButton"].connect( "clicked", lambda a1:self.trackInterface.noteStepVolume(0.05) )
+ self.GUI["2noteVolumeBox"].pack_start( self.GUI["2noteVolumePlusButton"] )
+ self.GUI["2noteVolumeMinusButton"] = gtk.Button("v")
+ self.GUI["2noteVolumeMinusButton"].connect( "clicked", lambda a1:self.trackInterface.noteStepVolume(-0.05) )
+ self.GUI["2noteVolumeBox"].pack_start( self.GUI["2noteVolumeMinusButton"] )
+ self.GUI["2noteBox"].pack_start( self.GUI["2noteVolumeBox"] )
self.GUI["2contextBox"].put( self.GUI["2noteBox"], 25, 0 )
self.GUI["2toolPanel"].pack_start( self.GUI["2contextBox"], False )
# + + transport box
self.GUI["2transportBox"] = formatRoundBox( RoundHBox(), "#6C9790" )
- self.GUI["2generateButton"] = gtk.Button("G")
- self.GUI["2generateButton"].connect( "clicked", self.handleGenerate, None )
- self.GUI["2transportBox"].pack_start( self.GUI["2generateButton"] )
self.GUI["2recordButton"] = gtk.ToggleButton("R")
self.GUI["2transportBox"].pack_start( self.GUI["2recordButton"] )
self.GUI["2playButton"] = gtk.ToggleButton("P")
@@ -311,6 +355,10 @@ class MainWindow( gtk.EventBox ):
self.currentpageId = 0
self.playingTuneIdx = 0
+ # timers
+ self.predrawTimeout = False
+ self.playbackTimeout = False
+
# FPS stuff
self.fpsTotalTime = 0
self.fpsFrameCount = 0
@@ -323,7 +371,7 @@ class MainWindow( gtk.EventBox ):
init_data() #above
init_GUI() #above
-
+
self.csnd.setMasterVolume( self.getVolume() )
for tid in range(Config.NUMBER_OF_TRACKS):
@@ -376,7 +424,10 @@ class MainWindow( gtk.EventBox ):
notes += self.noteDB.getCSNotesByTrack( page, track )
self.playing = True
- self.playbackTimeout = gobject.timeout_add( 100, self.onTimeout )
+ if self.predrawTimeout:
+ gobject.source_remove( self.predrawTimeout )
+ self.predrawTimeout = False
+ self.playbackTimeout = gobject.timeout_add( 50, self.onTimeout )
if len(self.pages_playing) > 1:
self.displayPage( self.pages_playing[0], self.pages_playing[1] )
@@ -407,6 +458,7 @@ class MainWindow( gtk.EventBox ):
else: #stop
gobject.source_remove( self.playbackTimeout )
+ self.playbackTimeout = False
if False:
#This is causing csound to stop working...
# reimplement this with real CSoundNotes and it should be ok.
@@ -426,10 +478,22 @@ class MainWindow( gtk.EventBox ):
curtick = self.csnd.loopGetTick()
curIdx = curtick / ( 4 * Config.TICKS_PER_BEAT) #TODO handle each pages_playing length
- if curIdx + 1 < len(self.pages_playing): predraw = self.pages_playing[curIdx+1]
- else: predraw = self.pages_playing[0]
- self.displayPage( self.pages_playing[curIdx], predraw )
+ # TODO update playhead
+
+ if self.pages_playing[curIdx] != self.displayedPage:
+ if curIdx + 1 < len(self.pages_playing): predraw = self.pages_playing[curIdx+1]
+ else: predraw = self.pages_playing[0]
+ self.displayPage( self.pages_playing[curIdx], predraw )
+ else:
+ self.trackInterface.predrawPage( time.time() + 0.020 ) # 20 ms time limit
+
+ return True
+
+ def onPredrawTimeout( self ):
+ if self.trackInterface.predrawPage( time.time() + 0.020 ): # 20 ms time limit
+ self.predrawTimeout = False
+ return False
return True
def onMuteTrack( self, widget, trackId ):
@@ -478,6 +542,10 @@ class MainWindow( gtk.EventBox ):
def handleToolClick( self, widget, mode ):
if widget.get_active(): self.trackInterface.setInterfaceMode( mode )
+ def getTool( self ):
+ if self.GUI["2toolPointerButton"].get_active(): return "default"
+ else: return "draw"
+
def onKeyboardButton( self, widget, data ):
self.kb_active = widget.get_active()
@@ -488,11 +556,6 @@ class MainWindow( gtk.EventBox ):
#-----------------------------------
# generation functions
#-----------------------------------
- def handleGenerate( self, widget, data ):
- #if widget.get_active():
- self.generationParametersWindow.show_all()
- #else:
- # self.handleCloseGeneratonParametersWindow()
def handleCloseGenerationParametersWindow( self, widget = None, data = None ):
self.generationParametersWindow.hide_all()
@@ -507,11 +570,19 @@ class MainWindow( gtk.EventBox ):
for p in range(Config.NUMBER_OF_PAGES):
dict[t][p] = []
- if self.trackSelected == [ 0 for i in range(Config.NUMBER_OF_TRACKS) ]:
+ if self.generateMode == "note":
+ # unsupported!?
+ self.handleCloseGenerationParametersWindow( None, None )
+ return
+ elif self.generateMode == "track":
+ if self.trackSelected == [ 0 for i in range(Config.NUMBER_OF_TRACKS) ]:
+ newtracks = set(range(Config.NUMBER_OF_TRACKS))
+ else:
+ newtracks = set( [ i for i in range(Config.NUMBER_OF_TRACKS) if self.trackSelected[i] ] )
+ newpages = self.tuneInterface.getSelectedIds()
+ else: # page mode
newtracks = set(range(Config.NUMBER_OF_TRACKS))
- else:
- newtracks = set( [ i for i in range(Config.NUMBER_OF_TRACKS) if self.trackSelected[i] ] )
- newpages = self.tuneInterface.getSelectedIds()
+ newpages = self.tuneInterface.getSelectedIds()
algo(
params,
@@ -532,17 +603,21 @@ class MainWindow( gtk.EventBox ):
note.pageId = page
note.trackId = track
- # add the new notes
+ # prepare the new notes
newnotes = []
for tid in dict:
for pid in dict[tid]:
newnotes += dict[tid][pid]
# delete the notes and add the new
+ if self.generateMode == "note":
+ print "TODO generateMode == note"
+ else: # track or page mode
+ self.noteDB.deleteNotesByTrack( newpages, newtracks )
+
stream = []
for page in newpages:
for track in newtracks:
- self.noteDB.deleteNotesByTrack( page, track )
stream += [ page, track, len(dict[track][page]) ]
stream += dict[track][page]
stream += [-1]
@@ -557,14 +632,96 @@ class MainWindow( gtk.EventBox ):
self.recompose( variate, params)
#=======================================================
+ # Clipboard Functions
+
+ def getClipboardArea( self, page = -1 ):
+ if page == -1: page = self.displayedPage
+ ids = self.tuneInterface.getSelectedIds()
+ return self.noteDB.getClipboardArea( ids.index(page) )
+
+ def pasteClipboard( self, offset, trackMap ):
+ pages = self.tuneInterface.getSelectedIds()
+ return self.noteDB.pasteClipboard( pages, offset, trackMap )
+
+ def cleanupClipboard( self ):
+ if self.GUI["2noteDuplicateButton"].get_active():
+ self.GUI["2noteDuplicateButton"].set_active(False)
+ if self.GUI["2trackDuplicateButton"].get_active():
+ self.GUI["2trackDuplicateButton"].set_active(False)
+ self.trackInterface.donePaste()
+
+
+ #=======================================================
+ # Note Functions
+
+ def noteGenerate( self ):
+ self.generateMode = "note"
+ self.generationParametersWindow.show_all()
+ return
+
+ def noteProperties( self ):
+ # TODO
+ return
+
+ def noteDelete( self ):
+ ids = self.trackInterface.getSelectedNotes()
+ stream = []
+ for t in range(Config.NUMBER_OF_TRACKS):
+ N = len(ids[t])
+ if not N: continue
+ stream += [ self.displayedPage, t, N ] + ids[t]
+ if len(stream):
+ self.noteDB.deleteNotes( stream + [-1] )
+
+ def noteDuplicate( self ):
+ ids = self.trackInterface.getSelectedNotes()
+ stream = []
+ for t in range(Config.NUMBER_OF_TRACKS):
+ N = len(ids[t])
+ if not N: continue
+ stream += [ self.displayedPage, t, N ] + ids[t]
+ if len(stream):
+ if self.GUI["2trackDuplicateButton"].get_active():
+ self.GUI["2trackDuplicateButton"].set_active( False )
+ self.noteDB.notesToClipboard( stream + [-1] )
+ self.trackInterface.setInterfaceMode("paste_notes")
+ return True
+ return False
+
+ def noteDuplicateWidget( self, widget ):
+ if widget.get_active():
+ if self.noteDuplicate(): # duplicate succeeded
+ return
+ # cancel duplicate
+ self.trackInterface.setInterfaceMode("tool")
+ widget.set_active(False)
+
+ def noteOnset( self, step ):
+ self.trackInterface.noteStepOnset( step )
+
+ def notePitch( self, step ):
+ # TODO
+ return
+
+ def noteDuration( self, step ):
+ # TODO
+ return
+
+ def noteVolume( self, step ):
+ # TODO
+ return
+
+ #=======================================================
# Track Functions
def toggleTrack( self, trackN, exclusive ):
if exclusive:
for i in range(Config.NUMBER_OF_TRACKS):
- self.trackSelected[i] = False
+ if self.trackSelected[i]:
+ self.trackSelected[i] = False
+ self.trackInterface.trackToggled( i )
self.trackSelected[trackN] = True
- self.trackInterface.trackToggled() # invalidate whole page
+ self.trackInterface.trackToggled( trackN )
self.setContextState( CONTEXT.TRACK, True )
self.setContext( CONTEXT.TRACK )
else:
@@ -577,27 +734,60 @@ class MainWindow( gtk.EventBox ):
return
self.setContextState( CONTEXT.TRACK, False )
+ def setTrack( self, trackN, state ):
+ if self.trackSelected[trackN] != state:
+ self.trackSelected[trackN] = state
+ self.trackInterface.trackToggled( trackN )
+
+ def clearTracks( self ):
+ for i in range(Config.NUMBER_OF_TRACKS):
+ if self.trackSelected[i]:
+ self.trackSelected[i]= False
+ self.trackInterface.trackToggled( i )
+
+ self.setContextState( CONTEXT.TRACK, False )
+
def getTrackSelected( self, trackN ):
return self.trackSelected[trackN]
- #=======================================================
- # NoteDB notifications
+ def trackGenerate( self ):
+ self.generateMode = "track"
+ self.generationParametersWindow.show_all()
- def notifyPageAdd( self, id, at ):
- self.displayPage( id )
+ def trackProperties( self, trackIds = -1 ):
+ # TODO
+ return
- def notifyPageDelete( self, which, safe ):
- if self.displayedPage in which:
- self.displayPage( safe )
+ def trackDelete( self, pageIds = -1, trackIds = -1 ):
- def notifyPageDuplicate( self, new, at ):
- self.displayPage( new[self.displayedPage] )
+ if pageIds == -1: pageIds = self.tuneInterface.getSelectedIds()
+ if trackIds == -1: trackIds = [ i for i in range(Config.NUMBER_OF_TRACKS) if self.trackSelected[i] ]
- def notifyPageMove( self, which, low, high ):
- return
+ self.noteDB.deleteNotesByTrack( pageIds, trackIds )
+
+ def trackDuplicate( self, pageIds = -1, trackIds = -1 ):
+
+ if pageIds == -1: pageIds = self.tuneInterface.getSelectedIds()
+ if trackIds == -1: trackIds = [ i for i in range(Config.NUMBER_OF_TRACKS) if self.trackSelected[i] ]
+
+ if len(trackIds):
+ if self.GUI["2noteDuplicateButton"].get_active():
+ self.GUI["2noteDuplicateButton"].set_active( False )
+ self.noteDB.tracksToClipboard( pageIds, trackIds )
+ self.trackInterface.setInterfaceMode("paste_tracks")
+ return True
+ return False
+
+ def trackDuplicateWidget( self, widget ):
+ if widget.get_active():
+ if self.trackDuplicate(): # duplicate succeeded
+ return
+ # cancel duplicate
+ self.trackInterface.setInterfaceMode("tool")
+ widget.set_active(False)
#-----------------------------------
- # tune functions
+ # tune/page functions
#-----------------------------------
def scrollTune( self, scroll ):
@@ -614,25 +804,63 @@ class MainWindow( gtk.EventBox ):
self.trackInterface.displayPage( pageId, nextId )
- def addPage( self, after = -1, beats = False ):
+ def predrawPage( self, pageId ):
+ if self.playbackTimeout: return # we're playing, predrawing is already handled
+ if self.trackInterface.setPredrawPage( pageId ): # page needs to be drawn
+ if not self.predrawTimeout:
+ self.predrawTimeout = gobject.timeout_add( 50, self.onPredrawTimeout )
- if after == -1: after = self.tuneInterface.getLastSelected()
- if not beats: beats = self.noteDB.getPage( self.displayedPage ).beats
+ def pageGenerate( self ):
+ self.generateMode = "page"
+ self.generationParametersWindow.show_all()
- self.noteDB.addPage( beats, after )
+ def pageProperties( self, pageIds = -1 ):
- def duplicatePages( self, after = -1, pageIds = False ):
+ if pageIds == -1: pageIds = self.tuneInterface.getSelectedIds()
+
+ # TODO show properties or something
+
+ def pageDelete( self, pageIds = -1 ):
+
+ if pageIds == -1: pageIds = self.tuneInterface.getSelectedIds()
+
+ self.noteDB.deletePages( pageIds )
+
+ def pageDuplicate( self, after = -1, pageIds = False ):
if after == -1: after = self.tuneInterface.getLastSelected()
if not pageIds: pageIds = self.tuneInterface.getSelectedIds()
self.noteDB.duplicatePages( pageIds, after )
- def removePages( self, pageIds = -1 ):
+ def pageAdd( self, after = -1, beats = False ):
+
+ if after == -1: after = self.tuneInterface.getLastSelected()
+ if not beats: beats = self.noteDB.getPage( self.displayedPage ).beats
+
+ self.noteDB.addPage( beats, after )
+
+ def pageBeats( self, pageIds = -1 ):
if pageIds == -1: pageIds = self.tuneInterface.getSelectedIds()
- self.noteDB.deletePages( pageIds )
+ # TODO change the beats
+
+ #=======================================================
+ # NoteDB notifications
+
+ def notifyPageAdd( self, id, at ):
+ self.displayPage( id )
+
+ def notifyPageDelete( self, which, safe ):
+ if self.displayedPage in which:
+ self.displayPage( safe )
+
+ def notifyPageDuplicate( self, new, at ):
+ self.displayPage( new[self.displayedPage] )
+
+ def notifyPageMove( self, which, low, high ):
+ return
#-----------------------------------
# load and save functions
diff --git a/Edit/NoteInterface.py b/Edit/NoteInterface.py
index 9dc9e43..25a160d 100644
--- a/Edit/NoteInterface.py
+++ b/Edit/NoteInterface.py
@@ -40,7 +40,11 @@ class NoteInterface:
self.updateParameter( None, None )
def destroy( self ):
- self.owner.invalidate_rect( self.imgX, self.imgY, self.imgWidth, self.imgHeight, self.note.page, True )
+ if self.selected:
+ print "destroy", self.note.id
+ self.owner.deselectNotes( { self.note.track: [self] } )
+ else: # if we were deselected above the rect has already been invalidated
+ self.owner.invalidate_rect( self.imgX, self.imgY, self.imgWidth, self.imgHeight, self.note.page, True )
def updateParameter( self, parameter, value ):
self.end = self.note.cs.onset + self.note.cs.duration
@@ -70,10 +74,14 @@ class NoteInterface:
return self.note.cs.pitch
def updateTransform( self ):
- if self.note.page == self.owner.curPage and not self.firstTransform:
- oldX = self.imgX
- oldY = self.imgY
- oldEndX = self.imgX + self.imgWidth
+ if self.note.page in self.owner.getActivePages():
+ if not self.firstTransform:
+ oldX = self.imgX
+ oldY = self.imgY
+ oldEndX = self.imgX + self.imgWidth
+ dirty = True
+ else:
+ dirty = False
if self.note.cs.onset != self.oldOnset:
self.x = self.owner.ticksToPixels( self.noteDB.getPage( self.note.page).beats, self.note.cs.onset )
@@ -89,15 +97,16 @@ class NoteInterface:
self.imgY = self.y - Config.NOTE_IMAGE_PADDING
self.oldPitch = self.note.cs.pitch
- if self.firstTransform:
- self.owner.invalidate_rect( self.imgX, self.imgY, self.imgWidth, self.imgHeight, self.note.page, True )
- self.firstTransform = False
- else:
- x = min( self.imgX, oldX )
- y = min( self.imgY, oldY )
- endx = max( self.imgX + self.imgWidth, oldEndX )
- endy = max( self.imgY, oldY ) + self.imgHeight
- self.owner.invalidate_rect( x, y, endx-x, endy-y, self.note.page, True )
+ if dirty:
+ if self.firstTransform:
+ self.owner.invalidate_rect( self.imgX, self.imgY, self.imgWidth, self.imgHeight, self.note.page, True )
+ self.firstTransform = False
+ else:
+ x = min( self.imgX, oldX )
+ y = min( self.imgY, oldY )
+ endx = max( self.imgX + self.imgWidth, oldEndX )
+ endy = max( self.imgY, oldY ) + self.imgHeight
+ self.owner.invalidate_rect( x, y, endx-x, endy-y, self.note.page, True )
def updateDragLimits( self, dragLimits, leftBound, rightBound, widthBound, maxRightBound ):
left = leftBound - self.note.cs.onset
@@ -187,24 +196,23 @@ class NoteInterface:
return True
- def noteDrag( self, emitter, do, dp, dd ):
- self.potentialDeselect = False
-
+ def noteDragOnset( self, do, stream ):
+ self. potentialDeselect = False
if do != self.lastDragO:
self.lastDragO = do
- self.noteDB.updateNote( self.note.page, self.note.track, self.note.id, PARAMETER.ONSET, self.baseOnset + do )
- self.end = self.note.cs.onset + self.note.cs.duration
+ stream += [ self.note.id, self.baseOnset + do ]
+ def noteDragPitch( self, dp, stream ):
+ self.potentialDeselect = False
if dp != self.lastDragP:
self.lastDragP = dp
- newPitch = self.basePitch + dp
- self.noteDB.updateNote( self.note.page, self.note.track, self.note.id, PARAMETER.PITCH, newPitch )
- self.updateSampleNote( newPitch )
+ stream += [ self.note.id, self.basePitch + dp ]
+ def noteDragDuration( self, dd, stream ):
+ self.potentialDeselect = False
if dd != self.lastDragD:
self.lastDragD = dd
- self.noteDB.updateNote( self.note.page, self.note.track, self.note.id, PARAMETER.DURATION, self.baseDuration + dd )
- self.end = self.note.cs.onset + self.note.cs.duration
+ stream += [ self.note.id, self.baseDuration + dd ]
def doneNoteDrag( self, emitter ):
self.baseOnset = self.note.cs.onset
@@ -217,6 +225,47 @@ class NoteInterface:
self.clearSampleNote()
+ def noteDecOnset( self, step, leftBound, stream ):
+ if self.selected:
+ if leftBound < self.note.cs.onset:
+ onset = max( self.note.cs.onset+step, leftBound )
+ stream += [ self.note.id, onset ]
+ return onset + self.note.cs.duration
+ return self.end
+
+ def noteIncOnset( self, step, rightBound, stream ):
+ if self.selected:
+ if rightBound > self.end:
+ onset = min( self.end+step, rightBound ) - self.note.cs.duration
+ stream += [ self.note.id, onset ]
+ return onset
+ return self.note.cs.onset
+
+ def noteDecPitch( self, step, stream ):
+ if self.note.cs.pitch > Config.MINIMUM_PITCH:
+ stream += [ self.note.id, max( self.note.cs.pitch+step, Config.MINIMUM_PITCH ) ]
+
+ def noteIncPitch( self, step, stream ):
+ if self.note.cs.pitch < Config.MAXIMUM_PITCH:
+ stream += [ self.note.id, min( self.note.cs.pitch+step, Config.MAXIMUM_PITCH ) ]
+
+ def noteDecDuration( self, step, stream ):
+ if self.note.cs.duration > Config.MINIMUM_NOTE_DURATION:
+ stream += [ self.note.id, max( self.note.cs.duration+step, Config.MINIMUM_NOTE_DURATION ) ]
+
+ def noteIncDuration( self, step, rightBound, stream ):
+ if self.selected:
+ if self.end < rightBound:
+ stream += [ self.note.id, min( self.end+step, rightBound ) - self.note.cs.onset ]
+
+ def noteDecVolume( self, step, stream ):
+ if self.note.cs.amplitude > 0:
+ stream += [ self.note.id, max( self.note.cs.amplitude+step, 0 ) ]
+
+ def noteIncVolume( self, step, stream ):
+ if self.note.cs.amplitude < 1:
+ stream += [ self.note.id, min( self.note.cs.amplitude+step, 1 ) ]
+
def handleMarqueeSelect( self, emitter, start, stop ):
intersectionY = [ max(start[1],self.y), min(stop[1],self.y+self.height) ]
if intersectionY[0] > intersectionY[1]:
diff --git a/Edit/TrackInterface.py b/Edit/TrackInterface.py
index a3b3986..a5b7593 100644
--- a/Edit/TrackInterface.py
+++ b/Edit/TrackInterface.py
@@ -3,12 +3,15 @@ pygtk.require( '2.0' )
import gtk
from math import floor
+import time
import Config
from Edit.NoteInterface import NoteInterface
from Edit.HitInterface import HitInterface
from Edit.MainWindow import CONTEXT
+from Util.NoteDB import PARAMETER
+
from Util.Profiler import TP
class SELECTNOTES:
@@ -22,7 +25,8 @@ class SELECTNOTES:
class INTERFACEMODE:
DEFAULT = 0
DRAW = 1
- PASTE = 2
+ PASTE_NOTES = 2
+ PASTE_TRACKS = 3
class TrackInterfaceParasite:
def __init__( self, noteDB, owner, note ):
@@ -66,15 +70,20 @@ class TrackInterface( gtk.EventBox ):
self.marqueeLoc = False # current drag location of the marquee
self.marqueeRect = [[0,0],[0,0]]
+ self.pasteTick = -1
+ self.pasteTrack = -1
+ self.pasteRect = False
+
self.playheadX = Config.TRACK_SPACING_DIV2
self.cursor = { \
"default": None, \
"drag-onset": gtk.gdk.Cursor(gtk.gdk.SB_RIGHT_ARROW), \
- "drag-pitch": gtk.gdk.Cursor(gtk.gdk.SB_V_DOUBLE_ARROW), \
- "drag-duration": gtk.gdk.Cursor(gtk.gdk.SB_H_DOUBLE_ARROW), \
- "drag-playhead": gtk.gdk.Cursor(gtk.gdk.LEFT_SIDE), \
+ "drag-pitch": gtk.gdk.Cursor(gtk.gdk.BOTTOM_SIDE), \
+ "drag-duration": gtk.gdk.Cursor(gtk.gdk.RIGHT_SIDE), \
+ "drag-playhead": gtk.gdk.Cursor(gtk.gdk.SB_H_DOUBLE_ARROW), \
"pencil": gtk.gdk.Cursor(gtk.gdk.PENCIL), \
+ "paste": gtk.gdk.Cursor(gtk.gdk.CENTER_PTR), \
"error": None }
self.add_events(gtk.gdk.POINTER_MOTION_MASK|gtk.gdk.POINTER_MOTION_HINT_MASK)
@@ -164,6 +173,16 @@ class TrackInterface( gtk.EventBox ):
self.curScreen = 0
self.preScreen = 1
+ #-- private --------------------------------------------
+
+ def _updateClipboardArea( self ):
+ self.clipboardArea = self.owner.getClipboardArea( self.curPage )
+ self.clipboardTrackTop = 0
+ for t in range(self.drumIndex):
+ if self.clipboardArea["tracks"][t]: break
+ self.clipboardTrackTop += 1
+ self.clipboardDrumTrack = self.clipboardArea["tracks"][self.drumIndex]
+
#=======================================================
# Module Interface
@@ -173,18 +192,32 @@ class TrackInterface( gtk.EventBox ):
else:
return ( self.image["note"], self.image["noteSelected"], self.drawingArea.get_colormap(), self.trackColors[track] )
- def predrawPage( self, page ):
+ def getActivePages( self ):
+ return self.screenBufPage
+
+ def setPredrawPage( self, page ):
if self.screenBufPage[self.preScreen] != page:
self.screenBufPage[self.preScreen] = page
self.screenBufBeats[self.preScreen] = self.noteDB.getPage(page).beats
self.invalidate_rect( 0, 0, self.width, self.height, page )
+ return True
+ return False
+
+ def predrawPage( self, timeout ):
+ return self.draw( self.preScreen, False, timeout )
def displayPage( self, page, predraw = -1 ):
- if page == self.curPage: return
+ if page == self.curPage:
+ if predraw >= 0 and self.screenBufPage[self.preScreen] != predraw:
+ self.screenBufPage[self.preScreen] = predraw
+ self.screenBufBeats[self.preScreen] = self.noteDB.getPage(predraw).beats
+ self.invalidate_rect( 0, 0, self.width, self.height, predraw )
+ return
if self.curPage >= 0 and self.curPage != page: clearNotes = True
else: clearNotes = False
+ oldPage = self.curPage
self.curPage = page
self.curBeats = self.noteDB.getPage(page).beats
@@ -202,23 +235,43 @@ class TrackInterface( gtk.EventBox ):
self.screenBufPage[self.preScreen] = predraw
self.screenBufBeats[self.preScreen] = self.noteDB.getPage(predraw).beats
self.invalidate_rect( 0, 0, self.width, self.height, predraw )
+ elif self.screenBufPage[self.preScreen] == -1: # make sure predraw is assigned to a valid page at least
+ self.screenBufPage[self.preScreen] = self.screenBufPage[self.curScreen]
if clearNotes: # clear the notes now that we've sorted out the screen buffers
- self.clearSelectedNotes()
+ self.clearSelectedNotes( oldPage )
+
+ if self.curAction == "paste":
+ self._updateClipboardArea()
def setPlayhead( self, ticks ):
self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height, self.curPage, False )
- self.playheadX = self.ticksToPixels( ticks, self.screenBufBeats[self.curScreen] ) + Config.TRACK_SPACING_DIV2
+ self.playheadX = self.ticksToPixels( self.curBeats, ticks ) + Config.TRACK_SPACING_DIV2
self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height, self.curPage, False )
def setInterfaceMode( self, mode ):
- if mode == "Draw":
+ self.doneCurrentAction()
+
+ if mode == "tool":
+ mode = self.owner.getTool()
+
+ if mode == "draw":
self.interfaceMode = INTERFACEMODE.DRAW
- elif mode == "Paste":
- self.interfaceMode = INTERFACEMODE.PASTE
+ elif mode == "paste_notes":
+ self.interfaceMode = INTERFACEMODE.PASTE_NOTES
+ self.setCurrentAction("paste", self)
+ elif mode == "paste_tracks":
+ self.interfaceMode = INTERFACEMODE.PASTE_TRACKS
+ self.setCurrentAction("paste", self )
else:
self.interfaceMode = INTERFACEMODE.DEFAULT
+ def getSelectedNotes( self ):
+ ids = []
+ for t in range(Config.NUMBER_OF_TRACKS):
+ ids.append( [ n.note.id for n in self.selectedNotes[t] ] )
+ return ids
+
#=======================================================
# Event Callbacks
@@ -226,7 +279,7 @@ class TrackInterface( gtk.EventBox ):
self.alloc = allocation
width = allocation.width
height = allocation.height
-
+
self.drawingArea.set_size_request( width, height )
if self.window != None:
@@ -242,6 +295,13 @@ class TrackInterface( gtk.EventBox ):
self.clickLoc = [ int(event.x), int(event.y) ]
+ if self.curAction == "paste":
+ self.doPaste()
+ self.setCurrentAction("block-track-select")
+ TP.ProfileEnd( "TI::handleButtonPress" )
+ return
+
+
# check if we clicked on the playhead
if event.x >= self.playheadX and event.x <= self.playheadX + Config.PLAYHEAD_SIZE:
self.setCurrentAction( "playhead-drag", self )
@@ -289,8 +349,9 @@ class TrackInterface( gtk.EventBox ):
if self.trackLimits[i][0] > event.y: break
if self.trackLimits[i][1] < event.y: continue
if event.button == 1:
- if self.buttonPressCount == 1: self.owner.toggleTrack( i, False )
- else: self.owner.toggleTrack( i, True )
+ if self.buttonPressCount == 1: self.owner.toggleTrack( i, False )
+ elif self.buttonPressCount == 2: self.owner.toggleTrack( i, True )
+ else: self.owner.clearTracks()
break
TP.ProfileEnd( "TI::handleButtonRelease" )
@@ -317,7 +378,6 @@ class TrackInterface( gtk.EventBox ):
def handleMotion( self, widget, event ):
TP.ProfileBegin( "TI::handleMotion::Common" )
-
if event.is_hint:
x, y, state = self.window.get_pointer()
event.x = float(x)
@@ -326,7 +386,17 @@ class TrackInterface( gtk.EventBox ):
TP.ProfileEnd( "TI::handleMotion::Common" )
- if event.state & gtk.gdk.BUTTON1_MASK:
+ if self.curAction == "paste":
+ TP.ProfileBegin( "TI::handleMotion::Paste" )
+ top = Config.NUMBER_OF_TRACKS
+ for i in range(Config.NUMBER_OF_TRACKS):
+ if self.trackLimits[i][0] > event.y: break
+ if self.trackLimits[i][1] < event.y: continue
+ top = i
+ break
+ self.updatePaste( self.pixelsToTicks( self.curBeats, event.x ), top )
+ TP.ProfileEnd( "TI::handleMotion::Paste" )
+ elif event.state & gtk.gdk.BUTTON1_MASK:
TP.ProfileBegin( "TI::handleMotion::Drag" )
if not self.curAction: # no action is in progress yet we're dragging, start a marquee
@@ -361,9 +431,9 @@ class TrackInterface( gtk.EventBox ):
#=======================================================
# Actions
- def setCurrentAction( self, action, obj ):
+ def setCurrentAction( self, action, obj = None ):
if self.curAction:
- print "BackgroundView - Action already in progress!"
+ self.doneCurrentAction()
self.curAction = action
self.curActionObject = obj
@@ -372,19 +442,25 @@ class TrackInterface( gtk.EventBox ):
elif action == "note-drag-duration": self.updateDragLimits()
elif action == "note-drag-pitch": self.updateDragLimits()
elif action == "note-drag-pitch-drum": self.updateDragLimits()
+ elif action == "paste":
+ self._updateClipboardArea()
+ self.setCursor("paste")
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()
- elif self.curAction == "note-drag-pitch-drum": self.doneNoteDrag()
-
+ if not self.curAction: return
+ action = self.curAction
self.curAction = False
- self.curActionObject = False
+
+ if action == "note-drag-onset": self.doneNoteDrag()
+ elif action == "note-drag-duration": self.doneNoteDrag()
+ elif action == "note-drag-pitch": self.doneNoteDrag()
+ elif action == "note-drag-pitch-drum": self.doneNoteDrag()
+ elif action == "paste":
+ self.owner.cleanupClipboard()
def trackToggled( self, trackN = -1 ):
- if trackN == -1: self.invalidate_rect( 0, 0, self.width, self.height, self.curPage )
- else: self.invalidate_rect( 0, self.trackLimits[trackN][0], self.width, self.trackLimits[trackN][1]-self.trackLimits[trackN][0], self.curPage )
+ if trackN == -1: self.invalidate_rect( 0, 0, self.width, self.height )
+ else: self.invalidate_rect( 0, self.trackLimits[trackN][0], self.width, self.trackLimits[trackN][1]-self.trackLimits[trackN][0] )
def selectionChanged( self ):
if self.curAction == "note-drag-onset": self.updateDragLimits()
@@ -398,14 +474,15 @@ class TrackInterface( gtk.EventBox ):
return
self.owner.setContextState( CONTEXT.NOTE, False )
- def applyNoteSelection( self, mode, trackN, which ):
+ def applyNoteSelection( self, mode, trackN, which, page = -1 ):
+ if page == -1: page = self.curPage
if mode == SELECTNOTES.ALL:
- track = self.noteDB.getNotesByTrack( self.curPage, trackN, self )
+ track = self.noteDB.getNotesByTrack( page, trackN, self )
map( lambda note:note.setSelected( True ), track )
self.selectedNotes[trackN] = []
map( lambda note:self.selectedNotes[trackN].append(note), track )
elif mode == SELECTNOTES.NONE:
- track = self.noteDB.getNotesByTrack( self.curPage, trackN, self )
+ track = self.noteDB.getNotesByTrack( page, trackN, self )
map( lambda note:note.setSelected( False ), track )
self.selectedNotes[trackN] = []
elif mode == SELECTNOTES.ADD:
@@ -425,7 +502,7 @@ class TrackInterface( gtk.EventBox ):
note.setSelected( True )
self.selectedNotes[trackN].append( note )
elif mode == SELECTNOTES.EXCLUSIVE:
- notes = self.noteDB.getNotesByTrack( self.curPage, trackN, self )
+ notes = self.noteDB.getNotesByTrack( page, trackN, self )
for n in range(len(notes)):
if notes[n] in which:
if notes[n].setSelected( True ):
@@ -434,51 +511,51 @@ class TrackInterface( gtk.EventBox ):
if notes[n].setSelected( False ):
self.selectedNotes[trackN].remove( notes[n] )
- def selectNotesByBar( self, trackN, start, stop ):
+ def selectNotesByBar( self, trackN, start, stop, page = -1 ):
for i in range(Config.NUMBER_OF_TRACKS):
if i == trackN:
notes = []
track = self.noteDB.getNotesByTrack( self.curPage, trackN, self )
for n in range(len(track)):
if track[n].testOnset( start, stop ): notes.append(track[n])
- if not Config.ModKeys.ctrlDown: self.applyNoteSelection( SELECTNOTES.EXCLUSIVE, trackN, notes )
- else: self.applyNoteSelection( SELECTNOTES.ADD, trackN, notes )
+ if not Config.ModKeys.ctrlDown: self.applyNoteSelection( SELECTNOTES.EXCLUSIVE, trackN, notes, page )
+ else: self.applyNoteSelection( SELECTNOTES.ADD, trackN, notes, page )
else:
- if not Config.ModKeys.ctrlDown: self.applyNoteSelection( SELECTNOTES.NONE, i, [] )
+ if not Config.ModKeys.ctrlDown: self.applyNoteSelection( SELECTNOTES.NONE, i, [], page )
self.selectionChanged()
- def selectNotesByTrack( self, trackN ):
+ def selectNotesByTrack( self, trackN, page = -1 ):
if Config.ModKeys.ctrlDown:
- self.applyNoteSelection( SELECTNOTES.ALL, trackN, [] )
+ self.applyNoteSelection( SELECTNOTES.ALL, trackN, [], page )
else:
for i in range(Config.NUMBER_OF_TRACKS):
- if i == trackN: self.applyNoteSelection( SELECTNOTES.ALL, trackN, [] )
- else: self.applyNoteSelection( SELECTNOTES.NONE, i, [] )
+ if i == trackN: self.applyNoteSelection( SELECTNOTES.ALL, trackN, [], page )
+ else: self.applyNoteSelection( SELECTNOTES.NONE, i, [], page )
self.selectionChanged()
- def selectNotes( self, noteDic ):
- if Config.ModKeys.ctrlDown:
+ def selectNotes( self, noteDic, ignoreCtrl = False, page = -1 ):
+ if Config.ModKeys.ctrlDown and not ignoreCtrl:
for i in noteDic:
- self.applyNoteSelection( SELECTNOTES.FLIP, i, noteDic[i] )
+ self.applyNoteSelection( SELECTNOTES.FLIP, i, noteDic[i], page )
else:
for i in range(Config.NUMBER_OF_TRACKS):
- if i in noteDic: self.applyNoteSelection( SELECTNOTES.EXCLUSIVE, i, noteDic[i] )
- else: self.applyNoteSelection( SELECTNOTES.NONE, i, [] )
+ if i in noteDic: self.applyNoteSelection( SELECTNOTES.EXCLUSIVE, i, noteDic[i], page )
+ else: self.applyNoteSelection( SELECTNOTES.NONE, i, [], page )
self.selectionChanged()
- def deselectNotes( self, noteDic ):
+ def deselectNotes( self, noteDic, page = -1 ):
for i in noteDic:
- self.applyNoteSelection( SELECTNOTES.REMOVE, i, noteDic[i] )
+ self.applyNoteSelection( SELECTNOTES.REMOVE, i, noteDic[i], page )
self.selectionChanged()
- def clearSelectedNotes( self ):
+ def clearSelectedNotes( self, page = -1 ):
for i in range(Config.NUMBER_OF_TRACKS):
- self.applyNoteSelection( SELECTNOTES.NONE, i, [] )
+ self.applyNoteSelection( SELECTNOTES.NONE, i, [], page )
self.selectionChanged()
def updateDragLimits( self ):
self.dragLimits = [ [-9999,9999], [-9999,9999], [-9999,9999] ] # initialize to big numbers!
- maxRightBound = self.curBeats * Config.TICKS_PER_BEAT
+ maxRightBound = self.noteDB.getPage(self.curPage).ticks
for i in range(Config.NUMBER_OF_TRACKS):
if not len(self.selectedNotes[i]): continue # no selected notes here
@@ -510,39 +587,133 @@ class TrackInterface( gtk.EventBox ):
def noteDragOnset( self, event ):
do = self.pixelsToTicks( self.curBeats, event.x - self.clickLoc[0] )
do = min( self.dragLimits[0][1], max( self.dragLimits[0][0], do ) )
- dp = 0
- dd = 0
+ stream = []
for i in range(Config.NUMBER_OF_TRACKS):
+ tstream = []
for note in self.selectedNotes[i]:
- note.noteDrag(self, do, dp, dd)
+ note.noteDragOnset( do, tstream )
+ if len(tstream):
+ stream += [ self.curPage, i, PARAMETER.ONSET, len(tstream)//2 ] + tstream
+ if len(stream):
+ self.noteDB.updateNotes( stream + [-1] )
def noteDragDuration( self, event ):
- do = 0
- dp = 0
dd = self.pixelsToTicks( self.curBeats, event.x - self.clickLoc[0] )
dd = min( self.dragLimits[2][1], max( self.dragLimits[2][0], dd ) )
+ stream = []
for i in range(Config.NUMBER_OF_TRACKS):
+ tstream = []
for note in self.selectedNotes[i]:
- note.noteDrag(self, do, dp, dd)
+ note.noteDragDuration( dd, tstream )
+ if len(tstream):
+ stream += [ self.curPage, i, PARAMETER.DURATION, len(tstream)//2 ] + tstream
+ if len(stream):
+ self.noteDB.updateNotes( stream + [-1] )
def noteDragPitch( self, event, drum = False ):
- do = 0
if not drum: dp = self.pixelsToPitch( event.y - self.clickLoc[1] )
else: dp = self.pixelsToPitchDrum( event.y - self.clickLoc[1] )
dp = min( self.dragLimits[1][1], max( self.dragLimits[1][0], dp ) )
- dd = 0
+ stream = []
for i in range(Config.NUMBER_OF_TRACKS):
+ tstream = []
for note in self.selectedNotes[i]:
- note.noteDrag(self, do, dp, dd)
+ note.noteDragPitch( dp, tstream )
+ if len(tstream):
+ stream += [ self.curPage, i, PARAMETER.PITCH, len(tstream)//2 ] + tstream
+ if len(stream):
+ self.noteDB.updateNotes( stream + [-1] )
def doneNoteDrag( self ):
for i in range(Config.NUMBER_OF_TRACKS):
for note in self.selectedNotes[i]:
note.doneNoteDrag( self )
+ def noteStepOnset( self, step ):
+ stream = []
+ for i in range(Config.NUMBER_OF_TRACKS):
+ if not len(self.selectedNotes[i]): continue # no selected notes here
+
+ tstream = []
+ track = self.noteDB.getNotesByTrack( self.curPage, i, self )
+ if step < 0: # moving to the left, iterate forwards
+ leftBound = 0
+ for n in range(len(track)):
+ leftBound = track[n].noteDecOnset( step, leftBound, tstream )
+ else: # moving to the right, iterate backwards
+ rightBound = self.noteDB.getPage(self.curPage).ticks
+ for n in range(len(track)-1, -1, -1 ):
+ rightBound = track[n].noteIncOnset( step, rightBound, tstream )
+
+ if len(tstream):
+ stream += [ self.curPage, i, PARAMETER.ONSET, len(tstream)//2 ] + tstream
+
+ if len(stream):
+ self.noteDB.updateNotes( stream + [-1] )
+
+ def noteStepPitch( self, step ):
+ stream = []
+ for i in range(Config.NUMBER_OF_TRACKS):
+ if not len(self.selectedNotes[i]): continue # no selected notes here
+
+ tstream = []
+ if step < 0:
+ for n in self.selectedNotes[i]:
+ n.noteDecPitch( step, tstream )
+ else:
+ for n in self.selectedNotes[i]:
+ n.noteIncPitch( step, tstream )
+
+ if len(tstream):
+ stream += [ self.curPage, i, PARAMETER.PITCH, len(tstream)//2 ] + tstream
+
+ if len(stream):
+ self.noteDB.updateNotes( stream + [-1] )
+
+ def noteStepDuration( self, step ):
+ stream = []
+ for i in range(Config.NUMBER_OF_TRACKS):
+ if not len(self.selectedNotes[i]): continue # no selected notes here
+
+ tstream = []
+ if step < 0:
+ for n in self.selectedNotes[i]:
+ n.noteDecDuration( step, tstream )
+ else:
+ track = self.noteDB.getNotesByTrack( self.curPage, i, self )
+ for j in range(len(track)-1):
+ track[j].noteIncDuration( step, track[j+1].getStartTick(), tstream )
+ track[len(track)-1].noteIncDuration( step, self.noteDB.getPage(self.curPage).ticks, tstream )
+
+ if len(tstream):
+ stream += [ self.curPage, i, PARAMETER.DURATION, len(tstream)//2 ] + tstream
+
+ if len(stream):
+ self.noteDB.updateNotes( stream + [-1] )
+
+ def noteStepVolume( self, step ):
+ stream = []
+ for i in range(Config.NUMBER_OF_TRACKS):
+ if not len(self.selectedNotes[i]): continue # no selected notes here
+
+ tstream = []
+ if step < 0:
+ for n in self.selectedNotes[i]:
+ n.noteDecVolume( step, tstream )
+ else:
+ for n in self.selectedNotes[i]:
+ n.noteIncVolume( step, tstream )
+
+ if len(tstream):
+ stream += [ self.curPage, i, PARAMETER.AMPLITUDE, len(tstream)//2 ] + tstream
+
+ if len(stream):
+ self.noteDB.updateNotes( stream + [-1] )
+
+
def updateMarquee( self, event ):
if self.marqueeLoc:
oldX = self.marqueeRect[0][0]
@@ -616,6 +787,79 @@ class TrackInterface( gtk.EventBox ):
print "set playhead to %d ticks" % (ticks)
self.doneCurrentAction()
+ def updatePaste( self, tick, track ):
+ if self.interfaceMode == INTERFACEMODE.PASTE_TRACKS: tick = 0
+ if self.pasteTick == tick and self.pasteTrack == track: return
+ if self.noteDB.getPage(self.curPage).ticks < tick < 0 \
+ or track > self.drumIndex \
+ or ( track == self.drumIndex and not self.clipboardDrumTrack ):
+ if self.pasteRect:
+ self.invalidate_rect( self.pasteRect[0][0], self.pasteRect[0][1], self.pasteRect[1][0], self.pasteRect[1][1], self.curPage, False )
+ self.pasteTick = self.pasteTrack = -1
+ self.pasteRect = False
+ return
+ if self.pasteRect:
+ self.invalidate_rect( self.pasteRect[0][0], self.pasteRect[0][1], self.pasteRect[1][0], self.pasteRect[1][1], self.curPage, False )
+ if self.clipboardDrumTrack:
+ bottom = self.drumIndex
+ else:
+ bottom = self.drumIndex - 1
+ for t in range(self.drumIndex-1,self.clipboardTrackTop-1,-1):
+ if self.clipboardArea["tracks"][t]: break
+ bottom -= 1
+ end = -tick + min( self.noteDB.getPage(self.curPage).ticks, tick + self.clipboardArea["limit"][1]-self.clipboardArea["limit"][0] )
+ self.pasteTick = tick
+ self.pasteTrack = track
+ self.pasteRect = [ [ self.ticksToPixels( self.curBeats, tick ), \
+ self.trackLimits[track][0] ], \
+ [ self.ticksToPixels( self.curBeats, end), \
+ self.trackLimits[bottom][1] ] ]
+ self.invalidate_rect( self.pasteRect[0][0], self.pasteRect[0][1], self.pasteRect[1][0], self.pasteRect[1][1], self.curPage, False )
+
+ def doPaste( self ):
+ if self.pasteTrack == -1:
+ self.doneCurrentAction()
+ return
+
+ trackMap = {}
+ for t in range(self.pasteTrack,self.drumIndex):
+ ind = t+self.clipboardTrackTop-self.pasteTrack
+ if ind >= self.drumIndex: break
+ if not self.clipboardArea["tracks"][ind]:
+ continue
+ trackMap[t] = ind
+ if self.clipboardDrumTrack:
+ trackMap[self.drumIndex] = self.drumIndex
+ new = self.owner.pasteClipboard( self.pasteTick - self.clipboardArea["limit"][0], trackMap )
+ if self.interfaceMode == INTERFACEMODE.PASTE_NOTES and self.curPage in new:
+ noteDic = {}
+ for t in range(Config.NUMBER_OF_TRACKS):
+ if len(new[self.curPage][t]):
+ noteDic[t] = [ self.noteDB.getNote( self.curPage, t, n, self ) for n in new[self.curPage][t] ]
+ self.selectNotes(noteDic)
+ elif self.interfaceMode == INTERFACEMODE.PASTE_TRACKS:
+ for t in range(self.drumIndex):
+ ind = t + self.clipboardTrackTop - self.pasteTrack
+ if ind >= self.drumIndex or ind < 0: self.owner.setTrack( t, False )
+ else: self.owner.setTrack( t, self.clipboardArea["tracks"][ind] )
+ self.owner.setTrack( self.drumIndex, self.clipboardDrumTrack )
+
+ self.doneCurrentAction()
+
+ def donePaste( self ):
+ if self.pasteRect:
+ self.invalidate_rect( self.pasteRect[0][0], self.pasteRect[0][1], self.pasteRect[1][0], self.pasteRect[1][1], self.curPage, False )
+ self.pasteTick = self.pasteTrack = -1
+ self.pasteRect = False
+ self.setInterfaceMode("tool")
+ # make a fake event for updateTooltip
+ event = gtk.gdk.Event(gtk.gdk.MOTION_NOTIFY)
+ x, y, state = self.window.get_pointer()
+ event.x = float(x)
+ event.y = float(y)
+ event.state = state
+ self.updateTooltip( event )
+
def updateTooltip( self, event ):
# check clicked the playhead
@@ -654,8 +898,10 @@ class TrackInterface( gtk.EventBox ):
#=======================================================
# Drawing
- def predraw( self, buf, noescape = True ):
- TP.ProfileBegin( "TrackInterface::predraw" )
+ def draw( self, buf, noescape = True, timeout = 0 ):
+ if not self.screenBufDirty[buf]: return True
+
+ TP.ProfileBegin( "TrackInterface::draw" )
startX = self.screenBufDirtyRect[buf].x
startY = self.screenBufDirtyRect[buf].y
@@ -675,7 +921,7 @@ class TrackInterface( gtk.EventBox ):
self.gc.set_line_attributes( Config.BEAT_LINE_SIZE, gtk.gdk.LINE_ON_OFF_DASH, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER )
# regular tracks
for i in range( resume[0], self.drumIndex ):
- if resume[0] == 0:
+ if resume[1] == 0:
if startY > self.trackLimits[i][1]: continue
if stopY < self.trackLimits[i][0]: break
@@ -691,28 +937,30 @@ class TrackInterface( gtk.EventBox ):
x = beatStart + j*beatSpacing
pixmap.draw_line( self.gc, x, self.trackRect[i].y, x, self.trackRect[i].y+self.trackRect[i].height )
+ resume[1] = 1 # background drawn
+
# draw notes
TP.ProfileBegin("TI::draw notes")
- notes = self.noteDB.getNotesByTrack( self.curPage, i, self )
- for n in range( resume[1], len(notes) ):
+ notes = self.noteDB.getNotesByTrack( self.screenBufPage[buf], i, self )
+ for n in range( resume[2], len(notes) ):
# check escape
- if 0:
+ if not noescape and time.time() > timeout:
resume[0] = i
- resume[1] = n
- TP.ProfilePause( "TrackInterface::predraw" )
+ resume[2] = n
+ TP.ProfilePause( "TrackInterface::draw" )
return False
if not notes[n].draw( pixmap, self.gc, startX, stopX ): break
TP.ProfileEnd("TI::draw notes")
# finished a track, reset the resume values for the next one
- resume[0] = 0
resume[1] = 0
+ resume[2] = 0
# drum track
if stopY > self.trackLimits[self.drumIndex][0]:
- if resume[0] == 0:
+ if resume[1] == 0:
# draw background
if self.owner.getTrackSelected( self.drumIndex ):
pixmap.draw_drawable( self.gc, self.image["trackBGDrumSelected"], 0, 0, 0, self.trackLimits[self.drumIndex][0], self.trackFullWidth, self.trackFullHeightDrum )
@@ -725,27 +973,29 @@ class TrackInterface( gtk.EventBox ):
x = beatStart + j*beatSpacing
pixmap.draw_line( self.gc, x, self.trackRect[self.drumIndex].y, x, self.trackRect[self.drumIndex].y+self.trackRect[self.drumIndex].height )
+ resume[1] = 1 # background drawn
+
# draw notes
- notes = self.noteDB.getNotesByTrack( self.curPage, self.drumIndex, self )
- for n in range( resume[1], len(notes) ):
+ notes = self.noteDB.getNotesByTrack( self.screenBufPage[buf], self.drumIndex, self )
+ for n in range( resume[2], len(notes) ):
# check escape
- if 0:
+ if not noescape and time.time() > timeout:
resume[0] = i
- resume[1] = n
- TP.ProfilePause( "TrackInterface::predraw" )
+ resume[2] = n
+ TP.ProfilePause( "TrackInterface::draw" )
return False
if not notes[n].draw( pixmap, self.gc, startX, stopX ): break
self.screenBufDirty[buf] = False
- TP.ProfileEnd( "TrackInterface::predraw" )
+ TP.ProfileEnd( "TrackInterface::draw" )
return True
def expose( self, DA, event ):
if self.screenBufDirty[self.curScreen]:
- self.predraw( self.curScreen )
+ self.draw( self.curScreen )
TP.ProfileBegin( "TrackInterface::expose" )
@@ -771,11 +1021,23 @@ class TrackInterface( gtk.EventBox ):
self.gc.foreground = self.marqueeColor
DA.window.draw_rectangle( self.gc, False, self.marqueeRect[0][0], self.marqueeRect[0][1], self.marqueeRect[1][0], self.marqueeRect[1][1] )
+ if self.pasteRect: # draw the paste highlight
+ self.gc.set_function( gtk.gdk.INVERT )
+ for t in range(self.pasteTrack,self.drumIndex):
+ ind = t+self.clipboardTrackTop-self.pasteTrack
+ if ind >= self.drumIndex: break
+ if not self.clipboardArea["tracks"][ind]:
+ continue
+ DA.window.draw_rectangle( self.gc, True, self.pasteRect[0][0], self.trackLimits[t][0] + Config.TRACK_SPACING_DIV2, self.pasteRect[1][0], self.trackHeight )
+ if self.clipboardDrumTrack:
+ DA.window.draw_rectangle( self.gc, True, self.pasteRect[0][0], self.trackLimits[self.drumIndex][0] + Config.TRACK_SPACING_DIV2, self.pasteRect[1][0], self.trackHeightDrum )
+ self.gc.set_function( gtk.gdk.COPY )
+
self.drawingAreaDirty = False
TP.ProfileEnd( "TrackInterface::expose" )
- def invalidate_rect( self, x, y, width, height, page, base = True ):
+ def invalidate_rect( self, x, y, width, height, page = -1, base = True ):
#print "%d %d %d %d Page %d CurPage %d" % (x,y,width,height,page,self.curPage)
self.dirtyRectToAdd.x = x
self.dirtyRectToAdd.y = y
@@ -783,7 +1045,7 @@ class TrackInterface( gtk.EventBox ):
self.dirtyRectToAdd.height = height
#print "dirty %d %d %d %d %d %d" % (x, y, width, height, x+width, y+height)
- if page == self.curPage:
+ if page == self.curPage or page == -1:
if base: # the base image has been dirtied
if not self.screenBufDirty[self.curScreen]:
self.screenBufDirtyRect[self.curScreen].x = x
@@ -792,13 +1054,13 @@ class TrackInterface( gtk.EventBox ):
self.screenBufDirtyRect[self.curScreen].height = height
else:
self.screenBufDirtyRect[self.curScreen] = self.screenBufDirtyRect[self.curScreen].union( self.dirtyRectToAdd )
- self.screenBufResume[self.curScreen] = [0,0]
+ self.screenBufResume[self.curScreen] = [0,0,0]
self.screenBufDirty[self.curScreen] = True
if self.drawingArea.window != None:
self.drawingArea.window.invalidate_rect( self.dirtyRectToAdd, True )
self.drawingAreaDirty = True
- elif page == self.screenBufPage[self.preScreen]:
+ if page == self.screenBufPage[self.preScreen] or page == -1:
if not self.screenBufDirty[self.preScreen]:
self.screenBufDirtyRect[self.preScreen].x = x
self.screenBufDirtyRect[self.preScreen].y = y
@@ -806,7 +1068,7 @@ class TrackInterface( gtk.EventBox ):
self.screenBufDirtyRect[self.preScreen].height = height
else:
self.screenBufDirtyRect[self.preScreen] = self.screenBufDirtyRect[self.preScreen].union( self.dirtyRectToAdd )
- self.screenBufResume[self.preScreen] = [0,0]
+ self.screenBufResume[self.preScreen] = [0,0,0]
self.screenBufDirty[self.preScreen] = True
#self.queue_draw()
diff --git a/Edit/TuneInterface.py b/Edit/TuneInterface.py
index e6790b9..d1d5481 100644
--- a/Edit/TuneInterface.py
+++ b/Edit/TuneInterface.py
@@ -58,6 +58,8 @@ class TuneInterface( gtk.EventBox ):
self.dragMode = None
self.dropAt = -1
+ self.add_events(gtk.gdk.POINTER_MOTION_MASK|gtk.gdk.POINTER_MOTION_HINT_MASK)
+
self.connect( "size-allocate", self.size_allocated )
self.drawingArea.connect( "expose-event", self.draw )
self.connect( "button-press-event", self.handleButtonPress )
@@ -90,15 +92,23 @@ class TuneInterface( gtk.EventBox ):
def handleButtonPress( self, widget, event ):
ind = int(event.x-self.pageOffset)//self.pageSpacing
if ind >= self.noteDB.getPageCount():
- self.dragMode = self.DRAG_BLOCK
+ if self.dragMode != self.DRAG_MOVE:
+ self.dragMode = self.DRAG_BLOCK
return
if ind < 0: ind = 0
-
+
self.clickX = event.x
id = self.noteDB.getPageByIndex( ind )
-
- if event.type == gtk.gdk._2BUTTON_PRESS: # double click -> exclusive select
+
+ if event.state & gtk.gdk.BUTTON2_MASK:
+ # bring up properties or something
+ return
+
+ if event.type == gtk.gdk._3BUTTON_PRESS: # triple click -> select all
+ self.selectAll()
+ self.owner.displayPage( id )
+ elif event.type == gtk.gdk._2BUTTON_PRESS: # double click -> exclusive select
self.selectPage( id )
self.owner.displayPage( id )
else:
@@ -120,38 +130,54 @@ class TuneInterface( gtk.EventBox ):
self.owner.setContext( CONTEXT.PAGE )
def handleButtonRelease( self, widget, event ):
-
- if self.dragMode == self.DRAG_MOVE:
+ if self.dragMode == self.DRAG_MOVE \
+ and event.button == 1:
self.invalidate_rect( 0, 0, self.width, self.height ) # drop head
if self.dropAt > 0: after = self.noteDB.getPageByIndex( self.dropAt-1 )
else: after = False
self.noteDB.movePages( self.selectedIds, after )
+
self.dropAt = -1
- self.dragMode = None
+ self.dragMode = None
def handleMotion( self, widget, event ):
- if Config.ModKeys.ctrlDown and (self.dragMode == None or self.dragMode == self.DRAG_MOVE):
- self.dropAt = -1
- self.dragMode = self.DRAG_SELECT
-
- if self.dragMode == self.DRAG_SELECT: # select on drag
- ind = int(event.x-self.pageOffset)//self.pageSpacing
- if ind < self.noteDB.getPageCount(): self.selectPage( self.noteDB.getPageByIndex(ind), False )
- elif self.dragMode == self.DRAG_DESELECT: # deselect on drag
+ if event.is_hint:
+ x, y, state = self.window.get_pointer()
+ event.x = float(x)
+ event.y = float(y)
+ event.state = state
+
+ if event.state & gtk.gdk.BUTTON1_MASK: # clicking
+ if Config.ModKeys.ctrlDown and (self.dragMode == None or self.dragMode == self.DRAG_MOVE):
+ self.dropAt = -1
+ self.dragMode = self.DRAG_SELECT
+
+ if self.dragMode == self.DRAG_SELECT: # select on drag
+ ind = int(event.x-self.pageOffset)//self.pageSpacing
+ if ind < self.noteDB.getPageCount(): self.selectPage( self.noteDB.getPageByIndex(ind), False )
+ elif self.dragMode == self.DRAG_DESELECT: # deselect on drag
+ ind = int(event.x-self.pageOffset)//self.pageSpacing
+ if ind < self.noteDB.getPageCount(): self.deselectPage( self.noteDB.getPageByIndex(ind) )
+ elif self.dragMode == None and abs(self.clickX-event.x) > 20: # drag and drop
+ self.dragMode = self.DRAG_MOVE
+
+ if self.dragMode == self.DRAG_MOVE:
+ self.dropAt = int(event.x-self.pageOffset+Config.PAGE_THUMBNAIL_WIDTH_DIV2)//self.pageSpacing
+ c = self.noteDB.getPageCount()
+ if self.dropAt > c: self.dropAt = c
+ self.invalidate_rect( 0, 0, self.width, self.height )
+
+ else: # hovering
ind = int(event.x-self.pageOffset)//self.pageSpacing
- if ind < self.noteDB.getPageCount(): self.deselectPage( self.noteDB.getPageByIndex(ind) )
- elif self.dragMode == None and abs(self.clickX-event.x) > 20: # drag and drop
- self.dragMode = self.DRAG_MOVE
+ if 0 <= ind < self.noteDB.getPageCount():
+ id = self.noteDB.getPageByIndex(ind)
+ if id != self.displayedPage:
+ self.owner.predrawPage( id )
- if self.dragMode == self.DRAG_MOVE:
- self.dropAt = int(event.x-self.pageOffset+Config.PAGE_THUMBNAIL_WIDTH_DIV2)//self.pageSpacing
- c = self.noteDB.getPageCount()
- if self.dropAt > c: self.dropAt = c
- self.invalidate_rect( 0, 0, self.width, self.height )
def displayPage( self, id, scroll ):
if self.displayedPage == id: return -1
@@ -160,12 +186,12 @@ class TuneInterface( gtk.EventBox ):
if id not in self.selectedIds:
self.selectPage( id )
-
+
ind = self.noteDB.getPageIndex( id )
-
+
startX = self.pageOffset + ind*self.pageSpacing
stopX = startX + self.pageSpacing
-
+
self.invalidate_rect( 0, 0, self.width, self.height )
if scroll > startX: scroll = startX
@@ -176,7 +202,7 @@ class TuneInterface( gtk.EventBox ):
return -1
else:
scroll = stopX - self.baseWidth
-
+
return scroll
def selectPage( self, id, exclusive = True ):
@@ -213,11 +239,14 @@ class TuneInterface( gtk.EventBox ):
return True # page removed from the selection
+ def selectAll( self ):
+ self.selectedIds = self.noteDB.getTune()[:]
+ self.invalidate_rect( 0, 0, self.width, self.height )
+
def clearSelection( self ):
self.selectedIds = []
-
self.invalidate_rect( 0, 0, self.width, self.height )
-
+
def getSelectedIds( self ):
return self.selectedIds
@@ -249,7 +278,7 @@ class TuneInterface( gtk.EventBox ):
# Drawing
def draw( self, drawingArea, event ):
-
+
startX = event.area.x
startY = event.area.y
stopX = event.area.x + event.area.width