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
|
||||
};
|
||||
|
||||
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;
|
||||
|
|
|
@ -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]
|
||||
|
@ -843,44 +845,35 @@ const float kSemiFloor = -1.0f*kLineH;
|
|||
- (void) mouseDown:(NSEvent *)event
|
||||
{
|
||||
BOOL extend = ([event modifierFlags] & NSShiftKeyMask) != 0;
|
||||
switch ([self findRegionForEvent:event]) {
|
||||
VLRegion region = [self findRegionForEvent:event];
|
||||
if (extend && [[self editTarget] canExtendSelection:region])
|
||||
[[self editTarget] extendSelection:fCursorLocation];
|
||||
else
|
||||
switch (region) {
|
||||
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;
|
||||
[self editLyrics];
|
||||
}
|
||||
break;
|
||||
case kRegionMeasure:
|
||||
[self setEditTarget:nil];
|
||||
[self editSelection:extend];
|
||||
[self editSelection];
|
||||
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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
fSelStart = startMeas;
|
||||
fSelEnd = endMeas;
|
||||
|
||||
[self updateMenus];
|
||||
[self setNeedsDisplay:YES];
|
||||
} else {
|
||||
fSelStart = fCursorLocation.fMeasure;
|
||||
fSelEnd = fSelAnchor;
|
||||
[self updateMenus];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fCursorRegion = kRegionMeasure;
|
||||
}
|
||||
|
||||
- (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 {
|
||||
|
|
Loading…
Reference in New Issue
Block a user