// // VLSheetView.mm // Vocalese // // Created by Matthias Neeracher on 12/17/05. // Copyright 2005 __MyCompanyName__. All rights reserved. // #import "VLSheetView.h" #import "VLSheetViewInternal.h" #import "VLSheetViewChords.h" #import "VLSheetViewNotes.h" #import "VLDocument.h" #include @implementation VLSheetView static NSImage ** sMusic; static NSString * sElementNames[kMusicElements] = { @"g-clef", @"flat", @"sharp", @"natural", @"whole-notehead", @"half-notehead", @"notehead", @"whole-rest", @"half-rest", @"quarter-rest", @"eighth-rest", @"sixteenth-rest", @"thirtysecondth-rest", @"eighth-flag", @"sixteenth-flag", @"thirtysecondth-flag", @"notecursor" }; static float sSharpPos[] = { 4.0f*kLineH, // F# 2.5f*kLineH, // C# 4.5f*kLineH, // G# 3.0f*kLineH, // D# 1.5f*kLineH, // A# 3.5f*kLineH, // E# 2.0f*kLineH, // B# }; static float sFlatPos[] = { 2.0f*kLineH, // Bb 3.5f*kLineH, // Eb 1.5f*kLineH, // Ab 3.0f*kLineH, // Db 1.0f*kLineH, // Gb 2.5f*kLineH, // Cb 0.5f*kLineH, // Fb }; - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { if (!sMusic) { NSBundle * b = [NSBundle mainBundle]; sMusic = new NSImage * [kMusicElements]; for (int i=0; ifProperties.front().fKey >= 0; float y = octave*3.5f*kLineH; float sharp = useSharps ? 0.0f : 0.5f*kLineH; switch (semi) { case 0: // C return y-1.0f*kLineH; case 1: // C# / Db return y-1.0f*kLineH+sharp; case 2: // D return y-0.5f*kLineH; case 3: // D# / Eb return y-0.5f*kLineH+sharp; case 4: // E return y; case 5: // F return y+0.5f*kLineH; case 6: // F# / Gb return y+0.5f*kLineH+sharp; case 7: // G return y+1.0f*kLineH; case 8: // G# / Ab return y+1.0f*kLineH+sharp; case 9: // A return y+1.5f*kLineH; case 10: // A# / Bb return y+1.5f*kLineH+sharp; case 11: // B default: return y+2.0f*kLineH; } } - (float) noteXInMeasure:(int)measure at:(VLFraction)at { const VLProperties & prop = [self song]->fProperties.front(); const float mx = fClefKeyW+(measure%fMeasPerSystem)*fMeasureW; at /= prop.fTime / (4 * prop.fDivisions); int div = at.fNum / at.fDenom; return mx + (div + (div / fDivPerGroup) + 1)*kNoteW; } - (void) recalculateDimensions { fNeedsRecalc = NO; NSSize sz = [[self enclosingScrollView] contentSize]; sz.width /= fDisplayScale; sz.height/= fDisplayScale; const VLSong * song = [self song]; const VLProperties & prop = song->fProperties.front(); fGroups = prop.fTime.fNum / std::max(prop.fTime.fDenom / 4, 1); fQuarterBeats = (prop.fTime.fNum*4) / prop.fTime.fDenom; fDivPerGroup = prop.fDivisions * (fQuarterBeats / fGroups); fClefKeyW = kClefX+kClefW+(std::labs(prop.fKey)+1)*kKeyW; fMeasureW = fGroups*(fDivPerGroup+1)*kNoteW; fMeasPerSystem = (int)std::floor((sz.width-fClefKeyW) / fMeasureW); fNumSystems = (song->CountMeasures()+fMeasPerSystem-1)/fMeasPerSystem; sz.height = fNumSystems*kSystemH; #if 0 noteRect = NSMakeRect(clefKeyW, kLineY-kMaxLedgers*kLineH, visibleMeasures*fMeasureW, (4.0f+2.0f*kMaxLedgers)*kLineH); NSPoint mouse = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView: nil]; BOOL inNoteRect = [self mouse:mouse inRect:noteRect]; [self removeTrackingRect:noteRectTracker]; noteRectTracker = [self addTrackingRect:noteRect owner:self userData:nil assumeInside:inNoteRect]; [[self window] setAcceptsMouseMovedEvents:inNoteRect]; #endif [[self window] makeFirstResponder:self]; NSSize frameSz = {sz.width * fDisplayScale, sz.height * fDisplayScale}; [self setFrameSize:frameSz]; [self setBoundsSize:sz]; [self setNeedsDisplay:YES]; } - (void)drawRect:(NSRect)rect { static NSDictionary * sMeasNoFont = nil; if (!sMeasNoFont) sMeasNoFont = [[NSDictionary alloc] initWithObjectsAndKeys: [NSFont fontWithName: @"Helvetica" size: 10], NSFontAttributeName, nil]; const VLSong * song = [self song]; const VLProperties & prop = song->fProperties.front(); NSBezierPath * bz = [NSBezierPath bezierPath]; // // Draw lines // [bz setLineWidth:0.0]; if (fNeedsRecalc) [self recalculateDimensions]; for (int system = 0; system 0) { float x = kClefX+kClefW; for (int i=0; iprop.fKey; ++i) { [[self musicElement: kMusicFlat] compositeToPoint: NSMakePoint(x, kLineY+sFlatPos[i]+kFlatY) operation: NSCompositeSourceOver]; x += kAccW; } } } // // Draw notes // [self drawNotes]; } - (IBAction) setKey:(id)sender { int key = [[sender selectedItem] tag]; [[self document] setKey: key transpose: YES]; fNeedsRecalc = YES; [self setNeedsDisplay: YES]; } - (IBAction) setTime:(id)sender { int time = [[sender selectedItem] tag]; [[self document] setTimeNum: time >> 8 denom: time & 0xFF]; fNeedsRecalc = YES; [self setNeedsDisplay: YES]; } - (IBAction) setDivisions:(id)sender { int div = [[sender selectedItem] tag]; [[self document] setDivisions: div]; fNeedsRecalc = YES; [self setNeedsDisplay: YES]; } - (IBAction)showFieldEditor:(id)sender withAction:(SEL)selector { fFieldBeingEdited = sender; [fFieldEditor setObjectValue:[sender title]]; [fFieldEditor setAction:selector]; [self setValue: [NSNumber numberWithBool:YES] forKey: @"fShowFieldEditor"]; } - (IBAction)hideFieldEditor:(id)sender { [fFieldEditor setAction:nil]; [self setValue: [NSNumber numberWithBool:NO] forKey: @"fShowFieldEditor"]; } @end