2006-12-02 03:35:21 +00:00
|
|
|
//
|
2007-04-27 06:41:34 +00:00
|
|
|
// File: VLSheetViewLyrics.mm - Lyrics editing functionality
|
2006-12-02 03:35:21 +00:00
|
|
|
//
|
2007-04-27 06:41:34 +00:00
|
|
|
// Author(s):
|
|
|
|
//
|
|
|
|
// (MN) Matthias Neeracher
|
|
|
|
//
|
|
|
|
// Copyright © 2006-2007 Matthias Neeracher
|
2006-12-02 03:35:21 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#import "VLSheetView.h"
|
|
|
|
#import "VLSheetViewLyrics.h"
|
|
|
|
#import "VLSheetViewInternal.h"
|
2006-12-30 09:57:40 +00:00
|
|
|
#import "VLDocument.h"
|
2006-12-02 03:35:21 +00:00
|
|
|
|
|
|
|
#import "VLModel.h"
|
|
|
|
#import "VLSoundOut.h"
|
|
|
|
|
|
|
|
@implementation VLLyricsEditable
|
|
|
|
|
|
|
|
- (VLLyricsEditable *)initWithView:(VLSheetView *)view
|
|
|
|
song:(VLSong *)song
|
2006-12-02 09:02:44 +00:00
|
|
|
stanza:(int)stanza
|
2006-12-02 03:35:21 +00:00
|
|
|
measure:(int)measure
|
|
|
|
at:(VLFract)at
|
|
|
|
{
|
2007-04-13 04:26:35 +00:00
|
|
|
self = [super init];
|
|
|
|
fView = view;
|
|
|
|
fSong = song;
|
|
|
|
fStanza = stanza;
|
|
|
|
fMeasure = measure;
|
|
|
|
fAt = at;
|
|
|
|
fNextMeas = fMeasure;
|
|
|
|
fNextAt = fAt;
|
2006-12-02 03:35:21 +00:00
|
|
|
|
2006-12-04 07:04:24 +00:00
|
|
|
VLFraction At = fAt;
|
|
|
|
fSong->FindWord(fStanza, fMeasure, At);
|
|
|
|
fAt = At;
|
2008-05-29 18:54:30 +00:00
|
|
|
[fView highlightTextInStanza:fStanza measure:fMeasure at:fAt one:NO];
|
2006-12-02 09:02:44 +00:00
|
|
|
|
2006-12-02 03:35:21 +00:00
|
|
|
[fView setNeedsDisplay: YES];
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) stringValue
|
|
|
|
{
|
2006-12-02 09:02:44 +00:00
|
|
|
std::string word = fSong->GetWord(fStanza, fMeasure, fAt);
|
|
|
|
return [NSString stringWithUTF8String:word.c_str()];
|
2006-12-02 03:35:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setStringValue:(NSString *)val
|
|
|
|
{
|
2006-12-04 07:04:24 +00:00
|
|
|
[[fView document] willChangeSong];
|
2007-12-09 17:37:01 +00:00
|
|
|
fSong->SetWord(fStanza, fMeasure, fAt, val ? [val UTF8String] : "", &fNextMeas, &fNextAt);
|
2006-12-04 07:04:24 +00:00
|
|
|
[[fView document] didChangeSong];
|
2006-12-02 03:35:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) validValue:(NSString *)val
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) moveToNext
|
2006-12-02 09:02:44 +00:00
|
|
|
{
|
2007-04-13 04:26:35 +00:00
|
|
|
if (fNextMeas != fMeasure || fNextAt != fAt) {
|
|
|
|
fMeasure = fNextMeas;
|
|
|
|
VLFraction at = fNextAt;
|
2006-12-04 07:04:24 +00:00
|
|
|
fSong->FindWord(fStanza, fMeasure, at);
|
2007-04-13 04:26:35 +00:00
|
|
|
fAt = at;
|
|
|
|
} else {
|
|
|
|
VLFraction at = fAt;
|
|
|
|
if (!fSong->NextWord(fStanza, fMeasure, at)) {
|
|
|
|
fMeasure = 0;
|
|
|
|
at = 0;
|
|
|
|
fSong->FindWord(fStanza, fMeasure, at);
|
|
|
|
}
|
|
|
|
fAt = at;
|
2006-12-02 09:02:44 +00:00
|
|
|
}
|
2007-04-13 04:26:35 +00:00
|
|
|
fNextMeas = fMeasure;
|
|
|
|
fNextAt = fAt;
|
2008-07-13 21:14:19 +00:00
|
|
|
[fView highlightTextInStanza:fStanza measure:fMeasure at:fAt one:NO];
|
2008-03-24 01:04:05 +00:00
|
|
|
[fView scrollMeasureToVisible:fMeasure];
|
2006-12-02 03:35:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) moveToPrev
|
|
|
|
{
|
2006-12-04 07:04:24 +00:00
|
|
|
VLFraction at = fAt;
|
|
|
|
if (!fSong->PrevWord(fStanza, fMeasure, at)) {
|
2006-12-02 09:02:44 +00:00
|
|
|
fMeasure = fSong->CountMeasures()-1;
|
2007-12-23 13:14:09 +00:00
|
|
|
at = fSong->Properties(fMeasure).fTime;
|
2006-12-04 07:04:24 +00:00
|
|
|
fSong->PrevWord(fStanza, fMeasure, at);
|
2006-12-02 09:02:44 +00:00
|
|
|
}
|
2006-12-04 07:04:24 +00:00
|
|
|
fAt = at;
|
2007-04-13 04:26:35 +00:00
|
|
|
fNextMeas = fMeasure;
|
|
|
|
fNextAt = fAt;
|
2008-07-13 21:14:19 +00:00
|
|
|
[fView highlightTextInStanza:fStanza measure:fMeasure at:fAt one:NO];
|
2008-03-24 01:04:05 +00:00
|
|
|
[fView scrollMeasureToVisible:fMeasure];
|
2006-12-02 03:35:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) highlightCursor
|
|
|
|
{
|
2008-05-29 18:54:30 +00:00
|
|
|
std::string word = fSong->GetWord(fStanza, fMeasure, fAt);
|
|
|
|
if (!word.size())
|
|
|
|
[fView highlightLyricsInStanza:fStanza measure:fMeasure at:fAt];
|
2006-12-02 03:35:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2007-12-25 16:49:45 +00:00
|
|
|
class VLCocoaFontHandler : public VLFontHandler {
|
|
|
|
public:
|
|
|
|
VLCocoaFontHandler(NSString * name, float size);
|
|
|
|
|
2008-05-29 18:54:30 +00:00
|
|
|
virtual void Draw(float x, float y, const char * utf8Text, bool highlight);
|
2007-12-25 16:49:45 +00:00
|
|
|
virtual float Width(const char * utf8Text);
|
|
|
|
private:
|
|
|
|
NSDictionary * fTextAttr;
|
|
|
|
};
|
|
|
|
|
|
|
|
VLCocoaFontHandler::VLCocoaFontHandler(NSString * name, float size)
|
|
|
|
{
|
|
|
|
NSFont * font = [NSFont fontWithName:name size:size];
|
|
|
|
|
|
|
|
fTextAttr =
|
|
|
|
[[NSDictionary alloc] initWithObjectsAndKeys:
|
|
|
|
font, NSFontAttributeName, nil];
|
|
|
|
}
|
|
|
|
|
2008-05-29 18:54:30 +00:00
|
|
|
static NSColor * sHighlightColor;
|
|
|
|
|
|
|
|
void VLCocoaFontHandler::Draw(float x, float y,
|
|
|
|
const char * utf8Text, bool highlight)
|
2007-12-25 16:49:45 +00:00
|
|
|
{
|
2008-05-29 18:54:30 +00:00
|
|
|
NSDictionary * attr = fTextAttr;
|
|
|
|
if (highlight) {
|
|
|
|
NSMutableDictionary * aa =
|
|
|
|
[NSMutableDictionary dictionaryWithDictionary:attr];
|
|
|
|
[aa setValue:sHighlightColor forKey:NSBackgroundColorAttributeName];
|
|
|
|
attr = aa;
|
|
|
|
}
|
|
|
|
NSString * t = [NSString stringWithUTF8String:utf8Text];
|
|
|
|
[t drawAtPoint:NSMakePoint(x,y) withAttributes:attr];
|
2007-12-25 16:49:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float VLCocoaFontHandler::Width(const char * utf8Text)
|
|
|
|
{
|
|
|
|
NSString * t = [NSString stringWithUTF8String:utf8Text];
|
|
|
|
NSSize sz= [t sizeWithAttributes:fTextAttr];
|
|
|
|
|
|
|
|
return sz.width;
|
|
|
|
}
|
|
|
|
|
2006-12-02 03:35:21 +00:00
|
|
|
@implementation VLSheetView (Lyrics)
|
|
|
|
|
|
|
|
- (void) drawLyricsForSystem:(int)system stanza:(size_t)stanza
|
|
|
|
{
|
2007-12-25 16:49:45 +00:00
|
|
|
static VLFontHandler * sRegularFont = nil;
|
|
|
|
static VLFontHandler * sNarrowFont = nil;
|
|
|
|
if (!sRegularFont) {
|
|
|
|
sRegularFont = new VLCocoaFontHandler(@"Arial", 12.0f);
|
|
|
|
sNarrowFont = new VLCocoaFontHandler(@"ArialNarrow", 12.0f);
|
|
|
|
}
|
|
|
|
VLTextLayout text(sRegularFont, sNarrowFont);
|
2006-12-02 03:35:21 +00:00
|
|
|
|
2007-12-23 12:45:17 +00:00
|
|
|
const VLSong * song = [self song];
|
|
|
|
const float kSystemY = [self systemY:system];
|
|
|
|
const VLSystemLayout & kLayout = (*fLayout)[system];
|
|
|
|
const int kFirstMeas = fLayout->FirstMeasure(system);
|
2006-12-02 03:35:21 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Build new list
|
|
|
|
//
|
2007-12-23 12:45:17 +00:00
|
|
|
for (int m = 0; m<kLayout.NumMeasures(); ++m) {
|
|
|
|
int measIdx = m+kFirstMeas;
|
2006-12-02 03:35:21 +00:00
|
|
|
if (measIdx >= song->CountMeasures())
|
|
|
|
break;
|
|
|
|
const VLMeasure measure = song->fMeasures[measIdx];
|
|
|
|
const VLNoteList & notes = measure.fMelody;
|
|
|
|
VLFraction at(0);
|
|
|
|
for (VLNoteList::const_iterator note = notes.begin();
|
|
|
|
note != notes.end();
|
|
|
|
++note
|
|
|
|
) {
|
|
|
|
if (note->fLyrics.size() < stanza
|
|
|
|
|| !note->fLyrics[stanza-1].fText.size()
|
|
|
|
) {
|
|
|
|
;
|
|
|
|
} else {
|
2008-05-29 18:54:30 +00:00
|
|
|
if (!fHighlightNow) {
|
|
|
|
fHighlightNow = stanza == fHighlightStanza
|
|
|
|
&& measIdx == fHighlightMeasure
|
|
|
|
&& at == fHighlightAt;
|
|
|
|
if (fHighlightNow && !sHighlightColor)
|
|
|
|
sHighlightColor =
|
|
|
|
[[self textBackgroundColorForSystem:system]
|
|
|
|
shadowWithLevel:0.2];
|
|
|
|
}
|
|
|
|
|
2007-12-25 16:49:45 +00:00
|
|
|
text.AddSyllable(note->fLyrics[stanza-1],
|
2008-05-29 18:54:30 +00:00
|
|
|
[self noteXInMeasure:measIdx at:at],
|
|
|
|
fHighlightNow);
|
|
|
|
fHighlightNow = fHighlightNow && !fHighlightOne &&
|
|
|
|
note->fLyrics[stanza-1].fKind & VLSyllable::kHasNext;
|
2006-12-02 03:35:21 +00:00
|
|
|
}
|
|
|
|
at += note->fDuration;
|
|
|
|
}
|
|
|
|
}
|
2007-12-25 16:49:45 +00:00
|
|
|
|
|
|
|
text.DrawLine(kSystemY+kLyricsY-stanza*kLyricsH);
|
2008-05-29 18:54:30 +00:00
|
|
|
sHighlightColor = nil;
|
2006-12-02 03:35:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) editLyrics
|
|
|
|
{
|
|
|
|
VLEditable * e =
|
|
|
|
[[VLLyricsEditable alloc]
|
|
|
|
initWithView:self
|
|
|
|
song:[self song]
|
2006-12-02 09:02:44 +00:00
|
|
|
stanza:fCursorStanza
|
2006-12-02 03:35:21 +00:00
|
|
|
measure:fCursorMeasure
|
|
|
|
at:fCursorAt];
|
|
|
|
[self setEditTarget:e];
|
|
|
|
[fFieldEditor selectText:self];
|
|
|
|
}
|
|
|
|
|
2006-12-02 09:02:44 +00:00
|
|
|
- (void) highlightLyricsInStanza:(size_t)stanza measure:(int)measure at:(VLFraction)at
|
2006-12-02 03:35:21 +00:00
|
|
|
{
|
2008-05-29 18:54:30 +00:00
|
|
|
const float kSystemY = [self systemY:fLayout->SystemForMeasure(measure)];
|
|
|
|
NSRect r =
|
|
|
|
NSMakeRect([self noteXInMeasure:measure at:at]-kNoteW*0.5f,
|
|
|
|
kSystemY+kLyricsY-stanza*kLyricsH, kNoteW, kLyricsH);
|
|
|
|
[[NSColor colorWithCalibratedWhite:0.8f alpha:1.0f] setFill];
|
|
|
|
NSRectFillUsingOperation(r, NSCompositePlusDarker);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) highlightTextInStanza:(size_t)stanza measure:(int)measure at:(VLFraction)at one:(BOOL)one
|
|
|
|
{
|
|
|
|
fHighlightStanza = stanza;
|
|
|
|
fHighlightMeasure= measure;
|
|
|
|
fHighlightAt = at;
|
|
|
|
fHighlightNow = false;
|
|
|
|
fHighlightOne = one;
|
2006-12-02 03:35:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|