5 // Created by Joseph Spiros on Wed Apr 30 2003.
6 // Copyright (c) 2003 iThink Software. All rights reserved.
9 #import "MenuController.h"
10 #import "NewMainController.h"
11 #import "HotKeyCenter.h"
14 @interface MenuController (SubmenuMethods)
15 - (NSMenu *)ratingMenu;
16 - (NSMenu *)upcomingSongsMenu;
17 - (NSMenu *)playlistsMenu;
19 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
20 onItem:(NSMenuItem *)item;
23 @implementation MenuController
27 if ( (self = [super init]) ) {
28 _menuLayout = [[NSMutableArray alloc] initWithCapacity:0];
35 NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
36 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
37 NSArray *menuArray = [defaults arrayForKey:@"menu"];
38 NSEnumerator *enumerator = [menuArray objectEnumerator];
41 NSEnumerator *itemEnum;
45 _currentPlaylist = [currentRemote currentPlaylistIndex];
46 _playingRadio = ([currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
48 //Kill the old submenu items
49 if ( (tempItem = [_currentMenu itemWithTag:1]) ) {
50 [tempItem setSubmenu:nil];
53 if ( (tempItem = [_currentMenu itemWithTag:2]) ) {
54 [tempItem setSubmenu:nil];
57 if ( (tempItem = [_currentMenu itemWithTag:3]) ) {
58 [tempItem setSubmenu:nil];
61 if ( (tempItem = [_currentMenu itemWithTag:4]) ) {
62 [tempItem setSubmenu:nil];
66 while ( (nextObject = [enumerator nextObject]) ) {
68 if ([nextObject isEqualToString:@"Play/Pause"]) {
69 tempItem = [menu addItemWithTitle:@"Play"
70 action:@selector(performMainMenuAction:)
72 [tempItem setTag:MTMenuPlayPauseItem];
73 [tempItem setTarget:self];
75 if ( (keyCombo = [[HotKeyCenter sharedCenter] keyComboForName:@"PlayPause"]) ) {
76 [self setKeyEquivalentForCode:[keyCombo keyCode]
77 andModifiers:[keyCombo modifiers]
81 switch ([currentRemote playerPlayingState]) {
82 case ITMTRemotePlayerPlaying:
83 [tempItem setTitle:@"Pause"];
85 case ITMTRemotePlayerRewinding:
86 case ITMTRemotePlayerForwarding:
87 [tempItem setTitle:@"Resume"];
92 } else if ([nextObject isEqualToString:@"Next Track"]) {
93 tempItem = [menu addItemWithTitle:@"Next Track"
94 action:@selector(performMainMenuAction:)
97 if ( (keyCombo = [[HotKeyCenter sharedCenter] keyComboForName:@"NextTrack"]) ) {
98 [self setKeyEquivalentForCode:[keyCombo keyCode]
99 andModifiers:[keyCombo modifiers]
103 if (_currentPlaylist) {
104 [tempItem setTag:MTMenuNextTrackItem];
105 [tempItem setTarget:self];
107 } else if ([nextObject isEqualToString:@"Previous Track"]) {
108 tempItem = [menu addItemWithTitle:@"Previous Track"
109 action:@selector(performMainMenuAction:)
112 if ( (keyCombo = [[HotKeyCenter sharedCenter] keyComboForName:@"PrevTrack"]) ) {
113 [self setKeyEquivalentForCode:[keyCombo keyCode]
114 andModifiers:[keyCombo modifiers]
118 if (_currentPlaylist) {
119 [tempItem setTag:MTMenuPreviousTrackItem];
120 [tempItem setTarget:self];
122 } else if ([nextObject isEqualToString:@"Fast Forward"]) {
123 tempItem = [menu addItemWithTitle:@"Fast Forward"
124 action:@selector(performMainMenuAction:)
126 if (_currentPlaylist) {
127 [tempItem setTag:MTMenuFastForwardItem];
128 [tempItem setTarget:self];
130 } else if ([nextObject isEqualToString:@"Rewind"]) {
131 tempItem = [menu addItemWithTitle:@"Rewind"
132 action:@selector(performMainMenuAction:)
134 if (_currentPlaylist) {
135 [tempItem setTag:MTMenuRewindItem];
136 [tempItem setTarget:self];
138 } else if ([nextObject isEqualToString:@"Show Player"]) {
139 tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"Show %@", [[[MainController sharedController] currentRemote] playerSimpleName]] action:@selector(performMainMenuAction:) keyEquivalent:@""];
141 if ( (keyCombo = [[HotKeyCenter sharedCenter] keyComboForName:@"ShowPlayer"]) ) {
142 [self setKeyEquivalentForCode:[keyCombo keyCode]
143 andModifiers:[keyCombo modifiers]
147 [tempItem setTarget:self];
148 [tempItem setTag:MTMenuShowPlayerItem];
149 } else if ([nextObject isEqualToString:@"Preferences"]) {
150 tempItem = [menu addItemWithTitle:@"Preferences..."
151 action:@selector(performMainMenuAction:)
153 [tempItem setTag:MTMenuPreferencesItem];
154 [tempItem setTarget:self];
155 } else if ([nextObject isEqualToString:@"Quit"]) {
156 tempItem = [menu addItemWithTitle:@"Quit"
157 action:@selector(performMainMenuAction:)
159 [tempItem setTag:MTMenuQuitItem];
160 [tempItem setTarget:self];
161 } else if ([nextObject isEqualToString:@"Current Track Info"]) {
162 //Handle playing radio too
163 if (_currentPlaylist) {
164 NSString *title = [currentRemote currentSongTitle];
166 [menu addItemWithTitle:@"Now Playing" action:NULL keyEquivalent:@""];
168 if ([title length] > 0) {
169 [menu addItemWithTitle:[NSString stringWithFormat:@" %@", title]
174 if ([defaults boolForKey:@"showAlbum"]) {
175 [menu addItemWithTitle:[NSString stringWithFormat:@" %@", [currentRemote currentSongAlbum]]
180 if ([defaults boolForKey:@"showArtist"]) {
181 [menu addItemWithTitle:[NSString stringWithFormat:@" %@", [currentRemote currentSongArtist]]
186 if ([defaults boolForKey:@"showTrackNumber"]) {
187 int track = [currentRemote currentSongTrack];
189 [menu addItemWithTitle:[NSString stringWithFormat:@" Track %i", track]
195 if ([defaults boolForKey:@"showTime"]) {
196 int left = [[currentRemote currentSongRemaining] intValue];
197 NSString *remaining = [NSString stringWithFormat:@"%i:%02i", left / 60, left % 60];
198 [menu addItemWithTitle:[NSString stringWithFormat:@" %@/%@", remaining, [currentRemote currentSongLength]]
203 [menu addItemWithTitle:@"No Song" action:NULL keyEquivalent:@""];
205 } else if ([nextObject isEqualToString:@"<separator>"]) {
206 [menu addItem:[NSMenuItem separatorItem]];
208 } else if ([nextObject isEqualToString:@"Song Rating"]) {
209 tempItem = [menu addItemWithTitle:@"Song Rating"
212 [tempItem setSubmenu:_ratingMenu];
215 itemEnum = [[_ratingMenu itemArray] objectEnumerator];
216 while ( (tempItem = [itemEnum nextObject]) ) {
217 [tempItem setState:NSOffState];
220 [[_ratingMenu itemAtIndex:([currentRemote currentSongRating] * 5)] setState:NSOnState];
221 if (_playingRadio || !_currentPlaylist) {
222 [tempItem setEnabled:NO];
224 } else if ([nextObject isEqualToString:@"Upcoming Songs"]) {
225 tempItem = [menu addItemWithTitle:@"Upcoming Songs"
228 [tempItem setSubmenu:_upcomingSongsMenu];
230 if (_playingRadio || !_currentPlaylist) {
231 [tempItem setEnabled:NO];
233 } else if ([nextObject isEqualToString:@"Playlists"]) {
234 tempItem = [menu addItemWithTitle:@"Playlists"
237 [tempItem setSubmenu:_playlistsMenu];
239 } else if ([nextObject isEqualToString:@"EQ Presets"]) {
240 tempItem = [menu addItemWithTitle:@"EQ Presets"
243 [tempItem setSubmenu:_eqMenu];
246 itemEnum = [[_eqMenu itemArray] objectEnumerator];
247 while ( (tempItem = [itemEnum nextObject]) ) {
248 [tempItem setState:NSOffState];
250 [[_eqMenu itemAtIndex:([currentRemote currentEQPresetIndex] - 1)] setState:NSOnState];
253 [_currentMenu release];
258 - (NSMenu *)menuForNoPlayer
260 NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
261 NSMenuItem *tempItem;
262 tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"Open %@", [[[MainController sharedController] currentRemote] playerSimpleName]] action:@selector(performMainMenuAction:) keyEquivalent:@""];
263 [tempItem setTag:MTMenuShowPlayerItem];
264 [tempItem setTarget:self];
265 [menu addItem:[NSMenuItem separatorItem]];
266 tempItem = [menu addItemWithTitle:@"Preferences" action:@selector(performMainMenuAction:) keyEquivalent:@""];
267 [tempItem setTag:MTMenuPreferencesItem];
268 [tempItem setTarget:self];
269 tempItem = [menu addItemWithTitle:@"Quit" action:@selector(performMainMenuAction:) keyEquivalent:@""];
270 [tempItem setTag:MTMenuQuitItem];
271 [tempItem setTarget:self];
272 return [menu autorelease];
275 - (void)rebuildSubmenus
277 currentRemote = [[MainController sharedController] currentRemote];
278 _currentPlaylist = [currentRemote currentPlaylistIndex];
279 _currentTrack = [currentRemote currentSongIndex];
280 _playingRadio = ([currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
282 [_ratingMenu release];
283 [_upcomingSongsMenu release];
284 [_playlistsMenu release];
286 _ratingMenu = [self ratingMenu];
287 _upcomingSongsMenu = [self upcomingSongsMenu];
288 _playlistsMenu = [self playlistsMenu];
289 _eqMenu = [self eqMenu];
292 - (NSMenu *)ratingMenu
294 NSMenu *ratingMenu = [[NSMenu alloc] initWithTitle:@""];
295 if (_currentPlaylist && !_playingRadio) {
296 NSEnumerator *itemEnum;
299 SEL itemSelector = @selector(performRatingMenuAction:);
301 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"☆☆☆☆☆"] action:nil keyEquivalent:@""];
302 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★☆☆☆☆"] action:nil keyEquivalent:@""];
303 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★☆☆☆"] action:nil keyEquivalent:@""];
304 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★☆☆"] action:nil keyEquivalent:@""];
305 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★★☆"] action:nil keyEquivalent:@""];
306 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★★★"] action:nil keyEquivalent:@""];
308 itemEnum = [[ratingMenu itemArray] objectEnumerator];
309 while ( (anItem = [itemEnum nextObject]) ) {
310 [anItem setAction:itemSelector];
311 [anItem setTarget:self];
312 [anItem setTag:itemTag];
319 - (NSMenu *)upcomingSongsMenu
321 NSMenu *upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""];
322 int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:_currentPlaylist];
323 int numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
325 if (_currentPlaylist && !_playingRadio) {
329 for (i = _currentTrack + 1; i <= _currentTrack + numSongsInAdvance; i++) {
331 NSString *curSong = [currentRemote songTitleAtIndex:i];
332 NSMenuItem *songItem;
333 songItem = [upcomingSongsMenu addItemWithTitle:curSong action:@selector(performUpcomingSongsMenuAction:) keyEquivalent:@""];
335 [songItem setTarget:self];
342 return upcomingSongsMenu;
345 - (NSMenu *)playlistsMenu
347 NSMenu *playlistsMenu = [[NSMenu alloc] initWithTitle:@""];
348 NSArray *playlists = [currentRemote playlists];
349 NSMenuItem *tempItem;
352 for (i = 0; i < [playlists count]; i++) {
353 tempItem = [playlistsMenu addItemWithTitle:[playlists objectAtIndex:i] action:@selector(performPlaylistMenuAction:) keyEquivalent:@""];
354 [tempItem setTag:i + 1];
355 [tempItem setTarget:self];
358 if (!_playingRadio && _currentPlaylist) {
359 [[playlistsMenu itemAtIndex:_currentPlaylist - 1] setState:NSOnState];
361 return playlistsMenu;
366 NSMenu *eqMenu = [[NSMenu alloc] initWithTitle:@""];
367 NSArray *eqPresets = [currentRemote eqPresets];
368 NSMenuItem *tempItem;
371 for (i = 0; i < [eqPresets count]; i++) {
373 if ( ( name = [eqPresets objectAtIndex:i] ) ) {
374 tempItem = [eqMenu addItemWithTitle:name action:@selector(performEqualizerMenuAction:) keyEquivalent:@""];
376 [tempItem setTarget:self];
382 - (void)performMainMenuAction:(id)sender
384 switch ( [sender tag] )
386 case MTMenuPlayPauseItem:
387 NSLog(@"MenuController: Play/Pause");
388 [[MainController sharedController] playPause];
390 case MTMenuFastForwardItem:
391 NSLog(@"MenuController: Fast Forward");
392 [[MainController sharedController] fastForward];
394 case MTMenuRewindItem:
395 NSLog(@"MenuController: Rewind");
396 [[MainController sharedController] rewind];
398 case MTMenuPreviousTrackItem:
399 NSLog(@"MenuController: Previous Track");
400 [[MainController sharedController] prevSong];
402 case MTMenuNextTrackItem:
403 NSLog(@"MenuController: Next Track");
404 [[MainController sharedController] nextSong];
406 case MTMenuShowPlayerItem:
407 NSLog(@"MainController: Show Main Interface");
408 [[MainController sharedController] showPlayer];
410 case MTMenuPreferencesItem:
411 NSLog(@"MenuController: Preferences...");
412 [[MainController sharedController] showPreferences];
415 NSLog(@"MenuController: Quit");
416 [[MainController sharedController] quitMenuTunes];
419 NSLog(@"MenuController: Unimplemented Menu Item OR Child-bearing Menu Item");
424 - (void)performRatingMenuAction:(id)sender
426 [[MainController sharedController] selectSongRating:[sender tag]];
429 - (void)performPlaylistMenuAction:(id)sender
431 [[MainController sharedController] selectPlaylistAtIndex:[sender tag]];
434 - (void)performEqualizerMenuAction:(id)sender
436 [[MainController sharedController] selectEQPresetAtIndex:[sender tag]];
439 - (void)performUpcomingSongsMenuAction:(id)sender
441 [[MainController sharedController] selectSongAtIndex:[sender tag]];
447 [_currentMenu update];
450 - (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem
455 - (NSString *)systemUIColor
457 NSDictionary *tmpDict;
459 if ( (tmpDict = [NSDictionary dictionaryWithContentsOfFile:[@"~/Library/Preferences/.GlobalPreferences.plist" stringByExpandingTildeInPath]]) ) {
460 if ( (tmpNumber = [tmpDict objectForKey:@"AppleAquaColorVariant"]) ) {
461 if ( ([tmpNumber intValue] == 1) ) {
474 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
475 onItem:(NSMenuItem *)item
477 unichar charcode = 'a';
479 long cocoaModifiers = 0;
480 static long carbonToCocoa[6][2] =
482 { cmdKey, NSCommandKeyMask },
483 { optionKey, NSAlternateKeyMask },
484 { controlKey, NSControlKeyMask },
485 { shiftKey, NSShiftKeyMask },
488 for (i = 0; i < 6; i++) {
489 if (modifiers & carbonToCocoa[i][0]) {
490 cocoaModifiers += carbonToCocoa[i][1];
493 [item setKeyEquivalentModifierMask:cocoaModifiers];
495 //Missing key combos for some keys. Must find them later.
509 // Haven't tested this, though it should work.
510 // This doesn't work. :'(
512 [[NSString stringWithString:@"Space"] getCharacters:&buffer];
514 /*MenuRef menuRef = _NSGetCarbonMenu([item menu]);
515 NSLog(@"%@", menuRef);
516 SetMenuItemCommandKey(menuRef, 0, NO, 49);
517 SetMenuItemModifiers(menuRef, 0, kMenuNoCommandModifier);
518 SetMenuItemKeyGlyph(menuRef, 0, kMenuBlankGlyph);
525 charcode = NSDeleteFunctionKey;
541 charcode = NSF5FunctionKey;
545 charcode = NSF6FunctionKey;
549 charcode = NSF7FunctionKey;
553 charcode = NSF3FunctionKey;
557 charcode = NSF8FunctionKey;
561 charcode = NSF9FunctionKey;
565 charcode = NSF11FunctionKey;
569 charcode = NSF3FunctionKey;
573 charcode = NSF14FunctionKey;
577 charcode = NSF10FunctionKey;
581 charcode = NSF12FunctionKey;
585 charcode = NSF13FunctionKey;
589 charcode = NSInsertFunctionKey;
593 charcode = NSHomeFunctionKey;
597 charcode = NSPageUpFunctionKey;
601 charcode = NSDeleteFunctionKey;
605 charcode = NSF4FunctionKey;
609 charcode = NSEndFunctionKey;
613 charcode = NSF2FunctionKey;
617 charcode = NSPageDownFunctionKey;
621 charcode = NSF1FunctionKey;
625 charcode = NSLeftArrowFunctionKey;
629 charcode = NSRightArrowFunctionKey;
633 charcode = NSDownArrowFunctionKey;
637 charcode = NSUpArrowFunctionKey;
641 if (charcode == 'a') {
647 kchr = (Ptr) GetScriptVariable(smCurrentScript, smKCHRCache);
648 keyTrans = KeyTranslate(kchr, code, &state);
650 [item setKeyEquivalent:[NSString stringWithCString:&charCode length:1]];
651 } else if (charcode != 'b') {
652 [item setKeyEquivalent:[NSString stringWithCharacters:&charcode length:1]];