diff --git a/Sources/VLSheetView.h b/Sources/VLSheetView.h index 2e929b1..d8a122d 100644 --- a/Sources/VLSheetView.h +++ b/Sources/VLSheetView.h @@ -70,6 +70,8 @@ enum VLCursorVisual { kCursorNoPitch = -128 }; +const uint32_t kNoMeasure = (uint32_t)-1; + @class VLEditable; @interface VLSheetView : NSView { @@ -85,9 +87,8 @@ enum VLCursorVisual { int fCursorVertPos; uint16_t fCursorVisual; size_t fCursorStanza; - int fSelStart; - int fSelEnd; - int fSelAnchor; + uint32_t fSelStart; + uint32_t fSelEnd; int fNumTopLedgers; int fNumBotLedgers; int fNumStanzas; diff --git a/Sources/VLSheetView.mm b/Sources/VLSheetView.mm index 108cd55..52ca927 100644 --- a/Sources/VLSheetView.mm +++ b/Sources/VLSheetView.mm @@ -104,7 +104,7 @@ static float sFlatPos[] = { fCursorVertPos = 0; fCursorVisual = 0; fSelStart = 0; - fSelEnd = -1; + fSelEnd = kNoMeasure; fNumTopLedgers = 0; fNumBotLedgers = 2; fNumStanzas = 2; @@ -581,8 +581,10 @@ const char * sBreak[3] = {"", "\xE2\xA4\xBE", "\xE2\x8E\x98"}; - (void)highlightSelectionForSystem:(int)system { - int startMeas = std::max(fSelStart-fLayout->FirstMeasure(system), 0); - int endMeas = std::min(fSelEnd-fLayout->FirstMeasure(system), (*fLayout)[system].NumMeasures()); + uint32_t startMeas = + std::max(fSelStart-fLayout->FirstMeasure(system), 0); + uint32_t endMeas = + std::min(fSelEnd-fLayout->FirstMeasure(system), (*fLayout)[system].NumMeasures()); const float kRawSystemY = [self systemY:system]-kSystemBaseline; const VLSystemLayout & kLayout = (*fLayout)[system]; @@ -625,7 +627,7 @@ const char * sBreak[3] = {"", "\xE2\xA4\xBE", "\xE2\x8E\x98"}; // When highlighting, draw highlight FIRST and then draw our stuff // on top. // - if (fSelStart <= fSelEnd + if (fSelEnd != kNoMeasure && fSelStart <= fSelEnd && fLayout->FirstMeasure(system+1) > fSelStart-(fSelStart==fSelEnd) && fLayout->FirstMeasure(system) < fSelEnd+(fSelStart==fSelEnd) ) @@ -667,7 +669,7 @@ const char * sBreak[3] = {"", "\xE2\xA4\xBE", "\xE2\x8E\x98"}; otherButton:@"Change Key" informativeTextWithFormat: @"Do you want to transpose the %@ into the new key?", - (fSelEnd > -1 && song->fProperties.size() > 1) + (fSelEnd != kNoMeasure && song->fProperties.size() > 1) ? (plural ? @"sections" : @"section") : @"song" ] beginSheetModalForWindow:[self window] @@ -842,45 +844,36 @@ const float kSemiFloor = -1.0f*kLineH; - (void) mouseDown:(NSEvent *)event { - BOOL extend = ([event modifierFlags] & NSShiftKeyMask) != 0; - switch ([self findRegionForEvent:event]) { - case kRegionNote: - [self setEditTarget:nil]; - fSelEnd = -1; - [self addNoteAtCursor]; - break; - case kRegionChord: - fSelEnd = -1; - [self editChord]; - break; - case kRegionLyrics: - if (extend && [[self editTarget] canExtendSelection:kRegionLyrics]) { - [[self editTarget] extendSelection:fCursorLocation]; - } else { - fSelEnd = -1; + BOOL extend = ([event modifierFlags] & NSShiftKeyMask) != 0; + VLRegion region = [self findRegionForEvent:event]; + if (extend && [[self editTarget] canExtendSelection:region]) + [[self editTarget] extendSelection:fCursorLocation]; + else + switch (region) { + case kRegionNote: + [self setEditTarget:nil]; + [self addNoteAtCursor]; + break; + case kRegionChord: + [self editChord]; + break; + case kRegionLyrics: [self editLyrics]; + break; + case kRegionMeasure: + [self editSelection]; + break; + default: + [self setEditTarget:nil]; + break; } - break; - case kRegionMeasure: - [self setEditTarget:nil]; - [self editSelection:extend]; - break; - default: - [self setEditTarget:nil]; - fSelEnd = -1; - break; - } } - (void) mouseDragged:(NSEvent *)event { - VLRegion prevRegion = fCursorRegion; - [super mouseDragged:event]; [self autoscroll:event]; - if (prevRegion == kRegionMeasure) - [self adjustSelection:event]; - else if ([[self editTarget] canExtendSelection:[self findRegionForEvent:event]]) + if ([[self editTarget] canExtendSelection:[self findRegionForEvent:event]]) [[self editTarget] extendSelection:fCursorLocation]; } diff --git a/Sources/VLSheetViewNotes.mm b/Sources/VLSheetViewNotes.mm index f9dc884..8bfda84 100644 --- a/Sources/VLSheetViewNotes.mm +++ b/Sources/VLSheetViewNotes.mm @@ -21,7 +21,7 @@ - (void) addNoteAtCursor { - if (fCursorLocation.fMeasure > -1 && fCursorVertPos != kCursorNoPitch) { + if (fCursorLocation.fMeasure != kNoMeasure && fCursorVertPos != kCursorNoPitch) { [[self document] willChangeSong]; if (fCursorVisual == kCursorExtend) { VLNote oldNote = [self song]->ExtendNote(fCursorLocation); diff --git a/Sources/VLSheetViewSelection.h b/Sources/VLSheetViewSelection.h index d994014..3e0ef80 100644 --- a/Sources/VLSheetViewSelection.h +++ b/Sources/VLSheetViewSelection.h @@ -12,8 +12,8 @@ @interface VLSheetView (Selection) -- (void)editSelection:(BOOL)extend; -- (void)adjustSelection:(NSEvent *)event; +- (void)editSelection; +- (void)selectMeasure:(uint32_t)startMeas to:(uint32_t)endMeas; - (NSRange)sectionsInSelection; - (BOOL)validateUserInterfaceItem:(id)item; diff --git a/Sources/VLSheetViewSelection.mm b/Sources/VLSheetViewSelection.mm index 0815e6e..f02805c 100644 --- a/Sources/VLSheetViewSelection.mm +++ b/Sources/VLSheetViewSelection.mm @@ -18,6 +18,86 @@ #import "VLDocument.h" #import "VLPitchGrid.h" +#pragma mark VLMeasureEditable + +@interface VLMeasureEditable : VLEditable { + VLSheetView * fView; + uint32_t fAnchor; + VLRegion fRegion; +} + +- (VLMeasureEditable *)initWithView:(VLSheetView *)view anchor:(uint32_t)anchor; +- (BOOL)canExtendSelection:(VLRegion)region; +- (void)extendSelection:(VLLocation)at; +- (BOOL)hidden; + +@end + +@implementation VLMeasureEditable + +- (VLMeasureEditable *)initWithView:(VLSheetView *)view anchor:(uint32_t)anchor +{ + fView = view; + fAnchor = anchor; + [fView selectMeasure:fAnchor to:fAnchor]; + + return self; +} + +- (void)dealloc +{ + [fView selectMeasure:0 to:kNoMeasure]; + [super dealloc]; +} + +- (BOOL)canExtendSelection:(VLRegion)region +{ + switch ((fRegion = region)) { + case kRegionNote: + case kRegionChord: + case kRegionLyrics: + case kRegionMeasure: + return YES; + default: + return NO; + } +} + +- (void)extendSelection:(VLLocation)at +{ + uint32_t meas = at.fMeasure; + switch (fRegion) { + case kRegionNote: + case kRegionChord: + case kRegionLyrics: + if (at.fAt > VLFraction(0) && meas >= fAnchor) + ++meas; + // + // Fall through + // + case kRegionMeasure: + meas = std::max(0, std::min(meas, [fView song]->CountMeasures())); + if (meas >= fAnchor) { + [fView selectMeasure:fAnchor to:meas]; + } else { + [fView selectMeasure:meas to:fAnchor]; + } + break; + default: + break; + } +} + +- (BOOL)hidden +{ + return YES; +} + +@end + +#pragma mark - +#pragma mark VLPlaybackEditable + @interface VLPlaybackEditable : VLEditable { VLSheetView * fView; size_t fStanza; @@ -113,50 +193,19 @@ VLSequenceCallback( @implementation VLSheetView (Selection) -- (void)editSelection:(BOOL)extend +- (void)editSelection { - if (extend && fSelEnd > -1) { - if (fCursorLocation.fMeasure > fSelEnd) - fSelEnd = fCursorLocation.fMeasure; - else if (fCursorLocation.fMeasure < fSelStart) - fSelStart = fCursorLocation.fMeasure; - } else { - fSelStart = fSelEnd = fSelAnchor = fCursorLocation.fMeasure; - } - [self updateMenus]; - [self setNeedsDisplay:YES]; + [self setEditTarget:[[VLMeasureEditable alloc] + initWithView:self anchor:fCursorLocation.fMeasure]]; } -- (void)adjustSelection:(NSEvent *)event +- (void)selectMeasure:(uint32_t)startMeas to:(uint32_t)endMeas { - switch ([self findRegionForEvent:event]) { - case kRegionNote: - case kRegionChord: - case kRegionLyrics: - if (fCursorLocation.fAt.fNum > 0 && fCursorLocation.fMeasure >= fSelAnchor) - ++fCursorLocation.fMeasure; - // - // Fall through - // - case kRegionMeasure: - fCursorLocation.fMeasure = - std::max(0, std::min(fCursorLocation.fMeasure, [self song]->CountMeasures())); - if (fCursorLocation.fMeasure >= fSelAnchor) { - fSelStart = fSelAnchor; - fSelEnd = fCursorLocation.fMeasure; - [self updateMenus]; - [self setNeedsDisplay:YES]; - } else { - fSelStart = fCursorLocation.fMeasure; - fSelEnd = fSelAnchor; - [self updateMenus]; - [self setNeedsDisplay:YES]; - } - break; - default: - break; - } - fCursorRegion = kRegionMeasure; + fSelStart = startMeas; + fSelEnd = endMeas; + + [self updateMenus]; + [self setNeedsDisplay:YES]; } - (NSRange)sectionsInSelection @@ -166,7 +215,7 @@ VLSequenceCallback( int lastSection; VLSong * song = [self song]; - if (fSelEnd > -1) { + if (fSelEnd != kNoMeasure) { firstSection = song->fMeasures[fSelStart].fPropIdx; lastSection = fSelEnd==fSelStart ? firstSection : song->fMeasures[fSelEnd-1].fPropIdx; } else {