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 "MainController.h"
11 #import <ITKit/ITHotKeyCenter.h>
12 #import <ITKit/ITHotKey.h>
13 #import <ITKit/ITKeyCombo.h>
15 @interface MenuController (SubmenuMethods)
16 - (NSMenu *)ratingMenu;
17 - (NSMenu *)upcomingSongsMenu;
18 - (NSMenu *)playlistsMenu;
20 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
21 onItem:(NSMenuItem *)item;
24 @implementation MenuController
28 if ( (self = [super init]) ) {
29 _menuLayout = [[NSMutableArray alloc] initWithCapacity:0];
36 NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
37 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
38 NSArray *menuArray = [defaults arrayForKey:@"menu"];
39 NSEnumerator *enumerator = [menuArray objectEnumerator];
42 NSEnumerator *itemEnum;
44 NSArray *hotKeys = [[ITHotKeyCenter sharedCenter] allHotKeys];
47 _currentPlaylist = [currentRemote currentPlaylistIndex];
48 _playingRadio = ([currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
50 //Kill the old submenu items
51 if ( (tempItem = [_currentMenu itemWithTag:1]) ) {
52 [tempItem setSubmenu:nil];
55 if ( (tempItem = [_currentMenu itemWithTag:2]) ) {
56 [tempItem setSubmenu:nil];
59 if ( (tempItem = [_currentMenu itemWithTag:3]) ) {
60 [tempItem setSubmenu:nil];
63 if ( (tempItem = [_currentMenu itemWithTag:4]) ) {
64 [tempItem setSubmenu:nil];
68 while ( (nextObject = [enumerator nextObject]) ) {
70 if ([nextObject isEqualToString:@"playPause"]) {
71 tempItem = [menu addItemWithTitle:NSLocalizedString(@"play", @"Play")
72 action:@selector(performMainMenuAction:)
74 [tempItem setTag:MTMenuPlayPauseItem];
75 [tempItem setTarget:self];
77 itemEnum = [hotKeys objectEnumerator];
78 while ( (hotKey = [itemEnum nextObject]) ) {
79 if ([[hotKey name] isEqualToString:@"PlayPause"]) {
80 ITKeyCombo *combo = [hotKey keyCombo];
81 [self setKeyEquivalentForCode:[combo keyCode]
82 andModifiers:[combo modifiers]
87 switch ([currentRemote playerPlayingState]) {
88 case ITMTRemotePlayerPlaying:
89 [tempItem setTitle:NSLocalizedString(@"pause", @"Pause")];
91 case ITMTRemotePlayerRewinding:
92 case ITMTRemotePlayerForwarding:
93 [tempItem setTitle:NSLocalizedString(@"resume", @"Resume")];
98 } else if ([nextObject isEqualToString:@"nextTrack"]) {
99 tempItem = [menu addItemWithTitle:NSLocalizedString(@"nextTrack", @"Next Track")
100 action:@selector(performMainMenuAction:)
103 itemEnum = [hotKeys objectEnumerator];
104 while ( (hotKey = [itemEnum nextObject]) ) {
105 if ([[hotKey name] isEqualToString:@"NextTrack"]) {
106 ITKeyCombo *combo = [hotKey keyCombo];
107 [self setKeyEquivalentForCode:[combo keyCode]
108 andModifiers:[combo modifiers]
113 if (_currentPlaylist) {
114 [tempItem setTag:MTMenuNextTrackItem];
115 [tempItem setTarget:self];
117 } else if ([nextObject isEqualToString:@"prevTrack"]) {
118 tempItem = [menu addItemWithTitle:NSLocalizedString(@"prevTrack", @"Previous Track")
119 action:@selector(performMainMenuAction:)
122 itemEnum = [hotKeys objectEnumerator];
123 while ( (hotKey = [itemEnum nextObject]) ) {
124 if ([[hotKey name] isEqualToString:@"PrevTrack"]) {
125 ITKeyCombo *combo = [hotKey keyCombo];
126 [self setKeyEquivalentForCode:[combo keyCode]
127 andModifiers:[combo modifiers]
132 if (_currentPlaylist) {
133 [tempItem setTag:MTMenuPreviousTrackItem];
134 [tempItem setTarget:self];
136 } else if ([nextObject isEqualToString:@"fastForward"]) {
137 tempItem = [menu addItemWithTitle:NSLocalizedString(@"fastForward", @"Fast Forward")
138 action:@selector(performMainMenuAction:)
140 if (_currentPlaylist) {
141 [tempItem setTag:MTMenuFastForwardItem];
142 [tempItem setTarget:self];
144 } else if ([nextObject isEqualToString:@"rewind"]) {
145 tempItem = [menu addItemWithTitle:NSLocalizedString(@"rewind", @"Rewind")
146 action:@selector(performMainMenuAction:)
148 if (_currentPlaylist) {
149 [tempItem setTag:MTMenuRewindItem];
150 [tempItem setTarget:self];
152 } else if ([nextObject isEqualToString:@"showPlayer"]) {
153 tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@",
154 NSLocalizedString(@"show", @"Show"),
155 [[[MainController sharedController] currentRemote] playerSimpleName]]
156 action:@selector(performMainMenuAction:)
159 itemEnum = [hotKeys objectEnumerator];
160 while ( (hotKey = [itemEnum nextObject]) ) {
161 if ([[hotKey name] isEqualToString:@"ShowPlayer"]) {
162 ITKeyCombo *combo = [hotKey keyCombo];
163 [self setKeyEquivalentForCode:[combo keyCode]
164 andModifiers:[combo modifiers]
169 [tempItem setTarget:self];
170 [tempItem setTag:MTMenuShowPlayerItem];
171 } else if ([nextObject isEqualToString:@"preferences"]) {
172 tempItem = [menu addItemWithTitle:NSLocalizedString(@"preferences", @"Preferences...")
173 action:@selector(performMainMenuAction:)
175 [tempItem setTag:MTMenuPreferencesItem];
176 [tempItem setTarget:self];
177 } else if ([nextObject isEqualToString:@"quit"]) {
178 tempItem = [menu addItemWithTitle:NSLocalizedString(@"quit", @"Quit")
179 action:@selector(performMainMenuAction:)
181 [tempItem setTag:MTMenuQuitItem];
182 [tempItem setTarget:self];
183 } else if ([nextObject isEqualToString:@"trackInfo"]) {
184 //Handle playing radio too
185 if (_currentPlaylist) {
186 NSString *title = [currentRemote currentSongTitle];
188 [menu addItemWithTitle:NSLocalizedString(@"nowPlaying", @"Now Playing") action:NULL keyEquivalent:@""];
190 if ([title length] > 0) {
191 [menu addItemWithTitle:[NSString stringWithFormat:@" %@", title]
196 if ([defaults boolForKey:@"showAlbum"]) {
197 NSString *curAlbum = [currentRemote currentSongAlbum];
198 if ([curAlbum length]) {
199 [menu addItemWithTitle:[NSString stringWithFormat:@" %@", curAlbum]
205 if ([defaults boolForKey:@"showArtist"]) {
206 NSString *curArtist = [currentRemote currentSongArtist];
207 if ([curArtist length]) {
208 [menu addItemWithTitle:[NSString stringWithFormat:@" %@", curArtist]
214 if ([defaults boolForKey:@"showTrackNumber"]) {
215 int track = [currentRemote currentSongTrack];
217 [menu addItemWithTitle:[NSString stringWithFormat:@" %@ %i", NSLocalizedString(@"track", @"Track"), track]
223 if ([defaults boolForKey:@"showTime"]) {
224 int left = [[currentRemote currentSongRemaining] intValue];
225 NSString *remaining = [NSString stringWithFormat:@"%i:%02i", left / 60, left % 60];
226 [menu addItemWithTitle:[NSString stringWithFormat:@" %@/%@", remaining, [currentRemote currentSongLength]]
231 [menu addItemWithTitle:NSLocalizedString(@"noSong", @"No Song") action:NULL keyEquivalent:@""];
233 } else if ([nextObject isEqualToString:@"separator"]) {
234 [menu addItem:[NSMenuItem separatorItem]];
236 } else if ([nextObject isEqualToString:@"songRating"]) {
237 tempItem = [menu addItemWithTitle:NSLocalizedString(@"songRating", @"Song Rating")
240 [tempItem setSubmenu:_ratingMenu];
242 if (_playingRadio || !_currentPlaylist) {
243 [tempItem setEnabled:NO];
246 itemEnum = [[_ratingMenu itemArray] objectEnumerator];
247 while ( (tempItem = [itemEnum nextObject]) ) {
248 [tempItem setState:NSOffState];
251 [[_ratingMenu itemAtIndex:([currentRemote currentSongRating] * 5)] setState:NSOnState];
252 } else if ([nextObject isEqualToString:@"upcomingSongs"]) {
253 tempItem = [menu addItemWithTitle:NSLocalizedString(@"upcomingSongs", @"Upcoming Songs")
256 [tempItem setSubmenu:_upcomingSongsMenu];
258 if (_playingRadio || !_currentPlaylist) {
259 [tempItem setEnabled:NO];
261 } else if ([nextObject isEqualToString:@"playlists"]) {
262 tempItem = [menu addItemWithTitle:NSLocalizedString(@"playlists", @"Playlists")
265 [tempItem setSubmenu:_playlistsMenu];
267 } else if ([nextObject isEqualToString:@"eqPresets"]) {
268 tempItem = [menu addItemWithTitle:NSLocalizedString(@"eqPresets", @"EQ Presets")
271 [tempItem setSubmenu:_eqMenu];
274 itemEnum = [[_eqMenu itemArray] objectEnumerator];
275 while ( (tempItem = [itemEnum nextObject]) ) {
276 [tempItem setState:NSOffState];
278 [[_eqMenu itemAtIndex:([currentRemote currentEQPresetIndex] - 1)] setState:NSOnState];
281 [_currentMenu release];
286 - (NSMenu *)menuForNoPlayer
288 NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
289 NSMenuItem *tempItem;
290 tempItem = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"open", @"Open"), [[[MainController sharedController] currentRemote] playerSimpleName]] action:@selector(performMainMenuAction:) keyEquivalent:@""];
291 [tempItem setTag:MTMenuShowPlayerItem];
292 [tempItem setTarget:self];
293 [menu addItem:[NSMenuItem separatorItem]];
294 tempItem = [menu addItemWithTitle:NSLocalizedString(@"preferences", @"Preferences...") action:@selector(performMainMenuAction:) keyEquivalent:@""];
295 [tempItem setTag:MTMenuPreferencesItem];
296 [tempItem setTarget:self];
297 tempItem = [menu addItemWithTitle:NSLocalizedString(@"quit", @"Quit") action:@selector(performMainMenuAction:) keyEquivalent:@""];
298 [tempItem setTag:MTMenuQuitItem];
299 [tempItem setTarget:self];
300 return [menu autorelease];
303 - (void)rebuildSubmenus
305 currentRemote = [[MainController sharedController] currentRemote];
306 _currentPlaylist = [currentRemote currentPlaylistIndex];
307 _currentTrack = [currentRemote currentSongIndex];
308 _playingRadio = ([currentRemote currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist);
310 [_ratingMenu release];
311 [_upcomingSongsMenu release];
312 [_playlistsMenu release];
314 _ratingMenu = [self ratingMenu];
315 _upcomingSongsMenu = [self upcomingSongsMenu];
316 _playlistsMenu = [self playlistsMenu];
317 _eqMenu = [self eqMenu];
320 - (NSMenu *)ratingMenu
322 NSMenu *ratingMenu = [[NSMenu alloc] initWithTitle:@""];
323 NSEnumerator *itemEnum;
326 SEL itemSelector = @selector(performRatingMenuAction:);
328 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"☆☆☆☆☆"] action:nil keyEquivalent:@""];
329 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★☆☆☆☆"] action:nil keyEquivalent:@""];
330 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★☆☆☆"] action:nil keyEquivalent:@""];
331 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★☆☆"] action:nil keyEquivalent:@""];
332 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★★☆"] action:nil keyEquivalent:@""];
333 [ratingMenu addItemWithTitle:[NSString stringWithUTF8String:"★★★★★"] action:nil keyEquivalent:@""];
335 itemEnum = [[ratingMenu itemArray] objectEnumerator];
336 while ( (anItem = [itemEnum nextObject]) ) {
337 [anItem setAction:itemSelector];
338 [anItem setTarget:self];
339 [anItem setTag:itemTag];
345 - (NSMenu *)upcomingSongsMenu
347 NSMenu *upcomingSongsMenu = [[NSMenu alloc] initWithTitle:@""];
348 int numSongs = [currentRemote numberOfSongsInPlaylistAtIndex:_currentPlaylist];
349 int numSongsInAdvance = [[NSUserDefaults standardUserDefaults] integerForKey:@"SongsInAdvance"];
351 if (_currentPlaylist && !_playingRadio) {
355 for (i = _currentTrack + 1; i <= _currentTrack + numSongsInAdvance; i++) {
357 NSString *curSong = [currentRemote songTitleAtIndex:i];
358 NSMenuItem *songItem;
359 songItem = [upcomingSongsMenu addItemWithTitle:curSong action:@selector(performUpcomingSongsMenuAction:) keyEquivalent:@""];
361 [songItem setTarget:self];
368 return upcomingSongsMenu;
371 - (NSMenu *)playlistsMenu
373 NSMenu *playlistsMenu = [[NSMenu alloc] initWithTitle:@""];
374 NSArray *playlists = [currentRemote playlists];
375 NSMenuItem *tempItem;
378 for (i = 0; i < [playlists count]; i++) {
379 tempItem = [playlistsMenu addItemWithTitle:[playlists objectAtIndex:i] action:@selector(performPlaylistMenuAction:) keyEquivalent:@""];
380 [tempItem setTag:i + 1];
381 [tempItem setTarget:self];
384 if (!_playingRadio && _currentPlaylist) {
385 [[playlistsMenu itemAtIndex:_currentPlaylist - 1] setState:NSOnState];
387 return playlistsMenu;
392 NSMenu *eqMenu = [[NSMenu alloc] initWithTitle:@""];
393 NSArray *eqPresets = [currentRemote eqPresets];
394 NSMenuItem *tempItem;
397 for (i = 0; i < [eqPresets count]; i++) {
399 if ( ( name = [eqPresets objectAtIndex:i] ) ) {
400 tempItem = [eqMenu addItemWithTitle:name action:@selector(performEqualizerMenuAction:) keyEquivalent:@""];
402 [tempItem setTarget:self];
408 - (void)performMainMenuAction:(id)sender
410 switch ( [sender tag] )
412 case MTMenuPlayPauseItem:
413 NSLog(@"MenuController: Play/Pause");
414 [[MainController sharedController] playPause];
416 case MTMenuFastForwardItem:
417 NSLog(@"MenuController: Fast Forward");
418 [[MainController sharedController] fastForward];
420 case MTMenuRewindItem:
421 NSLog(@"MenuController: Rewind");
422 [[MainController sharedController] rewind];
424 case MTMenuPreviousTrackItem:
425 NSLog(@"MenuController: Previous Track");
426 [[MainController sharedController] prevSong];
428 case MTMenuNextTrackItem:
429 NSLog(@"MenuController: Next Track");
430 [[MainController sharedController] nextSong];
432 case MTMenuShowPlayerItem:
433 NSLog(@"MainController: Show Main Interface");
434 [[MainController sharedController] showPlayer];
436 case MTMenuPreferencesItem:
437 NSLog(@"MenuController: Preferences...");
438 [[MainController sharedController] showPreferences];
441 NSLog(@"MenuController: Quit");
442 [[MainController sharedController] quitMenuTunes];
445 NSLog(@"MenuController: Unimplemented Menu Item OR Child-bearing Menu Item");
450 - (void)performRatingMenuAction:(id)sender
452 [[MainController sharedController] selectSongRating:[sender tag]];
455 - (void)performPlaylistMenuAction:(id)sender
457 [[MainController sharedController] selectPlaylistAtIndex:[sender tag]];
460 - (void)performEqualizerMenuAction:(id)sender
462 [[MainController sharedController] selectEQPresetAtIndex:[sender tag]];
465 - (void)performUpcomingSongsMenuAction:(id)sender
467 [[MainController sharedController] selectSongAtIndex:[sender tag]];
473 [_currentMenu update];
476 - (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem
481 - (NSString *)systemUIColor
483 NSDictionary *tmpDict;
485 if ( (tmpDict = [NSDictionary dictionaryWithContentsOfFile:[@"~/Library/Preferences/.GlobalPreferences.plist" stringByExpandingTildeInPath]]) ) {
486 if ( (tmpNumber = [tmpDict objectForKey:@"AppleAquaColorVariant"]) ) {
487 if ( ([tmpNumber intValue] == 1) ) {
500 - (void)setKeyEquivalentForCode:(short)code andModifiers:(long)modifiers
501 onItem:(NSMenuItem *)item
503 unichar charcode = 'a';
505 long cocoaModifiers = 0;
506 static long carbonToCocoa[6][2] =
508 { cmdKey, NSCommandKeyMask },
509 { optionKey, NSAlternateKeyMask },
510 { controlKey, NSControlKeyMask },
511 { shiftKey, NSShiftKeyMask },
514 for (i = 0; i < 6; i++) {
515 if (modifiers & carbonToCocoa[i][0]) {
516 cocoaModifiers += carbonToCocoa[i][1];
519 [item setKeyEquivalentModifierMask:cocoaModifiers];
521 //Missing key combos for some keys. Must find them later.
535 // Haven't tested this, though it should work.
536 // This doesn't work. :'(
538 [[NSString stringWithString:@"Space"] getCharacters:&buffer];
540 /*MenuRef menuRef = _NSGetCarbonMenu([item menu]);
541 NSLog(@"%@", menuRef);
542 SetMenuItemCommandKey(menuRef, 0, NO, 49);
543 SetMenuItemModifiers(menuRef, 0, kMenuNoCommandModifier);
544 SetMenuItemKeyGlyph(menuRef, 0, kMenuBlankGlyph);
551 charcode = NSDeleteFunctionKey;
567 charcode = NSF5FunctionKey;
571 charcode = NSF6FunctionKey;
575 charcode = NSF7FunctionKey;
579 charcode = NSF3FunctionKey;
583 charcode = NSF8FunctionKey;
587 charcode = NSF9FunctionKey;
591 charcode = NSF11FunctionKey;
595 charcode = NSF3FunctionKey;
599 charcode = NSF14FunctionKey;
603 charcode = NSF10FunctionKey;
607 charcode = NSF12FunctionKey;
611 charcode = NSF13FunctionKey;
615 charcode = NSInsertFunctionKey;
619 charcode = NSHomeFunctionKey;
623 charcode = NSPageUpFunctionKey;
627 charcode = NSDeleteFunctionKey;
631 charcode = NSF4FunctionKey;
635 charcode = NSEndFunctionKey;
639 charcode = NSF2FunctionKey;
643 charcode = NSPageDownFunctionKey;
647 charcode = NSF1FunctionKey;
651 charcode = NSLeftArrowFunctionKey;
655 charcode = NSRightArrowFunctionKey;
659 charcode = NSDownArrowFunctionKey;
663 charcode = NSUpArrowFunctionKey;
667 if (charcode == 'a') {
673 kchr = (Ptr) GetScriptVariable(smCurrentScript, smKCHRCache);
674 keyTrans = KeyTranslate(kchr, code, &state);
676 [item setKeyEquivalent:[NSString stringWithCString:&charCode length:1]];
677 } else if (charcode != 'b') {
678 [item setKeyEquivalent:[NSString stringWithCharacters:&charcode length:1]];