mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 19:23:59 +00:00
Show mixed property state in menus
This commit is contained in:
parent
b92c94ce7e
commit
5423e65457
2658
English.lproj/VLDocument.nib/designable.nib
generated
2658
English.lproj/VLDocument.nib/designable.nib
generated
File diff suppressed because it is too large
Load Diff
BIN
English.lproj/VLDocument.nib/keyedobjects.nib
generated
BIN
English.lproj/VLDocument.nib/keyedobjects.nib
generated
Binary file not shown.
|
@ -91,6 +91,9 @@ enum VLRecalc {
|
||||||
IBOutlet id fRepeatMsg;
|
IBOutlet id fRepeatMsg;
|
||||||
IBOutlet id fEndingMsg;
|
IBOutlet id fEndingMsg;
|
||||||
IBOutlet id fGrooveMenu;
|
IBOutlet id fGrooveMenu;
|
||||||
|
IBOutlet id fKeyMenu;
|
||||||
|
IBOutlet id fTimeMenu;
|
||||||
|
IBOutlet id fDivisionMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction) setKey:(id)sender;
|
- (IBAction) setKey:(id)sender;
|
||||||
|
|
|
@ -983,6 +983,8 @@ static int8_t sSharpAcc[] = {
|
||||||
[doc addObserver:self];
|
[doc addObserver:self];
|
||||||
[doc addObserver:self forKeyPath:@"song" options:0 context:nil];
|
[doc addObserver:self forKeyPath:@"song" options:0 context:nil];
|
||||||
[doc addObserver:self forKeyPath:@"songKey" options:0 context:nil];
|
[doc addObserver:self forKeyPath:@"songKey" options:0 context:nil];
|
||||||
|
[doc addObserver:self forKeyPath:@"songTime" options:0 context:nil];
|
||||||
|
[doc addObserver:self forKeyPath:@"songDivisions" options:0 context:nil];
|
||||||
[doc addObserver:self forKeyPath:@"songGroove" options:0 context:nil];
|
[doc addObserver:self forKeyPath:@"songGroove" options:0 context:nil];
|
||||||
[self setGrooveMenu:[doc valueForKey:@"songGroove"]];
|
[self setGrooveMenu:[doc valueForKey:@"songGroove"]];
|
||||||
|
|
||||||
|
@ -990,12 +992,16 @@ static int8_t sSharpAcc[] = {
|
||||||
fNumTopLedgers = std::max<int>(song->CountTopLedgers(), 1);
|
fNumTopLedgers = std::max<int>(song->CountTopLedgers(), 1);
|
||||||
fNumBotLedgers = std::max<int>(song->CountBotLedgers(), 1);
|
fNumBotLedgers = std::max<int>(song->CountBotLedgers(), 1);
|
||||||
fNumStanzas = std::max<int>(song->CountStanzas(), 2);
|
fNumStanzas = std::max<int>(song->CountStanzas(), 2);
|
||||||
|
|
||||||
|
[self updateMenus];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeObservers:(id)target
|
- (void)removeObservers:(id)target
|
||||||
{
|
{
|
||||||
[target removeObserver:self forKeyPath:@"song"];
|
[target removeObserver:self forKeyPath:@"song"];
|
||||||
[target removeObserver:self forKeyPath:@"songKey"];
|
[target removeObserver:self forKeyPath:@"songKey"];
|
||||||
|
[target removeObserver:self forKeyPath:@"songTime"];
|
||||||
|
[target removeObserver:self forKeyPath:@"songDivisions"];
|
||||||
[target removeObserver:self forKeyPath:@"songGroove"];
|
[target removeObserver:self forKeyPath:@"songGroove"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,8 +1010,13 @@ static int8_t sSharpAcc[] = {
|
||||||
if ([keyPath isEqual:@"songKey"]) {
|
if ([keyPath isEqual:@"songKey"]) {
|
||||||
fNeedsRecalc = kRecalc;
|
fNeedsRecalc = kRecalc;
|
||||||
[self setNeedsDisplay: YES];
|
[self setNeedsDisplay: YES];
|
||||||
|
[self updateKeyMenu];
|
||||||
} else if ([keyPath isEqual:@"song"]) {
|
} else if ([keyPath isEqual:@"song"]) {
|
||||||
[self setNeedsDisplay: YES];
|
[self setNeedsDisplay: YES];
|
||||||
|
} else if ([keyPath isEqual:@"songTime"]) {
|
||||||
|
[self updateTimeMenu];
|
||||||
|
} else if ([keyPath isEqual:@"songDivisions"]) {
|
||||||
|
[self updateDivisionMenu];
|
||||||
} else if ([keyPath isEqual:@"songGroove"]) {
|
} else if ([keyPath isEqual:@"songGroove"]) {
|
||||||
[self setGrooveMenu:[[self document] valueForKey:@"songGroove"]];
|
[self setGrooveMenu:[[self document] valueForKey:@"songGroove"]];
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
- (IBAction)insertJumpToCoda:(id)sender;
|
- (IBAction)insertJumpToCoda:(id)sender;
|
||||||
- (IBAction)insertBreak:(id)sender;
|
- (IBAction)insertBreak:(id)sender;
|
||||||
|
|
||||||
|
- (void)updateKeyMenu;
|
||||||
|
- (void)updateTimeMenu;
|
||||||
|
- (void)updateDivisionMenu;
|
||||||
|
- (void)updateMenus;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
|
|
|
@ -12,6 +12,19 @@
|
||||||
#import "VLSheetViewSelection.h"
|
#import "VLSheetViewSelection.h"
|
||||||
#import "VLDocument.h"
|
#import "VLDocument.h"
|
||||||
|
|
||||||
|
@interface NSMenuItem (VLSetStateToOff)
|
||||||
|
- (void) VLSetStateToOff;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSMenuItem (VLSetStateToOff)
|
||||||
|
|
||||||
|
- (void) VLSetStateToOff
|
||||||
|
{
|
||||||
|
[self setState:NSOffState];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
//
|
//
|
||||||
// We're too lazy to properly serialize our private pasteboard format.
|
// We're too lazy to properly serialize our private pasteboard format.
|
||||||
//
|
//
|
||||||
|
@ -22,6 +35,7 @@ static VLSong sPasteboard;
|
||||||
- (void)editSelection
|
- (void)editSelection
|
||||||
{
|
{
|
||||||
fSelStart = fSelEnd = fCursorMeasure;
|
fSelStart = fSelEnd = fCursorMeasure;
|
||||||
|
[self updateMenus];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,15 +56,19 @@ static VLSong sPasteboard;
|
||||||
std::max(0, std::min<int>(fCursorMeasure, [self song]->CountMeasures()));
|
std::max(0, std::min<int>(fCursorMeasure, [self song]->CountMeasures()));
|
||||||
if (fCursorMeasure > fSelEnd) {
|
if (fCursorMeasure > fSelEnd) {
|
||||||
fSelEnd = fCursorMeasure;
|
fSelEnd = fCursorMeasure;
|
||||||
|
[self updateMenus];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
} else if (fCursorMeasure < fSelStart) {
|
} else if (fCursorMeasure < fSelStart) {
|
||||||
fSelStart = fCursorMeasure;
|
fSelStart = fCursorMeasure;
|
||||||
|
[self updateMenus];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
} else if (prevMeasure == fSelEnd && fCursorMeasure<prevMeasure) {
|
} else if (prevMeasure == fSelEnd && fCursorMeasure<prevMeasure) {
|
||||||
fSelEnd = fCursorMeasure;
|
fSelEnd = fCursorMeasure;
|
||||||
|
[self updateMenus];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
} else if (prevMeasure == fSelStart && fCursorMeasure>prevMeasure) {
|
} else if (prevMeasure == fSelStart && fCursorMeasure>prevMeasure) {
|
||||||
fSelStart = fCursorMeasure;
|
fSelStart = fCursorMeasure;
|
||||||
|
[self updateMenus];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -317,4 +335,82 @@ static VLSong sPasteboard;
|
||||||
[[self document] didChangeSong];
|
[[self document] didChangeSong];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int KeyModeTag(const VLProperties & prop)
|
||||||
|
{
|
||||||
|
return (prop.fKey << 8) | (prop.fMode & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateKeyMenu
|
||||||
|
{
|
||||||
|
NSMenu *menu = [fKeyMenu menu];
|
||||||
|
NSRange sections = [self sectionsInSelection];
|
||||||
|
VLSong *song = [self song];
|
||||||
|
|
||||||
|
[[menu itemArray] makeObjectsPerformSelector:@selector(VLSetStateToOff)];
|
||||||
|
int firstTag = KeyModeTag(song->fProperties[sections.location]);
|
||||||
|
[fKeyMenu selectItemWithTag:firstTag];
|
||||||
|
int firstState = NSOnState;
|
||||||
|
while (--sections.length > 0) {
|
||||||
|
int thisTag = KeyModeTag(song->fProperties[++sections.location]);
|
||||||
|
if (thisTag != firstTag) {
|
||||||
|
firstState = NSMixedState;
|
||||||
|
[[menu itemWithTag:thisTag] setState:NSMixedState];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[[menu itemWithTag:firstTag] setState:firstState];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int TimeTag(const VLProperties & prop)
|
||||||
|
{
|
||||||
|
return (prop.fTime.fNum << 8) | prop.fTime.fDenom;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)updateTimeMenu
|
||||||
|
{
|
||||||
|
NSMenu *menu = [fTimeMenu menu];
|
||||||
|
NSRange sections = [self sectionsInSelection];
|
||||||
|
VLSong *song = [self song];
|
||||||
|
|
||||||
|
[[menu itemArray] makeObjectsPerformSelector:@selector(VLSetStateToOff)];
|
||||||
|
int firstTag = TimeTag(song->fProperties[sections.location]);
|
||||||
|
[fTimeMenu selectItemWithTag:firstTag];
|
||||||
|
int firstState = NSOnState;
|
||||||
|
while (--sections.length > 0) {
|
||||||
|
int thisTag = TimeTag(song->fProperties[++sections.location]);
|
||||||
|
if (thisTag != firstTag) {
|
||||||
|
firstState = NSMixedState;
|
||||||
|
[[menu itemWithTag:thisTag] setState:NSMixedState];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[[menu itemWithTag:firstTag] setState:firstState];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateDivisionMenu
|
||||||
|
{
|
||||||
|
NSMenu *menu = [fDivisionMenu menu];
|
||||||
|
NSRange sections = [self sectionsInSelection];
|
||||||
|
VLSong *song = [self song];
|
||||||
|
|
||||||
|
[[menu itemArray] makeObjectsPerformSelector:@selector(VLSetStateToOff)];
|
||||||
|
int firstTag = song->fProperties[sections.location].fDivisions;
|
||||||
|
[fDivisionMenu selectItemWithTag:firstTag];
|
||||||
|
int firstState = NSOnState;
|
||||||
|
while (--sections.length > 0) {
|
||||||
|
int thisTag = song->fProperties[++sections.location].fDivisions;
|
||||||
|
if (thisTag != firstTag) {
|
||||||
|
firstState = NSMixedState;
|
||||||
|
[[menu itemWithTag:thisTag] setState:NSMixedState];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[[menu itemWithTag:firstTag] setState:firstState];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateMenus
|
||||||
|
{
|
||||||
|
[self updateKeyMenu];
|
||||||
|
[self updateTimeMenu];
|
||||||
|
[self updateDivisionMenu];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user