Make measure selection an editable

This commit is contained in:
Matthias Neeracher 2011-09-11 04:39:54 +02:00
parent ddc7b4d923
commit a6b1f3cf1f
5 changed files with 126 additions and 83 deletions

View File

@ -70,6 +70,8 @@ enum VLCursorVisual {
kCursorNoPitch = -128
};
const uint32_t kNoMeasure = (uint32_t)-1;
@class VLEditable;
@interface VLSheetView : NSView {
@ -85,9 +87,8 @@ enum VLCursorVisual {
int fCursorVertPos;
uint16_t fCursorVisual;
size_t fCursorStanza;
int fSelStart;
int fSelEnd;
int fSelAnchor;
uint32_t fSelStart;
uint32_t fSelEnd;
int fNumTopLedgers;
int fNumBotLedgers;
int fNumStanzas;

View File

@ -104,7 +104,7 @@ static float sFlatPos[] = {
fCursorVertPos = 0;
fCursorVisual = 0;
fSelStart = 0;
fSelEnd = -1;
fSelEnd = kNoMeasure;
fNumTopLedgers = 0;
fNumBotLedgers = 2;
fNumStanzas = 2;
@ -581,8 +581,10 @@ const char * sBreak[3] = {"", "\xE2\xA4\xBE", "\xE2\x8E\x98"};
- (void)highlightSelectionForSystem:(int)system
{
int startMeas = std::max(fSelStart-fLayout->FirstMeasure(system), 0);
int endMeas = std::min(fSelEnd-fLayout->FirstMeasure(system), (*fLayout)[system].NumMeasures());
uint32_t startMeas =
std::max<uint32_t>(fSelStart-fLayout->FirstMeasure(system), 0);
uint32_t endMeas =
std::min<uint32_t>(fSelEnd-fLayout->FirstMeasure(system), (*fLayout)[system].NumMeasures());
const float kRawSystemY = [self systemY:system]-kSystemBaseline;
const VLSystemLayout & kLayout = (*fLayout)[system];
@ -625,7 +627,7 @@ const char * sBreak[3] = {"", "\xE2\xA4\xBE", "\xE2\x8E\x98"};
// When highlighting, draw highlight FIRST and then draw our stuff
// on top.
//
if (fSelStart <= fSelEnd
if (fSelEnd != kNoMeasure && fSelStart <= fSelEnd
&& fLayout->FirstMeasure(system+1) > fSelStart-(fSelStart==fSelEnd)
&& fLayout->FirstMeasure(system) < fSelEnd+(fSelStart==fSelEnd)
)
@ -667,7 +669,7 @@ const char * sBreak[3] = {"", "\xE2\xA4\xBE", "\xE2\x8E\x98"};
otherButton:@"Change Key"
informativeTextWithFormat:
@"Do you want to transpose the %@ into the new key?",
(fSelEnd > -1 && song->fProperties.size() > 1)
(fSelEnd != kNoMeasure && song->fProperties.size() > 1)
? (plural ? @"sections" : @"section") : @"song"
]
beginSheetModalForWindow:[self window]
@ -842,45 +844,36 @@ const float kSemiFloor = -1.0f*kLineH;
- (void) mouseDown:(NSEvent *)event
{
BOOL extend = ([event modifierFlags] & NSShiftKeyMask) != 0;
switch ([self findRegionForEvent:event]) {
case kRegionNote:
[self setEditTarget:nil];
fSelEnd = -1;
[self addNoteAtCursor];
break;
case kRegionChord:
fSelEnd = -1;
[self editChord];
break;
case kRegionLyrics:
if (extend && [[self editTarget] canExtendSelection:kRegionLyrics]) {
[[self editTarget] extendSelection:fCursorLocation];
} else {
fSelEnd = -1;
BOOL extend = ([event modifierFlags] & NSShiftKeyMask) != 0;
VLRegion region = [self findRegionForEvent:event];
if (extend && [[self editTarget] canExtendSelection:region])
[[self editTarget] extendSelection:fCursorLocation];
else
switch (region) {
case kRegionNote:
[self setEditTarget:nil];
[self addNoteAtCursor];
break;
case kRegionChord:
[self editChord];
break;
case kRegionLyrics:
[self editLyrics];
break;
case kRegionMeasure:
[self editSelection];
break;
default:
[self setEditTarget:nil];
break;
}
break;
case kRegionMeasure:
[self setEditTarget:nil];
[self editSelection:extend];
break;
default:
[self setEditTarget:nil];
fSelEnd = -1;
break;
}
}
- (void) mouseDragged:(NSEvent *)event
{
VLRegion prevRegion = fCursorRegion;
[super mouseDragged:event];
[self autoscroll:event];
if (prevRegion == kRegionMeasure)
[self adjustSelection:event];
else if ([[self editTarget] canExtendSelection:[self findRegionForEvent:event]])
if ([[self editTarget] canExtendSelection:[self findRegionForEvent:event]])
[[self editTarget] extendSelection:fCursorLocation];
}

View File

@ -21,7 +21,7 @@
- (void) addNoteAtCursor
{
if (fCursorLocation.fMeasure > -1 && fCursorVertPos != kCursorNoPitch) {
if (fCursorLocation.fMeasure != kNoMeasure && fCursorVertPos != kCursorNoPitch) {
[[self document] willChangeSong];
if (fCursorVisual == kCursorExtend) {
VLNote oldNote = [self song]->ExtendNote(fCursorLocation);

View File

@ -12,8 +12,8 @@
@interface VLSheetView (Selection)
- (void)editSelection:(BOOL)extend;
- (void)adjustSelection:(NSEvent *)event;
- (void)editSelection;
- (void)selectMeasure:(uint32_t)startMeas to:(uint32_t)endMeas;
- (NSRange)sectionsInSelection;
- (BOOL)validateUserInterfaceItem:(id)item;

View File

@ -18,6 +18,86 @@
#import "VLDocument.h"
#import "VLPitchGrid.h"
#pragma mark VLMeasureEditable
@interface VLMeasureEditable : VLEditable {
VLSheetView * fView;
uint32_t fAnchor;
VLRegion fRegion;
}
- (VLMeasureEditable *)initWithView:(VLSheetView *)view anchor:(uint32_t)anchor;
- (BOOL)canExtendSelection:(VLRegion)region;
- (void)extendSelection:(VLLocation)at;
- (BOOL)hidden;
@end
@implementation VLMeasureEditable
- (VLMeasureEditable *)initWithView:(VLSheetView *)view anchor:(uint32_t)anchor
{
fView = view;
fAnchor = anchor;
[fView selectMeasure:fAnchor to:fAnchor];
return self;
}
- (void)dealloc
{
[fView selectMeasure:0 to:kNoMeasure];
[super dealloc];
}
- (BOOL)canExtendSelection:(VLRegion)region
{
switch ((fRegion = region)) {
case kRegionNote:
case kRegionChord:
case kRegionLyrics:
case kRegionMeasure:
return YES;
default:
return NO;
}
}
- (void)extendSelection:(VLLocation)at
{
uint32_t meas = at.fMeasure;
switch (fRegion) {
case kRegionNote:
case kRegionChord:
case kRegionLyrics:
if (at.fAt > VLFraction(0) && meas >= fAnchor)
++meas;
//
// Fall through
//
case kRegionMeasure:
meas = std::max<uint32_t>(0, std::min<uint32_t>(meas, [fView song]->CountMeasures()));
if (meas >= fAnchor) {
[fView selectMeasure:fAnchor to:meas];
} else {
[fView selectMeasure:meas to:fAnchor];
}
break;
default:
break;
}
}
- (BOOL)hidden
{
return YES;
}
@end
#pragma mark -
#pragma mark VLPlaybackEditable
@interface VLPlaybackEditable : VLEditable {
VLSheetView * fView;
size_t fStanza;
@ -113,50 +193,19 @@ VLSequenceCallback(
@implementation VLSheetView (Selection)
- (void)editSelection:(BOOL)extend
- (void)editSelection
{
if (extend && fSelEnd > -1) {
if (fCursorLocation.fMeasure > fSelEnd)
fSelEnd = fCursorLocation.fMeasure;
else if (fCursorLocation.fMeasure < fSelStart)
fSelStart = fCursorLocation.fMeasure;
} else {
fSelStart = fSelEnd = fSelAnchor = fCursorLocation.fMeasure;
}
[self updateMenus];
[self setNeedsDisplay:YES];
[self setEditTarget:[[VLMeasureEditable alloc]
initWithView:self anchor:fCursorLocation.fMeasure]];
}
- (void)adjustSelection:(NSEvent *)event
- (void)selectMeasure:(uint32_t)startMeas to:(uint32_t)endMeas
{
switch ([self findRegionForEvent:event]) {
case kRegionNote:
case kRegionChord:
case kRegionLyrics:
if (fCursorLocation.fAt.fNum > 0 && fCursorLocation.fMeasure >= fSelAnchor)
++fCursorLocation.fMeasure;
//
// Fall through
//
case kRegionMeasure:
fCursorLocation.fMeasure =
std::max(0, std::min<int>(fCursorLocation.fMeasure, [self song]->CountMeasures()));
if (fCursorLocation.fMeasure >= fSelAnchor) {
fSelStart = fSelAnchor;
fSelEnd = fCursorLocation.fMeasure;
[self updateMenus];
[self setNeedsDisplay:YES];
} else {
fSelStart = fCursorLocation.fMeasure;
fSelEnd = fSelAnchor;
[self updateMenus];
[self setNeedsDisplay:YES];
}
break;
default:
break;
}
fCursorRegion = kRegionMeasure;
fSelStart = startMeas;
fSelEnd = endMeas;
[self updateMenus];
[self setNeedsDisplay:YES];
}
- (NSRange)sectionsInSelection
@ -166,7 +215,7 @@ VLSequenceCallback(
int lastSection;
VLSong * song = [self song];
if (fSelEnd > -1) {
if (fSelEnd != kNoMeasure) {
firstSection = song->fMeasures[fSelStart].fPropIdx;
lastSection = fSelEnd==fSelStart ? firstSection : song->fMeasures[fSelEnd-1].fPropIdx;
} else {