diff options
author | Nat <natcl@hotmail.com> | 2007-09-13 16:01:09 (GMT) |
---|---|---|
committer | Nat <natcl@hotmail.com> | 2007-09-13 16:01:09 (GMT) |
commit | 6d7e6f83bec91d4c3e49fe64d7793f12d1d3509b (patch) | |
tree | 013613f48b4f4a3f91d3ea9f1c0511153cd6f2b4 /Edit/TrackInterface.py | |
parent | e12dbff4dda5aafbaac98f75f0467ef00dc06c32 (diff) |
split
Diffstat (limited to 'Edit/TrackInterface.py')
-rw-r--r-- | Edit/TrackInterface.py | 1364 |
1 files changed, 0 insertions, 1364 deletions
diff --git a/Edit/TrackInterface.py b/Edit/TrackInterface.py deleted file mode 100644 index b8a3a27..0000000 --- a/Edit/TrackInterface.py +++ /dev/null @@ -1,1364 +0,0 @@ -import pygtk -pygtk.require( '2.0' ) -import gtk - -import gobject - -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.CSoundNote import CSoundNote -from Generation.GenerationConstants import GenerationConstants -from Util.Profiler import TP - -class SELECTNOTES: - ALL = -1 - NONE = 0 - ADD = 1 - REMOVE = 2 - FLIP = 3 - EXCLUSIVE = 4 - -class INTERFACEMODE: - DEFAULT = 0 - DRAW = 1 - PASTE_NOTES = 2 - PASTE_TRACKS = 3 - PAINT = 4 - -class TrackInterfaceParasite: - def __init__( self, noteDB, owner, note ): - if note.track == Config.NUMBER_OF_TRACKS-1: # drum track - self.parasite = HitInterface( noteDB, owner, note ) - else: - self.parasite = NoteInterface( noteDB, owner, note ) - - def attach( self ): - return self.parasite - -class TrackInterface( gtk.EventBox ): - - def __init__( self, noteDB, owner, getScaleFunction ): - gtk.EventBox.__init__( self ) - - self.noteDB = noteDB - self.owner = owner - self.getScale = getScaleFunction - - self.drawingArea = gtk.DrawingArea() - self.drawingAreaDirty = False # are we waiting to draw? - self.add( self.drawingArea ) - self.dirtyRectToAdd = gtk.gdk.Rectangle() # used by the invalidate_rect function - - self.fullWidth = 1 # store the maximum allowed width - self.width = 1 - self.height = 1 - - self.interfaceMode = INTERFACEMODE.DEFAULT - - self.curPage = -1 # this isn't a real page at all! - self.curBeats = 4 - self.painting = False - self.pointerGrid = 1 - self.drawGrid = Config.DEFAULT_GRID - self.paintGrid = Config.DEFAULT_GRID - self.paintNoteDur = Config.DEFAULT_GRID - - self.selectedNotes = [ [] for i in range(Config.NUMBER_OF_TRACKS) ] - - self.curAction = False # stores the current mouse action - self.curActionObject = False # stores the object that in handling the action - - self.lastDO = self.lastDP = self.lastDrumDP = self.lastDD = None - - self.clickButton = 0 # used in release and motion events to make sure we where actually the widget originally clicked. (hack for popup windows) - self.buttonPressCount = 1 # used on release events to indicate double/triple releases - self.clickLoc = [0,0] # location of the last click - self.marqueeLoc = False # current drag location of the marquee - self.marqueeRect = [[0,0],[0,0]] - - self.pasteTick = -1 - self.pasteTrack = -1 - self.pasteRect = False - - self.playheadT = 0 - 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.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) - - self.connect( "size-allocate", self.size_allocate ) - - self.drawingArea.connect( "expose-event", self.expose ) - self.connect( "button-press-event", self.handleButtonPress ) - self.connect( "button-release-event", self.handleButtonRelease ) - self.connect( "motion-notify-event", self.handleMotion ) - - # prepare drawing stuff - hexToInt = { "0":0, "1":1, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "A":10, "B":11, "C":12, "D":13, "E":14, "F":15, "a":10, "b":11, "c":12, "d":13, "e":14, "f":15 } - self.trackColors = [] - for i in Config.TRACK_COLORS: - low = ( 256*(hexToInt[i[0][1]]*16+hexToInt[i[0][2]]), 256*(hexToInt[i[0][3]]*16+hexToInt[i[0][4]]), 256*(hexToInt[i[0][5]]*16+hexToInt[i[0][6]]) ) - high = ( 256*(hexToInt[i[1][1]]*16+hexToInt[i[1][2]]), 256*(hexToInt[i[1][3]]*16+hexToInt[i[1][4]]), 256*(hexToInt[i[1][5]]*16+hexToInt[i[1][6]]) ) - delta = ( high[0]-low[0], high[1]-low[1], high[2]-low[2] ) - self.trackColors.append( (low, delta) ) - - colormap = self.drawingArea.get_colormap() - self.beatColor = colormap.alloc_color( Config.BEAT_COLOR, True, True ) - self.playheadColor = colormap.alloc_color( Config.PLAYHEAD_COLOR, True, True ) - self.marqueeColor = colormap.alloc_color( Config.MARQUEE_COLOR, True, True ) - - self.image = {} - win = gtk.gdk.get_default_root_window() - self.gc = gtk.gdk.GC( win ) - - def prepareDrawable( name ): - pix = gtk.gdk.pixbuf_new_from_file( Config.IMAGE_ROOT+name+".png" ) - self.image[name] = gtk.gdk.Pixmap( win, pix.get_width(), pix.get_height() ) - self.image[name].draw_pixbuf( self.gc, pix, 0, 0, 0, 0, pix.get_width(), pix.get_height(), gtk.gdk.RGB_DITHER_NONE ) - def preparePixbuf( name ): - self.image[name] = gtk.gdk.pixbuf_new_from_file( Config.IMAGE_ROOT+name+".png" ) - - prepareDrawable( "trackBG" ) - prepareDrawable( "trackBGSelected" ) - prepareDrawable( "trackBGDrum" ) - prepareDrawable( "trackBGDrumSelected" ) - preparePixbuf( "note" ) - preparePixbuf( "noteSelected" ) - preparePixbuf( "hit" ) - preparePixbuf( "hitSelected" ) - - # define dimensions - self.width = self.trackFullWidth = self.image["trackBG"].get_size()[0] - self.trackWidth = self.width - Config.TRACK_SPACING - self.trackFullHeight = self.image["trackBG"].get_size()[1] - self.trackHeight = self.trackFullHeight - Config.TRACK_SPACING - self.trackFullHeightDrum = self.image["trackBGDrum"].get_size()[1] - self.trackHeightDrum = self.trackFullHeightDrum - Config.TRACK_SPACING - self.height = self.trackHeight*(Config.NUMBER_OF_TRACKS-1) + self.trackHeightDrum + Config.TRACK_SPACING*Config.NUMBER_OF_TRACKS - self.trackLimits = [] - self.trackRect = [] - self.drumIndex = Config.NUMBER_OF_TRACKS-1 - for i in range(self.drumIndex): - start = i*(self.trackFullHeight) - self.trackLimits.append( (start,start+self.trackFullHeight) ) - self.trackRect.append( gtk.gdk.Rectangle(Config.TRACK_SPACING_DIV2,start+Config.TRACK_SPACING_DIV2, self.trackWidth, self.trackHeight ) ) - self.trackLimits.append( ( self.height - self.trackFullHeightDrum, self.height ) ) - self.trackRect.append( gtk.gdk.Rectangle( Config.TRACK_SPACING_DIV2, self.height - self.trackFullHeightDrum + Config.TRACK_SPACING_DIV2, self.trackWidth, self.trackHeightDrum ) ) - - 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) - self.pitchPerPixelDrum = float(Config.NUMBER_OF_POSSIBLE_PITCHES_DRUM-1)*Config.PITCH_STEP_DRUM / (self.trackHeightDrum - Config.HIT_HEIGHT) - self.pixelsPerPitchDrum = float(self.trackHeightDrum-Config.HIT_HEIGHT)/(Config.MAXIMUM_PITCH_DRUM - Config.MINIMUM_PITCH_DRUM ) - - self.pixelsPerTick = [0] + [ self.trackWidth/float(i*Config.TICKS_PER_BEAT) for i in range(1,Config.MAXIMUM_BEATS+1) ] - - self.ticksPerPixel = [0] + [ 1.0/self.pixelsPerTick[i] for i in range(1,Config.MAXIMUM_BEATS+1) ] - - self.beatSpacing = [[0]] - for i in range(1,Config.MAXIMUM_BEATS+1): - self.beatSpacing.append( [ self.ticksToPixels( i, Config.TICKS_PER_BEAT*j ) for j in range(i) ] ) - - # 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.screenBufBeats = [ -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 - self.predrawTimeout = False - - #-- 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] - - #======================================================= - # NoteDB notifications - - def notifyPageAdd( self, id, at ): - return - - def notifyPageDelete( self, which, safe ): - if self.screenBufPage[self.preScreen] in which: - self.screenBufPage[self.preScreen] = -1 - - def notifyPageDuplicate( self, new, at ): - return - - def notifyPageMove( self, which, low, high ): - return - - def notifyPageUpdate( self, page, parameter, value ): - if parameter == PARAMETER.PAGE_BEATS: - notes = self.noteDB.getNotesByPage( page, self ) - for note in notes: - note.updateTransform() - - if page == self.screenBufPage[self.curScreen]: - self.screenBufBeats[self.curScreen] = value - self.curBeats = value - if self.playheadT >= value*Config.TICKS_PER_BEAT: - self.playheadT = value*Config.TICKS_PER_BEAT - 1 - self.playheadX = self.ticksToPixels( self.curBeats, self.playheadT ) + Config.TRACK_SPACING_DIV2 - self.invalidate_rect( 0, 0, self.width, self.height, page ) - if page == self.screenBufPage[self.preScreen]: - self.screenBufBeats[self.preScreen] = value - self.invalidate_rect( 0, 0, self.width, self.height, page ) - self.predrawPage() - - - #======================================================= - # Module Interface - - def getDrawingPackage( self, track ): - if track == self.drumIndex: - return ( self.image["hit"], self.image["hitSelected"], self.drawingArea.get_colormap(), self.trackColors[track] ) - else: - return ( self.image["note"], self.image["noteSelected"], self.drawingArea.get_colormap(), self.trackColors[track] ) - - 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 ): - if self.screenBufPage[self.preScreen] == -1: return True # no page to predraw - if not self.predrawTimeout: - self.predrawTimeout = gobject.timeout_add( 50, self._predrawTimeout ) - - def abortPredrawPage( self ): - if self.predrawTimeout: - gobject.source_remove( self.predrawTimeout ) - self.predrawTimeout = False - - def _predrawTimeout( self ): - if self.preScreen == -1: return False # no page to predraw - if self.draw( self.preScreen, False, time.time() + 0.020 ): # 20 ms time limit - self.predrawTimeout = False - return False - return True - - - - def displayPage( self, page, predraw = -1 ): - 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 - - 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.screenBufBeats[self.curScreen] = self.curBeats - 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.screenBufBeats[self.preScreen] = self.noteDB.getPage(predraw).beats - 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( oldPage ) - - if self.curAction == "paste": - self._updateClipboardArea() - - def getPlayhead( self ): - return self.playheadT - - def setPlayhead( self, ticks ): - if self.playheadT != ticks: - self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height, self.curPage, False ) - 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 ) - self.playheadT = ticks - - def setInterfaceMode( self, mode ): - self.doneCurrentAction() - - if mode == "tool": - mode = self.owner.getTool() - - if mode == "draw": - self.interfaceMode = INTERFACEMODE.DRAW - elif mode == "paint": - self.interfaceMode = INTERFACEMODE.PAINT - 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 - - def size_allocate( self, widget, allocation ): - self.alloc = allocation - width = allocation.width - height = allocation.height - - self.drawingArea.set_size_request( width, height ) - - if self.window != None: - self.invalidate_rect( 0, 0, width, height, self.curPage, False ) - - def setPointerGrid(self, value): - self.pointerGrid = value - - def setDrawGrid(self, value): - self.drawGrid = value - - def setPaintGrid(self, value): - self.paintGrid = value - - def setPaintNoteDur(self, value): - self.paintNoteDur = value - - def handleButtonPress( self, widget, event ): - - TP.ProfileBegin( "TI::handleButtonPress" ) - - self.clickButton = event.button - - if event.type == gtk.gdk._2BUTTON_PRESS: self.buttonPressCount = 2 - elif event.type == gtk.gdk._3BUTTON_PRESS: self.buttonPressCount = 3 - else: self.buttonPressCount = 1 - - self.clickLoc = [ 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 ) - TP.ProfileEnd( "TI::handleButtonPress" ) - return - - for i in range(Config.NUMBER_OF_TRACKS): - if self.trackLimits[i][0] > event.y: break - if self.trackLimits[i][1] < event.y: continue - - handled = 0 - notes = self.noteDB.getNotesByTrack( self.curPage, i, self ) - last = len(notes)-1 - for n in range(last+1): - if i == self.drumIndex and n < last: # check to see if the next hit overlaps this one - if notes[n].getStartTick() == notes[n+1].getStartTick() and notes[n].getPitch() == notes[n+1].getPitch(): - continue - handled = notes[n].handleButtonPress( self, event ) - if handled == 0: - continue - elif handled == 1: - if not self.curAction: self.curAction = True # it was handled but no action was declared, set curAction to True anyway - TP.ProfileEnd( "TI::handleButtonPress" ) - return - else: # all other options mean we can stop looking - break - - if self.interfaceMode == INTERFACEMODE.DRAW: - if not handled or handled == -1: # event didn't overlap any notes, so we can draw - if i == self.drumIndex: pitch = min( self.pixelsToPitchDrumFloor( self.clickLoc[1] - self.trackLimits[i][1] + Config.HIT_HEIGHT//2 )//Config.PITCH_STEP_DRUM, Config.NUMBER_OF_POSSIBLE_PITCHES_DRUM-1)*Config.PITCH_STEP_DRUM + Config.MINIMUM_PITCH_DRUM - else: pitch = min( self.pixelsToPitchFloor( self.clickLoc[1] - self.trackLimits[i][1] + Config.NOTE_HEIGHT//2 ), Config.NUMBER_OF_POSSIBLE_PITCHES-1) + Config.MINIMUM_PITCH - onset = self.pixelsToTicksFloor( self.curBeats, self.clickLoc[0] - self.trackRect[i].x) - snapOnset = self.drawGrid * int(onset / float(self.drawGrid) + 0.5) - cs = CSoundNote( snapOnset, - pitch, - 0.75, - 0.5, - 1, - i, - instrumentId = self.owner.getTrackInstrument(i).instrumentId ) - cs.pageId = self.curPage - id = self.noteDB.addNote( -1, self.curPage, i, cs ) - n = self.noteDB.getNote( self.curPage, i, id, self ) - self.selectNotes( { i:[n] }, True ) - n.playSampleNote( False ) - - noteS = self.noteDB.getNotesByTrack(self.curPage, i) - for note in noteS: - if note.cs.onset < snapOnset and (note.cs.onset + note.cs.duration) > snapOnset: - self.noteDB.updateNote(self.curPage, i, note.id, PARAMETER.DURATION, snapOnset - note.cs.onset) - - if i != self.drumIndex: # switch to drag duration - self.updateDragLimits() - self.clickLoc[0] += self.ticksToPixels( self.curBeats, 1 ) - self.setCurrentAction( "note-drag-duration", n ) - self.setCursor("drag-duration") - else: - self.curAction = True # we handled this, but there's no real action - - TP.ProfileEnd( "TI::handleButtonPress" ) - return - elif self.interfaceMode == INTERFACEMODE.PAINT: - self.scale = self.getScale() - self.painting = True - self.paintTrack = i - if i == self.drumIndex: - pitch = min( self.pixelsToPitchDrumFloor( self.clickLoc[1] - self.trackLimits[i][1] + Config.HIT_HEIGHT//2 )//Config.PITCH_STEP_DRUM, Config.NUMBER_OF_POSSIBLE_PITCHES_DRUM-1)*Config.PITCH_STEP_DRUM + Config.MINIMUM_PITCH_DRUM - if pitch < 24: - pitch = 24 - elif pitch > 48: - pitch = 48 - else: - pitch = pitch - else: - pitch = min( self.pixelsToPitchFloor( self.clickLoc[1] - self.trackLimits[i][1] + Config.NOTE_HEIGHT//2 ), Config.NUMBER_OF_POSSIBLE_PITCHES-1) + Config.MINIMUM_PITCH - if pitch < 24: - pitch = 24 - elif pitch > 48: - pitch = 48 - else: - pitch = pitch - - minDiff = 100 - for pit in GenerationConstants.SCALES[self.scale]: - diff = abs(pitch-(pit+36)) - if diff < minDiff: - minDiff = diff - nearestPit = pit - pitch = nearestPit+36 - - onset = self.pixelsToTicksFloor( self.curBeats, self.clickLoc[0] - self.trackRect[i].x ) - onset = self.paintGrid * int(onset / self.paintGrid + 0.5) - self.pLastPos = onset - if i != self.drumIndex: - noteS = self.noteDB.getNotesByTrack(self.curPage, i) - ids = [] - stream = [] - for n in noteS: - if n.cs.onset >= onset and n.cs.onset < (onset + self.paintNoteDur): - ids.append(n.id) - if onset > n.cs.onset and onset < (n.cs.onset + n.cs.duration): - ids.append(n.id) - if len(ids): - stream += [self.curPage, i, len(ids)] + ids - self.noteDB.deleteNotes( stream + [-1] ) - - cs = CSoundNote( int(onset), - pitch, - 0.75, - 0.5, - 1, - i, - instrumentId = self.owner.getTrackInstrument(i).instrumentId ) - cs.pageId = self.curPage - id = self.noteDB.addNote( -1, self.curPage, i, cs ) - self.noteDB.updateNote(self.curPage, i, id, PARAMETER.DURATION, self.paintNoteDur) - n = self.noteDB.getNote( self.curPage, i, id, self ) - self.selectNotes( { i:[n] }, True ) - n.playSampleNote( False ) - self.curAction = True - - TP.ProfileEnd( "TI::handleButtonPress" ) - - - def handleButtonRelease( self, widget, event ): - if not self.clickButton: return # we recieved this event but were never clicked! (probably a popup window was open) - self.clickButton = 0 - self.painting = False - - TP.ProfileBegin( "TI::handleButtonRelease" ) - - if event.button != 1: - TP.ProfileEnd( "TI::handleButtonRelease" ) - return - - if not self.curAction: #do track selection stuff here so that we can also handle marquee selection - for i in range(Config.NUMBER_OF_TRACKS): - 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 ) - elif self.buttonPressCount == 2: self.owner.toggleTrack( i, True ) - else: self.owner.clearTracks() - break - - TP.ProfileEnd( "TI::handleButtonRelease" ) - return - - if not self.curActionObject: # there was no real action to carry out - self.curAction = False - TP.ProfileEnd( "TI::handleButtonRelease" ) - return - - if self.curActionObject != self: - self.curActionObject.handleButtonRelease( self, event, self.buttonPressCount ) - self.updateTooltip( event ) - else: - # we're doing the action ourselves - if self.curAction == "marquee": self.doneMarquee( event ) - elif self.curAction == "playhead-drag": self.donePlayhead( event ) - self.updateTooltip( event ) - - - TP.ProfileEnd( "TI::handleButtonRelease" ) - return - - 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) - event.y = float(y) - event.state = state - - if self.painting: - i = self.paintTrack - curPos = self.pixelsToTicksFloor(self.curBeats, event.x - self.trackRect[i].x) - gridPos = self.paintGrid * int(curPos / self.paintGrid + 0.5) - if gridPos >= self.curBeats * Config.TICKS_PER_BEAT: - return - if gridPos != self.pLastPos: - self.pLastPos = gridPos - if i == self.drumIndex: - pitch = min( self.pixelsToPitchDrumFloor( int(event.y) - self.trackLimits[i][1] + Config.HIT_HEIGHT//2 )//Config.PITCH_STEP_DRUM, Config.NUMBER_OF_POSSIBLE_PITCHES_DRUM-1)*Config.PITCH_STEP_DRUM + Config.MINIMUM_PITCH_DRUM - if pitch < 24: - pitch = 24 - elif pitch > 48: - pitch = 48 - else: - pitch = pitch - else: - pitch = min( self.pixelsToPitchFloor( int(event.y) - self.trackLimits[i][1] + Config.NOTE_HEIGHT//2 ), Config.NUMBER_OF_POSSIBLE_PITCHES-1) + Config.MINIMUM_PITCH - if pitch < 24: - pitch = 24 - elif pitch > 48: - pitch = 48 - else: - pitch = pitch - minDiff = 100 - for pit in GenerationConstants.SCALES[self.scale]: - diff = abs(pitch-(pit+36)) - if diff < minDiff: - minDiff = diff - nearestPit = pit - pitch = nearestPit+36 - - onset = gridPos - if i != self.drumIndex: - noteS = self.noteDB.getNotesByTrack(self.curPage, i) - ids = [] - stream = [] - for n in noteS: - if n.cs.onset >= onset and n.cs.onset < (onset + self.paintNoteDur): - ids.append(n.id) - if onset > n.cs.onset and onset < (n.cs.onset + n.cs.duration): - ids.append(n.id) - if len(ids): - stream += [self.curPage, i, len(ids)] + ids - self.noteDB.deleteNotes( stream + [-1] ) - - cs = CSoundNote( int(onset), - pitch, - 0.75, - 0.5, - 1, - i, - instrumentId = self.owner.getTrackInstrument(i).instrumentId ) - cs.pageId = self.curPage - id = self.noteDB.addNote( -1, self.curPage, i, cs ) - self.noteDB.updateNote(self.curPage, i, id, PARAMETER.DURATION, self.paintNoteDur) - n = self.noteDB.getNote( self.curPage, i, id, self ) - self.selectNotes( { i:[n] }, True ) - n.playSampleNote( False ) - self.curAction = True - - - TP.ProfileEnd( "TI::handleMotion::Common" ) - - if not self.clickButton and self.curAction != "paste": # we recieved this event but were never clicked! (probably a popup window was open) - TP.ProfileBegin( "TI::handleMotion::Hover" ) - self.updateTooltip( event ) - TP.ProfileEnd( "TI::handleMotion::Hover" ) - return - - 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.pixelsToTicksFloor( 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 - self.setCurrentAction( "marquee", self ) - - if self.curAction == "note-drag-onset": - self.noteDragOnset( event ) - - elif self.curAction == "note-drag-duration": - self.noteDragDuration( event ) - - elif self.curAction == "note-drag-pitch": - self.noteDragPitch( event ) - - elif self.curAction == "note-drag-pitch-drum": - self.noteDragPitch( event, True ) - - elif self.curAction == "marquee": - self.updateMarquee( event ) - - elif self.curAction == "playhead-drag": - self.updatePlayhead( event ) - - TP.ProfileEnd( "TI::handleMotion::Drag" ) - else: - TP.ProfileBegin( "TI::handleMotion::Hover" ) - self.updateTooltip( event ) - TP.ProfileEnd( "TI::handleMotion::Hover" ) - - return - - #======================================================= - # Actions - - def setCurrentAction( self, action, obj = None ): - if self.curAction: - self.doneCurrentAction() - - self.curAction = action - self.curActionObject = obj - - if action == "note-drag-onset": self.updateDragLimits() - elif action == "note-drag-duration": self.updateDragLimits() - elif action == "note-drag-pitch": self.updateDragLimits() - elif action == "note-drag-pitch-drum": self.updateDragLimits() - elif action == "paste": - self._updateClipboardArea() - self.setCursor("paste") - - def doneCurrentAction( self ): - if not self.curAction: return - action = self.curAction - self.curAction = False - - if action == "note-drag-onset": self.doneNoteDrag( action ) - elif action == "note-drag-duration": self.doneNoteDrag( action ) - elif action == "note-drag-pitch": self.doneNoteDrag( action ) - elif action == "note-drag-pitch-drum": self.doneNoteDrag( action ) - elif action == "paste": - self.owner.cleanupClipboard() - - def trackToggled( self, trackN = -1 ): - 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() - elif self.curAction == "note-drag-duration": self.updateDragLimits() - elif self.curAction == "note-drag-pitch": self.updateDragLimits() - elif self.curAction == "note-drag-pitch-drum": self.updateDragLimits() - for i in range(Config.NUMBER_OF_TRACKS): - if len(self.selectedNotes[i]): - self.owner.setContextState( CONTEXT.NOTE, True ) - self.owner.setContext( CONTEXT.NOTE ) - return - self.owner.setContextState( CONTEXT.NOTE, False ) - - def applyNoteSelection( self, mode, trackN, which, page = -1 ): - if page == -1: page = self.curPage - if mode == SELECTNOTES.ALL: - 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.selectedNotes[trackN] #self.noteDB.getNotesByTrack( page, trackN, self ) - map( lambda note:note.setSelected( False ), track ) - self.selectedNotes[trackN] = [] - elif mode == SELECTNOTES.ADD: - for note in which: - if note.setSelected( True ): - self.selectedNotes[trackN].append( note ) - elif mode == SELECTNOTES.REMOVE: - for note in which: - if note.setSelected( False ): - self.selectedNotes[trackN].remove( note ) - elif mode == SELECTNOTES.FLIP: - for note in which: - if note.getSelected(): - note.setSelected( False ) - self.selectedNotes[trackN].remove( note ) - else: - note.setSelected( True ) - self.selectedNotes[trackN].append( note ) - elif mode == SELECTNOTES.EXCLUSIVE: - notes = self.noteDB.getNotesByTrack( page, trackN, self ) - for n in range(len(notes)): - if notes[n] in which: - if notes[n].setSelected( True ): - self.selectedNotes[trackN].append( notes[n] ) - else: - if notes[n].setSelected( False ): - self.selectedNotes[trackN].remove( notes[n] ) - - 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, page ) - else: self.applyNoteSelection( SELECTNOTES.ADD, trackN, notes, page ) - else: - if not Config.ModKeys.ctrlDown: self.applyNoteSelection( SELECTNOTES.NONE, i, [], page ) - self.selectionChanged() - - def selectNotesByTrack( self, trackN, page = -1 ): - if Config.ModKeys.ctrlDown: - self.applyNoteSelection( SELECTNOTES.ALL, trackN, [], page ) - else: - for i in range(Config.NUMBER_OF_TRACKS): - if i == trackN: self.applyNoteSelection( SELECTNOTES.ALL, trackN, [], page ) - else: self.applyNoteSelection( SELECTNOTES.NONE, i, [], page ) - self.selectionChanged() - - 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], page ) - else: - for i in range(Config.NUMBER_OF_TRACKS): - 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, page = -1 ): - for i in noteDic: - self.applyNoteSelection( SELECTNOTES.REMOVE, i, noteDic[i], page ) - self.selectionChanged() - - def clearSelectedNotes( self, page = -1 ): - for i in range(Config.NUMBER_OF_TRACKS): - 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.noteDB.getPage(self.curPage).ticks - - for i in range(Config.NUMBER_OF_TRACKS): - if not len(self.selectedNotes[i]): continue # no selected notes here - - track = self.noteDB.getNotesByTrack( self.curPage, i, self ) - leftBound = 0 - skip = True # skip the first note - for n in range(len(track)): - if skip: - skip = False - thisNote = track[n] - continue - nextNote = track[n] - if not thisNote.getSelected(): - leftBound = thisNote.getEndTick() - else: - if not nextNote.getSelected(): - rightBound = min( nextNote.getStartTick(), maxRightBound ) - widthBound = rightBound - else: - rightBound = maxRightBound - widthBound = min( nextNote.getStartTick(), maxRightBound ) - thisNote.updateDragLimits( self.dragLimits, leftBound, rightBound, widthBound, maxRightBound ) - thisNote = nextNote - # do the last note - if thisNote.getSelected(): - thisNote.updateDragLimits( self.dragLimits, leftBound, maxRightBound, maxRightBound, maxRightBound ) - - 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 ) ) - do = self.pointerGrid * int(do / self.pointerGrid) - - if do != self.lastDO: - self.lastDO = do - stream = [] - for i in range(Config.NUMBER_OF_TRACKS): - tstream = [] - for note in self.selectedNotes[i]: - 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 ): - dd = self.pixelsToTicks( self.curBeats, event.x - self.clickLoc[0] ) - dd = min( self.dragLimits[2][1], max( self.dragLimits[2][0], dd ) ) - - if dd != self.lastDD: - self.lastDD = dd - stream = [] - for i in range(Config.NUMBER_OF_TRACKS): - tstream = [] - for note in self.selectedNotes[i]: - 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 ): - 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 ) ) - - if dp != self.lastDP: - self.lastDP = dp - stream = [] - for i in range(Config.NUMBER_OF_TRACKS): - tstream = [] - for note in self.selectedNotes[i]: - 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] ) - - if self.curActionObject.note.track != self.drumIndex: - self.curActionObject.playSampleNote( True ) - elif dp != self.lastDrumDP and not dp%2: # only play of "full" drum pitches - self.lastDrumDP = dp - self.curActionObject.playSampleNote( False ) - - def doneNoteDrag( self, action ): - # if action == "note-drag-pitch" or action == "note-drag-pitch-drum": - # self.curActionObject.playSampleNote() - - self.lastDO = self.lastDP = self.lastDrumDP = self.lastDD = None - - 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] - oldEndX = self.marqueeRect[0][0] + self.marqueeRect[1][0] - oldY = self.marqueeRect[0][1] - oldEndY = self.marqueeRect[0][1] + self.marqueeRect[1][1] - else: - oldX = oldEndX = self.clickLoc[0] - oldY = oldEndY = self.clickLoc[1] - - self.marqueeLoc = [ int(event.x), int(event.y) ] - if self.marqueeLoc[0] < 0: self.marqueeLoc[0] = 0 - elif self.marqueeLoc[0] > self.width: self.marqueeLoc[0] = self.width - if self.marqueeLoc[1] < 0: self.marqueeLoc[1] = 0 - elif self.marqueeLoc[1] > self.height: self.marqueeLoc[1] = self.height - - if self.marqueeLoc[0] > self.clickLoc[0]: - self.marqueeRect[0][0] = self.clickLoc[0] - self.marqueeRect[1][0] = self.marqueeLoc[0] - self.clickLoc[0] - else: - self.marqueeRect[0][0] = self.marqueeLoc[0] - self.marqueeRect[1][0] = self.clickLoc[0] - self.marqueeLoc[0] - if self.marqueeLoc[1] > self.clickLoc[1]: - self.marqueeRect[0][1] = self.clickLoc[1] - self.marqueeRect[1][1] = self.marqueeLoc[1] - self.clickLoc[1] - else: - self.marqueeRect[0][1] = self.marqueeLoc[1] - self.marqueeRect[1][1] = self.clickLoc[1] - self.marqueeLoc[1] - - x = min( self.marqueeRect[0][0], oldX ) - 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.curPage, False ) - - def doneMarquee( self, event ): - if self.marqueeLoc: - stop = [ self.marqueeRect[0][0] + self.marqueeRect[1][0], self.marqueeRect[0][1] + self.marqueeRect[1][1] ] - - select = {} - - for i in range(Config.NUMBER_OF_TRACKS): - intersectionY = [ max(self.marqueeRect[0][1],self.trackLimits[i][0]), min(stop[1],self.trackLimits[i][1]) ] - if intersectionY[0] > intersectionY[1]: - continue - - notes = [] - track = self.noteDB.getNotesByTrack( self.curPage, i, self ) - for n in range(len(track)): - hit = track[n].handleMarqueeSelect( self, - [ self.marqueeRect[0][0], intersectionY[0] ], \ - [ stop[0], intersectionY[1] ] ) - if hit: notes.append(track[n]) - - if len(notes): select[i] = notes - - self.selectNotes( select ) - - 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.curPage, False ) - - def updatePlayhead( self, event ): - x = min( self.trackWidth - self.pixelsPerTick[self.curBeats], max( Config.TRACK_SPACING_DIV2, event.x ) ) - self.setPlayhead( self.pixelsToTicks( self.curBeats, x ) ) - - def donePlayhead( self, event ): - x = min( self.trackWidth - self.pixelsPerTick[self.curBeats], max( Config.TRACK_SPACING_DIV2, event.x ) ) - ticks = self.pixelsToTicks( self.curBeats, x ) - 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 - if event.x >= self.playheadX and event.x <= self.playheadX + Config.PLAYHEAD_SIZE: - self.setCursor("drag-playhead") - return - - for i in range(Config.NUMBER_OF_TRACKS): - if self.trackLimits[i][0] > event.y: break - if self.trackLimits[i][1] < event.y: continue - - notes = self.noteDB.getNotesByTrack( self.curPage, i, self ) - handled = 0 - for n in range(len(notes)): - handled = notes[n].updateTooltip( self, event ) - if handled == 0: continue - elif handled == 1: return # event was handled - else: break - - # note wasn't handled, could potentially draw a note - if self.interfaceMode == INTERFACEMODE.DRAW: - if handled == -2: # event X overlapped with a note - self.setCursor("default") - return - - self.setCursor("pencil") - return - - break - - self.setCursor("default") - - def setCursor( self, cursor ): - self.window.set_cursor(self.cursor[cursor]) - - #======================================================= - # Drawing - - 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 - stopX = self.screenBufDirtyRect[buf].x + self.screenBufDirtyRect[buf].width - stopY = self.screenBufDirtyRect[buf].y + self.screenBufDirtyRect[buf].height - - beatStart = Config.TRACK_SPACING_DIV2 - beats = self.screenBufBeats[buf] - - 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( resume[0], self.drumIndex ): - if resume[1] == 0: - if startY > self.trackLimits[i][1]: continue - if stopY < self.trackLimits[i][0]: break - - # draw background - if self.owner.getTrackSelected( 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 - for j in range(1,self.screenBufBeats[buf]): - x = beatStart + self.beatSpacing[beats][j] - 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.screenBufPage[buf], i, self ) - for n in range( resume[2], len(notes) ): - # check escape - if not noescape and time.time() > timeout: - resume[0] = i - 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[1] = 0 - resume[2] = 0 - - # drum track - if stopY > self.trackLimits[self.drumIndex][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 ) - 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 - for j in range(1,self.screenBufBeats[buf]): - x = beatStart + self.beatSpacing[beats][j] - 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.screenBufPage[buf], self.drumIndex, self ) - for n in range( resume[2], len(notes) ): - # check escape - if not noescape and time.time() > timeout: - resume[0] = i - 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::draw" ) - - return True - - def expose( self, DA, event ): - - if self.screenBufDirty[self.curScreen]: - self.draw( 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 - - #print "%d %d %d %d" % (startX,startY,stopX,stopY) - - self.gc.set_clip_rectangle( event.area ) - - # 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 ) - self.gc.foreground = self.playheadColor - DA.window.draw_line( self.gc, self.playheadX, startY, self.playheadX, stopY ) - - if self.marqueeLoc: # draw the selection rect - self.gc.set_line_attributes( Config.MARQUEE_SIZE, gtk.gdk.LINE_ON_OFF_DASH, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER ) - 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 = -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 - self.dirtyRectToAdd.width = width - self.dirtyRectToAdd.height = height - - #print "dirty %d %d %d %d %d %d" % (x, y, width, height, x+width, y+height) - 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 - 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,0] - self.screenBufDirty[self.curScreen] = True - if self.drawingArea.window != None: - self.drawingArea.window.invalidate_rect( self.dirtyRectToAdd, True ) - self.drawingAreaDirty = True - - 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 - 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,0] - self.screenBufDirty[self.preScreen] = True - - #self.queue_draw() - - def getTrackOrigin( self, track ): - return ( self.trackRect[track].x, self.trackRect[track].y ) - - def ticksToPixels( self, beats, ticks ): - return int(round( ticks * self.pixelsPerTick[beats] )) - def pixelsToTicks( self, beats, pixels ): - return int(round( pixels * self.ticksPerPixel[beats] )) - def ticksToPixelsFloor( self, beats, ticks ): - return int( ticks * self.pixelsPerTick[beats] ) - def pixelsToTicksFloor( self, beats, pixels ): - return int( pixels * self.ticksPerPixel[beats] ) - def pitchToPixels( self, pitch ): - return int(round( ( Config.MAXIMUM_PITCH - pitch ) * self.pixelsPerPitch )) - def pixelsToPitch( self, pixels ): - return int(round(-pixels*self.pitchPerPixel)) - def pitchToPixelsFloor( self, pitch ): - return int(( Config.MAXIMUM_PITCH - pitch ) * self.pixelsPerPitch ) - def pixelsToPitchFloor( self, pixels ): - return int(-pixels*self.pitchPerPixel) - def pitchToPixelsDrum( self, pitch ): - return int(round( ( Config.MAXIMUM_PITCH_DRUM - pitch ) * self.pixelsPerPitchDrum )) - def pixelsToPitchDrum( self, pixels ): - return int(round(-pixels*self.pitchPerPixelDrum)) - def pitchToPixelsDrumFloor( self, pitch ): - return int( ( Config.MAXIMUM_PITCH_DRUM - pitch ) * self.pixelsPerPitchDrum ) - def pixelsToPitchDrumFloor( self, pixels ): - return int(-pixels*self.pitchPerPixelDrum) |