mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
Make measure selection an editable
This commit is contained in:
parent
ddc7b4d923
commit
a6b1f3cf1f
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user