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

View File

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

View File

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

View File

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

View File

@ -18,6 +18,86 @@
#import "VLDocument.h" #import "VLDocument.h"
#import "VLPitchGrid.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 { @interface VLPlaybackEditable : VLEditable {
VLSheetView * fView; VLSheetView * fView;
size_t fStanza; size_t fStanza;
@ -113,50 +193,19 @@ VLSequenceCallback(
@implementation VLSheetView (Selection) @implementation VLSheetView (Selection)
- (void)editSelection:(BOOL)extend - (void)editSelection
{ {
if (extend && fSelEnd > -1) { [self setEditTarget:[[VLMeasureEditable alloc]
if (fCursorLocation.fMeasure > fSelEnd) initWithView:self anchor:fCursorLocation.fMeasure]];
fSelEnd = fCursorLocation.fMeasure;
else if (fCursorLocation.fMeasure < fSelStart)
fSelStart = fCursorLocation.fMeasure;
} else {
fSelStart = fSelEnd = fSelAnchor = fCursorLocation.fMeasure;
}
[self updateMenus];
[self setNeedsDisplay:YES];
} }
- (void)adjustSelection:(NSEvent *)event - (void)selectMeasure:(uint32_t)startMeas to:(uint32_t)endMeas
{ {
switch ([self findRegionForEvent:event]) { fSelStart = startMeas;
case kRegionNote: fSelEnd = endMeas;
case kRegionChord:
case kRegionLyrics: [self updateMenus];
if (fCursorLocation.fAt.fNum > 0 && fCursorLocation.fMeasure >= fSelAnchor) [self setNeedsDisplay:YES];
++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;
} }
- (NSRange)sectionsInSelection - (NSRange)sectionsInSelection
@ -166,7 +215,7 @@ VLSequenceCallback(
int lastSection; int lastSection;
VLSong * song = [self song]; VLSong * song = [self song];
if (fSelEnd > -1) { if (fSelEnd != kNoMeasure) {
firstSection = song->fMeasures[fSelStart].fPropIdx; firstSection = song->fMeasures[fSelStart].fPropIdx;
lastSection = fSelEnd==fSelStart ? firstSection : song->fMeasures[fSelEnd-1].fPropIdx; lastSection = fSelEnd==fSelStart ? firstSection : song->fMeasures[fSelEnd-1].fPropIdx;
} else { } else {