diff --git a/Sources/VLSheetView.h b/Sources/VLSheetView.h index 154ea20..438ebe5 100644 --- a/Sources/VLSheetView.h +++ b/Sources/VLSheetView.h @@ -100,7 +100,6 @@ enum VLCursorVisual { int fHighlightEndMeasure; VLFract fHighlightEndAt; size_t fHighlightStanza; - bool fHighlightNow; VLKeyValueUndo * fUndo; IBOutlet id fFieldEditor; @@ -153,6 +152,7 @@ enum VLCursorVisual { - (VLEditable *) editTarget; - (void) setEditTarget:(VLEditable *)editable; +- (void) updateEditTarget; - (VLRegion) findRegionForEvent:(NSEvent *) event; - (void) setGroove:(NSString *)groove; diff --git a/Sources/VLSheetView.mm b/Sources/VLSheetView.mm index d2609a1..5fb2ff1 100644 --- a/Sources/VLSheetView.mm +++ b/Sources/VLSheetView.mm @@ -148,6 +148,11 @@ static float sFlatPos[] = { [[[self window] windowController] setEditTarget:editable]; } +- (void) updateEditTarget +{ + [fFieldEditor takeStringValueFrom:[self editTarget]]; +} + - (VLSong *) song { return [[self document] song]; @@ -837,21 +842,26 @@ const float kSemiFloor = -1.0f*kLineH; - (void) mouseDown:(NSEvent *)event { + BOOL extend = ([event modifierFlags] & NSShiftKeyMask) != 0; switch ([self findRegionForEvent:event]) { case kRegionNote: fSelEnd = -1; - [self addNoteAtCursor]; + [self addNoteAtCursor]; break; case kRegionChord: fSelEnd = -1; [self editChord]; break; case kRegionLyrics: - fSelEnd = -1; - [self editLyrics]; + if (extend && [[self editTarget] canExtendSelection:kRegionLyrics]) { + [[self editTarget] extendSelection:fCursorMeasure at:fCursorAt]; + } else { + fSelEnd = -1; + [self editLyrics]; + } break; case kRegionMeasure: - [self editSelection:([event modifierFlags] & NSShiftKeyMask) != 0]; + [self editSelection:extend]; break; default: fSelEnd = -1; @@ -861,13 +871,14 @@ const float kSemiFloor = -1.0f*kLineH; - (void) mouseDragged:(NSEvent *)event { - bool inMeasureSelection = fCursorRegion == kRegionMeasure; - - if (!inMeasureSelection) - [super mouseDragged:event]; + VLRegion prevRegion = fCursorRegion; + + [super mouseDragged:event]; [self autoscroll:event]; - if (inMeasureSelection) + if (prevRegion == kRegionMeasure) [self adjustSelection:event]; + else if ([[self editTarget] canExtendSelection:[self findRegionForEvent:event]]) + [[self editTarget] extendSelection:fCursorMeasure at:fCursorAt]; } - (void) keyDown:(NSEvent *)event @@ -919,11 +930,9 @@ const float kSemiFloor = -1.0f*kLineH; [editable moveToPrev]; break; default: - [editable autorelease]; fHighlightStanza = 0xFFFFFFFF; - editable = nil; + editable = nil; } - [self setEditTarget:editable]; if (editable) [fFieldEditor selectText:self]; else diff --git a/Sources/VLSheetViewLyrics.h b/Sources/VLSheetViewLyrics.h index 7e0c3e4..ce71680 100644 --- a/Sources/VLSheetViewLyrics.h +++ b/Sources/VLSheetViewLyrics.h @@ -16,8 +16,11 @@ size_t fStanza; size_t fMeasure; VLFract fAt; + size_t fAnchorMeas; + VLFract fAnchorAt; size_t fNextMeas; VLFract fNextAt; + NSString * fText; } - (VLLyricsEditable *)initWithView:(VLSheetView *)view diff --git a/Sources/VLSheetViewLyrics.mm b/Sources/VLSheetViewLyrics.mm index 5c9ebdc..bfa604d 100644 --- a/Sources/VLSheetViewLyrics.mm +++ b/Sources/VLSheetViewLyrics.mm @@ -22,8 +22,11 @@ { size_t endMeas = fMeasure; VLFraction endAt = fAt; - fSong->NextWord(fStanza, endMeas, endAt); + if (!fSong->NextWord(fStanza, endMeas, endAt)) + endMeas = 1000; [fView highlightTextInStanza:fStanza startMeasure:fMeasure at:fAt endMeasure:endMeas at:endAt]; + std::string word = fSong->GetWord(fStanza, fMeasure, fAt); + fText = [[NSString alloc] initWithUTF8String:word.c_str()]; } - (VLLyricsEditable *)initWithView:(VLSheetView *)view @@ -38,6 +41,8 @@ fStanza = stanza; fMeasure = measure; fAt = at; + fAnchorMeas = measure; + fAnchorAt = at; fNextMeas = fMeasure; fNextAt = fAt; @@ -49,10 +54,14 @@ return self; } +- (void)dealloc +{ + [fText release]; +} + - (NSString *) stringValue { - std::string word = fSong->GetWord(fStanza, fMeasure, fAt); - return [NSString stringWithUTF8String:word.c_str()]; + return fText; } - (void) setStringValue:(NSString *)val @@ -111,6 +120,51 @@ [fView highlightLyricsInStanza:fStanza measure:fMeasure at:fAt]; } +- (BOOL)canExtendSelection:(VLRegion)region +{ + return region == kRegionLyrics; +} + +- (void)extendSelection:(size_t)measure at:(VLFract)At +{ + VLFraction at = At; + if (!fSong->FindWord(fStanza, measure, at)) + return; + if (measure < fAnchorMeas || (measure==fAnchorMeas && at < fAnchorAt)) { + // + // Backward from anchor + // + fMeasure = measure; + fAt = at; + measure = fAnchorMeas; + at = fAnchorAt; + } else { + // + // Forward from anchor + // + fMeasure = fAnchorMeas; + at = fAnchorAt; + fSong->FindWord(fStanza, fMeasure, at); + fAt = at; + at = At; + } + if (!fSong->NextWord(fStanza, measure, at)) + measure = 1000; + [fView highlightTextInStanza:fStanza startMeasure:fMeasure at:fAt endMeasure:measure at:at]; + std::string text; + size_t textMeas = fMeasure; + VLFraction textAt = fAt; + while (textMeas < measure || (textMeas == measure && textAt < at)) { + if (text.size()) + text += ' '; + text += fSong->GetWord(fStanza, textMeas, textAt); + fSong->NextWord(fStanza, textMeas, textAt); + } + [fText release]; + fText = [[NSString alloc] initWithUTF8String:text.c_str()]; + [fView updateEditTarget]; +} + @end class VLCocoaFontHandler : public VLFontHandler { @@ -192,23 +246,17 @@ float VLCocoaFontHandler::Width(const char * utf8Text) ) { ; } else { - if (!fHighlightNow) { - fHighlightNow = stanza == fHighlightStanza - && measIdx == fHighlightStartMeasure - && at == fHighlightStartAt; - if (fHighlightNow && !sHighlightColor) - sHighlightColor = - [[self textBackgroundColorForSystem:system] - shadowWithLevel:0.2]; - } else { - fHighlightNow = fHighlightNow && stanza == fHighlightStanza - && (measIdx < fHighlightEndMeasure - ||(measIdx == fHighlightEndMeasure && at < fHighlightEndAt)); - } + bool highlight = stanza == fHighlightStanza + && (measIdx > fHighlightStartMeasure + || (measIdx == fHighlightStartMeasure && at >= fHighlightStartAt)) + && (measIdx < fHighlightEndMeasure + || (measIdx == fHighlightEndMeasure && at < fHighlightEndAt)); + if (highlight && !sHighlightColor) + sHighlightColor = [[self textBackgroundColorForSystem:system] shadowWithLevel:0.2]; text.AddSyllable(note->fLyrics[stanza-1], [self noteXInMeasure:measIdx at:at], - fHighlightNow); + highlight); } at += note->fDuration; } @@ -249,7 +297,7 @@ float VLCocoaFontHandler::Width(const char * utf8Text) fHighlightStartAt = startAt; fHighlightEndMeasure = endMeasure; fHighlightEndAt = endAt; - fHighlightNow = false; + [self setNeedsDisplay:YES]; } @end diff --git a/Sources/VLSheetWindow.h b/Sources/VLSheetWindow.h index a3e71b8..813cef2 100644 --- a/Sources/VLSheetWindow.h +++ b/Sources/VLSheetWindow.h @@ -10,6 +10,7 @@ #import #import +#import "VLSheetView.h" @interface VLEditable : NSObject { @@ -21,6 +22,8 @@ - (void) moveToNext; - (void) moveToPrev; - (void) highlightCursor; +- (BOOL) canExtendSelection:(VLRegion)region; +- (void) extendSelection:(size_t)measure at:(VLFract)at; @end diff --git a/Sources/VLSheetWindow.mm b/Sources/VLSheetWindow.mm index ce87133..f8a205e 100644 --- a/Sources/VLSheetWindow.mm +++ b/Sources/VLSheetWindow.mm @@ -44,6 +44,15 @@ { } +- (BOOL)canExtendSelection:(VLRegion)region +{ + return NO; +} + +- (void)extendSelection:(size_t)measure at:(VLFract)at +{ +} + @end @implementation VLSheetWindow @@ -82,6 +91,7 @@ - (void)setEditTarget:(VLEditable *)editable { + [editTarget autorelease]; editTarget = editable; }