Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Edit/TrackInterface.py
diff options
context:
space:
mode:
authoramartin <olpc@localhost.localdomain>2007-01-16 08:32:18 (GMT)
committer amartin <olpc@localhost.localdomain>2007-01-16 08:32:18 (GMT)
commit1c5de0188ba5bf675d872ea6e73f29ef38b63bf5 (patch)
tree5c80c7666daa367f85db9b44ce0e01e68b608ddc /Edit/TrackInterface.py
parent20c60d6a435599dad56e97b0ce9d7efc6f02c4d4 (diff)
TrackInterface screen buffers
Diffstat (limited to 'Edit/TrackInterface.py')
-rw-r--r--Edit/TrackInterface.py213
1 files changed, 160 insertions, 53 deletions
diff --git a/Edit/TrackInterface.py b/Edit/TrackInterface.py
index 4522c0b..ddf9472 100644
--- a/Edit/TrackInterface.py
+++ b/Edit/TrackInterface.py
@@ -139,6 +139,17 @@ class TrackInterface( gtk.EventBox ):
self.pitchPerPixel = float(Config.NUMBER_OF_POSSIBLE_PITCHES-1) / (self.trackHeight - Config.NOTE_HEIGHT)
self.pixelsPerPitch = float(self.trackHeight-Config.NOTE_HEIGHT)/(Config.MAXIMUM_PITCH - Config.MINIMUM_PITCH)
+
+ # screen buffers
+ self.screenBuf = [ gtk.gdk.Pixmap( win, self.width, self.height ), \
+ gtk.gdk.Pixmap( win, self.width, self.height ) ]
+ self.screenBufPage = [ -1, -1 ]
+ self.screenBufDirtyRect = [ gtk.gdk.Rectangle(), gtk.gdk.Rectangle() ]
+ self.screenBufDirty = [ False, False ]
+ self.screenBufResume = [ [0,0], [0,0] ] # allows for stopping and restarting in the middle of a draw
+ self.curScreen = 0
+ self.preScreen = 1
+
#=======================================================
# Module Interface
@@ -210,14 +221,36 @@ class TrackInterface( gtk.EventBox ):
if self.note[page][i][j] == None: del self.note[page][i][j]
j -= 1
self.updateNoteMap( page )
+
+ def predrawPage( self, page ):
+ if self.screenBufPage[self.preScreen] != page:
+ self.screenBufPage[self.preScreen] = page
+ self.invalidate_rect( 0, 0, self.width, self.height, page )
- def displayPage( self, page, beatCount ):
+ def displayPage( self, page, beatCount, predraw = -1 ):
if page == self.curPage and self.beatCount == beatCount: return
- if self.curPage >= 0 and self.curPage != page: self.clearSelectedNotes()
+ if self.curPage >= 0 and self.curPage != page: clearNotes = True
+ else: clearNotes = False
self.curPage = page
+ if self.screenBufPage[self.preScreen] == self.curPage: # we predrew this page, so smart!
+ t = self.preScreen
+ self.preScreen = self.curScreen
+ self.curScreen = t
+ self.invalidate_rect( 0, 0, self.width, self.height, self.curPage, False )
+ else: # we need to draw this page from scratch
+ self.screenBufPage[self.curScreen] = self.curPage
+ self.invalidate_rect( 0, 0, self.width, self.height, self.curPage )
+
+ if predraw >= 0 and self.screenBufPage[self.preScreen] != predraw:
+ self.screenBufPage[self.preScreen] = predraw
+ self.invalidate_rect( 0, 0, self.width, self.height, predraw )
+
+ if clearNotes: # clear the notes now that we've sorted out the screen buffers
+ self.clearSelectedNotes()
+
if page not in self.note: # create a blank page if the page doesn't already exist
self.note[page] = []
for i in range(Config.NUMBER_OF_TRACKS):
@@ -241,12 +274,12 @@ class TrackInterface( gtk.EventBox ):
map( lambda note:note.updateTransform( True ), track )
if self.window != None:
- self.invalidate_rect( 0, 0, self.fullWidth, self.height )
+ self.invalidate_rect( 0, 0, self.fullWidth, self.height, self.curPage )
def setPlayhead( self, ticks ):
- self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height )
+ self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height, self.curPage, False )
self.playheadX = self.ticksToPixels( ticks ) + Config.TRACK_SPACING_DIV2
- self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height )
+ self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height, self.curPage, False )
def getSelectedTracks( self ):
r = []
@@ -272,7 +305,7 @@ class TrackInterface( gtk.EventBox ):
self.drawingArea.set_size_request( width, height )
if self.window != None:
- self.invalidate_rect( 0, 0, width, height )
+ self.invalidate_rect( 0, 0, width, height, self.curPage, False )
def handleButtonPress( self, widget, event ):
@@ -420,10 +453,10 @@ class TrackInterface( gtk.EventBox ):
for i in range(Config.NUMBER_OF_TRACKS):
self.trackSelected[i] = False
self.trackSelected[trackN] = True
- self.invalidate_rect( 0, 0, self.width, self.height )
+ self.invalidate_rect( 0, 0, self.width, self.height, self.curPage )
else:
self.trackSelected[trackN] = not self.trackSelected[trackN]
- self.invalidate_rect( 0, self.trackLimits[trackN][0], self.width, self.trackLimits[trackN][1]-self.trackLimits[trackN][0] )
+ self.invalidate_rect( 0, self.trackLimits[trackN][0], self.width, self.trackLimits[trackN][1]-self.trackLimits[trackN][0], self.curPage )
def selectionChanged( self ):
if self.curAction == "note-drag-onset": self.updateDragLimits()
@@ -605,7 +638,7 @@ class TrackInterface( gtk.EventBox ):
width = max( self.marqueeRect[0][0] + self.marqueeRect[1][0], oldEndX ) - x
y = min( self.marqueeRect[0][1], oldY )
height = max( self.marqueeRect[0][1] + self.marqueeRect[1][1], oldEndY ) - y
- self.invalidate_rect( x-1, y-1, width+2, height+2 )
+ self.invalidate_rect( x-1, y-1, width+2, height+2, self.curPage, False )
def doneMarquee( self, event ):
if self.marqueeLoc:
@@ -633,7 +666,7 @@ class TrackInterface( gtk.EventBox ):
self.marqueeLoc = False
self.doneCurrentAction()
- self.invalidate_rect( self.marqueeRect[0][0]-1, self.marqueeRect[0][1]-1, self.marqueeRect[1][0]+2, self.marqueeRect[1][1]+2 )
+ self.invalidate_rect( self.marqueeRect[0][0]-1, self.marqueeRect[0][1]-1, self.marqueeRect[1][0]+2, self.marqueeRect[1][1]+2, self.curPage, False )
def updatePlayhead( self, event ):
x = min( self.trackWidth - self.pixelsPerTick, max( Config.TRACK_SPACING_DIV2, event.x ) )
@@ -683,60 +716,109 @@ class TrackInterface( gtk.EventBox ):
#=======================================================
# Drawing
+
+ def predraw( self, buf, noescape = True ):
+ TP.ProfileBegin( "TrackInterface::predraw" )
- def expose( self, DA, event ):
- TP.ProfileBegin( "TrackInterface::draw" )
+ startX = self.screenBufDirtyRect[buf].x
+ startY = self.screenBufDirtyRect[buf].y
+ stopX = self.screenBufDirtyRect[buf].x + self.screenBufDirtyRect[buf].width
+ stopY = self.screenBufDirtyRect[buf].y + self.screenBufDirtyRect[buf].height
- startX = event.area.x
- startY = event.area.y
- stopX = event.area.x + event.area.width
- stopY = event.area.y + event.area.height
-
- #print "%d %d %d %d" % (startX,startY,stopX,stopY)
+ pixmap = self.screenBuf[buf]
+
+ resume = self.screenBufResume[buf]
+
+ self.gc.set_clip_rectangle( self.screenBufDirtyRect[buf] )
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( self.drumIndex ):
- if startY > self.trackLimits[i][1]: continue
- if stopY < self.trackLimits[i][0]: break
-
- # draw background
- if self.trackSelected[i]:
- DA.window.draw_drawable( self.gc, self.image["trackBGSelected"], 0, 0, 0, self.trackLimits[i][0], self.trackFullWidth, self.trackFullHeight )
- else:
- DA.window.draw_drawable( self.gc, self.image["trackBG"], 0, 0, 0, self.trackLimits[i][0], self.trackFullWidth, self.trackFullHeight )
+ for i in range( resume[0], self.drumIndex ):
+ if resume[0] == 0:
+ if startY > self.trackLimits[i][1]: continue
+ if stopY < self.trackLimits[i][0]: break
+
+ # draw background
+ if self.trackSelected[i]:
+ pixmap.draw_drawable( self.gc, self.image["trackBGSelected"], 0, 0, 0, self.trackLimits[i][0], self.trackFullWidth, self.trackFullHeight )
+ else:
+ pixmap.draw_drawable( self.gc, self.image["trackBG"], 0, 0, 0, self.trackLimits[i][0], self.trackFullWidth, self.trackFullHeight )
- # draw beat lines
- self.gc.foreground = self.beatColor
- beatStart = Config.TRACK_SPACING_DIV2
- for j in range(1,self.beatCount):
- x = beatStart + j*self.beatSpacing
- DA.window.draw_line( self.gc, x, self.trackRect[i].y, x, self.trackRect[i].y+self.trackRect[i].height )
+ # draw beat lines
+ self.gc.foreground = self.beatColor
+ beatStart = Config.TRACK_SPACING_DIV2
+ for j in range(1,self.beatCount):
+ x = beatStart + j*self.beatSpacing
+ pixmap.draw_line( self.gc, x, self.trackRect[i].y, x, self.trackRect[i].y+self.trackRect[i].height )
# draw notes
notes = self.note[self.curPage][i]
- for n in range(len(notes)):
- if not notes[n].draw( DA.window, self.gc, startX, stopX ): break
-
+ for n in range( resume[1], len(notes) ):
+ # check escape
+ if 0:
+ resume[0] = i
+ resume[1] = n
+ TP.ProfilePause( "TrackInterface::predraw" )
+ return False
+
+ if not notes[n].draw( pixmap, self.gc, startX, stopX ): break
+
+ # finished a track, reset the resume values for the next one
+ resume[0] = 0
+ resume[1] = 0
+
# drum track
if stopY > self.trackLimits[self.drumIndex][0]:
- # draw background
- if self.trackSelected[self.drumIndex]:
- DA.window.draw_drawable( self.gc, self.image["trackBGDrumSelected"], 0, 0, 0, self.trackLimits[self.drumIndex][0], self.trackFullWidth, self.trackFullHeightDrum )
- else:
- DA.window.draw_drawable( self.gc, self.image["trackBGDrum"], 0, 0, 0, self.trackLimits[self.drumIndex][0], self.trackFullWidth, self.trackFullHeightDrum )
+
+ if resume[0] == 0:
+ # draw background
+ if self.trackSelected[self.drumIndex]:
+ pixmap.draw_drawable( self.gc, self.image["trackBGDrumSelected"], 0, 0, 0, self.trackLimits[self.drumIndex][0], self.trackFullWidth, self.trackFullHeightDrum )
+ else:
+ pixmap.draw_drawable( self.gc, self.image["trackBGDrum"], 0, 0, 0, self.trackLimits[self.drumIndex][0], self.trackFullWidth, self.trackFullHeightDrum )
- # draw beat lines
- self.gc.foreground = self.beatColor
- beatStart = Config.TRACK_SPACING_DIV2
- for j in range(1,self.beatCount):
- x = beatStart + j*self.beatSpacing
- DA.window.draw_line( self.gc, x, self.trackRect[self.drumIndex].y, x, self.trackRect[self.drumIndex].y+self.trackRect[self.drumIndex].height )
+ # draw beat lines
+ self.gc.foreground = self.beatColor
+ beatStart = Config.TRACK_SPACING_DIV2
+ for j in range(1,self.beatCount):
+ x = beatStart + j*self.beatSpacing
+ pixmap.draw_line( self.gc, x, self.trackRect[self.drumIndex].y, x, self.trackRect[self.drumIndex].y+self.trackRect[self.drumIndex].height )
# draw notes
notes = self.note[self.curPage][self.drumIndex]
- for n in range(len(notes)):
- if not notes[n].draw( DA.window, self.gc, startX, stopX ): break
+ for n in range( resume[1], len(notes) ):
+ # check escape
+ if 0:
+ resume[0] = i
+ resume[1] = n
+ TP.ProfilePause( "TrackInterface::predraw" )
+ return False
+ if not notes[n].draw( pixmap, self.gc, startX, stopX ): break
+
+ self.screenBufDirty[buf] = False
+
+ TP.ProfileEnd( "TrackInterface::predraw" )
+
+ return True
+
+ def expose( self, DA, event ):
+
+ if self.screenBufDirty[self.curScreen]:
+ self.predraw( self.curScreen )
+
+ TP.ProfileBegin( "TrackInterface::expose" )
+
+ startX = event.area.x
+ startY = event.area.y
+ stopX = event.area.x + event.area.width
+ stopY = event.area.y + event.area.height
+
+ self.gc.set_clip_rectangle( event.area )
+
+ #print "%d %d %d %d" % (startX,startY,stopX,stopY)
+
+ # draw base
+ DA.window.draw_drawable( self.gc, self.screenBuf[self.curScreen], startX, startY, startX, startY, event.area.width, event.area.height )
# draw playhead
self.gc.set_line_attributes( Config.PLAYHEAD_SIZE, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER )
@@ -750,15 +832,40 @@ class TrackInterface( gtk.EventBox ):
self.drawingAreaDirty = False
- TP.ProfileEnd( "TrackInterface::draw" )
+ TP.ProfileEnd( "TrackInterface::expose" )
- def invalidate_rect( self, x, y, width, height ):
+ def invalidate_rect( self, x, y, width, height, page, base = True ):
self.dirtyRectToAdd.x = x
self.dirtyRectToAdd.y = y
self.dirtyRectToAdd.width = width
self.dirtyRectToAdd.height = height
- self.drawingArea.window.invalidate_rect( self.dirtyRectToAdd, True )
- self.drawingAreaDirty = True
+
+ if page == self.curPage:
+ if base: # the base image has been dirtied
+ if not self.screenBufDirty[self.curScreen]:
+ self.screenBufDirtyRect[self.curScreen].x = x
+ self.screenBufDirtyRect[self.curScreen].y = y
+ self.screenBufDirtyRect[self.curScreen].width = width
+ 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.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 not self.screenBufDirty[self.preScreen]:
+ self.screenBufDirtyRect[self.preScreen].x = x
+ self.screenBufDirtyRect[self.preScreen].y = y
+ self.screenBufDirtyRect[self.preScreen].width = width
+ 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.screenBufDirty[self.preScreen] = True
+
#self.queue_draw()
def getTrackOrigin( self, track ):