VocalEasel/Sources/VLSheetViewLyrics.mm

276 lines
6.7 KiB
Plaintext
Raw Normal View History

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"
#import "VLDocument.h"
2006-12-02 03:35:21 +00:00
#import "VLModel.h"
#import "VLSoundOut.h"
@implementation VLLyricsEditable
2011-09-10 21:33:40 +00:00
- (void)highlightWord
{
2011-09-11 02:03:22 +00:00
VLLocation end = fSelection;
if (!fSong->NextWord(fStanza, end))
end.fMeasure = 1000;
[fView highlightTextInStanza:fStanza start:fSelection end:end];
std::string word = fSong->GetWord(fStanza, fSelection);
2011-09-10 23:15:21 +00:00
fText = [[NSString alloc] initWithUTF8String:word.c_str()];
2011-09-10 21:33:40 +00:00
}
2006-12-02 03:35:21 +00:00
- (VLLyricsEditable *)initWithView:(VLSheetView *)view
song:(VLSong *)song
2006-12-02 09:02:44 +00:00
stanza:(int)stanza
2011-09-11 02:03:22 +00:00
at:(VLLocation)at
2006-12-02 03:35:21 +00:00
{
2007-04-13 04:26:35 +00:00
self = [super init];
fView = view;
fSong = song;
fStanza = stanza;
2011-09-11 02:03:22 +00:00
fSelection = at;
fAnchor = at;
fNext = at;
2006-12-02 03:35:21 +00:00
2011-09-11 02:03:22 +00:00
fSong->FindWord(fStanza, fSelection);
2011-09-10 21:33:40 +00:00
[self highlightWord];
2006-12-02 03:35:21 +00:00
return self;
}
2011-09-10 23:15:21 +00:00
- (void)dealloc
{
[fText release];
}
2006-12-02 03:35:21 +00:00
- (NSString *) stringValue
{
2011-09-10 23:15:21 +00:00
return fText;
2006-12-02 03:35:21 +00:00
}
- (void) setStringValue:(NSString *)val
{
2006-12-04 07:04:24 +00:00
[[fView document] willChangeSong];
2011-09-11 02:03:22 +00:00
fSong->SetWord(fStanza, fSelection, val ? [val UTF8String] : "", &fNext);
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
{
2011-09-11 02:03:22 +00:00
if (fNext != fSelection) {
fSelection = fNext;
fSong->FindWord(fStanza, fSelection);
2007-04-13 04:26:35 +00:00
} else {
2011-09-11 02:03:22 +00:00
if (!fSong->NextWord(fStanza, fSelection)) {
fSelection.fMeasure = 0;
fSelection.fAt = VLFraction(0);
fSong->FindWord(fStanza, fSelection);
2007-04-13 04:26:35 +00:00
}
2006-12-02 09:02:44 +00:00
}
2011-09-11 02:03:22 +00:00
fNext = fSelection;
2011-09-10 21:33:40 +00:00
[self highlightWord];
2011-09-11 02:03:22 +00:00
[fView scrollMeasureToVisible:fSelection.fMeasure];
2006-12-02 03:35:21 +00:00
}
- (void) moveToPrev
{
2011-09-11 02:03:22 +00:00
if (!fSong->PrevWord(fStanza, fSelection)) {
fSelection.fMeasure = fSong->CountMeasures()-1;
fSelection.fAt = fSong->Properties(fSelection.fMeasure).fTime;
fSong->PrevWord(fStanza, fSelection);
2006-12-02 09:02:44 +00:00
}
2011-09-11 02:03:22 +00:00
fNext = fSelection;
2011-09-10 21:33:40 +00:00
[self highlightWord];
2011-09-11 02:03:22 +00:00
[fView scrollMeasureToVisible:fSelection.fMeasure];
2006-12-02 03:35:21 +00:00
}
- (void) highlightCursor
{
2011-09-11 02:03:22 +00:00
std::string word = fSong->GetWord(fStanza, fSelection);
2008-05-29 18:54:30 +00:00
if (!word.size())
2011-09-11 02:03:22 +00:00
[fView highlightLyricsInStanza:fStanza at:fSelection];
2006-12-02 03:35:21 +00:00
}
2011-09-10 23:15:21 +00:00
- (BOOL)canExtendSelection:(VLRegion)region
{
return region == kRegionLyrics;
}
2011-09-11 02:03:22 +00:00
- (void)extendSelection:(VLLocation)at
2011-09-10 23:15:21 +00:00
{
2011-09-11 02:03:22 +00:00
if (!fSong->FindWord(fStanza, at))
2011-09-10 23:15:21 +00:00
return;
2011-09-11 02:03:22 +00:00
if (at < fAnchor) {
2011-09-10 23:15:21 +00:00
//
// Backward from anchor
//
2011-09-11 02:03:22 +00:00
fSelection = at;
at = fAnchor;
2011-09-10 23:15:21 +00:00
} else {
//
// Forward from anchor
//
2011-09-11 02:03:22 +00:00
fSelection = fAnchor;
fSong->FindWord(fStanza, fSelection);
2011-09-10 23:15:21 +00:00
}
2011-09-11 02:03:22 +00:00
if (!fSong->NextWord(fStanza, at))
at.fMeasure = 1000;
[fView highlightTextInStanza:fStanza start:fSelection end:at];
2011-09-10 23:15:21 +00:00
std::string text;
2011-09-11 02:03:22 +00:00
VLLocation textAt = fSelection;
while (textAt < at) {
2011-09-10 23:15:21 +00:00
if (text.size())
text += ' ';
2011-09-11 02:03:22 +00:00
text += fSong->GetWord(fStanza, textAt);
2011-09-26 02:45:37 +00:00
if (!fSong->NextWord(fStanza, textAt))
break;
2011-09-10 23:15:21 +00:00
}
[fText release];
fText = [[NSString alloc] initWithUTF8String:text.c_str()];
[fView updateEditTarget];
}
2006-12-02 03:35:21 +00:00
@end
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);
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)
{
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];
}
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
{
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;
2011-09-11 02:03:22 +00:00
VLLocation at = {measIdx, VLFraction(0)};
2006-12-02 03:35:21 +00:00
for (VLNoteList::const_iterator note = notes.begin();
note != notes.end();
++note
) {
if (note->fLyrics.size() < stanza
|| !note->fLyrics[stanza-1].fText.size()
) {
;
} else {
2011-09-10 23:15:21 +00:00
bool highlight = stanza == fHighlightStanza
2011-09-11 02:03:22 +00:00
&& at >= fHighlightStart && at < fHighlightEnd;
2011-09-10 23:15:21 +00:00
if (highlight && !sHighlightColor)
sHighlightColor = [[self textBackgroundColorForSystem:system] shadowWithLevel:0.2];
2008-05-29 18:54:30 +00:00
text.AddSyllable(note->fLyrics[stanza-1],
2011-09-11 02:03:22 +00:00
[self noteXAt:at],
2011-09-10 23:15:21 +00:00
highlight);
2006-12-02 03:35:21 +00:00
}
2011-09-11 02:03:22 +00:00
at.fAt = at.fAt+note->fDuration;
2006-12-02 03:35:21 +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
2011-09-11 02:03:22 +00:00
at:fCursorLocation];
2006-12-02 03:35:21 +00:00
[self setEditTarget:e];
[fFieldEditor selectText:self];
}
2011-09-11 02:03:22 +00:00
- (void) highlightLyricsInStanza:(size_t)stanza at:(VLLocation)at
2006-12-02 03:35:21 +00:00
{
2011-09-11 02:03:22 +00:00
const float kSystemY = [self systemY:fLayout->SystemForMeasure(at.fMeasure)];
2008-05-29 18:54:30 +00:00
NSRect r =
2011-09-11 02:03:22 +00:00
NSMakeRect([self noteXAt:at]-kNoteW*0.5f,
2008-05-29 18:54:30 +00:00
kSystemY+kLyricsY-stanza*kLyricsH, kNoteW, kLyricsH);
[[NSColor colorWithCalibratedWhite:0.8f alpha:1.0f] setFill];
NSRectFillUsingOperation(r, NSCompositePlusDarker);
}
2011-09-11 02:03:22 +00:00
- (void) highlightTextInStanza:(size_t)stanza start:(VLLocation)start end:(VLLocation)end
2008-05-29 18:54:30 +00:00
{
2011-09-11 02:03:22 +00:00
fHighlightStanza = stanza;
fHighlightStart = start;
fHighlightEnd = end;
2011-09-10 23:15:21 +00:00
[self setNeedsDisplay:YES];
2006-12-02 03:35:21 +00:00
}
@end