Model, input, display repeats & endings

This commit is contained in:
Matthias Neeracher 2006-12-30 09:57:40 +00:00
parent 6dec6c2b82
commit 93d8aaba73
18 changed files with 683 additions and 75 deletions

View File

@ -2,6 +2,8 @@
IBClasses = (
{
ACTIONS = {
editRepeat = id;
editRepeatEnding = id;
zoomIn = id;
zoomOut = id;
zoomToActualSize = id;

View File

@ -3,20 +3,20 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>62 66 356 240 0 0 1024 746 </string>
<string>86 70 356 240 0 0 1280 778 </string>
<key>IBEditorPositions</key>
<dict>
<key>29</key>
<string>232 309 349 44 0 0 1024 746 </string>
<string>320 324 349 44 0 0 1280 778 </string>
</dict>
<key>IBFramework Version</key>
<string>453.0</string>
<string>454.0</string>
<key>IBOpenObjects</key>
<array>
<integer>217</integer>
<integer>29</integer>
</array>
<key>IBSystem Version</key>
<string>9A300</string>
<string>9A321</string>
</dict>
</plist>

Binary file not shown.

View File

@ -1,7 +1,14 @@
{
IBClasses = (
{
ACTIONS = {engrave = id; showLog = id; showOutput = id; zoomIn = id; zoomOut = id; };
ACTIONS = {
endRepeatSheet = id;
engrave = id;
showLog = id;
showOutput = id;
zoomIn = id;
zoomOut = id;
};
CLASS = FirstResponder;
LANGUAGE = ObjC;
SUPERCLASS = NSObject;
@ -21,10 +28,22 @@
SUPERCLASS = NSWindowController;
},
{
ACTIONS = {hideFieldEditor = id; setDivisions = id; setKey = id; setTime = id; };
ACTIONS = {
endRepeatSheet = id;
hideFieldEditor = id;
setDivisions = id;
setKey = id;
setTime = id;
};
CLASS = VLSheetView;
LANGUAGE = ObjC;
OUTLETS = {fFieldEditor = id; };
OUTLETS = {
fEndingMsg = id;
fEndingSheet = id;
fFieldEditor = id;
fRepeatMsg = id;
fRepeatSheet = id;
};
SUPERCLASS = NSView;
},
{

View File

@ -3,15 +3,17 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>43 29 356 240 0 0 1280 778 </string>
<string>372 26 356 240 0 0 1280 778 </string>
<key>IBFramework Version</key>
<string>453.0</string>
<string>454.0</string>
<key>IBOpenObjects</key>
<array>
<integer>216</integer>
<integer>196</integer>
<integer>5</integer>
<integer>144</integer>
</array>
<key>IBSystem Version</key>
<string>9A300</string>
<string>9A321</string>
</dict>
</plist>

Binary file not shown.

View File

@ -26,6 +26,7 @@
NSNumber * songTempo;
NSString * tmpPath;
NSFileWrapper * vcsWrapper;
int repeatVolta;
VLSheetWindow * sheetWin;
VLLogWindow * logWin;
@ -37,10 +38,12 @@
- (NSNumber *) songKey;
- (NSNumber *) songTime;
- (NSNumber *) songDivisions;
- (int) repeatVolta;
- (void) setKey:(int)key transpose:(BOOL)transpose;
- (void) setTimeNum:(int)num denom:(int)denom;
- (void) setDivisions:(int)divisions;
- (void) setRepeatVolta:(int)repeatVolta;
- (IBAction) engrave:(id)sender;
- (IBAction) showOutput:(id)sender;

View File

@ -72,6 +72,7 @@
logWin = nil;
tmpPath = nil;
vcsWrapper = nil;
repeatVolta = 2;
[self setHasUndoManager:YES];
undo =
[[VLKeyValueUndo alloc] initWithOwner:self
@ -217,6 +218,16 @@
[self updateChangeCount:NSChangeDone];
}
- (int) repeatVolta
{
return repeatVolta;
}
- (void) setRepeatVolta:(int)volta
{
repeatVolta = volta;
}
- (NSString *) tmpPath
{
if (!tmpPath) {

View File

@ -1153,6 +1153,8 @@ bool VLSong::PrevWord(size_t stanza, size_t & measure, VLFraction & at)
at = fProperties[meas.fPropIdx].fTime;
}
} while (measure-- > 0);
measure = 0;
return false;
}
@ -1164,7 +1166,6 @@ bool VLSong::NextWord(size_t stanza, size_t & measure, VLFraction & at)
VLMeasure & meas = fMeasures[measure];
VLNoteList::iterator note = fMeasures[measure].fMelody.begin();
VLNoteList::iterator end = fMeasures[measure].fMelody.end();
bool hasWord = false;
VLFraction now(0);
while (note != meas.fMelody.end()) {
@ -1191,11 +1192,11 @@ std::string VLSong::GetWord(size_t stanza, size_t measure, VLFraction at)
do {
VLMeasure & meas = fMeasures[measure];
VLNoteList::iterator note = fMeasures[measure].fMelody.begin();
VLNoteList::iterator end = fMeasures[measure].fMelody.end();
VLNoteList::iterator note = meas.fMelody.begin();
VLNoteList::iterator end = meas.fMelody.end();
VLFraction now(0);
while (note != meas.fMelody.end()) {
while (note != end) {
if (now >= at && note->fPitch != VLNote::kNoPitch) {
if (word.size())
word += '-';
@ -1261,3 +1262,268 @@ void VLSong::SetWord(size_t stanza, size_t measure, VLFraction at, std::string w
} while (++measure < fMeasures.size());
}
void VLSong::AddRepeat(size_t beginMeasure, size_t endMeasure, int times)
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (fRepeats[r].fEndings[0].fBegin == beginMeasure
&& fRepeats[r].fEndings[0].fEnd >= endMeasure
)
if (fRepeats[r].fEndings[0].fEnd == endMeasure) {
//
// Exact match, just change times
//
size_t mask = ((1<<times)-1) ^ ((1<<fRepeats[r].fTimes)-1);
if (fRepeats[r].fTimes < times)
fRepeats[r].fEndings[0].fVolta |= mask;
else if (fRepeats[r].fTimes > times)
for (size_t e=0; e<fRepeats[r].fEndings.size(); ++e)
fRepeats[r].fEndings[e].fVolta &= ~mask;
fRepeats[r].fTimes = times;
return;
} else {
fRepeats.erase(fRepeats.begin()+r);
break;
}
VLRepeat rep;
rep.fTimes = times;
rep.fEndings.push_back(VLRepeat::Ending(beginMeasure, endMeasure,
(1<<times)-1));
fRepeats.push_back(rep);
}
void VLSong::DelRepeat(size_t beginMeasure, size_t endMeasure)
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (fRepeats[r].fEndings[0].fBegin == beginMeasure
&& fRepeats[r].fEndings[0].fEnd >= endMeasure
) {
fRepeats.erase(fRepeats.begin()+r);
break;
}
}
void VLSong::AddEnding(size_t beginMeasure, size_t endMeasure, size_t volta)
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (fRepeats[r].fEndings[0].fBegin < beginMeasure
&& fRepeats[r].fEndings[0].fEnd >= beginMeasure
) {
VLRepeat & repeat = fRepeats[r];
for (size_t e=1; e<repeat.fEndings.size(); ++e)
if (repeat.fEndings[e].fBegin == beginMeasure
&& repeat.fEndings[e].fEnd == endMeasure
) {
//
// Found it, just edit volta
//
repeat.fEndings[0].fVolta |= repeat.fEndings[e].fVolta;
volta &= repeat.fEndings[0].fVolta;
repeat.fEndings[0].fVolta &= ~volta;
repeat.fEndings[e].fVolta = volta;
return;
}
//
// Not found, add new ending
//
volta &= fRepeats[r].fEndings[0].fVolta;
fRepeats[r].fEndings[0].fVolta &= ~volta;
fRepeats[r].fEndings[0].fEnd =
std::max<int8_t>(fRepeats[r].fEndings[0].fEnd, endMeasure);
fRepeats[r].fEndings.push_back(
VLRepeat::Ending(beginMeasure, endMeasure, volta));
return;
}
}
void VLSong::DelEnding(size_t beginMeasure, size_t endMeasure)
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (fRepeats[r].fEndings[0].fBegin <= beginMeasure
&& fRepeats[r].fEndings[0].fEnd > beginMeasure
)
for (size_t e=1; e<fRepeats[r].fEndings.size(); ++e)
if (fRepeats[r].fEndings[e].fBegin == beginMeasure) {
fRepeats[r].fEndings[0].fVolta |= fRepeats[r].fEndings[e].fVolta;
if (e > 1 && e == fRepeats[r].fEndings.size()-1)
fRepeats[r].fEndings[0].fEnd = fRepeats[r].fEndings[e].fBegin;
fRepeats[r].fEndings.erase(fRepeats[r].fEndings.begin()+e);
}
}
bool VLSong::CanBeRepeat(size_t beginMeasure, size_t endMeasure, int * times)
{
for (size_t r=0; r<fRepeats.size(); ++r) {
if (fRepeats[r].fEndings[0].fBegin == beginMeasure) {
//
// Look for exact match & return
//
if (times)
*times = fRepeats[r].fTimes;
if (fRepeats[r].fEndings[0].fEnd == endMeasure)
return true;
if (fRepeats[r].fEndings.size() > 1) {
if (fRepeats[r].fEndings[1].fBegin == endMeasure)
return true;
if (fRepeats[r].fEndings[1].fEnd == endMeasure)
return true;
}
}
//
// Look for overlap and reject
//
if (fRepeats[r].fEndings[0].fBegin >= beginMeasure
&& fRepeats[r].fEndings[0].fBegin < endMeasure
)
return false;
if (fRepeats[r].fEndings[0].fEnd > beginMeasure
&& fRepeats[r].fEndings[0].fEnd <= endMeasure
)
return false;
}
//
// Virgin territory, accept
//
if (times)
*times = 2;
return true;
}
bool VLSong::CanBeEnding(size_t beginMeasure, size_t endMeasure,
size_t * volta, size_t * voltaOK)
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (beginMeasure > fRepeats[r].fEndings[0].fBegin
&& beginMeasure <= fRepeats[r].fEndings[0].fEnd
) {
//
// Found right repeat
//
VLRepeat & repeat = fRepeats[r];
//
// Append new repeat, or carve out from ending
//
if (beginMeasure == repeat.fEndings[0].fEnd) {
for (size_t r2=0; r2<fRepeats.size(); ++r2)
if (r2 != r
&& fRepeats[r2].fEndings[0].fBegin >= beginMeasure
&& fRepeats[r2].fEndings[0].fBegin < endMeasure
)
return false; // Overlap
if (volta)
*volta = repeat.fEndings[0].fVolta;
if (voltaOK)
*voltaOK = repeat.fEndings[0].fVolta;
return true;
} else if (repeat.fEndings.size() == 1
&& endMeasure >= repeat.fEndings[0].fEnd
) {
if (volta)
*volta = repeat.fEndings[0].fVolta;
if (voltaOK)
*voltaOK = repeat.fEndings[0].fVolta;
return true;
}
//
// Otherwise must match existing
//
for (size_t e=1; e<repeat.fEndings.size(); ++e)
if (beginMeasure == repeat.fEndings[e].fBegin
&& endMeasure == repeat.fEndings[e].fEnd
) {
if (volta)
*volta = repeat.fEndings[e].fVolta;
if (voltaOK)
*voltaOK = repeat.fEndings[e].fVolta
| repeat.fEndings[0].fVolta;
return true;
}
return false;
}
return false;
}
bool VLSong::DoesBeginRepeat(size_t measure) const
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (fRepeats[r].fEndings[0].fBegin == measure)
return true;
return false;
}
bool VLSong::DoesEndRepeat(size_t measure, int * times) const
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (fRepeats[r].fEndings[0].fEnd == measure
&& fRepeats[r].fEndings.size() == 1
) {
*times = fRepeats[r].fTimes;
return true;
}
return false;
}
bool VLSong::DoesBeginEnding(size_t measure, size_t * volta) const
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (fRepeats[r].fEndings[0].fEnd >= measure
&& fRepeats[r].fEndings.size() > 1
) {
*volta = (1<<fRepeats[r].fTimes)-1;
for (size_t e=1; e<fRepeats[r].fEndings.size(); ++e)
if (fRepeats[r].fEndings[e].fBegin == measure) {
*volta = fRepeats[r].fEndings[e].fVolta;
return true;
} else
*volta&= ~fRepeats[r].fEndings[e].fVolta;
if (*volta && fRepeats[r].fEndings[0].fEnd == measure) {
//
// Implied ending for all not mentioned
//
return true;
}
}
return false;
}
bool VLSong::DoesEndEnding(size_t measure, bool * repeat) const
{
for (size_t r=0; r<fRepeats.size(); ++r)
if (fRepeats[r].fEndings[0].fEnd+1 >= measure
&& fRepeats[r].fEndings.size() > 1
) {
size_t volta = (1<<fRepeats[r].fTimes)-1;
for (size_t e=1; e<fRepeats[r].fEndings.size(); ++e)
if (fRepeats[r].fEndings[e].fEnd == measure) {
if (e == fRepeats[r].fEndings.size()-1
&& fRepeats[r].fEndings[e].fVolta == volta
)
*repeat = false; // Don't repeat after last alternative
else
*repeat = true;
return true;
} else
volta &= ~fRepeats[r].fEndings[e].fVolta;
if (volta && fRepeats[r].fEndings[0].fEnd+1 == measure) {
//
// Implied ending for all not mentioned
//
*repeat = false;
return true;
}
}
return false;
}

View File

@ -243,17 +243,43 @@ struct VLMeasure {
void MMAChords(std::string & chords, const VLProperties & prop) const;
};
struct VLRepeat {
int8_t fTimes;
struct Ending {
Ending(int8_t begin, int8_t end, uint16_t volta)
: fBegin(begin), fEnd(end), fVolta(volta) {}
int8_t fBegin;
int8_t fEnd;
uint16_t fVolta;
};
std::vector<Ending> fEndings;
};
struct VLSong {
VLSong();
void swap(VLSong & other);
std::vector<VLProperties> fProperties;
std::vector<VLMeasure> fMeasures;
std::vector<VLRepeat> fRepeats;
void AddChord(VLChord chord, size_t measure, VLFraction at);
void AddNote(VLLyricsNote note, size_t measure, VLFraction at);
void DelChord(size_t measure, VLFraction at);
void DelNote(size_t measure, VLFraction at);
void AddRepeat(size_t beginMeasure, size_t endMeasure, int times);
void DelRepeat(size_t beginMeasure, size_t endMeasure);
void AddEnding(size_t beginMeasure, size_t endMeasure, size_t volta);
void DelEnding(size_t beginMeasure, size_t endMeasure);
bool CanBeRepeat(size_t beginMeasure, size_t endMeasure, int * times = 0);
bool CanBeEnding(size_t beginMeasure, size_t endMeasure,
size_t * volta = 0, size_t * voltaOK = 0);
bool DoesBeginRepeat(size_t measure) const;
bool DoesEndRepeat(size_t measure, int * times) const;
bool DoesBeginEnding(size_t measure, size_t * volta) const;
bool DoesEndEnding(size_t measure, bool * repeat) const;
void Transpose(int semitones);
bool FindWord(size_t stanza, size_t & measure, VLFraction & at);

View File

@ -78,14 +78,21 @@ enum VLRecalc {
size_t fCursorStanza;
int fSelStart;
int fSelEnd;
size_t fVolta;
size_t fVoltaOK;
IBOutlet id fFieldEditor;
IBOutlet id fRepeatSheet;
IBOutlet id fEndingSheet;
IBOutlet id fRepeatMsg;
IBOutlet id fEndingMsg;
}
- (IBAction) setKey:(id)sender;
- (IBAction) setTime:(id)sender;
- (IBAction) setDivisions:(id)sender;
- (IBAction) hideFieldEditor:(id)sender;
- (IBAction) endRepeatSheet:(id)sender;
- (VLDocument *) document;
- (VLSong *) song;
@ -108,6 +115,7 @@ enum VLRecalc {
- (VLEditable *) editTarget;
- (void) setEditTarget:(VLEditable *)editable;
- (VLRegion) findRegionForEvent:(NSEvent *) event;
@end

View File

@ -11,6 +11,7 @@
#import "VLSheetViewChords.h"
#import "VLSheetViewNotes.h"
#import "VLSheetViewLyrics.h"
#import "VLSheetViewSelection.h"
#import "VLSoundOut.h"
#import "VLDocument.h"
@ -320,14 +321,99 @@ VLMusicElement sSemi2Accidental[12][12] = {
// Draw measure lines
//
[bz setLineWidth:2.0];
for (int measure = 0; measure<=fMeasPerSystem; ++measure) {
int m = system*fMeasPerSystem;
for (int measure = 0; measure<=fMeasPerSystem; ++measure, ++m) {
const float kDblLineOff = 1.5f;
const float kThick = 2.5f;
const float kThin = 1.0f;
const float kDotOff = 4.5f;
const float kDotRadius = 2.0f;
const float kVoltaTextOff = 7.0f;
const float x = fClefKeyW+measure*fMeasureW;
const float yy = kSystemY+4.0f*kLineH;
[bz moveToPoint: NSMakePoint(x, kSystemY)];
[bz lineToPoint: NSMakePoint(x, yy)];
bool repeat;
int times;
size_t volta;
bool dotsPrecede= measure != 0 &&
(song->DoesEndRepeat(m, &times)
|| (song->DoesEndEnding(m, &repeat) && repeat));
bool dotsFollow = measure<fMeasPerSystem && song->DoesBeginRepeat(m);
if (!dotsPrecede && !dotsFollow) {
//
// Regular
//
[bz moveToPoint: NSMakePoint(x, kSystemY)];
[bz lineToPoint: NSMakePoint(x, yy)];
[bz stroke];
[bz removeAllPoints];
} else {
[bz stroke];
[bz removeAllPoints];
[bz setLineWidth: dotsFollow ? kThick : kThin];
[bz moveToPoint: NSMakePoint(x-kDblLineOff, kSystemY)];
[bz lineToPoint: NSMakePoint(x-kDblLineOff, yy)];
[bz stroke];
[bz removeAllPoints];
[bz setLineWidth: dotsPrecede ? kThick : kThin];
[bz moveToPoint: NSMakePoint(x+kDblLineOff, kSystemY)];
[bz lineToPoint: NSMakePoint(x+kDblLineOff, yy)];
[bz stroke];
[bz removeAllPoints];
[bz setLineWidth:2.0];
if (dotsPrecede) {
[bz appendBezierPathWithOvalInRect:
NSMakeRect(x-kDotOff-kDotRadius,
kSystemY+1.5*kLineH-kDotRadius,
2.0f*kDotRadius, 2.0f*kDotRadius)];
[bz appendBezierPathWithOvalInRect:
NSMakeRect(x-kDotOff-kDotRadius,
kSystemY+2.5*kLineH-kDotRadius,
2.0f*kDotRadius, 2.0f*kDotRadius)];
}
if (dotsFollow) {
[bz appendBezierPathWithOvalInRect:
NSMakeRect(x+kDotOff-kDotRadius,
kSystemY+1.5*kLineH-kDotRadius,
2.0f*kDotRadius, 2.0f*kDotRadius)];
[bz appendBezierPathWithOvalInRect:
NSMakeRect(x+kDotOff-kDotRadius,
kSystemY+2.5*kLineH-kDotRadius,
2.0f*kDotRadius, 2.0f*kDotRadius)];
}
[bz fill];
[bz removeAllPoints];
}
if (measure<fMeasPerSystem) {
if (song->DoesBeginEnding(m, &volta)) {
[bz setLineWidth:kThin];
[bz moveToPoint: NSMakePoint(x+kDblLineOff, yy+0.5f*kLineH)];
[bz lineToPoint: NSMakePoint(x+kDblLineOff, yy+2.0f*kLineH)];
[bz lineToPoint: NSMakePoint(x+0.5f*fMeasureW, yy+2.0f*kLineH)];
[bz stroke];
[bz removeAllPoints];
[bz setLineWidth:2.0];
NSString * vs = nil;
for (size_t v=0; v<8; ++v)
if (volta & (1<<v))
if (vs)
vs = [NSString stringWithFormat:@"%@, %d", vs, v+1];
else
vs = [NSString stringWithFormat:@"%d", v+1];
[vs drawAtPoint: NSMakePoint(x+kVoltaTextOff, kSystemY+kMeasNoY)
withAttributes: sMeasNoFont];
}
if (song->DoesEndEnding(m+1, &repeat)) {
[bz setLineWidth:kThin];
[bz moveToPoint: NSMakePoint(x+0.5f*fMeasureW, yy+2.0f*kLineH)];
[bz lineToPoint: NSMakePoint(x+fMeasureW-kDblLineOff, yy+2.0f*kLineH)];
if (repeat)
[bz lineToPoint: NSMakePoint(x+fMeasureW-kDblLineOff, yy+0.5f*kLineH)];
[bz stroke];
[bz removeAllPoints];
[bz setLineWidth:2.0];
}
}
}
[bz stroke];
[bz removeAllPoints];
//
// Draw division lines
@ -701,8 +787,7 @@ static int8_t sSharpAcc[] = {
[self editLyrics];
break;
case kRegionMeasure:
fSelStart = fSelEnd = fCursorMeasure;
[self setNeedsDisplay:YES];
[self editSelection];
break;
default:
break;
@ -714,36 +799,7 @@ static int8_t sSharpAcc[] = {
if (fCursorRegion != kRegionMeasure)
[super mouseDragged:event];
[self autoscroll:event];
int prevMeasure = fCursorMeasure;
switch ([self findRegionForEvent:event]) {
case kRegionNote:
case kRegionChord:
case kRegionLyrics:
if (fCursorAt.fNum)
++fCursorMeasure;
//
// Fall through
//
case kRegionMeasure:
if (fCursorMeasure > fSelEnd) {
fSelEnd = fCursorMeasure;
[self setNeedsDisplay:YES];
} else if (fCursorMeasure < fSelStart) {
fSelStart = fCursorMeasure;
[self setNeedsDisplay:YES];
} else if (prevMeasure == fSelEnd && fCursorMeasure<prevMeasure) {
fSelEnd = fCursorMeasure;
[self setNeedsDisplay:YES];
} else if (prevMeasure == fSelStart && fCursorMeasure>prevMeasure) {
fSelStart = fCursorMeasure;
[self setNeedsDisplay:YES];
}
break;
default:
fCursorMeasure = prevMeasure;
break;
}
fCursorRegion = kRegionMeasure;
[self adjustSelection:event];
}
- (void) keyDown:(NSEvent *)event
@ -841,4 +897,9 @@ static int8_t sSharpAcc[] = {
[self setNeedsDisplay: YES];
}
- (IBAction)endRepeatSheet:(id)sender
{
[NSApp endSheet:[sender window] returnCode:[sender tag]];
}
@end

View File

@ -9,6 +9,7 @@
#import "VLSheetView.h"
#import "VLSheetViewChords.h"
#import "VLSheetViewInternal.h"
#import "VLDocument.h"
#import "VLModel.h"
#import "VLSoundOut.h"

View File

@ -9,6 +9,7 @@
#import "VLSheetView.h"
#import "VLSheetViewLyrics.h"
#import "VLSheetViewInternal.h"
#import "VLDocument.h"
#import "VLModel.h"
#import "VLSoundOut.h"

View File

@ -9,6 +9,7 @@
#import "VLSheetView.h"
#import "VLSheetViewNotes.h"
#import "VLSheetViewInternal.h"
#import "VLDocument.h"
#import "VLSoundOut.h"
#include <algorithm>

View File

@ -0,0 +1,27 @@
//
// VLSheetViewSelection.h
// Vocalese
//
// Created by Matthias Neeracher on 12/28/06.
// Copyright 2006 __MyCompanyName__. All rights reserved.
//
@interface VLSheetView (Selection)
- (void)editSelection;
- (void)adjustSelection:(NSEvent *)event;
- (BOOL)validateUserInterfaceItem:(id)item;
- (IBAction)cut:(id)sender;
- (IBAction)copy:(id)sender;
- (IBAction)paste:(id)sender;
- (IBAction)delete:(id)sender;
- (IBAction)editRepeat:(id)sender;
- (IBAction)editRepeatEnding:(id)sender;
@end
// Local Variables:
// mode:ObjC
// End:

View File

@ -0,0 +1,188 @@
//
// VLSheetViewSelection.mm
// Vocalese
//
// Created by Matthias Neeracher on 12/28/06.
// Copyright 2006 __MyCompanyName__. All rights reserved.
//
#import "VLSheetView.h"
#import "VLSheetViewSelection.h"
#import "VLDocument.h"
@implementation VLSheetView (Selection)
- (void)editSelection
{
fSelStart = fSelEnd = fCursorMeasure;
[self setNeedsDisplay:YES];
}
- (void)adjustSelection:(NSEvent *)event
{
int prevMeasure = fCursorMeasure;
switch ([self findRegionForEvent:event]) {
case kRegionNote:
case kRegionChord:
case kRegionLyrics:
if (fCursorAt.fNum)
++fCursorMeasure;
//
// Fall through
//
case kRegionMeasure:
if (fCursorMeasure > fSelEnd) {
fSelEnd = fCursorMeasure;
[self setNeedsDisplay:YES];
} else if (fCursorMeasure < fSelStart) {
fSelStart = fCursorMeasure;
[self setNeedsDisplay:YES];
} else if (prevMeasure == fSelEnd && fCursorMeasure<prevMeasure) {
fSelEnd = fCursorMeasure;
[self setNeedsDisplay:YES];
} else if (prevMeasure == fSelStart && fCursorMeasure>prevMeasure) {
fSelStart = fCursorMeasure;
[self setNeedsDisplay:YES];
}
break;
default:
fCursorMeasure = prevMeasure;
break;
}
fCursorRegion = kRegionMeasure;
}
- (BOOL)validateUserInterfaceItem:(id) item
{
SEL action = [item action];
if (action == @selector(cut:)
|| action == @selector(copy:)
|| action == @selector(delete:)
)
return fSelStart < fSelEnd;
else if (action == @selector(editRepeat:))
return fSelEnd > fSelStart
&& [self song]->CanBeRepeat(fSelStart, fSelEnd);
else if (action == @selector(editRepeatEnding:))
return fSelEnd > fSelStart
&& [self song]->CanBeEnding(fSelStart, fSelEnd);
else if (action == @selector(paste:))
return fSelStart <= fSelEnd;
else
return YES;
}
- (IBAction)cut:(id)sender
{
}
- (IBAction)copy:(id)sender
{
}
- (IBAction)paste:(id)sender
{
}
- (IBAction)delete:(id)sender
{
}
- (IBAction)editRepeat:(id)sender
{
int volta;
[self song]->CanBeRepeat(fSelStart, fSelEnd, &volta);
[fRepeatMsg setStringValue:
[NSString stringWithFormat:@"Repeat measures %d through %d",
fSelStart+1, fSelEnd]];
[NSApp beginSheet:fRepeatSheet modalForWindow:[self window]
modalDelegate:self
didEndSelector:@selector(didEndRepeatSheet:returnCode:contextInfo:)
contextInfo:nil];
}
- (void)didEndRepeatSheet:(NSWindow *)sheet returnCode:(int)returnCode
contextInfo:(void *)ctx
{
switch (returnCode) {
case NSAlertFirstButtonReturn:
[[self document] willChangeSong];
[self song]->AddRepeat(fSelStart, fSelEnd, [[self document] repeatVolta]);
[self setNeedsDisplay:YES];
[[self document] didChangeSong];
break;
case NSAlertThirdButtonReturn:
[[self document] willChangeSong];
[self song]->DelRepeat(fSelStart, fSelEnd);
[[self document] didChangeSong];
[self setNeedsDisplay:YES];
break;
default:
break;
}
[sheet orderOut:self];
}
- (IBAction)editRepeatEnding:(id)sender
{
[self song]->CanBeEnding(fSelStart, fSelEnd, &fVolta, &fVoltaOK);
[fEndingMsg setStringValue:
[NSString stringWithFormat:@"Ending in measures %d through %d applies to repeats:",
fSelStart+1, fSelEnd]];
[NSApp beginSheet:fEndingSheet modalForWindow:[self window]
modalDelegate:self
didEndSelector:@selector(didEndEndingSheet:returnCode:contextInfo:)
contextInfo:nil];
}
- (void)didEndEndingSheet:(NSWindow *)sheet returnCode:(int)returnCode
contextInfo:(void *)ctx
{
switch (returnCode) {
case NSAlertFirstButtonReturn:
[[self document] willChangeSong];
[self song]->AddEnding(fSelStart, fSelEnd, fVolta);
[self setNeedsDisplay:YES];
[[self document] didChangeSong];
break;
case NSAlertThirdButtonReturn:
[[self document] willChangeSong];
[self song]->DelEnding(fSelStart, fSelEnd);
[[self document] didChangeSong];
[self setNeedsDisplay:YES];
break;
default:
break;
}
[sheet orderOut:self];
}
//
// Data source for endings
//
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
return 1;
}
- (id)tableView:(NSTableView*)tv objectValueForTableColumn:(NSTableColumn *)col
row:(NSInteger)rowIndex
{
int mask = [[col identifier] intValue];
return (fVoltaOK & mask) ? [NSNumber numberWithBool:(fVolta & mask)] : nil;
}
- (void)tableView:(NSTableView *)tv setObjectValue:(id)val forTableColumn:(NSTableColumn *)col row:(NSInteger)rowIndex
{
int mask = [[col identifier] intValue];
if ([val boolValue])
fVolta |= mask;
else
fVolta &= ~mask;
}
@end

View File

@ -8,8 +8,6 @@
/* Begin PBXBuildFile section */
8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */; };
8D15AC2D0486D014006FF6A4 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B6FDCFA73011CA2CEA /* MainMenu.nib */; };
8D15AC2E0486D014006FF6A4 /* VLDocument.nib in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B4FDCFA73011CA2CEA /* VLDocument.nib */; };
8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165FFE840EACC02AAC07 /* InfoPlist.strings */; };
8D15AC310486D014006FF6A4 /* VLDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4ACFDCFA73011CA2CEA /* VLDocument.mm */; settings = {ATTRIBUTES = (); }; };
8D15AC320486D014006FF6A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4B0FDCFA73011CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
@ -40,6 +38,8 @@
95498DBD0AE3812F006B5F81 /* VLSoundSched.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95498DBC0AE3812F006B5F81 /* VLSoundSched.mm */; };
954BBD860AEDDE5300BBFD5F /* VLAppController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 954BBD850AEDDE5300BBFD5F /* VLAppController.mm */; };
954BBD9A0AEDE81500BBFD5F /* VLPitchTransformer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 954BBD990AEDE81500BBFD5F /* VLPitchTransformer.mm */; };
954DD4B90B444B220056C504 /* VLSheetViewSelection.h in Copy MMA Library */ = {isa = PBXBuildFile; fileRef = 954DD4B70B444B220056C504 /* VLSheetViewSelection.h */; };
954DD4E60B44E67F0056C504 /* VLSheetViewSelection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 954DD4E50B44E67F0056C504 /* VLSheetViewSelection.mm */; };
955CBA4E0B2366DD001CF4A1 /* VLKeyValueUndo.h in Copy MMA Library */ = {isa = PBXBuildFile; fileRef = 955CBA4C0B2366DD001CF4A1 /* VLKeyValueUndo.h */; };
955CBA4F0B2366DD001CF4A1 /* VLKeyValueUndo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 955CBA4D0B2366DD001CF4A1 /* VLKeyValueUndo.mm */; };
955E58E5095658AB0045FDA5 /* VLModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 955E58E4095658AB0045FDA5 /* VLModel.cpp */; };
@ -51,6 +51,8 @@
9593E4E90AE0ED1F00035816 /* vocalese.icns in Resources */ = {isa = PBXBuildFile; fileRef = 9593E4E70AE0ED1F00035816 /* vocalese.icns */; };
959408AD096922EA007CCCF8 /* TVLEdit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 959408AC096922EA007CCCF8 /* TVLEdit.cpp */; };
959408AE096922F7007CCCF8 /* VLModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 955E58E4095658AB0045FDA5 /* VLModel.cpp */; };
959420EB0B44E769006BC62C /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 954DD4DA0B44E6000056C504 /* MainMenu.nib */; };
959420EC0B44E77A006BC62C /* VLDocument.nib in Resources */ = {isa = PBXBuildFile; fileRef = 954DD4DF0B44E61E0056C504 /* VLDocument.nib */; };
95A1C37C0AF1D4370076597D /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95A1C37B0AF1D4370076597D /* Quartz.framework */; };
95A1C3860AF2ACE20076597D /* VLSheetWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95A1C3850AF2ACE20076597D /* VLSheetWindow.mm */; };
95B3E1A70960E58B000E9C0D /* Music in Resources */ = {isa = PBXBuildFile; fileRef = 95B3E1980960E58B000E9C0D /* Music */; };
@ -109,6 +111,7 @@
95009B650B0ED18700EB33A4 /* CAMath.h in Copy MMA Library */,
95E299BF0B2006F5001977D2 /* VLSheetViewLyrics.h in Copy MMA Library */,
955CBA4E0B2366DD001CF4A1 /* VLKeyValueUndo.h in Copy MMA Library */,
954DD4B90B444B220056C504 /* VLSheetViewSelection.h in Copy MMA Library */,
);
name = "Copy MMA Library";
runOnlyForDeploymentPostprocessing = 0;
@ -135,8 +138,6 @@
2A37F4ACFDCFA73011CA2CEA /* VLDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLDocument.mm; path = Sources/VLDocument.mm; sourceTree = "<group>"; };
2A37F4AEFDCFA73011CA2CEA /* VLDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLDocument.h; path = Sources/VLDocument.h; sourceTree = "<group>"; };
2A37F4B0FDCFA73011CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Sources/main.m; sourceTree = "<group>"; };
2A37F4B5FDCFA73011CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/VLDocument.nib; sourceTree = "<group>"; };
2A37F4B7FDCFA73011CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
2A37F4BAFDCFA73011CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = "<group>"; };
2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
@ -170,6 +171,10 @@
954BBD850AEDDE5300BBFD5F /* VLAppController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLAppController.mm; path = Sources/VLAppController.mm; sourceTree = "<group>"; };
954BBD980AEDE81500BBFD5F /* VLPitchTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLPitchTransformer.h; path = Sources/VLPitchTransformer.h; sourceTree = "<group>"; };
954BBD990AEDE81500BBFD5F /* VLPitchTransformer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLPitchTransformer.mm; path = Sources/VLPitchTransformer.mm; sourceTree = "<group>"; };
954DD4B70B444B220056C504 /* VLSheetViewSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLSheetViewSelection.h; path = Sources/VLSheetViewSelection.h; sourceTree = "<group>"; };
954DD4DA0B44E6000056C504 /* MainMenu.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = MainMenu.nib; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
954DD4DF0B44E61E0056C504 /* VLDocument.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = VLDocument.nib; path = English.lproj/VLDocument.nib; sourceTree = "<group>"; };
954DD4E50B44E67F0056C504 /* VLSheetViewSelection.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = VLSheetViewSelection.mm; path = Sources/VLSheetViewSelection.mm; sourceTree = "<group>"; };
955CBA4C0B2366DD001CF4A1 /* VLKeyValueUndo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLKeyValueUndo.h; path = Sources/VLKeyValueUndo.h; sourceTree = "<group>"; };
955CBA4D0B2366DD001CF4A1 /* VLKeyValueUndo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLKeyValueUndo.mm; path = Sources/VLKeyValueUndo.mm; sourceTree = "<group>"; };
955E58E3095658AB0045FDA5 /* VLModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLModel.h; path = Sources/VLModel.h; sourceTree = "<group>"; };
@ -363,6 +368,8 @@
954BBD990AEDE81500BBFD5F /* VLPitchTransformer.mm */,
955CBA4C0B2366DD001CF4A1 /* VLKeyValueUndo.h */,
955CBA4D0B2366DD001CF4A1 /* VLKeyValueUndo.mm */,
954DD4B70B444B220056C504 /* VLSheetViewSelection.h */,
954DD4E50B44E67F0056C504 /* VLSheetViewSelection.mm */,
);
name = Classes;
sourceTree = "<group>";
@ -379,6 +386,8 @@
2A37F4B8FDCFA73011CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
954DD4DF0B44E61E0056C504 /* VLDocument.nib */,
954DD4DA0B44E6000056C504 /* MainMenu.nib */,
95FC66BC0AF0A4D4003D9C11 /* console.icns */,
95FC66BD0AF0A4D4003D9C11 /* music.tiff */,
95FC66BE0AF0A4D4003D9C11 /* nextpage.tiff */,
@ -394,8 +403,6 @@
95F5F51E0ADCCFBB003980B2 /* DTD */,
95B3E1980960E58B000E9C0D /* Music */,
2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */,
2A37F4B6FDCFA73011CA2CEA /* MainMenu.nib */,
2A37F4B4FDCFA73011CA2CEA /* VLDocument.nib */,
8D15AC360486D014006FF6A4 /* Info.plist */,
089C165FFE840EACC02AAC07 /* InfoPlist.strings */,
);
@ -575,8 +582,6 @@
buildActionMask = 2147483647;
files = (
8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */,
8D15AC2D0486D014006FF6A4 /* MainMenu.nib in Resources */,
8D15AC2E0486D014006FF6A4 /* VLDocument.nib in Resources */,
8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */,
95B3E1A70960E58B000E9C0D /* Music in Resources */,
95F5F5340ADCCFBB003980B2 /* DTD in Resources */,
@ -592,6 +597,8 @@
95FC66C70AF0A4D5003D9C11 /* run.icns in Resources */,
95FC66C80AF0A4D5003D9C11 /* zoomin.tiff in Resources */,
95FC66C90AF0A4D5003D9C11 /* zoomout.tiff in Resources */,
959420EB0B44E769006BC62C /* MainMenu.nib in Resources */,
959420EC0B44E77A006BC62C /* VLDocument.nib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -642,6 +649,7 @@
95009B500B0ED0BB00EB33A4 /* CADebugMacros.cpp in Sources */,
95E299C00B2006F5001977D2 /* VLSheetViewLyrics.mm in Sources */,
955CBA4F0B2366DD001CF4A1 /* VLKeyValueUndo.mm in Sources */,
954DD4E60B44E67F0056C504 /* VLSheetViewSelection.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -700,22 +708,6 @@
name = InfoPlist.strings;
sourceTree = "<group>";
};
2A37F4B4FDCFA73011CA2CEA /* VLDocument.nib */ = {
isa = PBXVariantGroup;
children = (
2A37F4B5FDCFA73011CA2CEA /* English */,
);
name = VLDocument.nib;
sourceTree = "<group>";
};
2A37F4B6FDCFA73011CA2CEA /* MainMenu.nib */ = {
isa = PBXVariantGroup;
children = (
2A37F4B7FDCFA73011CA2CEA /* English */,
);
name = MainMenu.nib;
sourceTree = "<group>";
};
2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */ = {
isa = PBXVariantGroup;
children = (