Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Edit/TuneInterface.py
diff options
context:
space:
mode:
authoramartin <olpc@localhost.localdomain>2007-02-20 05:01:20 (GMT)
committer amartin <olpc@localhost.localdomain>2007-02-20 05:01:20 (GMT)
commit09b31158f45345d586fd48ec349aebf00a676e08 (patch)
treeb95fb13d963f3113cad64cf1cd8b19f4c444589e /Edit/TuneInterface.py
parentaea628ad8d2b592bdbb149f3c562f031cd1bba22 (diff)
tuneInteface (2nd try, fu git)
Diffstat (limited to 'Edit/TuneInterface.py')
-rw-r--r--Edit/TuneInterface.py409
1 files changed, 332 insertions, 77 deletions
diff --git a/Edit/TuneInterface.py b/Edit/TuneInterface.py
index ce61dd3..8d705a3 100644
--- a/Edit/TuneInterface.py
+++ b/Edit/TuneInterface.py
@@ -7,22 +7,73 @@ import Config
from Util.Profiler import TP
from Edit.MainWindow import CONTEXT
+from Util.NoteDB import PARAMETER
+
class TuneInterfaceParasite:
def __init__( self, noteDB, owner, note ):
- self.parasite = self
self.noteDB = noteDB
self.owner = owner
self.note = note
+ self.x = self.y = self.width = -1
+
def attach( self ):
+ self.updateParameter( None, None )
return self
def destroy( self ):
- return
+ self.owner.invalidate_thumbnail( self.note.page, self.x, self.y, self.width, 1 )
def updateParameter( self, parameter, value ):
- return
+ if parameter == PARAMETER.AMPLITUDE: return
+ x = 2 + Config.THUMBNAIL_TRACK_RECT[self.note.track][0] + self.owner.ticksToPixels( self.noteDB.getPage( self.note.page).beats, self.note.cs.onset )
+ if self.note.track == Config.NUMBER_OF_TRACKS-1: # drum track
+ y = Config.THUMBNAIL_TRACK_RECT[self.note.track][1] + self.owner.pitchToPixelsDrum( self.note.cs.pitch )
+ if x != self.x or y != self.y:
+ if parameter != None: # not the first update
+ xx = min( self.x, x )
+ yy = min( self.y, y )
+ endxx = max( self.endx, x + 1 )
+ endyy = max( self.y, y ) + 1
+ self.x = x
+ self.endx = x + 1
+ self.y = y
+ self.owner.invalidate_thumbnail( self.note.page, xx, yy, endxx-xx, endyy-yy )
+ else:
+ self.x = x
+ self.endx = x + 1
+ self.y = y
+ self.owner.invalidate_thumbnail( self.note.page, x, y, 1, 1 )
+ else:
+ y = Config.THUMBNAIL_TRACK_RECT[self.note.track][1] + self.owner.pitchToPixels( self.note.cs.pitch )
+ width = max( 1, self.owner.ticksToPixels( self.noteDB.getPage( self.note.page).beats, self.note.cs.duration ) )
+ if x != self.x or y != self.y or width != self.width:
+ if parameter != None: # not the first update
+ xx = min( self.x, x )
+ yy = min( self.y, y )
+ endxx = max( self.endx, x + width )
+ endyy = max( self.y, y ) + 1
+ self.x = x
+ self.endx = x + width
+ self.y = y
+ self.width = width
+ self.owner.invalidate_thumbnail( self.note.page, xx, yy, endxx-xx, endyy-yy )
+ else:
+ self.x = x
+ self.endx = x + width
+ self.y = y
+ self.width = width
+ self.owner.invalidate_thumbnail( self.note.page, x, y, width, 1 )
+
+ def draw( self, win, gc, startX, stopX ):
+ if stopX < self.x: return False # we don't need to draw and no one after us will draw
+ if startX > self.endx: return True # we don't need to draw, but maybe a later note does
+
+ win.draw_line( gc, self.x, self.y, self.endx, self.y )
+
+ return True # we drew something
+
class TuneInterface( gtk.EventBox ):
@@ -31,11 +82,14 @@ class TuneInterface( gtk.EventBox ):
DRAG_DESELECT = 2
DRAG_MOVE = 3
- def __init__( self, noteDB, owner ):
+ def __init__( self, noteDB, owner, adjustment ):
gtk.EventBox.__init__( self )
self.noteDB = noteDB
self.owner = owner
+ self.adjustment = adjustment
+ #adjustment.connect( "changed", self.adjustmentChanged )
+ adjustment.connect( "value-changed", self.adjustmentValue )
self.drawingArea = gtk.DrawingArea()
self.drawingAreaDirty = False # is the drawingArea waiting to draw?
@@ -45,6 +99,61 @@ class TuneInterface( gtk.EventBox ):
self.selectedIds = []
self.displayedPage = -1
+ self.drumIndex = Config.NUMBER_OF_TRACKS-1
+
+ self.trackRect = Config.THUMBNAIL_TRACK_RECT
+ self.thumbnail = {}
+ self.thumbnailDirty = {}
+ self.thumbnailDirtyRect = {}
+ self.defaultwin = gtk.gdk.get_default_root_window() # used when creating pixmaps
+ self.gc = gtk.gdk.GC( self.defaultwin )
+ colormap = self.drawingArea.get_colormap()
+ self.bgColor = colormap.alloc_color( Config.BG_COLOR, True, True )
+ self.lineColor = colormap.alloc_color( Config.THUMBNAIL_DRAG_COLOR, True, True )
+ self.trackColor = colormap.alloc_color( Config.THUMBNAIL_TRACK_COLOR, True, True )
+ self.displayedColor = colormap.alloc_color( Config.THUMBNAIL_DISPLAYED_COLOR, True, True )
+ self.selectedColor = colormap.alloc_color( Config.THUMBNAIL_SELECTED_COLOR, True, True )
+
+ # prepare thumbnail
+ pix = gtk.gdk.pixbuf_new_from_file( Config.IMAGE_ROOT+"pageThumbnailBG.png" )
+ self.thumbnailBG = gtk.gdk.Pixmap( self.defaultwin, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ self.gc.foreground = self.bgColor
+ self.thumbnailBG.draw_rectangle( self.gc, True, 0, 0, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ self.thumbnailBG.draw_pixbuf( self.gc, pix, 0, 0, 0, 0, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT, gtk.gdk.RGB_DITHER_NONE )
+
+ # load clipmask
+ pix = gtk.gdk.pixbuf_new_from_file(Config.IMAGE_ROOT+'pageThumbnailMask.png')
+ pixels = pix.get_pixels()
+ stride = pix.get_rowstride()
+ channels = pix.get_n_channels()
+ bitmap = ""
+ byte = 0
+ shift = 0
+ for j in range(pix.get_height()):
+ offset = stride*j
+ for i in range(pix.get_width()):
+ if pixels[i*channels+offset] != "\0":
+ byte += 1 << shift
+ shift += 1
+ if shift > 7:
+ bitmap += "%c" % byte
+ byte = 0
+ shift = 0
+ if shift:
+ bitmap += "%c" % byte
+ byte = 0
+ shift = 0
+ self.clipMask = gtk.gdk.bitmap_create_from_data( None, bitmap, pix.get_width(), pix.get_height() )
+ self.clearMask = gtk.gdk.Rectangle( 0, 0, 1200, 800 )
+
+ self.pageOffset = 5 # offset the first page by this
+ self.dropWidth = 5 # line thickness of the drop head
+ self.dropWidthDIV2 = self.dropWidth//2
+
+ self.pixelsPerPitch = float(self.trackRect[0][3]-1)/(Config.MAXIMUM_PITCH - Config.MINIMUM_PITCH)
+ self.pixelsPerPitchDrum = float(self.trackRect[self.drumIndex][3]-1)/(Config.MAXIMUM_PITCH_DRUM - Config.MINIMUM_PITCH_DRUM )
+ self.pixelsPerTick = [0] + [ float(self.trackRect[0][2]-4)/(i*Config.TICKS_PER_BEAT) for i in range(1,Config.MAXIMUM_BEATS+1) ]
+
self.alloced = False
self.width = self.baseWidth = self.height = -1
self.waitingForAlloc = True
@@ -52,11 +161,14 @@ class TuneInterface( gtk.EventBox ):
self.clickX = -1
self.set_size_request( self.width, self.height )
- self.pageSpacing = Config.PAGE_THUMBNAIL_WIDTH + Config.PAGE_THUMBNAIL_PADDING_MUL2
- self.pageOffset = Config.PAGE_THUMBNAIL_PADDING + Config.PAGE_THUMBNAIL_PADDING_DIV2
+ self.button1Down = False
self.dragMode = None
self.dropAt = -1
+ self.dropAtX = 0
+
+ self.visibleX = 0
+ self.visibleEndX = 0
self.add_events(gtk.gdk.POINTER_MOTION_MASK|gtk.gdk.POINTER_MOTION_HINT_MASK)
@@ -69,23 +181,30 @@ class TuneInterface( gtk.EventBox ):
def size_allocated( self, widget, allocation ):
if not self.alloced:
self.baseWidth = allocation.width
+ self.visibleEndX = self.baseWidth
self.baseHeight = allocation.height
self.alloced = True
self.width = allocation.width
self.height = allocation.height
self.drawingArea.set_size_request( self.width, self.height )
+ self.clearMask.height = self.height
+ self.clearMask.width = self.width
self.pageY = (self.height-Config.PAGE_THUMBNAIL_HEIGHT)//2
if self.scrollTo >= 0:
- self.owner.scrollTune( self.scrollTo )
+ self.adjustment.set_value( self.scrollTo )
self.scrollTo = -1
self.waitingForAlloc = False
+ def adjustmentValue( self, adj ):
+ self.visibleX = int(adj.value)
+ self.visibleEndX = self.visibleX + self.baseWidth
+
def updateSize( self ):
if not self.alloced: return
- width = self.noteDB.getPageCount()*(Config.PAGE_THUMBNAIL_WIDTH + Config.PAGE_THUMBNAIL_PADDING_MUL2) + Config.PAGE_THUMBNAIL_PADDING_MUL2
+ width = self.pageOffset + self.noteDB.getPageCount()*Config.PAGE_THUMBNAIL_WIDTH
self.waitingForAlloc = True
self.set_size_request( max( self.baseWidth, width), -1 )
@@ -94,7 +213,11 @@ class TuneInterface( gtk.EventBox ):
# bring up properties or something
return
- ind = int(event.x-self.pageOffset)//self.pageSpacing
+ self.button1Down = True
+
+ self.owner.abortPredrawPage()
+
+ ind = int(event.x-self.pageOffset)//Config.PAGE_THUMBNAIL_WIDTH
if ind >= self.noteDB.getPageCount():
if self.dragMode != self.DRAG_MOVE:
self.dragMode = self.DRAG_BLOCK
@@ -116,25 +239,31 @@ class TuneInterface( gtk.EventBox ):
if id in self.selectedIds: # ctrl click, selected page -> remove page from selection
if self.deselectPage( id ):
self.dragMode = self.DRAG_DESELECT
+ self.dragLastInd = ind
else:
self.dragMode = self.DRAG_SELECT # special case, they clicked on the last selected page and it wasn't deselected
- else: # ctrl click, unselected page -> add page to selection (but don't display it)
+ self.dragLastInd = ind
+ else: # ctrl click, unselected page -> add page to selection (but don't display it)
self.selectPage( id, False )
self.dragMode = self.DRAG_SELECT
+ self.dragLastInd = ind
elif id in self.selectedIds: # click, selected page -> display this page but don't change the selection
self.owner.displayPage( id )
else: # click, unselected page -> exclusive select
self.selectPage( id )
self.owner.displayPage( id )
+
self.owner.setContext( CONTEXT.PAGE )
def handleButtonRelease( self, widget, event ):
if event.button != 1:
return
+ self.button1Down = False
+
if self.dragMode == self.DRAG_MOVE:
- self.invalidate_rect( 0, 0, self.width, self.height ) # drop head
+ self.invalidate_rect( self.dropAtX - self.dropWidthDIV2, 0, self.dropWidth, self.height ) # drop head
if self.dropAt > 0: after = self.noteDB.getPageByIndex( self.dropAt-1 )
else: after = False
@@ -143,7 +272,7 @@ class TuneInterface( gtk.EventBox ):
self.dropAt = -1
- self.dragMode = None
+ self.dragMode = None
def handleMotion( self, widget, event ):
@@ -153,37 +282,78 @@ class TuneInterface( gtk.EventBox ):
event.y = float(y)
event.state = state
- if event.state & gtk.gdk.BUTTON1_MASK: # clicking
+ if self.button1Down: # clicking
if Config.ModKeys.ctrlDown and (self.dragMode == None or self.dragMode == self.DRAG_MOVE):
self.dropAt = -1
self.dragMode = self.DRAG_SELECT
+ if event.x >= self.pageOffset: ind = int(event.x-self.pageOffset)//Config.PAGE_THUMBNAIL_WIDTH
+ else: ind = 0
+ self.dragLastInd = ind
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 )
+ if event.x > self.pageOffset: ind = int(event.x-self.pageOffset)//Config.PAGE_THUMBNAIL_WIDTH
+ else: ind = 0
+ pageCount = self.noteDB.getPageCount()
+ if ind >= pageCount: ind = pageCount-1
+ for i in range( min(ind,self.dragLastInd), max(ind,self.dragLastInd)+1):
+ self.selectPage( self.noteDB.getPageByIndex(i), False )
+ self.dragLastInd = ind
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) )
+ if event.x > self.pageOffset: ind = int(event.x-self.pageOffset)//Config.PAGE_THUMBNAIL_WIDTH
+ else: ind = 0
+ pageCount = self.noteDB.getPageCount()
+ if ind >= pageCount: ind = pageCount-1
+ for i in range( min(ind,self.dragLastInd), max(ind,self.dragLastInd)+1):
+ self.deselectPage( self.noteDB.getPageByIndex(i) )
+ self.dragLastInd = 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
+ if self.dropAt >= 0: lastX = self.dropAtX
+ else: lastX = -1
+ if event.x > self.pageOffset: self.dropAt = int(event.x-self.pageOffset+Config.PAGE_THUMBNAIL_WIDTH_DIV2)//Config.PAGE_THUMBNAIL_WIDTH
+ else: self.dropAt = 0
c = self.noteDB.getPageCount()
if self.dropAt > c: self.dropAt = c
- self.invalidate_rect( 0, 0, self.width, self.height )
+ self.dropAtX = self.pageOffset + self.dropAt*Config.PAGE_THUMBNAIL_WIDTH - self.dropWidthDIV2 - 1
+ if lastX >= 0 and lastX != self.dropAtX:
+ if lastX < self.dropAtX:
+ x = lastX - self.dropWidthDIV2
+ w = self.dropAtX - lastX + self.dropWidth
+ else:
+ x = self.dropAtX - self.dropWidthDIV2
+ w = lastX - self.dropAtX + self.dropWidth
+ self.invalidate_rect( x, 0, w, self.height )
+ elif lastX == -1:
+ self.invalidate_rect( self.dropAtX-self.dropWidthDIV2, 0, self.dropWidth, self.height )
else: # hovering
- ind = int(event.x-self.pageOffset)//self.pageSpacing
+ ind = int(event.x-self.pageOffset)//Config.PAGE_THUMBNAIL_WIDTH
if 0 <= ind < self.noteDB.getPageCount():
id = self.noteDB.getPageByIndex(ind)
if id != self.displayedPage:
self.owner.predrawPage( id )
- def displayPage( self, id, scroll ):
+ def trackToggled( self, i ):
+ self.invalidate_rect( self.visibleX, 0, self.baseWidth, self.height )
+
+ def displayPage( self, id ):
if self.displayedPage == id: return -1
+ if self.displayedPage != -1:
+ ind = self.noteDB.getPageIndex( self.displayedPage )
+ self.invalidate_rect( self.pageOffset + ind*Config.PAGE_THUMBNAIL_WIDTH, 0, Config.PAGE_THUMBNAIL_WIDTH, self.height )
+
+ if not self.thumbnail.has_key( id ):
+ # premptive add
+ self.thumbnail[id] = gtk.gdk.Pixmap( self.defaultwin, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ self.thumbnailDirtyRect[id] = gtk.gdk.Rectangle( 0, 0, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ self.thumbnailDirty[id] = True
+ self.selectPage( id )
+ self.updateSize()
+
self.displayedPage = id
if id not in self.selectedIds:
@@ -191,21 +361,23 @@ class TuneInterface( gtk.EventBox ):
ind = self.noteDB.getPageIndex( id )
- startX = self.pageOffset + ind*self.pageSpacing
- stopX = startX + self.pageSpacing
+ startX = self.pageOffset + ind*Config.PAGE_THUMBNAIL_WIDTH
+ stopX = startX + Config.PAGE_THUMBNAIL_WIDTH
- self.invalidate_rect( 0, 0, self.width, self.height )
+ self.invalidate_rect( startX, 0, Config.PAGE_THUMBNAIL_WIDTH, self.height )
- if scroll > startX: scroll = startX
- elif scroll + self.baseWidth < stopX:
- scroll = stopX - self.baseWidth
+ if self.adjustment.value > startX:
+ scroll = startX + Config.PAGE_THUMBNAIL_WIDTH + Config.PAGE_THUMBNAIL_WIDTH_DIV2 - self.baseWidth
+ if scroll < 0: scroll = 0
+ self.adjustment.set_value( scroll )
+ elif self.adjustment.value + self.baseWidth < stopX:
+ scroll = startX - Config.PAGE_THUMBNAIL_WIDTH_DIV2
+ if scroll + self.baseWidth > self.width:
+ scroll = stopX - self.baseWidth
if self.waitingForAlloc:
self.scrollTo = scroll
- return -1
else:
- scroll = stopX - self.baseWidth
-
- return scroll
+ self.adjustment.set_value( scroll )
def selectPage( self, id, exclusive = True ):
if exclusive: self.selectedIds = []
@@ -221,7 +393,7 @@ class TuneInterface( gtk.EventBox ):
self.selectedIds.insert( i, id )
- self.invalidate_rect( 0, 0, self.width, self.height )
+ self.invalidate_rect( self.pageOffset + ind*Config.PAGE_THUMBNAIL_WIDTH, 0, Config.PAGE_THUMBNAIL_WIDTH, self.height )
return True # page added to selection
@@ -237,17 +409,18 @@ class TuneInterface( gtk.EventBox ):
else: self.owner.displayPage( self.selectedIds[i-1] )
self.selectedIds.remove( id )
- self.invalidate_rect( 0, 0, self.width, self.height )
+ ind = self.noteDB.getPageIndex( id )
+ self.invalidate_rect( self.pageOffset + ind*Config.PAGE_THUMBNAIL_WIDTH, 0, Config.PAGE_THUMBNAIL_WIDTH, self.height )
return True # page removed from the selection
def selectAll( self ):
self.selectedIds = self.noteDB.getTune()[:]
- self.invalidate_rect( 0, 0, self.width, self.height )
+ self.invalidate_rect( self.visibleX, 0, self.baseWidth, self.height )
def clearSelection( self ):
self.selectedIds = []
- self.invalidate_rect( 0, 0, self.width, self.height )
+ self.invalidate_rect( self.visibleX, 0, self.baseWidth, self.height )
def getSelectedIds( self ):
return self.selectedIds
@@ -259,26 +432,67 @@ class TuneInterface( gtk.EventBox ):
# NoteDB notifications
def notifyPageAdd( self, id, at ):
- self.selectPage( id )
- self.updateSize()
+ if not self.thumbnail.has_key(id):
+ self.thumbnail[id] = gtk.gdk.Pixmap( self.defaultwin, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ self.thumbnailDirtyRect[id] = gtk.gdk.Rectangle( 0, 0, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ self.thumbnailDirty[id] = True
+ self.selectPage( id )
+ self.updateSize()
def notifyPageDelete( self, which, safe ):
for id in self.selectedIds:
if id in which: self.deselectPage( id, True )
+ for id in which:
+ del self.thumbnail[id]
+ del self.thumbnailDirtyRect[id]
+ del self.thumbnailDirty[id]
self.updateSize()
def notifyPageDuplicate( self, new, at ):
self.clearSelection()
- for k in new.keys():
- self.selectPage( new[k], False )
+ for id in new:
+ self.thumbnail[new[id]] = gtk.gdk.Pixmap( self.defaultwin, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ self.thumbnailDirtyRect[new[id]] = gtk.gdk.Rectangle( 0, 0, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ self.thumbnailDirty[new[id]] = True
+ self.selectPage( new[id], False )
self.updateSize()
def notifyPageMove( self, which, low, high ):
- self.invalidate_rect( 0, 0, self.width, self.height )
+ self.invalidate_rect( self.visibleX, 0, self.baseWidth, self.height )
#=======================================================
# Drawing
+ def drawThumbnail( self, id, pixmap, rect ):
+ startX = rect.x
+ startY = rect.y
+ stopX = rect.x + rect.width
+ stopY = rect.y + rect.height
+
+ # draw background
+ pixmap.draw_drawable( self.gc, self.thumbnailBG, startX, startY, startX, startY, rect.width, rect.height+1 )
+
+ # draw regular tracks
+ self.gc.foreground = self.lineColor
+ self.gc.set_line_attributes( 1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER )
+ for i in range(self.drumIndex):
+ if startY >= self.trackRect[i+1][1]: continue
+ if stopY < self.trackRect[i][1]: break
+
+ # draw notes
+ notes = self.noteDB.getNotesByTrack( id, i, self )
+ for n in range( len(notes) ):
+ if not notes[n].draw( pixmap, self.gc, startX, stopX ): break
+ # drum track
+ if stopY > self.trackRect[self.drumIndex][0]:
+ # draw notes
+ notes = self.noteDB.getNotesByTrack( id, self.drumIndex, self )
+ for n in range( len(notes) ):
+ if not notes[n].draw( pixmap, self.gc, startX, stopX ): break
+
+ self.thumbnailDirty[id] = False
+
+
def draw( self, drawingArea, event ):
startX = event.area.x
@@ -286,56 +500,97 @@ class TuneInterface( gtk.EventBox ):
stopX = event.area.x + event.area.width
stopY = event.area.y + event.area.height
- 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!?
- context.set_line_width( 2 )
-
- context.move_to( 0, 0 )
- context.rel_line_to( self.width, 0 )
- context.rel_line_to( 0, self.height )
- context.rel_line_to( -self.width, 0 )
- context.close_path()
+ # draw bg for pageOffset
+ self.gc.foreground = self.bgColor
+ drawingArea.window.draw_rectangle( self.gc, True, 0, 0, self.pageOffset, Config.PAGE_THUMBNAIL_HEIGHT )
- #draw background
- context.set_source_rgb( 0.75, 0.05, 0.0 )
- context.fill_preserve()
+ tracks = [ self.owner.getTrackSelected(i) for i in range(Config.NUMBER_OF_TRACKS) ]
# draw pages
- x = Config.PAGE_THUMBNAIL_PADDING_MUL2 # double padding on first page!
- l = len(self.selectedIds)
- j = 0
+ self.gc.set_clip_mask( self.clipMask )
+
+ x = self.pageOffset
+ endx = x + Config.PAGE_THUMBNAIL_WIDTH
for pageId in self.noteDB.getTune():
- if pageId == self.displayedPage: # displayed page border
- context.set_source_rgb( 1.0, 1.0, 1.0 )
- if j<l and self.selectedIds[j] == pageId: j += 1
- elif j<l and self.selectedIds[j] == pageId: # selected page border
- context.set_source_rgb( 0.05, 0.75, 0.8 )
- j += 1
- else: # normal border
- context.set_source_rgb( 0.05, 0.75, 0.0 )
-
- context.move_to( x, self.pageY )
- context.rel_line_to( Config.PAGE_THUMBNAIL_WIDTH, 0 )
- context.rel_line_to( 0, Config.PAGE_THUMBNAIL_HEIGHT )
- context.rel_line_to( -Config.PAGE_THUMBNAIL_WIDTH, 0 )
- context.close_path()
- context.stroke()
-
- x += self.pageSpacing
+ if endx < startX:
+ x = endx
+ endx += Config.PAGE_THUMBNAIL_WIDTH
+ continue
+ if x > stopX: break
+
+ # draw thumbnail
+ if self.thumbnailDirty[pageId]:
+ self.gc.set_clip_origin( 0, 0 )
+ self.drawThumbnail( pageId, self.thumbnail[pageId], self.thumbnailDirtyRect[pageId] )
+ self.gc.set_clip_origin( x, 0 )
+ drawingArea.window.draw_drawable( self.gc, self.thumbnail[pageId], 0, 0, x, 0, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+
+ # draw border if necessary
+ if pageId == self.displayedPage: # displayed page border
+ self.gc.set_function( gtk.gdk.INVERT )
+ for i in range(Config.NUMBER_OF_TRACKS):
+ if tracks[i]:
+ drawingArea.window.draw_rectangle( self.gc, True, x + self.trackRect[i][0], self.trackRect[i][1], self.trackRect[i][2], self.trackRect[i][3] )
+ self.gc.set_function( gtk.gdk.COPY )
+ self.gc.foreground = self.displayedColor
+ self.gc.set_clip_origin( x - Config.PAGE_THUMBNAIL_WIDTH, 0 )
+ drawingArea.window.draw_rectangle( self.gc, True, x, 0, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+ elif pageId in self.selectedIds: # selected page border
+ self.gc.set_function( gtk.gdk.INVERT )
+ for i in range(Config.NUMBER_OF_TRACKS):
+ if tracks[i]:
+ drawingArea.window.draw_rectangle( self.gc, True, x + self.trackRect[i][0], self.trackRect[i][1], self.trackRect[i][2], self.trackRect[i][3] )
+ self.gc.set_function( gtk.gdk.COPY )
+ self.gc.foreground = self.selectedColor
+ self.gc.set_clip_origin( x - Config.PAGE_THUMBNAIL_WIDTH, 0 )
+ drawingArea.window.draw_rectangle( self.gc, True, x, 0, Config.PAGE_THUMBNAIL_WIDTH, Config.PAGE_THUMBNAIL_HEIGHT )
+
+ x += Config.PAGE_THUMBNAIL_WIDTH
+
+ self.gc.set_clip_rectangle( self.clearMask )
+
+ # fill in extra background
+ if x < self.width:
+ self.gc.foreground = self.bgColor
+ drawingArea.window.draw_rectangle( self.gc, True, x, 0, self.width-x, Config.PAGE_THUMBNAIL_HEIGHT )
# draw drop marker
if self.dropAt >= 0:
- context.set_line_width( Config.PAGE_THUMBNAIL_PADDING )
- context.set_source_rgb( 0.0, 0.0, 0.0 )
- context.move_to( Config.PAGE_THUMBNAIL_PADDING + self.pageSpacing*self.dropAt, self.pageY - 4 )
- context.rel_line_to( 0, Config.PAGE_THUMBNAIL_HEIGHT + 8 )
- context.stroke()
+ self.gc.set_line_attributes( self.dropWidth, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER )
+ self.gc.foreground = self.lineColor
+ drawingArea.window.draw_line( self.gc, self.dropAtX, 2, self.dropAtX, Config.PAGE_THUMBNAIL_HEIGHT-4 )
def invalidate_rect( self, x, y, width, height ):
if self.alloced == False: return
+ if x < self.visibleX: x = self.visibleX
+ if x + width > self.visibleEndX: width = self.visibleEndX - x
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
+
+ def invalidate_thumbnail( self, id, x, y, width, height ):
+ if not self.thumbnailDirty[id]:
+ self.thumbnailDirtyRect[id].x = x
+ self.thumbnailDirtyRect[id].y = y
+ self.thumbnailDirtyRect[id].width = width
+ self.thumbnailDirtyRect[id].height = height
+ self.thumbnailDirty[id] = True
+ else:
+ self.dirtyRectToAdd.x = x
+ self.dirtyRectToAdd.y = y
+ self.dirtyRectToAdd.width = width
+ self.dirtyRectToAdd.height = height
+ self.thumbnailDirtyRect[id] = self.thumbnailDirtyRect[id].union( self.dirtyRectToAdd )
+
+ ind = self.noteDB.getPageIndex( id )
+ self.invalidate_rect( self.pageOffset + ind*Config.PAGE_THUMBNAIL_WIDTH, 0, Config.PAGE_THUMBNAIL_WIDTH, self.height )
+
+ def ticksToPixels( self, beats, ticks ):
+ return int(round( ticks * self.pixelsPerTick[beats] ))
+ def pitchToPixels( self, pitch ):
+ return int(round( ( Config.MAXIMUM_PITCH - pitch ) * self.pixelsPerPitch ))
+ def pitchToPixelsDrum( self, pitch ):
+ return int(round( ( Config.MAXIMUM_PITCH_DRUM - pitch ) * self.pixelsPerPitchDrum ))